Commit a30af172e8

David Rubin <daviru007@icloud.com>
2024-04-17 01:39:31
riscv: math progress
1 parent a615fbc
src/arch/riscv64/CodeGen.zig
@@ -11,6 +11,7 @@ const Type = @import("../../type.zig").Type;
 const Value = @import("../../Value.zig");
 const link = @import("../../link.zig");
 const Module = @import("../../Module.zig");
+const Package = @import("../../Package.zig");
 const InternPool = @import("../../InternPool.zig");
 const Compilation = @import("../../Compilation.zig");
 const ErrorMsg = Module.ErrorMsg;
@@ -54,6 +55,7 @@ const RegisterView = enum(u1) {
 
 gpa: Allocator,
 air: Air,
+mod: *Package.Module,
 liveness: Liveness,
 bin_file: *link.File,
 target: *const std.Target,
@@ -724,6 +726,7 @@ pub fn generate(
     var function = Self{
         .gpa = gpa,
         .air = air,
+        .mod = mod,
         .liveness = liveness,
         .target = target,
         .bin_file = bin_file,
@@ -2138,82 +2141,78 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
         const lhs_ty = self.typeOf(extra.lhs);
         const rhs_ty = self.typeOf(extra.rhs);
 
-        const add_result_mcv = try self.binOp(.add, lhs, lhs_ty, rhs, rhs_ty);
-        const add_result_lock = self.register_manager.lockRegAssumeUnused(add_result_mcv.register);
-        defer self.register_manager.unlockReg(add_result_lock);
-
-        const tuple_ty = self.typeOfIndex(inst);
         const int_info = lhs_ty.intInfo(zcu);
 
-        // TODO: optimization, set this to true. needs the other struct access stuff to support
-        // accessing registers.
+        const tuple_ty = self.typeOfIndex(inst);
         const result_mcv = try self.allocRegOrMem(inst, false);
         const offset = result_mcv.load_frame;
 
-        try self.genSetStack(
-            lhs_ty,
-            .{
-                .index = offset.index,
-                .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
-            },
-            add_result_mcv,
-        );
-
         if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
-            if (int_info.signedness == .unsigned) {
-                switch (int_info.bits) {
-                    1...8 => {
-                        const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
+            const add_result = try self.binOp(.add, lhs, lhs_ty, rhs, rhs_ty);
+            const add_result_reg = try self.copyToTmpRegister(lhs_ty, add_result);
+            const add_result_reg_lock = self.register_manager.lockRegAssumeUnused(add_result_reg);
+            defer self.register_manager.unlockReg(add_result_reg_lock);
 
-                        const overflow_reg, const overflow_lock = try self.allocReg();
-                        defer self.register_manager.unlockReg(overflow_lock);
+            const shift_amount: u6 = @intCast(Type.usize.bitSize(zcu) - int_info.bits);
 
-                        const add_reg, const add_lock = blk: {
-                            if (add_result_mcv == .register) break :blk .{ add_result_mcv.register, null };
+            const shift_reg, const shift_lock = try self.allocReg();
+            defer self.register_manager.unlockReg(shift_lock);
 
-                            const add_reg, const add_lock = try self.allocReg();
-                            try self.genSetReg(lhs_ty, add_reg, add_result_mcv);
-                            break :blk .{ add_reg, add_lock };
-                        };
-                        defer if (add_lock) |lock| self.register_manager.unlockReg(lock);
-
-                        _ = try self.addInst(.{
-                            .tag = .andi,
-                            .ops = .rri,
-                            .data = .{ .i_type = .{
-                                .rd = overflow_reg,
-                                .rs1 = add_reg,
-                                .imm12 = Immediate.s(max_val),
-                            } },
-                        });
-
-                        const overflow_mcv = try self.binOp(
-                            .cmp_neq,
-                            .{ .register = overflow_reg },
-                            lhs_ty,
-                            .{ .register = add_reg },
-                            lhs_ty,
-                        );
-
-                        try self.genSetStack(
-                            Type.u1,
-                            .{
-                                .index = offset.index,
-                                .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
-                            },
-                            overflow_mcv,
-                        );
+            _ = try self.addInst(.{
+                .tag = .slli,
+                .ops = .rri,
+                .data = .{
+                    .i_type = .{
+                        .rd = shift_reg,
+                        .rs1 = add_result_reg,
+                        .imm12 = Immediate.s(shift_amount),
+                    },
+                },
+            });
 
-                        break :result result_mcv;
+            _ = try self.addInst(.{
+                .tag = if (int_info.signedness == .unsigned) .srli else .srai,
+                .ops = .rri,
+                .data = .{
+                    .i_type = .{
+                        .rd = shift_reg,
+                        .rs1 = shift_reg,
+                        .imm12 = Immediate.s(shift_amount),
                     },
+                },
+            });
 
-                    else => return self.fail("TODO: addWithOverflow check for size {d}", .{int_info.bits}),
-                }
-            } else {
-                return self.fail("TODO: airAddWithOverFlow calculate carry for signed addition", .{});
-            }
+            const add_result_frame: FrameAddr = .{
+                .index = offset.index,
+                .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
+            };
+            try self.genSetStack(
+                lhs_ty,
+                add_result_frame,
+                add_result,
+            );
+
+            const overflow_mcv = try self.binOp(
+                .cmp_neq,
+                .{ .register = shift_reg },
+                lhs_ty,
+                .{ .register = add_result_reg },
+                lhs_ty,
+            );
+
+            const overflow_frame: FrameAddr = .{
+                .index = offset.index,
+                .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
+            };
+            try self.genSetStack(
+                Type.u1,
+                overflow_frame,
+                overflow_mcv,
+            );
+
+            break :result result_mcv;
         } else {
-            return self.fail("TODO: airAddWithOverflow with < 8 bits or non-pow of 2", .{});
+            return self.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
         }
     };
 
@@ -3500,9 +3499,11 @@ fn genCall(
                         if (self.bin_file.cast(link.File.Elf)) |elf_file| {
                             const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
                             const sym = elf_file.symbol(sym_index);
+
                             _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
                             const got_addr = sym.zigGotAddress(elf_file);
                             try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr });
+
                             _ = try self.addInst(.{
                                 .tag = .jalr,
                                 .ops = .rri,
src/arch/riscv64/Encoding.zig
@@ -16,6 +16,7 @@ pub const Mnemonic = enum {
     andi,
     slli,
     srli,
+    srai,
 
     addi,
     jalr,
@@ -69,6 +70,7 @@ pub const Mnemonic = enum {
             .jalr   => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null      },
             .slli   => .{ .opcode = 0b0010011, .funct3 = 0b001, .funct7 = null      },
             .srli   => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null      },
+            .srai   => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null,   .offset = 1 << 10  },
 
             .lui    => .{ .opcode = 0b0110111, .funct3 = null,  .funct7 = null      },
 
@@ -123,6 +125,7 @@ pub const InstEnc = enum {
             .andi,
             .slli,
             .srli,
+            .srai,
             => .I,
 
             .lui,
@@ -299,7 +302,7 @@ pub const Data = union(InstEnc) {
                     .I = .{
                         .rd = ops[0].reg.id(),
                         .rs1 = ops[1].reg.id(),
-                        .imm0_11 = ops[2].imm.asBits(u12),
+                        .imm0_11 = ops[2].imm.asBits(u12) + enc.offset,
 
                         .opcode = enc.opcode,
                         .funct3 = enc.funct3.?,
@@ -374,6 +377,7 @@ const Enc = struct {
     opcode: u7,
     funct3: ?u3,
     funct7: ?u7,
+    offset: u12 = 0,
 };
 
 fn verifyOps(mnem: Mnemonic, ops: []const Operand) bool {
src/arch/riscv64/Mir.zig
@@ -53,6 +53,8 @@ pub const Inst = struct {
         srli,
         /// Immediate Logical Left Shift, uses i_type payload
         slli,
+        /// Immediate Arithmetic Right Shift, uses i_type payload.
+        srai,
         /// Register Logical Left Shift, uses r_type payload
         sllw,
         /// Register Logical Right Shit, uses r_type payload
test/behavior/align.zig
@@ -44,7 +44,6 @@ test "default alignment allows unspecified in type syntax" {
 }
 
 test "implicitly decreasing pointer alignment" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
     const a: u32 align(4) = 3;
     const b: u32 align(8) = 4;
     try expect(addUnaligned(&a, &b) == 7);
@@ -227,7 +226,6 @@ fn fnWithAlignedStack() i32 {
 }
 
 test "implicitly decreasing slice alignment" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 
test/behavior/array.zig
@@ -203,7 +203,6 @@ test "nested arrays of strings" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
     for (array_of_strings, 0..) |s, i| {
@@ -329,7 +328,6 @@ test "read/write through global variable array of struct fields initialized via
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = struct {
         fn doTheTest() !void {
@@ -738,8 +736,6 @@ test "pointer to array has ptr field" {
 }
 
 test "discarded array init preserves result location" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     const S = struct {
         fn f(p: *u32) u16 {
             p.* += 1;
test/behavior/basic.zig
@@ -85,8 +85,6 @@ test "type equality" {
 }
 
 test "pointer dereferencing" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var x = @as(i32, 3);
     const y = &x;
 
@@ -138,21 +136,18 @@ fn first4KeysOfHomeRow() []const u8 {
 
 test "return string from function" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
 }
 
 test "hex escape" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
 }
 
 test "multiline string" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const s1 =
         \\one
@@ -165,7 +160,6 @@ test "multiline string" {
 
 test "multiline string comments at start" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const s1 =
         //\\one
@@ -178,7 +172,6 @@ test "multiline string comments at start" {
 
 test "multiline string comments at end" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const s1 =
         \\one
@@ -191,7 +184,6 @@ test "multiline string comments at end" {
 
 test "multiline string comments in middle" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const s1 =
         \\one
@@ -204,7 +196,6 @@ test "multiline string comments in middle" {
 
 test "multiline string comments at multiple places" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const s1 =
         \\one
@@ -218,14 +209,11 @@ test "multiline string comments at multiple places" {
 }
 
 test "string concatenation simple" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
 }
 
 test "array mult operator" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try expect(mem.eql(u8, "ab" ** 5, "ababababab"));
 }
@@ -308,8 +296,6 @@ test "function closes over local const" {
 }
 
 test "volatile load and store" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var number: i32 = 1234;
     const ptr = @as(*volatile i32, &number);
     ptr.* += 1;
@@ -326,7 +312,6 @@ fn fB() []const u8 {
 test "call function pointer in struct" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try expect(mem.eql(u8, f3(true), "a"));
     try expect(mem.eql(u8, f3(false), "b"));
@@ -350,7 +335,6 @@ const FnPtrWrapper = struct {
 
 test "const ptr from var variable" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var x: u64 = undefined;
     var y: u64 = undefined;
@@ -370,7 +354,6 @@ test "call result of if else expression" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try expect(mem.eql(u8, f2(true), "a"));
     try expect(mem.eql(u8, f2(false), "b"));
@@ -479,7 +462,6 @@ fn nine() u8 {
 test "struct inside function" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try testStructInFn();
     try comptime testStructInFn();
@@ -1219,7 +1201,6 @@ test "integer compare" {
 
 test "reference to inferred local variable works as expected" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const Crasher = struct {
         lets_crash: u64 = 0,
test/behavior/bitcast.zig
@@ -520,7 +520,6 @@ test "@bitCast of packed struct of bools all false" {
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const P = packed struct {
         b0: bool,
test/behavior/call.zig
@@ -572,8 +572,6 @@ test "call function pointer in comptime field" {
 }
 
 test "generic function pointer can be called" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     const S = struct {
         var ok = false;
         fn foo(x: anytype) void {
test/behavior/cast.zig
@@ -400,7 +400,6 @@ test "cast from ?[*]T to ??[*]T" {
 test "peer type unsigned int to signed" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var w: u31 = 5;
     var x: u8 = 7;
@@ -443,7 +442,6 @@ test "peer resolve array and const slice" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try testPeerResolveArrayConstSlice(true);
     try comptime testPeerResolveArrayConstSlice(true);
@@ -535,7 +533,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
 test "implicit cast from *const [N]T to []const T" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try testCastConstArrayRefToConstSlice();
     try comptime testCastConstArrayRefToConstSlice();
@@ -718,7 +715,6 @@ test "peer type resolution: error set supersets" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const a: error{ One, Two } = undefined;
     const b: error{One} = undefined;
@@ -748,7 +744,6 @@ test "peer type resolution: disjoint error sets" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const a: error{ One, Two } = undefined;
     const b: error{Three} = undefined;
@@ -813,7 +808,6 @@ test "peer type resolution: error union after non-error" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const a: u32 = undefined;
     const b: error{ One, Two }!u32 = undefined;
@@ -1393,7 +1387,6 @@ test "cast between *[N]void and []void" {
 test "peer resolve arrays of different size to const slice" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try expect(mem.eql(u8, boolToStr(true), "true"));
     try expect(mem.eql(u8, boolToStr(false), "false"));
test/behavior/decltest.zig
@@ -5,7 +5,5 @@ pub fn the_add_function(a: u32, b: u32) u32 {
 }
 
 test the_add_function {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     if (the_add_function(1, 2) != 3) unreachable;
 }
test/behavior/defer.zig
@@ -5,8 +5,6 @@ const expectEqual = std.testing.expectEqual;
 const expectError = std.testing.expectError;
 
 test "break and continue inside loop inside defer expression" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     testBreakContInDefer(10);
     comptime testBreakContInDefer(10);
 }
@@ -23,8 +21,6 @@ fn testBreakContInDefer(x: usize) void {
 }
 
 test "defer and labeled break" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var i = @as(usize, 0);
 
     blk: {
@@ -38,7 +34,6 @@ test "defer and labeled break" {
 test "errdefer does not apply to fn inside fn" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
 }
test/behavior/enum.zig
@@ -1055,7 +1055,6 @@ test "tag name with assigned enum values" {
 test "@tagName on enum literals" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
     comptime assert(mem.eql(u8, @tagName(.FooBar), "FooBar"));
test/behavior/eval.zig
@@ -306,8 +306,6 @@ fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
 }
 
 test "comptime iterate over fn ptr list" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     try expect(performFn('t', 1) == 6);
     try expect(performFn('o', 0) == 1);
     try expect(performFn('w', 99) == 99);
@@ -413,8 +411,6 @@ var st_init_str_foo = StInitStrFoo{
 };
 
 test "inline for with same type but different values" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var res: usize = 0;
     inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| {
         var a: T = undefined;
@@ -544,7 +540,6 @@ test "runtime 128 bit integer division" {
 test "@tagName of @typeInfo" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const str = @tagName(@typeInfo(u8));
     try expect(std.mem.eql(u8, str, "Int"));
@@ -1007,7 +1002,6 @@ test "closure capture type of runtime-known var" {
 
 test "comptime break passing through runtime condition converted to runtime break" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = struct {
         fn doTheTest() !void {
@@ -1042,7 +1036,6 @@ test "comptime break to outer loop passing through runtime condition converted t
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = struct {
         fn doTheTest() !void {
@@ -1266,7 +1259,6 @@ test "pass pointer to field of comptime-only type as a runtime parameter" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = struct {
         const Mixed = struct {
@@ -1508,7 +1500,6 @@ test "continue nested inline for loop in named block expr" {
 
 test "x and false is comptime-known false" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const T = struct {
         var x: u32 = 0;
@@ -1536,7 +1527,6 @@ test "x and false is comptime-known false" {
 
 test "x or true is comptime-known true" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const T = struct {
         var x: u32 = 0;
@@ -1598,8 +1588,6 @@ test "comptime function turns function value to function pointer" {
 }
 
 test "container level const and var have unique addresses" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     const S = struct {
         x: i32,
         y: i32,
test/behavior/export_keyword.zig
@@ -26,7 +26,6 @@ const PackedUnion = packed union {
 test "packed struct, enum, union parameters in extern function" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     testPackedStuff(&(PackedStruct{
         .a = 1,
test/behavior/fn.zig
@@ -6,8 +6,6 @@ const expect = testing.expect;
 const expectEqual = testing.expectEqual;
 
 test "params" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     try expect(testParamsAdd(22, 11) == 33);
 }
 fn testParamsAdd(a: i32, b: i32) i32 {
@@ -15,8 +13,6 @@ fn testParamsAdd(a: i32, b: i32) i32 {
 }
 
 test "local variables" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     testLocVars(2);
 }
 fn testLocVars(b: i32) void {
@@ -25,8 +21,6 @@ fn testLocVars(b: i32) void {
 }
 
 test "mutable local variables" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var zero: i32 = 0;
     _ = &zero;
     try expect(zero == 0);
@@ -325,7 +319,6 @@ test "function pointers" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const fns = [_]*const @TypeOf(fn1){
         &fn1,
@@ -403,8 +396,6 @@ test "function call with anon list literal - 2D" {
 }
 
 test "ability to give comptime types and non comptime types to same parameter" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     const S = struct {
         fn doTheTest() !void {
             var x: i32 = 1;
test/behavior/for.zig
@@ -7,7 +7,6 @@ const mem = std.mem;
 test "continue in for loop" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const array = [_]i32{ 1, 2, 3, 4, 5 };
     var sum: i32 = 0;
@@ -22,8 +21,6 @@ test "continue in for loop" {
 }
 
 test "break from outer for loop" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     try testBreakOuter();
     try comptime testBreakOuter();
 }
@@ -41,8 +38,6 @@ fn testBreakOuter() !void {
 }
 
 test "continue outer for loop" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     try testContinueOuter();
     try comptime testContinueOuter();
 }
@@ -263,7 +258,6 @@ test "for loop with else branch" {
 test "count over fixed range" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var sum: usize = 0;
     for (0..6) |i| {
@@ -276,7 +270,6 @@ test "count over fixed range" {
 test "two counters" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var sum: usize = 0;
     for (0..10, 10..20) |i, j| {
test/behavior/generics.zig
@@ -5,8 +5,6 @@ const expect = testing.expect;
 const expectEqual = testing.expectEqual;
 
 test "one param, explicit comptime" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var x: usize = 0;
     x += checkSize(i32);
     x += checkSize(bool);
@@ -151,8 +149,6 @@ fn GenericDataThing(comptime count: isize) type {
 }
 
 test "use generic param in generic param" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     try expect(aGenericFn(i32, 3, 4) == 7);
 }
 fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
@@ -258,7 +254,6 @@ test "generic function instantiation turns into comptime call" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = struct {
         fn doTheTest() !void {
test/behavior/globals.zig
@@ -50,7 +50,6 @@ test "global loads can affect liveness" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = struct {
         const ByRef = struct {
test/behavior/packed-struct.zig
@@ -889,7 +889,6 @@ test "runtime init of unnamed packed struct type" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var z: u8 = 123;
     _ = &z;
test/behavior/pointers.zig
@@ -6,8 +6,6 @@ const expect = testing.expect;
 const expectError = testing.expectError;
 
 test "dereference pointer" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     try comptime testDerefPtr();
     try testDerefPtr();
 }
@@ -55,7 +53,6 @@ fn PtrOf(comptime T: type) type {
 
 test "implicit cast single item pointer to C pointer and back" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var y: u8 = 11;
     const x: [*c]u8 = &y;
test/behavior/ptrcast.zig
@@ -176,7 +176,6 @@ test "reinterpret struct field at comptime" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const numNative = comptime Bytes.init(0x12345678);
     if (native_endian != .little) {
test/behavior/sizeof_and_typeof.zig
@@ -144,8 +144,6 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" {
 }
 
 test "@TypeOf() has no runtime side effects" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     const S = struct {
         fn foo(comptime T: type, ptr: *T) T {
             ptr.* += 1;
@@ -438,8 +436,6 @@ test "Extern function calls, dereferences and field access in @TypeOf" {
 }
 
 test "@sizeOf struct is resolved when used as operand of slicing" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     const dummy = struct {};
     const S = struct {
         var buf: [1]u8 = undefined;
test/behavior/slice.zig
@@ -176,7 +176,6 @@ test "comptime pointer cast array and then slice" {
 test "slicing zero length array" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const s1 = ""[0..];
     const s2 = ([_]u32{})[0..];
@@ -738,7 +737,6 @@ test "array mult of slice gives ptr to array" {
 
 test "slice bounds in comptime concatenation" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const bs = comptime blk: {
         const b = "........1........";
test/behavior/string_literals.zig
@@ -8,7 +8,6 @@ const ptr_tag_name: [*:0]const u8 = tag_name;
 test "@tagName() returns a string literal" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try std.testing.expect(*const [13:0]u8 == @TypeOf(tag_name));
     try std.testing.expect(std.mem.eql(u8, "TestEnumValue", tag_name));
@@ -22,7 +21,6 @@ const ptr_error_name: [*:0]const u8 = error_name;
 test "@errorName() returns a string literal" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try std.testing.expect(*const [13:0]u8 == @TypeOf(error_name));
     try std.testing.expect(std.mem.eql(u8, "TestErrorCode", error_name));
test/behavior/struct.zig
@@ -12,7 +12,6 @@ top_level_field: i32,
 test "top level fields" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var instance = @This(){
         .top_level_field = 1234,
@@ -125,8 +124,6 @@ test "struct byval assign" {
 }
 
 test "call struct static method" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     const result = StructWithNoFields.add(3, 4);
     try expect(result == 7);
 }
@@ -759,7 +756,6 @@ test "packed struct with u0 field access" {
 test "access to global struct fields" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     g_foo.bar.value = 42;
     try expect(g_foo.bar.value == 42);
@@ -2134,7 +2130,6 @@ test "struct field default value is a call" {
 
 test "aggregate initializers should allow initializing comptime fields, verifying equality" {
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var x: u32 = 15;
     _ = &x;
test/behavior/this.zig
@@ -21,8 +21,6 @@ fn add(x: i32, y: i32) i32 {
 }
 
 test "this refer to module call private fn" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     try expect(module.add(1, 2) == 3);
 }
 
test/behavior/tuple.zig
@@ -258,7 +258,6 @@ test "offsetOf anon struct" {
 test "initializing tuple with mixed comptime-runtime fields" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var x: u32 = 15;
     _ = &x;
@@ -271,7 +270,6 @@ test "initializing tuple with mixed comptime-runtime fields" {
 test "initializing anon struct with mixed comptime-runtime fields" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var x: u32 = 15;
     _ = &x;
test/behavior/type_info.zig
@@ -161,7 +161,6 @@ test "type info: error set, error union info, anyerror" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try testErrorSet();
     try comptime testErrorSet();
@@ -193,7 +192,6 @@ test "type info: error set single value" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const TestSet = error.One;
 
@@ -207,7 +205,6 @@ test "type info: error set merged" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const TestSet = error{ One, Two } || error{Three};
 
@@ -223,7 +220,6 @@ test "type info: enum info" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try testEnum();
     try comptime testEnum();
@@ -286,7 +282,6 @@ fn testUnion() !void {
 
 test "type info: struct info" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try testStruct();
     try comptime testStruct();
@@ -535,7 +530,6 @@ test "type info for async frames" {
 
 test "Declarations are returned in declaration order" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = struct {
         pub const a = 1;
@@ -558,7 +552,6 @@ test "Struct.is_tuple for anon list literal" {
 
 test "Struct.is_tuple for anon struct literal" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const info = @typeInfo(@TypeOf(.{ .a = 0 }));
     try expect(!info.Struct.is_tuple);
test/behavior/undefined.zig
@@ -48,7 +48,6 @@ test "assign undefined to struct" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     comptime {
         var foo: Foo = undefined;
@@ -66,7 +65,6 @@ test "assign undefined to struct with method" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     comptime {
         var foo: Foo = undefined;
@@ -82,7 +80,6 @@ test "assign undefined to struct with method" {
 
 test "type name of undefined" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const x = undefined;
     try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@TypeOf(undefined)"));
test/behavior/union.zig
@@ -486,7 +486,6 @@ test "global union with single field is correctly initialized" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     glbl = Foo1{
         .f = @typeInfo(Foo1).Union.fields[0].type{ .x = 123 },
@@ -546,7 +545,6 @@ test "union initializer generates padding only if needed" {
 test "runtime tag name with single field" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const U = union(enum) {
         A: i32,
@@ -1467,7 +1465,6 @@ test "packed union in packed struct" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = packed struct {
         nested: packed union {
@@ -1556,7 +1553,6 @@ test "packed union with zero-bit field" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = packed struct {
         nested: packed union {
test/behavior/vector.zig
@@ -433,7 +433,6 @@ test "load vector elements via runtime index" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const S = struct {
         fn doTheTest() !void {
test/behavior/while.zig
@@ -5,7 +5,6 @@ const assert = std.debug.assert;
 
 test "while loop" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     var i: i32 = 0;
     while (i < 4) {
@@ -39,8 +38,6 @@ fn staticWhileLoop2() i32 {
 }
 
 test "while with continue expression" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var sum: i32 = 0;
     {
         var i: i32 = 0;
@@ -53,8 +50,6 @@ test "while with continue expression" {
 }
 
 test "while with else" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var sum: i32 = 0;
     var i: i32 = 0;
     var got_else: i32 = 0;
@@ -82,8 +77,6 @@ fn getNumberOrNull() ?i32 {
 }
 
 test "continue outer while loop" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     testContinueOuter();
     comptime testContinueOuter();
 }
@@ -131,7 +124,6 @@ test "while copies its payload" {
 
 test "continue and break" {
     if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try runContinueAndBreakTest();
     try expect(continue_and_break_counter == 8);
@@ -349,8 +341,6 @@ test "continue inline while loop" {
 }
 
 test "else continue outer while" {
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
     var i: usize = 0;
     while (true) {
         i += 1;