mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
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
This commit is contained in:
parent
8614397110
commit
13c6a58a61
4 changed files with 99 additions and 22 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
|||
build/
|
||||
build2/
|
||||
build-release/
|
||||
/.cproject
|
||||
/.project
|
||||
|
|
|
|||
|
|
@ -1257,6 +1257,7 @@ enum ZigLLVMFnId {
|
|||
ZigLLVMFnIdClz,
|
||||
ZigLLVMFnIdOverflowArithmetic,
|
||||
ZigLLVMFnIdOverflowArithmeticPanic,
|
||||
ZigLLVMFnIdBoundsCheck,
|
||||
};
|
||||
|
||||
enum AddSubMul {
|
||||
|
|
@ -1280,6 +1281,10 @@ struct ZigLLVMFnKey {
|
|||
uint32_t bit_count;
|
||||
bool is_signed;
|
||||
} overflow_arithmetic;
|
||||
struct {
|
||||
LLVMIntPredicate pred;
|
||||
uint32_t bit_count;
|
||||
} bounds_check;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4145,6 +4145,9 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
|
|||
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);
|
||||
case ZigLLVMFnIdBoundsCheck:
|
||||
return (uint32_t)(x.data.bounds_check.pred) * (uint32_t)3146725107 +
|
||||
x.data.bounds_check.bit_count * (uint32_t)2904561957;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
|
@ -4162,6 +4165,9 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
|
|||
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);
|
||||
case ZigLLVMFnIdBoundsCheck:
|
||||
return a.data.bounds_check.pred == b.data.bounds_check.pred &&
|
||||
a.data.bounds_check.bit_count == b.data.bounds_check.bit_count;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
|
|
|||
109
src/codegen.cpp
109
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();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
LLVMValueRef target_val = LLVMGetParam(fn_val, 0);
|
||||
LLVMValueRef bound_val = LLVMGetParam(fn_val, 1);
|
||||
|
||||
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, "");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue