authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-25 16:53:22-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-25 16:53:22-04:00
log13c6a58a61817ae6aae66dd1843385452fe65bd1
tree6ac0236d6aba9740a36addb192fa639446457518
parent8614397110595e267b7e4e1f558bfce619e60c02

compile time improvement - move bounds checking to function calls

once again this barely had an effect: Before: ./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 After: ./build size: 1.3 MB hello.zig size: 300 KB full test: 1m31.882s debug test: 19.569s hello.zig timing: Name Start End Duration Percent Initialize 0.0000 0.0000 0.0000 0.0002 Semantic Analysis 0.0000 0.0425 0.0424 0.2228 Code Generation 0.0425 0.0661 0.0236 0.1239 LLVM Emit Object 0.0661 0.1762 0.1101 0.5782 Build Dependencies 0.1762 0.1888 0.0126 0.0664 LLVM Link 0.1888 0.1905 0.0016 0.0085 Generate .h 0.1905 0.1905 0.0000 0.0000 Total 0.0000 0.1905 0.1905 1.0000

4 files changed, 99 insertions(+), 22 deletions(-)

.gitignore+1
......@@ -1,4 +1,5 @@
11build/
2build2/
23build-release/
34/.cproject
45/.project
src/all_types.hpp+5
......@@ -1257,6 +1257,7 @@ enum ZigLLVMFnId {
12571257 ZigLLVMFnIdClz,
12581258 ZigLLVMFnIdOverflowArithmetic,
12591259 ZigLLVMFnIdOverflowArithmeticPanic,
1260 ZigLLVMFnIdBoundsCheck,
12601261};
12611262
12621263enum AddSubMul {
......@@ -1280,6 +1281,10 @@ struct ZigLLVMFnKey {
12801281 uint32_t bit_count;
12811282 bool is_signed;
12821283 } overflow_arithmetic;
1284 struct {
1285 LLVMIntPredicate pred;
1286 uint32_t bit_count;
1287 } bounds_check;
12831288 } data;
12841289};
12851290
src/analyze.cpp+6
......@@ -4145,6 +4145,9 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
41454145 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 3329604261) +
41464146 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 966805797) +
41474147 ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 3679835291 : 1187552903);
4148 case ZigLLVMFnIdBoundsCheck:
4149 return (uint32_t)(x.data.bounds_check.pred) * (uint32_t)3146725107 +
4150 x.data.bounds_check.bit_count * (uint32_t)2904561957;
41484151 }
41494152 zig_unreachable();
41504153}
......@@ -4162,6 +4165,9 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
41624165 return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&
41634166 (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&
41644167 (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed);
4168 case ZigLLVMFnIdBoundsCheck:
4169 return a.data.bounds_check.pred == b.data.bounds_check.pred &&
4170 a.data.bounds_check.bit_count == b.data.bounds_check.bit_count;
41654171 }
41664172 zig_unreachable();
41674173}
src/codegen.cpp+87-22
......@@ -812,37 +812,102 @@ static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
812812 LLVMBuildUnreachable(g->builder);
813813}
814814
815static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
816 LLVMIntPredicate lower_pred, LLVMValueRef lower_value,
817 LLVMIntPredicate upper_pred, LLVMValueRef upper_value)
818{
819 if (!lower_value && !upper_value) {
820 return;
821 }
822 if (upper_value && !lower_value) {
823 lower_value = upper_value;
824 lower_pred = upper_pred;
825 upper_value = nullptr;
815static const char *pred_name(LLVMIntPredicate pred) {
816 switch (pred) {
817 case LLVMIntEQ: return "eq";
818 case LLVMIntNE: return "ne";
819 case LLVMIntULT: return "lt";
820 case LLVMIntULE: return "le";
821 default:
822 zig_unreachable();
826823 }
824}
825
826static LLVMValueRef get_bounds_check_fn_val(CodeGen *g, LLVMIntPredicate pred, uint32_t bit_count) {
827 ZigLLVMFnKey key = {};
828 key.id = ZigLLVMFnIdBoundsCheck;
829 key.data.bounds_check.pred = pred;
830 key.data.bounds_check.bit_count = bit_count;
831
832 auto existing_entry = g->llvm_fn_table.maybe_get(key);
833 if (existing_entry)
834 return existing_entry->value;
835
836 Buf *desired_name = buf_sprintf("__zig_bounds_check_%s_%" PRIu32, pred_name(pred), bit_count);
837 Buf *fn_name = get_mangled_name(g, desired_name, false);
838 LLVMTypeRef type_ref = LLVMIntType(bit_count);
839 LLVMTypeRef arg_types[] = { type_ref, type_ref };
840 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
841 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
842 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
843 LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
844
845 auto prev_state = save_and_clear_builder_state(g);
846
847 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
848 LLVMPositionBuilderAtEnd(g->builder, entry_block);
827849
828 LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail");
829 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk");
830 LLVMBasicBlockRef lower_ok_block = upper_value ?
831 LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block;
850 LLVMValueRef target_val = LLVMGetParam(fn_val, 0);
851 LLVMValueRef bound_val = LLVMGetParam(fn_val, 1);
832852
833 LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, "");
834 LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block);
853 LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(fn_val, "BoundsCheckFail");
854 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "BoundsCheckOk");
855
856 LLVMValueRef ok_val = LLVMBuildICmp(g->builder, pred, target_val, bound_val, "");
857 LLVMBuildCondBr(g->builder, ok_val, ok_block, bounds_check_fail_block);
835858
836859 LLVMPositionBuilderAtEnd(g->builder, bounds_check_fail_block);
837860 gen_debug_safety_crash(g, PanicMsgIdBoundsCheckFailure);
838861
839 if (upper_value) {
840 LLVMPositionBuilderAtEnd(g->builder, lower_ok_block);
841 LLVMValueRef upper_ok_val = LLVMBuildICmp(g->builder, upper_pred, target_val, upper_value, "");
842 LLVMBuildCondBr(g->builder, upper_ok_val, ok_block, bounds_check_fail_block);
862 LLVMPositionBuilderAtEnd(g->builder, ok_block);
863 LLVMBuildRetVoid(g->builder);
864
865 restore_builder_state(g, prev_state);
866 g->llvm_fn_table.put(key, fn_val);
867 return fn_val;
868}
869
870static void add_one_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMIntPredicate pred, LLVMValueRef bound_val) {
871 LLVMValueRef arg1;
872 LLVMValueRef arg2;
873 switch (pred) {
874 case LLVMIntEQ:
875 case LLVMIntNE:
876 case LLVMIntULT:
877 case LLVMIntULE:
878 arg1 = target_val;
879 arg2 = bound_val;
880 break;
881 case LLVMIntUGT:
882 arg1 = bound_val;
883 arg2 = target_val;
884 pred = LLVMIntULE;
885 break;
886 case LLVMIntUGE:
887 arg1 = bound_val;
888 arg2 = target_val;
889 pred = LLVMIntULT;
890 break;
891 default:
892 zig_unreachable();
843893 }
894 uint32_t bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(target_val));
895 LLVMValueRef fn_val = get_bounds_check_fn_val(g, pred, bit_count);
896 LLVMValueRef params[] = { arg1, arg2, };
897 LLVMBuildCall(g->builder, fn_val, params, 2, "");
898}
844899
845 LLVMPositionBuilderAtEnd(g->builder, ok_block);
900static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
901 LLVMIntPredicate lower_pred, LLVMValueRef lower_value,
902 LLVMIntPredicate upper_pred, LLVMValueRef upper_value)
903{
904 if (lower_value) {
905 add_one_bounds_check(g, target_val, lower_pred, lower_value);
906 }
907
908 if (upper_value) {
909 add_one_bounds_check(g, target_val, upper_pred, upper_value);
910 }
846911}
847912
848913static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, TypeTableEntry *actual_type,