authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-09-14 13:49:54-07:00
committergravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-21 10:44:20-07:00
log724d75363855176aa5e6b3d9bcd1656e2cc1f6a6
treef3b5c2e68dcc355ade60e3c75065002715040790
parent3007fdde45868142654d0bfa59bc0e17e5f24a1c

stage2: Add `.save_err_return_trace_index` AIR op

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.

12 files changed, 76 insertions(+), 10 deletions(-)

src/Air.zig+5
...@@ -733,6 +733,10 @@ pub const Inst = struct {...@@ -733,6 +733,10 @@ pub const Inst = struct {
733 /// Uses the `ty_op` field.733 /// Uses the `ty_op` field.
734 addrspace_cast,734 addrspace_cast,
735735
736 /// Saves the error return trace index, if any. Otherwise, returns 0.
737 /// Uses the `ty_op` field.
738 save_err_return_trace_index,
739
736 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {740 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {
737 switch (op) {741 switch (op) {
738 .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt,742 .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt,
...@@ -1179,6 +1183,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1179,6 +1183,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1179 .slice_len,1183 .slice_len,
1180 .ret_addr,1184 .ret_addr,
1181 .frame_addr,1185 .frame_addr,
1186 .save_err_return_trace_index,
1182 => return Type.usize,1187 => return Type.usize,
11831188
1184 .wasm_memory_grow => return Type.i32,1189 .wasm_memory_grow => return Type.i32,
src/Liveness.zig+2
...@@ -228,6 +228,7 @@ pub fn categorizeOperand(...@@ -228,6 +228,7 @@ pub fn categorizeOperand(
228 .frame_addr,228 .frame_addr,
229 .wasm_memory_size,229 .wasm_memory_size,
230 .err_return_trace,230 .err_return_trace,
231 .save_err_return_trace_index,
231 => return .none,232 => return .none,
232233
233 .fence => return .write,234 .fence => return .write,
...@@ -805,6 +806,7 @@ fn analyzeInst(...@@ -805,6 +806,7 @@ fn analyzeInst(
805 .frame_addr,806 .frame_addr,
806 .wasm_memory_size,807 .wasm_memory_size,
807 .err_return_trace,808 .err_return_trace,
809 .save_err_return_trace_index,
808 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),810 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
809811
810 .not,812 .not,
src/Sema.zig+17-10
...@@ -16228,22 +16228,28 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -16228,22 +16228,28 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
16228 // This is only relevant at runtime.16228 // This is only relevant at runtime.
16229 if (block.is_comptime) return Air.Inst.Ref.zero_usize;16229 if (block.is_comptime) return Air.Inst.Ref.zero_usize;
1623016230
16231 // In the corner case that `catch { ... }` or `else |err| { ... }` is used in a function
16232 // that does *not* make any errorable calls, we still need an error trace to interact with
16233 // the AIR instructions we've already emitted.
16234 if (sema.owner_func != null)
16235 sema.owner_func.?.calls_or_awaits_errorable_fn = true;
16236
16237 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;16231 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
16238 const ok = sema.mod.comp.bin_file.options.error_return_tracing and16232 const ok = sema.mod.comp.bin_file.options.error_return_tracing and
16239 backend_supports_error_return_tracing;16233 backend_supports_error_return_tracing;
16240 if (!ok) return Air.Inst.Ref.zero_usize;16234 if (!ok) return Air.Inst.Ref.zero_usize;
1624116235
16236 // This is encoded as a primitive AIR instruction to resolve one corner case: A function
16237 // may include a `catch { ... }` or `else |err| { ... }` block but not call any errorable
16238 // fn. In that case, there is no error return trace to save the index of and codegen needs
16239 // to avoid interacting with the non-existing error trace.
16240 //
16241 // By using a primitive AIR op, we can depend on Liveness to mark this unused in this corner case.
16242
16242 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");16243 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
16243 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);16244 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
16244 const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);16245 const field_index = try sema.structFieldIndex(block, stack_trace_ty, "index", src);
16245 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);16246 return block.addInst(.{
16246 return sema.fieldVal(block, src, err_return_trace, "index", src);16247 .tag = .save_err_return_trace_index,
16248 .data = .{ .ty_pl = .{
16249 .ty = try sema.addType(stack_trace_ty),
16250 .payload = @intCast(u32, field_index),
16251 } },
16252 });
16247}16253}
1624816254
16249fn zirRestoreErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {16255fn 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...@@ -16254,7 +16260,8 @@ fn zirRestoreErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
16254 if (block.is_comptime) return;16260 if (block.is_comptime) return;
1625516261
16256 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;16262 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
16257 const ok = sema.mod.comp.bin_file.options.error_return_tracing and16263 const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and
16264 sema.mod.comp.bin_file.options.error_return_tracing and
16258 backend_supports_error_return_tracing;16265 backend_supports_error_return_tracing;
16259 if (!ok) return;16266 if (!ok) return;
1626016267
src/arch/aarch64/CodeGen.zig+6
...@@ -702,6 +702,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -702,6 +702,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
702 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),702 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
703 .err_return_trace => try self.airErrReturnTrace(inst),703 .err_return_trace => try self.airErrReturnTrace(inst),
704 .set_err_return_trace => try self.airSetErrReturnTrace(inst),704 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
705 .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst),
705706
706 .wrap_optional => try self.airWrapOptional(inst),707 .wrap_optional => try self.airWrapOptional(inst),
707 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),708 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -2867,6 +2868,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {...@@ -2867,6 +2868,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
2867 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});2868 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
2868}2869}
28692870
2871fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {
2872 _ = inst;
2873 return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch});
2874}
2875
2870fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {2876fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
2871 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2877 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2872 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2878 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
src/arch/arm/CodeGen.zig+6
...@@ -751,6 +751,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -751,6 +751,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
751 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),751 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
752 .err_return_trace => try self.airErrReturnTrace(inst),752 .err_return_trace => try self.airErrReturnTrace(inst),
753 .set_err_return_trace => try self.airSetErrReturnTrace(inst),753 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
754 .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst),
754755
755 .wrap_optional => try self.airWrapOptional(inst),756 .wrap_optional => try self.airWrapOptional(inst),
756 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),757 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -2116,6 +2117,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {...@@ -2116,6 +2117,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
2116 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});2117 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
2117}2118}
21182119
2120fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {
2121 _ = inst;
2122 return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch});
2123}
2124
2119/// T to E!T2125/// T to E!T
2120fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {2126fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
2121 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2127 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
src/arch/riscv64/CodeGen.zig+6
...@@ -665,6 +665,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -665,6 +665,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
665 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),665 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
666 .err_return_trace => try self.airErrReturnTrace(inst),666 .err_return_trace => try self.airErrReturnTrace(inst),
667 .set_err_return_trace => try self.airSetErrReturnTrace(inst),667 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
668 .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst),
668669
669 .wrap_optional => try self.airWrapOptional(inst),670 .wrap_optional => try self.airWrapOptional(inst),
670 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),671 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -1329,6 +1330,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {...@@ -1329,6 +1330,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
1329 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});1330 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
1330}1331}
13311332
1333fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {
1334 _ = inst;
1335 return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch});
1336}
1337
1332fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {1338fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1333 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1339 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1334 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1340 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
src/arch/sparc64/CodeGen.zig+1
...@@ -679,6 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -679,6 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
679 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),679 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
680 .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"),680 .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"),
681 .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"),681 .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"),
682 .save_err_return_trace_index=> @panic("TODO try self.airSaveErrReturnTraceIndex(inst)"),
682683
683 .wrap_optional => try self.airWrapOptional(inst),684 .wrap_optional => try self.airWrapOptional(inst),
684 .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"),685 .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"),
src/arch/wasm/CodeGen.zig+1
...@@ -1857,6 +1857,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1857,6 +1857,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1857 .tag_name,1857 .tag_name,
1858 .err_return_trace,1858 .err_return_trace,
1859 .set_err_return_trace,1859 .set_err_return_trace,
1860 .save_err_return_trace_index,
1860 .is_named_enum_value,1861 .is_named_enum_value,
1861 .error_set_has_value,1862 .error_set_has_value,
1862 .addrspace_cast,1863 .addrspace_cast,
src/arch/x86_64/CodeGen.zig+6
...@@ -756,6 +756,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -756,6 +756,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
756 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),756 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
757 .err_return_trace => try self.airErrReturnTrace(inst),757 .err_return_trace => try self.airErrReturnTrace(inst),
758 .set_err_return_trace => try self.airSetErrReturnTrace(inst),758 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
759 .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst),
759760
760 .wrap_optional => try self.airWrapOptional(inst),761 .wrap_optional => try self.airWrapOptional(inst),
761 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),762 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -1973,6 +1974,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {...@@ -1973,6 +1974,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
1973 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});1974 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
1974}1975}
19751976
1977fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {
1978 _ = inst;
1979 return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch});
1980}
1981
1976fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {1982fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1977 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1983 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1978 if (self.liveness.isUnused(inst)) {1984 if (self.liveness.isUnused(inst)) {
src/codegen/c.zig+6
...@@ -1935,6 +1935,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1935,6 +1935,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1935 .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),1935 .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),
1936 .err_return_trace => try airErrReturnTrace(f, inst),1936 .err_return_trace => try airErrReturnTrace(f, inst),
1937 .set_err_return_trace => try airSetErrReturnTrace(f, inst),1937 .set_err_return_trace => try airSetErrReturnTrace(f, inst),
1938 .save_err_return_trace_index => try airSaveErrReturnTraceIndex(f, inst),
19381939
1939 .wasm_memory_size => try airWasmMemorySize(f, inst),1940 .wasm_memory_size => try airWasmMemorySize(f, inst),
1940 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),1941 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
...@@ -3625,6 +3626,11 @@ fn airSetErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3625,6 +3626,11 @@ fn airSetErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
3625 return f.fail("TODO: C backend: implement airSetErrReturnTrace", .{});3626 return f.fail("TODO: C backend: implement airSetErrReturnTrace", .{});
3626}3627}
36273628
3629fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {
3630 _ = inst;
3631 return f.fail("TODO: C backend: implement airSaveErrReturnTraceIndex", .{});
3632}
3633
3628fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {3634fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
3629 if (f.liveness.isUnused(inst))3635 if (f.liveness.isUnused(inst))
3630 return CValue.none;3636 return CValue.none;
src/codegen/llvm.zig+19
...@@ -4592,6 +4592,7 @@ pub const FuncGen = struct {...@@ -4592,6 +4592,7 @@ pub const FuncGen = struct {
4592 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),4592 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
4593 .err_return_trace => try self.airErrReturnTrace(inst),4593 .err_return_trace => try self.airErrReturnTrace(inst),
4594 .set_err_return_trace => try self.airSetErrReturnTrace(inst),4594 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
4595 .save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst),
45954596
4596 .wrap_optional => try self.airWrapOptional(inst),4597 .wrap_optional => try self.airWrapOptional(inst),
4597 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),4598 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -6543,6 +6544,24 @@ pub const FuncGen = struct {...@@ -6543,6 +6544,24 @@ pub const FuncGen = struct {
6543 return null;6544 return null;
6544 }6545 }
65456546
6547 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6548 if (self.liveness.isUnused(inst)) return null;
6549
6550 const target = self.dg.module.getTarget();
6551
6552 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6553 //const struct_ty = try self.resolveInst(ty_pl.ty);
6554 const struct_ty = self.air.getRefType(ty_pl.ty);
6555 const field_index = ty_pl.payload;
6556
6557 var ptr_ty_buf: Type.Payload.Pointer = undefined;
6558 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
6559 const struct_llvm_ty = try self.dg.lowerType(struct_ty);
6560 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field_index, "");
6561 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
6562 return self.load(field_ptr, field_ptr_ty);
6563 }
6564
6546 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6565 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6547 if (self.liveness.isUnused(inst)) return null;6566 if (self.liveness.isUnused(inst)) return null;
65486567
src/print_air.zig+1
...@@ -197,6 +197,7 @@ const Writer = struct {...@@ -197,6 +197,7 @@ const Writer = struct {
197 .unreach,197 .unreach,
198 .ret_addr,198 .ret_addr,
199 .frame_addr,199 .frame_addr,
200 .save_err_return_trace_index,
200 => try w.writeNoOp(s, inst),201 => try w.writeNoOp(s, inst),
201202
202 .const_ty,203 .const_ty,