authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-29 10:11:24+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-30 00:37:42+02:00
logf9773ab622d84527ddfdb08d07443ec05cf28737
tree75747d45594e877f6ab1821ac739e6693bb76e8a
parent12e1304805cbe132d17b31bac2e8123869007e4d

x64: clean up abstraction for generating integer division


3 files changed, 33 insertions(+), 29 deletions(-)

src/arch/x86_64/CodeGen.zig+27-27
...@@ -1501,11 +1501,12 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1501,11 +1501,12 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1501 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});1501 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
1502}1502}
15031503
1504/// Generates signed or unsigned integer division.1504/// Generates signed or unsigned integer multiplication/division.
1505/// Requires use of .rax and .rdx registers. Spills them if necessary.1505/// Requires use of .rax and .rdx registers. Spills them if necessary.
1506/// Quotient is saved in .rax and remainder in .rdx.1506/// Quotient is saved in .rax and remainder in .rdx.
1507fn genIntDivOpMir(1507fn genIntMulDivOpMir(
1508 self: *Self,1508 self: *Self,
1509 tag: Mir.Inst.Tag,
1509 ty: Type,1510 ty: Type,
1510 signedness: std.builtin.Signedness,1511 signedness: std.builtin.Signedness,
1511 lhs: MCValue,1512 lhs: MCValue,
...@@ -1513,7 +1514,7 @@ fn genIntDivOpMir(...@@ -1513,7 +1514,7 @@ fn genIntDivOpMir(
1513) !void {1514) !void {
1514 const abi_size = @intCast(u32, ty.abiSize(self.target.*));1515 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
1515 if (abi_size > 8) {1516 if (abi_size > 8) {
1516 return self.fail("TODO implement genIntDivOpMir for ABI size larger than 8", .{});1517 return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});
1517 }1518 }
15181519
1519 try self.register_manager.getReg(.rax, null);1520 try self.register_manager.getReg(.rax, null);
...@@ -1521,17 +1522,7 @@ fn genIntDivOpMir(...@@ -1521,17 +1522,7 @@ fn genIntDivOpMir(
1521 self.register_manager.freezeRegs(&.{ .rax, .rdx });1522 self.register_manager.freezeRegs(&.{ .rax, .rdx });
1522 defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx });1523 defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx });
15231524
1524 const dividend = switch (lhs) {1525 try self.genSetReg(ty, .rax, lhs);
1525 .register => lhs,
1526 else => blk: {
1527 const reg = try self.copyToTmpRegister(ty, lhs);
1528 break :blk MCValue{ .register = reg };
1529 },
1530 };
1531 try self.genSetReg(ty, .rax, dividend);
1532
1533 self.register_manager.freezeRegs(&.{dividend.register});
1534 defer self.register_manager.unfreezeRegs(&.{dividend.register});
15351526
1536 switch (signedness) {1527 switch (signedness) {
1537 .signed => {1528 .signed => {
...@@ -1555,22 +1546,19 @@ fn genIntDivOpMir(...@@ -1555,22 +1546,19 @@ fn genIntDivOpMir(
1555 },1546 },
1556 }1547 }
15571548
1558 const divisor = switch (rhs) {1549 const factor = switch (rhs) {
1559 .register => rhs,1550 .register => rhs,
1551 .stack_offset => rhs,
1560 else => blk: {1552 else => blk: {
1561 const reg = try self.copyToTmpRegister(ty, rhs);1553 const reg = try self.copyToTmpRegister(ty, rhs);
1562 break :blk MCValue{ .register = reg };1554 break :blk MCValue{ .register = reg };
1563 },1555 },
1564 };1556 };
1565 const op_tag: Mir.Inst.Tag = switch (signedness) {
1566 .signed => .idiv,
1567 .unsigned => .div,
1568 };
15691557
1570 switch (divisor) {1558 switch (factor) {
1571 .register => |reg| {1559 .register => |reg| {
1572 _ = try self.addInst(.{1560 _ = try self.addInst(.{
1573 .tag = op_tag,1561 .tag = tag,
1574 .ops = (Mir.Ops{1562 .ops = (Mir.Ops{
1575 .reg1 = reg,1563 .reg1 = reg,
1576 }).encode(),1564 }).encode(),
...@@ -1579,7 +1567,7 @@ fn genIntDivOpMir(...@@ -1579,7 +1567,7 @@ fn genIntDivOpMir(
1579 },1567 },
1580 .stack_offset => |off| {1568 .stack_offset => |off| {
1581 _ = try self.addInst(.{1569 _ = try self.addInst(.{
1582 .tag = op_tag,1570 .tag = tag,
1583 .ops = (Mir.Ops{1571 .ops = (Mir.Ops{
1584 .reg2 = .rbp,1572 .reg2 = .rbp,
1585 .flags = switch (abi_size) {1573 .flags = switch (abi_size) {
...@@ -1612,7 +1600,10 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa...@@ -1612,7 +1600,10 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
1612 self.register_manager.freezeRegs(&.{divisor});1600 self.register_manager.freezeRegs(&.{divisor});
1613 defer self.register_manager.unfreezeRegs(&.{ dividend, divisor });1601 defer self.register_manager.unfreezeRegs(&.{ dividend, divisor });
16141602
1615 try self.genIntDivOpMir(Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor });1603 try self.genIntMulDivOpMir(switch (signedness) {
1604 .signed => .idiv,
1605 .unsigned => .div,
1606 }, Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor });
16161607
1617 _ = try self.addInst(.{1608 _ = try self.addInst(.{
1618 .tag = .xor,1609 .tag = .xor,
...@@ -1673,13 +1664,16 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void {...@@ -1673,13 +1664,16 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
16731664
1674 const signedness = ty.intInfo(self.target.*).signedness;1665 const signedness = ty.intInfo(self.target.*).signedness;
1675 if (signedness == .unsigned) {1666 if (signedness == .unsigned) {
1676 try self.genIntDivOpMir(ty, signedness, lhs, rhs);1667 try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs);
1677 break :result MCValue{ .register = .rax };1668 break :result MCValue{ .register = .rax };
1678 }1669 }
16791670
1680 switch (tag) {1671 switch (tag) {
1681 .div_exact, .div_trunc => {1672 .div_exact, .div_trunc => {
1682 try self.genIntDivOpMir(ty, signedness, lhs, rhs);1673 try self.genIntMulDivOpMir(switch (signedness) {
1674 .signed => .idiv,
1675 .unsigned => .div,
1676 }, ty, signedness, lhs, rhs);
1683 break :result MCValue{ .register = .rax };1677 break :result MCValue{ .register = .rax };
1684 },1678 },
1685 .div_floor => {1679 .div_floor => {
...@@ -1704,7 +1698,10 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void {...@@ -1704,7 +1698,10 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void {
1704 const lhs = try self.resolveInst(bin_op.lhs);1698 const lhs = try self.resolveInst(bin_op.lhs);
1705 const rhs = try self.resolveInst(bin_op.rhs);1699 const rhs = try self.resolveInst(bin_op.rhs);
1706 const signedness = ty.intInfo(self.target.*).signedness;1700 const signedness = ty.intInfo(self.target.*).signedness;
1707 try self.genIntDivOpMir(ty, signedness, lhs, rhs);1701 try self.genIntMulDivOpMir(switch (signedness) {
1702 .signed => .idiv,
1703 .unsigned => .div,
1704 }, ty, signedness, lhs, rhs);
1708 break :result MCValue{ .register = .rdx };1705 break :result MCValue{ .register = .rdx };
1709 };1706 };
1710 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1707 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 {...@@ -1725,7 +1722,10 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
1725 const signedness = ty.intInfo(self.target.*).signedness;1722 const signedness = ty.intInfo(self.target.*).signedness;
1726 switch (signedness) {1723 switch (signedness) {
1727 .unsigned => {1724 .unsigned => {
1728 try self.genIntDivOpMir(ty, signedness, lhs, rhs);1725 try self.genIntMulDivOpMir(switch (signedness) {
1726 .signed => .idiv,
1727 .unsigned => .div,
1728 }, ty, signedness, lhs, rhs);
1729 break :result MCValue{ .register = .rdx };1729 break :result MCValue{ .register = .rdx };
1730 },1730 },
1731 .signed => {1731 .signed => {
src/arch/x86_64/Emit.zig+5-2
...@@ -145,6 +145,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -145,6 +145,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
145 .sar => try emit.mirShift(.sar, inst),145 .sar => try emit.mirShift(.sar, inst),
146146
147 .imul => try emit.mirMulDiv(.imul, inst),147 .imul => try emit.mirMulDiv(.imul, inst),
148 .mul => try emit.mirMulDiv(.mul, inst),
148 .idiv => try emit.mirMulDiv(.idiv, inst),149 .idiv => try emit.mirMulDiv(.idiv, inst),
149 .div => try emit.mirMulDiv(.div, inst),150 .div => try emit.mirMulDiv(.div, inst),
150 .imul_complex => try emit.mirIMulComplex(inst),151 .imul_complex => try emit.mirIMulComplex(inst),
...@@ -1164,6 +1165,7 @@ const Tag = enum {...@@ -1164,6 +1165,7 @@ const Tag = enum {
1164 brk,1165 brk,
1165 nop,1166 nop,
1166 imul,1167 imul,
1168 mul,
1167 idiv,1169 idiv,
1168 div,1170 div,
1169 syscall,1171 syscall,
...@@ -1411,7 +1413,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1411,7 +1413,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1411 .setnl, .setge => OpCode.twoByte(0x0f, 0x9d),1413 .setnl, .setge => OpCode.twoByte(0x0f, 0x9d),
1412 .setle, .setng => OpCode.twoByte(0x0f, 0x9e),1414 .setle, .setng => OpCode.twoByte(0x0f, 0x9e),
1413 .setnle, .setg => OpCode.twoByte(0x0f, 0x9f),1415 .setnle, .setg => OpCode.twoByte(0x0f, 0x9f),
1414 .idiv, .div, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),1416 .idiv, .div, .imul, .mul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
1415 .fisttp16 => OpCode.oneByte(0xdf),1417 .fisttp16 => OpCode.oneByte(0xdf),
1416 .fisttp32 => OpCode.oneByte(0xdb),1418 .fisttp32 => OpCode.oneByte(0xdb),
1417 .fisttp64 => OpCode.oneByte(0xdd),1419 .fisttp64 => OpCode.oneByte(0xdd),
...@@ -1554,9 +1556,10 @@ inline fn getModRmExt(tag: Tag) ?u3 {...@@ -1554,9 +1556,10 @@ inline fn getModRmExt(tag: Tag) ?u3 {
1554 => 0x4,1556 => 0x4,
1555 .shr => 0x5,1557 .shr => 0x5,
1556 .sar => 0x7,1558 .sar => 0x7,
1559 .mul => 0x4,
1557 .imul => 0x5,1560 .imul => 0x5,
1558 .idiv => 0x7,
1559 .div => 0x6,1561 .div => 0x6,
1562 .idiv => 0x7,
1560 .fisttp16 => 0x1,1563 .fisttp16 => 0x1,
1561 .fisttp32 => 0x1,1564 .fisttp32 => 0x1,
1562 .fisttp64 => 0x1,1565 .fisttp64 => 0x1,
src/arch/x86_64/Mir.zig+1
...@@ -227,6 +227,7 @@ pub const Inst = struct {...@@ -227,6 +227,7 @@ pub const Inst = struct {
227 /// 0b11 qword ptr [reg2 + imm32]227 /// 0b11 qword ptr [reg2 + imm32]
228 imul,228 imul,
229 idiv,229 idiv,
230 mul,
230 div,231 div,
231232
232 /// ops flags: form:233 /// ops flags: form: