diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2018-01-25 11:51:41 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2018-01-25 11:51:41 -0500 |
| commit | 47be64af5add5c146541c16dbb043ddf97f97d34 (patch) | |
| tree | 3fabcb50c94b254a71cdbf009f29ad1ece6b1f67 /src/codegen.cpp | |
| parent | 4556f448060b19492d7b104ff01585241ba9c256 (diff) | |
| parent | f7670882aff5fb3a943057edd9da34d053b5fe59 (diff) | |
| download | zig-47be64af5add5c146541c16dbb043ddf97f97d34.tar.gz zig-47be64af5add5c146541c16dbb043ddf97f97d34.zip | |
Merge remote-tracking branch 'origin/master' into llvm6
Diffstat (limited to 'src/codegen.cpp')
| -rw-r--r-- | src/codegen.cpp | 351 |
1 files changed, 270 insertions, 81 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index 15423d6315..b1412b2b59 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -485,11 +485,14 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { addLLVMFnAttr(fn_table_entry->llvm_value, "naked"); } else { LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc)); - if (fn_type->data.fn.fn_type_id.cc == CallingConventionCold) { - ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value); - } } + bool want_cold = fn_table_entry->is_cold || fn_type->data.fn.fn_type_id.cc == CallingConventionCold; + if (want_cold) { + ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value); + } + + LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage)); if (linkage == GlobalLinkageIdInternal) { @@ -803,7 +806,7 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) { return true; } -static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) { +static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) { if (g->build_mode == BuildModeFastRelease) return false; @@ -898,7 +901,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace LLVMBuildUnreachable(g->builder); } -static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { +static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) { gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr); } @@ -1137,7 +1140,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { return fn_val; } -static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { +static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val; if (err_ret_trace_val == nullptr) { @@ -1176,7 +1179,7 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block); LLVMPositionBuilderAtEnd(g->builder, bounds_check_fail_block); - gen_debug_safety_crash(g, PanicMsgIdBoundsCheckFailure); + gen_safety_crash(g, PanicMsgIdBoundsCheckFailure); if (upper_value) { LLVMPositionBuilderAtEnd(g->builder, lower_ok_block); @@ -1187,7 +1190,7 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMPositionBuilderAtEnd(g->builder, ok_block); } -static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, TypeTableEntry *actual_type, +static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, TypeTableEntry *actual_type, TypeTableEntry *wanted_type, LLVMValueRef expr_val) { assert(actual_type->id == wanted_type->id); @@ -1206,7 +1209,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ if (actual_bits >= wanted_bits && actual_type->id == TypeTableEntryIdInt && !wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed && - want_debug_safety) + want_runtime_safety) { LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, ""); @@ -1216,7 +1219,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdCastNegativeToUnsigned); + gen_safety_crash(g, PanicMsgIdCastNegativeToUnsigned); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -1240,7 +1243,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, ""); } else if (actual_type->id == TypeTableEntryIdInt) { LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); - if (!want_debug_safety) { + if (!want_runtime_safety) { return trunc_val; } LLVMValueRef orig_val; @@ -1255,7 +1258,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdCastTruncatedData); + gen_safety_crash(g, PanicMsgIdCastTruncatedData); LLVMPositionBuilderAtEnd(g->builder, ok_block); return trunc_val; @@ -1283,7 +1286,7 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdIntegerOverflow); + gen_safety_crash(g, PanicMsgIdIntegerOverflow); LLVMPositionBuilderAtEnd(g->builder, ok_block); return result; @@ -1491,7 +1494,7 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry, LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdShlOverflowedBits); + gen_safety_crash(g, PanicMsgIdShlOverflowedBits); LLVMPositionBuilderAtEnd(g->builder, ok_block); return result; @@ -1516,7 +1519,7 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, TypeTableEntry *type_entry, LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdShrOverflowedBits); + gen_safety_crash(g, PanicMsgIdShrOverflowedBits); LLVMPositionBuilderAtEnd(g->builder, ok_block); return result; @@ -1562,14 +1565,14 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { } } -static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_math, +static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast_math, LLVMValueRef val1, LLVMValueRef val2, TypeTableEntry *type_entry, DivKind div_kind) { ZigLLVMSetFastMath(g->builder, want_fast_math); LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); - if (want_debug_safety && (want_fast_math || type_entry->id != TypeTableEntryIdFloat)) { + if (want_runtime_safety && (want_fast_math || type_entry->id != TypeTableEntryIdFloat)) { LLVMValueRef is_zero_bit; if (type_entry->id == TypeTableEntryIdInt) { is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, ""); @@ -1583,7 +1586,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_m LLVMBuildCondBr(g->builder, is_zero_bit, div_zero_fail_block, div_zero_ok_block); LLVMPositionBuilderAtEnd(g->builder, div_zero_fail_block); - gen_debug_safety_crash(g, PanicMsgIdDivisionByZero); + gen_safety_crash(g, PanicMsgIdDivisionByZero); LLVMPositionBuilderAtEnd(g->builder, div_zero_ok_block); @@ -1600,7 +1603,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_m LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block); LLVMPositionBuilderAtEnd(g->builder, overflow_fail_block); - gen_debug_safety_crash(g, PanicMsgIdIntegerOverflow); + gen_safety_crash(g, PanicMsgIdIntegerOverflow); LLVMPositionBuilderAtEnd(g->builder, overflow_ok_block); } @@ -1612,7 +1615,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_m case DivKindFloat: return result; case DivKindExact: - if (want_debug_safety) { + if (want_runtime_safety) { LLVMValueRef floored = gen_floor(g, result, type_entry); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); @@ -1621,7 +1624,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_m LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdExactDivisionRemainder); + gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -1669,7 +1672,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_m return LLVMBuildUDiv(g->builder, val1, val2, ""); } case DivKindExact: - if (want_debug_safety) { + if (want_runtime_safety) { LLVMValueRef remainder_val; if (type_entry->data.integral.is_signed) { remainder_val = LLVMBuildSRem(g->builder, val1, val2, ""); @@ -1683,7 +1686,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_m LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdExactDivisionRemainder); + gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -1721,14 +1724,14 @@ enum RemKind { RemKindMod, }; -static LLVMValueRef gen_rem(CodeGen *g, bool want_debug_safety, bool want_fast_math, +static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast_math, LLVMValueRef val1, LLVMValueRef val2, TypeTableEntry *type_entry, RemKind rem_kind) { ZigLLVMSetFastMath(g->builder, want_fast_math); LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); - if (want_debug_safety) { + if (want_runtime_safety) { LLVMValueRef is_zero_bit; if (type_entry->id == TypeTableEntryIdInt) { LLVMIntPredicate pred = type_entry->data.integral.is_signed ? LLVMIntSLE : LLVMIntEQ; @@ -1743,7 +1746,7 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_debug_safety, bool want_fast_m LLVMBuildCondBr(g->builder, is_zero_bit, rem_zero_fail_block, rem_zero_ok_block); LLVMPositionBuilderAtEnd(g->builder, rem_zero_fail_block); - gen_debug_safety_crash(g, PanicMsgIdRemainderDivisionByZero); + gen_safety_crash(g, PanicMsgIdRemainderDivisionByZero); LLVMPositionBuilderAtEnd(g->builder, rem_zero_ok_block); } @@ -1789,8 +1792,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, op_id == IrBinOpBitShiftRightExact); TypeTableEntry *type_entry = op1->value.type; - bool want_debug_safety = bin_op_instruction->safety_check_on && - ir_want_debug_safety(g, &bin_op_instruction->base); + bool want_runtime_safety = bin_op_instruction->safety_check_on && + ir_want_runtime_safety(g, &bin_op_instruction->base); LLVMValueRef op1_value = ir_llvm_value(g, op1); LLVMValueRef op2_value = ir_llvm_value(g, op2); @@ -1838,7 +1841,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, bool is_wrapping = (op_id == IrBinOpAddWrap); if (is_wrapping) { return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); - } else if (want_debug_safety) { + } else if (want_runtime_safety) { return gen_overflow_op(g, type_entry, AddSubMulAdd, op1_value, op2_value); } else if (type_entry->data.integral.is_signed) { return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); @@ -1863,7 +1866,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy); if (is_sloppy) { return LLVMBuildShl(g->builder, op1_value, op2_casted, ""); - } else if (want_debug_safety) { + } else if (want_runtime_safety) { return gen_overflow_shl_op(g, type_entry, op1_value, op2_casted); } else if (type_entry->data.integral.is_signed) { return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, ""); @@ -1884,7 +1887,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, } else { return LLVMBuildLShr(g->builder, op1_value, op2_casted, ""); } - } else if (want_debug_safety) { + } else if (want_runtime_safety) { return gen_overflow_shr_op(g, type_entry, op1_value, op2_casted); } else if (type_entry->data.integral.is_signed) { return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, ""); @@ -1901,7 +1904,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, bool is_wrapping = (op_id == IrBinOpSubWrap); if (is_wrapping) { return LLVMBuildSub(g->builder, op1_value, op2_value, ""); - } else if (want_debug_safety) { + } else if (want_runtime_safety) { return gen_overflow_op(g, type_entry, AddSubMulSub, op1_value, op2_value); } else if (type_entry->data.integral.is_signed) { return LLVMBuildNSWSub(g->builder, op1_value, op2_value, ""); @@ -1920,7 +1923,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, bool is_wrapping = (op_id == IrBinOpMultWrap); if (is_wrapping) { return LLVMBuildMul(g->builder, op1_value, op2_value, ""); - } else if (want_debug_safety) { + } else if (want_runtime_safety) { return gen_overflow_op(g, type_entry, AddSubMulMul, op1_value, op2_value); } else if (type_entry->data.integral.is_signed) { return LLVMBuildNSWMul(g->builder, op1_value, op2_value, ""); @@ -1931,22 +1934,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, zig_unreachable(); } case IrBinOpDivUnspecified: - return gen_div(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), + return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), op1_value, op2_value, type_entry, DivKindFloat); case IrBinOpDivExact: - return gen_div(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), + return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), op1_value, op2_value, type_entry, DivKindExact); case IrBinOpDivTrunc: - return gen_div(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), + return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), op1_value, op2_value, type_entry, DivKindTrunc); case IrBinOpDivFloor: - return gen_div(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), + return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), op1_value, op2_value, type_entry, DivKindFloor); case IrBinOpRemRem: - return gen_rem(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), + return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), op1_value, op2_value, type_entry, RemKindRem); case IrBinOpRemMod: - return gen_rem(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), + return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), op1_value, op2_value, type_entry, RemKindMod); } zig_unreachable(); @@ -2004,7 +2007,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, new_len = LLVMBuildMul(g->builder, src_len, src_size_val, ""); } else if (src_size == 1) { LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, dest_size, false); - if (ir_want_debug_safety(g, &cast_instruction->base)) { + if (ir_want_runtime_safety(g, &cast_instruction->base)) { LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, ""); LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref); LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); @@ -2013,7 +2016,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdSliceWidenRemainder); + gen_safety_crash(g, PanicMsgIdSliceWidenRemainder); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -2108,7 +2111,7 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa int_type = actual_type; } LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), int_type, + return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), int_type, instruction->base.value.type, target_val); } @@ -2130,7 +2133,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type; LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), + return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), instruction->target->value.type, tag_int_type, target_val); } @@ -2144,7 +2147,7 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - if (ir_want_debug_safety(g, &instruction->base)) { + if (ir_want_runtime_safety(g, &instruction->base)) { LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, ""); LLVMValueRef ok_bit; @@ -2168,7 +2171,7 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdInvalidErrorCode); + gen_safety_crash(g, PanicMsgIdInvalidErrorCode); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -2185,11 +2188,11 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I LLVMValueRef target_val = ir_llvm_value(g, instruction->target); if (actual_type->id == TypeTableEntryIdPureError) { - return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), + return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), g->err_tag_type, wanted_type, target_val); } else if (actual_type->id == TypeTableEntryIdErrorUnion) { if (!type_has_bits(actual_type->data.error.child_type)) { - return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), + return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), g->err_tag_type, wanted_type, target_val); } else { zig_panic("TODO"); @@ -2202,8 +2205,8 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable, IrInstructionUnreachable *unreachable_instruction) { - if (ir_want_debug_safety(g, &unreachable_instruction->base)) { - gen_debug_safety_crash(g, PanicMsgIdUnreachable); + if (ir_want_runtime_safety(g, &unreachable_instruction->base)) { + gen_safety_crash(g, PanicMsgIdUnreachable); } else { LLVMBuildUnreachable(g->builder); } @@ -2245,7 +2248,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst } else if (expr_type->id == TypeTableEntryIdInt) { if (op_id == IrUnOpNegationWrap) { return LLVMBuildNeg(g->builder, expr, ""); - } else if (ir_want_debug_safety(g, &un_op_instruction->base)) { + } else if (ir_want_runtime_safety(g, &un_op_instruction->base)) { LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr)); return gen_overflow_op(g, expr_type, AddSubMulSub, zero, expr); } else if (expr_type->data.integral.is_signed) { @@ -2314,7 +2317,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, var->align_bytes, 0, 0); gen_assign_raw(g, var->value_ref, var_ptr_type, ir_llvm_value(g, init_value)); } else { - bool want_safe = ir_want_debug_safety(g, &decl_var_instruction->base); + bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); if (want_safe) { TypeTableEntry *usize = g->builtin_types.entry_usize; uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref); @@ -2406,7 +2409,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI if (!type_has_bits(array_type)) return nullptr; - bool safety_check_on = ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on; + bool safety_check_on = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on; if (array_type->id == TypeTableEntryIdArray) { if (safety_check_on) { @@ -2590,7 +2593,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab return bitcasted_union_field_ptr; } - if (ir_want_debug_safety(g, &instruction->base)) { + if (ir_want_runtime_safety(g, &instruction->base)) { LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, ""); @@ -2603,7 +2606,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block); LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_debug_safety_crash(g, PanicMsgIdBadUnionField); + gen_safety_crash(g, PanicMsgIdBadUnionField); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -2773,14 +2776,14 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, TypeTableEntry *child_type = maybe_type->data.maybe.child_type; LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value); LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); - if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) { + if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail"); LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdUnwrapMaybeFail); + gen_safety_crash(g, PanicMsgIdUnwrapMaybeFail); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -2910,7 +2913,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI } LLVMValueRef err_val = ir_llvm_value(g, instruction->value); - if (ir_want_debug_safety(g, &instruction->base)) { + if (ir_want_runtime_safety(g, &instruction->base)) { LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val)); LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false); add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val); @@ -2932,7 +2935,7 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); - if (ir_want_debug_safety(g, &instruction->base)) { + if (ir_want_runtime_safety(g, &instruction->base)) { size_t field_count = enum_type->data.enumeration.src_field_count; // if the field_count can't fit in the bits of the enum_type, then it can't possibly @@ -2985,8 +2988,8 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I LLVMValueRef target_val = ir_llvm_value(g, instruction->target); assert(target_val); - bool want_debug_safety = ir_want_debug_safety(g, &instruction->base); - if (!want_debug_safety) { + bool want_runtime_safety = ir_want_runtime_safety(g, &instruction->base); + if (!want_runtime_safety) { return target_val; } @@ -3035,7 +3038,7 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_debug_safety_crash(g, PanicMsgIdIncorrectAlignment); + gen_safety_crash(g, PanicMsgIdIncorrectAlignment); LLVMPositionBuilderAtEnd(g->builder, ok_block); @@ -3173,7 +3176,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr; - bool want_debug_safety = instruction->safety_check_on && ir_want_debug_safety(g, &instruction->base); + bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); if (array_type->id == TypeTableEntryIdArray) { LLVMValueRef start_val = ir_llvm_value(g, instruction->start); @@ -3184,7 +3187,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false); } - if (want_debug_safety) { + if (want_runtime_safety) { add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); if (instruction->end) { LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref, @@ -3195,7 +3198,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst if (!type_has_bits(array_type)) { LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); - // TODO if debug safety is on, store 0xaaaaaaa in ptr field + // TODO if runtime safety is on, store 0xaaaaaaa in ptr field LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); gen_store_untyped(g, len_value, len_field_ptr, 0, false); return tmp_struct_ptr; @@ -3219,7 +3222,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst LLVMValueRef start_val = ir_llvm_value(g, instruction->start); LLVMValueRef end_val = ir_llvm_value(g, instruction->end); - if (want_debug_safety) { + if (want_runtime_safety) { add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); } @@ -3243,7 +3246,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst assert(len_index != SIZE_MAX); LLVMValueRef prev_end = nullptr; - if (!instruction->end || want_debug_safety) { + if (!instruction->end || want_runtime_safety) { LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, ""); prev_end = gen_load_untyped(g, src_len_ptr, 0, false, ""); } @@ -3256,7 +3259,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst end_val = prev_end; } - if (want_debug_safety) { + if (want_runtime_safety) { assert(prev_end); add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); if (instruction->end) { @@ -3429,7 +3432,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); - if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on && g->error_decls.length > 1) { + if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->error_decls.length > 1) { LLVMValueRef err_val; if (type_has_bits(child_type)) { LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); @@ -3444,7 +3447,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); LLVMPositionBuilderAtEnd(g->builder, err_block); - gen_debug_safety_crash_for_err(g, err_val); + gen_safety_crash_for_err(g, err_val); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -3656,7 +3659,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdToPtrType: case IrInstructionIdPtrTypeChild: case IrInstructionIdFieldPtr: - case IrInstructionIdSetDebugSafety: + case IrInstructionIdSetCold: + case IrInstructionIdSetRuntimeSafety: case IrInstructionIdSetFloatMode: case IrInstructionIdArrayType: case IrInstructionIdSliceType: @@ -5233,7 +5237,8 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int - create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); + create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); + create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2); create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2); @@ -5788,7 +5793,76 @@ static const char *c_int_type_names[] = { "unsigned long long", }; -static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { +struct GenH { + ZigList<TypeTableEntry *> types_to_declare; +}; + +static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry) { + if (type_entry->gen_h_loop_flag) + return; + type_entry->gen_h_loop_flag = true; + + switch (type_entry->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdVar: + case TypeTableEntryIdMetaType: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdArgTuple: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + zig_unreachable(); + case TypeTableEntryIdVoid: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdBool: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + return; + case TypeTableEntryIdOpaque: + gen_h->types_to_declare.append(type_entry); + return; + case TypeTableEntryIdStruct: + for (uint32_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { + TypeStructField *field = &type_entry->data.structure.fields[i]; + prepend_c_type_to_decl_list(g, gen_h, field->type_entry); + } + gen_h->types_to_declare.append(type_entry); + return; + case TypeTableEntryIdUnion: + for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { + TypeUnionField *field = &type_entry->data.unionation.fields[i]; + prepend_c_type_to_decl_list(g, gen_h, field->type_entry); + } + gen_h->types_to_declare.append(type_entry); + return; + case TypeTableEntryIdEnum: + prepend_c_type_to_decl_list(g, gen_h, type_entry->data.enumeration.tag_int_type); + gen_h->types_to_declare.append(type_entry); + return; + case TypeTableEntryIdPointer: + prepend_c_type_to_decl_list(g, gen_h, type_entry->data.pointer.child_type); + return; + case TypeTableEntryIdArray: + prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type); + return; + case TypeTableEntryIdMaybe: + prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type); + return; + case TypeTableEntryIdFn: + for (size_t i = 0; i < type_entry->data.fn.fn_type_id.param_count; i += 1) { + prepend_c_type_to_decl_list(g, gen_h, type_entry->data.fn.fn_type_id.param_info[i].type); + } + prepend_c_type_to_decl_list(g, gen_h, type_entry->data.fn.fn_type_id.return_type); + return; + } +} + +static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf *out_buf) { assert(type_entry); for (size_t i = 0; i < array_length(c_int_type_names); i += 1) { @@ -5816,6 +5890,8 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { return; } + prepend_c_type_to_decl_list(g, gen_h, type_entry); + switch (type_entry->id) { case TypeTableEntryIdVoid: buf_init_from_str(out_buf, "void"); @@ -5856,7 +5932,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { { Buf child_buf = BUF_INIT; TypeTableEntry *child_type = type_entry->data.pointer.child_type; - get_c_type(g, child_type, &child_buf); + get_c_type(g, gen_h, child_type, &child_buf); const char *const_str = type_entry->data.pointer.is_const ? "const " : ""; buf_resize(out_buf, 0); @@ -5872,23 +5948,47 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { } else if (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn) { - return get_c_type(g, child_type, out_buf); + return get_c_type(g, gen_h, child_type, out_buf); } else { zig_unreachable(); } } case TypeTableEntryIdStruct: + { + buf_init_from_str(out_buf, "struct "); + buf_append_buf(out_buf, &type_entry->name); + return; + } + case TypeTableEntryIdUnion: + { + buf_init_from_str(out_buf, "union "); + buf_append_buf(out_buf, &type_entry->name); + return; + } + case TypeTableEntryIdEnum: + { + buf_init_from_str(out_buf, "enum "); + buf_append_buf(out_buf, &type_entry->name); + return; + } case TypeTableEntryIdOpaque: { - // TODO add to table of structs we need to declare buf_init_from_buf(out_buf, &type_entry->name); return; } case TypeTableEntryIdArray: + { + TypeTableEntryArray *array_data = &type_entry->data.array; + + Buf *child_buf = buf_alloc(); + get_c_type(g, gen_h, array_data->child_type, child_buf); + + buf_resize(out_buf, 0); + buf_appendf(out_buf, "%s", buf_ptr(child_buf)); + return; + } case TypeTableEntryIdErrorUnion: case TypeTableEntryIdPureError: - case TypeTableEntryIdEnum: - case TypeTableEntryIdUnion: case TypeTableEntryIdFn: zig_panic("TODO implement get_c_type for more types"); case TypeTableEntryIdInvalid: @@ -5942,6 +6042,9 @@ static void gen_h_file(CodeGen *g) { if (!g->want_h_file) return; + GenH gen_h_data = {0}; + GenH *gen_h = &gen_h_data; + codegen_add_time_event(g, "Generate .h"); assert(!g->is_test_build); @@ -5971,7 +6074,7 @@ static void gen_h_file(CodeGen *g) { FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; Buf return_type_c = BUF_INIT; - get_c_type(g, fn_type_id->return_type, &return_type_c); + get_c_type(g, gen_h, fn_type_id->return_type, &return_type_c); buf_appendf(&h_buf, "%s %s %s(", buf_ptr(export_macro), @@ -5987,9 +6090,16 @@ static void gen_h_file(CodeGen *g) { const char *comma_str = (param_i == 0) ? "" : ", "; const char *restrict_str = param_info->is_noalias ? "restrict" : ""; - get_c_type(g, param_info->type, ¶m_type_c); - buf_appendf(&h_buf, "%s%s%s %s", comma_str, buf_ptr(¶m_type_c), - restrict_str, buf_ptr(param_name)); + get_c_type(g, gen_h, param_info->type, ¶m_type_c); + + if (param_info->type->id == TypeTableEntryIdArray) { + // Arrays decay to pointers + buf_appendf(&h_buf, "%s%s%s %s[]", comma_str, buf_ptr(¶m_type_c), + restrict_str, buf_ptr(param_name)); + } else { + buf_appendf(&h_buf, "%s%s%s %s", comma_str, buf_ptr(¶m_type_c), + restrict_str, buf_ptr(param_name)); + } } buf_appendf(&h_buf, ")"); } else { @@ -6027,6 +6137,85 @@ static void gen_h_file(CodeGen *g) { fprintf(out_h, "#endif\n"); fprintf(out_h, "\n"); + for (size_t type_i = 0; type_i < gen_h->types_to_declare.length; type_i += 1) { + TypeTableEntry *type_entry = gen_h->types_to_declare.at(type_i); + switch (type_entry->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdVar: + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdArray: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdArgTuple: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdFn: + zig_unreachable(); + case TypeTableEntryIdEnum: + assert(type_entry->data.enumeration.layout == ContainerLayoutExtern); + fprintf(out_h, "enum %s {\n", buf_ptr(&type_entry->name)); + for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) { + TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i]; + Buf *value_buf = buf_alloc(); + bigint_append_buf(value_buf, &enum_field->value, 10); + fprintf(out_h, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf)); + if (field_i != type_entry->data.enumeration.src_field_count - 1) { + fprintf(out_h, ","); + } + fprintf(out_h, "\n"); + } + fprintf(out_h, "};\n\n"); + break; + case TypeTableEntryIdStruct: + assert(type_entry->data.structure.layout == ContainerLayoutExtern); + fprintf(out_h, "struct %s {\n", buf_ptr(&type_entry->name)); + for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) { + TypeStructField *struct_field = &type_entry->data.structure.fields[field_i]; + + Buf *type_name_buf = buf_alloc(); + get_c_type(g, gen_h, struct_field->type_entry, type_name_buf); + + if (struct_field->type_entry->id == TypeTableEntryIdArray) { + fprintf(out_h, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf), + buf_ptr(struct_field->name), + struct_field->type_entry->data.array.len); + } else { + fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name)); + } + + } + fprintf(out_h, "};\n\n"); + break; + case TypeTableEntryIdUnion: + assert(type_entry->data.unionation.layout == ContainerLayoutExtern); + fprintf(out_h, "union %s {\n", buf_ptr(&type_entry->name)); + for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) { + TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i]; + + Buf *type_name_buf = buf_alloc(); + get_c_type(g, gen_h, union_field->type_entry, type_name_buf); + fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name)); + } + fprintf(out_h, "};\n\n"); + break; + case TypeTableEntryIdOpaque: + fprintf(out_h, "struct %s;\n\n", buf_ptr(&type_entry->name)); + break; + } + } + fprintf(out_h, "%s", buf_ptr(&h_buf)); fprintf(out_h, "\n#endif\n"); |
