| author | |
| committer | |
| log | ef885a78d606693c73641159731274cc57f6ea98 |
| tree | 6c962ecd3098f25ca6e5da87cd018fb90c6f1520 |
| parent | 0224ad19b82bb307a2c246f2e30826af599aa895 |
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 of | 337 | /// 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 | }; |
| 782 | 796 | ||
| 797 | /// This data is stored inside extra. Trailing: | ||
| 798 | /// 0. body: Inst.Index // for each body_len | ||
| 799 | pub 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 | ||
| 805 | pub const TryPtr = struct { | ||
| 806 | ptr: Inst.Ref, | ||
| 807 | body_len: u32, | ||
| 808 | }; | ||
| 809 | |||
| 783 | pub const StructField = struct { | 810 | pub 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), |
| 1032 | 1060 | ||
| 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 | } |
| 1107 | 1140 |
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); |
| 4897 | 4897 | ||
| 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 | } |
| 4901 | 4902 | ||
| 4902 | fn orelseCatchExpr( | 4903 | fn 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, needs | 1042 | // 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 | else | 12990 | 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 | } |
| 13015 | 13059 | ||
| 13016 | // A `break` statement is inside a runtime condition, but trying to | 13060 | // 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), |
| 667 | 667 | ||
| 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), |
| 679 | 679 | ||
| 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), |
| 606 | 606 | ||
| 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)"), |
| 606 | 606 | ||
| 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), |
| 1492 | 1492 | ||
| 1493 | .@"try" => @panic("TODO"), | ||
| 1494 | .try_ptr => @panic("TODO"), | ||
| 1495 | |||
| 1493 | // TODO | 1496 | // 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), |
| 683 | 683 | ||
| 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), |
| 1877 | 1877 | ||
| 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 | } |
| 4733 | 4735 | ||
| 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); | ||
| 5685 | 5755 | ||
| 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 | } |
| 626 | 628 | ||
| 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); |