| ... | @@ -513,7 +513,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -513,7 +513,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 513 | .mul_sat => try self.airMulSat(inst), | 513 | .mul_sat => try self.airMulSat(inst), |
| 514 | .rem => try self.airRem(inst), | 514 | .rem => try self.airRem(inst), |
| 515 | .mod => try self.airMod(inst), | 515 | .mod => try self.airMod(inst), |
| 516 | .shl, .shl_exact => try self.airShl(inst), | 516 | .shl, .shl_exact => try self.airBinOp(inst), |
| 517 | .shl_sat => try self.airShlSat(inst), | 517 | .shl_sat => try self.airShlSat(inst), |
| 518 | .min => try self.airMin(inst), | 518 | .min => try self.airMin(inst), |
| 519 | .max => try self.airMax(inst), | 519 | .max => try self.airMax(inst), |
| ... | @@ -553,7 +553,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -553,7 +553,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 553 | .bit_and => try self.airBinOp(inst), | 553 | .bit_and => try self.airBinOp(inst), |
| 554 | .bit_or => try self.airBinOp(inst), | 554 | .bit_or => try self.airBinOp(inst), |
| 555 | .xor => try self.airBinOp(inst), | 555 | .xor => try self.airBinOp(inst), |
| 556 | .shr, .shr_exact => try self.airShr(inst), | 556 | .shr, .shr_exact => try self.airBinOp(inst), |
| 557 | | 557 | |
| 558 | .alloc => try self.airAlloc(inst), | 558 | .alloc => try self.airAlloc(inst), |
| 559 | .ret_ptr => try self.airRetPtr(inst), | 559 | .ret_ptr => try self.airRetPtr(inst), |
| ... | @@ -1091,24 +1091,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1091,24 +1091,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1091 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1091 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1092 | } | 1092 | } |
| 1093 | | 1093 | |
| 1094 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1095 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1096 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, .shl); | | |
| 1097 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1098 | } | | |
| 1099 | | | |
| 1100 | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { | 1094 | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1101 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1095 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1102 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); | 1096 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); |
| 1103 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1097 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1104 | } | 1098 | } |
| 1105 | | 1099 | |
| 1106 | fn airShr(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1107 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1108 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, .shr); | | |
| 1109 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1110 | } | | |
| 1111 | | | |
| 1112 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | 1100 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1113 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1101 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1114 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}); | 1102 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}); |
| ... | @@ -1820,6 +1808,15 @@ fn binOpRegister( | ... | @@ -1820,6 +1808,15 @@ fn binOpRegister( |
| 1820 | .bit_or, | 1808 | .bit_or, |
| 1821 | .bool_or, | 1809 | .bool_or, |
| 1822 | => .orr, | 1810 | => .orr, |
| | 1811 | .shl, |
| | 1812 | .shl_exact, |
| | 1813 | => .lsl, |
| | 1814 | .shr, |
| | 1815 | .shr_exact, |
| | 1816 | => switch (lhs_ty.intInfo(self.target.*).signedness) { |
| | 1817 | .signed => Mir.Inst.Tag.asr, |
| | 1818 | .unsigned => Mir.Inst.Tag.lsr, |
| | 1819 | }, |
| 1823 | .xor => .eor, | 1820 | .xor => .eor, |
| 1824 | else => unreachable, | 1821 | else => unreachable, |
| 1825 | }; | 1822 | }; |
| ... | @@ -1838,6 +1835,15 @@ fn binOpRegister( | ... | @@ -1838,6 +1835,15 @@ fn binOpRegister( |
| 1838 | .rn = lhs_reg, | 1835 | .rn = lhs_reg, |
| 1839 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), | 1836 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), |
| 1840 | } }, | 1837 | } }, |
| | 1838 | .shl, |
| | 1839 | .shl_exact, |
| | 1840 | .shr, |
| | 1841 | .shr_exact, |
| | 1842 | => .{ .rr_shift = .{ |
| | 1843 | .rd = dest_reg, |
| | 1844 | .rm = lhs_reg, |
| | 1845 | .shift_amount = Instruction.ShiftAmount.reg(rhs_reg), |
| | 1846 | } }, |
| 1841 | .mul => .{ .rrr = .{ | 1847 | .mul => .{ .rrr = .{ |
| 1842 | .rd = dest_reg, | 1848 | .rd = dest_reg, |
| 1843 | .rn = lhs_reg, | 1849 | .rn = lhs_reg, |
| ... | @@ -1924,6 +1930,15 @@ fn binOpImmediate( | ... | @@ -1924,6 +1930,15 @@ fn binOpImmediate( |
| 1924 | .bit_or, | 1930 | .bit_or, |
| 1925 | .bool_or, | 1931 | .bool_or, |
| 1926 | => .orr, | 1932 | => .orr, |
| | 1933 | .shl, |
| | 1934 | .shl_exact, |
| | 1935 | => .lsl, |
| | 1936 | .shr, |
| | 1937 | .shr_exact, |
| | 1938 | => switch (lhs_ty.intInfo(self.target.*).signedness) { |
| | 1939 | .signed => Mir.Inst.Tag.asr, |
| | 1940 | .unsigned => Mir.Inst.Tag.lsr, |
| | 1941 | }, |
| 1927 | .xor => .eor, | 1942 | .xor => .eor, |
| 1928 | else => unreachable, | 1943 | else => unreachable, |
| 1929 | }; | 1944 | }; |
| ... | @@ -1940,6 +1955,15 @@ fn binOpImmediate( | ... | @@ -1940,6 +1955,15 @@ fn binOpImmediate( |
| 1940 | .rn = lhs_reg, | 1955 | .rn = lhs_reg, |
| 1941 | .op = Instruction.Operand.fromU32(rhs.immediate).?, | 1956 | .op = Instruction.Operand.fromU32(rhs.immediate).?, |
| 1942 | } }, | 1957 | } }, |
| | 1958 | .shl, |
| | 1959 | .shl_exact, |
| | 1960 | .shr, |
| | 1961 | .shr_exact, |
| | 1962 | => .{ .rr_shift = .{ |
| | 1963 | .rd = dest_reg, |
| | 1964 | .rm = lhs_reg, |
| | 1965 | .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs.immediate)), |
| | 1966 | } }, |
| 1943 | else => unreachable, | 1967 | else => unreachable, |
| 1944 | }; | 1968 | }; |
| 1945 | | 1969 | |
| ... | @@ -2060,6 +2084,28 @@ fn binOp( | ... | @@ -2060,6 +2084,28 @@ fn binOp( |
| 2060 | else => unreachable, | 2084 | else => unreachable, |
| 2061 | } | 2085 | } |
| 2062 | }, | 2086 | }, |
| | 2087 | .shl, |
| | 2088 | .shr, |
| | 2089 | => { |
| | 2090 | switch (lhs_ty.zigTypeTag()) { |
| | 2091 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| | 2092 | .Int => { |
| | 2093 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 2094 | if (int_info.bits <= 32) { |
| | 2095 | const rhs_immediate_ok = rhs == .immediate; |
| | 2096 | |
| | 2097 | if (rhs_immediate_ok) { |
| | 2098 | return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false); |
| | 2099 | } else { |
| | 2100 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 2101 | } |
| | 2102 | } else { |
| | 2103 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| | 2104 | } |
| | 2105 | }, |
| | 2106 | else => unreachable, |
| | 2107 | } |
| | 2108 | }, |
| 2063 | .bool_and, | 2109 | .bool_and, |
| 2064 | .bool_or, | 2110 | .bool_or, |
| 2065 | => { | 2111 | => { |
| ... | @@ -2129,212 +2175,6 @@ fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool { | ... | @@ -2129,212 +2175,6 @@ fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool { |
| 2129 | }; | 2175 | }; |
| 2130 | } | 2176 | } |
| 2131 | | 2177 | |
| 2132 | fn genBinOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref, op: Air.Inst.Tag) !MCValue { | | |
| 2133 | // In the case of bitshifts, the type of rhs is different | | |
| 2134 | // from the resulting type | | |
| 2135 | const ty = self.air.typeOf(op_lhs); | | |
| 2136 | | | |
| 2137 | switch (ty.zigTypeTag()) { | | |
| 2138 | .Int => { | | |
| 2139 | const int_info = ty.intInfo(self.target.*); | | |
| 2140 | return self.genBinIntOp(inst, op_lhs, op_rhs, op, int_info.bits, int_info.signedness); | | |
| 2141 | }, | | |
| 2142 | else => unreachable, | | |
| 2143 | } | | |
| 2144 | } | | |
| 2145 | | | |
| 2146 | fn genBinIntOp( | | |
| 2147 | self: *Self, | | |
| 2148 | inst: Air.Inst.Index, | | |
| 2149 | op_lhs: Air.Inst.Ref, | | |
| 2150 | op_rhs: Air.Inst.Ref, | | |
| 2151 | op: Air.Inst.Tag, | | |
| 2152 | bits: u16, | | |
| 2153 | signedness: std.builtin.Signedness, | | |
| 2154 | ) !MCValue { | | |
| 2155 | if (bits > 32) { | | |
| 2156 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); | | |
| 2157 | } | | |
| 2158 | | | |
| 2159 | const lhs = try self.resolveInst(op_lhs); | | |
| 2160 | const rhs = try self.resolveInst(op_rhs); | | |
| 2161 | | | |
| 2162 | const lhs_is_register = lhs == .register; | | |
| 2163 | const rhs_is_register = rhs == .register; | | |
| 2164 | const lhs_should_be_register = switch (op) { | | |
| 2165 | .shr, .shl => true, | | |
| 2166 | else => try self.armOperandShouldBeRegister(lhs), | | |
| 2167 | }; | | |
| 2168 | const rhs_should_be_register = try self.armOperandShouldBeRegister(rhs); | | |
| 2169 | const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op_lhs, 0, lhs); | | |
| 2170 | const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, op_rhs, 1, rhs); | | |
| 2171 | const can_swap_lhs_and_rhs = switch (op) { | | |
| 2172 | .shr, .shl => false, | | |
| 2173 | else => true, | | |
| 2174 | }; | | |
| 2175 | | | |
| 2176 | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); | | |
| 2177 | defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register}); | | |
| 2178 | if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register}); | | |
| 2179 | defer if (rhs_is_register) self.register_manager.unfreezeRegs(&.{rhs.register}); | | |
| 2180 | | | |
| 2181 | // Destination must be a register | | |
| 2182 | var dst_mcv: MCValue = undefined; | | |
| 2183 | var lhs_mcv = lhs; | | |
| 2184 | var rhs_mcv = rhs; | | |
| 2185 | var swap_lhs_and_rhs = false; | | |
| 2186 | | | |
| 2187 | // Allocate registers for operands and/or destination | | |
| 2188 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | | |
| 2189 | if (reuse_lhs) { | | |
| 2190 | // Allocate 0 or 1 registers | | |
| 2191 | if (!rhs_is_register and rhs_should_be_register) { | | |
| 2192 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) }; | | |
| 2193 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); | | |
| 2194 | } | | |
| 2195 | dst_mcv = lhs; | | |
| 2196 | } else if (reuse_rhs and can_swap_lhs_and_rhs) { | | |
| 2197 | // Allocate 0 or 1 registers | | |
| 2198 | if (!lhs_is_register and lhs_should_be_register) { | | |
| 2199 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) }; | | |
| 2200 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv); | | |
| 2201 | } | | |
| 2202 | dst_mcv = rhs; | | |
| 2203 | | | |
| 2204 | swap_lhs_and_rhs = true; | | |
| 2205 | } else { | | |
| 2206 | // Allocate 1 or 2 registers | | |
| 2207 | if (lhs_should_be_register and rhs_should_be_register) { | | |
| 2208 | if (lhs_is_register and rhs_is_register) { | | |
| 2209 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; | | |
| 2210 | } else if (lhs_is_register) { | | |
| 2211 | // Move RHS to register | | |
| 2212 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; | | |
| 2213 | rhs_mcv = dst_mcv; | | |
| 2214 | } else if (rhs_is_register) { | | |
| 2215 | // Move LHS to register | | |
| 2216 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; | | |
| 2217 | lhs_mcv = dst_mcv; | | |
| 2218 | } else { | | |
| 2219 | // Move LHS and RHS to register | | |
| 2220 | const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }); | | |
| 2221 | lhs_mcv = MCValue{ .register = regs[0] }; | | |
| 2222 | rhs_mcv = MCValue{ .register = regs[1] }; | | |
| 2223 | dst_mcv = lhs_mcv; | | |
| 2224 | | | |
| 2225 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); | | |
| 2226 | } | | |
| 2227 | } else if (lhs_should_be_register) { | | |
| 2228 | // RHS is immediate | | |
| 2229 | if (lhs_is_register) { | | |
| 2230 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; | | |
| 2231 | } else { | | |
| 2232 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; | | |
| 2233 | lhs_mcv = dst_mcv; | | |
| 2234 | } | | |
| 2235 | } else if (rhs_should_be_register and can_swap_lhs_and_rhs) { | | |
| 2236 | // LHS is immediate | | |
| 2237 | if (rhs_is_register) { | | |
| 2238 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; | | |
| 2239 | } else { | | |
| 2240 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; | | |
| 2241 | rhs_mcv = dst_mcv; | | |
| 2242 | } | | |
| 2243 | | | |
| 2244 | swap_lhs_and_rhs = true; | | |
| 2245 | } else unreachable; // binary operation on two immediates | | |
| 2246 | } | | |
| 2247 | | | |
| 2248 | // Move the operands to the newly allocated registers | | |
| 2249 | if (lhs_mcv == .register and !lhs_is_register) { | | |
| 2250 | try self.genSetReg(self.air.typeOf(op_lhs), lhs_mcv.register, lhs); | | |
| 2251 | } | | |
| 2252 | if (rhs_mcv == .register and !rhs_is_register) { | | |
| 2253 | try self.genSetReg(self.air.typeOf(op_rhs), rhs_mcv.register, rhs); | | |
| 2254 | } | | |
| 2255 | | | |
| 2256 | try self.genBinOpCode( | | |
| 2257 | dst_mcv.register, | | |
| 2258 | lhs_mcv, | | |
| 2259 | rhs_mcv, | | |
| 2260 | swap_lhs_and_rhs, | | |
| 2261 | op, | | |
| 2262 | signedness, | | |
| 2263 | ); | | |
| 2264 | return dst_mcv; | | |
| 2265 | } | | |
| 2266 | | | |
| 2267 | fn genBinOpCode( | | |
| 2268 | self: *Self, | | |
| 2269 | dst_reg: Register, | | |
| 2270 | lhs_mcv: MCValue, | | |
| 2271 | rhs_mcv: MCValue, | | |
| 2272 | swap_lhs_and_rhs: bool, | | |
| 2273 | op: Air.Inst.Tag, | | |
| 2274 | signedness: std.builtin.Signedness, | | |
| 2275 | ) !void { | | |
| 2276 | assert(lhs_mcv == .register or rhs_mcv == .register); | | |
| 2277 | | | |
| 2278 | const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register; | | |
| 2279 | const op2 = if (swap_lhs_and_rhs) lhs_mcv else rhs_mcv; | | |
| 2280 | | | |
| 2281 | const operand = switch (op2) { | | |
| 2282 | .none => unreachable, | | |
| 2283 | .undef => unreachable, | | |
| 2284 | .dead, .unreach => unreachable, | | |
| 2285 | .compare_flags_unsigned => unreachable, | | |
| 2286 | .compare_flags_signed => unreachable, | | |
| 2287 | .ptr_stack_offset => unreachable, | | |
| 2288 | .ptr_embedded_in_code => unreachable, | | |
| 2289 | .immediate => |imm| Instruction.Operand.fromU32(@intCast(u32, imm)).?, | | |
| 2290 | .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none), | | |
| 2291 | .stack_offset, | | |
| 2292 | .stack_argument_offset, | | |
| 2293 | .embedded_in_code, | | |
| 2294 | .memory, | | |
| 2295 | => unreachable, | | |
| 2296 | }; | | |
| 2297 | | | |
| 2298 | switch (op) { | | |
| 2299 | .cmp_eq => { | | |
| 2300 | _ = try self.addInst(.{ | | |
| 2301 | .tag = .cmp, | | |
| 2302 | .data = .{ .rr_op = .{ | | |
| 2303 | .rd = .r0, | | |
| 2304 | .rn = op1, | | |
| 2305 | .op = operand, | | |
| 2306 | } }, | | |
| 2307 | }); | | |
| 2308 | }, | | |
| 2309 | .shl, .shr => { | | |
| 2310 | assert(!swap_lhs_and_rhs); | | |
| 2311 | const shift_amount = switch (operand) { | | |
| 2312 | .register => |reg_op| Instruction.ShiftAmount.reg(@intToEnum(Register, reg_op.rm)), | | |
| 2313 | .immediate => |imm_op| Instruction.ShiftAmount.imm(@intCast(u5, imm_op.imm)), | | |
| 2314 | }; | | |
| 2315 | | | |
| 2316 | const tag: Mir.Inst.Tag = switch (op) { | | |
| 2317 | .shl => .lsl, | | |
| 2318 | .shr => switch (signedness) { | | |
| 2319 | .signed => Mir.Inst.Tag.asr, | | |
| 2320 | .unsigned => Mir.Inst.Tag.lsr, | | |
| 2321 | }, | | |
| 2322 | else => unreachable, | | |
| 2323 | }; | | |
| 2324 | | | |
| 2325 | _ = try self.addInst(.{ | | |
| 2326 | .tag = tag, | | |
| 2327 | .data = .{ .rr_shift = .{ | | |
| 2328 | .rd = dst_reg, | | |
| 2329 | .rm = op1, | | |
| 2330 | .shift_amount = shift_amount, | | |
| 2331 | } }, | | |
| 2332 | }); | | |
| 2333 | }, | | |
| 2334 | else => unreachable, // not a binary instruction | | |
| 2335 | } | | |
| 2336 | } | | |
| 2337 | | | |
| 2338 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void { | 2178 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void { |
| 2339 | switch (abi_size) { | 2179 | switch (abi_size) { |
| 2340 | 1, 3, 4 => { | 2180 | 1, 3, 4 => { |
| ... | @@ -2769,9 +2609,18 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -2769,9 +2609,18 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2769 | branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs); | 2609 | branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs); |
| 2770 | } | 2610 | } |
| 2771 | | 2611 | |
| 2772 | // The destination register is not present in the cmp instruction | 2612 | _ = try self.addInst(.{ |
| 2773 | // The signedness of the integer does not matter for the cmp instruction | 2613 | .tag = .cmp, |
| 2774 | try self.genBinOpCode(undefined, lhs_mcv, rhs_mcv, false, .cmp_eq, undefined); | 2614 | .data = .{ .rr_op = .{ |
| | 2615 | .rd = undefined, |
| | 2616 | .rn = lhs_mcv.register, |
| | 2617 | .op = switch (rhs_mcv) { |
| | 2618 | .immediate => |imm| Instruction.Operand.fromU32(@intCast(u32, imm)).?, |
| | 2619 | .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none), |
| | 2620 | else => unreachable, |
| | 2621 | }, |
| | 2622 | } }, |
| | 2623 | }); |
| 2775 | | 2624 | |
| 2776 | break :result switch (signedness) { | 2625 | break :result switch (signedness) { |
| 2777 | .signed => MCValue{ .compare_flags_signed = op }, | 2626 | .signed => MCValue{ .compare_flags_signed = op }, |
| ... | @@ -3003,7 +2852,14 @@ fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -3003,7 +2852,14 @@ fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3003 | else => .{ .register = try self.copyToTmpRegister(ty, operand) }, | 2852 | else => .{ .register = try self.copyToTmpRegister(ty, operand) }, |
| 3004 | }; | 2853 | }; |
| 3005 | | 2854 | |
| 3006 | try self.genBinOpCode(undefined, reg_mcv, .{ .immediate = 0 }, false, .cmp_eq, undefined); | 2855 | _ = try self.addInst(.{ |
| | 2856 | .tag = .cmp, |
| | 2857 | .data = .{ .rr_op = .{ |
| | 2858 | .rd = undefined, |
| | 2859 | .rn = reg_mcv.register, |
| | 2860 | .op = Instruction.Operand.fromU32(0).?, |
| | 2861 | } }, |
| | 2862 | }); |
| 3007 | | 2863 | |
| 3008 | return MCValue{ .compare_flags_unsigned = .eq }; | 2864 | return MCValue{ .compare_flags_unsigned = .eq }; |
| 3009 | } else { | 2865 | } else { |
| ... | @@ -3033,7 +2889,14 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -3033,7 +2889,14 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3033 | else => .{ .register = try self.copyToTmpRegister(error_type, operand) }, | 2889 | else => .{ .register = try self.copyToTmpRegister(error_type, operand) }, |
| 3034 | }; | 2890 | }; |
| 3035 | | 2891 | |
| 3036 | try self.genBinOpCode(undefined, reg_mcv, .{ .immediate = 0 }, false, .cmp_eq, undefined); | 2892 | _ = try self.addInst(.{ |
| | 2893 | .tag = .cmp, |
| | 2894 | .data = .{ .rr_op = .{ |
| | 2895 | .rd = undefined, |
| | 2896 | .rn = reg_mcv.register, |
| | 2897 | .op = Instruction.Operand.fromU32(0).?, |
| | 2898 | } }, |
| | 2899 | }); |
| 3037 | | 2900 | |
| 3038 | return MCValue{ .compare_flags_unsigned = .gt }; | 2901 | return MCValue{ .compare_flags_unsigned = .gt }; |
| 3039 | } else { | 2902 | } else { |