Commit 28df64cba4

David Rubin <daviru007@icloud.com>
2024-03-14 05:02:15
riscv: implement `@abs`
- add the `abs` MIR instruction - implement `@abs` by shifting to the right by `bits - 1`, and xoring.
1 parent 060c475
Changed files (6)
lib/std/builtin.zig
@@ -760,9 +760,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
     @setCold(true);
 
     // stage2_riscv64 backend doesn't support loops yet.
-    if (builtin.zig_backend == .stage2_riscv64 or
-        builtin.cpu.arch == .riscv64)
-    {
+    if (builtin.zig_backend == .stage2_riscv64) {
         unreachable;
     }
 
src/arch/riscv64/bits.zig
@@ -250,7 +250,7 @@ pub const Instruction = union(enum) {
     }
 
     pub fn srai(rd: Register, r1: Register, shamt: u6) Instruction {
-        return iType(0b0010011, 0b101, rd, r1, (1 << 10) + shamt);
+        return iType(0b0010011, 0b101, rd, r1, (@as(i12, 1) << 10) + shamt);
     }
 
     pub fn slti(rd: Register, r1: Register, imm: i12) Instruction {
@@ -267,16 +267,16 @@ pub const Instruction = union(enum) {
         return iType(0b0011011, 0b000, rd, r1, imm);
     }
 
-    pub fn slliw(rd: Register, r1: Register, shamt: u5) Instruction {
+    pub fn slliw(rd: Register, r1: Register, shamt: u6) Instruction {
         return iType(0b0011011, 0b001, rd, r1, shamt);
     }
 
-    pub fn srliw(rd: Register, r1: Register, shamt: u5) Instruction {
+    pub fn srliw(rd: Register, r1: Register, shamt: u6) Instruction {
         return iType(0b0011011, 0b101, rd, r1, shamt);
     }
 
-    pub fn sraiw(rd: Register, r1: Register, shamt: u5) Instruction {
-        return iType(0b0011011, 0b101, rd, r1, (1 << 10) + shamt);
+    pub fn sraiw(rd: Register, r1: Register, shamt: u6) Instruction {
+        return iType(0b0011011, 0b101, rd, r1, (@as(i12, 1) << 10) + shamt);
     }
 
     // Upper Immediate
src/arch/riscv64/CodeGen.zig
@@ -1385,8 +1385,44 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
 }
 
 fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
+    const mod = self.bin_file.comp.module.?;
     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
-    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airAbs for {}", .{self.target.cpu.arch});
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+        const ty = self.typeOf(ty_op.operand);
+        const scalar_ty = ty.scalarType(mod);
+        const operand = try self.resolveInst(ty_op.operand);
+
+        switch (scalar_ty.zigTypeTag(mod)) {
+            .Int => if (ty.zigTypeTag(mod) == .Vector) {
+                return self.fail("TODO implement airAbs for {}", .{ty.fmt(mod)});
+            } else {
+                const int_bits = ty.intInfo(mod).bits;
+
+                if (int_bits > 32) {
+                    return self.fail("TODO: airAbs for larger than 32 bits", .{});
+                }
+
+                // promote the src into a register
+                const src_mcv = try self.copyToNewRegister(inst, operand);
+                // temp register for shift
+                const temp_reg = try self.register_manager.allocReg(inst, gp);
+
+                _ = try self.addInst(.{
+                    .tag = .abs,
+                    .data = .{
+                        .i_type = .{
+                            .rs1 = src_mcv.register,
+                            .rd = temp_reg,
+                            .imm12 = @intCast(int_bits - 1),
+                        },
+                    },
+                });
+
+                break :result src_mcv;
+            },
+            else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(mod)}),
+        }
+    };
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
 
@@ -1603,8 +1639,6 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
                 self.register_manager.getRegAssumeFree(src_reg, inst);
                 break :dst src_mcv;
             },
-            // don't need to allocate anything, can just be used immediately.
-            .stack_offset => src_mcv,
             else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),
         };
 
src/arch/riscv64/Emit.zig
@@ -58,6 +58,7 @@ pub fn emitMir(
 
             .addi => try emit.mirIType(inst),
             .jalr => try emit.mirIType(inst),
+            .abs => try emit.mirIType(inst),
 
             .jal => try emit.mirJType(inst),
 
@@ -200,6 +201,12 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
 
         .ldr_ptr_stack => try emit.writeInstruction(Instruction.add(i_type.rd, i_type.rs1, .sp)),
 
+        .abs => {
+            try emit.writeInstruction(Instruction.sraiw(i_type.rd, i_type.rs1, @intCast(i_type.imm12)));
+            try emit.writeInstruction(Instruction.xor(i_type.rs1, i_type.rs1, i_type.rd));
+            try emit.writeInstruction(Instruction.subw(i_type.rs1, i_type.rs1, i_type.rd));
+        },
+
         else => unreachable,
     }
 }
src/arch/riscv64/Mir.zig
@@ -38,6 +38,9 @@ pub const Inst = struct {
         /// Subtraction
         sub,
 
+        /// Absolute Value, uses i_type payload.
+        abs,
+
         jal,
         /// Jumps. Uses `inst` payload.
         j,
src/target.zig
@@ -507,7 +507,7 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken
     if (use_llvm) return .stage2_llvm;
     if (target.ofmt == .c) return .stage2_c;
     return switch (target.cpu.arch) {
-        .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
+        .wasm32, .wasm64 => .stage2_wasm,
         .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
         .x86_64 => .stage2_x86_64,
         .x86 => .stage2_x86,