Commit 724d753638
Changed files (12)
src
arch
aarch64
arm
riscv64
sparc64
wasm
x86_64
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: {
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;
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: {
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)"),
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,
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)) {
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;
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;
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,
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,
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,
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;