| ... | ... | @@ -1104,7 +1104,13 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1104 | 1104 | |
| 1105 | 1105 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1106 | 1106 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1107 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union payload for {}", .{self.target.cpu.arch}); |
| 1107 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1108 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 1109 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1110 | if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; |
| 1111 | |
| 1112 | return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); |
| 1113 | }; |
| 1108 | 1114 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1109 | 1115 | } |
| 1110 | 1116 | |
| ... | ... | @@ -2008,18 +2014,52 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue { |
| 2008 | 2014 | return self.fail("TODO call isNull and invert the result", .{}); |
| 2009 | 2015 | } |
| 2010 | 2016 | |
| 2011 | | fn isErr(self: *Self, operand: MCValue) !MCValue { |
| 2017 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2012 | 2018 | _ = operand; |
| 2013 | | // Here you can specialize this instruction if it makes sense to, otherwise the default |
| 2014 | | // will call isNonNull and invert the result. |
| 2015 | | return self.fail("TODO call isNonErr and invert the result", .{}); |
| 2019 | |
| 2020 | const error_type = ty.errorUnionSet(); |
| 2021 | const payload_type = ty.errorUnionPayload(); |
| 2022 | |
| 2023 | if (!error_type.hasRuntimeBits()) { |
| 2024 | return MCValue{ .immediate = 0 }; // always false |
| 2025 | } else if (!payload_type.hasRuntimeBits()) { |
| 2026 | if (error_type.abiSize(self.target.*) <= 8) { |
| 2027 | const reg_mcv: MCValue = switch (operand) { |
| 2028 | .register => operand, |
| 2029 | else => .{ .register = try self.copyToTmpRegister(error_type, operand) }, |
| 2030 | }; |
| 2031 | |
| 2032 | _ = try self.addInst(.{ |
| 2033 | .tag = .cmp_immediate, |
| 2034 | .data = .{ .rr_imm12_sh = .{ |
| 2035 | .rd = .xzr, |
| 2036 | .rn = reg_mcv.register, |
| 2037 | .imm12 = 0, |
| 2038 | } }, |
| 2039 | }); |
| 2040 | |
| 2041 | return MCValue{ .compare_flags_unsigned = .gt }; |
| 2042 | } else { |
| 2043 | return self.fail("TODO isErr for errors with size > 8", .{}); |
| 2044 | } |
| 2045 | } else { |
| 2046 | return self.fail("TODO isErr for non-empty payloads", .{}); |
| 2047 | } |
| 2016 | 2048 | } |
| 2017 | 2049 | |
| 2018 | | fn isNonErr(self: *Self, operand: MCValue) !MCValue { |
| 2019 | | _ = operand; |
| 2020 | | // Here you can specialize this instruction if it makes sense to, otherwise the default |
| 2021 | | // will call isNull and invert the result. |
| 2022 | | return self.fail("TODO call isErr and invert the result", .{}); |
| 2050 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2051 | const is_err_result = try self.isErr(ty, operand); |
| 2052 | switch (is_err_result) { |
| 2053 | .compare_flags_unsigned => |op| { |
| 2054 | assert(op == .gt); |
| 2055 | return MCValue{ .compare_flags_unsigned = .lte }; |
| 2056 | }, |
| 2057 | .immediate => |imm| { |
| 2058 | assert(imm == 0); |
| 2059 | return MCValue{ .immediate = 1 }; |
| 2060 | }, |
| 2061 | else => unreachable, |
| 2062 | } |
| 2023 | 2063 | } |
| 2024 | 2064 | |
| 2025 | 2065 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2080,7 +2120,8 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2080 | 2120 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2081 | 2121 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2082 | 2122 | const operand = try self.resolveInst(un_op); |
| 2083 | | break :result try self.isErr(operand); |
| 2123 | const ty = self.air.typeOf(un_op); |
| 2124 | break :result try self.isErr(ty, operand); |
| 2084 | 2125 | }; |
| 2085 | 2126 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2086 | 2127 | } |
| ... | ... | @@ -2089,6 +2130,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2089 | 2130 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2090 | 2131 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2091 | 2132 | const operand_ptr = try self.resolveInst(un_op); |
| 2133 | const ptr_ty = self.air.typeOf(un_op); |
| 2092 | 2134 | const operand: MCValue = blk: { |
| 2093 | 2135 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2094 | 2136 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | ... | @@ -2098,7 +2140,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2098 | 2140 | } |
| 2099 | 2141 | }; |
| 2100 | 2142 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); |
| 2101 | | break :result try self.isErr(operand); |
| 2143 | break :result try self.isErr(ptr_ty.elemType(), operand); |
| 2102 | 2144 | }; |
| 2103 | 2145 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2104 | 2146 | } |
| ... | ... | @@ -2107,7 +2149,8 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2107 | 2149 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2108 | 2150 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2109 | 2151 | const operand = try self.resolveInst(un_op); |
| 2110 | | break :result try self.isNonErr(operand); |
| 2152 | const ty = self.air.typeOf(un_op); |
| 2153 | break :result try self.isNonErr(ty, operand); |
| 2111 | 2154 | }; |
| 2112 | 2155 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2113 | 2156 | } |
| ... | ... | @@ -2116,6 +2159,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2116 | 2159 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2117 | 2160 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2118 | 2161 | const operand_ptr = try self.resolveInst(un_op); |
| 2162 | const ptr_ty = self.air.typeOf(un_op); |
| 2119 | 2163 | const operand: MCValue = blk: { |
| 2120 | 2164 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2121 | 2165 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | ... | @@ -2125,7 +2169,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2125 | 2169 | } |
| 2126 | 2170 | }; |
| 2127 | 2171 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); |
| 2128 | | break :result try self.isNonErr(operand); |
| 2172 | break :result try self.isNonErr(ptr_ty.elemType(), operand); |
| 2129 | 2173 | }; |
| 2130 | 2174 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2131 | 2175 | } |
| ... | ... | @@ -2864,14 +2908,23 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 2864 | 2908 | .ErrorUnion => { |
| 2865 | 2909 | const error_type = typed_value.ty.errorUnionSet(); |
| 2866 | 2910 | const payload_type = typed_value.ty.errorUnionPayload(); |
| 2867 | | const sub_val = typed_value.val.castTag(.eu_payload).?.data; |
| 2868 | 2911 | |
| 2869 | | if (!payload_type.hasRuntimeBits()) { |
| 2870 | | // We use the error type directly as the type. |
| 2871 | | return self.genTypedValue(.{ .ty = error_type, .val = sub_val }); |
| 2872 | | } |
| 2912 | if (typed_value.val.castTag(.eu_payload)) |pl| { |
| 2913 | if (!payload_type.hasRuntimeBits()) { |
| 2914 | // We use the error type directly as the type. |
| 2915 | return MCValue{ .immediate = 0 }; |
| 2916 | } |
| 2873 | 2917 | |
| 2874 | | return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty}); |
| 2918 | _ = pl; |
| 2919 | return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty}); |
| 2920 | } else { |
| 2921 | if (!payload_type.hasRuntimeBits()) { |
| 2922 | // We use the error type directly as the type. |
| 2923 | return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); |
| 2924 | } |
| 2925 | |
| 2926 | return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty}); |
| 2927 | } |
| 2875 | 2928 | }, |
| 2876 | 2929 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), |
| 2877 | 2930 | } |