authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-06-21 23:19:09+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-06-24 21:19:33+07:00
log65c5ef52e94323e15005cb943cd98b929119ce39
treed3615fced8c6f423282a269bff6a6537508eafe2
parent27adee3f12f1940a16e5042b7172ed61c32b1e76

stage2: sparc64: Implement airRem, airMod, and SPARCv9 s/udivx


4 files changed, 229 insertions(+), 4 deletions(-)

src/arch/sparc64/CodeGen.zig+205-3
...@@ -507,8 +507,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -507,8 +507,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
507 .mul => @panic("TODO try self.airMul(inst)"),507 .mul => @panic("TODO try self.airMul(inst)"),
508 .mulwrap => @panic("TODO try self.airMulWrap(inst)"),508 .mulwrap => @panic("TODO try self.airMulWrap(inst)"),
509 .mul_sat => @panic("TODO try self.airMulSat(inst)"),509 .mul_sat => @panic("TODO try self.airMulSat(inst)"),
510 .rem => @panic("TODO try self.airRem(inst)"),510 .rem => try self.airRem(inst),
511 .mod => @panic("TODO try self.airMod(inst)"),511 .mod => try self.airMod(inst),
512 .shl, .shl_exact => @panic("TODO try self.airShl(inst)"),512 .shl, .shl_exact => @panic("TODO try self.airShl(inst)"),
513 .shl_sat => @panic("TODO try self.airShlSat(inst)"),513 .shl_sat => @panic("TODO try self.airShlSat(inst)"),
514 .min => @panic("TODO try self.airMin(inst)"),514 .min => @panic("TODO try self.airMin(inst)"),
...@@ -1602,6 +1602,144 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void {...@@ -1602,6 +1602,144 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void {
1602 return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch});1602 return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch});
1603}1603}
16041604
1605fn airMod(self: *Self, inst: Air.Inst.Index) !void {
1606 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1607 const lhs = try self.resolveInst(bin_op.lhs);
1608 const rhs = try self.resolveInst(bin_op.rhs);
1609 const lhs_ty = self.air.typeOf(bin_op.lhs);
1610 const rhs_ty = self.air.typeOf(bin_op.rhs);
1611 assert(lhs_ty.eql(rhs_ty, self.bin_file.options.module.?));
1612
1613 if (self.liveness.isUnused(inst))
1614 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1615
1616 // TODO add safety check
1617
1618 // We use manual assembly emission to generate faster code
1619 // First, ensure lhs, rhs, rem, and added are in registers
1620
1621 const lhs_is_register = lhs == .register;
1622 const rhs_is_register = rhs == .register;
1623
1624 const lhs_reg = if (lhs_is_register)
1625 lhs.register
1626 else
1627 try self.register_manager.allocReg(null, gp);
1628
1629 const lhs_lock = self.register_manager.lockReg(lhs_reg);
1630 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1631
1632 const rhs_reg = if (rhs_is_register)
1633 rhs.register
1634 else
1635 try self.register_manager.allocReg(null, gp);
1636 const rhs_lock = self.register_manager.lockReg(rhs_reg);
1637 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1638
1639 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1640 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
1641
1642 const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
1643 const regs_locks = self.register_manager.lockRegsAssumeUnused(2, regs);
1644 defer for (regs_locks) |reg| {
1645 self.register_manager.unlockReg(reg);
1646 };
1647
1648 const add_reg = regs[0];
1649 const mod_reg = regs[1];
1650
1651 // mod_reg = @rem(lhs_reg, rhs_reg)
1652 _ = try self.addInst(.{
1653 .tag = .sdivx,
1654 .data = .{
1655 .arithmetic_3op = .{
1656 .is_imm = false,
1657 .rd = mod_reg,
1658 .rs1 = lhs_reg,
1659 .rs2_or_imm = .{ .rs2 = rhs_reg },
1660 },
1661 },
1662 });
1663
1664 _ = try self.addInst(.{
1665 .tag = .mulx,
1666 .data = .{
1667 .arithmetic_3op = .{
1668 .is_imm = false,
1669 .rd = mod_reg,
1670 .rs1 = mod_reg,
1671 .rs2_or_imm = .{ .rs2 = rhs_reg },
1672 },
1673 },
1674 });
1675
1676 _ = try self.addInst(.{
1677 .tag = .sub,
1678 .data = .{
1679 .arithmetic_3op = .{
1680 .is_imm = false,
1681 .rd = mod_reg,
1682 .rs1 = lhs_reg,
1683 .rs2_or_imm = .{ .rs2 = mod_reg },
1684 },
1685 },
1686 });
1687
1688 // add_reg = mod_reg + rhs_reg
1689 _ = try self.addInst(.{
1690 .tag = .add,
1691 .data = .{
1692 .arithmetic_3op = .{
1693 .is_imm = false,
1694 .rd = add_reg,
1695 .rs1 = mod_reg,
1696 .rs2_or_imm = .{ .rs2 = rhs_reg },
1697 },
1698 },
1699 });
1700
1701 // if (add_reg == rhs_reg) add_reg = 0
1702 _ = try self.addInst(.{
1703 .tag = .cmp,
1704 .data = .{
1705 .arithmetic_2op = .{
1706 .is_imm = false,
1707 .rs1 = add_reg,
1708 .rs2_or_imm = .{ .rs2 = rhs_reg },
1709 },
1710 },
1711 });
1712
1713 _ = try self.addInst(.{
1714 .tag = .movcc,
1715 .data = .{
1716 .conditional_move_int = .{
1717 .is_imm = true,
1718 .ccr = .xcc,
1719 .cond = .{ .icond = .eq },
1720 .rd = add_reg,
1721 .rs2_or_imm = .{ .imm = 0 },
1722 },
1723 },
1724 });
1725
1726 // if (lhs_reg < 0) mod_reg = add_reg
1727 _ = try self.addInst(.{
1728 .tag = .movr,
1729 .data = .{
1730 .conditional_move_reg = .{
1731 .is_imm = false,
1732 .cond = .lt_zero,
1733 .rd = mod_reg,
1734 .rs1 = lhs_reg,
1735 .rs2_or_imm = .{ .rs2 = add_reg },
1736 },
1737 },
1738 });
1739
1740 return self.finishAir(inst, .{ .register = mod_reg }, .{ bin_op.lhs, bin_op.rhs, .none });
1741}
1742
1605fn airNot(self: *Self, inst: Air.Inst.Index) !void {1743fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1606 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1744 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1607 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1745 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
...@@ -1704,6 +1842,27 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1704,6 +1842,27 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1704 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });1842 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1705}1843}
17061844
1845fn airRem(self: *Self, inst: Air.Inst.Index) !void {
1846 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1847 const lhs = try self.resolveInst(bin_op.lhs);
1848 const rhs = try self.resolveInst(bin_op.rhs);
1849 const lhs_ty = self.air.typeOf(bin_op.lhs);
1850 const rhs_ty = self.air.typeOf(bin_op.rhs);
1851
1852 // TODO add safety check
1853
1854 // result = lhs - @divTrunc(lhs, rhs) * rhs
1855 const result: MCValue = if (self.liveness.isUnused(inst)) blk: {
1856 break :blk .dead;
1857 } else blk: {
1858 const tmp0 = try self.binOp(.div_trunc, lhs, rhs, lhs_ty, rhs_ty, null);
1859 const tmp1 = try self.binOp(.mul, tmp0, rhs, lhs_ty, rhs_ty, null);
1860 break :blk try self.binOp(.sub, lhs, tmp1, lhs_ty, rhs_ty, null);
1861 };
1862
1863 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1864}
1865
1707fn airRet(self: *Self, inst: Air.Inst.Index) !void {1866fn airRet(self: *Self, inst: Air.Inst.Index) !void {
1708 const un_op = self.air.instructions.items(.data)[inst].un_op;1867 const un_op = self.air.instructions.items(.data)[inst].un_op;
1709 const operand = try self.resolveInst(un_op);1868 const operand = try self.resolveInst(un_op);
...@@ -2077,7 +2236,10 @@ fn binOp(...@@ -2077,7 +2236,10 @@ fn binOp(
2077) InnerError!MCValue {2236) InnerError!MCValue {
2078 const mod = self.bin_file.options.module.?;2237 const mod = self.bin_file.options.module.?;
2079 switch (tag) {2238 switch (tag) {
2080 .add, .cmp_eq => {2239 .add,
2240 .sub,
2241 .cmp_eq,
2242 => {
2081 switch (lhs_ty.zigTypeTag()) {2243 switch (lhs_ty.zigTypeTag()) {
2082 .Float => return self.fail("TODO binary operations on floats", .{}),2244 .Float => return self.fail("TODO binary operations on floats", .{}),
2083 .Vector => return self.fail("TODO binary operations on vectors", .{}),2245 .Vector => return self.fail("TODO binary operations on vectors", .{}),
...@@ -2103,6 +2265,7 @@ fn binOp(...@@ -2103,6 +2265,7 @@ fn binOp(
21032265
2104 const mir_tag: Mir.Inst.Tag = switch (tag) {2266 const mir_tag: Mir.Inst.Tag = switch (tag) {
2105 .add => .add,2267 .add => .add,
2268 .sub => .sub,
2106 .cmp_eq => .cmp,2269 .cmp_eq => .cmp,
2107 else => unreachable,2270 else => unreachable,
2108 };2271 };
...@@ -2124,6 +2287,39 @@ fn binOp(...@@ -2124,6 +2287,39 @@ fn binOp(
2124 }2287 }
2125 },2288 },
21262289
2290 .div_trunc => {
2291 switch (lhs_ty.zigTypeTag()) {
2292 .Vector => return self.fail("TODO binary operations on vectors", .{}),
2293 .Int => {
2294 assert(lhs_ty.eql(rhs_ty, mod));
2295 const int_info = lhs_ty.intInfo(self.target.*);
2296 if (int_info.bits <= 64) {
2297 const rhs_immediate_ok = switch (tag) {
2298 .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12),
2299 else => unreachable,
2300 };
2301
2302 const mir_tag: Mir.Inst.Tag = switch (tag) {
2303 .div_trunc => switch (int_info.signedness) {
2304 .signed => Mir.Inst.Tag.sdivx,
2305 .unsigned => Mir.Inst.Tag.udivx,
2306 },
2307 else => unreachable,
2308 };
2309
2310 if (rhs_immediate_ok) {
2311 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, true, metadata);
2312 } else {
2313 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2314 }
2315 } else {
2316 return self.fail("TODO binary operations on int with bits > 64", .{});
2317 }
2318 },
2319 else => unreachable,
2320 }
2321 },
2322
2127 .mul => {2323 .mul => {
2128 switch (lhs_ty.zigTypeTag()) {2324 switch (lhs_ty.zigTypeTag()) {
2129 .Vector => return self.fail("TODO binary operations on vectors", .{}),2325 .Vector => return self.fail("TODO binary operations on vectors", .{}),
...@@ -2382,6 +2578,9 @@ fn binOpImmediate(...@@ -2382,6 +2578,9 @@ fn binOpImmediate(
2382 .xor,2578 .xor,
2383 .xnor,2579 .xnor,
2384 .mulx,2580 .mulx,
2581 .sdivx,
2582 .udivx,
2583 .sub,
2385 .subcc,2584 .subcc,
2386 => .{2585 => .{
2387 .arithmetic_3op = .{2586 .arithmetic_3op = .{
...@@ -2503,6 +2702,9 @@ fn binOpRegister(...@@ -2503,6 +2702,9 @@ fn binOpRegister(
2503 .xor,2702 .xor,
2504 .xnor,2703 .xnor,
2505 .mulx,2704 .mulx,
2705 .sdivx,
2706 .udivx,
2707 .sub,
2506 .subcc,2708 .subcc,
2507 => .{2709 => .{
2508 .arithmetic_3op = .{2710 .arithmetic_3op = .{
src/arch/sparc64/Emit.zig+6
...@@ -105,6 +105,8 @@ pub fn emitMir(...@@ -105,6 +105,8 @@ pub fn emitMir(
105 .movr => @panic("TODO implement sparc64 movr"),105 .movr => @panic("TODO implement sparc64 movr"),
106106
107 .mulx => try emit.mirArithmetic3Op(inst),107 .mulx => try emit.mirArithmetic3Op(inst),
108 .sdivx => try emit.mirArithmetic3Op(inst),
109 .udivx => try emit.mirArithmetic3Op(inst),
108110
109 .nop => try emit.mirNop(),111 .nop => try emit.mirNop(),
110112
...@@ -234,6 +236,8 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -234,6 +236,8 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
234 .xor => try emit.writeInstruction(Instruction.xor(i13, rs1, imm, rd)),236 .xor => try emit.writeInstruction(Instruction.xor(i13, rs1, imm, rd)),
235 .xnor => try emit.writeInstruction(Instruction.xnor(i13, rs1, imm, rd)),237 .xnor => try emit.writeInstruction(Instruction.xnor(i13, rs1, imm, rd)),
236 .mulx => try emit.writeInstruction(Instruction.mulx(i13, rs1, imm, rd)),238 .mulx => try emit.writeInstruction(Instruction.mulx(i13, rs1, imm, rd)),
239 .sdivx => try emit.writeInstruction(Instruction.sdivx(i13, rs1, imm, rd)),
240 .udivx => try emit.writeInstruction(Instruction.udivx(i13, rs1, imm, rd)),
237 .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),241 .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),
238 .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),242 .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),
239 .stb => try emit.writeInstruction(Instruction.stb(i13, rs1, imm, rd)),243 .stb => try emit.writeInstruction(Instruction.stb(i13, rs1, imm, rd)),
...@@ -259,6 +263,8 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -259,6 +263,8 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
259 .xor => try emit.writeInstruction(Instruction.xor(Register, rs1, rs2, rd)),263 .xor => try emit.writeInstruction(Instruction.xor(Register, rs1, rs2, rd)),
260 .xnor => try emit.writeInstruction(Instruction.xnor(Register, rs1, rs2, rd)),264 .xnor => try emit.writeInstruction(Instruction.xnor(Register, rs1, rs2, rd)),
261 .mulx => try emit.writeInstruction(Instruction.mulx(Register, rs1, rs2, rd)),265 .mulx => try emit.writeInstruction(Instruction.mulx(Register, rs1, rs2, rd)),
266 .sdivx => try emit.writeInstruction(Instruction.sdivx(Register, rs1, rs2, rd)),
267 .udivx => try emit.writeInstruction(Instruction.udivx(Register, rs1, rs2, rd)),
262 .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),268 .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),
263 .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),269 .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),
264 .stb => try emit.writeInstruction(Instruction.stb(Register, rs1, rs2, rd)),270 .stb => try emit.writeInstruction(Instruction.stb(Register, rs1, rs2, rd)),
src/arch/sparc64/Mir.zig+2-1
...@@ -92,8 +92,9 @@ pub const Inst = struct {...@@ -92,8 +92,9 @@ pub const Inst = struct {
9292
93 /// A.37 Multiply and Divide (64-bit)93 /// A.37 Multiply and Divide (64-bit)
94 /// This uses the arithmetic_3op field.94 /// This uses the arithmetic_3op field.
95 // TODO add other operations.
96 mulx,95 mulx,
96 sdivx,
97 udivx,
9798
98 /// A.40 No Operation99 /// A.40 No Operation
99 /// This uses the nop field.100 /// This uses the nop field.
src/arch/sparc64/bits.zig+16
...@@ -1281,6 +1281,22 @@ pub const Instruction = union(enum) {...@@ -1281,6 +1281,22 @@ pub const Instruction = union(enum) {
1281 };1281 };
1282 }1282 }
12831283
1284 pub fn sdivx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1285 return switch (s2) {
1286 Register => format3a(0b10, 0b10_1101, rs1, rs2, rd),
1287 i13 => format3b(0b10, 0b10_1101, rs1, rs2, rd),
1288 else => unreachable,
1289 };
1290 }
1291
1292 pub fn udivx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1293 return switch (s2) {
1294 Register => format3a(0b10, 0b00_1101, rs1, rs2, rd),
1295 i13 => format3b(0b10, 0b00_1101, rs1, rs2, rd),
1296 else => unreachable,
1297 };
1298 }
1299
1284 pub fn nop() Instruction {1300 pub fn nop() Instruction {
1285 return sethi(0, .g0);1301 return sethi(0, .g0);
1286 }1302 }