authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-02 18:48:32-07:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-05 10:37:08+02:00
logef885a78d606693c73641159731274cc57f6ea98
tree6c962ecd3098f25ca6e5da87cd018fb90c6f1520
parent0224ad19b82bb307a2c246f2e30826af599aa895

stage2: implement the new "try" ZIR/AIR instruction

Implements semantic analysis for the new try/try_inline ZIR instruction. Adds the new try/try_ptr AIR instructions and implements them for the LLVM backend. Fixes not calling rvalue() for tryExpr in AstGen. This is part of an effort to implement #11772.

13 files changed, 229 insertions(+), 8 deletions(-)

src/Air.zig+33
...@@ -320,6 +320,20 @@ pub const Inst = struct {...@@ -320,6 +320,20 @@ pub const Inst = struct {
320 /// Result type is always noreturn; no instructions in a block follow this one.320 /// Result type is always noreturn; no instructions in a block follow this one.
321 /// Uses the `pl_op` field. Operand is the condition. Payload is `SwitchBr`.321 /// Uses the `pl_op` field. Operand is the condition. Payload is `SwitchBr`.
322 switch_br,322 switch_br,
323 /// Given an operand which is an error union, splits control flow. In
324 /// case of error, control flow goes into the block that is part of this
325 /// instruction, which is guaranteed to end with a return instruction
326 /// and never breaks out of the block.
327 /// In the case of non-error, control flow proceeds to the next instruction
328 /// after the `try`, with the result of this instruction being the unwrapped
329 /// payload value, as if `unwrap_errunion_payload` was executed on the operand.
330 /// Uses the `pl_op` field. Payload is `Try`.
331 @"try",
332 /// Same as `try` except the operand is a pointer to an error union, and the
333 /// result is a pointer to the payload. Result is as if `unwrap_errunion_payload_ptr`
334 /// was executed on the operand.
335 /// Uses the `ty_pl` field. Payload is `TryPtr`.
336 try_ptr,
323 /// A comptime-known value. Uses the `ty_pl` field, payload is index of337 /// A comptime-known value. Uses the `ty_pl` field, payload is index of
324 /// `values` array.338 /// `values` array.
325 constant,339 constant,
...@@ -780,6 +794,19 @@ pub const SwitchBr = struct {...@@ -780,6 +794,19 @@ pub const SwitchBr = struct {
780 };794 };
781};795};
782796
797/// This data is stored inside extra. Trailing:
798/// 0. body: Inst.Index // for each body_len
799pub const Try = struct {
800 body_len: u32,
801};
802
803/// This data is stored inside extra. Trailing:
804/// 0. body: Inst.Index // for each body_len
805pub const TryPtr = struct {
806 ptr: Inst.Ref,
807 body_len: u32,
808};
809
783pub const StructField = struct {810pub const StructField = struct {
784 /// Whether this is a pointer or byval is determined by the AIR tag.811 /// Whether this is a pointer or byval is determined by the AIR tag.
785 struct_operand: Inst.Ref,812 struct_operand: Inst.Ref,
...@@ -1028,6 +1055,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1028,6 +1055,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1028 .popcount,1055 .popcount,
1029 .byte_swap,1056 .byte_swap,
1030 .bit_reverse,1057 .bit_reverse,
1058 .try_ptr,
1031 => return air.getRefType(datas[inst].ty_op.ty),1059 => return air.getRefType(datas[inst].ty_op.ty),
10321060
1033 .loop,1061 .loop,
...@@ -1102,6 +1130,11 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1102,6 +1130,11 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1102 const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data;1130 const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data;
1103 return air.typeOf(extra.lhs);1131 return air.typeOf(extra.lhs);
1104 },1132 },
1133
1134 .@"try" => {
1135 const err_union_ty = air.typeOf(datas[inst].pl_op.operand);
1136 return err_union_ty.errorUnionPayload();
1137 },
1105 }1138 }
1106}1139}
11071140
src/AstGen.zig+2-1
...@@ -4896,7 +4896,8 @@ fn tryExpr(...@@ -4896,7 +4896,8 @@ fn tryExpr(
4896 _ = try else_scope.addUnNode(.ret_node, err_code, node);4896 _ = try else_scope.addUnNode(.ret_node, err_code, node);
48974897
4898 try else_scope.setTryBody(try_inst, operand);4898 try else_scope.setTryBody(try_inst, operand);
4899 return indexToRef(try_inst);4899 const result = indexToRef(try_inst);
4900 return rvalue(parent_gz, rl, result, node);
4900}4901}
49014902
4902fn orelseCatchExpr(4903fn orelseCatchExpr(
src/Liveness.zig+19
...@@ -478,6 +478,12 @@ pub fn categorizeOperand(...@@ -478,6 +478,12 @@ pub fn categorizeOperand(
478 .block => {478 .block => {
479 return .complex;479 return .complex;
480 },480 },
481 .@"try" => {
482 return .complex;
483 },
484 .try_ptr => {
485 return .complex;
486 },
481 .loop => {487 .loop => {
482 return .complex;488 return .complex;
483 },489 },
...@@ -1019,6 +1025,19 @@ fn analyzeInst(...@@ -1019,6 +1025,19 @@ fn analyzeInst(
1019 try analyzeWithContext(a, new_set, body);1025 try analyzeWithContext(a, new_set, body);
1020 return; // Loop has no operands and it is always unreferenced.1026 return; // Loop has no operands and it is always unreferenced.
1021 },1027 },
1028 .@"try" => {
1029 const pl_op = inst_datas[inst].pl_op;
1030 const extra = a.air.extraData(Air.Try, pl_op.payload);
1031 const body = a.air.extra[extra.end..][0..extra.data.body_len];
1032 try analyzeWithContext(a, new_set, body);
1033 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, .none, .none });
1034 },
1035 .try_ptr => {
1036 const extra = a.air.extraData(Air.TryPtr, inst_datas[inst].ty_pl.payload);
1037 const body = a.air.extra[extra.end..][0..extra.data.body_len];
1038 try analyzeWithContext(a, new_set, body);
1039 return trackOperands(a, new_set, inst, main_tomb, .{ extra.data.ptr, .none, .none });
1040 },
1022 .cond_br => {1041 .cond_br => {
1023 // Each death that occurs inside one branch, but not the other, needs1042 // Each death that occurs inside one branch, but not the other, needs
1024 // to be added as a death immediately upon entering the other branch.1043 // to be added as a death immediately upon entering the other branch.
src/Sema.zig+48-4
...@@ -12983,7 +12983,8 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -12983,7 +12983,8 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
12983 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);12983 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
12984 const body = sema.code.extra[extra.end..][0..extra.data.body_len];12984 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
12985 const operand = try sema.resolveInst(extra.data.operand);12985 const operand = try sema.resolveInst(extra.data.operand);
12986 const is_ptr = sema.typeOf(operand).zigTypeTag() == .Pointer;12986 const operand_ty = sema.typeOf(operand);
12987 const is_ptr = operand_ty.zigTypeTag() == .Pointer;
12987 const err_union = if (is_ptr)12988 const err_union = if (is_ptr)
12988 try sema.analyzeLoad(parent_block, src, operand, operand_src)12989 try sema.analyzeLoad(parent_block, src, operand, operand_src)
12989 else12990 else
...@@ -13008,9 +13009,52 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -13008,9 +13009,52 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
13008 // no breaks from the body possible, and that the body is noreturn.13009 // no breaks from the body possible, and that the body is noreturn.
13009 return sema.resolveBody(parent_block, body, inst);13010 return sema.resolveBody(parent_block, body, inst);
13010 }13011 }
13011 _ = body;13012
13012 _ = is_non_err;13013 var sub_block = parent_block.makeSubBlock();
13013 @panic("TODO");13014 defer sub_block.instructions.deinit(sema.gpa);
13015
13016 // This body is guaranteed to end with noreturn and has no breaks.
13017 _ = try sema.analyzeBodyInner(&sub_block, body);
13018
13019 if (is_ptr) {
13020 const ptr_info = operand_ty.ptrInfo().data;
13021 const res_ty = try Type.ptr(sema.arena, sema.mod, .{
13022 .pointee_type = err_union_ty.errorUnionPayload(),
13023 .@"addrspace" = ptr_info.@"addrspace",
13024 .mutable = ptr_info.mutable,
13025 .@"allowzero" = ptr_info.@"allowzero",
13026 .@"volatile" = ptr_info.@"volatile",
13027 });
13028 const res_ty_ref = try sema.addType(res_ty);
13029 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len +
13030 sub_block.instructions.items.len);
13031 const try_inst = try parent_block.addInst(.{
13032 .tag = .try_ptr,
13033 .data = .{ .ty_pl = .{
13034 .ty = res_ty_ref,
13035 .payload = sema.addExtraAssumeCapacity(Air.TryPtr{
13036 .ptr = operand,
13037 .body_len = @intCast(u32, sub_block.instructions.items.len),
13038 }),
13039 } },
13040 });
13041 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
13042 return try_inst;
13043 }
13044
13045 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Try).Struct.fields.len +
13046 sub_block.instructions.items.len);
13047 const try_inst = try parent_block.addInst(.{
13048 .tag = .@"try",
13049 .data = .{ .pl_op = .{
13050 .operand = operand,
13051 .payload = sema.addExtraAssumeCapacity(Air.Try{
13052 .body_len = @intCast(u32, sub_block.instructions.items.len),
13053 }),
13054 } },
13055 });
13056 sema.air_extra.appendSliceAssumeCapacity(sub_block.instructions.items);
13057 return try_inst;
13014}13058}
1301513059
13016// A `break` statement is inside a runtime condition, but trying to13060// A `break` statement is inside a runtime condition, but trying to
src/arch/aarch64/CodeGen.zig+3
...@@ -665,6 +665,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -665,6 +665,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
665 .prefetch => try self.airPrefetch(inst),665 .prefetch => try self.airPrefetch(inst),
666 .mul_add => try self.airMulAdd(inst),666 .mul_add => try self.airMulAdd(inst),
667667
668 .@"try" => @panic("TODO"),
669 .try_ptr => @panic("TODO"),
670
668 .dbg_var_ptr,671 .dbg_var_ptr,
669 .dbg_var_val,672 .dbg_var_val,
670 => try self.airDbgVar(inst),673 => try self.airDbgVar(inst),
src/arch/arm/CodeGen.zig+3
...@@ -677,6 +677,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -677,6 +677,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
677 .prefetch => try self.airPrefetch(inst),677 .prefetch => try self.airPrefetch(inst),
678 .mul_add => try self.airMulAdd(inst),678 .mul_add => try self.airMulAdd(inst),
679679
680 .@"try" => @panic("TODO"),
681 .try_ptr => @panic("TODO"),
682
680 .dbg_var_ptr,683 .dbg_var_ptr,
681 .dbg_var_val,684 .dbg_var_val,
682 => try self.airDbgVar(inst),685 => try self.airDbgVar(inst),
src/arch/riscv64/CodeGen.zig+3
...@@ -604,6 +604,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -604,6 +604,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
604 .prefetch => try self.airPrefetch(inst),604 .prefetch => try self.airPrefetch(inst),
605 .mul_add => try self.airMulAdd(inst),605 .mul_add => try self.airMulAdd(inst),
606606
607 .@"try" => @panic("TODO"),
608 .try_ptr => @panic("TODO"),
609
607 .dbg_var_ptr,610 .dbg_var_ptr,
608 .dbg_var_val,611 .dbg_var_val,
609 => try self.airDbgVar(inst),612 => try self.airDbgVar(inst),
src/arch/sparc64/CodeGen.zig+3
...@@ -604,6 +604,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -604,6 +604,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
604 .prefetch => @panic("TODO try self.airPrefetch(inst)"),604 .prefetch => @panic("TODO try self.airPrefetch(inst)"),
605 .mul_add => @panic("TODO try self.airMulAdd(inst)"),605 .mul_add => @panic("TODO try self.airMulAdd(inst)"),
606606
607 .@"try" => @panic("TODO try self.airTry(inst)"),
608 .try_ptr => @panic("TODO try self.airTryPtr(inst)"),
609
607 .dbg_var_ptr,610 .dbg_var_ptr,
608 .dbg_var_val,611 .dbg_var_val,
609 => try self.airDbgVar(inst),612 => try self.airDbgVar(inst),
src/arch/wasm/CodeGen.zig+3
...@@ -1490,6 +1490,9 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1490,6 +1490,9 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1490 .int_to_float => self.airIntToFloat(inst),1490 .int_to_float => self.airIntToFloat(inst),
1491 .get_union_tag => self.airGetUnionTag(inst),1491 .get_union_tag => self.airGetUnionTag(inst),
14921492
1493 .@"try" => @panic("TODO"),
1494 .try_ptr => @panic("TODO"),
1495
1493 // TODO1496 // TODO
1494 .dbg_inline_begin,1497 .dbg_inline_begin,
1495 .dbg_inline_end,1498 .dbg_inline_end,
src/arch/x86_64/CodeGen.zig+3
...@@ -681,6 +681,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -681,6 +681,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
681 .prefetch => try self.airPrefetch(inst),681 .prefetch => try self.airPrefetch(inst),
682 .mul_add => try self.airMulAdd(inst),682 .mul_add => try self.airMulAdd(inst),
683683
684 .@"try" => @panic("TODO"),
685 .try_ptr => @panic("TODO"),
686
684 .dbg_var_ptr,687 .dbg_var_ptr,
685 .dbg_var_val,688 .dbg_var_val,
686 => try self.airDbgVar(inst),689 => try self.airDbgVar(inst),
src/codegen/c.zig+3
...@@ -1875,6 +1875,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1875,6 +1875,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1875 .union_init => try airUnionInit(f, inst),1875 .union_init => try airUnionInit(f, inst),
1876 .prefetch => try airPrefetch(f, inst),1876 .prefetch => try airPrefetch(f, inst),
18771877
1878 .@"try" => @panic("TODO"),
1879 .try_ptr => @panic("TODO"),
1880
1878 .dbg_var_ptr,1881 .dbg_var_ptr,
1879 .dbg_var_val,1882 .dbg_var_val,
1880 => try airDbgVar(f, inst),1883 => try airDbgVar(f, inst),
src/codegen/llvm.zig+74-3
...@@ -4040,6 +4040,8 @@ pub const FuncGen = struct {...@@ -4040,6 +4040,8 @@ pub const FuncGen = struct {
4040 .ret_addr => try self.airRetAddr(inst),4040 .ret_addr => try self.airRetAddr(inst),
4041 .frame_addr => try self.airFrameAddress(inst),4041 .frame_addr => try self.airFrameAddress(inst),
4042 .cond_br => try self.airCondBr(inst),4042 .cond_br => try self.airCondBr(inst),
4043 .@"try" => try self.airTry(inst),
4044 .try_ptr => try self.airTryPtr(inst),
4043 .intcast => try self.airIntCast(inst),4045 .intcast => try self.airIntCast(inst),
4044 .trunc => try self.airTrunc(inst),4046 .trunc => try self.airTrunc(inst),
4045 .fptrunc => try self.airFptrunc(inst),4047 .fptrunc => try self.airFptrunc(inst),
...@@ -4731,6 +4733,75 @@ pub const FuncGen = struct {...@@ -4731,6 +4733,75 @@ pub const FuncGen = struct {
4731 return null;4733 return null;
4732 }4734 }
47334735
4736 fn airTry(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4737 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4738 const err_union = try self.resolveInst(pl_op.operand);
4739 const extra = self.air.extraData(Air.Try, pl_op.payload);
4740 const body = self.air.extra[extra.end..][0..extra.data.body_len];
4741 const err_union_ty = self.air.typeOf(pl_op.operand);
4742 const result_ty = self.air.typeOfIndex(inst);
4743 return lowerTry(self, err_union, body, err_union_ty, false, result_ty);
4744 }
4745
4746 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4747 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
4748 const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
4749 const err_union_ptr = try self.resolveInst(extra.data.ptr);
4750 const body = self.air.extra[extra.end..][0..extra.data.body_len];
4751 const err_union_ty = self.air.typeOf(extra.data.ptr).childType();
4752 const result_ty = self.air.typeOfIndex(inst);
4753 return lowerTry(self, err_union_ptr, body, err_union_ty, true, result_ty);
4754 }
4755
4756 fn lowerTry(fg: *FuncGen, err_union: *const llvm.Value, body: []const Air.Inst.Index, err_union_ty: Type, operand_is_ptr: bool, result_ty: Type) !?*const llvm.Value {
4757 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
4758 // If the error set has no fields, then the payload and the error
4759 // union are the same value.
4760 return err_union;
4761 }
4762
4763 const payload_ty = err_union_ty.errorUnionPayload();
4764 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
4765 const target = fg.dg.module.getTarget();
4766 const is_err = err: {
4767 const err_set_ty = try fg.dg.lowerType(Type.anyerror);
4768 const zero = err_set_ty.constNull();
4769 if (!payload_has_bits) {
4770 const loaded = if (operand_is_ptr) fg.builder.buildLoad(err_union, "") else err_union;
4771 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
4772 }
4773 const err_field_index = errUnionErrorOffset(payload_ty, target);
4774 if (operand_is_ptr or isByRef(err_union_ty)) {
4775 const err_field_ptr = fg.builder.buildStructGEP(err_union, err_field_index, "");
4776 const loaded = fg.builder.buildLoad(err_field_ptr, "");
4777 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
4778 }
4779 const loaded = fg.builder.buildExtractValue(err_union, err_field_index, "");
4780 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
4781 };
4782
4783 const return_block = fg.context.appendBasicBlock(fg.llvm_func, "TryRet");
4784 const continue_block = fg.context.appendBasicBlock(fg.llvm_func, "TryCont");
4785 _ = fg.builder.buildCondBr(is_err, return_block, continue_block);
4786
4787 fg.builder.positionBuilderAtEnd(return_block);
4788 try fg.genBody(body);
4789
4790 fg.builder.positionBuilderAtEnd(continue_block);
4791 if (!payload_has_bits) {
4792 if (!operand_is_ptr) return null;
4793
4794 // TODO once we update to LLVM 14 this bitcast won't be necessary.
4795 const res_ptr_ty = try fg.dg.lowerType(result_ty);
4796 return fg.builder.buildBitCast(err_union, res_ptr_ty, "");
4797 }
4798 const offset = errUnionPayloadOffset(payload_ty, target);
4799 if (operand_is_ptr or isByRef(payload_ty)) {
4800 return fg.builder.buildStructGEP(err_union, offset, "");
4801 }
4802 return fg.builder.buildExtractValue(err_union, offset, "");
4803 }
4804
4734 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {4805 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4735 const pl_op = self.air.instructions.items(.data)[inst].pl_op;4806 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4736 const cond = try self.resolveInst(pl_op.operand);4807 const cond = try self.resolveInst(pl_op.operand);
...@@ -5673,15 +5744,14 @@ pub const FuncGen = struct {...@@ -5673,15 +5744,14 @@ pub const FuncGen = struct {
5673 const operand = try self.resolveInst(ty_op.operand);5744 const operand = try self.resolveInst(ty_op.operand);
5674 const operand_ty = self.air.typeOf(ty_op.operand);5745 const operand_ty = self.air.typeOf(ty_op.operand);
5675 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;5746 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
5676 // If the error set has no fields, then the payload and the error
5677 // union are the same value.
5678 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {5747 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5748 // If the error set has no fields, then the payload and the error
5749 // union are the same value.
5679 return operand;5750 return operand;
5680 }5751 }
5681 const result_ty = self.air.typeOfIndex(inst);5752 const result_ty = self.air.typeOfIndex(inst);
5682 const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;5753 const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
5683 const target = self.dg.module.getTarget();5754 const target = self.dg.module.getTarget();
5684 const offset = errUnionPayloadOffset(payload_ty, target);
56855755
5686 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5756 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5687 if (!operand_is_ptr) return null;5757 if (!operand_is_ptr) return null;
...@@ -5690,6 +5760,7 @@ pub const FuncGen = struct {...@@ -5690,6 +5760,7 @@ pub const FuncGen = struct {
5690 const res_ptr_ty = try self.dg.lowerType(result_ty);5760 const res_ptr_ty = try self.dg.lowerType(result_ty);
5691 return self.builder.buildBitCast(operand, res_ptr_ty, "");5761 return self.builder.buildBitCast(operand, res_ptr_ty, "");
5692 }5762 }
5763 const offset = errUnionPayloadOffset(payload_ty, target);
5693 if (operand_is_ptr or isByRef(payload_ty)) {5764 if (operand_is_ptr or isByRef(payload_ty)) {
5694 return self.builder.buildStructGEP(operand, offset, "");5765 return self.builder.buildStructGEP(operand, offset, "");
5695 }5766 }
src/print_air.zig+32
...@@ -258,6 +258,8 @@ const Writer = struct {...@@ -258,6 +258,8 @@ const Writer = struct {
258 .union_init => try w.writeUnionInit(s, inst),258 .union_init => try w.writeUnionInit(s, inst),
259 .br => try w.writeBr(s, inst),259 .br => try w.writeBr(s, inst),
260 .cond_br => try w.writeCondBr(s, inst),260 .cond_br => try w.writeCondBr(s, inst),
261 .@"try" => try w.writeTry(s, inst),
262 .try_ptr => try w.writeTryPtr(s, inst),
261 .switch_br => try w.writeSwitchBr(s, inst),263 .switch_br => try w.writeSwitchBr(s, inst),
262 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),264 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
263 .fence => try w.writeFence(s, inst),265 .fence => try w.writeFence(s, inst),
...@@ -624,6 +626,36 @@ const Writer = struct {...@@ -624,6 +626,36 @@ const Writer = struct {
624 try w.writeOperand(s, inst, 0, br.operand);626 try w.writeOperand(s, inst, 0, br.operand);
625 }627 }
626628
629 fn writeTry(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
630 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
631 const extra = w.air.extraData(Air.Try, pl_op.payload);
632 const body = w.air.extra[extra.end..][0..extra.data.body_len];
633
634 try w.writeOperand(s, inst, 0, pl_op.operand);
635 try s.writeAll(", {\n");
636 const old_indent = w.indent;
637 w.indent += 2;
638 try w.writeBody(s, body);
639 w.indent = old_indent;
640 try s.writeByteNTimes(' ', w.indent);
641 try s.writeAll("}");
642 }
643
644 fn writeTryPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
645 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
646 const extra = w.air.extraData(Air.TryPtr, ty_pl.payload);
647 const body = w.air.extra[extra.end..][0..extra.data.body_len];
648
649 try w.writeOperand(s, inst, 0, extra.data.ptr);
650 try s.print(", {}, {{\n", .{w.air.getRefType(ty_pl.ty).fmtDebug()});
651 const old_indent = w.indent;
652 w.indent += 2;
653 try w.writeBody(s, body);
654 w.indent = old_indent;
655 try s.writeByteNTimes(' ', w.indent);
656 try s.writeAll("}");
657 }
658
627 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {659 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
628 const pl_op = w.air.instructions.items(.data)[inst].pl_op;660 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
629 const extra = w.air.extraData(Air.CondBr, pl_op.payload);661 const extra = w.air.extraData(Air.CondBr, pl_op.payload);