Commit 65cee0b3fd

joachimschmidt557 <joachim.schmidt557@outlook.com>
2021-05-16 06:54:51
stage2 ARM: correct spilling in genArmMul as well
1 parent b7eab32
Changed files (2)
src
test
stage2
src/codegen.zig
@@ -1563,28 +1563,63 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
             const lhs = try self.resolveInst(op_lhs);
             const rhs = try self.resolveInst(op_rhs);
 
+            const lhs_is_register = lhs == .register;
+            const rhs_is_register = rhs == .register;
+            const reuse_lhs = lhs_is_register and self.reuseOperand(inst, 0, lhs);
+            const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, 1, rhs);
+
             // Destination must be a register
             // LHS must be a register
             // RHS must be a register
             var dst_mcv: MCValue = undefined;
-            var lhs_mcv: MCValue = undefined;
-            var rhs_mcv: MCValue = undefined;
-            if (self.reuseOperand(inst, 0, lhs)) {
-                // LHS is the destination
-                lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs;
-                rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
-                dst_mcv = lhs_mcv;
-            } else if (self.reuseOperand(inst, 1, rhs)) {
-                // RHS is the destination
-                lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs;
-                rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
-                dst_mcv = rhs_mcv;
+            var lhs_mcv: MCValue = lhs;
+            var rhs_mcv: MCValue = rhs;
+
+            // Allocate registers for operands and/or destination
+            const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
+            if (reuse_lhs) {
+                // Allocate 0 or 1 registers
+                if (!rhs_is_register) {
+                    rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(op_rhs, &.{lhs.register}) };
+                    branch.inst_table.putAssumeCapacity(op_rhs, rhs_mcv);
+                }
+                dst_mcv = lhs;
+            } else if (reuse_rhs) {
+                // Allocate 0 or 1 registers
+                if (!lhs_is_register) {
+                    lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(op_lhs, &.{rhs.register}) };
+                    branch.inst_table.putAssumeCapacity(op_lhs, lhs_mcv);
+                }
+                dst_mcv = rhs;
             } else {
-                // TODO save 1 copy instruction by directly allocating the destination register
-                // LHS is the destination
-                lhs_mcv = try self.copyToNewRegister(inst, lhs);
-                rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
-                dst_mcv = lhs_mcv;
+                // Allocate 1 or 2 registers
+                if (lhs_is_register and rhs_is_register) {
+                    dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{ lhs.register, rhs.register }) };
+                } else if (lhs_is_register) {
+                    // Move RHS to register
+                    dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{lhs.register}) };
+                    rhs_mcv = dst_mcv;
+                } else if (rhs_is_register) {
+                    // Move LHS to register
+                    dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) };
+                    lhs_mcv = dst_mcv;
+                } else {
+                    // Move LHS and RHS to register
+                    const regs = try self.register_manager.allocRegs(2, .{ inst, op_rhs }, &.{});
+                    lhs_mcv = MCValue{ .register = regs[0] };
+                    rhs_mcv = MCValue{ .register = regs[1] };
+                    dst_mcv = lhs_mcv;
+
+                    branch.inst_table.putAssumeCapacity(op_rhs, rhs_mcv);
+                }
+            }
+
+            // Move the operands to the newly allocated registers
+            if (!lhs_is_register) {
+                try self.genSetReg(op_lhs.src, op_lhs.ty, lhs_mcv.register, lhs);
+            }
+            if (!rhs_is_register) {
+                try self.genSetReg(op_rhs.src, op_rhs.ty, rhs_mcv.register, rhs);
             }
 
             writeInt(u32, try self.code.addManyAsArray(4), Instruction.mul(.al, dst_mcv.register, lhs_mcv.register, rhs_mcv.register).toU32());
test/stage2/arm.zig
@@ -510,5 +510,54 @@ pub fn addCases(ctx: *TestContext) !void {
         ,
             "",
         );
+
+        case.addCompareOutput(
+            \\export fn _start() noreturn {
+            \\    assert(addMul(3, 4) == 357747496);
+            \\    exit();
+            \\}
+            \\
+            \\fn addMul(a: u32, b: u32) u32 {
+            \\    const x: u32 = blk: {
+            \\        const c = a + b; // 7
+            \\        const d = a + c; // 10
+            \\        const e = d + b; // 14
+            \\        const f = d + e; // 24
+            \\        const g = e + f; // 38
+            \\        const h = f + g; // 62
+            \\        const i = g + h; // 100
+            \\        const j = i + d; // 110
+            \\        const k = i + j; // 210
+            \\        const l = k + c; // 217
+            \\        const m = l * d; // 2170     
+            \\        const n = m + e; // 2184     
+            \\        const o = n * f; // 52416    
+            \\        const p = o + g; // 52454    
+            \\        const q = p * h; // 3252148  
+            \\        const r = q + i; // 3252248  
+            \\        const s = r * j; // 357747280
+            \\        const t = s + k; // 357747490
+            \\        break :blk t;
+            \\    };
+            \\    const y = x + a; // 357747493
+            \\    const z = y + a; // 357747496
+            \\    return z;
+            \\}
+            \\
+            \\fn assert(ok: bool) void {
+            \\    if (!ok) unreachable;
+            \\}
+            \\
+            \\fn exit() noreturn {
+            \\    asm volatile ("svc #0"
+            \\        :
+            \\        : [number] "{r7}" (1),
+            \\          [arg1] "{r0}" (0)
+            \\        : "memory"
+            \\    );
+            \\    unreachable;
+            \\}            
+            ,
+            "",);
     }
 }