diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-04-25 15:37:56 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-04-25 15:37:56 -0400 |
| commit | 8614397110595e267b7e4e1f558bfce619e60c02 (patch) | |
| tree | 70cb89a4692f268ad17b8869be41e09149b63e39 /src | |
| parent | efa771af754281cd76a77ef22af107eb0a9aaf9a (diff) | |
| download | zig-8614397110595e267b7e4e1f558bfce619e60c02.tar.gz zig-8614397110595e267b7e4e1f558bfce619e60c02.zip | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 2 | ||||
| -rw-r--r-- | src/analyze.cpp | 5 | ||||
| -rw-r--r-- | src/codegen.cpp | 105 |
3 files changed, 94 insertions, 18 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index a9bcf14d78..0fc74d2212 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -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; diff --git a/src/analyze.cpp b/src/analyze.cpp index ebbb3e0689..a190ee88b7 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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); diff --git a/src/codegen.cpp b/src/codegen.cpp index efa9e26c05..a5411e8df1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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) { |
