Commit 0728847ce7

Jakub Konka <kubkon@jakubkonka.com>
2022-05-05 19:29:24
x64: handle unsigned mul_with_overflow for non-pow-2 ints
1 parent 0fc1e8b
Changed files (1)
src
arch
src/arch/x86_64/CodeGen.zig
@@ -1487,28 +1487,52 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     break :result result;
                 }
 
-                const lhs = try self.resolveInst(bin_op.lhs);
-                const rhs = try self.resolveInst(bin_op.rhs);
+                const dst_reg: Register = dst_reg: {
+                    switch (int_info.signedness) {
+                        .signed => {
+                            const lhs = try self.resolveInst(bin_op.lhs);
+                            const rhs = try self.resolveInst(bin_op.rhs);
+
+                            rhs.freezeIfRegister(&self.register_manager);
+                            defer rhs.unfreezeIfRegister(&self.register_manager);
+
+                            // TODO check if we could reuse rhs instead, and swap the values out.
+                            const dst_reg: Register = blk: {
+                                if (self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
+                                    if (lhs.isRegister()) break :blk lhs.register;
+                                }
+                                break :blk try self.copyToTmpRegister(ty, lhs);
+                            };
+                            self.register_manager.freezeRegs(&.{dst_reg});
+
+                            const rhs_mcv = blk: {
+                                if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
+                                break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) };
+                            };
+                            rhs_mcv.freezeIfRegister(&self.register_manager);
+                            defer rhs_mcv.unfreezeIfRegister(&self.register_manager);
+
+                            try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv);
+
+                            break :dst_reg dst_reg;
+                        },
+                        .unsigned => {
+                            // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
+                            try self.register_manager.getReg(.rax, null);
+                            try self.register_manager.getReg(.rdx, null);
+                            self.register_manager.freezeRegs(&.{ .rax, .rdx });
+                            defer self.register_manager.unfreezeRegs(&.{.rdx});
 
-                rhs.freezeIfRegister(&self.register_manager);
-                defer rhs.unfreezeIfRegister(&self.register_manager);
+                            const lhs = try self.resolveInst(bin_op.lhs);
+                            const rhs = try self.resolveInst(bin_op.rhs);
 
-                // TODO check if we could reuse rhs instead, and swap the values out.
-                const dst_mcv = blk: {
-                    if (self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
-                        if (lhs.isRegister()) break :blk lhs;
-                    }
-                    break :blk MCValue{ .register = try self.copyToTmpRegister(ty, lhs) };
-                };
-                dst_mcv.freezeIfRegister(&self.register_manager);
-                defer dst_mcv.unfreezeIfRegister(&self.register_manager);
+                            try self.genIntMulDivOpMir(.mul, ty, .unsigned, lhs, rhs);
 
-                const rhs_mcv = blk: {
-                    if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
-                    break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) };
+                            break :dst_reg registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*)));
+                        },
+                    }
                 };
-                rhs_mcv.freezeIfRegister(&self.register_manager);
-                defer rhs_mcv.unfreezeIfRegister(&self.register_manager);
+                defer self.register_manager.unfreezeRegs(&.{dst_reg});
 
                 const tuple_ty = self.air.typeOfIndex(inst);
                 const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));
@@ -1521,8 +1545,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     .unsigned => ty,
                 };
 
-                try self.genIntMulComplexOpMir(extended_ty, dst_mcv, rhs_mcv);
-
                 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null });
                 self.register_manager.freezeRegs(&temp_regs);
                 defer self.register_manager.unfreezeRegs(&temp_regs);
@@ -1542,9 +1564,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 });
 
                 const scratch_reg = temp_regs[1];
-                try self.genSetReg(extended_ty, scratch_reg, dst_mcv);
+                try self.genSetReg(extended_ty, scratch_reg, .{ .register = dst_reg });
                 try self.truncateRegister(ty, scratch_reg);
-                try self.genBinMathOpMir(.cmp, extended_ty, dst_mcv, .{ .register = scratch_reg });
+                try self.genBinMathOpMir(
+                    .cmp,
+                    extended_ty,
+                    .{ .register = dst_reg },
+                    .{ .register = scratch_reg },
+                );
 
                 const eq_reg = temp_regs[2];
                 _ = try self.addInst(.{
@@ -6626,7 +6653,12 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
         .unsigned => {
             const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
             const mask = (~@as(u64, 0)) >> shift;
-            try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask });
+            if (int_info.bits <= 32) {
+                try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask });
+            } else {
+                const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
+                try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg });
+            }
         },
     }
 }