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
signature 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;
3838const FrameIndex = bits.FrameIndex;
3939const RegisterManager = abi.RegisterManager;
4040const 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
5142const InnerError = CodeGenError || error{OutOfRegisters};
5243
53const RegisterView = enum(u1) {
54 caller,
55 callee,
56};
57
5844gpa: Allocator,
5945air: Air,
6046mod: *Package.Module,
......@@ -919,10 +905,24 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
919905 return result;
920906}
921907
908const required_features = [_]Target.riscv.Feature{
909 .d,
910 .m,
911};
912
922913fn gen(self: *Self) !void {
923914 const mod = self.bin_file.comp.module.?;
924915 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
926926 if (fn_info.cc != .Naked) {
927927 try self.addPseudoNone(.pseudo_dbg_prologue_end);
928928
......@@ -1454,9 +1454,9 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
14541454 }
14551455
14561456 var save_reg_list = Mir.RegisterList{};
1457 for (callee_preserved_regs) |reg| {
1457 for (abi.Registers.all_preserved) |reg| {
14581458 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);
14601460 }
14611461 }
14621462
......@@ -1600,6 +1600,33 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex {
16001600 }));
16011601}
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
16031630fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
16041631 const zcu = self.bin_file.comp.module.?;
16051632 const elem_ty = self.typeOfIndex(inst);
......@@ -1608,11 +1635,15 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
16081635 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)});
16091636 };
16101637
1611 if (reg_ok) {
1612 if (abi_size <= 8) {
1613 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
1614 return .{ .register = reg };
1615 }
1638 const min_size: u32 = switch (elem_ty.zigTypeTag(zcu)) {
1639 .Float => 4,
1640 .Vector => @panic("allocRegOrMem Vector"),
1641 else => 8,
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 };
16161647 }
16171648 }
16181649
......@@ -1623,19 +1654,37 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
16231654/// Allocates a register from the general purpose set and returns the Register and the Lock.
16241655///
16251656/// Up to the caller to unlock the register later.
1626fn allocReg(self: *Self) !struct { Register, RegisterLock } {
1627 const reg = try self.register_manager.allocReg(null, gp);
1657fn allocReg(self: *Self, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } {
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);
16281667 const lock = self.register_manager.lockRegAssumeUnused(reg);
16291668 return .{ reg, lock };
16301669}
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
16321681fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
16331682 const reg: Register = blk: {
16341683 switch (index) {
16351684 .immediate => |imm| {
16361685 // Optimisation: if index MCValue is an immediate, we can multiply in `comptime`
16371686 // 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));
16391688 try self.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size });
16401689 break :blk reg;
16411690 },
......@@ -1671,7 +1720,8 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
16711720/// allocated. A second call to `copyToTmpRegister` may return the same register.
16721721/// This can have a side effect of spilling instructions to the stack to free up a register.
16731722fn 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));
16751725 try self.genSetReg(ty, reg, mcv);
16761726 return reg;
16771727}
......@@ -1680,7 +1730,8 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
16801730/// `reg_owner` is the instruction that gets associated with the register in the register table.
16811731/// This can have a side effect of spilling instructions to the stack to free up a register.
16821732fn 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));
16841735 try self.genSetReg(self.typeOfIndex(reg_owner), reg, mcv);
16851736 return MCValue{ .register = reg };
16861737}
......@@ -1797,7 +1848,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
17971848 if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)
17981849 operand.register
17991850 else
1800 try self.register_manager.allocReg(inst, gp);
1851 (try self.allocRegOrMem(inst, true)).register;
18011852
18021853 _ = try self.addInst(.{
18031854 .tag = .pseudo,
......@@ -1843,7 +1894,7 @@ fn airMinMax(
18431894 const lhs_reg, const lhs_lock = blk: {
18441895 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);
18471898 try self.genSetReg(lhs_ty, lhs_reg, lhs);
18481899 break :blk .{ lhs_reg, lhs_lock };
18491900 };
......@@ -1852,16 +1903,16 @@ fn airMinMax(
18521903 const rhs_reg, const rhs_lock = blk: {
18531904 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);
18561907 try self.genSetReg(rhs_ty, rhs_reg, rhs);
18571908 break :blk .{ rhs_reg, rhs_lock };
18581909 };
18591910 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);
18621913 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);
18651916 defer self.register_manager.unlockReg(result_lock);
18661917
18671918 _ = try self.addInst(.{
......@@ -1955,20 +2006,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
19552006 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
19562007}
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.
19722009fn binOp(
19732010 self: *Self,
19742011 tag: Air.Inst.Tag,
......@@ -1991,11 +2028,18 @@ fn binOp(
19912028 .cmp_lt,
19922029 .cmp_lte,
19932030 => {
2031 assert(lhs_ty.eql(rhs_ty, zcu));
19942032 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 },
19962041 .Vector => return self.fail("TODO binary operations on vectors", .{}),
19972042 .Int, .Enum, .ErrorSet => {
1998 assert(lhs_ty.eql(rhs_ty, zcu));
19992043 const int_info = lhs_ty.intInfo(zcu);
20002044 if (int_info.bits <= 64) {
20012045 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
......@@ -2071,14 +2115,7 @@ fn binOp(
20712115 else => return self.fail("TODO binOp {}", .{tag}),
20722116 }
20732117}
2074/// Don't call this function directly. Use binOp instead.
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.
2118
20822119fn binOpRegister(
20832120 self: *Self,
20842121 tag: Air.Inst.Tag,
......@@ -2087,25 +2124,13 @@ fn binOpRegister(
20872124 rhs: MCValue,
20882125 rhs_ty: Type,
20892126) !MCValue {
2090 const lhs_reg, const lhs_lock = blk: {
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 };
2127 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
20972128 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
20982129
2099 const rhs_reg, const rhs_lock = blk: {
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 };
2130 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
21062131 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);
21092134 defer self.register_manager.unlockReg(dest_lock);
21102135
21112136 const mir_tag: Mir.Inst.Tag = switch (tag) {
......@@ -2184,7 +2209,50 @@ fn binOpRegister(
21842209 else => unreachable,
21852210 }
21862211
2187 // generate the struct for OF checks
2212 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
21892257 return MCValue{ .register = dest_reg };
21902258}
......@@ -2279,7 +2347,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22792347
22802348 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);
22832351 defer self.register_manager.unlockReg(shift_lock);
22842352
22852353 _ = try self.addInst(.{
......@@ -2357,25 +2425,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
23572425 const result_mcv = try self.allocRegOrMem(inst, false);
23582426 const offset = result_mcv.load_frame;
23592427
2360 const lhs_reg, const lhs_lock = blk: {
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 };
2428 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
23672429 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
23682430
2369 const rhs_reg, const rhs_lock = blk: {
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 };
2431 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
23762432 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);
23792435 defer self.register_manager.unlockReg(dest_lock);
23802436
23812437 switch (int_info.signedness) {
......@@ -2503,18 +2559,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
25032559 1...8 => {
25042560 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
25052561
2506 const overflow_reg, const overflow_lock = try self.allocReg();
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 };
2562 const add_reg, const add_lock = try self.promoteReg(lhs_ty, lhs);
25162563 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
25182568 _ = try self.addInst(.{
25192569 .tag = .andi,
25202570 .ops = .rri,
......@@ -2595,25 +2645,13 @@ fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void {
25952645 const lhs_ty = self.typeOf(bin_op.lhs);
25962646 const rhs_ty = self.typeOf(bin_op.rhs);
25972647
2598 const lhs_reg, const lhs_lock = blk: {
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 };
2648 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
26052649 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
26062650
2607 const rhs_reg, const rhs_lock = blk: {
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 };
2651 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
26142652 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);
26172655 defer self.register_manager.unlockReg(dest_lock);
26182656
26192657 _ = try self.addInst(.{
......@@ -2640,25 +2678,13 @@ fn airBitOr(self: *Self, inst: Air.Inst.Index) !void {
26402678 const lhs_ty = self.typeOf(bin_op.lhs);
26412679 const rhs_ty = self.typeOf(bin_op.rhs);
26422680
2643 const lhs_reg, const lhs_lock = blk: {
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 };
2681 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
26502682 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
26512683
2652 const rhs_reg, const rhs_lock = blk: {
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 };
2684 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
26592685 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);
26622688 defer self.register_manager.unlockReg(dest_lock);
26632689
26642690 _ = try self.addInst(.{
......@@ -3102,7 +3128,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
31023128 const elem_ty = array_ty.childType(zcu);
31033129 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);
31063132 defer self.register_manager.unlockReg(addr_reg_lock);
31073133
31083134 switch (array_mcv) {
......@@ -3211,46 +3237,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
32113237
32123238fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
32133239 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3214 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
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
3240 _ = ty_op;
32543241 return self.fail("TODO: finish ctz", .{});
32553242}
32563243
......@@ -3267,38 +3254,18 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
32673254 const ty = self.typeOf(ty_op.operand);
32683255 const scalar_ty = ty.scalarType(zcu);
32693256 const operand = try self.resolveInst(ty_op.operand);
3257 _ = operand;
32703258
32713259 switch (scalar_ty.zigTypeTag(zcu)) {
32723260 .Int => if (ty.zigTypeTag(zcu) == .Vector) {
32733261 return self.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)});
32743262 } else {
3275 const int_bits = ty.intInfo(zcu).bits;
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;
3263 return self.fail("TODO: implement airAbs for Int", .{});
32993264 },
33003265 else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}),
33013266 }
3267
3268 break :result .{.unreach};
33023269 };
33033270 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
33043271}
......@@ -3317,15 +3284,24 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
33173284 return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
33183285 }
33193286
3320 const dest_reg = try self.register_manager.allocReg(null, gp);
3321 try self.genSetReg(ty, dest_reg, operand);
3322
3323 const dest_mcv: MCValue = .{ .register = dest_reg };
3287 const dest_mcv = try self.copyToNewRegister(inst, operand);
3288 const dest_reg = dest_mcv.register;
33243289
33253290 switch (int_bits) {
33263291 16 => {
3327 const temp = try self.binOp(.shr, dest_mcv, ty, .{ .immediate = 8 }, Type.u8);
3328 assert(temp == .register);
3292 const temp_reg, const temp_lock = try self.allocReg(.int);
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
33293305 _ = try self.addInst(.{
33303306 .tag = .slli,
33313307 .ops = .rri,
......@@ -3341,7 +3317,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
33413317 .data = .{ .r_type = .{
33423318 .rd = dest_reg,
33433319 .rs1 = dest_reg,
3344 .rs2 = temp.register,
3320 .rs2 = temp_reg,
33453321 } },
33463322 });
33473323 },
......@@ -3360,11 +3336,12 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
33603336}
33613337
33623338fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
3339 const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
33633340 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
33643341 const result: MCValue = if (self.liveness.isUnused(inst))
33653342 .unreach
33663343 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 });
33683345 return self.finishAir(inst, result, .{ un_op, .none, .none });
33693346}
33703347
......@@ -3640,7 +3617,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
36403617 @intCast(field_bit_size),
36413618 );
36423619
3643 const dst_reg, const dst_lock = try self.allocReg();
3620 const dst_reg, const dst_lock = try self.allocReg(.int);
36443621 const dst_mcv = MCValue{ .register = dst_reg };
36453622 defer self.register_manager.unlockReg(dst_lock);
36463623
......@@ -3658,7 +3635,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
36583635 break :dst dst_mcv;
36593636 };
36603637 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);
36623639 defer self.register_manager.unlockReg(tmp_lock);
36633640
36643641 const hi_mcv =
......@@ -3972,7 +3949,7 @@ fn genCall(
39723949 }
39733950 } else {
39743951 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);
39763953 defer self.register_manager.unlockReg(addr_lock);
39773954 try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee });
39783955
......@@ -4072,32 +4049,49 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
40724049 const rhs = try self.resolveInst(bin_op.rhs);
40734050 const lhs_ty = self.typeOf(bin_op.lhs);
40744051
4075 const int_ty = switch (lhs_ty.zigTypeTag(zcu)) {
4076 .Vector => unreachable, // Handled by cmp_vector.
4077 .Enum => lhs_ty.intTagType(zcu),
4078 .Int => lhs_ty,
4079 .Bool => Type.u1,
4080 .Pointer => Type.usize,
4081 .ErrorSet => Type.u16,
4082 .Optional => blk: {
4083 const payload_ty = lhs_ty.optionalChild(zcu);
4084 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4085 break :blk Type.u1;
4086 } else if (lhs_ty.isPtrLikeOptional(zcu)) {
4087 break :blk Type.usize;
4052 switch (lhs_ty.zigTypeTag(zcu)) {
4053 .Int,
4054 .Enum,
4055 .Bool,
4056 .Pointer,
4057 .ErrorSet,
4058 .Optional,
4059 => {
4060 const int_ty = switch (lhs_ty.zigTypeTag(zcu)) {
4061 .Enum => lhs_ty.intTagType(zcu),
4062 .Int => lhs_ty,
4063 .Bool => Type.u1,
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);
40884082 } else {
4089 return self.fail("TODO riscv cmp non-pointer optionals", .{});
4083 return self.fail("TODO riscv cmp for ints > 64 bits", .{});
40904084 }
40914085 },
4092 .Float => return self.fail("TODO riscv cmp floats", .{}),
4093 else => unreachable,
4094 };
4086 .Float => {
4087 const float_bits = lhs_ty.floatBits(self.target.*);
4088 if (float_bits > 32) {
4089 return self.fail("TODO: airCmp float > 32 bits", .{});
4090 }
40954091
4096 const int_info = int_ty.intInfo(zcu);
4097 if (int_info.bits <= 64) {
4098 break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty);
4099 } else {
4100 return self.fail("TODO riscv cmp for ints > 64 bits", .{});
4092 break :result try self.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty);
4093 },
4094 else => unreachable,
41014095 }
41024096 };
41034097
......@@ -4716,25 +4710,13 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
47164710 const lhs_ty = Type.bool;
47174711 const rhs_ty = Type.bool;
47184712
4719 const lhs_reg, const lhs_lock = blk: {
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 };
4713 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
47264714 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
47274715
4728 const rhs_reg, const rhs_lock = blk: {
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 };
4716 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
47354717 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);
47384720 defer self.register_manager.unlockReg(result_lock);
47394721
47404722 _ = try self.addInst(.{
......@@ -4881,7 +4863,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
48814863 return self.finishAirResult(inst, result);
48824864}
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`.
48854867fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
48864868 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 {
48904872
48914873 if (!dst_mcv.isMutable()) {
48924874 // 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)});
48944876 }
48954877
48964878 switch (dst_mcv) {
......@@ -4924,13 +4906,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
49244906 ),
49254907 .memory => return self.fail("TODO: genCopy memory", .{}),
49264908 .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) {
49284910 .register_pair, .memory, .indirect, .load_frame => null,
49294911 .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());
49314913 errdefer self.register_manager.unlockReg(src_addr_lock);
49324914
4933 try self.genSetReg(Type.usize, src_addr_reg, src_mcv.address());
49344915 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
49354916 },
49364917 .air_ref => |src_ref| return self.genCopy(
......@@ -4940,7 +4921,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
49404921 ),
49414922 else => unreachable,
49424923 };
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
49454931 var part_disp: i32 = 0;
49464932 for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| {
......@@ -4966,7 +4952,7 @@ fn genInlineMemcpy(
49664952 src_ptr: MCValue,
49674953 len: MCValue,
49684954) !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);
49704956 const locks = self.register_manager.lockRegsAssumeUnused(4, regs);
49714957 defer for (locks) |lock| self.register_manager.unlockReg(lock);
49724958
......@@ -5060,9 +5046,7 @@ fn genInlineMemcpy(
50605046 _ = try self.addInst(.{
50615047 .tag = .pseudo,
50625048 .ops = .pseudo_j,
5063 .data = .{
5064 .inst = first_inst,
5065 },
5049 .data = .{ .inst = first_inst },
50665050 });
50675051}
50685052
......@@ -5072,7 +5056,7 @@ fn genInlineMemset(
50725056 src_value: MCValue,
50735057 len: MCValue,
50745058) !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);
50765060 const locks = self.register_manager.lockRegsAssumeUnused(3, regs);
50775061 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!
51535137
51545138 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
51565142 switch (src_mcv) {
51575143 .dead => unreachable,
51585144 .unreach, .none => return, // Nothing to do.
......@@ -5163,6 +5149,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
51635149 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
51645150 },
51655151 .immediate => |unsigned_x| {
5152 assert(dst_reg_class == .int);
5153
51665154 const x: i64 = @bitCast(unsigned_x);
51675155 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {
51685156 _ = try self.addInst(.{
......@@ -5200,7 +5188,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
52005188 // TODO: use a more advanced myriad seq to do this without a reg.
52015189 // 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);
52045192 defer self.register_manager.unlockReg(temp_lock);
52055193
52065194 const lo32: i32 = @truncate(x);
......@@ -5236,6 +5224,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
52365224 if (src_reg.id() == reg.id())
52375225 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
52395240 // mv reg, src_reg
52405241 _ = try self.addInst(.{
52415242 .tag = .pseudo,
......@@ -5309,11 +5310,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
53095310 });
53105311 },
53115312 .indirect => |reg_off| {
5313 const float_class = dst_reg_class == .float;
5314
53125315 const load_tag: Mir.Inst.Tag = switch (abi_size) {
5313 1 => .lb,
5314 2 => .lh,
5315 4 => .lw,
5316 8 => .ld,
5316 1 => if (float_class)
5317 unreachable // Zig does not support 8-bit floats
5318 else
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,
53175326 else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}),
53185327 };
53195328
......@@ -5336,15 +5345,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
53365345 .tag = .pseudo,
53375346 .ops = .pseudo_load_symbol,
53385347 .data = .{ .payload = try self.addExtra(Mir.LoadSymbolPayload{
5339 .register = reg.id(),
5348 .register = reg.encodeId(),
53405349 .atom_index = atom_index,
53415350 .sym_index = sym_off.sym,
53425351 }) },
53435352 });
53445353 },
53455354 .load_symbol => {
5346 try self.genSetReg(ty, reg, src_mcv.address());
5347 try self.genSetReg(ty, reg, .{ .indirect = .{ .reg = reg } });
5355 const addr_reg, const addr_lock = try self.allocReg(.int);
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 } });
53485360 },
53495361 .air_ref => |ref| try self.genSetReg(ty, reg, try self.resolveInst(ref)),
53505362 else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),
......@@ -5386,7 +5398,8 @@ fn genSetMem(
53865398 => switch (abi_size) {
53875399 0 => {},
53885400 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);
53905403 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
53915404 defer self.register_manager.unlockReg(src_lock);
53925405
......@@ -5460,10 +5473,8 @@ fn genSetMem(
54605473 .immediate => {
54615474 // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with
54625475 // a register allocation.
5463 const reg, const reg_lock = try self.allocReg();
5464 defer self.register_manager.unlockReg(reg_lock);
5465
5466 try self.genSetReg(ty, reg, src_mcv);
5476 const reg, const reg_lock = try self.promoteReg(ty, src_mcv);
5477 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
54675478
54685479 return self.genSetMem(base, disp, ty, .{ .register = reg });
54695480 },
......@@ -5632,7 +5643,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
56325643 assert(len != 0); // prevented by Sema
56335644 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);
56365647 defer self.register_manager.unlockReg(second_elem_ptr_lock);
56375648
56385649 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
......@@ -5677,7 +5688,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
56775688 const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);
56785689 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);
56815692 defer self.register_manager.unlockReg(addr_lock);
56825693
56835694 // this is now the base address of the error name table
......@@ -5691,13 +5702,13 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
56915702 return self.fail("TODO: riscv non-elf", .{});
56925703 }
56935704
5694 const start_reg, const start_lock = try self.allocReg();
5705 const start_reg, const start_lock = try self.allocReg(.int);
56955706 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);
56985709 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);
57015712 // defer self.register_manager.unlockReg(tmp_lock);
57025713
57035714 // we move the base address forward by the following formula: base + (errno * 8)
......@@ -6025,16 +6036,16 @@ fn resolveCallingConventionValues(
60256036
60266037 for (classes) |class| switch (class) {
60276038 .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];
60296040 ret_int_reg_i += 1;
60306041
60316042 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg });
60326043 ret_tracking_i += 1;
60336044 },
60346045 .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];
60366047 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];
60386049 param_int_reg_i += 1;
60396050
60406051 ret_tracking[ret_tracking_i] = .{
......@@ -6069,7 +6080,7 @@ fn resolveCallingConventionValues(
60696080
60706081 for (classes) |class| switch (class) {
60716082 .integer => {
6072 const param_int_regs = abi.function_arg_regs;
6083 const param_int_regs = abi.Registers.Integer.function_arg_regs;
60736084 if (param_int_reg_i >= param_int_regs.len) break;
60746085
60756086 const param_int_reg = param_int_regs[param_int_reg_i];
......@@ -6079,7 +6090,7 @@ fn resolveCallingConventionValues(
60796090 arg_mcv_i += 1;
60806091 },
60816092 .memory => {
6082 const param_int_regs = abi.function_arg_regs;
6093 const param_int_regs = abi.Registers.Integer.function_arg_regs;
60836094
60846095 const param_int_reg = param_int_regs[param_int_reg_i];
60856096 param_int_reg_i += 1;
src/arch/riscv64/Encoding.zig+259-96
......@@ -1,7 +1,65 @@
11mnemonic: Mnemonic,
22data: 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
460pub const Mnemonic = enum {
61 // base mnemonics
62
563 // I Type
664 ld,
765 lw,
......@@ -10,6 +68,7 @@ pub const Mnemonic = enum {
1068 lhu,
1169 lb,
1270 lbu,
71
1372 sltiu,
1473 xori,
1574 andi,
......@@ -52,56 +111,130 @@ pub const Mnemonic = enum {
52111 ebreak,
53112 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
55127 pub fn encoding(mnem: Mnemonic) Enc {
56128 return switch (mnem) {
57129 // zig fmt: off
58 .add => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000000 },
59 .sltu => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 },
60 .@"and" => .{ .opcode = 0b0110011, .funct3 = 0b111, .funct7 = 0b0000000 },
61 .@"or" => .{ .opcode = 0b0110011, .funct3 = 0b110, .funct7 = 0b0000000 },
62 .sub => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0100000 },
63
64 .ld => .{ .opcode = 0b0000011, .funct3 = 0b011, .funct7 = null },
65 .lw => .{ .opcode = 0b0000011, .funct3 = 0b010, .funct7 = null },
66 .lwu => .{ .opcode = 0b0000011, .funct3 = 0b110, .funct7 = null },
67 .lh => .{ .opcode = 0b0000011, .funct3 = 0b001, .funct7 = null },
68 .lhu => .{ .opcode = 0b0000011, .funct3 = 0b101, .funct7 = null },
69 .lb => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null },
70 .lbu => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null },
71
72 .sltiu => .{ .opcode = 0b0010011, .funct3 = 0b011, .funct7 = null },
73
74 .addi => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null },
75 .andi => .{ .opcode = 0b0010011, .funct3 = 0b111, .funct7 = null },
76 .xori => .{ .opcode = 0b0010011, .funct3 = 0b100, .funct7 = null },
77 .jalr => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null },
78 .slli => .{ .opcode = 0b0010011, .funct3 = 0b001, .funct7 = null },
79 .srli => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null },
80 .srai => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null, .offset = 1 << 10 },
130
131 // OP
132
133 .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
134 .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
135
136 .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
137 .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
138 .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
139
140 .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
141 .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
142
143 .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
144
145
146 // OP_IMM
147
148 .addi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
149 .andi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b111 } } },
150 .xori => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b100 } } },
81151
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 },
88 .sw => .{ .opcode = 0b0100011, .funct3 = 0b010, .funct7 = null },
89 .sh => .{ .opcode = 0b0100011, .funct3 = 0b001, .funct7 = null },
90 .sb => .{ .opcode = 0b0100011, .funct3 = 0b000, .funct7 = null },
207 // LUI
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 },
105238 // zig fmt: on
106239 };
107240 }
......@@ -109,6 +242,7 @@ pub const Mnemonic = enum {
109242
110243pub const InstEnc = enum {
111244 R,
245 R4,
112246 I,
113247 S,
114248 B,
......@@ -121,13 +255,6 @@ pub const InstEnc = enum {
121255 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {
122256 return switch (mnem) {
123257 .addi,
124 .ld,
125 .lw,
126 .lwu,
127 .lh,
128 .lhu,
129 .lb,
130 .lbu,
131258 .jalr,
132259 .sltiu,
133260 .xori,
......@@ -135,6 +262,17 @@ pub const InstEnc = enum {
135262 .slli,
136263 .srli,
137264 .srai,
265
266 .ld,
267 .lw,
268 .lwu,
269 .lh,
270 .lhu,
271 .lb,
272 .lbu,
273
274 .flw,
275 .fld,
138276 => .I,
139277
140278 .lui,
......@@ -145,6 +283,9 @@ pub const InstEnc = enum {
145283 .sw,
146284 .sh,
147285 .sb,
286
287 .fsd,
288 .fsw,
148289 => .S,
149290
150291 .jal,
......@@ -162,6 +303,11 @@ pub const InstEnc = enum {
162303 .sub,
163304 .@"and",
164305 .@"or",
306
307 .fadds,
308 .faddd,
309 .feqs,
310 .feqd,
165311 => .R,
166312
167313 .ecall,
......@@ -171,16 +317,17 @@ pub const InstEnc = enum {
171317 };
172318 }
173319
174 pub fn opsList(enc: InstEnc) [3]std.meta.FieldEnum(Operand) {
320 pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) {
175321 return switch (enc) {
176322 // zig fmt: off
177 .R => .{ .reg, .reg, .reg, },
178 .I => .{ .reg, .reg, .imm, },
179 .S => .{ .reg, .reg, .imm, },
180 .B => .{ .reg, .reg, .imm, },
181 .U => .{ .reg, .imm, .none, },
182 .J => .{ .reg, .imm, .none, },
183 .system => .{ .none, .none, .none, },
323 .R => .{ .reg, .reg, .reg, .none },
324 .R4 => .{ .reg, .reg, .reg, .reg },
325 .I => .{ .reg, .reg, .imm, .none },
326 .S => .{ .reg, .reg, .imm, .none },
327 .B => .{ .reg, .reg, .imm, .none },
328 .U => .{ .reg, .imm, .none, .none },
329 .J => .{ .reg, .imm, .none, .none },
330 .system => .{ .none, .none, .none, .none },
184331 // zig fmt: on
185332 };
186333 }
......@@ -195,6 +342,15 @@ pub const Data = union(InstEnc) {
195342 rs2: u5,
196343 funct7: u7,
197344 },
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 },
198354 I: packed struct {
199355 opcode: u7,
200356 rd: u5,
......@@ -237,19 +393,21 @@ pub const Data = union(InstEnc) {
237393
238394 pub fn toU32(self: Data) u32 {
239395 return switch (self) {
240 .R => |v| @as(u32, @bitCast(v)),
241 .I => |v| @as(u32, @bitCast(v)),
242 .S => |v| @as(u32, @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),
244 .U => |v| @as(u32, @bitCast(v)),
245 .J => |v| @as(u32, @bitCast(v)),
396 // zig fmt: off
397 .R => |v| @bitCast(v),
398 .R4 => |v| @bitCast(v),
399 .I => |v| @bitCast(v),
400 .S => |v| @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),
246404 .system => unreachable,
405 // zig fmt: on
247406 };
248407 }
249408
250409 pub fn construct(mnem: Mnemonic, ops: []const Operand) !Data {
251410 const inst_enc = InstEnc.fromMnemonic(mnem);
252
253411 const enc = mnem.encoding();
254412
255413 // special mnemonics
......@@ -261,8 +419,8 @@ pub const Data = union(InstEnc) {
261419 assert(ops.len == 0);
262420 return .{
263421 .I = .{
264 .rd = Register.zero.id(),
265 .rs1 = Register.zero.id(),
422 .rd = Register.zero.encodeId(),
423 .rs1 = Register.zero.encodeId(),
266424 .imm0_11 = switch (mnem) {
267425 .ecall => 0x000,
268426 .ebreak => 0x001,
......@@ -270,8 +428,8 @@ pub const Data = union(InstEnc) {
270428 else => unreachable,
271429 },
272430
273 .opcode = enc.opcode,
274 .funct3 = enc.funct3.?,
431 .opcode = @intFromEnum(enc.opcode),
432 .funct3 = enc.data.fo.funct3,
275433 },
276434 };
277435 },
......@@ -282,14 +440,26 @@ pub const Data = union(InstEnc) {
282440 .R => {
283441 assert(ops.len == 3);
284442 return .{
285 .R = .{
286 .rd = ops[0].reg.id(),
287 .rs1 = ops[1].reg.id(),
288 .rs2 = ops[2].reg.id(),
289
290 .opcode = enc.opcode,
291 .funct3 = enc.funct3.?,
292 .funct7 = enc.funct7.?,
443 .R = switch (enc.data) {
444 .ff => |ff| .{
445 .rd = ops[0].reg.encodeId(),
446 .rs1 = ops[1].reg.encodeId(),
447 .rs2 = ops[2].reg.encodeId(),
448
449 .opcode = @intFromEnum(enc.opcode),
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,
293463 },
294464 };
295465 },
......@@ -300,12 +470,12 @@ pub const Data = union(InstEnc) {
300470 return .{
301471 .S = .{
302472 .imm0_4 = @truncate(umm),
303 .rs1 = ops[0].reg.id(),
304 .rs2 = ops[1].reg.id(),
473 .rs1 = ops[0].reg.encodeId(),
474 .rs2 = ops[1].reg.encodeId(),
305475 .imm5_11 = @truncate(umm >> 5),
306476
307 .opcode = enc.opcode,
308 .funct3 = enc.funct3.?,
477 .opcode = @intFromEnum(enc.opcode),
478 .funct3 = enc.data.fo.funct3,
309479 },
310480 };
311481 },
......@@ -313,12 +483,12 @@ pub const Data = union(InstEnc) {
313483 assert(ops.len == 3);
314484 return .{
315485 .I = .{
316 .rd = ops[0].reg.id(),
317 .rs1 = ops[1].reg.id(),
318 .imm0_11 = ops[2].imm.asBits(u12) + enc.offset,
486 .rd = ops[0].reg.encodeId(),
487 .rs1 = ops[1].reg.encodeId(),
488 .imm0_11 = ops[2].imm.asBits(u12) + enc.data.fo.offset,
319489
320 .opcode = enc.opcode,
321 .funct3 = enc.funct3.?,
490 .opcode = @intFromEnum(enc.opcode),
491 .funct3 = enc.data.fo.funct3,
322492 },
323493 };
324494 },
......@@ -326,10 +496,10 @@ pub const Data = union(InstEnc) {
326496 assert(ops.len == 2);
327497 return .{
328498 .U = .{
329 .rd = ops[0].reg.id(),
499 .rd = ops[0].reg.encodeId(),
330500 .imm12_31 = ops[1].imm.asBits(u20),
331501
332 .opcode = enc.opcode,
502 .opcode = @intFromEnum(enc.opcode),
333503 },
334504 };
335505 },
......@@ -341,13 +511,13 @@ pub const Data = union(InstEnc) {
341511
342512 return .{
343513 .J = .{
344 .rd = ops[0].reg.id(),
514 .rd = ops[0].reg.encodeId(),
345515 .imm1_10 = @truncate(umm >> 1),
346516 .imm11 = @truncate(umm >> 11),
347517 .imm12_19 = @truncate(umm >> 12),
348518 .imm20 = @truncate(umm >> 20),
349519
350 .opcode = enc.opcode,
520 .opcode = @intFromEnum(enc.opcode),
351521 },
352522 };
353523 },
......@@ -359,15 +529,15 @@ pub const Data = union(InstEnc) {
359529
360530 return .{
361531 .B = .{
362 .rs1 = ops[0].reg.id(),
363 .rs2 = ops[1].reg.id(),
532 .rs1 = ops[0].reg.encodeId(),
533 .rs2 = ops[1].reg.encodeId(),
364534 .imm1_4 = @truncate(umm >> 1),
365535 .imm5_10 = @truncate(umm >> 5),
366536 .imm11 = @truncate(umm >> 11),
367537 .imm12 = @truncate(umm >> 12),
368538
369 .opcode = enc.opcode,
370 .funct3 = enc.funct3.?,
539 .opcode = @intFromEnum(enc.opcode),
540 .funct3 = enc.data.fo.funct3,
371541 },
372542 };
373543 },
......@@ -386,13 +556,6 @@ pub fn findByMnemonic(mnem: Mnemonic, ops: []const Operand) !?Encoding {
386556 };
387557}
388558
389const Enc = struct {
390 opcode: u7,
391 funct3: ?u3,
392 funct7: ?u7,
393 offset: u12 = 0,
394};
395
396559fn verifyOps(mnem: Mnemonic, ops: []const Operand) bool {
397560 const inst_enc = InstEnc.fromMnemonic(mnem);
398561 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,
1414result_insts: [
1515 @max(
1616 1, // non-pseudo instruction
17 abi.callee_preserved_regs.len, // spill / restore regs,
17 abi.Registers.all_preserved.len, // spill / restore regs,
1818 )
1919]Instruction = undefined,
2020result_relocs: [1]Reloc = undefined,
......@@ -71,11 +71,24 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
7171
7272 switch (inst.ops) {
7373 .pseudo_load_rm => {
74 const tag: Encoding.Mnemonic = switch (rm.m.mod.size()) {
75 .byte => .lb,
76 .hword => .lh,
77 .word => .lw,
78 .dword => .ld,
74 const dest_reg = rm.r;
75 const dest_reg_class = dest_reg.class();
76 const float = dest_reg_class == .float;
77
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,
7992 };
8093
8194 try lower.emit(tag, &.{
......@@ -85,11 +98,25 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
8598 });
8699 },
87100 .pseudo_store_rm => {
88 const tag: Encoding.Mnemonic = switch (rm.m.mod.size()) {
89 .byte => .sb,
90 .hword => .sh,
91 .word => .sw,
92 .dword => .sd,
101 const src_reg = rm.r;
102 const src_reg_class = src_reg.class();
103 const float = src_reg_class == .float;
104
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,
93120 };
94121
95122 try lower.emit(tag, &.{
......@@ -336,16 +363,19 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
336363 var reg_i: u31 = 0;
337364 while (it.next()) |i| {
338365 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
340370 if (spilling) {
341 try lower.emit(.sd, &.{
371 try lower.emit(if (is_float_reg) .fsd else .sd, &.{
342372 .{ .reg = frame.base },
343 .{ .reg = abi.callee_preserved_regs[i] },
373 .{ .reg = abi.Registers.all_preserved[i] },
344374 .{ .imm = Immediate.s(frame.disp + reg_i) },
345375 });
346376 } else {
347 try lower.emit(.ld, &.{
348 .{ .reg = abi.callee_preserved_regs[i] },
377 try lower.emit(if (is_float_reg) .fld else .ld, &.{
378 .{ .reg = abi.Registers.all_preserved[i] },
349379 .{ .reg = frame.base },
350380 .{ .imm = Immediate.s(frame.disp + reg_i) },
351381 });
src/arch/riscv64/Mir.zig+20-39
......@@ -20,87 +20,68 @@ pub const Inst = struct {
2020 pub const Index = u32;
2121
2222 pub const Tag = enum(u16) {
23 /// Add immediate. Uses i_type payload.
24 addi,
2523
26 /// Add immediate and produce a sign-extended result.
27 ///
28 /// Uses i-type payload.
24 // base extension
25 addi,
2926 addiw,
3027
3128 jalr,
3229 lui,
33 mv,
3430
3531 @"and",
32 andi,
33
3634 xor,
35 @"or",
3736
3837 ebreak,
3938 ecall,
4039 unimp,
4140
42 /// OR instruction. Uses r_type payload.
43 @"or",
44
45 /// Addition
4641 add,
47 /// Subtraction
4842 sub,
49 /// Multiply, uses r_type. Needs the M extension.
50 mul,
51
52 /// Absolute Value, uses i_type payload.
53 abs,
5443
5544 sltu,
5645 slt,
5746
58 /// Immediate Logical Right Shift, uses i_type payload
5947 srli,
60 /// Immediate Logical Left Shift, uses i_type payload
6148 slli,
62 /// Immediate Arithmetic Right Shift, uses i_type payload.
6349 srai,
64 /// Register Logical Left Shift, uses r_type payload
6550 sllw,
66 /// Register Logical Right Shit, uses r_type payload
6751 srlw,
6852
69 /// Jumps, but stores the address of the instruction following the
70 /// jump in `rd`.
71 ///
72 /// Uses j_type payload.
7353 jal,
7454
75 /// Immediate AND, uses i_type payload
76 andi,
77
78 /// Branch if equal, Uses b_type
7955 beq,
80 /// Branch if not equal, Uses b_type
8156 bne,
8257
83 /// Generates a NO-OP, uses nop payload
8458 nop,
8559
86 /// Load double (64 bits), uses i_type payload
8760 ld,
88 /// Load word (32 bits), uses i_type payload
8961 lw,
90 /// Load half (16 bits), uses i_type payload
9162 lh,
92 /// Load byte (8 bits), uses i_type payload
9363 lb,
9464
95 /// Store double (64 bits), uses s_type payload
9665 sd,
97 /// Store word (32 bits), uses s_type payload
9866 sw,
99 /// Store half (16 bits), uses s_type payload
10067 sh,
101 /// Store byte (8 bits), uses s_type payload
10268 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
10485 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
10586 /// assembly instruction.
10687 pseudo,
src/arch/riscv64/abi.zig+66-47
......@@ -238,62 +238,81 @@ fn classifyStruct(
238238 }
239239}
240240
241pub const callee_preserved_regs = [_]Register{
242 // .s0 is ommited to be used as a frame pointer
243 .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
244};
241const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs;
242pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
245243
246pub const function_arg_regs = [_]Register{
247 .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,
248};
244// Register classes
245const RegisterBitSet = RegisterManager.RegisterBitSet;
249246
250pub const function_ret_regs = [_]Register{
251 .a0, .a1,
247pub const RegisterClass = enum {
248 int,
249 float,
252250};
253251
254pub const temporary_regs = [_]Register{
255 .t0, .t1, .t2, .t3, .t4, .t5, .t6,
256};
252pub const Registers = struct {
253 pub const all_preserved = Integer.callee_preserved_regs ++ Float.callee_preserved_regs;
257254
258const allocatable_registers = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
259pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
255 pub const Integer = struct {
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 classes
262const RegisterBitSet = RegisterManager.RegisterBitSet;
263pub const RegisterClass = struct {
264 pub const gp: RegisterBitSet = blk: {
265 var set = RegisterBitSet.initEmpty();
266 set.setRangeValue(.{
267 .start = 0,
268 .end = callee_preserved_regs.len,
269 }, true);
270 break :blk set;
271 };
263 pub const callee_preserved_regs = [_]Register{
264 // .s0 is omitted to be used as the frame pointer register
265 .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
266 };
272267
273 pub const fa: RegisterBitSet = blk: {
274 var set = RegisterBitSet.initEmpty();
275 set.setRangeValue(.{
276 .start = callee_preserved_regs.len,
277 .end = callee_preserved_regs.len + function_arg_regs.len,
278 }, true);
279 break :blk set;
280 };
268 pub const function_arg_regs = [_]Register{
269 .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,
270 };
271
272 pub const function_ret_regs = [_]Register{
273 .a0, .a1,
274 };
275
276 pub const temporary_regs = [_]Register{
277 .t0, .t1, .t2, .t3, .t4, .t5, .t6,
278 };
281279
282 pub const fr: RegisterBitSet = blk: {
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;
280 pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
289281 };
290282
291 pub const tp: RegisterBitSet = blk: {
292 var set = RegisterBitSet.initEmpty();
293 set.setRangeValue(.{
294 .start = callee_preserved_regs.len + function_arg_regs.len,
295 .end = callee_preserved_regs.len + function_arg_regs.len + temporary_regs.len,
296 }, true);
297 break :blk set;
283 pub const Float = struct {
284 // zig fmt: off
285 pub const general_purpose = initRegBitSet(Integer.all_regs.len, callee_preserved_regs.len);
286 pub const function_arg = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len, function_arg_regs.len);
287 pub const function_ret = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len, function_ret_regs.len);
288 pub const temporary = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len + function_arg_regs.len, temporary_regs.len);
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;
298308 };
299309};
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;
44const testing = std.testing;
55const Encoding = @import("Encoding.zig");
66const Mir = @import("Mir.zig");
7const abi = @import("abi.zig");
78
89pub const Memory = struct {
910 base: Base,
......@@ -154,10 +155,10 @@ pub const Immediate = union(enum) {
154155 }
155156};
156157
157pub const Register = enum(u6) {
158pub const Register = enum(u8) {
158159 // zig fmt: off
159160
160 // general purpose registers
161 // base extension registers
161162
162163 zero, // zero
163164 ra, // return address. caller saved
......@@ -178,12 +179,48 @@ pub const Register = enum(u6) {
178179 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
181199 // zig fmt: on
182200
183 /// Returns the unique 5-bit ID of this register which is used in
184 /// the machine code
185 pub fn id(self: Register) u5 {
186 return @as(u5, @truncate(@intFromEnum(self)));
201 /// in RISC-V registers are stored as 5 bit IDs and a register can have
202 /// two names. Example being `zero` and `x0` are the same register and have the
203 /// same ID, but are two different entries in the enum. We store floating point
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));
187224 }
188225
189226 pub fn dwarfLocOp(reg: Register) u8 {
......@@ -192,7 +229,21 @@ pub const Register = enum(u6) {
192229
193230 pub fn bitSize(reg: Register) u32 {
194231 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
196247 };
197248 }
198249};
test/behavior/byteswap.zig+1
......@@ -100,6 +100,7 @@ test "@byteSwap vectors u8" {
100100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
101101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102102 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103104
104105 try comptime vector8();
105106 try vector8();
test/behavior/fn.zig-2
......@@ -349,7 +349,6 @@ test "function call with anon list literal" {
349349 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
350350 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
351351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
352 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
353352
354353 const S = struct {
355354 fn doTheTest() !void {
......@@ -370,7 +369,6 @@ test "function call with anon list literal - 2D" {
370369 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
371370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
372371 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
373 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
374372
375373 const S = struct {
376374 fn doTheTest() !void {
test/behavior/globals.zig-1
......@@ -7,7 +7,6 @@ test "store to global array" {
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
1211 try expect(pos[1] == 0.0);
1312 pos = [2]f32{ 0.0, 1.0 };
test/behavior/slice.zig+1
......@@ -1001,6 +1001,7 @@ test "sentinel-terminated 0-length slices" {
10011001 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
10021002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10031003 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1004 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10041005
10051006 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" {
434434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
435435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
436436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
437 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
437438
438439 const S = struct {
439440 fn doTheTest() !void {