authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-25 15:37:56-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-25 15:37:56-04:00
log8614397110595e267b7e4e1f558bfce619e60c02
tree70cb89a4692f268ad17b8869be41e09149b63e39
parentefa771af754281cd76a77ef22af107eb0a9aaf9a

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

3 files changed, 94 insertions(+), 18 deletions(-)

src/all_types.hpp+2
...@@ -1256,6 +1256,7 @@ enum ZigLLVMFnId {...@@ -1256,6 +1256,7 @@ enum ZigLLVMFnId {
1256 ZigLLVMFnIdCtz,1256 ZigLLVMFnIdCtz,
1257 ZigLLVMFnIdClz,1257 ZigLLVMFnIdClz,
1258 ZigLLVMFnIdOverflowArithmetic,1258 ZigLLVMFnIdOverflowArithmetic,
1259 ZigLLVMFnIdOverflowArithmeticPanic,
1259};1260};
12601261
1261enum AddSubMul {1262enum AddSubMul {
...@@ -1424,6 +1425,7 @@ struct CodeGen {...@@ -1424,6 +1425,7 @@ struct CodeGen {
1424 FnTableEntry *extern_panic_fn;1425 FnTableEntry *extern_panic_fn;
1425 LLVMValueRef cur_ret_ptr;1426 LLVMValueRef cur_ret_ptr;
1426 LLVMValueRef cur_fn_val;1427 LLVMValueRef cur_fn_val;
1428 bool dbg_clear;
1427 ZigList<LLVMBasicBlockRef> break_block_stack;1429 ZigList<LLVMBasicBlockRef> break_block_stack;
1428 ZigList<LLVMBasicBlockRef> continue_block_stack;1430 ZigList<LLVMBasicBlockRef> continue_block_stack;
1429 bool c_want_stdint;1431 bool c_want_stdint;
src/analyze.cpp+5
...@@ -4141,6 +4141,10 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {...@@ -4141,6 +4141,10 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
4141 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +4141 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +
4142 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +4142 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +
4143 ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820);4143 ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820);
4144 case ZigLLVMFnIdOverflowArithmeticPanic:
4145 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 3329604261) +
4146 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 966805797) +
4147 ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 3679835291 : 1187552903);
4144 }4148 }
4145 zig_unreachable();4149 zig_unreachable();
4146}4150}
...@@ -4154,6 +4158,7 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {...@@ -4154,6 +4158,7 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
4154 case ZigLLVMFnIdClz:4158 case ZigLLVMFnIdClz:
4155 return a.data.clz.bit_count == b.data.clz.bit_count;4159 return a.data.clz.bit_count == b.data.clz.bit_count;
4156 case ZigLLVMFnIdOverflowArithmetic:4160 case ZigLLVMFnIdOverflowArithmetic:
4161 case ZigLLVMFnIdOverflowArithmeticPanic:
4157 return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&4162 return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&
4158 (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&4163 (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&
4159 (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed);4164 (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed);
src/codegen.cpp+87-18
...@@ -474,6 +474,31 @@ static void clear_debug_source_node(CodeGen *g) {...@@ -474,6 +474,31 @@ static void clear_debug_source_node(CodeGen *g) {
474 ZigLLVMClearCurrentDebugLocation(g->builder);474 ZigLLVMClearCurrentDebugLocation(g->builder);
475}475}
476476
477struct BuilderState {
478 LLVMValueRef debug_loc;
479 LLVMBasicBlockRef basic_block;
480 bool is_clear;
481};
482
483static BuilderState save_and_clear_builder_state(CodeGen *g) {
484 BuilderState prev_state;
485 prev_state.debug_loc = LLVMGetCurrentDebugLocation(g->builder);
486 prev_state.basic_block = LLVMGetInsertBlock(g->builder);
487 prev_state.is_clear = g->dbg_clear;
488
489 ZigLLVMClearCurrentDebugLocation(g->builder);
490 g->dbg_clear = true;
491
492 return prev_state;
493}
494
495static void restore_builder_state(CodeGen *g, const BuilderState &prev_state) {
496 LLVMPositionBuilderAtEnd(g->builder, prev_state.basic_block);
497 if (!prev_state.is_clear)
498 LLVMSetCurrentDebugLocation(g->builder, prev_state.debug_loc);
499 g->dbg_clear = prev_state.is_clear;
500}
501
477static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,502static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
478 const char *signed_name, const char *unsigned_name)503 const char *signed_name, const char *unsigned_name)
479{504{
...@@ -662,9 +687,8 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) {...@@ -662,9 +687,8 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) {
662 LLVMSetLinkage(fn_val, LLVMInternalLinkage);687 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
663 LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);688 LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
664689
690 auto prev_state = save_and_clear_builder_state(g);
665 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");691 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
666 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
667 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
668 LLVMPositionBuilderAtEnd(g->builder, entry_block);692 LLVMPositionBuilderAtEnd(g->builder, entry_block);
669693
670 LLVMValueRef msg_arg = LLVMGetParam(fn_val, 0);694 LLVMValueRef msg_arg = LLVMGetParam(fn_val, 0);
...@@ -678,8 +702,7 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) {...@@ -678,8 +702,7 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) {
678 LLVMValueRef msg_len = LLVMBuildLoad(g->builder, len_ptr, "");702 LLVMValueRef msg_len = LLVMBuildLoad(g->builder, len_ptr, "");
679 gen_panic_raw(g, msg_ptr, msg_len);703 gen_panic_raw(g, msg_ptr, msg_len);
680704
681 LLVMPositionBuilderAtEnd(g->builder, prev_block);705 restore_builder_state(g, prev_state);
682 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
683 g->panic_slice_fn = fn_val;706 g->panic_slice_fn = fn_val;
684 return g->panic_slice_fn;707 return g->panic_slice_fn;
685}708}
...@@ -744,11 +767,9 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -744,11 +767,9 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
744 LLVMSetLinkage(fn_val, LLVMInternalLinkage);767 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
745 LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);768 LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
746769
770 auto prev_state = save_and_clear_builder_state(g);
747 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");771 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
748 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
749 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
750 LLVMPositionBuilderAtEnd(g->builder, entry_block);772 LLVMPositionBuilderAtEnd(g->builder, entry_block);
751 ZigLLVMClearCurrentDebugLocation(g->builder);
752773
753 LLVMValueRef err_val = LLVMGetParam(fn_val, 0);774 LLVMValueRef err_val = LLVMGetParam(fn_val, 0);
754775
...@@ -779,8 +800,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -779,8 +800,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
779800
780 gen_panic_raw(g, full_buf_ptr, full_buf_len);801 gen_panic_raw(g, full_buf_ptr, full_buf_len);
781802
782 LLVMPositionBuilderAtEnd(g->builder, prev_block);803 restore_builder_state(g, prev_state);
783 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
784804
785 g->safety_crash_err_fn = fn_val;805 g->safety_crash_err_fn = fn_val;
786 return fn_val;806 return fn_val;
...@@ -905,26 +925,74 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ...@@ -905,26 +925,74 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ
905 }925 }
906}926}
907927
908static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op,928static const char *add_sub_mul_name(AddSubMul op) {
909 LLVMValueRef val1, LLVMValueRef val2)929 switch (op) {
910{930 case AddSubMulAdd: return "add";
911 LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op);931 case AddSubMulSub: return "sub";
932 case AddSubMulMul: return "mul";
933 }
934 zig_unreachable();
935}
936static LLVMValueRef get_int_overflow_panic_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op) {
937 ZigLLVMFnKey key = {};
938 key.id = ZigLLVMFnIdOverflowArithmeticPanic;
939 key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed;
940 key.data.overflow_arithmetic.add_sub_mul = op;
941 key.data.overflow_arithmetic.bit_count = (uint32_t)type_entry->data.integral.bit_count;
942
943 auto existing_entry = g->llvm_fn_table.maybe_get(key);
944 if (existing_entry)
945 return existing_entry->value;
946
947 Buf *desired_name = buf_sprintf("__zig_checked_%s_%c%" PRIu32, add_sub_mul_name(op),
948 type_entry->data.integral.is_signed ? 'i' : 'u', type_entry->data.integral.bit_count);
949 Buf *fn_name = get_mangled_name(g, desired_name, false);
950 LLVMTypeRef arg_types[] = { type_entry->type_ref, type_entry->type_ref };
951 LLVMTypeRef fn_type_ref = LLVMFunctionType(type_entry->type_ref, arg_types, 2, false);
952 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
953 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
954 LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
955
956 auto prev_state = save_and_clear_builder_state(g);
957
958 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
959 LLVMPositionBuilderAtEnd(g->builder, entry_block);
960
961 LLVMValueRef val1 = LLVMGetParam(fn_val, 0);
962 LLVMValueRef val2 = LLVMGetParam(fn_val, 1);
963
964 LLVMValueRef overflow_fn_val = get_int_overflow_fn(g, type_entry, op);
912 LLVMValueRef params[] = {965 LLVMValueRef params[] = {
913 val1,966 val1,
914 val2,967 val2,
915 };968 };
916 LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");969 LLVMValueRef result_struct = LLVMBuildCall(g->builder, overflow_fn_val, params, 2, "");
917 LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
918 LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");970 LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
919 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");971 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(fn_val, "OverflowFail");
920 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");972 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "OverflowOk");
921 LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);973 LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);
922974
923 LLVMPositionBuilderAtEnd(g->builder, fail_block);975 LLVMPositionBuilderAtEnd(g->builder, fail_block);
924 gen_debug_safety_crash(g, PanicMsgIdIntegerOverflow);976 gen_debug_safety_crash(g, PanicMsgIdIntegerOverflow);
925977
926 LLVMPositionBuilderAtEnd(g->builder, ok_block);978 LLVMPositionBuilderAtEnd(g->builder, ok_block);
927 return result;979 LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
980 LLVMBuildRet(g->builder, result);
981
982 restore_builder_state(g, prev_state);
983 g->llvm_fn_table.put(key, fn_val);
984 return fn_val;
985}
986
987static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op,
988 LLVMValueRef val1, LLVMValueRef val2)
989{
990 LLVMValueRef fn_val = get_int_overflow_panic_fn(g, type_entry, op);
991 LLVMValueRef params[] = {
992 val1,
993 val2,
994 };
995 return LLVMBuildCall(g->builder, fn_val, params, 2, "");
928}996}
929997
930static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) {998static 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) {...@@ -2882,6 +2950,7 @@ static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
28822950
2883 ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1,2951 ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1,
2884 (int)source_node->column + 1, get_di_scope(g, scope));2952 (int)source_node->column + 1, get_di_scope(g, scope));
2953 g->dbg_clear = false;
2885}2954}
28862955
2887static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {2956static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {