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 {...@@ -266,4 +266,6 @@ pub fn mainExtraSimple() !void {
266 };266 };
267 pass_count += 1;267 pass_count += 1;
268 }268 }
269
270 std.posix.exit(pass_count);
269}271}
src/arch/riscv64/CodeGen.zig+94-210
...@@ -1601,7 +1601,6 @@ fn allocReg(self: *Self) !struct { Register, RegisterLock } {...@@ -1601,7 +1601,6 @@ fn allocReg(self: *Self) !struct { Register, RegisterLock } {
1601}1601}
16021602
1603fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {1603fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
1604 log.debug("elemOffset: {}", .{index});
1605 const reg: Register = blk: {1604 const reg: Register = blk: {
1606 switch (index) {1605 switch (index) {
1607 .immediate => |imm| {1606 .immediate => |imm| {
...@@ -1616,14 +1615,14 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi...@@ -1616,14 +1615,14 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi
1616 const lock = self.register_manager.lockRegAssumeUnused(reg);1615 const lock = self.register_manager.lockRegAssumeUnused(reg);
1617 defer self.register_manager.unlockReg(lock);1616 defer self.register_manager.unlockReg(lock);
16181617
1619 try self.binOpMir(1618 const result = try self.binOp(
1620 .mul,1619 .mul,
1621 null,
1622 index_ty,
1623 .{ .register = reg },1620 .{ .register = reg },
1621 index_ty,
1624 .{ .immediate = elem_size },1622 .{ .immediate = elem_size },
1623 index_ty,
1625 );1624 );
1626 break :blk reg;1625 break :blk result.register;
1627 },1626 },
1628 }1627 }
1629 };1628 };
...@@ -1817,24 +1816,10 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -1817,24 +1816,10 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1817 const lhs_ty = self.typeOf(bin_op.lhs);1816 const lhs_ty = self.typeOf(bin_op.lhs);
1818 const rhs_ty = self.typeOf(bin_op.rhs);1817 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);1819 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1821 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1820 break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
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,
1837 };1821 };
1822 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1838}1823}
18391824
1840/// For all your binary operation needs, this function will generate1825/// For all your binary operation needs, this function will generate
...@@ -1854,10 +1839,9 @@ fn supportImmediate(tag: Air.Inst.Tag) bool {...@@ -1854,10 +1839,9 @@ fn supportImmediate(tag: Air.Inst.Tag) bool {
1854fn binOp(1839fn binOp(
1855 self: *Self,1840 self: *Self,
1856 tag: Air.Inst.Tag,1841 tag: Air.Inst.Tag,
1857 maybe_inst: ?Air.Inst.Index,
1858 lhs: MCValue,1842 lhs: MCValue,
1859 rhs: MCValue,
1860 lhs_ty: Type,1843 lhs_ty: Type,
1844 rhs: MCValue,
1861 rhs_ty: Type,1845 rhs_ty: Type,
1862) InnerError!MCValue {1846) InnerError!MCValue {
1863 const zcu = self.bin_file.comp.module.?;1847 const zcu = self.bin_file.comp.module.?;
...@@ -1881,15 +1865,12 @@ fn binOp(...@@ -1881,15 +1865,12 @@ fn binOp(
1881 assert(lhs_ty.eql(rhs_ty, zcu));1865 assert(lhs_ty.eql(rhs_ty, zcu));
1882 const int_info = lhs_ty.intInfo(zcu);1866 const int_info = lhs_ty.intInfo(zcu);
1883 if (int_info.bits <= 64) {1867 if (int_info.bits <= 64) {
1884 if (rhs == .immediate and supportImmediate(tag)) {1868 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
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);
1888 } else {1869 } else {
1889 return self.fail("TODO binary operations on int with bits > 64", .{});1870 return self.fail("TODO binary operations on int with bits > 64", .{});
1890 }1871 }
1891 },1872 },
1892 else => |x| return self.fail("TOOD: binOp {s}", .{@tagName(x)}),1873 else => |x| return std.debug.panic("TOOD: binOp {s}", .{@tagName(x)}),
1893 }1874 }
1894 },1875 },
18951876
...@@ -1912,23 +1893,21 @@ fn binOp(...@@ -1912,23 +1893,21 @@ fn binOp(
1912 else => unreachable,1893 else => unreachable,
1913 };1894 };
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);
1916 } else {1897 } else {
1917 const offset = try self.binOp(1898 const offset = try self.binOp(
1918 .mul,1899 .mul,
1919 null,
1920 rhs,1900 rhs,
1921 .{ .immediate = elem_size },
1922 Type.usize,1901 Type.usize,
1902 .{ .immediate = elem_size },
1923 Type.usize,1903 Type.usize,
1924 );1904 );
19251905
1926 const addr = try self.binOp(1906 const addr = try self.binOp(
1927 tag,1907 tag,
1928 null,
1929 lhs,1908 lhs,
1930 offset,
1931 Type.manyptr_u8,1909 Type.manyptr_u8,
1910 offset,
1932 Type.usize,1911 Type.usize,
1933 );1912 );
1934 return addr;1913 return addr;
...@@ -1948,10 +1927,7 @@ fn binOp(...@@ -1948,10 +1927,7 @@ fn binOp(
1948 .Int => {1927 .Int => {
1949 const int_info = lhs_ty.intInfo(zcu);1928 const int_info = lhs_ty.intInfo(zcu);
1950 if (int_info.bits <= 64) {1929 if (int_info.bits <= 64) {
1951 if (rhs == .immediate) {1930 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
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);
1955 } else {1931 } else {
1956 return self.fail("TODO binary operations on int with bits > 64", .{});1932 return self.fail("TODO binary operations on int with bits > 64", .{});
1957 }1933 }
...@@ -1973,14 +1949,11 @@ fn binOp(...@@ -1973,14 +1949,11 @@ fn binOp(
1973fn binOpRegister(1949fn binOpRegister(
1974 self: *Self,1950 self: *Self,
1975 tag: Air.Inst.Tag,1951 tag: Air.Inst.Tag,
1976 maybe_inst: ?Air.Inst.Index,
1977 lhs: MCValue,1952 lhs: MCValue,
1978 rhs: MCValue,
1979 lhs_ty: Type,1953 lhs_ty: Type,
1954 rhs: MCValue,
1980 rhs_ty: Type,1955 rhs_ty: Type,
1981) !MCValue {1956) !MCValue {
1982 _ = maybe_inst;
1983
1984 const lhs_reg, const lhs_lock = blk: {1957 const lhs_reg, const lhs_lock = blk: {
1985 if (lhs == .register) break :blk .{ lhs.register, null };1958 if (lhs == .register) break :blk .{ lhs.register, null };
19861959
...@@ -2006,164 +1979,79 @@ fn binOpRegister(...@@ -2006,164 +1979,79 @@ fn binOpRegister(
2006 .add => .add,1979 .add => .add,
2007 .sub => .sub,1980 .sub => .sub,
2008 .mul => .mul,1981 .mul => .mul,
2009 .cmp_eq => .cmp_eq,1982
2010 .cmp_neq => .cmp_neq,
2011 .cmp_gt => .cmp_gt,
2012 .cmp_gte => .cmp_gte,
2013 .cmp_lt => .cmp_lt,
2014 .shl => .sllw,1983 .shl => .sllw,
2015 .shr => .srlw,1984 .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 };1986 .cmp_eq,
2034}1987 .cmp_neq,
20351988 .cmp_gt,
2036/// Don't call this function directly. Use binOp instead.1989 .cmp_gte,
2037///1990 .cmp_lt,
2038/// Call this function if rhs is an immediate. Generates I version of binops.1991 => .pseudo,
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);
20661992
2067 const mir_tag: Mir.Inst.Tag = switch (tag) {1993 else => return self.fail("TODO: binOpRegister {s}", .{@tagName(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)}),
2078 };1994 };
20791995
2080 // apply some special operations needed
2081 switch (mir_tag) {1996 switch (mir_tag) {
2082 .slli,1997 .add,
2083 .srli,1998 .sub,
2084 .addi,1999 .mul,
2085 .cmp_imm_eq,2000 .sllw,
2086 .cmp_imm_neq,2001 .srlw,
2087 .cmp_imm_lte,
2088 .cmp_imm_lt,
2089 => {2002 => {
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
2118 _ = try self.addInst(.{2003 _ = try self.addInst(.{
2119 .tag = mir_tag,2004 .tag = mir_tag,
2120 .ops = .rrr,2005 .ops = .rrr,
2121 .data = .{ .r_type = .{2006 .data = .{
2122 .rd = dest_reg,2007 .r_type = .{
2123 .rs1 = imm_reg,2008 .rd = dest_reg,
2124 .rs2 = lhs_reg,2009 .rs1 = lhs_reg,
2125 } },2010 .rs2 = rhs_reg,
2011 },
2012 },
2126 });2013 });
2127 },2014 },
2128 else => unreachable,
2129 }
21302015
2131 return MCValue{ .register = dest_reg };2016 .pseudo => {
2132}2017 const pseudo_op = switch (tag) {
21332018 .cmp_eq,
2134fn binOpMir(2019 .cmp_neq,
2135 self: *Self,2020 .cmp_gt,
2136 mir_tag: Mir.Inst.Tag,2021 .cmp_gte,
2137 maybe_inst: ?Air.Inst.Index,2022 .cmp_lt,
2138 ty: Type,2023 => .pseudo_compare,
2139 dst_mcv: MCValue,2024 else => unreachable,
2140 src_mcv: MCValue,2025 };
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);
21512026
2152 _ = try self.addInst(.{2027 _ = try self.addInst(.{
2153 .tag = mir_tag,2028 .tag = .pseudo,
2154 .ops = .rrr,2029 .ops = pseudo_op,
2155 .data = .{2030 .data = .{
2156 .r_type = .{2031 .compare = .{
2157 .rd = dst_reg,2032 .rd = dest_reg,
2158 .rs1 = dst_reg,2033 .rs1 = lhs_reg,
2159 .rs2 = src_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 },
2160 },2044 },
2161 },2045 },
2162 });2046 });
2163 },2047 },
21642048
2165 else => return self.fail("TODO: binOpMir {s}", .{@tagName(dst_mcv)}),2049 else => unreachable,
2166 }2050 }
2051
2052 // generate the struct for OF checks
2053
2054 return MCValue{ .register = dest_reg };
2167}2055}
21682056
2169fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {2057fn 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...@@ -2174,7 +2062,9 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
2174 const lhs_ty = self.typeOf(bin_op.lhs);2062 const lhs_ty = self.typeOf(bin_op.lhs);
2175 const rhs_ty = self.typeOf(bin_op.rhs);2063 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 };
2178 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2068 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2179}2069}
21802070
...@@ -2200,7 +2090,7 @@ fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {...@@ -2200,7 +2090,7 @@ fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
2200 const lhs_ty = self.typeOf(bin_op.lhs);2090 const lhs_ty = self.typeOf(bin_op.lhs);
2201 const rhs_ty = self.typeOf(bin_op.rhs);2091 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);
2204 };2094 };
2205 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2095 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2206}2096}
...@@ -2240,7 +2130,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2240,7 +2130,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2240 const lhs_ty = self.typeOf(extra.lhs);2130 const lhs_ty = self.typeOf(extra.lhs);
2241 const rhs_ty = self.typeOf(extra.rhs);2131 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);
2244 const add_result_lock = self.register_manager.lockRegAssumeUnused(add_result_mcv.register);2134 const add_result_lock = self.register_manager.lockRegAssumeUnused(add_result_mcv.register);
2245 defer self.register_manager.unlockReg(add_result_lock);2135 defer self.register_manager.unlockReg(add_result_lock);
22462136
...@@ -2291,10 +2181,9 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2291,10 +2181,9 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22912181
2292 const overflow_mcv = try self.binOp(2182 const overflow_mcv = try self.binOp(
2293 .cmp_neq,2183 .cmp_neq,
2294 null,
2295 .{ .register = overflow_reg },2184 .{ .register = overflow_reg },
2296 .{ .register = add_reg },
2297 lhs_ty,2185 lhs_ty,
2186 .{ .register = add_reg },
2298 lhs_ty,2187 lhs_ty,
2299 );2188 );
23002189
...@@ -2347,7 +2236,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2347,7 +2236,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2347 switch (int_info.bits) {2236 switch (int_info.bits) {
2348 1...32 => {2237 1...32 => {
2349 if (self.hasFeature(.m)) {2238 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
2352 const add_result_lock = self.register_manager.lockRegAssumeUnused(dest.register);2241 const add_result_lock = self.register_manager.lockRegAssumeUnused(dest.register);
2353 defer self.register_manager.unlockReg(add_result_lock);2242 defer self.register_manager.unlockReg(add_result_lock);
...@@ -2393,10 +2282,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2393,10 +2282,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
23932282
2394 const overflow_mcv = try self.binOp(2283 const overflow_mcv = try self.binOp(
2395 .cmp_neq,2284 .cmp_neq,
2396 null,
2397 .{ .register = overflow_reg },2285 .{ .register = overflow_reg },
2398 .{ .register = add_reg },
2399 lhs_ty,2286 lhs_ty,
2287 .{ .register = add_reg },
2400 lhs_ty,2288 lhs_ty,
2401 );2289 );
24022290
...@@ -2479,7 +2367,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void {...@@ -2479,7 +2367,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void {
2479 const lhs_ty = self.typeOf(bin_op.lhs);2367 const lhs_ty = self.typeOf(bin_op.lhs);
2480 const rhs_ty = self.typeOf(bin_op.rhs);2368 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);
2483 };2371 };
2484 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2372 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2485}2373}
...@@ -2543,10 +2431,9 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2543,10 +2431,9 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
2543 if (err_off > 0) {2431 if (err_off > 0) {
2544 result = try self.binOp(2432 result = try self.binOp(
2545 .shr,2433 .shr,
2546 null,
2547 result,2434 result,
2548 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
2549 err_union_ty,2435 err_union_ty,
2436 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
2550 Type.u8,2437 Type.u8,
2551 );2438 );
2552 }2439 }
...@@ -2593,10 +2480,9 @@ fn genUnwrapErrUnionPayloadMir(...@@ -2593,10 +2480,9 @@ fn genUnwrapErrUnionPayloadMir(
2593 if (payload_off > 0) {2480 if (payload_off > 0) {
2594 result = try self.binOp(2481 result = try self.binOp(
2595 .shr,2482 .shr,
2596 null,
2597 result,2483 result,
2598 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
2599 err_union_ty,2484 err_union_ty,
2485 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
2600 Type.u8,2486 Type.u8,
2601 );2487 );
2602 }2488 }
...@@ -2837,7 +2723,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2837,7 +2723,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2837 };2723 };
28382724
2839 const dest = try self.allocRegOrMem(inst, true);2725 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);
2841 try self.load(dest, addr, slice_ptr_field_type);2727 try self.load(dest, addr, slice_ptr_field_type);
28422728
2843 break :result dest;2729 break :result dest;
...@@ -2885,13 +2771,14 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2885,13 +2771,14 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2885 defer self.register_manager.unlockReg(offset_lock);2771 defer self.register_manager.unlockReg(offset_lock);
28862772
2887 const dst_mcv = try self.allocRegOrMem(inst, false);2773 const dst_mcv = try self.allocRegOrMem(inst, false);
2888 try self.binOpMir(2774 _ = try self.addInst(.{
2889 .add,2775 .tag = .add,
2890 null,2776 .ops = .rr,
2891 Type.usize,2777 .data = .{ .rr = .{
2892 .{ .register = addr_reg },2778 .rd = addr_reg,
2893 .{ .register = offset_reg },2779 .rs = offset_reg,
2894 );2780 } },
2781 });
2895 try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });2782 try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
2896 break :result dst_mcv;2783 break :result dst_mcv;
2897 };2784 };
...@@ -3046,7 +2933,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {...@@ -3046,7 +2933,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
30462933
3047 switch (int_bits) {2934 switch (int_bits) {
3048 16 => {2935 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);
3050 assert(temp == .register);2937 assert(temp == .register);
3051 _ = try self.addInst(.{2938 _ = try self.addInst(.{
3052 .tag = .slli,2939 .tag = .slli,
...@@ -3752,7 +3639,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {...@@ -3752,7 +3639,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
37523639
3753 const int_info = int_ty.intInfo(zcu);3640 const int_info = int_ty.intInfo(zcu);
3754 if (int_info.bits <= 64) {3641 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);
3756 } else {3643 } else {
3757 return self.fail("TODO riscv cmp for ints > 64 bits", .{});3644 return self.fail("TODO riscv cmp for ints > 64 bits", .{});
3758 }3645 }
...@@ -4033,20 +3920,19 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)...@@ -4033,20 +3920,19 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)
4033 if (err_off > 0) {3920 if (err_off > 0) {
4034 return_mcv = try self.binOp(3921 return_mcv = try self.binOp(
4035 .shr,3922 .shr,
4036 null,
4037 return_mcv,3923 return_mcv,
4038 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
4039 eu_ty,3924 eu_ty,
3925 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
4040 Type.u8,3926 Type.u8,
4041 );3927 );
4042 }3928 }
40433929
4044 try self.binOpMir(3930 return_mcv = try self.binOp(
4045 .cmp_neq,3931 .cmp_neq,
4046 null,
4047 Type.anyerror,
4048 return_mcv,3932 return_mcv,
3933 Type.u16,
4049 .{ .immediate = 0 },3934 .{ .immediate = 0 },
3935 Type.u16,
4050 );3936 );
40513937
4052 return return_mcv;3938 return return_mcv;
...@@ -4070,8 +3956,8 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC...@@ -4070,8 +3956,8 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC
4070 switch (is_err_res) {3956 switch (is_err_res) {
4071 .register => |reg| {3957 .register => |reg| {
4072 _ = try self.addInst(.{3958 _ = try self.addInst(.{
4073 .tag = .not,3959 .tag = .pseudo,
4074 .ops = .rr,3960 .ops = .pseudo_not,
4075 .data = .{3961 .data = .{
4076 .rr = .{3962 .rr = .{
4077 .rd = reg,3963 .rd = reg,
...@@ -4440,9 +4326,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {...@@ -4440,9 +4326,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
4440 dst_mcv,4326 dst_mcv,
4441 try self.resolveInst(src_ref),4327 try self.resolveInst(src_ref),
4442 ),4328 ),
4443 else => return self.fail("TODO implement genCopy for {s} of {}", .{4329 else => unreachable,
4444 @tagName(src_mcv), ty.fmt(zcu),
4445 }),
4446 };4330 };
4447 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);4331 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,...@@ -2,9 +2,6 @@ mnemonic: Mnemonic,
2data: Data,2data: Data,
33
4pub const Mnemonic = enum {4pub const Mnemonic = enum {
5 // R Type
6 add,
7
8 // I Type5 // I Type
9 ld,6 ld,
10 lw,7 lw,
...@@ -13,6 +10,10 @@ pub const Mnemonic = enum {...@@ -13,6 +10,10 @@ pub const Mnemonic = enum {
13 lhu,10 lhu,
14 lb,11 lb,
15 lbu,12 lbu,
13 sltiu,
14 sltu,
15 xori,
16 andi,
1617
17 addi,18 addi,
18 jalr,19 jalr,
...@@ -32,6 +33,12 @@ pub const Mnemonic = enum {...@@ -32,6 +33,12 @@ pub const Mnemonic = enum {
32 // B Type33 // B Type
33 beq,34 beq,
3435
36 // R Type
37 add,
38 slt,
39 mul,
40 xor,
41
35 // System42 // System
36 ecall,43 ecall,
37 ebreak,44 ebreak,
...@@ -50,8 +57,11 @@ pub const Mnemonic = enum {...@@ -50,8 +57,11 @@ pub const Mnemonic = enum {
50 .lb => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null },57 .lb => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null },
51 .lbu => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null },58 .lbu => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null },
5259
60 .sltiu => .{ .opcode = 0b0010011, .funct3 = 0b011, .funct7 = null },
5361
54 .addi => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null },62 .addi => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null },
63 .andi => .{ .opcode = 0b0010011, .funct3 = 0b111, .funct7 = null },
64 .xori => .{ .opcode = 0b0010011, .funct3 = 0b100, .funct7 = null },
55 .jalr => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null },65 .jalr => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null },
5666
57 .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },67 .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },
...@@ -65,6 +75,13 @@ pub const Mnemonic = enum {...@@ -65,6 +75,13 @@ pub const Mnemonic = enum {
6575
66 .beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null },76 .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
68 .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },85 .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
69 .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },86 .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
70 .unimp => .{ .opcode = 0b0000000, .funct3 = 0b000, .funct7 = null },87 .unimp => .{ .opcode = 0b0000000, .funct3 = 0b000, .funct7 = null },
...@@ -98,6 +115,9 @@ pub const InstEnc = enum {...@@ -98,6 +115,9 @@ pub const InstEnc = enum {
98 .lb,115 .lb,
99 .lbu,116 .lbu,
100 .jalr,117 .jalr,
118 .sltiu,
119 .xori,
120 .andi,
101 => .I,121 => .I,
102122
103 .lui,123 .lui,
...@@ -115,6 +135,12 @@ pub const InstEnc = enum {...@@ -115,6 +135,12 @@ pub const InstEnc = enum {
115 .beq,135 .beq,
116 => .B,136 => .B,
117137
138 .slt,
139 .sltu,
140 .mul,
141 .xor,
142 => .R,
143
118 .ecall,144 .ecall,
119 .ebreak,145 .ebreak,
120 .unimp,146 .unimp,
src/arch/riscv64/Lower.zig+82-1
...@@ -159,7 +159,83 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -159,7 +159,83 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
159 });159 });
160 },160 },
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)}),
163 },239 },
164 }240 }
165241
...@@ -192,6 +268,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -192,6 +268,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
192 .{ .reg = inst.data.b_type.rs2 },268 .{ .reg = inst.data.b_type.rs2 },
193 .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) },269 .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) },
194 },270 },
271 .rrr => &.{
272 .{ .reg = inst.data.r_type.rd },
273 .{ .reg = inst.data.r_type.rs1 },
274 .{ .reg = inst.data.r_type.rs2 },
275 },
195 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),276 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
196 });277 });
197}278}
src/arch/riscv64/Mir.zig+17-30
...@@ -67,36 +67,6 @@ pub const Inst = struct {...@@ -67,36 +67,6 @@ pub const Inst = struct {
67 /// Immediate AND, uses i_type payload67 /// Immediate AND, uses i_type payload
68 andi,68 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
100 /// Branch if equal, Uses b_type70 /// Branch if equal, Uses b_type
101 beq,71 beq,
102 /// Branch if not equal, Uses b_type72 /// Branch if not equal, Uses b_type
...@@ -213,6 +183,20 @@ pub const Inst = struct {...@@ -213,6 +183,20 @@ pub const Inst = struct {
213 rd: Register,183 rd: Register,
214 rs: Register,184 rs: Register,
215 },185 },
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 },
216 };200 };
217201
218 pub const Ops = enum {202 pub const Ops = enum {
...@@ -291,6 +275,9 @@ pub const Inst = struct {...@@ -291,6 +275,9 @@ pub const Inst = struct {
291275
292 pseudo_restore_regs,276 pseudo_restore_regs,
293 pseudo_spill_regs,277 pseudo_spill_regs,
278
279 pseudo_compare,
280 pseudo_not,
294 };281 };
295282
296 // Make sure we don't accidentally make instructions bigger than expected.283 // 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 {...@@ -130,13 +130,16 @@ pub fn classifySystem(ty: Type, mod: *Module) [8]Class {
130 unreachable; // support > 128 bit int arguments130 unreachable; // support > 128 bit int arguments
131 },131 },
132 .ErrorUnion => {132 .ErrorUnion => {
133 const payload = ty.errorUnionPayload(mod);133 const payload_ty = ty.errorUnionPayload(mod);
134 const payload_bits = payload.bitSize(mod);134 const payload_bits = payload_ty.bitSize(mod);
135 if (payload_bits <= 64) {135
136 result[0] = .integer;136 // the error union itself
137 result[1] = .integer;137 result[0] = .integer;
138 }138
139 unreachable; // support > 64 bit error payloads139 // 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)});
140 },143 },
141 else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),144 else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
142 }145 }