diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 6e807f1f3b..b1ef2bbb10 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -6712,9 +6712,65 @@ fn airArrayToSlice(func: *Func, inst: Air.Inst.Index) !void { fn airFloatFromInt(func: *Func, inst: Air.Inst.Index) !void { const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airFloatFromInt for {}", .{ - func.target.cpu.arch, - }); + const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { + const pt = func.pt; + const zcu = pt.zcu; + + const operand = try func.resolveInst(ty_op.operand); + + const src_ty = func.typeOf(ty_op.operand); + const dst_ty = ty_op.ty.toType(); + + const src_reg, const src_lock = try func.promoteReg(src_ty, operand); + defer if (src_lock) |lock| func.register_manager.unlockReg(lock); + + const is_unsigned = dst_ty.isUnsignedInt(zcu); + const src_bits = src_ty.bitSize(pt); + const dst_bits = dst_ty.bitSize(pt); + + switch (src_bits) { + 32, 64 => {}, + else => try func.truncateRegister(src_ty, src_reg), + } + + const int_mod: Mir.FcvtOp = switch (src_bits) { + 8, 16, 32 => if (is_unsigned) .wu else .w, + 64 => if (is_unsigned) .lu else .l, + else => return func.fail("TODO: airFloatFromInt src size: {d}", .{src_bits}), + }; + + const float_mod: enum { s, d } = switch (dst_bits) { + 32 => .s, + 64 => .d, + else => return func.fail("TODO: airFloatFromInt dst size {d}", .{dst_bits}), + }; + + const dst_reg, const dst_lock = try func.allocReg(.int); + defer func.register_manager.unlockReg(dst_lock); + + _ = try func.addInst(.{ + .tag = switch (float_mod) { + .s => switch (int_mod) { + .l => .fcvtsl, + .lu => .fcvtslu, + .w => .fcvtsw, + .wu => .fcvtswu, + }, + .d => switch (int_mod) { + .l => .fcvtdl, + .lu => .fcvtdlu, + .w => .fcvtdw, + .wu => .fcvtdwu, + }, + }, + .data = .{ .rr = .{ + .rd = dst_reg, + .rs = src_reg, + } }, + }); + + break :result .{ .register = dst_reg }; + }; return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -6726,7 +6782,7 @@ fn airIntFromFloat(func: *Func, inst: Air.Inst.Index) !void { const operand = try func.resolveInst(ty_op.operand); const src_ty = func.typeOf(ty_op.operand); - const dst_ty = func.typeOfIndex(inst); + const dst_ty = ty_op.ty.toType(); const is_unsigned = dst_ty.isUnsignedInt(zcu); const src_bits = src_ty.bitSize(pt); @@ -6740,7 +6796,7 @@ fn airIntFromFloat(func: *Func, inst: Air.Inst.Index) !void { const int_mod: Mir.FcvtOp = switch (dst_bits) { 32 => if (is_unsigned) .wu else .w, - 64 => if (is_unsigned) .lu else .l, + 8, 16, 64 => if (is_unsigned) .lu else .l, else => return func.fail("TODO: airIntFromFloat dst size: {d}", .{dst_bits}), }; diff --git a/src/arch/riscv64/encoding.zig b/src/arch/riscv64/encoding.zig index a3e20698b6..7c1bd274e0 100644 --- a/src/arch/riscv64/encoding.zig +++ b/src/arch/riscv64/encoding.zig @@ -280,6 +280,16 @@ pub const Lir = struct { .fcvtld => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .l } } }, .fcvtlud => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .lu } } }, + .fcvtsw => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .S, .rm = 0b111, .width = .w } } }, + .fcvtswu => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .S, .rm = 0b111, .width = .wu } } }, + .fcvtsl => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .S, .rm = 0b111, .width = .l } } }, + .fcvtslu => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .S, .rm = 0b111, .width = .lu } } }, + + .fcvtdw => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .D, .rm = 0b111, .width = .w } } }, + .fcvtdwu => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .D, .rm = 0b111, .width = .wu } } }, + .fcvtdl => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .D, .rm = 0b111, .width = .l } } }, + .fcvtdlu => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .D, .rm = 0b111, .width = .lu } } }, + // LOAD .lb => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b000 } } }, diff --git a/src/arch/riscv64/mnem.zig b/src/arch/riscv64/mnem.zig index afd2f5c78c..d75bf5ccd0 100644 --- a/src/arch/riscv64/mnem.zig +++ b/src/arch/riscv64/mnem.zig @@ -127,6 +127,16 @@ pub const Mnemonic = enum(u16) { fcvtld, fcvtlud, + fcvtsw, + fcvtswu, + fcvtsl, + fcvtslu, + + fcvtdw, + fcvtdwu, + fcvtdl, + fcvtdlu, + fsgnjns, fsgnjnd, diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 8c51be2685..659fd764aa 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -514,6 +514,7 @@ test "struct field explicit alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Node = struct { diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 44fcb08cf3..db0e96128b 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -104,7 +104,6 @@ test "@floatFromInt" { 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 { @@ -163,7 +162,6 @@ test "@intFromFloat" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testIntFromFloats(); try comptime testIntFromFloats();