authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-04-13 21:12:26-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
loge622485df8d162fd2696b6ab1149262aa6b74407
treecca5d3eb0b600b8d88cb17363ee8ba053d37db83
parentd19b77d63f0d02ab9c0a0928391891ae4a77744c

riscv: actually working test runner


6 files changed, 234 insertions(+), 251 deletions(-)

lib/compiler/test_runner.zig+2
......@@ -266,4 +266,6 @@ pub fn mainExtraSimple() !void {
266266 };
267267 pass_count += 1;
268268 }
269
270 std.posix.exit(pass_count);
269271}
src/arch/riscv64/CodeGen.zig+94-210
......@@ -1601,7 +1601,6 @@ fn allocReg(self: *Self) !struct { Register, RegisterLock } {
16011601}
16021602
16031603fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
1604 log.debug("elemOffset: {}", .{index});
16051604 const reg: Register = blk: {
16061605 switch (index) {
16071606 .immediate => |imm| {
......@@ -1616,14 +1615,14 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi
16161615 const lock = self.register_manager.lockRegAssumeUnused(reg);
16171616 defer self.register_manager.unlockReg(lock);
16181617
1619 try self.binOpMir(
1618 const result = try self.binOp(
16201619 .mul,
1621 null,
1622 index_ty,
16231620 .{ .register = reg },
1621 index_ty,
16241622 .{ .immediate = elem_size },
1623 index_ty,
16251624 );
1626 break :blk reg;
1625 break :blk result.register;
16271626 },
16281627 }
16291628 };
......@@ -1817,24 +1816,10 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
18171816 const lhs_ty = self.typeOf(bin_op.lhs);
18181817 const rhs_ty = self.typeOf(bin_op.rhs);
18191818
1820 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
1821 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1822}
1823
1824fn supportImmediate(tag: Air.Inst.Tag) bool {
1825 return switch (tag) {
1826 .add,
1827 .sub,
1828 .cmp_eq,
1829 .cmp_neq,
1830 .cmp_gt,
1831 .cmp_gte,
1832 .cmp_lt,
1833 .cmp_lte,
1834 => true,
1835
1836 else => false,
1819 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1820 break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
18371821 };
1822 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
18381823}
18391824
18401825/// For all your binary operation needs, this function will generate
......@@ -1854,10 +1839,9 @@ fn supportImmediate(tag: Air.Inst.Tag) bool {
18541839fn binOp(
18551840 self: *Self,
18561841 tag: Air.Inst.Tag,
1857 maybe_inst: ?Air.Inst.Index,
18581842 lhs: MCValue,
1859 rhs: MCValue,
18601843 lhs_ty: Type,
1844 rhs: MCValue,
18611845 rhs_ty: Type,
18621846) InnerError!MCValue {
18631847 const zcu = self.bin_file.comp.module.?;
......@@ -1881,15 +1865,12 @@ fn binOp(
18811865 assert(lhs_ty.eql(rhs_ty, zcu));
18821866 const int_info = lhs_ty.intInfo(zcu);
18831867 if (int_info.bits <= 64) {
1884 if (rhs == .immediate and supportImmediate(tag)) {
1885 return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1886 }
1887 return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1868 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
18881869 } else {
18891870 return self.fail("TODO binary operations on int with bits > 64", .{});
18901871 }
18911872 },
1892 else => |x| return self.fail("TOOD: binOp {s}", .{@tagName(x)}),
1873 else => |x| return std.debug.panic("TOOD: binOp {s}", .{@tagName(x)}),
18931874 }
18941875 },
18951876
......@@ -1912,23 +1893,21 @@ fn binOp(
19121893 else => unreachable,
19131894 };
19141895
1915 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1896 return try self.binOpRegister(base_tag, lhs, lhs_ty, rhs, rhs_ty);
19161897 } else {
19171898 const offset = try self.binOp(
19181899 .mul,
1919 null,
19201900 rhs,
1921 .{ .immediate = elem_size },
19221901 Type.usize,
1902 .{ .immediate = elem_size },
19231903 Type.usize,
19241904 );
19251905
19261906 const addr = try self.binOp(
19271907 tag,
1928 null,
19291908 lhs,
1930 offset,
19311909 Type.manyptr_u8,
1910 offset,
19321911 Type.usize,
19331912 );
19341913 return addr;
......@@ -1948,10 +1927,7 @@ fn binOp(
19481927 .Int => {
19491928 const int_info = lhs_ty.intInfo(zcu);
19501929 if (int_info.bits <= 64) {
1951 if (rhs == .immediate) {
1952 return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1953 }
1954 return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1930 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
19551931 } else {
19561932 return self.fail("TODO binary operations on int with bits > 64", .{});
19571933 }
......@@ -1973,14 +1949,11 @@ fn binOp(
19731949fn binOpRegister(
19741950 self: *Self,
19751951 tag: Air.Inst.Tag,
1976 maybe_inst: ?Air.Inst.Index,
19771952 lhs: MCValue,
1978 rhs: MCValue,
19791953 lhs_ty: Type,
1954 rhs: MCValue,
19801955 rhs_ty: Type,
19811956) !MCValue {
1982 _ = maybe_inst;
1983
19841957 const lhs_reg, const lhs_lock = blk: {
19851958 if (lhs == .register) break :blk .{ lhs.register, null };
19861959
......@@ -2006,164 +1979,79 @@ fn binOpRegister(
20061979 .add => .add,
20071980 .sub => .sub,
20081981 .mul => .mul,
2009 .cmp_eq => .cmp_eq,
2010 .cmp_neq => .cmp_neq,
2011 .cmp_gt => .cmp_gt,
2012 .cmp_gte => .cmp_gte,
2013 .cmp_lt => .cmp_lt,
1982
20141983 .shl => .sllw,
20151984 .shr => .srlw,
2016 else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
2017 };
2018
2019 _ = try self.addInst(.{
2020 .tag = mir_tag,
2021 .ops = .rrr,
2022 .data = .{
2023 .r_type = .{
2024 .rd = dest_reg,
2025 .rs1 = lhs_reg,
2026 .rs2 = rhs_reg,
2027 },
2028 },
2029 });
2030
2031 // generate the struct for OF checks
20321985
2033 return MCValue{ .register = dest_reg };
2034}
2035
2036/// Don't call this function directly. Use binOp instead.
2037///
2038/// Call this function if rhs is an immediate. Generates I version of binops.
2039///
2040/// Asserts that rhs is an immediate MCValue
2041fn binOpImm(
2042 self: *Self,
2043 tag: Air.Inst.Tag,
2044 maybe_inst: ?Air.Inst.Index,
2045 lhs: MCValue,
2046 rhs: MCValue,
2047 lhs_ty: Type,
2048 rhs_ty: Type,
2049) !MCValue {
2050 assert(rhs == .immediate);
2051 _ = maybe_inst;
2052
2053 // TODO: use `maybe_inst` to track instead of forcing a lock.
2054
2055 const lhs_reg, const lhs_lock = blk: {
2056 if (lhs == .register) break :blk .{ lhs.register, null };
2057
2058 const lhs_reg, const lhs_lock = try self.allocReg();
2059 try self.genSetReg(lhs_ty, lhs_reg, lhs);
2060 break :blk .{ lhs_reg, lhs_lock };
2061 };
2062 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
2063
2064 const dest_reg, const dest_lock = try self.allocReg();
2065 defer self.register_manager.unlockReg(dest_lock);
1986 .cmp_eq,
1987 .cmp_neq,
1988 .cmp_gt,
1989 .cmp_gte,
1990 .cmp_lt,
1991 => .pseudo,
20661992
2067 const mir_tag: Mir.Inst.Tag = switch (tag) {
2068 .shl => .slli,
2069 .shr => .srli,
2070 .cmp_gte => .cmp_imm_gte,
2071 .cmp_eq => .cmp_imm_eq,
2072 .cmp_neq => .cmp_imm_neq,
2073 .cmp_lte => .cmp_imm_lte,
2074 .cmp_lt => .cmp_imm_lt,
2075 .add => .addi,
2076 .sub => .addiw,
2077 else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}),
1993 else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
20781994 };
20791995
2080 // apply some special operations needed
20811996 switch (mir_tag) {
2082 .slli,
2083 .srli,
2084 .addi,
2085 .cmp_imm_eq,
2086 .cmp_imm_neq,
2087 .cmp_imm_lte,
2088 .cmp_imm_lt,
1997 .add,
1998 .sub,
1999 .mul,
2000 .sllw,
2001 .srlw,
20892002 => {
2090 _ = try self.addInst(.{
2091 .tag = mir_tag,
2092 .ops = .rri,
2093 .data = .{ .i_type = .{
2094 .rd = dest_reg,
2095 .rs1 = lhs_reg,
2096 .imm12 = Immediate.s(math.cast(i12, rhs.immediate) orelse {
2097 return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
2098 }),
2099 } },
2100 });
2101 },
2102 .addiw => {
2103 _ = try self.addInst(.{
2104 .tag = mir_tag,
2105 .ops = .rri,
2106 .data = .{ .i_type = .{
2107 .rd = dest_reg,
2108 .rs1 = lhs_reg,
2109 .imm12 = Immediate.s(-(math.cast(i12, rhs.immediate) orelse {
2110 return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
2111 })),
2112 } },
2113 });
2114 },
2115 .cmp_imm_gte => {
2116 const imm_reg = try self.copyToTmpRegister(rhs_ty, .{ .immediate = rhs.immediate - 1 });
2117
21182003 _ = try self.addInst(.{
21192004 .tag = mir_tag,
21202005 .ops = .rrr,
2121 .data = .{ .r_type = .{
2122 .rd = dest_reg,
2123 .rs1 = imm_reg,
2124 .rs2 = lhs_reg,
2125 } },
2006 .data = .{
2007 .r_type = .{
2008 .rd = dest_reg,
2009 .rs1 = lhs_reg,
2010 .rs2 = rhs_reg,
2011 },
2012 },
21262013 });
21272014 },
2128 else => unreachable,
2129 }
21302015
2131 return MCValue{ .register = dest_reg };
2132}
2133
2134fn binOpMir(
2135 self: *Self,
2136 mir_tag: Mir.Inst.Tag,
2137 maybe_inst: ?Air.Inst.Index,
2138 ty: Type,
2139 dst_mcv: MCValue,
2140 src_mcv: MCValue,
2141) !void {
2142 const zcu = self.bin_file.comp.module.?;
2143 const abi_size: u32 = @intCast(ty.abiSize(zcu));
2144
2145 _ = abi_size;
2146 _ = maybe_inst;
2147
2148 switch (dst_mcv) {
2149 .register => |dst_reg| {
2150 const src_reg = try self.copyToTmpRegister(ty, src_mcv);
2016 .pseudo => {
2017 const pseudo_op = switch (tag) {
2018 .cmp_eq,
2019 .cmp_neq,
2020 .cmp_gt,
2021 .cmp_gte,
2022 .cmp_lt,
2023 => .pseudo_compare,
2024 else => unreachable,
2025 };
21512026
21522027 _ = try self.addInst(.{
2153 .tag = mir_tag,
2154 .ops = .rrr,
2028 .tag = .pseudo,
2029 .ops = pseudo_op,
21552030 .data = .{
2156 .r_type = .{
2157 .rd = dst_reg,
2158 .rs1 = dst_reg,
2159 .rs2 = src_reg,
2031 .compare = .{
2032 .rd = dest_reg,
2033 .rs1 = lhs_reg,
2034 .rs2 = rhs_reg,
2035 .op = switch (tag) {
2036 .cmp_eq => .eq,
2037 .cmp_neq => .neq,
2038 .cmp_gt => .gt,
2039 .cmp_gte => .gte,
2040 .cmp_lt => .lt,
2041 .cmp_lte => .lte,
2042 else => unreachable,
2043 },
21602044 },
21612045 },
21622046 });
21632047 },
21642048
2165 else => return self.fail("TODO: binOpMir {s}", .{@tagName(dst_mcv)}),
2049 else => unreachable,
21662050 }
2051
2052 // generate the struct for OF checks
2053
2054 return MCValue{ .register = dest_reg };
21672055}
21682056
21692057fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
......@@ -2174,7 +2062,9 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
21742062 const lhs_ty = self.typeOf(bin_op.lhs);
21752063 const rhs_ty = self.typeOf(bin_op.rhs);
21762064
2177 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
2065 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2066 break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
2067 };
21782068 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
21792069}
21802070
......@@ -2200,7 +2090,7 @@ fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
22002090 const lhs_ty = self.typeOf(bin_op.lhs);
22012091 const rhs_ty = self.typeOf(bin_op.rhs);
22022092
2203 break :result try self.binOp(.sub, inst, lhs, rhs, lhs_ty, rhs_ty);
2093 break :result try self.binOp(.sub, lhs, lhs_ty, rhs, rhs_ty);
22042094 };
22052095 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
22062096}
......@@ -2240,7 +2130,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22402130 const lhs_ty = self.typeOf(extra.lhs);
22412131 const rhs_ty = self.typeOf(extra.rhs);
22422132
2243 const add_result_mcv = try self.binOp(.add, null, lhs, rhs, lhs_ty, rhs_ty);
2133 const add_result_mcv = try self.binOp(.add, lhs, lhs_ty, rhs, rhs_ty);
22442134 const add_result_lock = self.register_manager.lockRegAssumeUnused(add_result_mcv.register);
22452135 defer self.register_manager.unlockReg(add_result_lock);
22462136
......@@ -2291,10 +2181,9 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22912181
22922182 const overflow_mcv = try self.binOp(
22932183 .cmp_neq,
2294 null,
22952184 .{ .register = overflow_reg },
2296 .{ .register = add_reg },
22972185 lhs_ty,
2186 .{ .register = add_reg },
22982187 lhs_ty,
22992188 );
23002189
......@@ -2347,7 +2236,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
23472236 switch (int_info.bits) {
23482237 1...32 => {
23492238 if (self.hasFeature(.m)) {
2350 const dest = try self.binOp(.mul, null, lhs, rhs, lhs_ty, rhs_ty);
2239 const dest = try self.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty);
23512240
23522241 const add_result_lock = self.register_manager.lockRegAssumeUnused(dest.register);
23532242 defer self.register_manager.unlockReg(add_result_lock);
......@@ -2393,10 +2282,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
23932282
23942283 const overflow_mcv = try self.binOp(
23952284 .cmp_neq,
2396 null,
23972285 .{ .register = overflow_reg },
2398 .{ .register = add_reg },
23992286 lhs_ty,
2287 .{ .register = add_reg },
24002288 lhs_ty,
24012289 );
24022290
......@@ -2479,7 +2367,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void {
24792367 const lhs_ty = self.typeOf(bin_op.lhs);
24802368 const rhs_ty = self.typeOf(bin_op.rhs);
24812369
2482 break :result try self.binOp(.shl, inst, lhs, rhs, lhs_ty, rhs_ty);
2370 break :result try self.binOp(.shl, lhs, lhs_ty, rhs, rhs_ty);
24832371 };
24842372 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
24852373}
......@@ -2543,10 +2431,9 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
25432431 if (err_off > 0) {
25442432 result = try self.binOp(
25452433 .shr,
2546 null,
25472434 result,
2548 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
25492435 err_union_ty,
2436 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
25502437 Type.u8,
25512438 );
25522439 }
......@@ -2593,10 +2480,9 @@ fn genUnwrapErrUnionPayloadMir(
25932480 if (payload_off > 0) {
25942481 result = try self.binOp(
25952482 .shr,
2596 null,
25972483 result,
2598 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
25992484 err_union_ty,
2485 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
26002486 Type.u8,
26012487 );
26022488 }
......@@ -2837,7 +2723,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
28372723 };
28382724
28392725 const dest = try self.allocRegOrMem(inst, true);
2840 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);
2726 const addr = try self.binOp(.ptr_add, base_mcv, slice_ptr_field_type, index_mcv, Type.usize);
28412727 try self.load(dest, addr, slice_ptr_field_type);
28422728
28432729 break :result dest;
......@@ -2885,13 +2771,14 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
28852771 defer self.register_manager.unlockReg(offset_lock);
28862772
28872773 const dst_mcv = try self.allocRegOrMem(inst, false);
2888 try self.binOpMir(
2889 .add,
2890 null,
2891 Type.usize,
2892 .{ .register = addr_reg },
2893 .{ .register = offset_reg },
2894 );
2774 _ = try self.addInst(.{
2775 .tag = .add,
2776 .ops = .rr,
2777 .data = .{ .rr = .{
2778 .rd = addr_reg,
2779 .rs = offset_reg,
2780 } },
2781 });
28952782 try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
28962783 break :result dst_mcv;
28972784 };
......@@ -3046,7 +2933,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
30462933
30472934 switch (int_bits) {
30482935 16 => {
3049 const temp = try self.binOp(.shr, null, dest_mcv, .{ .immediate = 8 }, ty, Type.u8);
2936 const temp = try self.binOp(.shr, dest_mcv, ty, .{ .immediate = 8 }, Type.u8);
30502937 assert(temp == .register);
30512938 _ = try self.addInst(.{
30522939 .tag = .slli,
......@@ -3752,7 +3639,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
37523639
37533640 const int_info = int_ty.intInfo(zcu);
37543641 if (int_info.bits <= 64) {
3755 break :result try self.binOp(tag, null, lhs, rhs, int_ty, int_ty);
3642 break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty);
37563643 } else {
37573644 return self.fail("TODO riscv cmp for ints > 64 bits", .{});
37583645 }
......@@ -4033,20 +3920,19 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)
40333920 if (err_off > 0) {
40343921 return_mcv = try self.binOp(
40353922 .shr,
4036 null,
40373923 return_mcv,
4038 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
40393924 eu_ty,
3925 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
40403926 Type.u8,
40413927 );
40423928 }
40433929
4044 try self.binOpMir(
3930 return_mcv = try self.binOp(
40453931 .cmp_neq,
4046 null,
4047 Type.anyerror,
40483932 return_mcv,
3933 Type.u16,
40493934 .{ .immediate = 0 },
3935 Type.u16,
40503936 );
40513937
40523938 return return_mcv;
......@@ -4070,8 +3956,8 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC
40703956 switch (is_err_res) {
40713957 .register => |reg| {
40723958 _ = try self.addInst(.{
4073 .tag = .not,
4074 .ops = .rr,
3959 .tag = .pseudo,
3960 .ops = .pseudo_not,
40753961 .data = .{
40763962 .rr = .{
40773963 .rd = reg,
......@@ -4440,9 +4326,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
44404326 dst_mcv,
44414327 try self.resolveInst(src_ref),
44424328 ),
4443 else => return self.fail("TODO implement genCopy for {s} of {}", .{
4444 @tagName(src_mcv), ty.fmt(zcu),
4445 }),
4329 else => unreachable,
44464330 };
44474331 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
44484332
src/arch/riscv64/Encoding.zig+29-3
......@@ -2,9 +2,6 @@ mnemonic: Mnemonic,
22data: Data,
33
44pub const Mnemonic = enum {
5 // R Type
6 add,
7
85 // I Type
96 ld,
107 lw,
......@@ -13,6 +10,10 @@ pub const Mnemonic = enum {
1310 lhu,
1411 lb,
1512 lbu,
13 sltiu,
14 sltu,
15 xori,
16 andi,
1617
1718 addi,
1819 jalr,
......@@ -32,6 +33,12 @@ pub const Mnemonic = enum {
3233 // B Type
3334 beq,
3435
36 // R Type
37 add,
38 slt,
39 mul,
40 xor,
41
3542 // System
3643 ecall,
3744 ebreak,
......@@ -50,8 +57,11 @@ pub const Mnemonic = enum {
5057 .lb => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null },
5158 .lbu => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null },
5259
60 .sltiu => .{ .opcode = 0b0010011, .funct3 = 0b011, .funct7 = null },
5361
5462 .addi => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null },
63 .andi => .{ .opcode = 0b0010011, .funct3 = 0b111, .funct7 = null },
64 .xori => .{ .opcode = 0b0010011, .funct3 = 0b100, .funct7 = null },
5565 .jalr => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null },
5666
5767 .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },
......@@ -65,6 +75,13 @@ pub const Mnemonic = enum {
6575
6676 .beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null },
6777
78 .slt => .{ .opcode = 0b0110011, .funct3 = 0b010, .funct7 = 0b0000000 },
79 .sltu => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 },
80
81 .xor => .{ .opcode = 0b0110011, .funct3 = 0b100, .funct7 = 0b0000000 },
82
83 .mul => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000001 },
84
6885 .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
6986 .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
7087 .unimp => .{ .opcode = 0b0000000, .funct3 = 0b000, .funct7 = null },
......@@ -98,6 +115,9 @@ pub const InstEnc = enum {
98115 .lb,
99116 .lbu,
100117 .jalr,
118 .sltiu,
119 .xori,
120 .andi,
101121 => .I,
102122
103123 .lui,
......@@ -115,6 +135,12 @@ pub const InstEnc = enum {
115135 .beq,
116136 => .B,
117137
138 .slt,
139 .sltu,
140 .mul,
141 .xor,
142 => .R,
143
118144 .ecall,
119145 .ebreak,
120146 .unimp,
src/arch/riscv64/Lower.zig+82-1
......@@ -159,7 +159,83 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
159159 });
160160 },
161161
162 else => return lower.fail("TODO Lower: psuedo {s}", .{@tagName(inst.ops)}),
162 .pseudo_compare => {
163 const compare = inst.data.compare;
164 const op = compare.op;
165
166 const rd = compare.rd;
167 const rs1 = compare.rs1;
168 const rs2 = compare.rs2;
169
170 switch (op) {
171 .eq => {
172 try lower.emit(.xor, &.{
173 .{ .reg = rd },
174 .{ .reg = rs1 },
175 .{ .reg = rs2 },
176 });
177
178 try lower.emit(.sltiu, &.{
179 .{ .reg = rd },
180 .{ .reg = rd },
181 .{ .imm = Immediate.s(1) },
182 });
183 },
184 .neq => {
185 try lower.emit(.xor, &.{
186 .{ .reg = rd },
187 .{ .reg = rs1 },
188 .{ .reg = rs2 },
189 });
190
191 try lower.emit(.sltu, &.{
192 .{ .reg = rd },
193 .{ .reg = .zero },
194 .{ .reg = rd },
195 });
196 },
197 .gt => {
198 try lower.emit(.sltu, &.{
199 .{ .reg = rd },
200 .{ .reg = rs1 },
201 .{ .reg = rs2 },
202 });
203 },
204 .gte => {
205 try lower.emit(.sltu, &.{
206 .{ .reg = rd },
207 .{ .reg = rs1 },
208 .{ .reg = rs2 },
209 });
210
211 try lower.emit(.xori, &.{
212 .{ .reg = rd },
213 .{ .reg = rd },
214 .{ .imm = Immediate.s(1) },
215 });
216 },
217 .lt => {
218 try lower.emit(.slt, &.{
219 .{ .reg = rd },
220 .{ .reg = rs1 },
221 .{ .reg = rs2 },
222 });
223 },
224 else => return lower.fail("TODO lower: pseudo_compare {s}", .{@tagName(op)}),
225 }
226 },
227
228 .pseudo_not => {
229 const rr = inst.data.rr;
230
231 try lower.emit(.xori, &.{
232 .{ .reg = rr.rd },
233 .{ .reg = rr.rs },
234 .{ .imm = Immediate.s(1) },
235 });
236 },
237
238 else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
163239 },
164240 }
165241
......@@ -192,6 +268,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
192268 .{ .reg = inst.data.b_type.rs2 },
193269 .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) },
194270 },
271 .rrr => &.{
272 .{ .reg = inst.data.r_type.rd },
273 .{ .reg = inst.data.r_type.rs1 },
274 .{ .reg = inst.data.r_type.rs2 },
275 },
195276 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
196277 });
197278}
src/arch/riscv64/Mir.zig+17-30
......@@ -67,36 +67,6 @@ pub const Inst = struct {
6767 /// Immediate AND, uses i_type payload
6868 andi,
6969
70 // NOTE: Maybe create a special data for compares that includes the ops
71 /// Register `==`, uses r_type
72 cmp_eq,
73 /// Register `!=`, uses r_type
74 cmp_neq,
75 /// Register `>`, uses r_type
76 cmp_gt,
77 /// Register `<`, uses r_type
78 cmp_lt,
79 /// Register `>=`, uses r_type
80 cmp_gte,
81
82 /// Immediate `>=`, uses r_type
83 ///
84 /// Note: this uses r_type because RISC-V does not provide a good way
85 /// to do `>=` comparisons on immediates. Usually we would just subtract
86 /// 1 from the immediate and do a `>` comparison, however there is no `>`
87 /// register to immedate comparison in RISC-V. This leads us to need to
88 /// allocate a register for temporary use.
89 cmp_imm_gte,
90
91 /// Immediate `==`, uses i_type
92 cmp_imm_eq,
93 /// Immediate `!=`, uses i_type.
94 cmp_imm_neq,
95 /// Immediate `<=`, uses i_type
96 cmp_imm_lte,
97 /// Immediate `<`, uses i_type
98 cmp_imm_lt,
99
10070 /// Branch if equal, Uses b_type
10171 beq,
10272 /// Branch if not equal, Uses b_type
......@@ -213,6 +183,20 @@ pub const Inst = struct {
213183 rd: Register,
214184 rs: Register,
215185 },
186
187 compare: struct {
188 rd: Register,
189 rs1: Register,
190 rs2: Register,
191 op: enum {
192 eq,
193 neq,
194 gt,
195 gte,
196 lt,
197 lte,
198 },
199 },
216200 };
217201
218202 pub const Ops = enum {
......@@ -291,6 +275,9 @@ pub const Inst = struct {
291275
292276 pseudo_restore_regs,
293277 pseudo_spill_regs,
278
279 pseudo_compare,
280 pseudo_not,
294281 };
295282
296283 // Make sure we don't accidentally make instructions bigger than expected.
src/arch/riscv64/abi.zig+10-7
......@@ -130,13 +130,16 @@ pub fn classifySystem(ty: Type, mod: *Module) [8]Class {
130130 unreachable; // support > 128 bit int arguments
131131 },
132132 .ErrorUnion => {
133 const payload = ty.errorUnionPayload(mod);
134 const payload_bits = payload.bitSize(mod);
135 if (payload_bits <= 64) {
136 result[0] = .integer;
137 result[1] = .integer;
138 }
139 unreachable; // support > 64 bit error payloads
133 const payload_ty = ty.errorUnionPayload(mod);
134 const payload_bits = payload_ty.bitSize(mod);
135
136 // the error union itself
137 result[0] = .integer;
138
139 // anyerror!void can fit into one register
140 if (payload_bits == 0) return result;
141
142 std.debug.panic("support ErrorUnion payload {}", .{payload_ty.fmt(mod)});
140143 },
141144 else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
142145 }