diff --git a/src/Air.zig b/src/Air.zig index 57479af590..1cd5d85d75 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -733,6 +733,10 @@ pub const Inst = struct { /// Uses the `ty_op` field. addrspace_cast, + /// Saves the error return trace index, if any. Otherwise, returns 0. + /// Uses the `ty_op` field. + save_err_return_trace_index, + pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag { switch (op) { .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt, @@ -1179,6 +1183,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .slice_len, .ret_addr, .frame_addr, + .save_err_return_trace_index, => return Type.usize, .wasm_memory_grow => return Type.i32, diff --git a/src/Liveness.zig b/src/Liveness.zig index 54a5041e8b..ff8afb8307 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -228,6 +228,7 @@ pub fn categorizeOperand( .frame_addr, .wasm_memory_size, .err_return_trace, + .save_err_return_trace_index, => return .none, .fence => return .write, @@ -805,6 +806,7 @@ fn analyzeInst( .frame_addr, .wasm_memory_size, .err_return_trace, + .save_err_return_trace_index, => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), .not, diff --git a/src/Sema.zig b/src/Sema.zig index 93f496a43a..791519c12a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -16228,22 +16228,28 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE // This is only relevant at runtime. if (block.is_comptime) return Air.Inst.Ref.zero_usize; - // In the corner case that `catch { ... }` or `else |err| { ... }` is used in a function - // that does *not* make any errorable calls, we still need an error trace to interact with - // the AIR instructions we've already emitted. - if (sema.owner_func != null) - sema.owner_func.?.calls_or_awaits_errorable_fn = true; - const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; const ok = sema.mod.comp.bin_file.options.error_return_tracing and backend_supports_error_return_tracing; if (!ok) return Air.Inst.Ref.zero_usize; + // This is encoded as a primitive AIR instruction to resolve one corner case: A function + // may include a `catch { ... }` or `else |err| { ... }` block but not call any errorable + // fn. In that case, there is no error return trace to save the index of and codegen needs + // to avoid interacting with the non-existing error trace. + // + // By using a primitive AIR op, we can depend on Liveness to mark this unused in this corner case. + const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); - const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); - const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); - return sema.fieldVal(block, src, err_return_trace, "index", src); + const field_index = try sema.structFieldIndex(block, stack_trace_ty, "index", src); + return block.addInst(.{ + .tag = .save_err_return_trace_index, + .data = .{ .ty_pl = .{ + .ty = try sema.addType(stack_trace_ty), + .payload = @intCast(u32, field_index), + } }, + }); } fn zirRestoreErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { @@ -16254,7 +16260,8 @@ fn zirRestoreErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi if (block.is_comptime) return; const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; - const ok = sema.mod.comp.bin_file.options.error_return_tracing and + const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and + sema.mod.comp.bin_file.options.error_return_tracing and backend_supports_error_return_tracing; if (!ok) return; diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 8da94f2e9c..eb8ca8e8f1 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -702,6 +702,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .err_return_trace => try self.airErrReturnTrace(inst), .set_err_return_trace => try self.airSetErrReturnTrace(inst), + .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -2867,6 +2868,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); } +fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); +} + fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 530d5c2b04..1ebc348fc2 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -751,6 +751,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .err_return_trace => try self.airErrReturnTrace(inst), .set_err_return_trace => try self.airSetErrReturnTrace(inst), + .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -2116,6 +2117,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); } +fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); +} + /// T to E!T fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index dd31bfb6f7..003d2c7e5f 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -665,6 +665,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .err_return_trace => try self.airErrReturnTrace(inst), .set_err_return_trace => try self.airSetErrReturnTrace(inst), + .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -1329,6 +1330,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); } +fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); +} + fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 6217119f34..9d37cd9d1b 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -679,6 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"), .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"), + .save_err_return_trace_index=> @panic("TODO try self.airSaveErrReturnTraceIndex(inst)"), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"), diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index b47bb71e98..538fcb13c1 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1857,6 +1857,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .tag_name, .err_return_trace, .set_err_return_trace, + .save_err_return_trace_index, .is_named_enum_value, .error_set_has_value, .addrspace_cast, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index a3888b4173..a1b354482b 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -756,6 +756,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .err_return_trace => try self.airErrReturnTrace(inst), .set_err_return_trace => try self.airSetErrReturnTrace(inst), + .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -1973,6 +1974,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); } +fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); +} + fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; if (self.liveness.isUnused(inst)) { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 072091d9b2..d6584d75ae 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1935,6 +1935,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst), .err_return_trace => try airErrReturnTrace(f, inst), .set_err_return_trace => try airSetErrReturnTrace(f, inst), + .save_err_return_trace_index => try airSaveErrReturnTraceIndex(f, inst), .wasm_memory_size => try airWasmMemorySize(f, inst), .wasm_memory_grow => try airWasmMemoryGrow(f, inst), @@ -3625,6 +3626,11 @@ fn airSetErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue { return f.fail("TODO: C backend: implement airSetErrReturnTrace", .{}); } +fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { + _ = inst; + return f.fail("TODO: C backend: implement airSaveErrReturnTraceIndex", .{}); +} + fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index b0d1588007..3ebca13c20 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4592,6 +4592,7 @@ pub const FuncGen = struct { .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .err_return_trace => try self.airErrReturnTrace(inst), .set_err_return_trace => try self.airSetErrReturnTrace(inst), + .save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -6543,6 +6544,24 @@ pub const FuncGen = struct { return null; } + fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { + if (self.liveness.isUnused(inst)) return null; + + const target = self.dg.module.getTarget(); + + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + //const struct_ty = try self.resolveInst(ty_pl.ty); + const struct_ty = self.air.getRefType(ty_pl.ty); + const field_index = ty_pl.payload; + + var ptr_ty_buf: Type.Payload.Pointer = undefined; + const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; + const struct_llvm_ty = try self.dg.lowerType(struct_ty); + const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field_index, ""); + const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); + return self.load(field_ptr, field_ptr_ty); + } + fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { if (self.liveness.isUnused(inst)) return null; diff --git a/src/print_air.zig b/src/print_air.zig index d3523c0fc6..0bbc1100f7 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -197,6 +197,7 @@ const Writer = struct { .unreach, .ret_addr, .frame_addr, + .save_err_return_trace_index, => try w.writeNoOp(s, inst), .const_ty,