diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-03-29 10:11:24 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-03-30 00:37:42 +0200 |
| commit | f9773ab622d84527ddfdb08d07443ec05cf28737 (patch) | |
| tree | 75747d45594e877f6ab1821ac739e6693bb76e8a /src | |
| parent | 12e1304805cbe132d17b31bac2e8123869007e4d (diff) | |
| download | zig-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.zig | 54 | ||||
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 7 | ||||
| -rw-r--r-- | src/arch/x86_64/Mir.zig | 1 |
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: |
