From d69c48370a0381c7dce463c68b2097dd8fa67eb7 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Sat, 25 May 2024 14:15:21 -0700 Subject: [PATCH] riscv: integer + float `@abs` --- src/arch/riscv64/CodeGen.zig | 71 +++++++++++++++++++++++++++++++++-- src/arch/riscv64/Encoding.zig | 8 ++++ src/arch/riscv64/Lower.zig | 20 ++++++++++ src/arch/riscv64/Mir.zig | 13 +++++++ test/behavior/abs.zig | 8 ++-- test/behavior/cast.zig | 1 - test/behavior/floatop.zig | 1 - test/behavior/math.zig | 1 - 8 files changed, 112 insertions(+), 11 deletions(-) diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index f252c9e6b7..cca02cb1a0 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/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 }); } diff --git a/src/arch/riscv64/Encoding.zig b/src/arch/riscv64/Encoding.zig index a944cac634..6f412935e4 100644 --- a/src/arch/riscv64/Encoding.zig +++ b/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, diff --git a/src/arch/riscv64/Lower.zig b/src/arch/riscv64/Lower.zig index 99270c8a7e..560f8349df 100644 --- a/src/arch/riscv64/Lower.zig +++ b/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; diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig index dd79a8dd83..76822c3968 100644 --- a/src/arch/riscv64/Mir.zig +++ b/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, diff --git a/test/behavior/abs.zig b/test/behavior/abs.zig index 21f02b2a3d..88d01de5c6 100644 --- a/test/behavior/abs.zig +++ b/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 { diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 1c5fbe09cd..2a141b3eda 100644 --- a/test/behavior/cast.zig +++ b/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) { diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 670a7a01ec..65d889776a 100644 --- a/test/behavior/floatop.zig +++ b/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); diff --git a/test/behavior/math.zig b/test/behavior/math.zig index ea03d3f89d..509bfbb16a 100644 --- a/test/behavior/math.zig +++ b/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();