| ... | ... | @@ -1295,38 +1295,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1295 | 1295 | const rhs = try self.resolveInst(op_rhs); |
| 1296 | 1296 | |
| 1297 | 1297 | // Destination must be a register |
| 1298 | | // Source may be register, memory or an immediate |
| 1299 | | // |
| 1300 | | // So there are two options: (lhs is src and rhs is dest) |
| 1301 | | // or (rhs is src and lhs is dest) |
| 1302 | | const lhs_is_dest = blk: { |
| 1303 | | if (self.reuseOperand(inst, 0, lhs)) { |
| 1304 | | break :blk true; |
| 1305 | | } else if (self.reuseOperand(inst, 1, rhs)) { |
| 1306 | | break :blk false; |
| 1307 | | } else { |
| 1308 | | break :blk lhs == .register; |
| 1309 | | } |
| 1310 | | }; |
| 1311 | | |
| 1312 | 1298 | var dst_mcv: MCValue = undefined; |
| 1313 | | var src_mcv: MCValue = undefined; |
| 1314 | | var src_inst: *ir.Inst = undefined; |
| 1315 | | if (lhs_is_dest) { |
| 1299 | var lhs_mcv: MCValue = undefined; |
| 1300 | var rhs_mcv: MCValue = undefined; |
| 1301 | if (self.reuseOperand(inst, 0, lhs)) { |
| 1316 | 1302 | // LHS is the destination |
| 1317 | 1303 | // RHS is the source |
| 1318 | | src_inst = op_rhs; |
| 1319 | | src_mcv = rhs; |
| 1320 | | dst_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs; |
| 1321 | | } else { |
| 1304 | lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs; |
| 1305 | rhs_mcv = rhs; |
| 1306 | dst_mcv = lhs_mcv; |
| 1307 | } else if (self.reuseOperand(inst, 1, rhs)) { |
| 1322 | 1308 | // RHS is the destination |
| 1323 | 1309 | // LHS is the source |
| 1324 | | src_inst = op_lhs; |
| 1325 | | src_mcv = lhs; |
| 1326 | | dst_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs; |
| 1310 | lhs_mcv = lhs; |
| 1311 | rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs; |
| 1312 | dst_mcv = rhs_mcv; |
| 1313 | } else { |
| 1314 | // TODO save 1 copy instruction by directly allocating the destination register |
| 1315 | // LHS is the destination |
| 1316 | // RHS is the source |
| 1317 | lhs_mcv = try self.copyToNewRegister(inst, lhs); |
| 1318 | rhs_mcv = rhs; |
| 1319 | dst_mcv = lhs_mcv; |
| 1327 | 1320 | } |
| 1328 | 1321 | |
| 1329 | | try self.genArmBinOpCode(inst.src, dst_mcv.register, src_mcv, lhs_is_dest, op); |
| 1322 | try self.genArmBinOpCode(inst.src, dst_mcv.register, lhs_mcv, rhs_mcv, op); |
| 1330 | 1323 | return dst_mcv; |
| 1331 | 1324 | } |
| 1332 | 1325 | |
| ... | ... | @@ -1334,11 +1327,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1334 | 1327 | self: *Self, |
| 1335 | 1328 | src: usize, |
| 1336 | 1329 | dst_reg: Register, |
| 1337 | | src_mcv: MCValue, |
| 1338 | | lhs_is_dest: bool, |
| 1330 | lhs_mcv: MCValue, |
| 1331 | rhs_mcv: MCValue, |
| 1339 | 1332 | op: ir.Inst.Tag, |
| 1340 | 1333 | ) !void { |
| 1341 | | const operand = switch (src_mcv) { |
| 1334 | assert(lhs_mcv == .register or lhs_mcv == .register); |
| 1335 | |
| 1336 | const swap_lhs_and_rhs = rhs_mcv == .register and lhs_mcv != .register; |
| 1337 | const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register; |
| 1338 | const op2 = if (swap_lhs_and_rhs) lhs_mcv else rhs_mcv; |
| 1339 | |
| 1340 | const operand = switch (op2) { |
| 1342 | 1341 | .none => unreachable, |
| 1343 | 1342 | .undef => unreachable, |
| 1344 | 1343 | .dead, .unreach => unreachable, |
| ... | ... | @@ -1352,37 +1351,37 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1352 | 1351 | // Load immediate into register if it doesn't fit |
| 1353 | 1352 | // as an operand |
| 1354 | 1353 | break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) orelse |
| 1355 | | Instruction.Operand.reg(try self.copyToTmpRegister(src, src_mcv), Instruction.Operand.Shift.none); |
| 1354 | Instruction.Operand.reg(try self.copyToTmpRegister(src, op2), Instruction.Operand.Shift.none); |
| 1356 | 1355 | }, |
| 1357 | | .register => |src_reg| Instruction.Operand.reg(src_reg, Instruction.Operand.Shift.none), |
| 1356 | .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none), |
| 1358 | 1357 | .stack_offset, |
| 1359 | 1358 | .embedded_in_code, |
| 1360 | 1359 | .memory, |
| 1361 | | => Instruction.Operand.reg(try self.copyToTmpRegister(src, src_mcv), Instruction.Operand.Shift.none), |
| 1360 | => Instruction.Operand.reg(try self.copyToTmpRegister(src, op2), Instruction.Operand.Shift.none), |
| 1362 | 1361 | }; |
| 1363 | 1362 | |
| 1364 | 1363 | switch (op) { |
| 1365 | 1364 | .add => { |
| 1366 | | writeInt(u32, try self.code.addManyAsArray(4), Instruction.add(.al, dst_reg, dst_reg, operand).toU32()); |
| 1365 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.add(.al, dst_reg, op1, operand).toU32()); |
| 1367 | 1366 | }, |
| 1368 | 1367 | .sub => { |
| 1369 | | if (lhs_is_dest) { |
| 1370 | | writeInt(u32, try self.code.addManyAsArray(4), Instruction.sub(.al, dst_reg, dst_reg, operand).toU32()); |
| 1368 | if (swap_lhs_and_rhs) { |
| 1369 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, op1, operand).toU32()); |
| 1371 | 1370 | } else { |
| 1372 | | writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32()); |
| 1371 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.sub(.al, dst_reg, op1, operand).toU32()); |
| 1373 | 1372 | } |
| 1374 | 1373 | }, |
| 1375 | 1374 | .bool_and, .bit_and => { |
| 1376 | | writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32()); |
| 1375 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, op1, operand).toU32()); |
| 1377 | 1376 | }, |
| 1378 | 1377 | .bool_or, .bit_or => { |
| 1379 | | writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32()); |
| 1378 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, op1, operand).toU32()); |
| 1380 | 1379 | }, |
| 1381 | 1380 | .not, .xor => { |
| 1382 | | writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, dst_reg, operand).toU32()); |
| 1381 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, op1, operand).toU32()); |
| 1383 | 1382 | }, |
| 1384 | 1383 | .cmp_eq => { |
| 1385 | | writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, dst_reg, operand).toU32()); |
| 1384 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, op1, operand).toU32()); |
| 1386 | 1385 | }, |
| 1387 | 1386 | else => unreachable, // not a binary instruction |
| 1388 | 1387 | } |
| ... | ... | @@ -2135,7 +2134,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2135 | 2134 | const src_mcv = rhs; |
| 2136 | 2135 | const dst_mcv = if (lhs != .register) try self.copyToNewRegister(&inst.base, lhs) else lhs; |
| 2137 | 2136 | |
| 2138 | | try self.genArmBinOpCode(inst.base.src, dst_mcv.register, src_mcv, true, .cmp_eq); |
| 2137 | try self.genArmBinOpCode(inst.base.src, dst_mcv.register, dst_mcv, src_mcv, .cmp_eq); |
| 2139 | 2138 | const info = inst.lhs.ty.intInfo(self.target.*); |
| 2140 | 2139 | return switch (info.signedness) { |
| 2141 | 2140 | .signed => MCValue{ .compare_flags_signed = op }, |