diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -209,7 +209,7 @@ SDValue lowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; - + SDValue lowerSETCC(SDValue Op, SelectionDAG &DAG) const; bool isEligibleForTailCallOptimization( CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, const SmallVector &ArgLocs) const; diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -211,6 +211,12 @@ setOperationAction(ISD::TRAP, MVT::Other, Legal); setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i64, Legal); + setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i64, Legal); + setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Custom); + setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Custom); + setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Custom); + setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Custom); if (Subtarget.hasStdExtA()) { setMaxAtomicSizeInBitsSupported(Subtarget.getXLen()); @@ -432,6 +438,9 @@ } case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG); + case ISD::STRICT_FSETCC: + case ISD::STRICT_FSETCCS: + return lowerSETCC(Op, DAG); } } @@ -835,6 +844,18 @@ return DAG.getMergeValues(Parts, DL); } +SDValue RISCVTargetLowering::lowerSETCC(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT VT = Op.getValueType(); + SDValue Chain = Op.getOperand(0); + SDValue LHS = Op.getOperand(1); + SDValue RHS = Op.getOperand(2); + ISD::CondCode CC = cast(Op.getOperand(3))->get(); + SDValue Result = + DAG.getNode(ISD::SETCC, DL, VT, LHS, RHS, DAG.getCondCode(CC)); + return DAG.getMergeValues({Result, Chain}, DL); +} + SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const { unsigned IntNo = cast(Op.getOperand(0))->getZExtValue(); diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td @@ -352,8 +352,8 @@ def : Pat<(fp_to_uint FPR64:$rs1), (FCVT_WU_D FPR64:$rs1, 0b001)>; // [u]int->double. -def : Pat<(sint_to_fp GPR:$rs1), (FCVT_D_W GPR:$rs1)>; -def : Pat<(uint_to_fp GPR:$rs1), (FCVT_D_WU GPR:$rs1)>; +def : Pat<(any_sint_to_fp GPR:$rs1), (FCVT_D_W GPR:$rs1)>; +def : Pat<(any_uint_to_fp GPR:$rs1), (FCVT_D_WU GPR:$rs1)>; } // Predicates = [HasStdExtD, IsRV32] let Predicates = [HasStdExtD, IsRV64] in { @@ -372,13 +372,13 @@ (FCVT_WU_D $rs1, 0b001)>; // [u]int32->fp -def : Pat<(sint_to_fp (sext_inreg GPR:$rs1, i32)), (FCVT_D_W $rs1)>; -def : Pat<(uint_to_fp (zexti32 GPR:$rs1)), (FCVT_D_WU $rs1)>; +def : Pat<(any_sint_to_fp (sext_inreg GPR:$rs1, i32)), (FCVT_D_W $rs1)>; +def : Pat<(any_uint_to_fp (zexti32 GPR:$rs1)), (FCVT_D_WU $rs1)>; def : Pat<(fp_to_sint FPR64:$rs1), (FCVT_L_D FPR64:$rs1, 0b001)>; def : Pat<(fp_to_uint FPR64:$rs1), (FCVT_LU_D FPR64:$rs1, 0b001)>; // [u]int64->fp. Match GCC and default to using dynamic rounding mode. -def : Pat<(sint_to_fp GPR:$rs1), (FCVT_D_L GPR:$rs1, 0b111)>; -def : Pat<(uint_to_fp GPR:$rs1), (FCVT_D_LU GPR:$rs1, 0b111)>; +def : Pat<(any_sint_to_fp GPR:$rs1), (FCVT_D_L GPR:$rs1, 0b111)>; +def : Pat<(any_uint_to_fp GPR:$rs1), (FCVT_D_LU GPR:$rs1, 0b111)>; } // Predicates = [HasStdExtD, IsRV64] diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td @@ -394,8 +394,8 @@ def : Pat<(fp_to_uint FPR32:$rs1), (FCVT_WU_S $rs1, 0b001)>; // [u]int->float. Match GCC and default to using dynamic rounding mode. -def : Pat<(sint_to_fp GPR:$rs1), (FCVT_S_W $rs1, 0b111)>; -def : Pat<(uint_to_fp GPR:$rs1), (FCVT_S_WU $rs1, 0b111)>; +def : Pat<(any_sint_to_fp GPR:$rs1), (FCVT_S_W $rs1, 0b111)>; +def : Pat<(any_uint_to_fp GPR:$rs1), (FCVT_S_WU $rs1, 0b111)>; } // Predicates = [HasStdExtF, IsRV32] let Predicates = [HasStdExtF, IsRV64] in { @@ -416,8 +416,8 @@ def : Pat<(fp_to_uint FPR32:$rs1), (FCVT_LU_S $rs1, 0b001)>; // [u]int->fp. Match GCC and default to using dynamic rounding mode. -def : Pat<(sint_to_fp (sext_inreg GPR:$rs1, i32)), (FCVT_S_W $rs1, 0b111)>; -def : Pat<(uint_to_fp (zexti32 GPR:$rs1)), (FCVT_S_WU $rs1, 0b111)>; -def : Pat<(sint_to_fp GPR:$rs1), (FCVT_S_L $rs1, 0b111)>; -def : Pat<(uint_to_fp GPR:$rs1), (FCVT_S_LU $rs1, 0b111)>; +def : Pat<(any_sint_to_fp (sext_inreg GPR:$rs1, i32)), (FCVT_S_W $rs1, 0b111)>; +def : Pat<(any_uint_to_fp (zexti32 GPR:$rs1)), (FCVT_S_WU $rs1, 0b111)>; +def : Pat<(any_sint_to_fp GPR:$rs1), (FCVT_S_L $rs1, 0b111)>; +def : Pat<(any_uint_to_fp GPR:$rs1), (FCVT_S_LU $rs1, 0b111)>; } // Predicates = [HasStdExtF, IsRV64] diff --git a/llvm/test/CodeGen/RISCV/fp-strict.ll b/llvm/test/CodeGen/RISCV/fp-strict.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/fp-strict.ll @@ -0,0 +1,161 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -O1 -mtriple=riscv64 -mattr="+d" -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64D +; RUN: llc -O1 -mtriple=riscv32 -mattr="+d" -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32D + +declare i1 @llvm.experimental.constrained.fcmps.f64(double, double, metadata, metadata) +declare i1 @llvm.experimental.constrained.fcmp.f64(double, double, metadata, metadata) + +define i1 @f_lt(double %a, double %b) strictfp nounwind { +; RV64D-LABEL: f_lt: +; RV64D: # %bb.0: # %entry +; RV64D-NEXT: fmv.d.x ft0, a1 +; RV64D-NEXT: fmv.d.x ft1, a0 +; RV64D-NEXT: flt.d a0, ft1, ft0 +; RV64D-NEXT: ret +; +; RV32D-LABEL: f_lt: +; RV32D: # %bb.0: # %entry +; RV32D-NEXT: addi sp, sp, -16 +; RV32D-NEXT: sw a2, 8(sp) +; RV32D-NEXT: sw a3, 12(sp) +; RV32D-NEXT: fld ft0, 8(sp) +; RV32D-NEXT: sw a0, 8(sp) +; RV32D-NEXT: sw a1, 12(sp) +; RV32D-NEXT: fld ft1, 8(sp) +; RV32D-NEXT: flt.d a0, ft1, ft0 +; RV32D-NEXT: addi sp, sp, 16 +; RV32D-NEXT: ret +entry: + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"olt", metadata !"fpexcept.strict") + ret i1 %cmp +} + +define i1 @f_leq(double %a, double %b) strictfp nounwind { +; RV64D-LABEL: f_leq: +; RV64D: # %bb.0: # %entry +; RV64D-NEXT: fmv.d.x ft0, a1 +; RV64D-NEXT: fmv.d.x ft1, a0 +; RV64D-NEXT: fle.d a0, ft1, ft0 +; RV64D-NEXT: ret +; +; RV32D-LABEL: f_leq: +; RV32D: # %bb.0: # %entry +; RV32D-NEXT: addi sp, sp, -16 +; RV32D-NEXT: sw a2, 8(sp) +; RV32D-NEXT: sw a3, 12(sp) +; RV32D-NEXT: fld ft0, 8(sp) +; RV32D-NEXT: sw a0, 8(sp) +; RV32D-NEXT: sw a1, 12(sp) +; RV32D-NEXT: fld ft1, 8(sp) +; RV32D-NEXT: fle.d a0, ft1, ft0 +; RV32D-NEXT: addi sp, sp, 16 +; RV32D-NEXT: ret +entry: + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"ole", metadata !"fpexcept.strict") + ret i1 %cmp +} + +define i1 @f_gt(double %a, double %b) strictfp nounwind { +; RV64D-LABEL: f_gt: +; RV64D: # %bb.0: # %entry +; RV64D-NEXT: fmv.d.x ft0, a0 +; RV64D-NEXT: fmv.d.x ft1, a1 +; RV64D-NEXT: flt.d a0, ft1, ft0 +; RV64D-NEXT: ret +; +; RV32D-LABEL: f_gt: +; RV32D: # %bb.0: # %entry +; RV32D-NEXT: addi sp, sp, -16 +; RV32D-NEXT: sw a0, 8(sp) +; RV32D-NEXT: sw a1, 12(sp) +; RV32D-NEXT: fld ft0, 8(sp) +; RV32D-NEXT: sw a2, 8(sp) +; RV32D-NEXT: sw a3, 12(sp) +; RV32D-NEXT: fld ft1, 8(sp) +; RV32D-NEXT: flt.d a0, ft1, ft0 +; RV32D-NEXT: addi sp, sp, 16 +; RV32D-NEXT: ret +entry: + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"ogt", metadata !"fpexcept.strict") + ret i1 %cmp +} + +define i1 @f_geq(double %a, double %b) strictfp nounwind { +; RV64D-LABEL: f_geq: +; RV64D: # %bb.0: # %entry +; RV64D-NEXT: fmv.d.x ft0, a0 +; RV64D-NEXT: fmv.d.x ft1, a1 +; RV64D-NEXT: fle.d a0, ft1, ft0 +; RV64D-NEXT: ret +; +; RV32D-LABEL: f_geq: +; RV32D: # %bb.0: # %entry +; RV32D-NEXT: addi sp, sp, -16 +; RV32D-NEXT: sw a0, 8(sp) +; RV32D-NEXT: sw a1, 12(sp) +; RV32D-NEXT: fld ft0, 8(sp) +; RV32D-NEXT: sw a2, 8(sp) +; RV32D-NEXT: sw a3, 12(sp) +; RV32D-NEXT: fld ft1, 8(sp) +; RV32D-NEXT: fle.d a0, ft1, ft0 +; RV32D-NEXT: addi sp, sp, 16 +; RV32D-NEXT: ret +entry: + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"oge", metadata !"fpexcept.strict") + ret i1 %cmp +} + +define i1 @f_eq(double %a, double %b) strictfp nounwind { +; RV64D-LABEL: f_eq: +; RV64D: # %bb.0: # %entry +; RV64D-NEXT: fmv.d.x ft0, a1 +; RV64D-NEXT: fmv.d.x ft1, a0 +; RV64D-NEXT: feq.d a0, ft1, ft0 +; RV64D-NEXT: ret +; +; RV32D-LABEL: f_eq: +; RV32D: # %bb.0: # %entry +; RV32D-NEXT: addi sp, sp, -16 +; RV32D-NEXT: sw a2, 8(sp) +; RV32D-NEXT: sw a3, 12(sp) +; RV32D-NEXT: fld ft0, 8(sp) +; RV32D-NEXT: sw a0, 8(sp) +; RV32D-NEXT: sw a1, 12(sp) +; RV32D-NEXT: fld ft1, 8(sp) +; RV32D-NEXT: feq.d a0, ft1, ft0 +; RV32D-NEXT: addi sp, sp, 16 +; RV32D-NEXT: ret +entry: + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"oeq", metadata !"fpexcept.strict") + ret i1 %cmp +} + +define i1 @f_neq(double %a, double %b) strictfp nounwind { +; RV64D-LABEL: f_neq: +; RV64D: # %bb.0: # %entry +; RV64D-NEXT: fmv.d.x ft0, a1 +; RV64D-NEXT: fmv.d.x ft1, a0 +; RV64D-NEXT: feq.d a0, ft1, ft0 +; RV64D-NEXT: xori a0, a0, 1 +; RV64D-NEXT: ret +; +; RV32D-LABEL: f_neq: +; RV32D: # %bb.0: # %entry +; RV32D-NEXT: addi sp, sp, -16 +; RV32D-NEXT: sw a2, 8(sp) +; RV32D-NEXT: sw a3, 12(sp) +; RV32D-NEXT: fld ft0, 8(sp) +; RV32D-NEXT: sw a0, 8(sp) +; RV32D-NEXT: sw a1, 12(sp) +; RV32D-NEXT: fld ft1, 8(sp) +; RV32D-NEXT: feq.d a0, ft1, ft0 +; RV32D-NEXT: xori a0, a0, 1 +; RV32D-NEXT: addi sp, sp, 16 +; RV32D-NEXT: ret +entry: + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"une", metadata !"fpexcept.strict") + ret i1 %cmp +} +