[RISCV64] Emit correct lib call for fp(float/double) to ui/si

Since i32 is not legal in riscv64,
it always promoted to i64 before emitting lib call and
for conversions like float/double to int and float/double to unsigned int
wrong lib call was emitted. This commit fix it using custom lowering.

Differential Revision: https://reviews.llvm.org/D80526
This commit is contained in:
Kamlesh Kumar 2020-06-18 19:16:54 +05:30
parent b2f2adee00
commit 7622ea5835
2 changed files with 156 additions and 2 deletions

View File

@ -197,6 +197,14 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
setTruncStoreAction(MVT::f64, MVT::f16, Expand); setTruncStoreAction(MVT::f64, MVT::f16, Expand);
} }
if (Subtarget.is64Bit() &&
!(Subtarget.hasStdExtD() || Subtarget.hasStdExtF())) {
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i32, Custom);
setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i32, Custom);
}
setOperationAction(ISD::GlobalAddress, XLenVT, Custom); setOperationAction(ISD::GlobalAddress, XLenVT, Custom);
setOperationAction(ISD::BlockAddress, XLenVT, Custom); setOperationAction(ISD::BlockAddress, XLenVT, Custom);
setOperationAction(ISD::ConstantPool, XLenVT, Custom); setOperationAction(ISD::ConstantPool, XLenVT, Custom);
@ -904,6 +912,32 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
switch (N->getOpcode()) { switch (N->getOpcode()) {
default: default:
llvm_unreachable("Don't know how to custom type legalize this operation!"); llvm_unreachable("Don't know how to custom type legalize this operation!");
case ISD::STRICT_FP_TO_SINT:
case ISD::STRICT_FP_TO_UINT:
case ISD::FP_TO_SINT:
case ISD::FP_TO_UINT: {
bool IsStrict = N->isStrictFPOpcode();
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
"Unexpected custom legalisation");
SDValue Op0 = IsStrict ? N->getOperand(1) : N->getOperand(0);
RTLIB::Libcall LC;
if (N->getOpcode() == ISD::FP_TO_SINT ||
N->getOpcode() == ISD::STRICT_FP_TO_SINT)
LC = RTLIB::getFPTOSINT(Op0.getValueType(), N->getValueType(0));
else
LC = RTLIB::getFPTOUINT(Op0.getValueType(), N->getValueType(0));
MakeLibCallOptions CallOptions;
EVT OpVT = Op0.getValueType();
CallOptions.setTypeListBeforeSoften(OpVT, N->getValueType(0), true);
SDValue Chain = IsStrict ? N->getOperand(0) : SDValue();
SDValue Result;
std::tie(Result, Chain) =
makeLibCall(DAG, LC, N->getValueType(0), Op0, CallOptions, DL, Chain);
Results.push_back(Result);
if (IsStrict)
Results.push_back(Chain);
break;
}
case ISD::READCYCLECOUNTER: { case ISD::READCYCLECOUNTER: {
assert(!Subtarget.is64Bit() && assert(!Subtarget.is64Bit() &&
"READCYCLECOUNTER only has custom type legalization on riscv32"); "READCYCLECOUNTER only has custom type legalization on riscv32");

View File

@ -174,7 +174,7 @@ define i32 @fcvt_w_s(float %a) nounwind {
; RV64I: # %bb.0: ; RV64I: # %bb.0:
; RV64I-NEXT: addi sp, sp, -16 ; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp) ; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixsfdi ; RV64I-NEXT: call __fixsfsi
; RV64I-NEXT: ld ra, 8(sp) ; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16 ; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret ; RV64I-NEXT: ret
@ -187,7 +187,7 @@ define i32 @fcvt_wu_s(float %a) nounwind {
; RV64I: # %bb.0: ; RV64I: # %bb.0:
; RV64I-NEXT: addi sp, sp, -16 ; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp) ; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixunssfdi ; RV64I-NEXT: call __fixunssfsi
; RV64I-NEXT: ld ra, 8(sp) ; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16 ; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret ; RV64I-NEXT: ret
@ -710,3 +710,123 @@ define float @fp_trunc(double %a) nounwind {
%conv = fptrunc double %a to float %conv = fptrunc double %a to float
ret float %conv ret float %conv
} }
define i32 @fp32_to_ui32(float %a) nounwind {
; RV64I-LABEL: fp32_to_ui32:
; RV64I: # %bb.0: # %entry
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixunssfsi
; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
entry:
%conv = fptoui float %a to i32
ret i32 %conv
}
define i32 @fp32_to_si32(float %a) nounwind {
; RV64I-LABEL: fp32_to_si32:
; RV64I: # %bb.0: # %entry
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixsfsi
; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
entry:
%conv = fptosi float %a to i32
ret i32 %conv
}
define i32 @fp64_to_ui32(double %a) nounwind {
; RV64I-LABEL: fp64_to_ui32:
; RV64I: # %bb.0: # %entry
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixunsdfsi
; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
entry:
%conv = fptoui double %a to i32
ret i32 %conv
}
define i32 @fp64_to_si32(double %a) nounwind {
; RV64I-LABEL: fp64_to_si32:
; RV64I: # %bb.0: # %entry
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixdfsi
; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
entry:
%conv = fptosi double %a to i32
ret i32 %conv
}
declare i32 @llvm.experimental.constrained.fptoui.i32.f32(float, metadata)
declare i32 @llvm.experimental.constrained.fptosi.i32.f32(float, metadata)
declare i32 @llvm.experimental.constrained.fptosi.i32.f64(double, metadata)
declare i32 @llvm.experimental.constrained.fptoui.i32.f64(double, metadata)
define i32 @strict_fp32_to_ui32(float %a) nounwind strictfp {
; RV64I-LABEL: strict_fp32_to_ui32:
; RV64I: # %bb.0: # %entry
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixunssfsi
; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
entry:
%conv = tail call i32 @llvm.experimental.constrained.fptoui.i32.f32(float %a, metadata !"fpexcept.strict")
ret i32 %conv
}
define i32 @strict_fp32_to_si32(float %a) nounwind strictfp {
; RV64I-LABEL: strict_fp32_to_si32:
; RV64I: # %bb.0: # %entry
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixsfsi
; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
entry:
%conv = tail call i32 @llvm.experimental.constrained.fptosi.i32.f32(float %a, metadata !"fpexcept.strict")
ret i32 %conv
}
define i32 @strict_fp64_to_ui32(double %a) nounwind strictfp {
; RV64I-LABEL: strict_fp64_to_ui32:
; RV64I: # %bb.0: # %entry
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixunsdfsi
; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
entry:
%conv = tail call i32 @llvm.experimental.constrained.fptoui.i32.f64(double %a, metadata !"fpexcept.strict")
ret i32 %conv
}
define i32 @struct_fp64_to_si32(double %a) nounwind strictfp {
; RV64I-LABEL: struct_fp64_to_si32:
; RV64I: # %bb.0: # %entry
; RV64I-NEXT: addi sp, sp, -16
; RV64I-NEXT: sd ra, 8(sp)
; RV64I-NEXT: call __fixdfsi
; RV64I-NEXT: ld ra, 8(sp)
; RV64I-NEXT: addi sp, sp, 16
; RV64I-NEXT: ret
entry:
%conv = tail call i32 @llvm.experimental.constrained.fptosi.i32.f64(double %a, metadata !"fpexcept.strict")
ret i32 %conv
}