Commit d69c48370a

David Rubin <daviru007@icloud.com>
2024-05-25 23:15:21
riscv: integer + float `@abs`
1 parent 206e668
src/arch/riscv64/CodeGen.zig
@@ -3377,18 +3377,83 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
         const ty = func.typeOf(ty_op.operand);
         const scalar_ty = ty.scalarType(zcu);
         const operand = try func.resolveInst(ty_op.operand);
-        _ = operand;
 
         switch (scalar_ty.zigTypeTag(zcu)) {
             .Int => if (ty.zigTypeTag(zcu) == .Vector) {
                 return func.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)});
             } else {
-                return func.fail("TODO: implement airAbs for Int", .{});
+                const return_mcv = try func.copyToNewRegister(inst, operand);
+                const operand_reg = return_mcv.register;
+
+                const temp_reg, const temp_lock = try func.allocReg(.int);
+                defer func.register_manager.unlockReg(temp_lock);
+
+                _ = try func.addInst(.{
+                    .tag = .srai,
+                    .ops = .rri,
+                    .data = .{ .i_type = .{
+                        .rd = temp_reg,
+                        .rs1 = operand_reg,
+                        .imm12 = Immediate.s(63),
+                    } },
+                });
+
+                _ = try func.addInst(.{
+                    .tag = .xor,
+                    .ops = .rrr,
+                    .data = .{ .r_type = .{
+                        .rd = operand_reg,
+                        .rs1 = operand_reg,
+                        .rs2 = temp_reg,
+                    } },
+                });
+
+                _ = try func.addInst(.{
+                    .tag = .sub,
+                    .ops = .rrr,
+                    .data = .{ .r_type = .{
+                        .rd = operand_reg,
+                        .rs1 = operand_reg,
+                        .rs2 = temp_reg,
+                    } },
+                });
+
+                break :result return_mcv;
+            },
+            .Float => {
+                const float_bits = scalar_ty.floatBits(zcu.getTarget());
+                switch (float_bits) {
+                    16 => return func.fail("TODO: airAbs 16-bit float", .{}),
+                    32 => {},
+                    64 => {},
+                    80 => return func.fail("TODO: airAbs 80-bit float", .{}),
+                    128 => return func.fail("TODO: airAbs 128-bit float", .{}),
+                    else => unreachable,
+                }
+
+                const return_mcv = try func.copyToNewRegister(inst, operand);
+                const operand_reg = return_mcv.register;
+
+                assert(operand_reg.class() == .float);
+
+                _ = try func.addInst(.{
+                    .tag = .pseudo,
+                    .ops = .pseudo_fabs,
+                    .data = .{
+                        .fabs = .{
+                            .rd = operand_reg,
+                            .rs = operand_reg,
+                            .bits = float_bits,
+                        },
+                    },
+                });
+
+                break :result return_mcv;
             },
             else => return func.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}),
         }
 
-        break :result .{.unreach};
+        break :result .unreach;
     };
     return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
src/arch/riscv64/Encoding.zig
@@ -130,6 +130,7 @@ pub const Mnemonic = enum {
     fles,
 
     fsgnjns,
+    fsgnjxs,
 
     // D extension (64-bit float)
     faddd,
@@ -150,6 +151,7 @@ pub const Mnemonic = enum {
     fled,
 
     fsgnjnd,
+    fsgnjxd,
 
     pub fn encoding(mnem: Mnemonic) Enc {
         return switch (mnem) {
@@ -218,6 +220,9 @@ pub const Mnemonic = enum {
             .fsgnjns => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
             .fsgnjnd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b000 } } },
 
+            .fsgnjxs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b0010} } },
+            .fsgnjxd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b0010} } },
+
 
             // LOAD
 
@@ -392,6 +397,9 @@ pub const InstEnc = enum {
 
             .fsgnjns,
             .fsgnjnd,
+
+            .fsgnjxs,
+            .fsgnjxd,
             => .R,
 
             .ecall,
src/arch/riscv64/Lower.zig
@@ -208,6 +208,26 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
                 });
             },
 
+            .pseudo_fabs => {
+                const fabs = inst.data.fabs;
+                assert(fabs.rs.class() == .float and fabs.rd.class() == .float);
+
+                const mnem: Encoding.Mnemonic = switch (fabs.bits) {
+                    16 => return lower.fail("TODO: airAbs Float 16", .{}),
+                    32 => .fsgnjxs,
+                    64 => .fsgnjxd,
+                    80 => return lower.fail("TODO: airAbs Float 80", .{}),
+                    128 => return lower.fail("TODO: airAbs Float 128", .{}),
+                    else => unreachable,
+                };
+
+                try lower.emit(mnem, &.{
+                    .{ .reg = fabs.rs },
+                    .{ .reg = fabs.rd },
+                    .{ .reg = fabs.rd },
+                });
+            },
+
             .pseudo_compare => {
                 const compare = inst.data.compare;
                 const op = compare.op;
src/arch/riscv64/Mir.zig
@@ -76,6 +76,8 @@ pub const Inst = struct {
         fmuls,
         fdivs,
 
+        fabss,
+
         fmins,
         fmaxs,
 
@@ -94,6 +96,8 @@ pub const Inst = struct {
         fmuld,
         fdivd,
 
+        fabsd,
+
         fmind,
         fmaxd,
 
@@ -194,6 +198,12 @@ pub const Inst = struct {
             rs: Register,
         },
 
+        fabs: struct {
+            rd: Register,
+            rs: Register,
+            bits: u16,
+        },
+
         compare: struct {
             rd: Register,
             rs1: Register,
@@ -273,6 +283,9 @@ pub const Inst = struct {
         /// Jumps. Uses `inst` payload.
         pseudo_j,
 
+        /// Floating point absolute value.
+        pseudo_fabs,
+
         /// Dead inst, ignored by the emitter.
         pseudo_dead,
 
test/behavior/abs.zig
@@ -6,7 +6,6 @@ test "@abs integers" {
     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;
 
     try comptime testAbsIntegers();
     try testAbsIntegers();
@@ -93,18 +92,17 @@ test "@abs floats" {
     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_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     try comptime testAbsFloats(f16);
-    try testAbsFloats(f16);
+    if (builtin.zig_backend != .stage2_riscv64) try testAbsFloats(f16);
     try comptime testAbsFloats(f32);
     try testAbsFloats(f32);
     try comptime testAbsFloats(f64);
     try testAbsFloats(f64);
     try comptime testAbsFloats(f80);
-    if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64) try testAbsFloats(f80);
+    if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64 and builtin.zig_backend != .stage2_riscv64) try testAbsFloats(f80);
     try comptime testAbsFloats(f128);
-    if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64) try testAbsFloats(f128);
+    if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64 and builtin.zig_backend != .stage2_riscv64) try testAbsFloats(f128);
 }
 
 fn testAbsFloats(comptime T: type) !void {
test/behavior/cast.zig
@@ -2608,7 +2608,6 @@ test "@as does not corrupt values with incompatible representations" {
     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_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 
     const x: f32 = @as(f16, blk: {
         if (false) {
test/behavior/floatop.zig
@@ -999,7 +999,6 @@ test "@abs f32/f64" {
     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;
 
     try testFabs(f32);
     try comptime testFabs(f32);
test/behavior/math.zig
@@ -1814,7 +1814,6 @@ test "absFloat" {
     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;
 
     try testAbsFloat();
     try comptime testAbsFloat();