compile time improvement - move overflow math safety to fns

move some boilerplate code having to do with overflow math safety
to functions.

Again the timing difference is not much:

Before:

./build size: 1.3 MB
hello.zig size: 308 KB
full test:  1m33.588s
debug test: 20.303s
hello.zig timing:
                Name       Start         End    Duration     Percent
          Initialize      0.0000      0.0000      0.0000      0.0002
   Semantic Analysis      0.0000      0.0425      0.0425      0.2202
     Code Generation      0.0425      0.0675      0.0250      0.1293
    LLVM Emit Object      0.0675      0.1789      0.1114      0.5773
  Build Dependencies      0.1789      0.1913      0.0124      0.0640
           LLVM Link      0.1913      0.1931      0.0018      0.0091
         Generate .h      0.1931      0.1931      0.0000      0.0000
               Total      0.0000      0.1931      0.1931      1.0000

After:

./build size: 1.3 MB
hello.zig size: 301 KB
full test: 1m31.253s
debug test: 19.607s
hello.zig timing:
                Name       Start         End    Duration     Percent
          Initialize      0.0000      0.0000      0.0000      0.0002
   Semantic Analysis      0.0000      0.0431      0.0431      0.2262
     Code Generation      0.0431      0.0660      0.0229      0.1201
    LLVM Emit Object      0.0660      0.1765      0.1105      0.5795
  Build Dependencies      0.1765      0.1890      0.0125      0.0655
           LLVM Link      0.1890      0.1906      0.0016      0.0086
         Generate .h      0.1906      0.1906      0.0000      0.0000
               Total      0.0000      0.1906      0.1906      1.0000
This commit is contained in:
Andrew Kelley 2017-04-25 15:37:56 -04:00
parent efa771af75
commit 8614397110
3 changed files with 94 additions and 18 deletions

View file

@ -1256,6 +1256,7 @@ enum ZigLLVMFnId {
ZigLLVMFnIdCtz,
ZigLLVMFnIdClz,
ZigLLVMFnIdOverflowArithmetic,
ZigLLVMFnIdOverflowArithmeticPanic,
};
enum AddSubMul {
@ -1424,6 +1425,7 @@ struct CodeGen {
FnTableEntry *extern_panic_fn;
LLVMValueRef cur_ret_ptr;
LLVMValueRef cur_fn_val;
bool dbg_clear;
ZigList<LLVMBasicBlockRef> break_block_stack;
ZigList<LLVMBasicBlockRef> continue_block_stack;
bool c_want_stdint;

View file

@ -4141,6 +4141,10 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +
((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +
((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820);
case ZigLLVMFnIdOverflowArithmeticPanic:
return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 3329604261) +
((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 966805797) +
((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 3679835291 : 1187552903);
}
zig_unreachable();
}
@ -4154,6 +4158,7 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
case ZigLLVMFnIdClz:
return a.data.clz.bit_count == b.data.clz.bit_count;
case ZigLLVMFnIdOverflowArithmetic:
case ZigLLVMFnIdOverflowArithmeticPanic:
return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&
(a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&
(a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed);

View file

@ -474,6 +474,31 @@ static void clear_debug_source_node(CodeGen *g) {
ZigLLVMClearCurrentDebugLocation(g->builder);
}
struct BuilderState {
LLVMValueRef debug_loc;
LLVMBasicBlockRef basic_block;
bool is_clear;
};
static BuilderState save_and_clear_builder_state(CodeGen *g) {
BuilderState prev_state;
prev_state.debug_loc = LLVMGetCurrentDebugLocation(g->builder);
prev_state.basic_block = LLVMGetInsertBlock(g->builder);
prev_state.is_clear = g->dbg_clear;
ZigLLVMClearCurrentDebugLocation(g->builder);
g->dbg_clear = true;
return prev_state;
}
static void restore_builder_state(CodeGen *g, const BuilderState &prev_state) {
LLVMPositionBuilderAtEnd(g->builder, prev_state.basic_block);
if (!prev_state.is_clear)
LLVMSetCurrentDebugLocation(g->builder, prev_state.debug_loc);
g->dbg_clear = prev_state.is_clear;
}
static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
const char *signed_name, const char *unsigned_name)
{
@ -662,9 +687,8 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) {
LLVMSetLinkage(fn_val, LLVMInternalLinkage);
LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
auto prev_state = save_and_clear_builder_state(g);
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
LLVMPositionBuilderAtEnd(g->builder, entry_block);
LLVMValueRef msg_arg = LLVMGetParam(fn_val, 0);
@ -678,8 +702,7 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) {
LLVMValueRef msg_len = LLVMBuildLoad(g->builder, len_ptr, "");
gen_panic_raw(g, msg_ptr, msg_len);
LLVMPositionBuilderAtEnd(g->builder, prev_block);
LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
restore_builder_state(g, prev_state);
g->panic_slice_fn = fn_val;
return g->panic_slice_fn;
}
@ -744,11 +767,9 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
LLVMSetLinkage(fn_val, LLVMInternalLinkage);
LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
auto prev_state = save_and_clear_builder_state(g);
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
LLVMPositionBuilderAtEnd(g->builder, entry_block);
ZigLLVMClearCurrentDebugLocation(g->builder);
LLVMValueRef err_val = LLVMGetParam(fn_val, 0);
@ -779,8 +800,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
gen_panic_raw(g, full_buf_ptr, full_buf_len);
LLVMPositionBuilderAtEnd(g->builder, prev_block);
LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
restore_builder_state(g, prev_state);
g->safety_crash_err_fn = fn_val;
return fn_val;
@ -905,26 +925,74 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ
}
}
static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op,
LLVMValueRef val1, LLVMValueRef val2)
{
LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op);
static const char *add_sub_mul_name(AddSubMul op) {
switch (op) {
case AddSubMulAdd: return "add";
case AddSubMulSub: return "sub";
case AddSubMulMul: return "mul";
}
zig_unreachable();
}
static LLVMValueRef get_int_overflow_panic_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op) {
ZigLLVMFnKey key = {};
key.id = ZigLLVMFnIdOverflowArithmeticPanic;
key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed;
key.data.overflow_arithmetic.add_sub_mul = op;
key.data.overflow_arithmetic.bit_count = (uint32_t)type_entry->data.integral.bit_count;
auto existing_entry = g->llvm_fn_table.maybe_get(key);
if (existing_entry)
return existing_entry->value;
Buf *desired_name = buf_sprintf("__zig_checked_%s_%c%" PRIu32, add_sub_mul_name(op),
type_entry->data.integral.is_signed ? 'i' : 'u', type_entry->data.integral.bit_count);
Buf *fn_name = get_mangled_name(g, desired_name, false);
LLVMTypeRef arg_types[] = { type_entry->type_ref, type_entry->type_ref };
LLVMTypeRef fn_type_ref = LLVMFunctionType(type_entry->type_ref, arg_types, 2, false);
LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
LLVMSetLinkage(fn_val, LLVMInternalLinkage);
LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
auto prev_state = save_and_clear_builder_state(g);
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
LLVMPositionBuilderAtEnd(g->builder, entry_block);
LLVMValueRef val1 = LLVMGetParam(fn_val, 0);
LLVMValueRef val2 = LLVMGetParam(fn_val, 1);
LLVMValueRef overflow_fn_val = get_int_overflow_fn(g, type_entry, op);
LLVMValueRef params[] = {
val1,
val2,
};
LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
LLVMValueRef result_struct = LLVMBuildCall(g->builder, overflow_fn_val, params, 2, "");
LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(fn_val, "OverflowFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "OverflowOk");
LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
gen_debug_safety_crash(g, PanicMsgIdIntegerOverflow);
LLVMPositionBuilderAtEnd(g->builder, ok_block);
return result;
LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
LLVMBuildRet(g->builder, result);
restore_builder_state(g, prev_state);
g->llvm_fn_table.put(key, fn_val);
return fn_val;
}
static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op,
LLVMValueRef val1, LLVMValueRef val2)
{
LLVMValueRef fn_val = get_int_overflow_panic_fn(g, type_entry, op);
LLVMValueRef params[] = {
val1,
val2,
};
return LLVMBuildCall(g->builder, fn_val, params, 2, "");
}
static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) {
@ -2882,6 +2950,7 @@ static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1,
(int)source_node->column + 1, get_di_scope(g, scope));
g->dbg_clear = false;
}
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {