diff --git a/cranelift/codegen/src/isa/riscv64/inst/args.rs b/cranelift/codegen/src/isa/riscv64/inst/args.rs index f4bd748d3a..140723c76b 100644 --- a/cranelift/codegen/src/isa/riscv64/inst/args.rs +++ b/cranelift/codegen/src/isa/riscv64/inst/args.rs @@ -327,7 +327,7 @@ impl FpuOPRR { } pub(crate) fn float_convert_2_int_op(from: Type, is_type_signed: bool, to: Type) -> Self { - let type_32 = to.bits() == 32; + let type_32 = to.bits() <= 32; match from { F32 => { if is_type_signed { diff --git a/cranelift/codegen/src/isa/riscv64/inst/emit.rs b/cranelift/codegen/src/isa/riscv64/inst/emit.rs index f1ae445809..0bee435712 100644 --- a/cranelift/codegen/src/isa/riscv64/inst/emit.rs +++ b/cranelift/codegen/src/isa/riscv64/inst/emit.rs @@ -1781,6 +1781,58 @@ impl MachInstEmit for Inst { rs, } .emit(&[], sink, emit_info, state); + if out_type.bits() < 32 && is_signed { + // load value part mask. + Inst::load_constant_u32( + tmp, + if 16 == out_type.bits() { + (u16::MAX >> 1) as u64 + } else { + // I8 + (u8::MAX >> 1) as u64 + }, + &mut |_| writable_spilltmp_reg(), + ) + .into_iter() + .for_each(|x| x.emit(&[], sink, emit_info, state)); + // keep value part. + Inst::AluRRR { + alu_op: AluOPRRR::And, + rd: tmp, + rs1: rd.to_reg(), + rs2: tmp.to_reg(), + } + .emit(&[], sink, emit_info, state); + // extact sign bit. + Inst::AluRRImm12 { + alu_op: AluOPRRI::Srli, + rd: rd, + rs: rd.to_reg(), + imm12: Imm12::from_bits(31), + } + .emit(&[], sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd: rd, + rs: rd.to_reg(), + imm12: Imm12::from_bits(if 16 == out_type.bits() { + 15 + } else { + // I8 + 7 + }), + } + .emit(&[], sink, emit_info, state); + // make result,sign bit and value part. + Inst::AluRRR { + alu_op: AluOPRRR::Or, + rd: rd, + rs1: rd.to_reg(), + rs2: tmp.to_reg(), + } + .emit(&[], sink, emit_info, state); + } + // I already have the result,jump over. Inst::Jal { dest: BranchTarget::Label(label_jump_over), diff --git a/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs b/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs index 247ee446b6..474bd98075 100644 --- a/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs @@ -2190,17 +2190,52 @@ fn riscv64_worst_case_instruction_size() { rs: fa0(), is_signed: true, in_type: F64, - out_type: I64, - is_sat: true, + out_type: I8, + is_sat: false, tmp: writable_a1(), }); - candidates.push(Inst::FcvtToInt { rd: writable_a0(), rs: fa0(), is_signed: true, in_type: F64, - out_type: I64, + out_type: I16, + is_sat: false, + tmp: writable_a1(), + }); + candidates.push(Inst::FcvtToInt { + rd: writable_a0(), + rs: fa0(), + is_signed: true, + in_type: F32, + out_type: I8, + is_sat: false, + tmp: writable_a1(), + }); + candidates.push(Inst::FcvtToInt { + rd: writable_a0(), + rs: fa0(), + is_signed: true, + in_type: F32, + out_type: I16, + is_sat: false, + tmp: writable_a1(), + }); + candidates.push(Inst::FcvtToInt { + rd: writable_a0(), + rs: fa0(), + is_signed: true, + in_type: F64, + out_type: I8, + is_sat: false, + tmp: writable_a1(), + }); + candidates.push(Inst::FcvtToInt { + rd: writable_a0(), + rs: fa0(), + is_signed: true, + in_type: F64, + out_type: I16, is_sat: false, tmp: writable_a1(), }); diff --git a/cranelift/codegen/src/isa/riscv64/inst/mod.rs b/cranelift/codegen/src/isa/riscv64/inst/mod.rs index 1f759a9b55..350b69b8a1 100644 --- a/cranelift/codegen/src/isa/riscv64/inst/mod.rs +++ b/cranelift/codegen/src/isa/riscv64/inst/mod.rs @@ -752,7 +752,7 @@ impl MachInst for Inst { fn worst_case_size() -> CodeOffset { // calculate by test function riscv64_worst_case_instruction_size() - 100 + 116 } fn ref_type_regclass(_settings: &settings::Flags) -> RegClass { diff --git a/cranelift/filetests/filetests/runtests/issue5528.clif b/cranelift/filetests/filetests/runtests/issue5528.clif new file mode 100644 index 0000000000..c147dc88a3 --- /dev/null +++ b/cranelift/filetests/filetests/runtests/issue5528.clif @@ -0,0 +1,20 @@ +test interpret +test run +target riscv64 + +function %a(f32) -> i8 system_v { +block0(v0: f32): + v1 = fcvt_to_sint_sat.i8 v0 + return v1 +} + +; run: %a(-0x1.000006p125) == -128 + + +function %b(f32) -> i16 system_v { +block0(v0: f32): + v1 = fcvt_to_sint_sat.i16 v0 + return v1 +} + +; run: %b(-0x1.000006p125) == -32768 \ No newline at end of file