Commit e622485df8

David Rubin <daviru007@icloud.com>
2024-04-14 06:12:26
riscv: actually working test runner
1 parent d19b77d
Changed files (6)
lib/compiler/test_runner.zig
@@ -266,4 +266,6 @@ pub fn mainExtraSimple() !void {
         };
         pass_count += 1;
     }
+
+    std.posix.exit(pass_count);
 }
src/arch/riscv64/abi.zig
@@ -130,13 +130,16 @@ pub fn classifySystem(ty: Type, mod: *Module) [8]Class {
             unreachable; // support > 128 bit int arguments
         },
         .ErrorUnion => {
-            const payload = ty.errorUnionPayload(mod);
-            const payload_bits = payload.bitSize(mod);
-            if (payload_bits <= 64) {
-                result[0] = .integer;
-                result[1] = .integer;
-            }
-            unreachable; // support > 64 bit error payloads
+            const payload_ty = ty.errorUnionPayload(mod);
+            const payload_bits = payload_ty.bitSize(mod);
+
+            // the error union itself
+            result[0] = .integer;
+
+            // anyerror!void can fit into one register
+            if (payload_bits == 0) return result;
+
+            std.debug.panic("support ErrorUnion payload {}", .{payload_ty.fmt(mod)});
         },
         else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
     }
src/arch/riscv64/CodeGen.zig
@@ -1601,7 +1601,6 @@ fn allocReg(self: *Self) !struct { Register, RegisterLock } {
 }
 
 fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
-    log.debug("elemOffset: {}", .{index});
     const reg: Register = blk: {
         switch (index) {
             .immediate => |imm| {
@@ -1616,14 +1615,14 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi
                 const lock = self.register_manager.lockRegAssumeUnused(reg);
                 defer self.register_manager.unlockReg(lock);
 
-                try self.binOpMir(
+                const result = try self.binOp(
                     .mul,
-                    null,
-                    index_ty,
                     .{ .register = reg },
+                    index_ty,
                     .{ .immediate = elem_size },
+                    index_ty,
                 );
-                break :blk reg;
+                break :blk result.register;
             },
         }
     };
@@ -1817,24 +1816,10 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
     const lhs_ty = self.typeOf(bin_op.lhs);
     const rhs_ty = self.typeOf(bin_op.rhs);
 
-    const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
-    return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
-}
-
-fn supportImmediate(tag: Air.Inst.Tag) bool {
-    return switch (tag) {
-        .add,
-        .sub,
-        .cmp_eq,
-        .cmp_neq,
-        .cmp_gt,
-        .cmp_gte,
-        .cmp_lt,
-        .cmp_lte,
-        => true,
-
-        else => false,
+    const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
+        break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
     };
+    return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
 /// For all your binary operation needs, this function will generate
@@ -1854,10 +1839,9 @@ fn supportImmediate(tag: Air.Inst.Tag) bool {
 fn binOp(
     self: *Self,
     tag: Air.Inst.Tag,
-    maybe_inst: ?Air.Inst.Index,
     lhs: MCValue,
-    rhs: MCValue,
     lhs_ty: Type,
+    rhs: MCValue,
     rhs_ty: Type,
 ) InnerError!MCValue {
     const zcu = self.bin_file.comp.module.?;
@@ -1881,15 +1865,12 @@ fn binOp(
                     assert(lhs_ty.eql(rhs_ty, zcu));
                     const int_info = lhs_ty.intInfo(zcu);
                     if (int_info.bits <= 64) {
-                        if (rhs == .immediate and supportImmediate(tag)) {
-                            return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
-                        }
-                        return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+                        return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
                     } else {
                         return self.fail("TODO binary operations on int with bits > 64", .{});
                     }
                 },
-                else => |x| return self.fail("TOOD: binOp {s}", .{@tagName(x)}),
+                else => |x| return std.debug.panic("TOOD: binOp {s}", .{@tagName(x)}),
             }
         },
 
@@ -1912,23 +1893,21 @@ fn binOp(
                             else => unreachable,
                         };
 
-                        return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+                        return try self.binOpRegister(base_tag, lhs, lhs_ty, rhs, rhs_ty);
                     } else {
                         const offset = try self.binOp(
                             .mul,
-                            null,
                             rhs,
-                            .{ .immediate = elem_size },
                             Type.usize,
+                            .{ .immediate = elem_size },
                             Type.usize,
                         );
 
                         const addr = try self.binOp(
                             tag,
-                            null,
                             lhs,
-                            offset,
                             Type.manyptr_u8,
+                            offset,
                             Type.usize,
                         );
                         return addr;
@@ -1948,10 +1927,7 @@ fn binOp(
                 .Int => {
                     const int_info = lhs_ty.intInfo(zcu);
                     if (int_info.bits <= 64) {
-                        if (rhs == .immediate) {
-                            return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
-                        }
-                        return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+                        return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
                     } else {
                         return self.fail("TODO binary operations on int with bits > 64", .{});
                     }
@@ -1973,14 +1949,11 @@ fn binOp(
 fn binOpRegister(
     self: *Self,
     tag: Air.Inst.Tag,
-    maybe_inst: ?Air.Inst.Index,
     lhs: MCValue,
-    rhs: MCValue,
     lhs_ty: Type,
+    rhs: MCValue,
     rhs_ty: Type,
 ) !MCValue {
-    _ = maybe_inst;
-
     const lhs_reg, const lhs_lock = blk: {
         if (lhs == .register) break :blk .{ lhs.register, null };
 
@@ -2006,164 +1979,79 @@ fn binOpRegister(
         .add => .add,
         .sub => .sub,
         .mul => .mul,
-        .cmp_eq => .cmp_eq,
-        .cmp_neq => .cmp_neq,
-        .cmp_gt => .cmp_gt,
-        .cmp_gte => .cmp_gte,
-        .cmp_lt => .cmp_lt,
+
         .shl => .sllw,
         .shr => .srlw,
-        else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
-    };
-
-    _ = try self.addInst(.{
-        .tag = mir_tag,
-        .ops = .rrr,
-        .data = .{
-            .r_type = .{
-                .rd = dest_reg,
-                .rs1 = lhs_reg,
-                .rs2 = rhs_reg,
-            },
-        },
-    });
-
-    // generate the struct for OF checks
 
-    return MCValue{ .register = dest_reg };
-}
-
-/// Don't call this function directly. Use binOp instead.
-///
-/// Call this function if rhs is an immediate. Generates I version of binops.
-///
-/// Asserts that rhs is an immediate MCValue
-fn binOpImm(
-    self: *Self,
-    tag: Air.Inst.Tag,
-    maybe_inst: ?Air.Inst.Index,
-    lhs: MCValue,
-    rhs: MCValue,
-    lhs_ty: Type,
-    rhs_ty: Type,
-) !MCValue {
-    assert(rhs == .immediate);
-    _ = maybe_inst;
-
-    // TODO: use `maybe_inst` to track instead of forcing a lock.
-
-    const lhs_reg, const lhs_lock = blk: {
-        if (lhs == .register) break :blk .{ lhs.register, null };
-
-        const lhs_reg, const lhs_lock = try self.allocReg();
-        try self.genSetReg(lhs_ty, lhs_reg, lhs);
-        break :blk .{ lhs_reg, lhs_lock };
-    };
-    defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
-
-    const dest_reg, const dest_lock = try self.allocReg();
-    defer self.register_manager.unlockReg(dest_lock);
+        .cmp_eq,
+        .cmp_neq,
+        .cmp_gt,
+        .cmp_gte,
+        .cmp_lt,
+        => .pseudo,
 
-    const mir_tag: Mir.Inst.Tag = switch (tag) {
-        .shl => .slli,
-        .shr => .srli,
-        .cmp_gte => .cmp_imm_gte,
-        .cmp_eq => .cmp_imm_eq,
-        .cmp_neq => .cmp_imm_neq,
-        .cmp_lte => .cmp_imm_lte,
-        .cmp_lt => .cmp_imm_lt,
-        .add => .addi,
-        .sub => .addiw,
-        else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}),
+        else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
     };
 
-    // apply some special operations needed
     switch (mir_tag) {
-        .slli,
-        .srli,
-        .addi,
-        .cmp_imm_eq,
-        .cmp_imm_neq,
-        .cmp_imm_lte,
-        .cmp_imm_lt,
+        .add,
+        .sub,
+        .mul,
+        .sllw,
+        .srlw,
         => {
-            _ = try self.addInst(.{
-                .tag = mir_tag,
-                .ops = .rri,
-                .data = .{ .i_type = .{
-                    .rd = dest_reg,
-                    .rs1 = lhs_reg,
-                    .imm12 = Immediate.s(math.cast(i12, rhs.immediate) orelse {
-                        return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
-                    }),
-                } },
-            });
-        },
-        .addiw => {
-            _ = try self.addInst(.{
-                .tag = mir_tag,
-                .ops = .rri,
-                .data = .{ .i_type = .{
-                    .rd = dest_reg,
-                    .rs1 = lhs_reg,
-                    .imm12 = Immediate.s(-(math.cast(i12, rhs.immediate) orelse {
-                        return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
-                    })),
-                } },
-            });
-        },
-        .cmp_imm_gte => {
-            const imm_reg = try self.copyToTmpRegister(rhs_ty, .{ .immediate = rhs.immediate - 1 });
-
             _ = try self.addInst(.{
                 .tag = mir_tag,
                 .ops = .rrr,
-                .data = .{ .r_type = .{
-                    .rd = dest_reg,
-                    .rs1 = imm_reg,
-                    .rs2 = lhs_reg,
-                } },
+                .data = .{
+                    .r_type = .{
+                        .rd = dest_reg,
+                        .rs1 = lhs_reg,
+                        .rs2 = rhs_reg,
+                    },
+                },
             });
         },
-        else => unreachable,
-    }
 
-    return MCValue{ .register = dest_reg };
-}
-
-fn binOpMir(
-    self: *Self,
-    mir_tag: Mir.Inst.Tag,
-    maybe_inst: ?Air.Inst.Index,
-    ty: Type,
-    dst_mcv: MCValue,
-    src_mcv: MCValue,
-) !void {
-    const zcu = self.bin_file.comp.module.?;
-    const abi_size: u32 = @intCast(ty.abiSize(zcu));
-
-    _ = abi_size;
-    _ = maybe_inst;
-
-    switch (dst_mcv) {
-        .register => |dst_reg| {
-            const src_reg = try self.copyToTmpRegister(ty, src_mcv);
+        .pseudo => {
+            const pseudo_op = switch (tag) {
+                .cmp_eq,
+                .cmp_neq,
+                .cmp_gt,
+                .cmp_gte,
+                .cmp_lt,
+                => .pseudo_compare,
+                else => unreachable,
+            };
 
             _ = try self.addInst(.{
-                .tag = mir_tag,
-                .ops = .rrr,
+                .tag = .pseudo,
+                .ops = pseudo_op,
                 .data = .{
-                    .r_type = .{
-                        .rd = dst_reg,
-                        .rs1 = dst_reg,
-                        .rs2 = src_reg,
+                    .compare = .{
+                        .rd = dest_reg,
+                        .rs1 = lhs_reg,
+                        .rs2 = rhs_reg,
+                        .op = switch (tag) {
+                            .cmp_eq => .eq,
+                            .cmp_neq => .neq,
+                            .cmp_gt => .gt,
+                            .cmp_gte => .gte,
+                            .cmp_lt => .lt,
+                            .cmp_lte => .lte,
+                            else => unreachable,
+                        },
                     },
                 },
             });
         },
 
-        else => return self.fail("TODO: binOpMir {s}", .{@tagName(dst_mcv)}),
+        else => unreachable,
     }
+
+    // generate the struct for OF checks
+
+    return MCValue{ .register = dest_reg };
 }
 
 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
     const lhs_ty = self.typeOf(bin_op.lhs);
     const rhs_ty = self.typeOf(bin_op.rhs);
 
-    const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
+    const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
+        break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
+    };
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
@@ -2200,7 +2090,7 @@ fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
         const lhs_ty = self.typeOf(bin_op.lhs);
         const rhs_ty = self.typeOf(bin_op.rhs);
 
-        break :result try self.binOp(.sub, inst, lhs, rhs, lhs_ty, rhs_ty);
+        break :result try self.binOp(.sub, lhs, lhs_ty, rhs, rhs_ty);
     };
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
@@ -2240,7 +2130,7 @@ 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, null, lhs, rhs, lhs_ty, rhs_ty);
+        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);
 
@@ -2291,10 +2181,9 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
 
                         const overflow_mcv = try self.binOp(
                             .cmp_neq,
-                            null,
                             .{ .register = overflow_reg },
-                            .{ .register = add_reg },
                             lhs_ty,
+                            .{ .register = add_reg },
                             lhs_ty,
                         );
 
@@ -2347,7 +2236,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 switch (int_info.bits) {
                     1...32 => {
                         if (self.hasFeature(.m)) {
-                            const dest = try self.binOp(.mul, null, lhs, rhs, lhs_ty, rhs_ty);
+                            const dest = try self.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty);
 
                             const add_result_lock = self.register_manager.lockRegAssumeUnused(dest.register);
                             defer self.register_manager.unlockReg(add_result_lock);
@@ -2393,10 +2282,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
 
                                             const overflow_mcv = try self.binOp(
                                                 .cmp_neq,
-                                                null,
                                                 .{ .register = overflow_reg },
-                                                .{ .register = add_reg },
                                                 lhs_ty,
+                                                .{ .register = add_reg },
                                                 lhs_ty,
                                             );
 
@@ -2479,7 +2367,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void {
         const lhs_ty = self.typeOf(bin_op.lhs);
         const rhs_ty = self.typeOf(bin_op.rhs);
 
-        break :result try self.binOp(.shl, inst, lhs, rhs, lhs_ty, rhs_ty);
+        break :result try self.binOp(.shl, lhs, lhs_ty, rhs, rhs_ty);
     };
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
@@ -2543,10 +2431,9 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
                 if (err_off > 0) {
                     result = try self.binOp(
                         .shr,
-                        null,
                         result,
-                        .{ .immediate = @as(u6, @intCast(err_off * 8)) },
                         err_union_ty,
+                        .{ .immediate = @as(u6, @intCast(err_off * 8)) },
                         Type.u8,
                     );
                 }
@@ -2593,10 +2480,9 @@ fn genUnwrapErrUnionPayloadMir(
                 if (payload_off > 0) {
                     result = try self.binOp(
                         .shr,
-                        null,
                         result,
-                        .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
                         err_union_ty,
+                        .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
                         Type.u8,
                     );
                 }
@@ -2837,7 +2723,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
         };
 
         const dest = try self.allocRegOrMem(inst, true);
-        const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);
+        const addr = try self.binOp(.ptr_add, base_mcv, slice_ptr_field_type, index_mcv, Type.usize);
         try self.load(dest, addr, slice_ptr_field_type);
 
         break :result dest;
@@ -2885,13 +2771,14 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
         defer self.register_manager.unlockReg(offset_lock);
 
         const dst_mcv = try self.allocRegOrMem(inst, false);
-        try self.binOpMir(
-            .add,
-            null,
-            Type.usize,
-            .{ .register = addr_reg },
-            .{ .register = offset_reg },
-        );
+        _ = try self.addInst(.{
+            .tag = .add,
+            .ops = .rr,
+            .data = .{ .rr = .{
+                .rd = addr_reg,
+                .rs = offset_reg,
+            } },
+        });
         try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
         break :result dst_mcv;
     };
@@ -3046,7 +2933,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
 
         switch (int_bits) {
             16 => {
-                const temp = try self.binOp(.shr, null, dest_mcv, .{ .immediate = 8 }, ty, Type.u8);
+                const temp = try self.binOp(.shr, dest_mcv, ty, .{ .immediate = 8 }, Type.u8);
                 assert(temp == .register);
                 _ = try self.addInst(.{
                     .tag = .slli,
@@ -3752,7 +3639,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
 
         const int_info = int_ty.intInfo(zcu);
         if (int_info.bits <= 64) {
-            break :result try self.binOp(tag, null, lhs, rhs, int_ty, int_ty);
+            break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty);
         } else {
             return self.fail("TODO riscv cmp for ints > 64 bits", .{});
         }
@@ -4033,20 +3920,19 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)
             if (err_off > 0) {
                 return_mcv = try self.binOp(
                     .shr,
-                    null,
                     return_mcv,
-                    .{ .immediate = @as(u6, @intCast(err_off * 8)) },
                     eu_ty,
+                    .{ .immediate = @as(u6, @intCast(err_off * 8)) },
                     Type.u8,
                 );
             }
 
-            try self.binOpMir(
+            return_mcv = try self.binOp(
                 .cmp_neq,
-                null,
-                Type.anyerror,
                 return_mcv,
+                Type.u16,
                 .{ .immediate = 0 },
+                Type.u16,
             );
 
             return return_mcv;
@@ -4070,8 +3956,8 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC
     switch (is_err_res) {
         .register => |reg| {
             _ = try self.addInst(.{
-                .tag = .not,
-                .ops = .rr,
+                .tag = .pseudo,
+                .ops = .pseudo_not,
                 .data = .{
                     .rr = .{
                         .rd = reg,
@@ -4440,9 +4326,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
                     dst_mcv,
                     try self.resolveInst(src_ref),
                 ),
-                else => return self.fail("TODO implement genCopy for {s} of {}", .{
-                    @tagName(src_mcv), ty.fmt(zcu),
-                }),
+                else => unreachable,
             };
             defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
 
src/arch/riscv64/Encoding.zig
@@ -2,9 +2,6 @@ mnemonic: Mnemonic,
 data: Data,
 
 pub const Mnemonic = enum {
-    // R Type
-    add,
-
     // I Type
     ld,
     lw,
@@ -13,6 +10,10 @@ pub const Mnemonic = enum {
     lhu,
     lb,
     lbu,
+    sltiu,
+    sltu,
+    xori,
+    andi,
 
     addi,
     jalr,
@@ -32,6 +33,12 @@ pub const Mnemonic = enum {
     // B Type
     beq,
 
+    // R Type
+    add,
+    slt,
+    mul,
+    xor,
+
     // System
     ecall,
     ebreak,
@@ -50,8 +57,11 @@ pub const Mnemonic = enum {
             .lb     => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null      },
             .lbu    => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null      },
 
+            .sltiu  => .{ .opcode = 0b0010011, .funct3 = 0b011, .funct7 = null      },
 
             .addi   => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null      },
+            .andi   => .{ .opcode = 0b0010011, .funct3 = 0b111, .funct7 = null      },
+            .xori   => .{ .opcode = 0b0010011, .funct3 = 0b100, .funct7 = null      },
             .jalr   => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null      },
 
             .lui    => .{ .opcode = 0b0110111, .funct3 = null,  .funct7 = null      },
@@ -65,6 +75,13 @@ pub const Mnemonic = enum {
 
             .beq    => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null      },
 
+            .slt    => .{ .opcode = 0b0110011, .funct3 = 0b010, .funct7 = 0b0000000 },
+            .sltu   => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 },
+
+            .xor    => .{ .opcode = 0b0110011, .funct3 = 0b100, .funct7 = 0b0000000 },
+
+            .mul    => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000001 },
+
             .ecall  => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null      },
             .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null      },
             .unimp  => .{ .opcode = 0b0000000, .funct3 = 0b000, .funct7 = null      },
@@ -98,6 +115,9 @@ pub const InstEnc = enum {
             .lb,
             .lbu,
             .jalr,
+            .sltiu,
+            .xori,
+            .andi,
             => .I,
 
             .lui,
@@ -115,6 +135,12 @@ pub const InstEnc = enum {
             .beq,
             => .B,
 
+            .slt,
+            .sltu,
+            .mul,
+            .xor,
+            => .R,
+
             .ecall,
             .ebreak,
             .unimp,
src/arch/riscv64/Lower.zig
@@ -159,7 +159,83 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
                 });
             },
 
-            else => return lower.fail("TODO Lower: psuedo {s}", .{@tagName(inst.ops)}),
+            .pseudo_compare => {
+                const compare = inst.data.compare;
+                const op = compare.op;
+
+                const rd = compare.rd;
+                const rs1 = compare.rs1;
+                const rs2 = compare.rs2;
+
+                switch (op) {
+                    .eq => {
+                        try lower.emit(.xor, &.{
+                            .{ .reg = rd },
+                            .{ .reg = rs1 },
+                            .{ .reg = rs2 },
+                        });
+
+                        try lower.emit(.sltiu, &.{
+                            .{ .reg = rd },
+                            .{ .reg = rd },
+                            .{ .imm = Immediate.s(1) },
+                        });
+                    },
+                    .neq => {
+                        try lower.emit(.xor, &.{
+                            .{ .reg = rd },
+                            .{ .reg = rs1 },
+                            .{ .reg = rs2 },
+                        });
+
+                        try lower.emit(.sltu, &.{
+                            .{ .reg = rd },
+                            .{ .reg = .zero },
+                            .{ .reg = rd },
+                        });
+                    },
+                    .gt => {
+                        try lower.emit(.sltu, &.{
+                            .{ .reg = rd },
+                            .{ .reg = rs1 },
+                            .{ .reg = rs2 },
+                        });
+                    },
+                    .gte => {
+                        try lower.emit(.sltu, &.{
+                            .{ .reg = rd },
+                            .{ .reg = rs1 },
+                            .{ .reg = rs2 },
+                        });
+
+                        try lower.emit(.xori, &.{
+                            .{ .reg = rd },
+                            .{ .reg = rd },
+                            .{ .imm = Immediate.s(1) },
+                        });
+                    },
+                    .lt => {
+                        try lower.emit(.slt, &.{
+                            .{ .reg = rd },
+                            .{ .reg = rs1 },
+                            .{ .reg = rs2 },
+                        });
+                    },
+                    else => return lower.fail("TODO lower: pseudo_compare {s}", .{@tagName(op)}),
+                }
+            },
+
+            .pseudo_not => {
+                const rr = inst.data.rr;
+
+                try lower.emit(.xori, &.{
+                    .{ .reg = rr.rd },
+                    .{ .reg = rr.rs },
+                    .{ .imm = Immediate.s(1) },
+                });
+            },
+
+            else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
         },
     }
 
@@ -192,6 +268,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
             .{ .reg = inst.data.b_type.rs2 },
             .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) },
         },
+        .rrr => &.{
+            .{ .reg = inst.data.r_type.rd },
+            .{ .reg = inst.data.r_type.rs1 },
+            .{ .reg = inst.data.r_type.rs2 },
+        },
         else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
     });
 }
src/arch/riscv64/Mir.zig
@@ -67,36 +67,6 @@ pub const Inst = struct {
         /// Immediate AND, uses i_type payload
         andi,
 
-        // NOTE: Maybe create a special data for compares that includes the ops
-        /// Register `==`, uses r_type
-        cmp_eq,
-        /// Register `!=`, uses r_type
-        cmp_neq,
-        /// Register `>`, uses r_type
-        cmp_gt,
-        /// Register `<`, uses r_type
-        cmp_lt,
-        /// Register `>=`, uses r_type
-        cmp_gte,
-
-        /// Immediate `>=`, uses r_type
-        ///
-        /// Note: this uses r_type because RISC-V does not provide a good way
-        /// to do `>=` comparisons on immediates. Usually we would just subtract
-        /// 1 from the immediate and do a `>` comparison, however there is no `>`
-        /// register to immedate comparison in RISC-V. This leads us to need to
-        /// allocate a register for temporary use.
-        cmp_imm_gte,
-
-        /// Immediate `==`, uses i_type
-        cmp_imm_eq,
-        /// Immediate `!=`, uses i_type.
-        cmp_imm_neq,
-        /// Immediate `<=`, uses i_type
-        cmp_imm_lte,
-        /// Immediate `<`, uses i_type
-        cmp_imm_lt,
-
         /// Branch if equal, Uses b_type
         beq,
         /// Branch if not equal, Uses b_type
@@ -213,6 +183,20 @@ pub const Inst = struct {
             rd: Register,
             rs: Register,
         },
+
+        compare: struct {
+            rd: Register,
+            rs1: Register,
+            rs2: Register,
+            op: enum {
+                eq,
+                neq,
+                gt,
+                gte,
+                lt,
+                lte,
+            },
+        },
     };
 
     pub const Ops = enum {
@@ -291,6 +275,9 @@ pub const Inst = struct {
 
         pseudo_restore_regs,
         pseudo_spill_regs,
+
+        pseudo_compare,
+        pseudo_not,
     };
 
     // Make sure we don't accidentally make instructions bigger than expected.