authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-10 23:11:27-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-06-13 02:21:38-07:00
log031d8248e02f019a4c689dfa2913b30ec796dfa5
tree79a46987a0d40fccbf228c6e304d8d00a2e228e7
parent7ed2f2156f4e93fa6463fb81f134c0d5e7e7cc89
signaturelock-open Commit is signed but in an unrecognized format.

riscv: first sign of floats!


11 files changed, 736 insertions(+), 481 deletions(-)

src/arch/riscv64/CodeGen.zig+285-274
...@@ -38,23 +38,9 @@ const Memory = bits.Memory;...@@ -38,23 +38,9 @@ const Memory = bits.Memory;
38const FrameIndex = bits.FrameIndex;38const FrameIndex = bits.FrameIndex;
39const RegisterManager = abi.RegisterManager;39const RegisterManager = abi.RegisterManager;
40const RegisterLock = RegisterManager.RegisterLock;40const RegisterLock = RegisterManager.RegisterLock;
41const callee_preserved_regs = abi.callee_preserved_regs;
42/// General Purpose
43const gp = abi.RegisterClass.gp;
44/// Function Args
45const fa = abi.RegisterClass.fa;
46/// Function Returns
47const fr = abi.RegisterClass.fr;
48/// Temporary Use
49const tp = abi.RegisterClass.tp;
5041
51const InnerError = CodeGenError || error{OutOfRegisters};42const InnerError = CodeGenError || error{OutOfRegisters};
5243
53const RegisterView = enum(u1) {
54 caller,
55 callee,
56};
57
58gpa: Allocator,44gpa: Allocator,
59air: Air,45air: Air,
60mod: *Package.Module,46mod: *Package.Module,
...@@ -919,10 +905,24 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {...@@ -919,10 +905,24 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
919 return result;905 return result;
920}906}
921907
908const required_features = [_]Target.riscv.Feature{
909 .d,
910 .m,
911};
912
922fn gen(self: *Self) !void {913fn gen(self: *Self) !void {
923 const mod = self.bin_file.comp.module.?;914 const mod = self.bin_file.comp.module.?;
924 const fn_info = mod.typeToFunc(self.fn_type).?;915 const fn_info = mod.typeToFunc(self.fn_type).?;
925916
917 inline for (required_features) |feature| {
918 if (!self.hasFeature(feature)) {
919 return self.fail(
920 "target missing required feature {s}",
921 .{@tagName(feature)},
922 );
923 }
924 }
925
926 if (fn_info.cc != .Naked) {926 if (fn_info.cc != .Naked) {
927 try self.addPseudoNone(.pseudo_dbg_prologue_end);927 try self.addPseudoNone(.pseudo_dbg_prologue_end);
928928
...@@ -1454,9 +1454,9 @@ fn computeFrameLayout(self: *Self) !FrameLayout {...@@ -1454,9 +1454,9 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
1454 }1454 }
14551455
1456 var save_reg_list = Mir.RegisterList{};1456 var save_reg_list = Mir.RegisterList{};
1457 for (callee_preserved_regs) |reg| {1457 for (abi.Registers.all_preserved) |reg| {
1458 if (self.register_manager.isRegAllocated(reg)) {1458 if (self.register_manager.isRegAllocated(reg)) {
1459 save_reg_list.push(&callee_preserved_regs, reg);1459 save_reg_list.push(&abi.Registers.all_preserved, reg);
1460 }1460 }
1461 }1461 }
14621462
...@@ -1600,6 +1600,33 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex {...@@ -1600,6 +1600,33 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex {
1600 }));1600 }));
1601}1601}
16021602
1603fn typeRegClass(self: *Self, ty: Type) abi.RegisterClass {
1604 const zcu = self.bin_file.comp.module.?;
1605 return switch (ty.zigTypeTag(zcu)) {
1606 .Float => .float,
1607 .Vector => @panic("TODO: typeRegClass for Vectors"),
1608 inline else => .int,
1609 };
1610}
1611
1612fn regGeneralClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet {
1613 const zcu = self.bin_file.comp.module.?;
1614 return switch (ty.zigTypeTag(zcu)) {
1615 .Float => abi.Registers.Float.general_purpose,
1616 .Vector => @panic("TODO: regGeneralClassForType for Vectors"),
1617 else => abi.Registers.Integer.general_purpose,
1618 };
1619}
1620
1621fn regTempClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet {
1622 const zcu = self.bin_file.comp.module.?;
1623 return switch (ty.zigTypeTag(zcu)) {
1624 .Float => abi.Registers.Float.temporary,
1625 .Vector => @panic("TODO: regTempClassForType for Vectors"),
1626 else => abi.Registers.Integer.temporary,
1627 };
1628}
1629
1603fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {1630fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1604 const zcu = self.bin_file.comp.module.?;1631 const zcu = self.bin_file.comp.module.?;
1605 const elem_ty = self.typeOfIndex(inst);1632 const elem_ty = self.typeOfIndex(inst);
...@@ -1608,11 +1635,15 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -1608,11 +1635,15 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1608 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)});1635 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)});
1609 };1636 };
16101637
1611 if (reg_ok) {1638 const min_size: u32 = switch (elem_ty.zigTypeTag(zcu)) {
1612 if (abi_size <= 8) {1639 .Float => 4,
1613 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {1640 .Vector => @panic("allocRegOrMem Vector"),
1614 return .{ .register = reg };1641 else => 8,
1615 }1642 };
1643
1644 if (reg_ok and abi_size <= min_size) {
1645 if (self.register_manager.tryAllocReg(inst, self.regGeneralClassForType(elem_ty))) |reg| {
1646 return .{ .register = reg };
1616 }1647 }
1617 }1648 }
16181649
...@@ -1623,19 +1654,37 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -1623,19 +1654,37 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1623/// Allocates a register from the general purpose set and returns the Register and the Lock.1654/// Allocates a register from the general purpose set and returns the Register and the Lock.
1624///1655///
1625/// Up to the caller to unlock the register later.1656/// Up to the caller to unlock the register later.
1626fn allocReg(self: *Self) !struct { Register, RegisterLock } {1657fn allocReg(self: *Self, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } {
1627 const reg = try self.register_manager.allocReg(null, gp);1658 if (reg_class == .float and !self.hasFeature(.f))
1659 std.debug.panic("allocReg class == float where F isn't enabled", .{});
1660
1661 const class = switch (reg_class) {
1662 .int => abi.Registers.Integer.general_purpose,
1663 .float => abi.Registers.Float.general_purpose,
1664 };
1665
1666 const reg = try self.register_manager.allocReg(null, class);
1628 const lock = self.register_manager.lockRegAssumeUnused(reg);1667 const lock = self.register_manager.lockRegAssumeUnused(reg);
1629 return .{ reg, lock };1668 return .{ reg, lock };
1630}1669}
16311670
1671/// Similar to `allocReg` but will copy the MCValue into the Register unless `operand` is already
1672/// a register, in which case it will return a possible lock to that register.
1673fn promoteReg(self: *Self, ty: Type, operand: MCValue) !struct { Register, ?RegisterLock } {
1674 if (operand == .register) return .{ operand.register, self.register_manager.lockReg(operand.register) };
1675
1676 const reg, const lock = try self.allocReg(self.typeRegClass(ty));
1677 try self.genSetReg(ty, reg, operand);
1678 return .{ reg, lock };
1679}
1680
1632fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {1681fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
1633 const reg: Register = blk: {1682 const reg: Register = blk: {
1634 switch (index) {1683 switch (index) {
1635 .immediate => |imm| {1684 .immediate => |imm| {
1636 // Optimisation: if index MCValue is an immediate, we can multiply in `comptime`1685 // Optimisation: if index MCValue is an immediate, we can multiply in `comptime`
1637 // and set the register directly to the scaled offset as an immediate.1686 // and set the register directly to the scaled offset as an immediate.
1638 const reg = try self.register_manager.allocReg(null, gp);1687 const reg = try self.register_manager.allocReg(null, self.regGeneralClassForType(index_ty));
1639 try self.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size });1688 try self.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size });
1640 break :blk reg;1689 break :blk reg;
1641 },1690 },
...@@ -1671,7 +1720,8 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -1671,7 +1720,8 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
1671/// allocated. A second call to `copyToTmpRegister` may return the same register.1720/// allocated. A second call to `copyToTmpRegister` may return the same register.
1672/// This can have a side effect of spilling instructions to the stack to free up a register.1721/// This can have a side effect of spilling instructions to the stack to free up a register.
1673fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {1722fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
1674 const reg = try self.register_manager.allocReg(null, tp);1723 log.debug("copyToTmpRegister ty: {}", .{ty.fmt(self.bin_file.comp.module.?)});
1724 const reg = try self.register_manager.allocReg(null, self.regTempClassForType(ty));
1675 try self.genSetReg(ty, reg, mcv);1725 try self.genSetReg(ty, reg, mcv);
1676 return reg;1726 return reg;
1677}1727}
...@@ -1680,7 +1730,8 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {...@@ -1680,7 +1730,8 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
1680/// `reg_owner` is the instruction that gets associated with the register in the register table.1730/// `reg_owner` is the instruction that gets associated with the register in the register table.
1681/// This can have a side effect of spilling instructions to the stack to free up a register.1731/// This can have a side effect of spilling instructions to the stack to free up a register.
1682fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {1732fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
1683 const reg = try self.register_manager.allocReg(reg_owner, gp);1733 const ty = self.typeOfIndex(reg_owner);
1734 const reg = try self.register_manager.allocReg(reg_owner, self.regGeneralClassForType(ty));
1684 try self.genSetReg(self.typeOfIndex(reg_owner), reg, mcv);1735 try self.genSetReg(self.typeOfIndex(reg_owner), reg, mcv);
1685 return MCValue{ .register = reg };1736 return MCValue{ .register = reg };
1686}1737}
...@@ -1797,7 +1848,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1797,7 +1848,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1797 if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)1848 if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)
1798 operand.register1849 operand.register
1799 else1850 else
1800 try self.register_manager.allocReg(inst, gp);1851 (try self.allocRegOrMem(inst, true)).register;
18011852
1802 _ = try self.addInst(.{1853 _ = try self.addInst(.{
1803 .tag = .pseudo,1854 .tag = .pseudo,
...@@ -1843,7 +1894,7 @@ fn airMinMax(...@@ -1843,7 +1894,7 @@ fn airMinMax(
1843 const lhs_reg, const lhs_lock = blk: {1894 const lhs_reg, const lhs_lock = blk: {
1844 if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) };1895 if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) };
18451896
1846 const lhs_reg, const lhs_lock = try self.allocReg();1897 const lhs_reg, const lhs_lock = try self.allocReg(.int);
1847 try self.genSetReg(lhs_ty, lhs_reg, lhs);1898 try self.genSetReg(lhs_ty, lhs_reg, lhs);
1848 break :blk .{ lhs_reg, lhs_lock };1899 break :blk .{ lhs_reg, lhs_lock };
1849 };1900 };
...@@ -1852,16 +1903,16 @@ fn airMinMax(...@@ -1852,16 +1903,16 @@ fn airMinMax(
1852 const rhs_reg, const rhs_lock = blk: {1903 const rhs_reg, const rhs_lock = blk: {
1853 if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) };1904 if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) };
18541905
1855 const rhs_reg, const rhs_lock = try self.allocReg();1906 const rhs_reg, const rhs_lock = try self.allocReg(.int);
1856 try self.genSetReg(rhs_ty, rhs_reg, rhs);1907 try self.genSetReg(rhs_ty, rhs_reg, rhs);
1857 break :blk .{ rhs_reg, rhs_lock };1908 break :blk .{ rhs_reg, rhs_lock };
1858 };1909 };
1859 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);1910 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
18601911
1861 const mask_reg, const mask_lock = try self.allocReg();1912 const mask_reg, const mask_lock = try self.allocReg(.int);
1862 defer self.register_manager.unlockReg(mask_lock);1913 defer self.register_manager.unlockReg(mask_lock);
18631914
1864 const result_reg, const result_lock = try self.allocReg();1915 const result_reg, const result_lock = try self.allocReg(.int);
1865 defer self.register_manager.unlockReg(result_lock);1916 defer self.register_manager.unlockReg(result_lock);
18661917
1867 _ = try self.addInst(.{1918 _ = try self.addInst(.{
...@@ -1955,20 +2006,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -1955,20 +2006,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1955 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2006 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1956}2007}
19572008
1958/// For all your binary operation needs, this function will generate
1959/// the corresponding Mir instruction(s). Returns the location of the
1960/// result.
1961///
1962/// If the binary operation itself happens to be an Air instruction,
1963/// pass the corresponding index in the inst parameter. That helps
1964/// this function do stuff like reusing operands.
1965///
1966/// This function does not do any lowering to Mir itself, but instead
1967/// looks at the lhs and rhs and determines which kind of lowering
1968/// would be best suitable and then delegates the lowering to other
1969/// functions.
1970///
1971/// `maybe_inst` **needs** to be a bin_op, make sure of that.
1972fn binOp(2009fn binOp(
1973 self: *Self,2010 self: *Self,
1974 tag: Air.Inst.Tag,2011 tag: Air.Inst.Tag,
...@@ -1991,11 +2028,18 @@ fn binOp(...@@ -1991,11 +2028,18 @@ fn binOp(
1991 .cmp_lt,2028 .cmp_lt,
1992 .cmp_lte,2029 .cmp_lte,
1993 => {2030 => {
2031 assert(lhs_ty.eql(rhs_ty, zcu));
1994 switch (lhs_ty.zigTypeTag(zcu)) {2032 switch (lhs_ty.zigTypeTag(zcu)) {
1995 .Float => return self.fail("TODO binary operations on floats", .{}),2033 .Float => {
2034 const float_bits = lhs_ty.floatBits(zcu.getTarget());
2035 if (float_bits <= 32) {
2036 return self.binOpFloat(tag, lhs, lhs_ty, rhs, rhs_ty);
2037 } else {
2038 return self.fail("TODO: binary operations for floats with bits > 32", .{});
2039 }
2040 },
1996 .Vector => return self.fail("TODO binary operations on vectors", .{}),2041 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1997 .Int, .Enum, .ErrorSet => {2042 .Int, .Enum, .ErrorSet => {
1998 assert(lhs_ty.eql(rhs_ty, zcu));
1999 const int_info = lhs_ty.intInfo(zcu);2043 const int_info = lhs_ty.intInfo(zcu);
2000 if (int_info.bits <= 64) {2044 if (int_info.bits <= 64) {
2001 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);2045 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
...@@ -2071,14 +2115,7 @@ fn binOp(...@@ -2071,14 +2115,7 @@ fn binOp(
2071 else => return self.fail("TODO binOp {}", .{tag}),2115 else => return self.fail("TODO binOp {}", .{tag}),
2072 }2116 }
2073}2117}
2074/// Don't call this function directly. Use binOp instead.2118
2075///
2076/// Calling this function signals an intention to generate a Mir
2077/// instruction of the form
2078///
2079/// op dest, lhs, rhs
2080///
2081/// Asserts that generating an instruction of that form is possible.
2082fn binOpRegister(2119fn binOpRegister(
2083 self: *Self,2120 self: *Self,
2084 tag: Air.Inst.Tag,2121 tag: Air.Inst.Tag,
...@@ -2087,25 +2124,13 @@ fn binOpRegister(...@@ -2087,25 +2124,13 @@ fn binOpRegister(
2087 rhs: MCValue,2124 rhs: MCValue,
2088 rhs_ty: Type,2125 rhs_ty: Type,
2089) !MCValue {2126) !MCValue {
2090 const lhs_reg, const lhs_lock = blk: {2127 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2091 if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) };
2092
2093 const lhs_reg, const lhs_lock = try self.allocReg();
2094 try self.genSetReg(lhs_ty, lhs_reg, lhs);
2095 break :blk .{ lhs_reg, lhs_lock };
2096 };
2097 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);2128 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
20982129
2099 const rhs_reg, const rhs_lock = blk: {2130 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2100 if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) };
2101
2102 const rhs_reg, const rhs_lock = try self.allocReg();
2103 try self.genSetReg(rhs_ty, rhs_reg, rhs);
2104 break :blk .{ rhs_reg, rhs_lock };
2105 };
2106 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);2131 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
21072132
2108 const dest_reg, const dest_lock = try self.allocReg();2133 const dest_reg, const dest_lock = try self.allocReg(.int);
2109 defer self.register_manager.unlockReg(dest_lock);2134 defer self.register_manager.unlockReg(dest_lock);
21102135
2111 const mir_tag: Mir.Inst.Tag = switch (tag) {2136 const mir_tag: Mir.Inst.Tag = switch (tag) {
...@@ -2184,7 +2209,50 @@ fn binOpRegister(...@@ -2184,7 +2209,50 @@ fn binOpRegister(
2184 else => unreachable,2209 else => unreachable,
2185 }2210 }
21862211
2187 // generate the struct for OF checks2212 return MCValue{ .register = dest_reg };
2213}
2214
2215fn binOpFloat(
2216 self: *Self,
2217 tag: Air.Inst.Tag,
2218 lhs: MCValue,
2219 lhs_ty: Type,
2220 rhs: MCValue,
2221 rhs_ty: Type,
2222) !MCValue {
2223 const zcu = self.bin_file.comp.module.?;
2224 const float_bits = lhs_ty.floatBits(zcu.getTarget());
2225
2226 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2227 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
2228
2229 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2230 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
2231
2232 const mir_tag: Mir.Inst.Tag = switch (tag) {
2233 .add => if (float_bits == 32) .fadds else .faddd,
2234 .cmp_eq => if (float_bits == 32) .feqs else .feqd,
2235 else => return self.fail("TODO: binOpFloat mir_tag {s}", .{@tagName(tag)}),
2236 };
2237
2238 const return_class: abi.RegisterClass = switch (tag) {
2239 .add => .float,
2240 .cmp_eq => .int,
2241 else => unreachable,
2242 };
2243
2244 const dest_reg, const dest_lock = try self.allocReg(return_class);
2245 defer self.register_manager.unlockReg(dest_lock);
2246
2247 _ = try self.addInst(.{
2248 .tag = mir_tag,
2249 .ops = .rrr,
2250 .data = .{ .r_type = .{
2251 .rd = dest_reg,
2252 .rs1 = lhs_reg,
2253 .rs2 = rhs_reg,
2254 } },
2255 });
21882256
2189 return MCValue{ .register = dest_reg };2257 return MCValue{ .register = dest_reg };
2190}2258}
...@@ -2279,7 +2347,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2279,7 +2347,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22792347
2280 const shift_amount: u6 = @intCast(Type.usize.bitSize(zcu) - int_info.bits);2348 const shift_amount: u6 = @intCast(Type.usize.bitSize(zcu) - int_info.bits);
22812349
2282 const shift_reg, const shift_lock = try self.allocReg();2350 const shift_reg, const shift_lock = try self.allocReg(.int);
2283 defer self.register_manager.unlockReg(shift_lock);2351 defer self.register_manager.unlockReg(shift_lock);
22842352
2285 _ = try self.addInst(.{2353 _ = try self.addInst(.{
...@@ -2357,25 +2425,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2357,25 +2425,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2357 const result_mcv = try self.allocRegOrMem(inst, false);2425 const result_mcv = try self.allocRegOrMem(inst, false);
2358 const offset = result_mcv.load_frame;2426 const offset = result_mcv.load_frame;
23592427
2360 const lhs_reg, const lhs_lock = blk: {2428 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2361 if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) };
2362
2363 const lhs_reg, const lhs_lock = try self.allocReg();
2364 try self.genSetReg(lhs_ty, lhs_reg, lhs);
2365 break :blk .{ lhs_reg, lhs_lock };
2366 };
2367 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);2429 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
23682430
2369 const rhs_reg, const rhs_lock = blk: {2431 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2370 if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) };
2371
2372 const rhs_reg, const rhs_lock = try self.allocReg();
2373 try self.genSetReg(rhs_ty, rhs_reg, rhs);
2374 break :blk .{ rhs_reg, rhs_lock };
2375 };
2376 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);2432 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
23772433
2378 const dest_reg, const dest_lock = try self.allocReg();2434 const dest_reg, const dest_lock = try self.allocReg(.int);
2379 defer self.register_manager.unlockReg(dest_lock);2435 defer self.register_manager.unlockReg(dest_lock);
23802436
2381 switch (int_info.signedness) {2437 switch (int_info.signedness) {
...@@ -2503,18 +2559,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2503,18 +2559,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2503 1...8 => {2559 1...8 => {
2504 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;2560 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
25052561
2506 const overflow_reg, const overflow_lock = try self.allocReg();2562 const add_reg, const add_lock = try self.promoteReg(lhs_ty, lhs);
2507 defer self.register_manager.unlockReg(overflow_lock);
2508
2509 const add_reg, const add_lock = blk: {
2510 if (dest == .register) break :blk .{ dest.register, null };
2511
2512 const add_reg, const add_lock = try self.allocReg();
2513 try self.genSetReg(lhs_ty, add_reg, dest);
2514 break :blk .{ add_reg, add_lock };
2515 };
2516 defer if (add_lock) |lock| self.register_manager.unlockReg(lock);2563 defer if (add_lock) |lock| self.register_manager.unlockReg(lock);
25172564
2565 const overflow_reg, const overflow_lock = try self.allocReg(.int);
2566 defer self.register_manager.unlockReg(overflow_lock);
2567
2518 _ = try self.addInst(.{2568 _ = try self.addInst(.{
2519 .tag = .andi,2569 .tag = .andi,
2520 .ops = .rri,2570 .ops = .rri,
...@@ -2595,25 +2645,13 @@ fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void {...@@ -2595,25 +2645,13 @@ fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void {
2595 const lhs_ty = self.typeOf(bin_op.lhs);2645 const lhs_ty = self.typeOf(bin_op.lhs);
2596 const rhs_ty = self.typeOf(bin_op.rhs);2646 const rhs_ty = self.typeOf(bin_op.rhs);
25972647
2598 const lhs_reg, const lhs_lock = blk: {2648 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2599 if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) };
2600
2601 const lhs_reg, const lhs_lock = try self.allocReg();
2602 try self.genSetReg(lhs_ty, lhs_reg, lhs);
2603 break :blk .{ lhs_reg, lhs_lock };
2604 };
2605 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);2649 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
26062650
2607 const rhs_reg, const rhs_lock = blk: {2651 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2608 if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) };
2609
2610 const rhs_reg, const rhs_lock = try self.allocReg();
2611 try self.genSetReg(rhs_ty, rhs_reg, rhs);
2612 break :blk .{ rhs_reg, rhs_lock };
2613 };
2614 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);2652 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
26152653
2616 const dest_reg, const dest_lock = try self.allocReg();2654 const dest_reg, const dest_lock = try self.allocReg(.int);
2617 defer self.register_manager.unlockReg(dest_lock);2655 defer self.register_manager.unlockReg(dest_lock);
26182656
2619 _ = try self.addInst(.{2657 _ = try self.addInst(.{
...@@ -2640,25 +2678,13 @@ fn airBitOr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2640,25 +2678,13 @@ fn airBitOr(self: *Self, inst: Air.Inst.Index) !void {
2640 const lhs_ty = self.typeOf(bin_op.lhs);2678 const lhs_ty = self.typeOf(bin_op.lhs);
2641 const rhs_ty = self.typeOf(bin_op.rhs);2679 const rhs_ty = self.typeOf(bin_op.rhs);
26422680
2643 const lhs_reg, const lhs_lock = blk: {2681 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2644 if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) };
2645
2646 const lhs_reg, const lhs_lock = try self.allocReg();
2647 try self.genSetReg(lhs_ty, lhs_reg, lhs);
2648 break :blk .{ lhs_reg, lhs_lock };
2649 };
2650 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);2682 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
26512683
2652 const rhs_reg, const rhs_lock = blk: {2684 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2653 if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) };
2654
2655 const rhs_reg, const rhs_lock = try self.allocReg();
2656 try self.genSetReg(rhs_ty, rhs_reg, rhs);
2657 break :blk .{ rhs_reg, rhs_lock };
2658 };
2659 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);2685 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
26602686
2661 const dest_reg, const dest_lock = try self.allocReg();2687 const dest_reg, const dest_lock = try self.allocReg(.int);
2662 defer self.register_manager.unlockReg(dest_lock);2688 defer self.register_manager.unlockReg(dest_lock);
26632689
2664 _ = try self.addInst(.{2690 _ = try self.addInst(.{
...@@ -3102,7 +3128,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3102,7 +3128,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
3102 const elem_ty = array_ty.childType(zcu);3128 const elem_ty = array_ty.childType(zcu);
3103 const elem_abi_size = elem_ty.abiSize(zcu);3129 const elem_abi_size = elem_ty.abiSize(zcu);
31043130
3105 const addr_reg, const addr_reg_lock = try self.allocReg();3131 const addr_reg, const addr_reg_lock = try self.allocReg(.int);
3106 defer self.register_manager.unlockReg(addr_reg_lock);3132 defer self.register_manager.unlockReg(addr_reg_lock);
31073133
3108 switch (array_mcv) {3134 switch (array_mcv) {
...@@ -3211,46 +3237,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -3211,46 +3237,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
32113237
3212fn airCtz(self: *Self, inst: Air.Inst.Index) !void {3238fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
3213 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3239 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3214 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {3240 _ = ty_op;
3215 const operand = try self.resolveInst(ty_op.operand);
3216 const operand_ty = self.typeOf(ty_op.operand);
3217
3218 const dest_reg = try self.register_manager.allocReg(inst, gp);
3219
3220 const source_reg, const source_lock = blk: {
3221 if (operand == .register) break :blk .{ operand.register, null };
3222
3223 const source_reg, const source_lock = try self.allocReg();
3224 try self.genSetReg(operand_ty, source_reg, operand);
3225 break :blk .{ source_reg, source_lock };
3226 };
3227 defer if (source_lock) |lock| self.register_manager.unlockReg(lock);
3228
3229 // TODO: the B extension for RISCV should have the ctz instruction, and we should use it.
3230
3231 try self.ctz(source_reg, dest_reg, operand_ty);
3232
3233 break :result .{ .register = dest_reg };
3234 };
3235 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3236}
3237
3238fn ctz(self: *Self, src: Register, dst: Register, ty: Type) !void {
3239 const zcu = self.bin_file.comp.module.?;
3240 const length = (ty.abiSize(zcu) * 8) - 1;
3241
3242 const count_reg, const count_lock = try self.allocReg();
3243 defer self.register_manager.unlockReg(count_lock);
3244
3245 const len_reg, const len_lock = try self.allocReg();
3246 defer self.register_manager.unlockReg(len_lock);
3247
3248 try self.genSetReg(Type.usize, count_reg, .{ .immediate = 0 });
3249 try self.genSetReg(Type.usize, len_reg, .{ .immediate = length });
3250
3251 _ = src;
3252 _ = dst;
3253
3254 return self.fail("TODO: finish ctz", .{});3241 return self.fail("TODO: finish ctz", .{});
3255}3242}
32563243
...@@ -3267,38 +3254,18 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {...@@ -3267,38 +3254,18 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
3267 const ty = self.typeOf(ty_op.operand);3254 const ty = self.typeOf(ty_op.operand);
3268 const scalar_ty = ty.scalarType(zcu);3255 const scalar_ty = ty.scalarType(zcu);
3269 const operand = try self.resolveInst(ty_op.operand);3256 const operand = try self.resolveInst(ty_op.operand);
3257 _ = operand;
32703258
3271 switch (scalar_ty.zigTypeTag(zcu)) {3259 switch (scalar_ty.zigTypeTag(zcu)) {
3272 .Int => if (ty.zigTypeTag(zcu) == .Vector) {3260 .Int => if (ty.zigTypeTag(zcu) == .Vector) {
3273 return self.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)});3261 return self.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)});
3274 } else {3262 } else {
3275 const int_bits = ty.intInfo(zcu).bits;3263 return self.fail("TODO: implement airAbs for Int", .{});
3276
3277 if (int_bits > 32) {
3278 return self.fail("TODO: airAbs for larger than 32 bits", .{});
3279 }
3280
3281 // promote the src into a register
3282 const src_mcv = try self.copyToNewRegister(inst, operand);
3283 // temp register for shift
3284 const temp_reg = try self.register_manager.allocReg(inst, gp);
3285
3286 _ = try self.addInst(.{
3287 .tag = .abs,
3288 .ops = .rri,
3289 .data = .{
3290 .i_type = .{
3291 .rs1 = src_mcv.register,
3292 .rd = temp_reg,
3293 .imm12 = Immediate.s(int_bits - 1),
3294 },
3295 },
3296 });
3297
3298 break :result src_mcv;
3299 },3264 },
3300 else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}),3265 else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}),
3301 }3266 }
3267
3268 break :result .{.unreach};
3302 };3269 };
3303 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3270 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3304}3271}
...@@ -3317,15 +3284,24 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {...@@ -3317,15 +3284,24 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
3317 return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });3284 return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
3318 }3285 }
33193286
3320 const dest_reg = try self.register_manager.allocReg(null, gp);3287 const dest_mcv = try self.copyToNewRegister(inst, operand);
3321 try self.genSetReg(ty, dest_reg, operand);3288 const dest_reg = dest_mcv.register;
3322
3323 const dest_mcv: MCValue = .{ .register = dest_reg };
33243289
3325 switch (int_bits) {3290 switch (int_bits) {
3326 16 => {3291 16 => {
3327 const temp = try self.binOp(.shr, dest_mcv, ty, .{ .immediate = 8 }, Type.u8);3292 const temp_reg, const temp_lock = try self.allocReg(.int);
3328 assert(temp == .register);3293 defer self.register_manager.unlockReg(temp_lock);
3294
3295 _ = try self.addInst(.{
3296 .tag = .srli,
3297 .ops = .rri,
3298 .data = .{ .i_type = .{
3299 .imm12 = Immediate.s(8),
3300 .rd = temp_reg,
3301 .rs1 = dest_reg,
3302 } },
3303 });
3304
3329 _ = try self.addInst(.{3305 _ = try self.addInst(.{
3330 .tag = .slli,3306 .tag = .slli,
3331 .ops = .rri,3307 .ops = .rri,
...@@ -3341,7 +3317,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {...@@ -3341,7 +3317,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
3341 .data = .{ .r_type = .{3317 .data = .{ .r_type = .{
3342 .rd = dest_reg,3318 .rd = dest_reg,
3343 .rs1 = dest_reg,3319 .rs1 = dest_reg,
3344 .rs2 = temp.register,3320 .rs2 = temp_reg,
3345 } },3321 } },
3346 });3322 });
3347 },3323 },
...@@ -3360,11 +3336,12 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -3360,11 +3336,12 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
3360}3336}
33613337
3362fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {3338fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
3339 const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
3363 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;3340 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3364 const result: MCValue = if (self.liveness.isUnused(inst))3341 const result: MCValue = if (self.liveness.isUnused(inst))
3365 .unreach3342 .unreach
3366 else3343 else
3367 return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch});3344 return self.fail("TODO implementairUnaryMath {s} for {}", .{ @tagName(tag), self.target.cpu.arch });
3368 return self.finishAir(inst, result, .{ un_op, .none, .none });3345 return self.finishAir(inst, result, .{ un_op, .none, .none });
3369}3346}
33703347
...@@ -3640,7 +3617,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3640,7 +3617,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3640 @intCast(field_bit_size),3617 @intCast(field_bit_size),
3641 );3618 );
36423619
3643 const dst_reg, const dst_lock = try self.allocReg();3620 const dst_reg, const dst_lock = try self.allocReg(.int);
3644 const dst_mcv = MCValue{ .register = dst_reg };3621 const dst_mcv = MCValue{ .register = dst_reg };
3645 defer self.register_manager.unlockReg(dst_lock);3622 defer self.register_manager.unlockReg(dst_lock);
36463623
...@@ -3658,7 +3635,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3658,7 +3635,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3658 break :dst dst_mcv;3635 break :dst dst_mcv;
3659 };3636 };
3660 if (field_abi_size * 8 > field_bit_size and dst_mcv.isMemory()) {3637 if (field_abi_size * 8 > field_bit_size and dst_mcv.isMemory()) {
3661 const tmp_reg, const tmp_lock = try self.allocReg();3638 const tmp_reg, const tmp_lock = try self.allocReg(.int);
3662 defer self.register_manager.unlockReg(tmp_lock);3639 defer self.register_manager.unlockReg(tmp_lock);
36633640
3664 const hi_mcv =3641 const hi_mcv =
...@@ -3972,7 +3949,7 @@ fn genCall(...@@ -3972,7 +3949,7 @@ fn genCall(
3972 }3949 }
3973 } else {3950 } else {
3974 assert(self.typeOf(callee).zigTypeTag(zcu) == .Pointer);3951 assert(self.typeOf(callee).zigTypeTag(zcu) == .Pointer);
3975 const addr_reg, const addr_lock = try self.allocReg();3952 const addr_reg, const addr_lock = try self.allocReg(.int);
3976 defer self.register_manager.unlockReg(addr_lock);3953 defer self.register_manager.unlockReg(addr_lock);
3977 try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee });3954 try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee });
39783955
...@@ -4072,32 +4049,49 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {...@@ -4072,32 +4049,49 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
4072 const rhs = try self.resolveInst(bin_op.rhs);4049 const rhs = try self.resolveInst(bin_op.rhs);
4073 const lhs_ty = self.typeOf(bin_op.lhs);4050 const lhs_ty = self.typeOf(bin_op.lhs);
40744051
4075 const int_ty = switch (lhs_ty.zigTypeTag(zcu)) {4052 switch (lhs_ty.zigTypeTag(zcu)) {
4076 .Vector => unreachable, // Handled by cmp_vector.4053 .Int,
4077 .Enum => lhs_ty.intTagType(zcu),4054 .Enum,
4078 .Int => lhs_ty,4055 .Bool,
4079 .Bool => Type.u1,4056 .Pointer,
4080 .Pointer => Type.usize,4057 .ErrorSet,
4081 .ErrorSet => Type.u16,4058 .Optional,
4082 .Optional => blk: {4059 => {
4083 const payload_ty = lhs_ty.optionalChild(zcu);4060 const int_ty = switch (lhs_ty.zigTypeTag(zcu)) {
4084 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4061 .Enum => lhs_ty.intTagType(zcu),
4085 break :blk Type.u1;4062 .Int => lhs_ty,
4086 } else if (lhs_ty.isPtrLikeOptional(zcu)) {4063 .Bool => Type.u1,
4087 break :blk Type.usize;4064 .Pointer => Type.usize,
4065 .ErrorSet => Type.u16,
4066 .Optional => blk: {
4067 const payload_ty = lhs_ty.optionalChild(zcu);
4068 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4069 break :blk Type.u1;
4070 } else if (lhs_ty.isPtrLikeOptional(zcu)) {
4071 break :blk Type.usize;
4072 } else {
4073 return self.fail("TODO riscv cmp non-pointer optionals", .{});
4074 }
4075 },
4076 else => unreachable,
4077 };
4078
4079 const int_info = int_ty.intInfo(zcu);
4080 if (int_info.bits <= 64) {
4081 break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty);
4088 } else {4082 } else {
4089 return self.fail("TODO riscv cmp non-pointer optionals", .{});4083 return self.fail("TODO riscv cmp for ints > 64 bits", .{});
4090 }4084 }
4091 },4085 },
4092 .Float => return self.fail("TODO riscv cmp floats", .{}),4086 .Float => {
4093 else => unreachable,4087 const float_bits = lhs_ty.floatBits(self.target.*);
4094 };4088 if (float_bits > 32) {
4089 return self.fail("TODO: airCmp float > 32 bits", .{});
4090 }
40954091
4096 const int_info = int_ty.intInfo(zcu);4092 break :result try self.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty);
4097 if (int_info.bits <= 64) {4093 },
4098 break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty);4094 else => unreachable,
4099 } else {
4100 return self.fail("TODO riscv cmp for ints > 64 bits", .{});
4101 }4095 }
4102 };4096 };
41034097
...@@ -4716,25 +4710,13 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -4716,25 +4710,13 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
4716 const lhs_ty = Type.bool;4710 const lhs_ty = Type.bool;
4717 const rhs_ty = Type.bool;4711 const rhs_ty = Type.bool;
47184712
4719 const lhs_reg, const lhs_lock = blk: {4713 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
4720 if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) };
4721
4722 const lhs_reg, const lhs_lock = try self.allocReg();
4723 try self.genSetReg(lhs_ty, lhs_reg, lhs);
4724 break :blk .{ lhs_reg, lhs_lock };
4725 };
4726 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);4714 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
47274715
4728 const rhs_reg, const rhs_lock = blk: {4716 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
4729 if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) };
4730
4731 const rhs_reg, const rhs_lock = try self.allocReg();
4732 try self.genSetReg(rhs_ty, rhs_reg, rhs);
4733 break :blk .{ rhs_reg, rhs_lock };
4734 };
4735 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);4717 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
47364718
4737 const result_reg, const result_lock = try self.allocReg();4719 const result_reg, const result_lock = try self.allocReg(.int);
4738 defer self.register_manager.unlockReg(result_lock);4720 defer self.register_manager.unlockReg(result_lock);
47394721
4740 _ = try self.addInst(.{4722 _ = try self.addInst(.{
...@@ -4881,7 +4863,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -4881,7 +4863,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
4881 return self.finishAirResult(inst, result);4863 return self.finishAirResult(inst, result);
4882}4864}
48834865
4884/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.4866/// Sets the value of `dst_mcv` to the value of `src_mcv`.
4885fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {4867fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
4886 const zcu = self.bin_file.comp.module.?;4868 const zcu = self.bin_file.comp.module.?;
48874869
...@@ -4890,7 +4872,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {...@@ -4890,7 +4872,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
48904872
4891 if (!dst_mcv.isMutable()) {4873 if (!dst_mcv.isMutable()) {
4892 // panic so we can see the trace4874 // panic so we can see the trace
4893 return self.fail("tried to genCopy immutable: {s}", .{@tagName(dst_mcv)});4875 return std.debug.panic("tried to genCopy immutable: {s}", .{@tagName(dst_mcv)});
4894 }4876 }
48954877
4896 switch (dst_mcv) {4878 switch (dst_mcv) {
...@@ -4924,13 +4906,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {...@@ -4924,13 +4906,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
4924 ),4906 ),
4925 .memory => return self.fail("TODO: genCopy memory", .{}),4907 .memory => return self.fail("TODO: genCopy memory", .{}),
4926 .register_pair => |dst_regs| {4908 .register_pair => |dst_regs| {
4927 const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) {4909 const src_info: ?struct { addr_reg: Register, addr_lock: ?RegisterLock } = switch (src_mcv) {
4928 .register_pair, .memory, .indirect, .load_frame => null,4910 .register_pair, .memory, .indirect, .load_frame => null,
4929 .load_symbol => src: {4911 .load_symbol => src: {
4930 const src_addr_reg, const src_addr_lock = try self.allocReg();4912 const src_addr_reg, const src_addr_lock = try self.promoteReg(Type.usize, src_mcv.address());
4931 errdefer self.register_manager.unlockReg(src_addr_lock);4913 errdefer self.register_manager.unlockReg(src_addr_lock);
49324914
4933 try self.genSetReg(Type.usize, src_addr_reg, src_mcv.address());
4934 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };4915 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
4935 },4916 },
4936 .air_ref => |src_ref| return self.genCopy(4917 .air_ref => |src_ref| return self.genCopy(
...@@ -4940,7 +4921,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {...@@ -4940,7 +4921,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
4940 ),4921 ),
4941 else => unreachable,4922 else => unreachable,
4942 };4923 };
4943 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);4924
4925 defer if (src_info) |info| {
4926 if (info.addr_lock) |lock| {
4927 self.register_manager.unlockReg(lock);
4928 }
4929 };
49444930
4945 var part_disp: i32 = 0;4931 var part_disp: i32 = 0;
4946 for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| {4932 for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| {
...@@ -4966,7 +4952,7 @@ fn genInlineMemcpy(...@@ -4966,7 +4952,7 @@ fn genInlineMemcpy(
4966 src_ptr: MCValue,4952 src_ptr: MCValue,
4967 len: MCValue,4953 len: MCValue,
4968) !void {4954) !void {
4969 const regs = try self.register_manager.allocRegs(4, .{null} ** 4, tp);4955 const regs = try self.register_manager.allocRegs(4, .{null} ** 4, abi.Registers.Integer.temporary);
4970 const locks = self.register_manager.lockRegsAssumeUnused(4, regs);4956 const locks = self.register_manager.lockRegsAssumeUnused(4, regs);
4971 defer for (locks) |lock| self.register_manager.unlockReg(lock);4957 defer for (locks) |lock| self.register_manager.unlockReg(lock);
49724958
...@@ -5060,9 +5046,7 @@ fn genInlineMemcpy(...@@ -5060,9 +5046,7 @@ fn genInlineMemcpy(
5060 _ = try self.addInst(.{5046 _ = try self.addInst(.{
5061 .tag = .pseudo,5047 .tag = .pseudo,
5062 .ops = .pseudo_j,5048 .ops = .pseudo_j,
5063 .data = .{5049 .data = .{ .inst = first_inst },
5064 .inst = first_inst,
5065 },
5066 });5050 });
5067}5051}
50685052
...@@ -5072,7 +5056,7 @@ fn genInlineMemset(...@@ -5072,7 +5056,7 @@ fn genInlineMemset(
5072 src_value: MCValue,5056 src_value: MCValue,
5073 len: MCValue,5057 len: MCValue,
5074) !void {5058) !void {
5075 const regs = try self.register_manager.allocRegs(3, .{null} ** 3, tp);5059 const regs = try self.register_manager.allocRegs(3, .{null} ** 3, abi.Registers.Integer.temporary);
5076 const locks = self.register_manager.lockRegsAssumeUnused(3, regs);5060 const locks = self.register_manager.lockRegsAssumeUnused(3, regs);
5077 defer for (locks) |lock| self.register_manager.unlockReg(lock);5061 defer for (locks) |lock| self.register_manager.unlockReg(lock);
50785062
...@@ -5153,6 +5137,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5153,6 +5137,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
51535137
5154 if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size});5138 if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size});
51555139
5140 const dst_reg_class = reg.class();
5141
5156 switch (src_mcv) {5142 switch (src_mcv) {
5157 .dead => unreachable,5143 .dead => unreachable,
5158 .unreach, .none => return, // Nothing to do.5144 .unreach, .none => return, // Nothing to do.
...@@ -5163,6 +5149,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5163,6 +5149,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5163 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });5149 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
5164 },5150 },
5165 .immediate => |unsigned_x| {5151 .immediate => |unsigned_x| {
5152 assert(dst_reg_class == .int);
5153
5166 const x: i64 = @bitCast(unsigned_x);5154 const x: i64 = @bitCast(unsigned_x);
5167 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {5155 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {
5168 _ = try self.addInst(.{5156 _ = try self.addInst(.{
...@@ -5200,7 +5188,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5200,7 +5188,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5200 // TODO: use a more advanced myriad seq to do this without a reg.5188 // TODO: use a more advanced myriad seq to do this without a reg.
5201 // see: https://github.com/llvm/llvm-project/blob/081a66ffacfe85a37ff775addafcf3371e967328/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp#L2245189 // see: https://github.com/llvm/llvm-project/blob/081a66ffacfe85a37ff775addafcf3371e967328/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp#L224
52025190
5203 const temp, const temp_lock = try self.allocReg();5191 const temp, const temp_lock = try self.allocReg(.int);
5204 defer self.register_manager.unlockReg(temp_lock);5192 defer self.register_manager.unlockReg(temp_lock);
52055193
5206 const lo32: i32 = @truncate(x);5194 const lo32: i32 = @truncate(x);
...@@ -5236,6 +5224,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5236,6 +5224,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5236 if (src_reg.id() == reg.id())5224 if (src_reg.id() == reg.id())
5237 return;5225 return;
52385226
5227 const src_reg_class = src_reg.class();
5228
5229 if (src_reg_class == .float) {
5230 if (dst_reg_class == .float) {
5231 return self.fail("TODO: genSetReg float -> float", .{});
5232 }
5233
5234 assert(dst_reg_class == .int); // a bit of future proofing
5235
5236 // to move from float -> int, we use FMV.X.W
5237 return self.fail("TODO: genSetReg float -> int", .{});
5238 }
5239
5239 // mv reg, src_reg5240 // mv reg, src_reg
5240 _ = try self.addInst(.{5241 _ = try self.addInst(.{
5241 .tag = .pseudo,5242 .tag = .pseudo,
...@@ -5309,11 +5310,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5309,11 +5310,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5309 });5310 });
5310 },5311 },
5311 .indirect => |reg_off| {5312 .indirect => |reg_off| {
5313 const float_class = dst_reg_class == .float;
5314
5312 const load_tag: Mir.Inst.Tag = switch (abi_size) {5315 const load_tag: Mir.Inst.Tag = switch (abi_size) {
5313 1 => .lb,5316 1 => if (float_class)
5314 2 => .lh,5317 unreachable // Zig does not support 8-bit floats
5315 4 => .lw,5318 else
5316 8 => .ld,5319 .lb,
5320 2 => if (float_class)
5321 return self.fail("TODO: genSetReg indirect 16-bit float", .{})
5322 else
5323 .lh,
5324 4 => if (float_class) .flw else .lw,
5325 8 => if (float_class) .fld else .ld,
5317 else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}),5326 else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}),
5318 };5327 };
53195328
...@@ -5336,15 +5345,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5336,15 +5345,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5336 .tag = .pseudo,5345 .tag = .pseudo,
5337 .ops = .pseudo_load_symbol,5346 .ops = .pseudo_load_symbol,
5338 .data = .{ .payload = try self.addExtra(Mir.LoadSymbolPayload{5347 .data = .{ .payload = try self.addExtra(Mir.LoadSymbolPayload{
5339 .register = reg.id(),5348 .register = reg.encodeId(),
5340 .atom_index = atom_index,5349 .atom_index = atom_index,
5341 .sym_index = sym_off.sym,5350 .sym_index = sym_off.sym,
5342 }) },5351 }) },
5343 });5352 });
5344 },5353 },
5345 .load_symbol => {5354 .load_symbol => {
5346 try self.genSetReg(ty, reg, src_mcv.address());5355 const addr_reg, const addr_lock = try self.allocReg(.int);
5347 try self.genSetReg(ty, reg, .{ .indirect = .{ .reg = reg } });5356 defer self.register_manager.unlockReg(addr_lock);
5357
5358 try self.genSetReg(ty, addr_reg, src_mcv.address());
5359 try self.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } });
5348 },5360 },
5349 .air_ref => |ref| try self.genSetReg(ty, reg, try self.resolveInst(ref)),5361 .air_ref => |ref| try self.genSetReg(ty, reg, try self.resolveInst(ref)),
5350 else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),5362 else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),
...@@ -5386,7 +5398,8 @@ fn genSetMem(...@@ -5386,7 +5398,8 @@ fn genSetMem(
5386 => switch (abi_size) {5398 => switch (abi_size) {
5387 0 => {},5399 0 => {},
5388 1, 2, 4, 8 => {5400 1, 2, 4, 8 => {
5389 const src_reg = try self.copyToTmpRegister(ty, src_mcv);5401 // no matter what type, it should use an integer register
5402 const src_reg = try self.copyToTmpRegister(Type.usize, src_mcv);
5390 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);5403 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
5391 defer self.register_manager.unlockReg(src_lock);5404 defer self.register_manager.unlockReg(src_lock);
53925405
...@@ -5460,10 +5473,8 @@ fn genSetMem(...@@ -5460,10 +5473,8 @@ fn genSetMem(
5460 .immediate => {5473 .immediate => {
5461 // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with5474 // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with
5462 // a register allocation.5475 // a register allocation.
5463 const reg, const reg_lock = try self.allocReg();5476 const reg, const reg_lock = try self.promoteReg(ty, src_mcv);
5464 defer self.register_manager.unlockReg(reg_lock);5477 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
5465
5466 try self.genSetReg(ty, reg, src_mcv);
54675478
5468 return self.genSetMem(base, disp, ty, .{ .register = reg });5479 return self.genSetMem(base, disp, ty, .{ .register = reg });
5469 },5480 },
...@@ -5632,7 +5643,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {...@@ -5632,7 +5643,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
5632 assert(len != 0); // prevented by Sema5643 assert(len != 0); // prevented by Sema
5633 try self.store(dst_ptr, src_val, elem_ptr_ty, elem_ty);5644 try self.store(dst_ptr, src_val, elem_ptr_ty, elem_ty);
56345645
5635 const second_elem_ptr_reg, const second_elem_ptr_lock = try self.allocReg();5646 const second_elem_ptr_reg, const second_elem_ptr_lock = try self.allocReg(.int);
5636 defer self.register_manager.unlockReg(second_elem_ptr_lock);5647 defer self.register_manager.unlockReg(second_elem_ptr_lock);
56375648
5638 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };5649 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
...@@ -5677,7 +5688,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -5677,7 +5688,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
5677 const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);5688 const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);
5678 defer self.register_manager.unlockReg(err_lock);5689 defer self.register_manager.unlockReg(err_lock);
56795690
5680 const addr_reg, const addr_lock = try self.allocReg();5691 const addr_reg, const addr_lock = try self.allocReg(.int);
5681 defer self.register_manager.unlockReg(addr_lock);5692 defer self.register_manager.unlockReg(addr_lock);
56825693
5683 // this is now the base address of the error name table5694 // this is now the base address of the error name table
...@@ -5691,13 +5702,13 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -5691,13 +5702,13 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
5691 return self.fail("TODO: riscv non-elf", .{});5702 return self.fail("TODO: riscv non-elf", .{});
5692 }5703 }
56935704
5694 const start_reg, const start_lock = try self.allocReg();5705 const start_reg, const start_lock = try self.allocReg(.int);
5695 defer self.register_manager.unlockReg(start_lock);5706 defer self.register_manager.unlockReg(start_lock);
56965707
5697 const end_reg, const end_lock = try self.allocReg();5708 const end_reg, const end_lock = try self.allocReg(.int);
5698 defer self.register_manager.unlockReg(end_lock);5709 defer self.register_manager.unlockReg(end_lock);
56995710
5700 // const tmp_reg, const tmp_lock = try self.allocReg();5711 // const tmp_reg, const tmp_lock = try self.allocReg(.int);
5701 // defer self.register_manager.unlockReg(tmp_lock);5712 // defer self.register_manager.unlockReg(tmp_lock);
57025713
5703 // we move the base address forward by the following formula: base + (errno * 8)5714 // we move the base address forward by the following formula: base + (errno * 8)
...@@ -6025,16 +6036,16 @@ fn resolveCallingConventionValues(...@@ -6025,16 +6036,16 @@ fn resolveCallingConventionValues(
60256036
6026 for (classes) |class| switch (class) {6037 for (classes) |class| switch (class) {
6027 .integer => {6038 .integer => {
6028 const ret_int_reg = abi.function_ret_regs[ret_int_reg_i];6039 const ret_int_reg = abi.Registers.Integer.function_ret_regs[ret_int_reg_i];
6029 ret_int_reg_i += 1;6040 ret_int_reg_i += 1;
60306041
6031 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg });6042 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg });
6032 ret_tracking_i += 1;6043 ret_tracking_i += 1;
6033 },6044 },
6034 .memory => {6045 .memory => {
6035 const ret_int_reg = abi.function_ret_regs[ret_int_reg_i];6046 const ret_int_reg = abi.Registers.Integer.function_ret_regs[ret_int_reg_i];
6036 ret_int_reg_i += 1;6047 ret_int_reg_i += 1;
6037 const ret_indirect_reg = abi.function_arg_regs[param_int_reg_i];6048 const ret_indirect_reg = abi.Registers.Integer.function_arg_regs[param_int_reg_i];
6038 param_int_reg_i += 1;6049 param_int_reg_i += 1;
60396050
6040 ret_tracking[ret_tracking_i] = .{6051 ret_tracking[ret_tracking_i] = .{
...@@ -6069,7 +6080,7 @@ fn resolveCallingConventionValues(...@@ -6069,7 +6080,7 @@ fn resolveCallingConventionValues(
60696080
6070 for (classes) |class| switch (class) {6081 for (classes) |class| switch (class) {
6071 .integer => {6082 .integer => {
6072 const param_int_regs = abi.function_arg_regs;6083 const param_int_regs = abi.Registers.Integer.function_arg_regs;
6073 if (param_int_reg_i >= param_int_regs.len) break;6084 if (param_int_reg_i >= param_int_regs.len) break;
60746085
6075 const param_int_reg = param_int_regs[param_int_reg_i];6086 const param_int_reg = param_int_regs[param_int_reg_i];
...@@ -6079,7 +6090,7 @@ fn resolveCallingConventionValues(...@@ -6079,7 +6090,7 @@ fn resolveCallingConventionValues(
6079 arg_mcv_i += 1;6090 arg_mcv_i += 1;
6080 },6091 },
6081 .memory => {6092 .memory => {
6082 const param_int_regs = abi.function_arg_regs;6093 const param_int_regs = abi.Registers.Integer.function_arg_regs;
60836094
6084 const param_int_reg = param_int_regs[param_int_reg_i];6095 const param_int_reg = param_int_regs[param_int_reg_i];
6085 param_int_reg_i += 1;6096 param_int_reg_i += 1;
src/arch/riscv64/Encoding.zig+259-96
...@@ -1,7 +1,65 @@...@@ -1,7 +1,65 @@
1mnemonic: Mnemonic,1mnemonic: Mnemonic,
2data: Data,2data: Data,
33
4const OpCode = enum(u7) {
5 OP = 0b0110011,
6 OP_IMM = 0b0010011,
7 OP_32 = 0b0111011,
8
9 BRANCH = 0b1100011,
10 LOAD = 0b0000011,
11 STORE = 0b0100011,
12 SYSTEM = 0b1110011,
13
14 OP_FP = 0b1010011,
15 LOAD_FP = 0b0000111,
16 STORE_FP = 0b0100111,
17
18 JALR = 0b1100111,
19 AUIPC = 0b0010111,
20 LUI = 0b0110111,
21 JAL = 0b1101111,
22 NONE = 0b0000000,
23};
24
25const Fmt = enum(u2) {
26 /// 32-bit single-precision
27 S = 0b00,
28 /// 64-bit double-precision
29 D = 0b01,
30 _reserved = 0b10,
31 /// 128-bit quad-precision
32 Q = 0b11,
33};
34
35const Enc = struct {
36 opcode: OpCode,
37
38 data: union(enum) {
39 /// funct3 + funct7
40 ff: struct {
41 funct3: u3,
42 funct7: u7,
43 },
44 /// funct3 + offset
45 fo: struct {
46 funct3: u3,
47 offset: u12 = 0,
48 },
49 /// funct5 + rm + fmt
50 fmt: struct {
51 funct5: u5,
52 rm: u3,
53 fmt: Fmt,
54 },
55 /// U-type
56 none,
57 },
58};
59
4pub const Mnemonic = enum {60pub const Mnemonic = enum {
61 // base mnemonics
62
5 // I Type63 // I Type
6 ld,64 ld,
7 lw,65 lw,
...@@ -10,6 +68,7 @@ pub const Mnemonic = enum {...@@ -10,6 +68,7 @@ pub const Mnemonic = enum {
10 lhu,68 lhu,
11 lb,69 lb,
12 lbu,70 lbu,
71
13 sltiu,72 sltiu,
14 xori,73 xori,
15 andi,74 andi,
...@@ -52,56 +111,130 @@ pub const Mnemonic = enum {...@@ -52,56 +111,130 @@ pub const Mnemonic = enum {
52 ebreak,111 ebreak,
53 unimp,112 unimp,
54113
114 // float mnemonics
115 fadds,
116 faddd,
117
118 feqs,
119 feqd,
120
121 fld,
122 flw,
123
124 fsd,
125 fsw,
126
55 pub fn encoding(mnem: Mnemonic) Enc {127 pub fn encoding(mnem: Mnemonic) Enc {
56 return switch (mnem) {128 return switch (mnem) {
57 // zig fmt: off129 // zig fmt: off
58 .add => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000000 },130
59 .sltu => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 },131 // OP
60 .@"and" => .{ .opcode = 0b0110011, .funct3 = 0b111, .funct7 = 0b0000000 },132
61 .@"or" => .{ .opcode = 0b0110011, .funct3 = 0b110, .funct7 = 0b0000000 },133 .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
62 .sub => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0100000 }, 134 .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
63135
64 .ld => .{ .opcode = 0b0000011, .funct3 = 0b011, .funct7 = null },136 .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
65 .lw => .{ .opcode = 0b0000011, .funct3 = 0b010, .funct7 = null },137 .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
66 .lwu => .{ .opcode = 0b0000011, .funct3 = 0b110, .funct7 = null },138 .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
67 .lh => .{ .opcode = 0b0000011, .funct3 = 0b001, .funct7 = null },139
68 .lhu => .{ .opcode = 0b0000011, .funct3 = 0b101, .funct7 = null },140 .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
69 .lb => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null },141 .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
70 .lbu => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null },142
71143 .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
72 .sltiu => .{ .opcode = 0b0010011, .funct3 = 0b011, .funct7 = null },144
73145
74 .addi => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null },146 // OP_IMM
75 .andi => .{ .opcode = 0b0010011, .funct3 = 0b111, .funct7 = null },147
76 .xori => .{ .opcode = 0b0010011, .funct3 = 0b100, .funct7 = null },148 .addi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
77 .jalr => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null },149 .andi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b111 } } },
78 .slli => .{ .opcode = 0b0010011, .funct3 = 0b001, .funct7 = null },150 .xori => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b100 } } },
79 .srli => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null },
80 .srai => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null, .offset = 1 << 10 },
81 151
82 .sllw => .{ .opcode = 0b0111011, .funct3 = 0b001, .funct7 = 0b0000000 },152 .sltiu => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b011 } } },
153
154 .slli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b001 } } },
155 .srli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101 } } },
156 .srai => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101, .offset = 1 << 10 } } },
157
158
159 // OP_FP
160
161 .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
162 .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
163
164 .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
165 .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
166
167 // LOAD
168
169 .ld => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b011 } } },
170 .lw => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b010 } } },
171 .lwu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b110 } } },
172 .lh => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b001 } } },
173 .lhu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b101 } } },
174 .lb => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b000 } } },
175 .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } },
176
177
178 // STORE
179
180 .sd => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b011 } } },
181 .sw => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b010 } } },
182 .sh => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b001 } } },
183 .sb => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
184
185
186 // LOAD_FP
187
188 .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
189 .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
190
191 // STORE_FP
192
193 .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
194 .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
195
196
197 // JALR
198
199 .jalr => .{ .opcode = .JALR, .data = .{ .fo = .{ .funct3 = 0b000 } } },
200
201
202 // OP_32
203
204 .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
83205
84 .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },
85 .auipc => .{ .opcode = 0b0010111, .funct3 = null, .funct7 = null },
86206
87 .sd => .{ .opcode = 0b0100011, .funct3 = 0b011, .funct7 = null },207 // LUI
88 .sw => .{ .opcode = 0b0100011, .funct3 = 0b010, .funct7 = null },
89 .sh => .{ .opcode = 0b0100011, .funct3 = 0b001, .funct7 = null },
90 .sb => .{ .opcode = 0b0100011, .funct3 = 0b000, .funct7 = null },
91208
92 .jal => .{ .opcode = 0b1101111, .funct3 = null, .funct7 = null },209 .lui => .{ .opcode = .LUI, .data = .{ .none = {} } },
93210
94 .beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null },
95211
96 .slt => .{ .opcode = 0b0110011, .funct3 = 0b010, .funct7 = 0b0000000 },212 // AUIPC
97213
98 .xor => .{ .opcode = 0b0110011, .funct3 = 0b100, .funct7 = 0b0000000 },214 .auipc => .{ .opcode = .AUIPC, .data = .{ .none = {} } },
215
216
217 // JAL
218
219 .jal => .{ .opcode = .JAL, .data = .{ .none = {} } },
220
221
222 // BRANCH
223
224 .beq => .{ .opcode = .BRANCH, .data = .{ .fo = .{ .funct3 = 0b000 } } },
225
226
227 // SYSTEM
228
229 .ecall => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
230 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
231
232
233 // NONE
234
235 .unimp => .{ .opcode = .NONE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
99236
100 .mul => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000001 },
101237
102 .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
103 .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
104 .unimp => .{ .opcode = 0b0000000, .funct3 = 0b000, .funct7 = null },
105 // zig fmt: on238 // zig fmt: on
106 };239 };
107 }240 }
...@@ -109,6 +242,7 @@ pub const Mnemonic = enum {...@@ -109,6 +242,7 @@ pub const Mnemonic = enum {
109242
110pub const InstEnc = enum {243pub const InstEnc = enum {
111 R,244 R,
245 R4,
112 I,246 I,
113 S,247 S,
114 B,248 B,
...@@ -121,13 +255,6 @@ pub const InstEnc = enum {...@@ -121,13 +255,6 @@ pub const InstEnc = enum {
121 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {255 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {
122 return switch (mnem) {256 return switch (mnem) {
123 .addi,257 .addi,
124 .ld,
125 .lw,
126 .lwu,
127 .lh,
128 .lhu,
129 .lb,
130 .lbu,
131 .jalr,258 .jalr,
132 .sltiu,259 .sltiu,
133 .xori,260 .xori,
...@@ -135,6 +262,17 @@ pub const InstEnc = enum {...@@ -135,6 +262,17 @@ pub const InstEnc = enum {
135 .slli,262 .slli,
136 .srli,263 .srli,
137 .srai,264 .srai,
265
266 .ld,
267 .lw,
268 .lwu,
269 .lh,
270 .lhu,
271 .lb,
272 .lbu,
273
274 .flw,
275 .fld,
138 => .I,276 => .I,
139277
140 .lui,278 .lui,
...@@ -145,6 +283,9 @@ pub const InstEnc = enum {...@@ -145,6 +283,9 @@ pub const InstEnc = enum {
145 .sw,283 .sw,
146 .sh,284 .sh,
147 .sb,285 .sb,
286
287 .fsd,
288 .fsw,
148 => .S,289 => .S,
149290
150 .jal,291 .jal,
...@@ -162,6 +303,11 @@ pub const InstEnc = enum {...@@ -162,6 +303,11 @@ pub const InstEnc = enum {
162 .sub,303 .sub,
163 .@"and",304 .@"and",
164 .@"or",305 .@"or",
306
307 .fadds,
308 .faddd,
309 .feqs,
310 .feqd,
165 => .R,311 => .R,
166312
167 .ecall,313 .ecall,
...@@ -171,16 +317,17 @@ pub const InstEnc = enum {...@@ -171,16 +317,17 @@ pub const InstEnc = enum {
171 };317 };
172 }318 }
173319
174 pub fn opsList(enc: InstEnc) [3]std.meta.FieldEnum(Operand) {320 pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) {
175 return switch (enc) {321 return switch (enc) {
176 // zig fmt: off322 // zig fmt: off
177 .R => .{ .reg, .reg, .reg, },323 .R => .{ .reg, .reg, .reg, .none },
178 .I => .{ .reg, .reg, .imm, },324 .R4 => .{ .reg, .reg, .reg, .reg },
179 .S => .{ .reg, .reg, .imm, },325 .I => .{ .reg, .reg, .imm, .none },
180 .B => .{ .reg, .reg, .imm, },326 .S => .{ .reg, .reg, .imm, .none },
181 .U => .{ .reg, .imm, .none, },327 .B => .{ .reg, .reg, .imm, .none },
182 .J => .{ .reg, .imm, .none, },328 .U => .{ .reg, .imm, .none, .none },
183 .system => .{ .none, .none, .none, },329 .J => .{ .reg, .imm, .none, .none },
330 .system => .{ .none, .none, .none, .none },
184 // zig fmt: on331 // zig fmt: on
185 };332 };
186 }333 }
...@@ -195,6 +342,15 @@ pub const Data = union(InstEnc) {...@@ -195,6 +342,15 @@ pub const Data = union(InstEnc) {
195 rs2: u5,342 rs2: u5,
196 funct7: u7,343 funct7: u7,
197 },344 },
345 R4: packed struct {
346 opcode: u7,
347 rd: u5,
348 funct3: u3,
349 rs1: u5,
350 rs2: u5,
351 funct2: u2,
352 rs3: u5,
353 },
198 I: packed struct {354 I: packed struct {
199 opcode: u7,355 opcode: u7,
200 rd: u5,356 rd: u5,
...@@ -237,19 +393,21 @@ pub const Data = union(InstEnc) {...@@ -237,19 +393,21 @@ pub const Data = union(InstEnc) {
237393
238 pub fn toU32(self: Data) u32 {394 pub fn toU32(self: Data) u32 {
239 return switch (self) {395 return switch (self) {
240 .R => |v| @as(u32, @bitCast(v)),396 // zig fmt: off
241 .I => |v| @as(u32, @bitCast(v)),397 .R => |v| @bitCast(v),
242 .S => |v| @as(u32, @bitCast(v)),398 .R4 => |v| @bitCast(v),
243 .B => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.imm11)) << 7) + (@as(u32, @intCast(v.imm1_4)) << 8) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.rs2)) << 20) + (@as(u32, @intCast(v.imm5_10)) << 25) + (@as(u32, @intCast(v.imm12)) << 31),399 .I => |v| @bitCast(v),
244 .U => |v| @as(u32, @bitCast(v)),400 .S => |v| @bitCast(v),
245 .J => |v| @as(u32, @bitCast(v)),401 .B => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.imm11)) << 7) + (@as(u32, @intCast(v.imm1_4)) << 8) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.rs2)) << 20) + (@as(u32, @intCast(v.imm5_10)) << 25) + (@as(u32, @intCast(v.imm12)) << 31),
402 .U => |v| @bitCast(v),
403 .J => |v| @bitCast(v),
246 .system => unreachable,404 .system => unreachable,
405 // zig fmt: on
247 };406 };
248 }407 }
249408
250 pub fn construct(mnem: Mnemonic, ops: []const Operand) !Data {409 pub fn construct(mnem: Mnemonic, ops: []const Operand) !Data {
251 const inst_enc = InstEnc.fromMnemonic(mnem);410 const inst_enc = InstEnc.fromMnemonic(mnem);
252
253 const enc = mnem.encoding();411 const enc = mnem.encoding();
254412
255 // special mnemonics413 // special mnemonics
...@@ -261,8 +419,8 @@ pub const Data = union(InstEnc) {...@@ -261,8 +419,8 @@ pub const Data = union(InstEnc) {
261 assert(ops.len == 0);419 assert(ops.len == 0);
262 return .{420 return .{
263 .I = .{421 .I = .{
264 .rd = Register.zero.id(),422 .rd = Register.zero.encodeId(),
265 .rs1 = Register.zero.id(),423 .rs1 = Register.zero.encodeId(),
266 .imm0_11 = switch (mnem) {424 .imm0_11 = switch (mnem) {
267 .ecall => 0x000,425 .ecall => 0x000,
268 .ebreak => 0x001,426 .ebreak => 0x001,
...@@ -270,8 +428,8 @@ pub const Data = union(InstEnc) {...@@ -270,8 +428,8 @@ pub const Data = union(InstEnc) {
270 else => unreachable,428 else => unreachable,
271 },429 },
272430
273 .opcode = enc.opcode,431 .opcode = @intFromEnum(enc.opcode),
274 .funct3 = enc.funct3.?,432 .funct3 = enc.data.fo.funct3,
275 },433 },
276 };434 };
277 },435 },
...@@ -282,14 +440,26 @@ pub const Data = union(InstEnc) {...@@ -282,14 +440,26 @@ pub const Data = union(InstEnc) {
282 .R => {440 .R => {
283 assert(ops.len == 3);441 assert(ops.len == 3);
284 return .{442 return .{
285 .R = .{443 .R = switch (enc.data) {
286 .rd = ops[0].reg.id(),444 .ff => |ff| .{
287 .rs1 = ops[1].reg.id(),445 .rd = ops[0].reg.encodeId(),
288 .rs2 = ops[2].reg.id(),446 .rs1 = ops[1].reg.encodeId(),
289447 .rs2 = ops[2].reg.encodeId(),
290 .opcode = enc.opcode,448
291 .funct3 = enc.funct3.?,449 .opcode = @intFromEnum(enc.opcode),
292 .funct7 = enc.funct7.?,450 .funct3 = ff.funct3,
451 .funct7 = ff.funct7,
452 },
453 .fmt => |fmt| .{
454 .rd = ops[0].reg.encodeId(),
455 .rs1 = ops[1].reg.encodeId(),
456 .rs2 = ops[2].reg.encodeId(),
457
458 .opcode = @intFromEnum(enc.opcode),
459 .funct3 = fmt.rm,
460 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
461 },
462 else => unreachable,
293 },463 },
294 };464 };
295 },465 },
...@@ -300,12 +470,12 @@ pub const Data = union(InstEnc) {...@@ -300,12 +470,12 @@ pub const Data = union(InstEnc) {
300 return .{470 return .{
301 .S = .{471 .S = .{
302 .imm0_4 = @truncate(umm),472 .imm0_4 = @truncate(umm),
303 .rs1 = ops[0].reg.id(),473 .rs1 = ops[0].reg.encodeId(),
304 .rs2 = ops[1].reg.id(),474 .rs2 = ops[1].reg.encodeId(),
305 .imm5_11 = @truncate(umm >> 5),475 .imm5_11 = @truncate(umm >> 5),
306476
307 .opcode = enc.opcode,477 .opcode = @intFromEnum(enc.opcode),
308 .funct3 = enc.funct3.?,478 .funct3 = enc.data.fo.funct3,
309 },479 },
310 };480 };
311 },481 },
...@@ -313,12 +483,12 @@ pub const Data = union(InstEnc) {...@@ -313,12 +483,12 @@ pub const Data = union(InstEnc) {
313 assert(ops.len == 3);483 assert(ops.len == 3);
314 return .{484 return .{
315 .I = .{485 .I = .{
316 .rd = ops[0].reg.id(),486 .rd = ops[0].reg.encodeId(),
317 .rs1 = ops[1].reg.id(),487 .rs1 = ops[1].reg.encodeId(),
318 .imm0_11 = ops[2].imm.asBits(u12) + enc.offset,488 .imm0_11 = ops[2].imm.asBits(u12) + enc.data.fo.offset,
319489
320 .opcode = enc.opcode,490 .opcode = @intFromEnum(enc.opcode),
321 .funct3 = enc.funct3.?,491 .funct3 = enc.data.fo.funct3,
322 },492 },
323 };493 };
324 },494 },
...@@ -326,10 +496,10 @@ pub const Data = union(InstEnc) {...@@ -326,10 +496,10 @@ pub const Data = union(InstEnc) {
326 assert(ops.len == 2);496 assert(ops.len == 2);
327 return .{497 return .{
328 .U = .{498 .U = .{
329 .rd = ops[0].reg.id(),499 .rd = ops[0].reg.encodeId(),
330 .imm12_31 = ops[1].imm.asBits(u20),500 .imm12_31 = ops[1].imm.asBits(u20),
331501
332 .opcode = enc.opcode,502 .opcode = @intFromEnum(enc.opcode),
333 },503 },
334 };504 };
335 },505 },
...@@ -341,13 +511,13 @@ pub const Data = union(InstEnc) {...@@ -341,13 +511,13 @@ pub const Data = union(InstEnc) {
341511
342 return .{512 return .{
343 .J = .{513 .J = .{
344 .rd = ops[0].reg.id(),514 .rd = ops[0].reg.encodeId(),
345 .imm1_10 = @truncate(umm >> 1),515 .imm1_10 = @truncate(umm >> 1),
346 .imm11 = @truncate(umm >> 11),516 .imm11 = @truncate(umm >> 11),
347 .imm12_19 = @truncate(umm >> 12),517 .imm12_19 = @truncate(umm >> 12),
348 .imm20 = @truncate(umm >> 20),518 .imm20 = @truncate(umm >> 20),
349519
350 .opcode = enc.opcode,520 .opcode = @intFromEnum(enc.opcode),
351 },521 },
352 };522 };
353 },523 },
...@@ -359,15 +529,15 @@ pub const Data = union(InstEnc) {...@@ -359,15 +529,15 @@ pub const Data = union(InstEnc) {
359529
360 return .{530 return .{
361 .B = .{531 .B = .{
362 .rs1 = ops[0].reg.id(),532 .rs1 = ops[0].reg.encodeId(),
363 .rs2 = ops[1].reg.id(),533 .rs2 = ops[1].reg.encodeId(),
364 .imm1_4 = @truncate(umm >> 1),534 .imm1_4 = @truncate(umm >> 1),
365 .imm5_10 = @truncate(umm >> 5),535 .imm5_10 = @truncate(umm >> 5),
366 .imm11 = @truncate(umm >> 11),536 .imm11 = @truncate(umm >> 11),
367 .imm12 = @truncate(umm >> 12),537 .imm12 = @truncate(umm >> 12),
368538
369 .opcode = enc.opcode,539 .opcode = @intFromEnum(enc.opcode),
370 .funct3 = enc.funct3.?,540 .funct3 = enc.data.fo.funct3,
371 },541 },
372 };542 };
373 },543 },
...@@ -386,13 +556,6 @@ pub fn findByMnemonic(mnem: Mnemonic, ops: []const Operand) !?Encoding {...@@ -386,13 +556,6 @@ pub fn findByMnemonic(mnem: Mnemonic, ops: []const Operand) !?Encoding {
386 };556 };
387}557}
388558
389const Enc = struct {
390 opcode: u7,
391 funct3: ?u3,
392 funct7: ?u7,
393 offset: u12 = 0,
394};
395
396fn verifyOps(mnem: Mnemonic, ops: []const Operand) bool {559fn verifyOps(mnem: Mnemonic, ops: []const Operand) bool {
397 const inst_enc = InstEnc.fromMnemonic(mnem);560 const inst_enc = InstEnc.fromMnemonic(mnem);
398 const list = std.mem.sliceTo(&inst_enc.opsList(), .none);561 const list = std.mem.sliceTo(&inst_enc.opsList(), .none);
src/arch/riscv64/Lower.zig+45-15
...@@ -14,7 +14,7 @@ result_relocs_len: u8 = undefined,...@@ -14,7 +14,7 @@ result_relocs_len: u8 = undefined,
14result_insts: [14result_insts: [
15 @max(15 @max(
16 1, // non-pseudo instruction16 1, // non-pseudo instruction
17 abi.callee_preserved_regs.len, // spill / restore regs,17 abi.Registers.all_preserved.len, // spill / restore regs,
18 )18 )
19]Instruction = undefined,19]Instruction = undefined,
20result_relocs: [1]Reloc = undefined,20result_relocs: [1]Reloc = undefined,
...@@ -71,11 +71,24 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -71,11 +71,24 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
7171
72 switch (inst.ops) {72 switch (inst.ops) {
73 .pseudo_load_rm => {73 .pseudo_load_rm => {
74 const tag: Encoding.Mnemonic = switch (rm.m.mod.size()) {74 const dest_reg = rm.r;
75 .byte => .lb,75 const dest_reg_class = dest_reg.class();
76 .hword => .lh,76 const float = dest_reg_class == .float;
77 .word => .lw,77
78 .dword => .ld,78 const src_size = rm.m.mod.size();
79
80 const tag: Encoding.Mnemonic = if (!float)
81 switch (src_size) {
82 .byte => .lb,
83 .hword => .lh,
84 .word => .lw,
85 .dword => .ld,
86 }
87 else switch (src_size) {
88 .byte => unreachable, // Zig does not support 8-bit floats
89 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
90 .word => .flw,
91 .dword => .fld,
79 };92 };
8093
81 try lower.emit(tag, &.{94 try lower.emit(tag, &.{
...@@ -85,11 +98,25 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -85,11 +98,25 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
85 });98 });
86 },99 },
87 .pseudo_store_rm => {100 .pseudo_store_rm => {
88 const tag: Encoding.Mnemonic = switch (rm.m.mod.size()) {101 const src_reg = rm.r;
89 .byte => .sb,102 const src_reg_class = src_reg.class();
90 .hword => .sh,103 const float = src_reg_class == .float;
91 .word => .sw,104
92 .dword => .sd,105 // TODO: do we actually need this? are all stores not usize?
106 const dest_size = rm.m.mod.size();
107
108 const tag: Encoding.Mnemonic = if (!float)
109 switch (dest_size) {
110 .byte => .sb,
111 .hword => .sh,
112 .word => .sw,
113 .dword => .sd,
114 }
115 else switch (dest_size) {
116 .byte => unreachable, // Zig does not support 8-bit floats
117 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
118 .word => .fsw,
119 .dword => .fsd,
93 };120 };
94121
95 try lower.emit(tag, &.{122 try lower.emit(tag, &.{
...@@ -336,16 +363,19 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register...@@ -336,16 +363,19 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
336 var reg_i: u31 = 0;363 var reg_i: u31 = 0;
337 while (it.next()) |i| {364 while (it.next()) |i| {
338 const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame));365 const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame));
366 const reg = abi.Registers.all_preserved[i];
367 const reg_class = reg.class();
368 const is_float_reg = reg_class == .float;
339369
340 if (spilling) {370 if (spilling) {
341 try lower.emit(.sd, &.{371 try lower.emit(if (is_float_reg) .fsd else .sd, &.{
342 .{ .reg = frame.base },372 .{ .reg = frame.base },
343 .{ .reg = abi.callee_preserved_regs[i] },373 .{ .reg = abi.Registers.all_preserved[i] },
344 .{ .imm = Immediate.s(frame.disp + reg_i) },374 .{ .imm = Immediate.s(frame.disp + reg_i) },
345 });375 });
346 } else {376 } else {
347 try lower.emit(.ld, &.{377 try lower.emit(if (is_float_reg) .fld else .ld, &.{
348 .{ .reg = abi.callee_preserved_regs[i] },378 .{ .reg = abi.Registers.all_preserved[i] },
349 .{ .reg = frame.base },379 .{ .reg = frame.base },
350 .{ .imm = Immediate.s(frame.disp + reg_i) },380 .{ .imm = Immediate.s(frame.disp + reg_i) },
351 });381 });
src/arch/riscv64/Mir.zig+20-39
...@@ -20,87 +20,68 @@ pub const Inst = struct {...@@ -20,87 +20,68 @@ pub const Inst = struct {
20 pub const Index = u32;20 pub const Index = u32;
2121
22 pub const Tag = enum(u16) {22 pub const Tag = enum(u16) {
23 /// Add immediate. Uses i_type payload.
24 addi,
2523
26 /// Add immediate and produce a sign-extended result.24 // base extension
27 ///25 addi,
28 /// Uses i-type payload.
29 addiw,26 addiw,
3027
31 jalr,28 jalr,
32 lui,29 lui,
33 mv,
3430
35 @"and",31 @"and",
32 andi,
33
36 xor,34 xor,
35 @"or",
3736
38 ebreak,37 ebreak,
39 ecall,38 ecall,
40 unimp,39 unimp,
4140
42 /// OR instruction. Uses r_type payload.
43 @"or",
44
45 /// Addition
46 add,41 add,
47 /// Subtraction
48 sub,42 sub,
49 /// Multiply, uses r_type. Needs the M extension.
50 mul,
51
52 /// Absolute Value, uses i_type payload.
53 abs,
5443
55 sltu,44 sltu,
56 slt,45 slt,
5746
58 /// Immediate Logical Right Shift, uses i_type payload
59 srli,47 srli,
60 /// Immediate Logical Left Shift, uses i_type payload
61 slli,48 slli,
62 /// Immediate Arithmetic Right Shift, uses i_type payload.
63 srai,49 srai,
64 /// Register Logical Left Shift, uses r_type payload
65 sllw,50 sllw,
66 /// Register Logical Right Shit, uses r_type payload
67 srlw,51 srlw,
6852
69 /// Jumps, but stores the address of the instruction following the
70 /// jump in `rd`.
71 ///
72 /// Uses j_type payload.
73 jal,53 jal,
7454
75 /// Immediate AND, uses i_type payload
76 andi,
77
78 /// Branch if equal, Uses b_type
79 beq,55 beq,
80 /// Branch if not equal, Uses b_type
81 bne,56 bne,
8257
83 /// Generates a NO-OP, uses nop payload
84 nop,58 nop,
8559
86 /// Load double (64 bits), uses i_type payload
87 ld,60 ld,
88 /// Load word (32 bits), uses i_type payload
89 lw,61 lw,
90 /// Load half (16 bits), uses i_type payload
91 lh,62 lh,
92 /// Load byte (8 bits), uses i_type payload
93 lb,63 lb,
9464
95 /// Store double (64 bits), uses s_type payload
96 sd,65 sd,
97 /// Store word (32 bits), uses s_type payload
98 sw,66 sw,
99 /// Store half (16 bits), uses s_type payload
100 sh,67 sh,
101 /// Store byte (8 bits), uses s_type payload
102 sb,68 sb,
10369
70 // M extension
71 mul,
72
73 // F extension (32-bit float)
74 fadds,
75 flw,
76 fsw,
77 feqs,
78
79 // D extension (64-bit float)
80 faddd,
81 fld,
82 fsd,
83 feqd,
84
104 /// A pseudo-instruction. Used for anything that isn't 1:1 with an85 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
105 /// assembly instruction.86 /// assembly instruction.
106 pseudo,87 pseudo,
src/arch/riscv64/abi.zig+66-47
...@@ -238,62 +238,81 @@ fn classifyStruct(...@@ -238,62 +238,81 @@ fn classifyStruct(
238 }238 }
239}239}
240240
241pub const callee_preserved_regs = [_]Register{241const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs;
242 // .s0 is ommited to be used as a frame pointer242pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
243 .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
244};
245243
246pub const function_arg_regs = [_]Register{244// Register classes
247 .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,245const RegisterBitSet = RegisterManager.RegisterBitSet;
248};
249246
250pub const function_ret_regs = [_]Register{247pub const RegisterClass = enum {
251 .a0, .a1,248 int,
249 float,
252};250};
253251
254pub const temporary_regs = [_]Register{252pub const Registers = struct {
255 .t0, .t1, .t2, .t3, .t4, .t5, .t6,253 pub const all_preserved = Integer.callee_preserved_regs ++ Float.callee_preserved_regs;
256};
257254
258const allocatable_registers = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;255 pub const Integer = struct {
259pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);256 // zig fmt: off
257 pub const general_purpose = initRegBitSet(0, callee_preserved_regs.len);
258 pub const function_arg = initRegBitSet(callee_preserved_regs.len, function_arg_regs.len);
259 pub const function_ret = initRegBitSet(callee_preserved_regs.len, function_ret_regs.len);
260 pub const temporary = initRegBitSet(callee_preserved_regs.len + function_arg_regs.len, temporary_regs.len);
261 // zig fmt: on
260262
261// Register classes263 pub const callee_preserved_regs = [_]Register{
262const RegisterBitSet = RegisterManager.RegisterBitSet;264 // .s0 is omitted to be used as the frame pointer register
263pub const RegisterClass = struct {265 .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
264 pub const gp: RegisterBitSet = blk: {266 };
265 var set = RegisterBitSet.initEmpty();
266 set.setRangeValue(.{
267 .start = 0,
268 .end = callee_preserved_regs.len,
269 }, true);
270 break :blk set;
271 };
272267
273 pub const fa: RegisterBitSet = blk: {268 pub const function_arg_regs = [_]Register{
274 var set = RegisterBitSet.initEmpty();269 .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,
275 set.setRangeValue(.{270 };
276 .start = callee_preserved_regs.len,271
277 .end = callee_preserved_regs.len + function_arg_regs.len,272 pub const function_ret_regs = [_]Register{
278 }, true);273 .a0, .a1,
279 break :blk set;274 };
280 };275
276 pub const temporary_regs = [_]Register{
277 .t0, .t1, .t2, .t3, .t4, .t5, .t6,
278 };
281279
282 pub const fr: RegisterBitSet = blk: {280 pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
283 var set = RegisterBitSet.initEmpty();
284 set.setRangeValue(.{
285 .start = callee_preserved_regs.len,
286 .end = callee_preserved_regs.len + function_ret_regs.len,
287 }, true);
288 break :blk set;
289 };281 };
290282
291 pub const tp: RegisterBitSet = blk: {283 pub const Float = struct {
292 var set = RegisterBitSet.initEmpty();284 // zig fmt: off
293 set.setRangeValue(.{285 pub const general_purpose = initRegBitSet(Integer.all_regs.len, callee_preserved_regs.len);
294 .start = callee_preserved_regs.len + function_arg_regs.len,286 pub const function_arg = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len, function_arg_regs.len);
295 .end = callee_preserved_regs.len + function_arg_regs.len + temporary_regs.len,287 pub const function_ret = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len, function_ret_regs.len);
296 }, true);288 pub const temporary = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len + function_arg_regs.len, temporary_regs.len);
297 break :blk set;289 // zig fmt: on
290
291 pub const callee_preserved_regs = [_]Register{
292 .fs0, .fs1, .fs2, .fs3, .fs4, .fs5, .fs6, .fs7, .fs8, .fs9, .fs10, .fs11,
293 };
294
295 pub const function_arg_regs = [_]Register{
296 .fa0, .fa1, .fa2, .fa3, .fa4, .fa5, .fa6, .fa7,
297 };
298
299 pub const function_ret_regs = [_]Register{
300 .fa0, .fa1,
301 };
302
303 pub const temporary_regs = [_]Register{
304 .ft0, .ft1, .ft2, .ft3, .ft4, .ft5, .ft6, .ft7, .ft8, .ft9, .ft10, .ft11,
305 };
306
307 pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
298 };308 };
299};309};
310
311fn initRegBitSet(start: usize, length: usize) RegisterBitSet {
312 var set = RegisterBitSet.initEmpty();
313 set.setRangeValue(.{
314 .start = start,
315 .end = start + length,
316 }, true);
317 return set;
318}
src/arch/riscv64/bits.zig+58-7
...@@ -4,6 +4,7 @@ const assert = std.debug.assert;...@@ -4,6 +4,7 @@ const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const Encoding = @import("Encoding.zig");5const Encoding = @import("Encoding.zig");
6const Mir = @import("Mir.zig");6const Mir = @import("Mir.zig");
7const abi = @import("abi.zig");
78
8pub const Memory = struct {9pub const Memory = struct {
9 base: Base,10 base: Base,
...@@ -154,10 +155,10 @@ pub const Immediate = union(enum) {...@@ -154,10 +155,10 @@ pub const Immediate = union(enum) {
154 }155 }
155};156};
156157
157pub const Register = enum(u6) {158pub const Register = enum(u8) {
158 // zig fmt: off159 // zig fmt: off
159160
160 // general purpose registers161 // base extension registers
161162
162 zero, // zero163 zero, // zero
163 ra, // return address. caller saved164 ra, // return address. caller saved
...@@ -178,12 +179,48 @@ pub const Register = enum(u6) {...@@ -178,12 +179,48 @@ pub const Register = enum(u6) {
178 x24, x25, x26, x27, x28, x29, x30, x31,179 x24, x25, x26, x27, x28, x29, x30, x31,
179180
180181
182 // F extension registers
183
184 ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7, // float temporaries. caller saved.
185 fs0, fs1, // float saved. callee saved.
186 fa0, fa1, // float arg/ret. caller saved.
187 fa2, fa3, fa4, fa5, fa6, fa7, // float arg. called saved.
188 fs2, fs3, fs4, fs5, fs6, fs7, fs8, fs9, fs10, fs11, // float saved. callee saved.
189 ft8, ft9, ft10, ft11, // foat temporaries. calller saved.
190
191 // this register is accessed only through API instructions instead of directly
192 // fcsr,
193
194 f0, f1, f2, f3, f4, f5, f6, f7,
195 f8, f9, f10, f11, f12, f13, f14, f15,
196 f16, f17, f18, f19, f20, f21, f22, f23,
197 f24, f25, f26, f27, f28, f29, f30, f31,
198
181 // zig fmt: on199 // zig fmt: on
182200
183 /// Returns the unique 5-bit ID of this register which is used in201 /// in RISC-V registers are stored as 5 bit IDs and a register can have
184 /// the machine code202 /// two names. Example being `zero` and `x0` are the same register and have the
185 pub fn id(self: Register) u5 {203 /// same ID, but are two different entries in the enum. We store floating point
186 return @as(u5, @truncate(@intFromEnum(self)));204 /// registers in the same enum. RISC-V uses the same IDs for `f0` and `x0` by
205 /// infering which register is being talked about given the instruction it's in.
206 ///
207 /// The goal of this function is to return the same ID for `zero` and `x0` but two
208 /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers
209 /// and is repeated twice, once for the named version, once for the number version.
210 pub fn id(reg: Register) u7 {
211 const base = switch (@intFromEnum(reg)) {
212 // zig fmt: off
213 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero),
214 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0),
215 else => unreachable,
216 // zig fmt: on
217 };
218
219 return @intCast(base + reg.encodeId());
220 }
221
222 pub fn encodeId(reg: Register) u5 {
223 return @truncate(@intFromEnum(reg));
187 }224 }
188225
189 pub fn dwarfLocOp(reg: Register) u8 {226 pub fn dwarfLocOp(reg: Register) u8 {
...@@ -192,7 +229,21 @@ pub const Register = enum(u6) {...@@ -192,7 +229,21 @@ pub const Register = enum(u6) {
192229
193 pub fn bitSize(reg: Register) u32 {230 pub fn bitSize(reg: Register) u32 {
194 return switch (@intFromEnum(reg)) {231 return switch (@intFromEnum(reg)) {
195 @intFromEnum(Register.zero)...@intFromEnum(Register.x31) => 64,232 // zig fmt: off
233 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,
234 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => 32,
235 else => unreachable,
236 // zig fmt: on
237 };
238 }
239
240 pub fn class(reg: Register) abi.RegisterClass {
241 return switch (@intFromEnum(reg)) {
242 // zig fmt: off
243 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int,
244 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float,
245 else => unreachable,
246 // zig fmt: on
196 };247 };
197 }248 }
198};249};
test/behavior/byteswap.zig+1
...@@ -100,6 +100,7 @@ test "@byteSwap vectors u8" {...@@ -100,6 +100,7 @@ test "@byteSwap vectors u8" {
100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;102 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103104
104 try comptime vector8();105 try comptime vector8();
105 try vector8();106 try vector8();
test/behavior/fn.zig-2
...@@ -349,7 +349,6 @@ test "function call with anon list literal" {...@@ -349,7 +349,6 @@ test "function call with anon list literal" {
349 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO349 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
350 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO350 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
352 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
353352
354 const S = struct {353 const S = struct {
355 fn doTheTest() !void {354 fn doTheTest() !void {
...@@ -370,7 +369,6 @@ test "function call with anon list literal - 2D" {...@@ -370,7 +369,6 @@ test "function call with anon list literal - 2D" {
370 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO369 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO371 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
373 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
374372
375 const S = struct {373 const S = struct {
376 fn doTheTest() !void {374 fn doTheTest() !void {
test/behavior/globals.zig-1
...@@ -7,7 +7,6 @@ test "store to global array" {...@@ -7,7 +7,6 @@ test "store to global array" {
7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
12 try expect(pos[1] == 0.0);11 try expect(pos[1] == 0.0);
13 pos = [2]f32{ 0.0, 1.0 };12 pos = [2]f32{ 0.0, 1.0 };
test/behavior/slice.zig+1
...@@ -1001,6 +1001,7 @@ test "sentinel-terminated 0-length slices" {...@@ -1001,6 +1001,7 @@ test "sentinel-terminated 0-length slices" {
1001 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO1001 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
1002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1003 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1003 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1004 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10041005
1005 const u32s: [4]u32 = [_]u32{ 0, 1, 2, 3 };1006 const u32s: [4]u32 = [_]u32{ 0, 1, 2, 3 };
10061007
test/behavior/vector.zig+1
...@@ -434,6 +434,7 @@ test "load vector elements via runtime index" {...@@ -434,6 +434,7 @@ test "load vector elements via runtime index" {
434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
437 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
437438
438 const S = struct {439 const S = struct {
439 fn doTheTest() !void {440 fn doTheTest() !void {