aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-03-29 10:11:24 +0200
committerJakub Konka <kubkon@jakubkonka.com>2022-03-30 00:37:42 +0200
commitf9773ab622d84527ddfdb08d07443ec05cf28737 (patch)
tree75747d45594e877f6ab1821ac739e6693bb76e8a /src
parent12e1304805cbe132d17b31bac2e8123869007e4d (diff)
downloadzig-f9773ab622d84527ddfdb08d07443ec05cf28737.tar.gz
zig-f9773ab622d84527ddfdb08d07443ec05cf28737.zip
x64: clean up abstraction for generating integer division
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig54
-rw-r--r--src/arch/x86_64/Emit.zig7
-rw-r--r--src/arch/x86_64/Mir.zig1
3 files changed, 33 insertions, 29 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index bc0171899a..ef4eeba3d8 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1501,11 +1501,12 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
}
-/// Generates signed or unsigned integer division.
+/// Generates signed or unsigned integer multiplication/division.
/// Requires use of .rax and .rdx registers. Spills them if necessary.
/// Quotient is saved in .rax and remainder in .rdx.
-fn genIntDivOpMir(
+fn genIntMulDivOpMir(
self: *Self,
+ tag: Mir.Inst.Tag,
ty: Type,
signedness: std.builtin.Signedness,
lhs: MCValue,
@@ -1513,7 +1514,7 @@ fn genIntDivOpMir(
) !void {
const abi_size = @intCast(u32, ty.abiSize(self.target.*));
if (abi_size > 8) {
- return self.fail("TODO implement genIntDivOpMir for ABI size larger than 8", .{});
+ return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});
}
try self.register_manager.getReg(.rax, null);
@@ -1521,17 +1522,7 @@ fn genIntDivOpMir(
self.register_manager.freezeRegs(&.{ .rax, .rdx });
defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx });
- const dividend = switch (lhs) {
- .register => lhs,
- else => blk: {
- const reg = try self.copyToTmpRegister(ty, lhs);
- break :blk MCValue{ .register = reg };
- },
- };
- try self.genSetReg(ty, .rax, dividend);
-
- self.register_manager.freezeRegs(&.{dividend.register});
- defer self.register_manager.unfreezeRegs(&.{dividend.register});
+ try self.genSetReg(ty, .rax, lhs);
switch (signedness) {
.signed => {
@@ -1555,22 +1546,19 @@ fn genIntDivOpMir(
},
}
- const divisor = switch (rhs) {
+ const factor = switch (rhs) {
.register => rhs,
+ .stack_offset => rhs,
else => blk: {
const reg = try self.copyToTmpRegister(ty, rhs);
break :blk MCValue{ .register = reg };
},
};
- const op_tag: Mir.Inst.Tag = switch (signedness) {
- .signed => .idiv,
- .unsigned => .div,
- };
- switch (divisor) {
+ switch (factor) {
.register => |reg| {
_ = try self.addInst(.{
- .tag = op_tag,
+ .tag = tag,
.ops = (Mir.Ops{
.reg1 = reg,
}).encode(),
@@ -1579,7 +1567,7 @@ fn genIntDivOpMir(
},
.stack_offset => |off| {
_ = try self.addInst(.{
- .tag = op_tag,
+ .tag = tag,
.ops = (Mir.Ops{
.reg2 = .rbp,
.flags = switch (abi_size) {
@@ -1612,7 +1600,10 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
self.register_manager.freezeRegs(&.{divisor});
defer self.register_manager.unfreezeRegs(&.{ dividend, divisor });
- try self.genIntDivOpMir(Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor });
+ try self.genIntMulDivOpMir(switch (signedness) {
+ .signed => .idiv,
+ .unsigned => .div,
+ }, Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor });
_ = try self.addInst(.{
.tag = .xor,
@@ -1673,13 +1664,16 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
const signedness = ty.intInfo(self.target.*).signedness;
if (signedness == .unsigned) {
- try self.genIntDivOpMir(ty, signedness, lhs, rhs);
+ try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs);
break :result MCValue{ .register = .rax };
}
switch (tag) {
.div_exact, .div_trunc => {
- try self.genIntDivOpMir(ty, signedness, lhs, rhs);
+ try self.genIntMulDivOpMir(switch (signedness) {
+ .signed => .idiv,
+ .unsigned => .div,
+ }, ty, signedness, lhs, rhs);
break :result MCValue{ .register = .rax };
},
.div_floor => {
@@ -1704,7 +1698,10 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const signedness = ty.intInfo(self.target.*).signedness;
- try self.genIntDivOpMir(ty, signedness, lhs, rhs);
+ try self.genIntMulDivOpMir(switch (signedness) {
+ .signed => .idiv,
+ .unsigned => .div,
+ }, ty, signedness, lhs, rhs);
break :result MCValue{ .register = .rdx };
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
@@ -1725,7 +1722,10 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
const signedness = ty.intInfo(self.target.*).signedness;
switch (signedness) {
.unsigned => {
- try self.genIntDivOpMir(ty, signedness, lhs, rhs);
+ try self.genIntMulDivOpMir(switch (signedness) {
+ .signed => .idiv,
+ .unsigned => .div,
+ }, ty, signedness, lhs, rhs);
break :result MCValue{ .register = .rdx };
},
.signed => {
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 8d478f0a64..e8ea10bf29 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -145,6 +145,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.sar => try emit.mirShift(.sar, inst),
.imul => try emit.mirMulDiv(.imul, inst),
+ .mul => try emit.mirMulDiv(.mul, inst),
.idiv => try emit.mirMulDiv(.idiv, inst),
.div => try emit.mirMulDiv(.div, inst),
.imul_complex => try emit.mirIMulComplex(inst),
@@ -1164,6 +1165,7 @@ const Tag = enum {
brk,
nop,
imul,
+ mul,
idiv,
div,
syscall,
@@ -1411,7 +1413,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
.setnl, .setge => OpCode.twoByte(0x0f, 0x9d),
.setle, .setng => OpCode.twoByte(0x0f, 0x9e),
.setnle, .setg => OpCode.twoByte(0x0f, 0x9f),
- .idiv, .div, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
+ .idiv, .div, .imul, .mul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
.fisttp16 => OpCode.oneByte(0xdf),
.fisttp32 => OpCode.oneByte(0xdb),
.fisttp64 => OpCode.oneByte(0xdd),
@@ -1554,9 +1556,10 @@ inline fn getModRmExt(tag: Tag) ?u3 {
=> 0x4,
.shr => 0x5,
.sar => 0x7,
+ .mul => 0x4,
.imul => 0x5,
- .idiv => 0x7,
.div => 0x6,
+ .idiv => 0x7,
.fisttp16 => 0x1,
.fisttp32 => 0x1,
.fisttp64 => 0x1,
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 96a8eec93d..183a76e4b7 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -227,6 +227,7 @@ pub const Inst = struct {
/// 0b11 qword ptr [reg2 + imm32]
imul,
idiv,
+ mul,
div,
/// ops flags: form: