| author | |
| committer | |
| log | 0e815c652d7908be62612bb931c2ee9698dd41da |
| tree | 2fdefb0b7575805af532ed4fb60057d1cb3dc206 |
| parent | 61fe307d0f05eea901577900f4ab2bdaf0ffb35f |
| parent | d4b6a53327352dc239644dab0ec2abbe3a1b1be9 |
| signature |
compiler: include error trace in all functions, implement for x86_64 backend12 files changed, 174 insertions(+), 106 deletions(-)
lib/std/builtin.zig+2-1| ... | @@ -1150,9 +1150,10 @@ pub const panicInactiveUnionField = Panic.inactiveUnionField; | ... | @@ -1150,9 +1150,10 @@ pub const panicInactiveUnionField = Panic.inactiveUnionField; |
| 1150 | /// To be deleted after zig1.wasm is updated. | 1150 | /// To be deleted after zig1.wasm is updated. |
| 1151 | pub const panic_messages = Panic.messages; | 1151 | pub const panic_messages = Panic.messages; |
| 1152 | 1152 | ||
| 1153 | pub noinline fn returnError(st: *StackTrace) void { | 1153 | pub noinline fn returnError() void { |
| 1154 | @branchHint(.unlikely); | 1154 | @branchHint(.unlikely); |
| 1155 | @setRuntimeSafety(false); | 1155 | @setRuntimeSafety(false); |
| 1156 | const st = @errorReturnTrace().?; | ||
| 1156 | if (st.index < st.instruction_addresses.len) | 1157 | if (st.index < st.instruction_addresses.len) |
| 1157 | st.instruction_addresses[st.index] = @returnAddress(); | 1158 | st.instruction_addresses[st.index] = @returnAddress(); |
| 1158 | st.index += 1; | 1159 | st.index += 1; |
src/InternPool.zig+7-18| ... | @@ -2294,17 +2294,6 @@ pub const Key = union(enum) { | ... | @@ -2294,17 +2294,6 @@ pub const Key = union(enum) { |
| 2294 | return @atomicLoad(FuncAnalysis, func.analysisPtr(ip), .unordered); | 2294 | return @atomicLoad(FuncAnalysis, func.analysisPtr(ip), .unordered); |
| 2295 | } | 2295 | } |
| 2296 | 2296 | ||
| 2297 | pub fn setCallsOrAwaitsErrorableFn(func: Func, ip: *InternPool, value: bool) void { | ||
| 2298 | const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex; | ||
| 2299 | extra_mutex.lock(); | ||
| 2300 | defer extra_mutex.unlock(); | ||
| 2301 | |||
| 2302 | const analysis_ptr = func.analysisPtr(ip); | ||
| 2303 | var analysis = analysis_ptr.*; | ||
| 2304 | analysis.calls_or_awaits_errorable_fn = value; | ||
| 2305 | @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); | ||
| 2306 | } | ||
| 2307 | |||
| 2308 | pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void { | 2297 | pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void { |
| 2309 | const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex; | 2298 | const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex; |
| 2310 | extra_mutex.lock(); | 2299 | extra_mutex.lock(); |
| ... | @@ -5975,7 +5964,7 @@ pub const FuncAnalysis = packed struct(u32) { | ... | @@ -5975,7 +5964,7 @@ pub const FuncAnalysis = packed struct(u32) { |
| 5975 | is_analyzed: bool, | 5964 | is_analyzed: bool, |
| 5976 | branch_hint: std.builtin.BranchHint, | 5965 | branch_hint: std.builtin.BranchHint, |
| 5977 | is_noinline: bool, | 5966 | is_noinline: bool, |
| 5978 | calls_or_awaits_errorable_fn: bool, | 5967 | has_error_trace: bool, |
| 5979 | /// True if this function has an inferred error set. | 5968 | /// True if this function has an inferred error set. |
| 5980 | inferred_error_set: bool, | 5969 | inferred_error_set: bool, |
| 5981 | disable_instrumentation: bool, | 5970 | disable_instrumentation: bool, |
| ... | @@ -9007,7 +8996,7 @@ pub fn getFuncDecl( | ... | @@ -9007,7 +8996,7 @@ pub fn getFuncDecl( |
| 9007 | .is_analyzed = false, | 8996 | .is_analyzed = false, |
| 9008 | .branch_hint = .none, | 8997 | .branch_hint = .none, |
| 9009 | .is_noinline = key.is_noinline, | 8998 | .is_noinline = key.is_noinline, |
| 9010 | .calls_or_awaits_errorable_fn = false, | 8999 | .has_error_trace = false, |
| 9011 | .inferred_error_set = false, | 9000 | .inferred_error_set = false, |
| 9012 | .disable_instrumentation = false, | 9001 | .disable_instrumentation = false, |
| 9013 | }, | 9002 | }, |
| ... | @@ -9116,7 +9105,7 @@ pub fn getFuncDeclIes( | ... | @@ -9116,7 +9105,7 @@ pub fn getFuncDeclIes( |
| 9116 | .is_analyzed = false, | 9105 | .is_analyzed = false, |
| 9117 | .branch_hint = .none, | 9106 | .branch_hint = .none, |
| 9118 | .is_noinline = key.is_noinline, | 9107 | .is_noinline = key.is_noinline, |
| 9119 | .calls_or_awaits_errorable_fn = false, | 9108 | .has_error_trace = false, |
| 9120 | .inferred_error_set = true, | 9109 | .inferred_error_set = true, |
| 9121 | .disable_instrumentation = false, | 9110 | .disable_instrumentation = false, |
| 9122 | }, | 9111 | }, |
| ... | @@ -9312,7 +9301,7 @@ pub fn getFuncInstance( | ... | @@ -9312,7 +9301,7 @@ pub fn getFuncInstance( |
| 9312 | .is_analyzed = false, | 9301 | .is_analyzed = false, |
| 9313 | .branch_hint = .none, | 9302 | .branch_hint = .none, |
| 9314 | .is_noinline = arg.is_noinline, | 9303 | .is_noinline = arg.is_noinline, |
| 9315 | .calls_or_awaits_errorable_fn = false, | 9304 | .has_error_trace = false, |
| 9316 | .inferred_error_set = false, | 9305 | .inferred_error_set = false, |
| 9317 | .disable_instrumentation = false, | 9306 | .disable_instrumentation = false, |
| 9318 | }, | 9307 | }, |
| ... | @@ -9410,7 +9399,7 @@ pub fn getFuncInstanceIes( | ... | @@ -9410,7 +9399,7 @@ pub fn getFuncInstanceIes( |
| 9410 | .is_analyzed = false, | 9399 | .is_analyzed = false, |
| 9411 | .branch_hint = .none, | 9400 | .branch_hint = .none, |
| 9412 | .is_noinline = arg.is_noinline, | 9401 | .is_noinline = arg.is_noinline, |
| 9413 | .calls_or_awaits_errorable_fn = false, | 9402 | .has_error_trace = false, |
| 9414 | .inferred_error_set = true, | 9403 | .inferred_error_set = true, |
| 9415 | .disable_instrumentation = false, | 9404 | .disable_instrumentation = false, |
| 9416 | }, | 9405 | }, |
| ... | @@ -12174,7 +12163,7 @@ pub fn funcAnalysisUnordered(ip: *const InternPool, func: Index) FuncAnalysis { | ... | @@ -12174,7 +12163,7 @@ pub fn funcAnalysisUnordered(ip: *const InternPool, func: Index) FuncAnalysis { |
| 12174 | return @atomicLoad(FuncAnalysis, ip.funcAnalysisPtr(func), .unordered); | 12163 | return @atomicLoad(FuncAnalysis, ip.funcAnalysisPtr(func), .unordered); |
| 12175 | } | 12164 | } |
| 12176 | 12165 | ||
| 12177 | pub fn funcSetCallsOrAwaitsErrorableFn(ip: *InternPool, func: Index) void { | 12166 | pub fn funcSetHasErrorTrace(ip: *InternPool, func: Index, has_error_trace: bool) void { |
| 12178 | const unwrapped_func = func.unwrap(ip); | 12167 | const unwrapped_func = func.unwrap(ip); |
| 12179 | const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex; | 12168 | const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex; |
| 12180 | extra_mutex.lock(); | 12169 | extra_mutex.lock(); |
| ... | @@ -12182,7 +12171,7 @@ pub fn funcSetCallsOrAwaitsErrorableFn(ip: *InternPool, func: Index) void { | ... | @@ -12182,7 +12171,7 @@ pub fn funcSetCallsOrAwaitsErrorableFn(ip: *InternPool, func: Index) void { |
| 12182 | 12171 | ||
| 12183 | const analysis_ptr = ip.funcAnalysisPtr(func); | 12172 | const analysis_ptr = ip.funcAnalysisPtr(func); |
| 12184 | var analysis = analysis_ptr.*; | 12173 | var analysis = analysis_ptr.*; |
| 12185 | analysis.calls_or_awaits_errorable_fn = true; | 12174 | analysis.has_error_trace = has_error_trace; |
| 12186 | @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); | 12175 | @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); |
| 12187 | } | 12176 | } |
| 12188 | 12177 |
src/Sema.zig+19-24| ... | @@ -7198,14 +7198,6 @@ fn zirCall( | ... | @@ -7198,14 +7198,6 @@ fn zirCall( |
| 7198 | const call_dbg_node: Zir.Inst.Index = @enumFromInt(@intFromEnum(inst) - 1); | 7198 | const call_dbg_node: Zir.Inst.Index = @enumFromInt(@intFromEnum(inst) - 1); |
| 7199 | const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); | 7199 | const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); |
| 7200 | 7200 | ||
| 7201 | switch (sema.owner.unwrap()) { | ||
| 7202 | .@"comptime", .type, .memoized_state, .nav_ty, .nav_val => input_is_error = false, | ||
| 7203 | .func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) { | ||
| 7204 | // No errorable fn actually called; we have no error return trace | ||
| 7205 | input_is_error = false; | ||
| 7206 | }, | ||
| 7207 | } | ||
| 7208 | |||
| 7209 | if (block.ownerModule().error_tracing and | 7201 | if (block.ownerModule().error_tracing and |
| 7210 | !block.isComptime() and !block.is_typeof and (input_is_error or pop_error_return_trace)) | 7202 | !block.isComptime() and !block.is_typeof and (input_is_error or pop_error_return_trace)) |
| 7211 | { | 7203 | { |
| ... | @@ -7872,6 +7864,12 @@ fn analyzeCall( | ... | @@ -7872,6 +7864,12 @@ fn analyzeCall( |
| 7872 | } | 7864 | } |
| 7873 | break :msg msg; | 7865 | break :msg msg; |
| 7874 | }); | 7866 | }); |
| 7867 | if (func_ty_info.cc == .auto) { | ||
| 7868 | switch (sema.owner.unwrap()) { | ||
| 7869 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, | ||
| 7870 | .func => |owner_func| ip.funcSetHasErrorTrace(owner_func, true), | ||
| 7871 | } | ||
| 7872 | } | ||
| 7875 | for (args, 0..) |arg, arg_idx| { | 7873 | for (args, 0..) |arg, arg_idx| { |
| 7876 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg); | 7874 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg); |
| 7877 | } | 7875 | } |
| ... | @@ -7946,13 +7944,6 @@ fn analyzeCall( | ... | @@ -7946,13 +7944,6 @@ fn analyzeCall( |
| 7946 | try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern()); | 7944 | try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern()); |
| 7947 | } | 7945 | } |
| 7948 | 7946 | ||
| 7949 | switch (sema.owner.unwrap()) { | ||
| 7950 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, | ||
| 7951 | .func => |owner_func| if (resolved_ret_ty.isError(zcu)) { | ||
| 7952 | ip.funcSetCallsOrAwaitsErrorableFn(owner_func); | ||
| 7953 | }, | ||
| 7954 | } | ||
| 7955 | |||
| 7956 | const call_tag: Air.Inst.Tag = switch (modifier) { | 7947 | const call_tag: Air.Inst.Tag = switch (modifier) { |
| 7957 | .auto, .no_async => .call, | 7948 | .auto, .no_async => .call, |
| 7958 | .never_tail => .call_never_tail, | 7949 | .never_tail => .call_never_tail, |
| ... | @@ -19706,16 +19697,16 @@ fn retWithErrTracing( | ... | @@ -19706,16 +19697,16 @@ fn retWithErrTracing( |
| 19706 | .bool_false => false, | 19697 | .bool_false => false, |
| 19707 | else => true, | 19698 | else => true, |
| 19708 | }; | 19699 | }; |
| 19700 | |||
| 19701 | // This means we're returning something that might be an error! | ||
| 19702 | // This should only be possible with the `auto` cc, so we definitely have an error trace. | ||
| 19703 | assert(pt.zcu.intern_pool.funcAnalysisUnordered(sema.owner.unwrap().func).has_error_trace); | ||
| 19704 | |||
| 19709 | const gpa = sema.gpa; | 19705 | const gpa = sema.gpa; |
| 19710 | const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace); | ||
| 19711 | try stack_trace_ty.resolveFields(pt); | ||
| 19712 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); | ||
| 19713 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | ||
| 19714 | const return_err_fn = Air.internedToRef(try sema.getBuiltin(src, .returnError)); | 19706 | const return_err_fn = Air.internedToRef(try sema.getBuiltin(src, .returnError)); |
| 19715 | const args: [1]Air.Inst.Ref = .{err_return_trace}; | ||
| 19716 | 19707 | ||
| 19717 | if (!need_check) { | 19708 | if (!need_check) { |
| 19718 | try sema.callBuiltin(block, src, return_err_fn, .never_inline, &args, .@"error return"); | 19709 | try sema.callBuiltin(block, src, return_err_fn, .never_inline, &.{}, .@"error return"); |
| 19719 | _ = try block.addUnOp(ret_tag, operand); | 19710 | _ = try block.addUnOp(ret_tag, operand); |
| 19720 | return; | 19711 | return; |
| 19721 | } | 19712 | } |
| ... | @@ -19726,7 +19717,7 @@ fn retWithErrTracing( | ... | @@ -19726,7 +19717,7 @@ fn retWithErrTracing( |
| 19726 | 19717 | ||
| 19727 | var else_block = block.makeSubBlock(); | 19718 | var else_block = block.makeSubBlock(); |
| 19728 | defer else_block.instructions.deinit(gpa); | 19719 | defer else_block.instructions.deinit(gpa); |
| 19729 | try sema.callBuiltin(&else_block, src, return_err_fn, .never_inline, &args, .@"error return"); | 19720 | try sema.callBuiltin(&else_block, src, return_err_fn, .never_inline, &.{}, .@"error return"); |
| 19730 | _ = try else_block.addUnOp(ret_tag, operand); | 19721 | _ = try else_block.addUnOp(ret_tag, operand); |
| 19731 | 19722 | ||
| 19732 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len + | 19723 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len + |
| ... | @@ -19837,7 +19828,7 @@ fn restoreErrRetIndex(sema: *Sema, start_block: *Block, src: LazySrcLoc, target_ | ... | @@ -19837,7 +19828,7 @@ fn restoreErrRetIndex(sema: *Sema, start_block: *Block, src: LazySrcLoc, target_ |
| 19837 | return; | 19828 | return; |
| 19838 | } | 19829 | } |
| 19839 | 19830 | ||
| 19840 | if (!zcu.intern_pool.funcAnalysisUnordered(sema.owner.unwrap().func).calls_or_awaits_errorable_fn) return; | 19831 | if (!zcu.intern_pool.funcAnalysisUnordered(sema.owner.unwrap().func).has_error_trace) return; |
| 19841 | if (!start_block.ownerModule().error_tracing) return; | 19832 | if (!start_block.ownerModule().error_tracing) return; |
| 19842 | 19833 | ||
| 19843 | assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere | 19834 | assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere |
| ... | @@ -21123,7 +21114,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { | ... | @@ -21123,7 +21114,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 21123 | const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern()); | 21114 | const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern()); |
| 21124 | 21115 | ||
| 21125 | switch (sema.owner.unwrap()) { | 21116 | switch (sema.owner.unwrap()) { |
| 21126 | .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) { | 21117 | .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) { |
| 21127 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); | 21118 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); |
| 21128 | }, | 21119 | }, |
| 21129 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, | 21120 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, |
| ... | @@ -27096,6 +27087,10 @@ fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPo | ... | @@ -27096,6 +27087,10 @@ fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPo |
| 27096 | const zcu = sema.pt.zcu; | 27087 | const zcu = sema.pt.zcu; |
| 27097 | try sema.ensureMemoizedStateResolved(src, .panic); | 27088 | try sema.ensureMemoizedStateResolved(src, .panic); |
| 27098 | try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call")); | 27089 | try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call")); |
| 27090 | switch (sema.owner.unwrap()) { | ||
| 27091 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, | ||
| 27092 | .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(owner_func, true), | ||
| 27093 | } | ||
| 27099 | return zcu.builtin_decl_values.get(panic_id.toBuiltin()); | 27094 | return zcu.builtin_decl_values.get(panic_id.toBuiltin()); |
| 27100 | } | 27095 | } |
| 27101 | 27096 |
src/Zcu/PerThread.zig+4-6| ... | @@ -2596,7 +2596,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE | ... | @@ -2596,7 +2596,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE |
| 2596 | } | 2596 | } |
| 2597 | 2597 | ||
| 2598 | // reset in case calls to errorable functions are removed. | 2598 | // reset in case calls to errorable functions are removed. |
| 2599 | func.setCallsOrAwaitsErrorableFn(ip, false); | 2599 | ip.funcSetHasErrorTrace(func_index, fn_ty_info.cc == .auto); |
| 2600 | 2600 | ||
| 2601 | // First few indexes of extra are reserved and set at the end. | 2601 | // First few indexes of extra are reserved and set at the end. |
| 2602 | const reserved_count = @typeInfo(Air.ExtraIndex).@"enum".fields.len; | 2602 | const reserved_count = @typeInfo(Air.ExtraIndex).@"enum".fields.len; |
| ... | @@ -2707,11 +2707,9 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE | ... | @@ -2707,11 +2707,9 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE |
| 2707 | 2707 | ||
| 2708 | func.setBranchHint(ip, sema.branch_hint orelse .none); | 2708 | func.setBranchHint(ip, sema.branch_hint orelse .none); |
| 2709 | 2709 | ||
| 2710 | // If we don't get an error return trace from a caller, create our own. | 2710 | if (zcu.comp.config.any_error_tracing and func.analysisUnordered(ip).has_error_trace and fn_ty_info.cc != .auto) { |
| 2711 | if (func.analysisUnordered(ip).calls_or_awaits_errorable_fn and | 2711 | // We're using an error trace, but didn't start out with one from the caller. |
| 2712 | zcu.comp.config.any_error_tracing and | 2712 | // We'll have to create it at the start of the function. |
| 2713 | !sema.fn_ret_ty.isError(zcu)) | ||
| 2714 | { | ||
| 2715 | sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { | 2713 | sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { |
| 2716 | error.ComptimeReturn => unreachable, | 2714 | error.ComptimeReturn => unreachable, |
| 2717 | error.ComptimeBreak => unreachable, | 2715 | error.ComptimeBreak => unreachable, |
src/arch/x86_64/CodeGen.zig+123-40| ... | @@ -33,6 +33,8 @@ const FrameIndex = bits.FrameIndex; | ... | @@ -33,6 +33,8 @@ const FrameIndex = bits.FrameIndex; |
| 33 | 33 | ||
| 34 | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; | 34 | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; |
| 35 | 35 | ||
| 36 | const err_ret_trace_index: Air.Inst.Index = @enumFromInt(std.math.maxInt(u32)); | ||
| 37 | |||
| 36 | gpa: Allocator, | 38 | gpa: Allocator, |
| 37 | pt: Zcu.PerThread, | 39 | pt: Zcu.PerThread, |
| 38 | air: Air, | 40 | air: Air, |
| ... | @@ -55,6 +57,7 @@ va_info: union { | ... | @@ -55,6 +57,7 @@ va_info: union { |
| 55 | win64: struct {}, | 57 | win64: struct {}, |
| 56 | }, | 58 | }, |
| 57 | ret_mcv: InstTracking, | 59 | ret_mcv: InstTracking, |
| 60 | err_ret_trace_reg: Register, | ||
| 58 | fn_type: Type, | 61 | fn_type: Type, |
| 59 | src_loc: Zcu.LazySrcLoc, | 62 | src_loc: Zcu.LazySrcLoc, |
| 60 | 63 | ||
| ... | @@ -626,6 +629,7 @@ const InstTracking = struct { | ... | @@ -626,6 +629,7 @@ const InstTracking = struct { |
| 626 | switch (self.long) { | 629 | switch (self.long) { |
| 627 | .none => self.long = try cg.allocRegOrMem(inst, false), | 630 | .none => self.long = try cg.allocRegOrMem(inst, false), |
| 628 | .load_frame => {}, | 631 | .load_frame => {}, |
| 632 | .lea_frame => return, | ||
| 629 | .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } }, | 633 | .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } }, |
| 630 | else => unreachable, | 634 | else => unreachable, |
| 631 | } | 635 | } |
| ... | @@ -887,6 +891,7 @@ pub fn generate( | ... | @@ -887,6 +891,7 @@ pub fn generate( |
| 887 | .args = undefined, // populated after `resolveCallingConventionValues` | 891 | .args = undefined, // populated after `resolveCallingConventionValues` |
| 888 | .va_info = undefined, // populated after `resolveCallingConventionValues` | 892 | .va_info = undefined, // populated after `resolveCallingConventionValues` |
| 889 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` | 893 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` |
| 894 | .err_ret_trace_reg = undefined, // populated after `resolveCallingConventionValues` | ||
| 890 | .fn_type = fn_type, | 895 | .fn_type = fn_type, |
| 891 | .src_loc = src_loc, | 896 | .src_loc = src_loc, |
| 892 | .end_di_line = func.rbrace_line, | 897 | .end_di_line = func.rbrace_line, |
| ... | @@ -935,6 +940,7 @@ pub fn generate( | ... | @@ -935,6 +940,7 @@ pub fn generate( |
| 935 | 940 | ||
| 936 | function.args = call_info.args; | 941 | function.args = call_info.args; |
| 937 | function.ret_mcv = call_info.return_value; | 942 | function.ret_mcv = call_info.return_value; |
| 943 | function.err_ret_trace_reg = call_info.err_ret_trace_reg; | ||
| 938 | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), .init(.{ | 944 | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), .init(.{ |
| 939 | .size = Type.usize.abiSize(zcu), | 945 | .size = Type.usize.abiSize(zcu), |
| 940 | .alignment = Type.usize.abiAlignment(zcu).min(call_info.stack_align), | 946 | .alignment = Type.usize.abiAlignment(zcu).min(call_info.stack_align), |
| ... | @@ -962,6 +968,14 @@ pub fn generate( | ... | @@ -962,6 +968,14 @@ pub fn generate( |
| 962 | } }, | 968 | } }, |
| 963 | .x86_64_win => .{ .win64 = .{} }, | 969 | .x86_64_win => .{ .win64 = .{} }, |
| 964 | }; | 970 | }; |
| 971 | if (call_info.err_ret_trace_reg != .none) { | ||
| 972 | function.register_manager.getRegAssumeFree(call_info.err_ret_trace_reg, err_ret_trace_index); | ||
| 973 | try function.inst_tracking.putNoClobber( | ||
| 974 | gpa, | ||
| 975 | err_ret_trace_index, | ||
| 976 | .init(.{ .register = call_info.err_ret_trace_reg }), | ||
| 977 | ); | ||
| 978 | } | ||
| 965 | 979 | ||
| 966 | function.gen() catch |err| switch (err) { | 980 | function.gen() catch |err| switch (err) { |
| 967 | error.CodegenFail => return error.CodegenFail, | 981 | error.CodegenFail => return error.CodegenFail, |
| ... | @@ -1042,6 +1056,7 @@ pub fn generateLazy( | ... | @@ -1042,6 +1056,7 @@ pub fn generateLazy( |
| 1042 | .args = undefined, | 1056 | .args = undefined, |
| 1043 | .va_info = undefined, | 1057 | .va_info = undefined, |
| 1044 | .ret_mcv = undefined, | 1058 | .ret_mcv = undefined, |
| 1059 | .err_ret_trace_reg = undefined, | ||
| 1045 | .fn_type = undefined, | 1060 | .fn_type = undefined, |
| 1046 | .src_loc = src_loc, | 1061 | .src_loc = src_loc, |
| 1047 | .end_di_line = undefined, // no debug info yet | 1062 | .end_di_line = undefined, // no debug info yet |
| ... | @@ -2503,9 +2518,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -2503,9 +2518,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2503 | .optional_payload => try cg.airOptionalPayload(inst), | 2518 | .optional_payload => try cg.airOptionalPayload(inst), |
| 2504 | .unwrap_errunion_err => try cg.airUnwrapErrUnionErr(inst), | 2519 | .unwrap_errunion_err => try cg.airUnwrapErrUnionErr(inst), |
| 2505 | .unwrap_errunion_payload => try cg.airUnwrapErrUnionPayload(inst), | 2520 | .unwrap_errunion_payload => try cg.airUnwrapErrUnionPayload(inst), |
| 2506 | .err_return_trace => try cg.airErrReturnTrace(inst), | ||
| 2507 | .set_err_return_trace => try cg.airSetErrReturnTrace(inst), | ||
| 2508 | .save_err_return_trace_index=> try cg.airSaveErrReturnTraceIndex(inst), | ||
| 2509 | 2521 | ||
| 2510 | .wrap_optional => try cg.airWrapOptional(inst), | 2522 | .wrap_optional => try cg.airWrapOptional(inst), |
| 2511 | .wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst), | 2523 | .wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst), |
| ... | @@ -11236,12 +11248,46 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -11236,12 +11248,46 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 11236 | .wasm_memory_size => unreachable, | 11248 | .wasm_memory_size => unreachable, |
| 11237 | .wasm_memory_grow => unreachable, | 11249 | .wasm_memory_grow => unreachable, |
| 11238 | 11250 | ||
| 11251 | .err_return_trace => { | ||
| 11252 | const ert: Temp = .{ .index = err_ret_trace_index }; | ||
| 11253 | try ert.moveTo(inst, cg); | ||
| 11254 | }, | ||
| 11255 | .set_err_return_trace => { | ||
| 11256 | const un_op = air_datas[@intFromEnum(inst)].un_op; | ||
| 11257 | var ops = try cg.tempsFromOperands(inst, .{un_op}); | ||
| 11258 | switch (ops[0].unwrap(cg)) { | ||
| 11259 | .ref => { | ||
| 11260 | const result = try cg.allocRegOrMem(err_ret_trace_index, true); | ||
| 11261 | try cg.genCopy(.usize, result, ops[0].tracking(cg).short, .{}); | ||
| 11262 | tracking_log.debug("{} => {} (birth)", .{ err_ret_trace_index, result }); | ||
| 11263 | cg.inst_tracking.putAssumeCapacityNoClobber(err_ret_trace_index, .init(result)); | ||
| 11264 | }, | ||
| 11265 | .temp => |temp_index| { | ||
| 11266 | const temp_tracking = temp_index.tracking(cg); | ||
| 11267 | tracking_log.debug("{} => {} (birth)", .{ err_ret_trace_index, temp_tracking.short }); | ||
| 11268 | cg.inst_tracking.putAssumeCapacityNoClobber(err_ret_trace_index, temp_tracking.*); | ||
| 11269 | assert(cg.reuseTemp(err_ret_trace_index, temp_index.toIndex(), temp_tracking)); | ||
| 11270 | }, | ||
| 11271 | .err_ret_trace => unreachable, | ||
| 11272 | } | ||
| 11273 | }, | ||
| 11274 | |||
| 11239 | .addrspace_cast => { | 11275 | .addrspace_cast => { |
| 11240 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; | 11276 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 11241 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); | 11277 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 11242 | try ops[0].moveTo(inst, cg); | 11278 | try ops[0].moveTo(inst, cg); |
| 11243 | }, | 11279 | }, |
| 11244 | 11280 | ||
| 11281 | .save_err_return_trace_index => { | ||
| 11282 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; | ||
| 11283 | const agg_ty = ty_pl.ty.toType(); | ||
| 11284 | assert(agg_ty.containerLayout(zcu) != .@"packed"); | ||
| 11285 | var ert: Temp = .{ .index = err_ret_trace_index }; | ||
| 11286 | var res = try ert.load(.usize, .{ .disp = @intCast(agg_ty.structFieldOffset(ty_pl.payload, zcu)) }, cg); | ||
| 11287 | try ert.die(cg); | ||
| 11288 | try res.moveTo(inst, cg); | ||
| 11289 | }, | ||
| 11290 | |||
| 11245 | .vector_store_elem => return cg.fail("TODO implement vector_store_elem", .{}), | 11291 | .vector_store_elem => return cg.fail("TODO implement vector_store_elem", .{}), |
| 11246 | 11292 | ||
| 11247 | .c_va_arg => try cg.airVaArg(inst), | 11293 | .c_va_arg => try cg.airVaArg(inst), |
| ... | @@ -11697,7 +11743,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co | ... | @@ -11697,7 +11743,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co |
| 11697 | const target_maybe_inst = if (state.free_registers.isSet(reg_index)) null else target_slot; | 11743 | const target_maybe_inst = if (state.free_registers.isSet(reg_index)) null else target_slot; |
| 11698 | if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst| | 11744 | if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst| |
| 11699 | assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len); | 11745 | assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len); |
| 11700 | if (opts.emit_instructions) { | 11746 | if (opts.emit_instructions and current_maybe_inst != target_maybe_inst) { |
| 11701 | if (current_maybe_inst) |current_inst| | 11747 | if (current_maybe_inst) |current_inst| |
| 11702 | try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst); | 11748 | try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst); |
| 11703 | if (target_maybe_inst) |target_inst| | 11749 | if (target_maybe_inst) |target_inst| |
| ... | @@ -11709,7 +11755,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co | ... | @@ -11709,7 +11755,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co |
| 11709 | self.register_manager.freeRegIndex(reg_index); | 11755 | self.register_manager.freeRegIndex(reg_index); |
| 11710 | } | 11756 | } |
| 11711 | if (target_maybe_inst) |target_inst| { | 11757 | if (target_maybe_inst) |target_inst| { |
| 11712 | self.register_manager.getRegIndexAssumeFree(reg_index, target_maybe_inst); | 11758 | self.register_manager.getRegIndexAssumeFree(reg_index, target_inst); |
| 11713 | self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking); | 11759 | self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking); |
| 11714 | } | 11760 | } |
| 11715 | } else if (target_maybe_inst) |_| | 11761 | } else if (target_maybe_inst) |_| |
| ... | @@ -11750,9 +11796,10 @@ pub fn spillEflagsIfOccupied(self: *CodeGen) !void { | ... | @@ -11750,9 +11796,10 @@ pub fn spillEflagsIfOccupied(self: *CodeGen) !void { |
| 11750 | } | 11796 | } |
| 11751 | } | 11797 | } |
| 11752 | 11798 | ||
| 11753 | pub fn spillCallerPreservedRegs(self: *CodeGen, cc: std.builtin.CallingConvention.Tag) !void { | 11799 | pub fn spillCallerPreservedRegs(self: *CodeGen, cc: std.builtin.CallingConvention.Tag, ignore_reg: Register) !void { |
| 11754 | switch (cc) { | 11800 | switch (cc) { |
| 11755 | inline .auto, .x86_64_sysv, .x86_64_win => |tag| try self.spillRegisters(abi.getCallerPreservedRegs(tag)), | 11801 | inline .auto, .x86_64_sysv, .x86_64_win => |tag| inline for (comptime abi.getCallerPreservedRegs(tag)) |reg| |
| 11802 | if (reg != ignore_reg) try self.register_manager.getKnownReg(reg, null), | ||
| 11756 | else => unreachable, | 11803 | else => unreachable, |
| 11757 | } | 11804 | } |
| 11758 | } | 11805 | } |
| ... | @@ -14406,22 +14453,6 @@ fn genUnwrapErrUnionPayloadPtrMir( | ... | @@ -14406,22 +14453,6 @@ fn genUnwrapErrUnionPayloadPtrMir( |
| 14406 | return result; | 14453 | return result; |
| 14407 | } | 14454 | } |
| 14408 | 14455 | ||
| 14409 | fn airErrReturnTrace(self: *CodeGen, inst: Air.Inst.Index) !void { | ||
| 14410 | _ = inst; | ||
| 14411 | return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch}); | ||
| 14412 | //return self.finishAir(inst, result, .{ .none, .none, .none }); | ||
| 14413 | } | ||
| 14414 | |||
| 14415 | fn airSetErrReturnTrace(self: *CodeGen, inst: Air.Inst.Index) !void { | ||
| 14416 | _ = inst; | ||
| 14417 | return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); | ||
| 14418 | } | ||
| 14419 | |||
| 14420 | fn airSaveErrReturnTraceIndex(self: *CodeGen, inst: Air.Inst.Index) !void { | ||
| 14421 | _ = inst; | ||
| 14422 | return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); | ||
| 14423 | } | ||
| 14424 | |||
| 14425 | fn airWrapOptional(self: *CodeGen, inst: Air.Inst.Index) !void { | 14456 | fn airWrapOptional(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 14426 | const pt = self.pt; | 14457 | const pt = self.pt; |
| 14427 | const zcu = pt.zcu; | 14458 | const zcu = pt.zcu; |
| ... | @@ -21188,7 +21219,7 @@ fn genCall(self: *CodeGen, info: union(enum) { | ... | @@ -21188,7 +21219,7 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 21188 | } | 21219 | } |
| 21189 | 21220 | ||
| 21190 | try self.spillEflagsIfOccupied(); | 21221 | try self.spillEflagsIfOccupied(); |
| 21191 | try self.spillCallerPreservedRegs(fn_info.cc); | 21222 | try self.spillCallerPreservedRegs(fn_info.cc, call_info.err_ret_trace_reg); |
| 21192 | 21223 | ||
| 21193 | // set stack arguments first because this can clobber registers | 21224 | // set stack arguments first because this can clobber registers |
| 21194 | // also clobber spill arguments as we go | 21225 | // also clobber spill arguments as we go |
| ... | @@ -21273,6 +21304,24 @@ fn genCall(self: *CodeGen, info: union(enum) { | ... | @@ -21273,6 +21304,24 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 21273 | else => unreachable, | 21304 | else => unreachable, |
| 21274 | }; | 21305 | }; |
| 21275 | 21306 | ||
| 21307 | if (call_info.err_ret_trace_reg != .none) { | ||
| 21308 | if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { | ||
| 21309 | if (switch (err_ret_trace.short) { | ||
| 21310 | .register => |reg| call_info.err_ret_trace_reg != reg, | ||
| 21311 | else => true, | ||
| 21312 | }) { | ||
| 21313 | try self.register_manager.getReg(call_info.err_ret_trace_reg, err_ret_trace_index); | ||
| 21314 | try reg_locks.append(self.register_manager.lockReg(call_info.err_ret_trace_reg)); | ||
| 21315 | |||
| 21316 | try self.genSetReg(call_info.err_ret_trace_reg, .usize, err_ret_trace.short, .{}); | ||
| 21317 | err_ret_trace.trackMaterialize(err_ret_trace_index, .{ | ||
| 21318 | .long = err_ret_trace.long, | ||
| 21319 | .short = .{ .register = call_info.err_ret_trace_reg }, | ||
| 21320 | }); | ||
| 21321 | } | ||
| 21322 | } | ||
| 21323 | } | ||
| 21324 | |||
| 21276 | // now we are free to set register arguments | 21325 | // now we are free to set register arguments |
| 21277 | switch (call_info.return_value.long) { | 21326 | switch (call_info.return_value.long) { |
| 21278 | .none, .unreach => {}, | 21327 | .none, .unreach => {}, |
| ... | @@ -21447,6 +21496,17 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -21447,6 +21496,17 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { |
| 21447 | else => unreachable, | 21496 | else => unreachable, |
| 21448 | } | 21497 | } |
| 21449 | self.ret_mcv.liveOut(self, inst); | 21498 | self.ret_mcv.liveOut(self, inst); |
| 21499 | |||
| 21500 | if (self.err_ret_trace_reg != .none) { | ||
| 21501 | if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { | ||
| 21502 | if (switch (err_ret_trace.short) { | ||
| 21503 | .register => |reg| self.err_ret_trace_reg != reg, | ||
| 21504 | else => true, | ||
| 21505 | }) try self.genSetReg(self.err_ret_trace_reg, .usize, err_ret_trace.short, .{}); | ||
| 21506 | err_ret_trace.liveOut(self, err_ret_trace_index); | ||
| 21507 | } | ||
| 21508 | } | ||
| 21509 | |||
| 21450 | try self.finishAir(inst, .unreach, .{ un_op, .none, .none }); | 21510 | try self.finishAir(inst, .unreach, .{ un_op, .none, .none }); |
| 21451 | 21511 | ||
| 21452 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction | 21512 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction |
| ... | @@ -21467,6 +21527,17 @@ fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -21467,6 +21527,17 @@ fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 21467 | else => unreachable, | 21527 | else => unreachable, |
| 21468 | } | 21528 | } |
| 21469 | self.ret_mcv.liveOut(self, inst); | 21529 | self.ret_mcv.liveOut(self, inst); |
| 21530 | |||
| 21531 | if (self.err_ret_trace_reg != .none) { | ||
| 21532 | if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { | ||
| 21533 | if (switch (err_ret_trace.short) { | ||
| 21534 | .register => |reg| self.err_ret_trace_reg != reg, | ||
| 21535 | else => true, | ||
| 21536 | }) try self.genSetReg(self.err_ret_trace_reg, .usize, err_ret_trace.short, .{}); | ||
| 21537 | err_ret_trace.liveOut(self, err_ret_trace_index); | ||
| 21538 | } | ||
| 21539 | } | ||
| 21540 | |||
| 21470 | try self.finishAir(inst, .unreach, .{ un_op, .none, .none }); | 21541 | try self.finishAir(inst, .unreach, .{ un_op, .none, .none }); |
| 21471 | 21542 | ||
| 21472 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction | 21543 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction |
| ... | @@ -26098,8 +26169,13 @@ fn airTagName(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -26098,8 +26169,13 @@ fn airTagName(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26098 | stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align); | 26169 | stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align); |
| 26099 | } | 26170 | } |
| 26100 | 26171 | ||
| 26172 | const err_ret_trace_reg = if (zcu.comp.config.any_error_tracing) err_ret_trace_reg: { | ||
| 26173 | const param_gpr = abi.getCAbiIntParamRegs(.auto); | ||
| 26174 | break :err_ret_trace_reg param_gpr[param_gpr.len - 1]; | ||
| 26175 | } else .none; | ||
| 26176 | |||
| 26101 | try self.spillEflagsIfOccupied(); | 26177 | try self.spillEflagsIfOccupied(); |
| 26102 | try self.spillCallerPreservedRegs(.auto); | 26178 | try self.spillCallerPreservedRegs(.auto, err_ret_trace_reg); |
| 26103 | 26179 | ||
| 26104 | const param_regs = abi.getCAbiIntParamRegs(.auto); | 26180 | const param_regs = abi.getCAbiIntParamRegs(.auto); |
| 26105 | 26181 | ||
| ... | @@ -28564,6 +28640,7 @@ const CallMCValues = struct { | ... | @@ -28564,6 +28640,7 @@ const CallMCValues = struct { |
| 28564 | stack_align: InternPool.Alignment, | 28640 | stack_align: InternPool.Alignment, |
| 28565 | gp_count: u32, | 28641 | gp_count: u32, |
| 28566 | fp_count: u32, | 28642 | fp_count: u32, |
| 28643 | err_ret_trace_reg: Register, | ||
| 28567 | 28644 | ||
| 28568 | fn deinit(self: *CallMCValues, func: *CodeGen) void { | 28645 | fn deinit(self: *CallMCValues, func: *CodeGen) void { |
| 28569 | func.gpa.free(self.args); | 28646 | func.gpa.free(self.args); |
| ... | @@ -28598,6 +28675,7 @@ fn resolveCallingConventionValues( | ... | @@ -28598,6 +28675,7 @@ fn resolveCallingConventionValues( |
| 28598 | .stack_align = undefined, | 28675 | .stack_align = undefined, |
| 28599 | .gp_count = 0, | 28676 | .gp_count = 0, |
| 28600 | .fp_count = 0, | 28677 | .fp_count = 0, |
| 28678 | .err_ret_trace_reg = .none, | ||
| 28601 | }; | 28679 | }; |
| 28602 | errdefer self.gpa.free(result.args); | 28680 | errdefer self.gpa.free(result.args); |
| 28603 | 28681 | ||
| ... | @@ -28842,6 +28920,11 @@ fn resolveCallingConventionValues( | ... | @@ -28842,6 +28920,11 @@ fn resolveCallingConventionValues( |
| 28842 | var param_x87 = abi.getCAbiX87ParamRegs(cc); | 28920 | var param_x87 = abi.getCAbiX87ParamRegs(cc); |
| 28843 | var param_sse = abi.getCAbiSseParamRegs(cc, self.target); | 28921 | var param_sse = abi.getCAbiSseParamRegs(cc, self.target); |
| 28844 | 28922 | ||
| 28923 | if (zcu.comp.config.any_error_tracing) { | ||
| 28924 | result.err_ret_trace_reg = param_gpr[param_gpr.len - 1]; | ||
| 28925 | param_gpr = param_gpr[0 .. param_gpr.len - 1]; | ||
| 28926 | } | ||
| 28927 | |||
| 28845 | // Return values | 28928 | // Return values |
| 28846 | result.return_value = if (ret_ty.isNoReturn(zcu)) | 28929 | result.return_value = if (ret_ty.isNoReturn(zcu)) |
| 28847 | .init(.unreach) | 28930 | .init(.unreach) |
| ... | @@ -29159,16 +29242,8 @@ fn typeOf(self: *CodeGen, inst: Air.Inst.Ref) Type { | ... | @@ -29159,16 +29242,8 @@ fn typeOf(self: *CodeGen, inst: Air.Inst.Ref) Type { |
| 29159 | } | 29242 | } |
| 29160 | 29243 | ||
| 29161 | fn typeOfIndex(self: *CodeGen, inst: Air.Inst.Index) Type { | 29244 | fn typeOfIndex(self: *CodeGen, inst: Air.Inst.Index) Type { |
| 29162 | const pt = self.pt; | ||
| 29163 | const zcu = pt.zcu; | ||
| 29164 | const temp: Temp = .{ .index = inst }; | 29245 | const temp: Temp = .{ .index = inst }; |
| 29165 | return switch (temp.unwrap(self)) { | 29246 | return temp.typeOf(self); |
| 29166 | .ref => switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) { | ||
| 29167 | .loop_switch_br => self.typeOf(self.air.unwrapSwitch(inst).operand), | ||
| 29168 | else => self.air.typeOfIndex(inst, &zcu.intern_pool), | ||
| 29169 | }, | ||
| 29170 | .temp => temp.typeOf(self), | ||
| 29171 | }; | ||
| 29172 | } | 29247 | } |
| 29173 | 29248 | ||
| 29174 | fn intCompilerRtAbiName(int_bits: u32) u8 { | 29249 | fn intCompilerRtAbiName(int_bits: u32) u8 { |
| ... | @@ -29336,10 +29411,12 @@ const Temp = struct { | ... | @@ -29336,10 +29411,12 @@ const Temp = struct { |
| 29336 | fn unwrap(temp: Temp, cg: *CodeGen) union(enum) { | 29411 | fn unwrap(temp: Temp, cg: *CodeGen) union(enum) { |
| 29337 | ref: Air.Inst.Ref, | 29412 | ref: Air.Inst.Ref, |
| 29338 | temp: Index, | 29413 | temp: Index, |
| 29414 | err_ret_trace, | ||
| 29339 | } { | 29415 | } { |
| 29340 | switch (temp.index.unwrap()) { | 29416 | switch (temp.index.unwrap()) { |
| 29341 | .ref => |ref| return .{ .ref = ref }, | 29417 | .ref => |ref| return .{ .ref = ref }, |
| 29342 | .target => |target_index| { | 29418 | .target => |target_index| { |
| 29419 | if (temp.index == err_ret_trace_index) return .err_ret_trace; | ||
| 29343 | const temp_index: Index = @enumFromInt(target_index); | 29420 | const temp_index: Index = @enumFromInt(target_index); |
| 29344 | assert(temp_index.isValid(cg)); | 29421 | assert(temp_index.isValid(cg)); |
| 29345 | return .{ .temp = temp_index }; | 29422 | return .{ .temp = temp_index }; |
| ... | @@ -29349,14 +29426,18 @@ const Temp = struct { | ... | @@ -29349,14 +29426,18 @@ const Temp = struct { |
| 29349 | 29426 | ||
| 29350 | fn typeOf(temp: Temp, cg: *CodeGen) Type { | 29427 | fn typeOf(temp: Temp, cg: *CodeGen) Type { |
| 29351 | return switch (temp.unwrap(cg)) { | 29428 | return switch (temp.unwrap(cg)) { |
| 29352 | .ref => |ref| cg.typeOf(ref), | 29429 | .ref => switch (cg.air.instructions.items(.tag)[@intFromEnum(temp.index)]) { |
| 29430 | .loop_switch_br => cg.typeOf(cg.air.unwrapSwitch(temp.index).operand), | ||
| 29431 | else => cg.air.typeOfIndex(temp.index, &cg.pt.zcu.intern_pool), | ||
| 29432 | }, | ||
| 29353 | .temp => |temp_index| temp_index.typeOf(cg), | 29433 | .temp => |temp_index| temp_index.typeOf(cg), |
| 29434 | .err_ret_trace => .usize, | ||
| 29354 | }; | 29435 | }; |
| 29355 | } | 29436 | } |
| 29356 | 29437 | ||
| 29357 | fn isMut(temp: Temp, cg: *CodeGen) bool { | 29438 | fn isMut(temp: Temp, cg: *CodeGen) bool { |
| 29358 | return switch (temp.unwrap(cg)) { | 29439 | return switch (temp.unwrap(cg)) { |
| 29359 | .ref => false, | 29440 | .ref, .err_ret_trace => false, |
| 29360 | .temp => |temp_index| switch (temp_index.tracking(cg).short) { | 29441 | .temp => |temp_index| switch (temp_index.tracking(cg).short) { |
| 29361 | .none, | 29442 | .none, |
| 29362 | .unreach, | 29443 | .unreach, |
| ... | @@ -29456,7 +29537,7 @@ const Temp = struct { | ... | @@ -29456,7 +29537,7 @@ const Temp = struct { |
| 29456 | fn toOffset(temp: *Temp, off: i32, cg: *CodeGen) !void { | 29537 | fn toOffset(temp: *Temp, off: i32, cg: *CodeGen) !void { |
| 29457 | if (off == 0) return; | 29538 | if (off == 0) return; |
| 29458 | switch (temp.unwrap(cg)) { | 29539 | switch (temp.unwrap(cg)) { |
| 29459 | .ref => {}, | 29540 | .ref, .err_ret_trace => {}, |
| 29460 | .temp => |temp_index| { | 29541 | .temp => |temp_index| { |
| 29461 | const temp_tracking = temp_index.tracking(cg); | 29542 | const temp_tracking = temp_index.tracking(cg); |
| 29462 | switch (temp_tracking.short) { | 29543 | switch (temp_tracking.short) { |
| ... | @@ -29617,6 +29698,7 @@ const Temp = struct { | ... | @@ -29617,6 +29698,7 @@ const Temp = struct { |
| 29617 | }, | 29698 | }, |
| 29618 | } | 29699 | } |
| 29619 | }, | 29700 | }, |
| 29701 | .err_ret_trace => unreachable, | ||
| 29620 | } | 29702 | } |
| 29621 | const new_temp = try temp.getLimb(limb_ty, limb_index, cg); | 29703 | const new_temp = try temp.getLimb(limb_ty, limb_index, cg); |
| 29622 | try temp.die(cg); | 29704 | try temp.die(cg); |
| ... | @@ -29633,7 +29715,7 @@ const Temp = struct { | ... | @@ -29633,7 +29715,7 @@ const Temp = struct { |
| 29633 | } | 29715 | } |
| 29634 | 29716 | ||
| 29635 | fn toReg(temp: *Temp, new_reg: Register, cg: *CodeGen) !bool { | 29717 | fn toReg(temp: *Temp, new_reg: Register, cg: *CodeGen) !bool { |
| 29636 | const val, const ty = val_ty: switch (temp.unwrap(cg)) { | 29718 | const val, const ty: Type = val_ty: switch (temp.unwrap(cg)) { |
| 29637 | .ref => |ref| .{ temp.tracking(cg).short, cg.typeOf(ref) }, | 29719 | .ref => |ref| .{ temp.tracking(cg).short, cg.typeOf(ref) }, |
| 29638 | .temp => |temp_index| { | 29720 | .temp => |temp_index| { |
| 29639 | const temp_tracking = temp_index.tracking(cg); | 29721 | const temp_tracking = temp_index.tracking(cg); |
| ... | @@ -29641,6 +29723,7 @@ const Temp = struct { | ... | @@ -29641,6 +29723,7 @@ const Temp = struct { |
| 29641 | temp_tracking.short.register == new_reg) return false; | 29723 | temp_tracking.short.register == new_reg) return false; |
| 29642 | break :val_ty .{ temp_tracking.short, temp_index.typeOf(cg) }; | 29724 | break :val_ty .{ temp_tracking.short, temp_index.typeOf(cg) }; |
| 29643 | }, | 29725 | }, |
| 29726 | .err_ret_trace => .{ temp.tracking(cg).short, .usize }, | ||
| 29644 | }; | 29727 | }; |
| 29645 | const new_temp_index = cg.next_temp_index; | 29728 | const new_temp_index = cg.next_temp_index; |
| 29646 | try cg.register_manager.getReg(new_reg, new_temp_index.toIndex()); | 29729 | try cg.register_manager.getReg(new_reg, new_temp_index.toIndex()); |
| ... | @@ -30167,7 +30250,7 @@ const Temp = struct { | ... | @@ -30167,7 +30250,7 @@ const Temp = struct { |
| 30167 | 30250 | ||
| 30168 | fn moveTo(temp: Temp, inst: Air.Inst.Index, cg: *CodeGen) !void { | 30251 | fn moveTo(temp: Temp, inst: Air.Inst.Index, cg: *CodeGen) !void { |
| 30169 | if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) { | 30252 | if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) { |
| 30170 | .ref => { | 30253 | .ref, .err_ret_trace => { |
| 30171 | const result = try cg.allocRegOrMem(inst, true); | 30254 | const result = try cg.allocRegOrMem(inst, true); |
| 30172 | try cg.genCopy(cg.typeOfIndex(inst), result, temp.tracking(cg).short, .{}); | 30255 | try cg.genCopy(cg.typeOfIndex(inst), result, temp.tracking(cg).short, .{}); |
| 30173 | tracking_log.debug("{} => {} (birth)", .{ inst, result }); | 30256 | tracking_log.debug("{} => {} (birth)", .{ inst, result }); |
| ... | @@ -30184,7 +30267,7 @@ const Temp = struct { | ... | @@ -30184,7 +30267,7 @@ const Temp = struct { |
| 30184 | 30267 | ||
| 30185 | fn die(temp: Temp, cg: *CodeGen) !void { | 30268 | fn die(temp: Temp, cg: *CodeGen) !void { |
| 30186 | switch (temp.unwrap(cg)) { | 30269 | switch (temp.unwrap(cg)) { |
| 30187 | .ref => {}, | 30270 | .ref, .err_ret_trace => {}, |
| 30188 | .temp => |temp_index| try temp_index.tracking(cg).die(cg, temp_index.toIndex()), | 30271 | .temp => |temp_index| try temp_index.tracking(cg).die(cg, temp_index.toIndex()), |
| 30189 | } | 30272 | } |
| 30190 | } | 30273 | } |
src/codegen/llvm.zig+14-12| ... | @@ -1497,8 +1497,7 @@ pub const Object = struct { | ... | @@ -1497,8 +1497,7 @@ pub const Object = struct { |
| 1497 | .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), | 1497 | .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), |
| 1498 | }; | 1498 | }; |
| 1499 | 1499 | ||
| 1500 | const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and | 1500 | const err_return_tracing = fn_info.cc == .auto and comp.config.any_error_tracing; |
| 1501 | comp.config.any_error_tracing; | ||
| 1502 | 1501 | ||
| 1503 | const err_ret_trace: Builder.Value = if (err_return_tracing) param: { | 1502 | const err_ret_trace: Builder.Value = if (err_return_tracing) param: { |
| 1504 | const param = wip.arg(llvm_arg_i); | 1503 | const param = wip.arg(llvm_arg_i); |
| ... | @@ -2805,9 +2804,7 @@ pub const Object = struct { | ... | @@ -2805,9 +2804,7 @@ pub const Object = struct { |
| 2805 | debug_param_types.appendAssumeCapacity(try o.lowerDebugType(Type.void)); | 2804 | debug_param_types.appendAssumeCapacity(try o.lowerDebugType(Type.void)); |
| 2806 | } | 2805 | } |
| 2807 | 2806 | ||
| 2808 | if (Type.fromInterned(fn_info.return_type).isError(zcu) and | 2807 | if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) { |
| 2809 | zcu.comp.config.any_error_tracing) | ||
| 2810 | { | ||
| 2811 | const ptr_ty = try pt.singleMutPtrType(try o.getStackTraceType()); | 2808 | const ptr_ty = try pt.singleMutPtrType(try o.getStackTraceType()); |
| 2812 | debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty)); | 2809 | debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty)); |
| 2813 | } | 2810 | } |
| ... | @@ -2970,8 +2967,7 @@ pub const Object = struct { | ... | @@ -2970,8 +2967,7 @@ pub const Object = struct { |
| 2970 | llvm_arg_i += 1; | 2967 | llvm_arg_i += 1; |
| 2971 | } | 2968 | } |
| 2972 | 2969 | ||
| 2973 | const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and | 2970 | const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; |
| 2974 | zcu.comp.config.any_error_tracing; | ||
| 2975 | 2971 | ||
| 2976 | if (err_return_tracing) { | 2972 | if (err_return_tracing) { |
| 2977 | try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); | 2973 | try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); |
| ... | @@ -3736,9 +3732,7 @@ pub const Object = struct { | ... | @@ -3736,9 +3732,7 @@ pub const Object = struct { |
| 3736 | try llvm_params.append(o.gpa, .ptr); | 3732 | try llvm_params.append(o.gpa, .ptr); |
| 3737 | } | 3733 | } |
| 3738 | 3734 | ||
| 3739 | if (Type.fromInterned(fn_info.return_type).isError(zcu) and | 3735 | if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) { |
| 3740 | zcu.comp.config.any_error_tracing) | ||
| 3741 | { | ||
| 3742 | const ptr_ty = try pt.singleMutPtrType(try o.getStackTraceType()); | 3736 | const ptr_ty = try pt.singleMutPtrType(try o.getStackTraceType()); |
| 3743 | try llvm_params.append(o.gpa, try o.lowerType(ptr_ty)); | 3737 | try llvm_params.append(o.gpa, try o.lowerType(ptr_ty)); |
| 3744 | } | 3738 | } |
| ... | @@ -5483,7 +5477,7 @@ pub const FuncGen = struct { | ... | @@ -5483,7 +5477,7 @@ pub const FuncGen = struct { |
| 5483 | break :blk ret_ptr; | 5477 | break :blk ret_ptr; |
| 5484 | }; | 5478 | }; |
| 5485 | 5479 | ||
| 5486 | const err_return_tracing = return_type.isError(zcu) and zcu.comp.config.any_error_tracing; | 5480 | const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; |
| 5487 | if (err_return_tracing) { | 5481 | if (err_return_tracing) { |
| 5488 | assert(self.err_ret_trace != .none); | 5482 | assert(self.err_ret_trace != .none); |
| 5489 | try llvm_args.append(self.err_ret_trace); | 5483 | try llvm_args.append(self.err_ret_trace); |
| ... | @@ -5762,6 +5756,8 @@ pub const FuncGen = struct { | ... | @@ -5762,6 +5756,8 @@ pub const FuncGen = struct { |
| 5762 | const panic_nav = ip.getNav(panic_func.owner_nav); | 5756 | const panic_nav = ip.getNav(panic_func.owner_nav); |
| 5763 | const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?; | 5757 | const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?; |
| 5764 | const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav); | 5758 | const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav); |
| 5759 | const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto; | ||
| 5760 | if (has_err_trace) assert(fg.err_ret_trace != .none); | ||
| 5765 | _ = try fg.wip.callIntrinsicAssumeCold(); | 5761 | _ = try fg.wip.callIntrinsicAssumeCold(); |
| 5766 | _ = try fg.wip.call( | 5762 | _ = try fg.wip.call( |
| 5767 | .normal, | 5763 | .normal, |
| ... | @@ -5769,7 +5765,13 @@ pub const FuncGen = struct { | ... | @@ -5769,7 +5765,13 @@ pub const FuncGen = struct { |
| 5769 | .none, | 5765 | .none, |
| 5770 | panic_global.typeOf(&o.builder), | 5766 | panic_global.typeOf(&o.builder), |
| 5771 | panic_global.toValue(&o.builder), | 5767 | panic_global.toValue(&o.builder), |
| 5772 | &.{ | 5768 | if (has_err_trace) &.{ |
| 5769 | fg.err_ret_trace, | ||
| 5770 | msg_ptr.toValue(), | ||
| 5771 | try o.builder.intValue(llvm_usize, msg_len), | ||
| 5772 | try o.builder.nullValue(.ptr), | ||
| 5773 | null_opt_addr_global.toValue(), | ||
| 5774 | } else &.{ | ||
| 5773 | msg_ptr.toValue(), | 5775 | msg_ptr.toValue(), |
| 5774 | try o.builder.intValue(llvm_usize, msg_len), | 5776 | try o.builder.intValue(llvm_usize, msg_len), |
| 5775 | try o.builder.nullValue(.ptr), | 5777 | try o.builder.nullValue(.ptr), |
src/target.zig+1-1| ... | @@ -708,7 +708,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt | ... | @@ -708,7 +708,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt |
| 708 | else => false, | 708 | else => false, |
| 709 | }, | 709 | }, |
| 710 | .error_return_trace => switch (backend) { | 710 | .error_return_trace => switch (backend) { |
| 711 | .stage2_llvm => true, | 711 | .stage2_llvm, .stage2_x86_64 => true, |
| 712 | else => false, | 712 | else => false, |
| 713 | }, | 713 | }, |
| 714 | .is_named_enum_value => switch (backend) { | 714 | .is_named_enum_value => switch (backend) { |
stage1/zig1.wasm| Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ | |||
test/cases/compile_errors/anytype_param_requires_comptime.zig+1-1| ... | @@ -15,6 +15,6 @@ pub export fn entry() void { | ... | @@ -15,6 +15,6 @@ pub export fn entry() void { |
| 15 | // error | 15 | // error |
| 16 | // | 16 | // |
| 17 | // :7:25: error: unable to resolve comptime value | 17 | // :7:25: error: unable to resolve comptime value |
| 18 | // :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_165.C' must be comptime-known | 18 | // :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_441.C' must be comptime-known |
| 19 | // :4:16: note: struct requires comptime because of this field | 19 | // :4:16: note: struct requires comptime because of this field |
| 20 | // :4:16: note: types are not available at runtime | 20 | // :4:16: note: types are not available at runtime |
test/cases/compile_errors/bogus_method_call_on_slice.zig+1-1| ... | @@ -16,5 +16,5 @@ pub export fn entry2() void { | ... | @@ -16,5 +16,5 @@ pub export fn entry2() void { |
| 16 | // | 16 | // |
| 17 | // :3:6: error: no field or member function named 'copy' in '[]const u8' | 17 | // :3:6: error: no field or member function named 'copy' in '[]const u8' |
| 18 | // :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})' | 18 | // :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})' |
| 19 | // :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_169' | 19 | // :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_445' |
| 20 | // :12:6: note: struct declared here | 20 | // :12:6: note: struct declared here |
test/cases/compile_errors/coerce_anon_struct.zig+1-1| ... | @@ -6,6 +6,6 @@ export fn foo() void { | ... | @@ -6,6 +6,6 @@ export fn foo() void { |
| 6 | 6 | ||
| 7 | // error | 7 | // error |
| 8 | // | 8 | // |
| 9 | // :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_158' | 9 | // :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_434' |
| 10 | // :3:16: note: struct declared here | 10 | // :3:16: note: struct declared here |
| 11 | // :1:11: note: struct declared here | 11 | // :1:11: note: struct declared here |
test/cases/compile_errors/implicit_cast_of_error_set_not_a_subset.zig+1-1| ... | @@ -12,5 +12,5 @@ fn foo(set1: Set1) void { | ... | @@ -12,5 +12,5 @@ fn foo(set1: Set1) void { |
| 12 | // backend=stage2 | 12 | // backend=stage2 |
| 13 | // target=native | 13 | // target=native |
| 14 | // | 14 | // |
| 15 | // :7:21: error: expected type 'error{A,C}', found 'error{A,B}' | 15 | // :7:21: error: expected type 'error{C,A}', found 'error{A,B}' |
| 16 | // :7:21: note: 'error.B' not a member of destination error set | 16 | // :7:21: note: 'error.B' not a member of destination error set |