| author | |
| committer | |
| log | 724d75363855176aa5e6b3d9bcd1656e2cc1f6a6 |
| tree | f3b5c2e68dcc355ade60e3c75065002715040790 |
| parent | 3007fdde45868142654d0bfa59bc0e17e5f24a1c |
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 | 733 | /// Uses the `ty_op` field. |
| 734 | 734 | addrspace_cast, |
| 735 | 735 | |
| 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 | 740 | pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag { |
| 737 | 741 | switch (op) { |
| 738 | 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 | 1183 | .slice_len, |
| 1180 | 1184 | .ret_addr, |
| 1181 | 1185 | .frame_addr, |
| 1186 | .save_err_return_trace_index, | |
| 1182 | 1187 | => return Type.usize, |
| 1183 | 1188 | |
| 1184 | 1189 | .wasm_memory_grow => return Type.i32, |
src/Liveness.zig+2| ... | ... | @@ -228,6 +228,7 @@ pub fn categorizeOperand( |
| 228 | 228 | .frame_addr, |
| 229 | 229 | .wasm_memory_size, |
| 230 | 230 | .err_return_trace, |
| 231 | .save_err_return_trace_index, | |
| 231 | 232 | => return .none, |
| 232 | 233 | |
| 233 | 234 | .fence => return .write, |
| ... | ... | @@ -805,6 +806,7 @@ fn analyzeInst( |
| 805 | 806 | .frame_addr, |
| 806 | 807 | .wasm_memory_size, |
| 807 | 808 | .err_return_trace, |
| 809 | .save_err_return_trace_index, | |
| 808 | 810 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), |
| 809 | 811 | |
| 810 | 812 | .not, |
src/Sema.zig+17-10| ... | ... | @@ -16228,22 +16228,28 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 16228 | 16228 | // This is only relevant at runtime. |
| 16229 | 16229 | if (block.is_comptime) return Air.Inst.Ref.zero_usize; |
| 16230 | 16230 | |
| 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 | 16231 | const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; |
| 16238 | 16232 | const ok = sema.mod.comp.bin_file.options.error_return_tracing and |
| 16239 | 16233 | backend_supports_error_return_tracing; |
| 16240 | 16234 | if (!ok) return Air.Inst.Ref.zero_usize; |
| 16241 | 16235 | |
| 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 | 16243 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); |
| 16243 | 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 err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | |
| 16246 | return sema.fieldVal(block, src, err_return_trace, "index", src); | |
| 16245 | const field_index = try sema.structFieldIndex(block, stack_trace_ty, "index", src); | |
| 16246 | return block.addInst(.{ | |
| 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 | } |
| 16248 | 16254 | |
| 16249 | 16255 | 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 |
| 16254 | 16260 | if (block.is_comptime) return; |
| 16255 | 16261 | |
| 16256 | 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 and | |
| 16263 | const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and | |
| 16264 | sema.mod.comp.bin_file.options.error_return_tracing and | |
| 16258 | 16265 | backend_supports_error_return_tracing; |
| 16259 | 16266 | if (!ok) return; |
| 16260 | 16267 |
src/arch/aarch64/CodeGen.zig+6| ... | ... | @@ -702,6 +702,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 702 | 702 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| 703 | 703 | .err_return_trace => try self.airErrReturnTrace(inst), |
| 704 | 704 | .set_err_return_trace => try self.airSetErrReturnTrace(inst), |
| 705 | .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), | |
| 705 | 706 | |
| 706 | 707 | .wrap_optional => try self.airWrapOptional(inst), |
| 707 | 708 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -2867,6 +2868,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| 2867 | 2868 | return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 2868 | 2869 | } |
| 2869 | 2870 | |
| 2871 | fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | |
| 2872 | _ = inst; | |
| 2873 | return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); | |
| 2874 | } | |
| 2875 | ||
| 2870 | 2876 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2871 | 2877 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2872 | 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 | 751 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| 752 | 752 | .err_return_trace => try self.airErrReturnTrace(inst), |
| 753 | 753 | .set_err_return_trace => try self.airSetErrReturnTrace(inst), |
| 754 | .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), | |
| 754 | 755 | |
| 755 | 756 | .wrap_optional => try self.airWrapOptional(inst), |
| 756 | 757 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -2116,6 +2117,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| 2116 | 2117 | return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 2117 | 2118 | } |
| 2118 | 2119 | |
| 2120 | fn 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 | 2125 | /// T to E!T |
| 2120 | 2126 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2121 | 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 | 665 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| 666 | 666 | .err_return_trace => try self.airErrReturnTrace(inst), |
| 667 | 667 | .set_err_return_trace => try self.airSetErrReturnTrace(inst), |
| 668 | .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), | |
| 668 | 669 | |
| 669 | 670 | .wrap_optional => try self.airWrapOptional(inst), |
| 670 | 671 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -1329,6 +1330,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| 1329 | 1330 | return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 1330 | 1331 | } |
| 1331 | 1332 | |
| 1333 | fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | |
| 1334 | _ = inst; | |
| 1335 | return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); | |
| 1336 | } | |
| 1337 | ||
| 1332 | 1338 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1333 | 1339 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1334 | 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 | 679 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| 680 | 680 | .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"), |
| 681 | 681 | .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"), |
| 682 | .save_err_return_trace_index=> @panic("TODO try self.airSaveErrReturnTraceIndex(inst)"), | |
| 682 | 683 | |
| 683 | 684 | .wrap_optional => try self.airWrapOptional(inst), |
| 684 | 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 | 1857 | .tag_name, |
| 1858 | 1858 | .err_return_trace, |
| 1859 | 1859 | .set_err_return_trace, |
| 1860 | .save_err_return_trace_index, | |
| 1860 | 1861 | .is_named_enum_value, |
| 1861 | 1862 | .error_set_has_value, |
| 1862 | 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 | 756 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| 757 | 757 | .err_return_trace => try self.airErrReturnTrace(inst), |
| 758 | 758 | .set_err_return_trace => try self.airSetErrReturnTrace(inst), |
| 759 | .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), | |
| 759 | 760 | |
| 760 | 761 | .wrap_optional => try self.airWrapOptional(inst), |
| 761 | 762 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -1973,6 +1974,11 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| 1973 | 1974 | return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 1974 | 1975 | } |
| 1975 | 1976 | |
| 1977 | fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | |
| 1978 | _ = inst; | |
| 1979 | return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); | |
| 1980 | } | |
| 1981 | ||
| 1976 | 1982 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1977 | 1983 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1978 | 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 | 1935 | .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst), |
| 1936 | 1936 | .err_return_trace => try airErrReturnTrace(f, inst), |
| 1937 | 1937 | .set_err_return_trace => try airSetErrReturnTrace(f, inst), |
| 1938 | .save_err_return_trace_index => try airSaveErrReturnTraceIndex(f, inst), | |
| 1938 | 1939 | |
| 1939 | 1940 | .wasm_memory_size => try airWasmMemorySize(f, inst), |
| 1940 | 1941 | .wasm_memory_grow => try airWasmMemoryGrow(f, inst), |
| ... | ... | @@ -3625,6 +3626,11 @@ fn airSetErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3625 | 3626 | return f.fail("TODO: C backend: implement airSetErrReturnTrace", .{}); |
| 3626 | 3627 | } |
| 3627 | 3628 | |
| 3629 | fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 3630 | _ = inst; | |
| 3631 | return f.fail("TODO: C backend: implement airSaveErrReturnTraceIndex", .{}); | |
| 3632 | } | |
| 3633 | ||
| 3628 | 3634 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3629 | 3635 | if (f.liveness.isUnused(inst)) |
| 3630 | 3636 | return CValue.none; |
src/codegen/llvm.zig+19| ... | ... | @@ -4592,6 +4592,7 @@ pub const FuncGen = struct { |
| 4592 | 4592 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| 4593 | 4593 | .err_return_trace => try self.airErrReturnTrace(inst), |
| 4594 | 4594 | .set_err_return_trace => try self.airSetErrReturnTrace(inst), |
| 4595 | .save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst), | |
| 4595 | 4596 | |
| 4596 | 4597 | .wrap_optional => try self.airWrapOptional(inst), |
| 4597 | 4598 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | ... | @@ -6543,6 +6544,24 @@ pub const FuncGen = struct { |
| 6543 | 6544 | return null; |
| 6544 | 6545 | } |
| 6545 | 6546 | |
| 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 | 6565 | fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6547 | 6566 | if (self.liveness.isUnused(inst)) return null; |
| 6548 | 6567 |
src/print_air.zig+1| ... | ... | @@ -197,6 +197,7 @@ const Writer = struct { |
| 197 | 197 | .unreach, |
| 198 | 198 | .ret_addr, |
| 199 | 199 | .frame_addr, |
| 200 | .save_err_return_trace_index, | |
| 200 | 201 | => try w.writeNoOp(s, inst), |
| 201 | 202 | |
| 202 | 203 | .const_ty, |