From 13c6a58a61817ae6aae66dd1843385452fe65bd1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 25 Apr 2017 16:53:22 -0400 Subject: 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 --- src/codegen.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 22 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index a5411e8df1..cca0037402 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -812,37 +812,102 @@ static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { LLVMBuildUnreachable(g->builder); } -static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, - LLVMIntPredicate lower_pred, LLVMValueRef lower_value, - LLVMIntPredicate upper_pred, LLVMValueRef upper_value) -{ - if (!lower_value && !upper_value) { - return; - } - if (upper_value && !lower_value) { - lower_value = upper_value; - lower_pred = upper_pred; - upper_value = nullptr; +static const char *pred_name(LLVMIntPredicate pred) { + switch (pred) { + case LLVMIntEQ: return "eq"; + case LLVMIntNE: return "ne"; + case LLVMIntULT: return "lt"; + case LLVMIntULE: return "le"; + default: + zig_unreachable(); } +} + +static LLVMValueRef get_bounds_check_fn_val(CodeGen *g, LLVMIntPredicate pred, uint32_t bit_count) { + ZigLLVMFnKey key = {}; + key.id = ZigLLVMFnIdBoundsCheck; + key.data.bounds_check.pred = pred; + key.data.bounds_check.bit_count = 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_bounds_check_%s_%" PRIu32, pred_name(pred), bit_count); + Buf *fn_name = get_mangled_name(g, desired_name, false); + LLVMTypeRef type_ref = LLVMIntType(bit_count); + LLVMTypeRef arg_types[] = { type_ref, type_ref }; + LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), 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); - LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk"); - LLVMBasicBlockRef lower_ok_block = upper_value ? - LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block; + LLVMValueRef target_val = LLVMGetParam(fn_val, 0); + LLVMValueRef bound_val = LLVMGetParam(fn_val, 1); - LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, ""); - LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block); + LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(fn_val, "BoundsCheckFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "BoundsCheckOk"); + + LLVMValueRef ok_val = LLVMBuildICmp(g->builder, pred, target_val, bound_val, ""); + LLVMBuildCondBr(g->builder, ok_val, ok_block, bounds_check_fail_block); LLVMPositionBuilderAtEnd(g->builder, bounds_check_fail_block); gen_debug_safety_crash(g, PanicMsgIdBoundsCheckFailure); - if (upper_value) { - LLVMPositionBuilderAtEnd(g->builder, lower_ok_block); - LLVMValueRef upper_ok_val = LLVMBuildICmp(g->builder, upper_pred, target_val, upper_value, ""); - LLVMBuildCondBr(g->builder, upper_ok_val, ok_block, bounds_check_fail_block); + LLVMPositionBuilderAtEnd(g->builder, ok_block); + LLVMBuildRetVoid(g->builder); + + restore_builder_state(g, prev_state); + g->llvm_fn_table.put(key, fn_val); + return fn_val; +} + +static void add_one_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMIntPredicate pred, LLVMValueRef bound_val) { + LLVMValueRef arg1; + LLVMValueRef arg2; + switch (pred) { + case LLVMIntEQ: + case LLVMIntNE: + case LLVMIntULT: + case LLVMIntULE: + arg1 = target_val; + arg2 = bound_val; + break; + case LLVMIntUGT: + arg1 = bound_val; + arg2 = target_val; + pred = LLVMIntULE; + break; + case LLVMIntUGE: + arg1 = bound_val; + arg2 = target_val; + pred = LLVMIntULT; + break; + default: + zig_unreachable(); } + uint32_t bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(target_val)); + LLVMValueRef fn_val = get_bounds_check_fn_val(g, pred, bit_count); + LLVMValueRef params[] = { arg1, arg2, }; + LLVMBuildCall(g->builder, fn_val, params, 2, ""); +} - LLVMPositionBuilderAtEnd(g->builder, ok_block); +static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, + LLVMIntPredicate lower_pred, LLVMValueRef lower_value, + LLVMIntPredicate upper_pred, LLVMValueRef upper_value) +{ + if (lower_value) { + add_one_bounds_check(g, target_val, lower_pred, lower_value); + } + + if (upper_value) { + add_one_bounds_check(g, target_val, upper_pred, upper_value); + } } static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, TypeTableEntry *actual_type, -- cgit v1.2.3