authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-02-07 20:01:11+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-02-09 23:58:41+01:00
log6a5a6386c60143258fc9970f52e26e3a974b52b5
tree6419bf13417fc9394f13df4031f7c55aefddc460
parentc2beaba85a87b5985fe9f1676ad2bc4888dd6c1a

stage2 ARM: fix register allocation in genArmBinOp

Previously, this would reuse an operand even if reuseOperand returned false for both operands. genArmBinOpCode was also changed to be more Three-address code oriented in the process.

1 files changed, 39 insertions(+), 40 deletions(-)

src/codegen.zig+39-40
......@@ -1295,38 +1295,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12951295 const rhs = try self.resolveInst(op_rhs);
12961296
12971297 // 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
13121298 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)) {
13161302 // LHS is the destination
13171303 // 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)) {
13221308 // RHS is the destination
13231309 // 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;
13271320 }
13281321
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);
13301323 return dst_mcv;
13311324 }
13321325
......@@ -1334,11 +1327,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13341327 self: *Self,
13351328 src: usize,
13361329 dst_reg: Register,
1337 src_mcv: MCValue,
1338 lhs_is_dest: bool,
1330 lhs_mcv: MCValue,
1331 rhs_mcv: MCValue,
13391332 op: ir.Inst.Tag,
13401333 ) !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) {
13421341 .none => unreachable,
13431342 .undef => unreachable,
13441343 .dead, .unreach => unreachable,
......@@ -1352,37 +1351,37 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13521351 // Load immediate into register if it doesn't fit
13531352 // as an operand
13541353 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);
13561355 },
1357 .register => |src_reg| Instruction.Operand.reg(src_reg, Instruction.Operand.Shift.none),
1356 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),
13581357 .stack_offset,
13591358 .embedded_in_code,
13601359 .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),
13621361 };
13631362
13641363 switch (op) {
13651364 .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());
13671366 },
13681367 .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());
13711370 } 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());
13731372 }
13741373 },
13751374 .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());
13771376 },
13781377 .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());
13801379 },
13811380 .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());
13831382 },
13841383 .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());
13861385 },
13871386 else => unreachable, // not a binary instruction
13881387 }
......@@ -2135,7 +2134,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21352134 const src_mcv = rhs;
21362135 const dst_mcv = if (lhs != .register) try self.copyToNewRegister(&inst.base, lhs) else lhs;
21372136
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);
21392138 const info = inst.lhs.ty.intInfo(self.target.*);
21402139 return switch (info.signedness) {
21412140 .signed => MCValue{ .compare_flags_signed = op },