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 @@ -86,14 +86,16 @@ FMV_X_ANYEXTW_RV64, // FP to XLen int conversions. Corresponds to fcvt.l(u).s/d/h on RV64 and // fcvt.w(u).s/d/h on RV32. Unlike FP_TO_S/UINT these saturate out of - // range inputs. These are used for FP_TO_S/UINT_SAT lowering. - FCVT_X_RTZ, - FCVT_XU_RTZ, + // range inputs. These are used for FP_TO_S/UINT_SAT lowering. Rounding mode + // is passed as a TargetConstant operand using the RISCVFPRndMode enum. + FCVT_X, + FCVT_XU, // FP to 32 bit int conversions for RV64. These are used to keep track of the // result being sign extended to 64 bit. These saturate out of range inputs. - // Used for FP_TO_S/UINT and FP_TO_S/UINT_SAT lowering. - FCVT_W_RTZ_RV64, - FCVT_WU_RTZ_RV64, + // Used for FP_TO_S/UINT and FP_TO_S/UINT_SAT lowering. Rounding mode + // is passed as a TargetConstant operand using the RISCVFPRndMode enum. + FCVT_W_RV64, + FCVT_WU_RV64, // READ_CYCLE_WIDE - A read of the 64-bit cycle CSR on a 32-bit target // (returns (Lo, Hi)). It takes a chain operand. READ_CYCLE_WIDE, @@ -284,8 +286,8 @@ // FP to 32 bit int conversions for RV64. These are used to keep track of the // result being sign extended to 64 bit. These saturate out of range inputs. - STRICT_FCVT_W_RTZ_RV64 = ISD::FIRST_TARGET_STRICTFP_OPCODE, - STRICT_FCVT_WU_RTZ_RV64, + STRICT_FCVT_W_RV64 = ISD::FIRST_TARGET_STRICTFP_OPCODE, + STRICT_FCVT_WU_RV64, // Memory opcodes start here. VLE_VL = ISD::FIRST_TARGET_MEMORY_OPCODE, 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 @@ -1683,7 +1683,8 @@ return false; } -static SDValue lowerFP_TO_INT_SAT(SDValue Op, SelectionDAG &DAG) { +static SDValue lowerFP_TO_INT_SAT(SDValue Op, SelectionDAG &DAG, + const RISCVSubtarget &Subtarget) { // RISCV FP-to-int conversions saturate to the destination register size, but // don't produce 0 for nan. We can use a conversion instruction and fix the // nan case with a compare and a select. @@ -1695,15 +1696,17 @@ bool IsSigned = Op.getOpcode() == ISD::FP_TO_SINT_SAT; unsigned Opc; if (SatVT == DstVT) - Opc = IsSigned ? RISCVISD::FCVT_X_RTZ : RISCVISD::FCVT_XU_RTZ; + Opc = IsSigned ? RISCVISD::FCVT_X : RISCVISD::FCVT_XU; else if (DstVT == MVT::i64 && SatVT == MVT::i32) - Opc = IsSigned ? RISCVISD::FCVT_W_RTZ_RV64 : RISCVISD::FCVT_WU_RTZ_RV64; + Opc = IsSigned ? RISCVISD::FCVT_W_RV64 : RISCVISD::FCVT_WU_RV64; else return SDValue(); // FIXME: Support other SatVTs by clamping before or after the conversion. SDLoc DL(Op); - SDValue FpToInt = DAG.getNode(Opc, DL, DstVT, Src); + SDValue FpToInt = DAG.getNode( + Opc, DL, DstVT, Src, + DAG.getTargetConstant(RISCVFPRndMode::RTZ, DL, Subtarget.getXLenVT())); SDValue ZeroInt = DAG.getConstant(0, DL, DstVT); return DAG.getSelectCC(DL, Src, Src, ZeroInt, FpToInt, ISD::CondCode::SETUO); @@ -3017,7 +3020,7 @@ } case ISD::FP_TO_SINT_SAT: case ISD::FP_TO_UINT_SAT: - return lowerFP_TO_INT_SAT(Op, DAG); + return lowerFP_TO_INT_SAT(Op, DAG, Subtarget); case ISD::FTRUNC: case ISD::FCEIL: case ISD::FFLOOR: @@ -5792,17 +5795,20 @@ if (!isTypeLegal(Op0.getValueType())) return; if (IsStrict) { - unsigned Opc = IsSigned ? RISCVISD::STRICT_FCVT_W_RTZ_RV64 - : RISCVISD::STRICT_FCVT_WU_RTZ_RV64; + unsigned Opc = IsSigned ? RISCVISD::STRICT_FCVT_W_RV64 + : RISCVISD::STRICT_FCVT_WU_RV64; SDVTList VTs = DAG.getVTList(MVT::i64, MVT::Other); - SDValue Res = DAG.getNode(Opc, DL, VTs, N->getOperand(0), Op0); + SDValue Res = DAG.getNode( + Opc, DL, VTs, N->getOperand(0), Op0, + DAG.getTargetConstant(RISCVFPRndMode::RTZ, DL, MVT::i64)); Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); Results.push_back(Res.getValue(1)); return; } - unsigned Opc = - IsSigned ? RISCVISD::FCVT_W_RTZ_RV64 : RISCVISD::FCVT_WU_RTZ_RV64; - SDValue Res = DAG.getNode(Opc, DL, MVT::i64, Op0); + unsigned Opc = IsSigned ? RISCVISD::FCVT_W_RV64 : RISCVISD::FCVT_WU_RV64; + SDValue Res = + DAG.getNode(Opc, DL, MVT::i64, Op0, + DAG.getTargetConstant(RISCVFPRndMode::RTZ, DL, MVT::i64)); Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); return; } @@ -7795,10 +7801,10 @@ case RISCVISD::UNSHFLW: case RISCVISD::BCOMPRESSW: case RISCVISD::BDECOMPRESSW: - case RISCVISD::FCVT_W_RTZ_RV64: - case RISCVISD::FCVT_WU_RTZ_RV64: - case RISCVISD::STRICT_FCVT_W_RTZ_RV64: - case RISCVISD::STRICT_FCVT_WU_RTZ_RV64: + case RISCVISD::FCVT_W_RV64: + case RISCVISD::FCVT_WU_RV64: + case RISCVISD::STRICT_FCVT_W_RV64: + case RISCVISD::STRICT_FCVT_WU_RV64: // TODO: As the result is sign-extended, this is conservatively correct. A // more precise answer could be calculated for SRAW depending on known // bits in the shift amount. @@ -9533,12 +9539,12 @@ NODE_NAME_CASE(FMV_X_ANYEXTH) NODE_NAME_CASE(FMV_W_X_RV64) NODE_NAME_CASE(FMV_X_ANYEXTW_RV64) - NODE_NAME_CASE(FCVT_X_RTZ) - NODE_NAME_CASE(FCVT_XU_RTZ) - NODE_NAME_CASE(FCVT_W_RTZ_RV64) - NODE_NAME_CASE(FCVT_WU_RTZ_RV64) - NODE_NAME_CASE(STRICT_FCVT_W_RTZ_RV64) - NODE_NAME_CASE(STRICT_FCVT_WU_RTZ_RV64) + NODE_NAME_CASE(FCVT_X) + NODE_NAME_CASE(FCVT_XU) + NODE_NAME_CASE(FCVT_W_RV64) + NODE_NAME_CASE(FCVT_WU_RV64) + NODE_NAME_CASE(STRICT_FCVT_W_RV64) + NODE_NAME_CASE(STRICT_FCVT_WU_RV64) NODE_NAME_CASE(READ_CYCLE_WIDE) NODE_NAME_CASE(GREV) NODE_NAME_CASE(GREVW) 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 @@ -266,8 +266,8 @@ def : Pat<(i32 (any_fp_to_uint FPR64:$rs1)), (FCVT_WU_D FPR64:$rs1, 0b001)>; // Saturating double->[u]int32. -def : Pat<(i32 (riscv_fcvt_x_rtz FPR64:$rs1)), (FCVT_W_D $rs1, 0b001)>; -def : Pat<(i32 (riscv_fcvt_xu_rtz FPR64:$rs1)), (FCVT_WU_D $rs1, 0b001)>; +def : Pat<(i32 (riscv_fcvt_x FPR64:$rs1, timm:$frm)), (FCVT_W_D $rs1, timm:$frm)>; +def : Pat<(i32 (riscv_fcvt_xu FPR64:$rs1, timm:$frm)), (FCVT_WU_D $rs1, timm:$frm)>; // float->int32 with current rounding mode. def : Pat<(i32 (any_lrint FPR64:$rs1)), (FCVT_W_D $rs1, 0b111)>; @@ -292,16 +292,16 @@ // Use target specific isd nodes to help us remember the result is sign // extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be // duplicated if it has another user that didn't need the sign_extend. -def : Pat<(riscv_any_fcvt_w_rtz_rv64 FPR64:$rs1), (FCVT_W_D $rs1, 0b001)>; -def : Pat<(riscv_any_fcvt_wu_rtz_rv64 FPR64:$rs1), (FCVT_WU_D $rs1, 0b001)>; +def : Pat<(riscv_any_fcvt_w_rv64 FPR64:$rs1, timm:$frm), (FCVT_W_D $rs1, timm:$frm)>; +def : Pat<(riscv_any_fcvt_wu_rv64 FPR64:$rs1, timm:$frm), (FCVT_WU_D $rs1, timm:$frm)>; // [u]int32->fp def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_D_W $rs1)>; def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_D_WU $rs1)>; // Saturating double->[u]int64. -def : Pat<(i64 (riscv_fcvt_x_rtz FPR64:$rs1)), (FCVT_L_D $rs1, 0b001)>; -def : Pat<(i64 (riscv_fcvt_xu_rtz FPR64:$rs1)), (FCVT_LU_D $rs1, 0b001)>; +def : Pat<(i64 (riscv_fcvt_x FPR64:$rs1, timm:$frm)), (FCVT_L_D $rs1, timm:$frm)>; +def : Pat<(i64 (riscv_fcvt_xu FPR64:$rs1, timm:$frm)), (FCVT_LU_D $rs1, timm:$frm)>; // double->[u]int64. Round-to-zero must be used. def : Pat<(i64 (any_fp_to_sint FPR64:$rs1)), (FCVT_L_D FPR64:$rs1, 0b001)>; 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 @@ -20,36 +20,38 @@ def SDT_RISCVFMV_X_ANYEXTW_RV64 : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>; def SDT_RISCVFCVT_W_RV64 - : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisFP<1>]>; + : SDTypeProfile<1, 2, [SDTCisVT<0, i64>, SDTCisFP<1>, + SDTCisVT<2, i64>]>; def SDT_RISCVFCVT_X - : SDTypeProfile<1, 1, [SDTCisVT<0, XLenVT>, SDTCisFP<1>]>; + : SDTypeProfile<1, 2, [SDTCisVT<0, XLenVT>, SDTCisFP<1>, + SDTCisVT<2, XLenVT>]>; def riscv_fmv_w_x_rv64 : SDNode<"RISCVISD::FMV_W_X_RV64", SDT_RISCVFMV_W_X_RV64>; def riscv_fmv_x_anyextw_rv64 : SDNode<"RISCVISD::FMV_X_ANYEXTW_RV64", SDT_RISCVFMV_X_ANYEXTW_RV64>; -def riscv_fcvt_w_rtz_rv64 - : SDNode<"RISCVISD::FCVT_W_RTZ_RV64", SDT_RISCVFCVT_W_RV64>; -def riscv_fcvt_wu_rtz_rv64 - : SDNode<"RISCVISD::FCVT_WU_RTZ_RV64", SDT_RISCVFCVT_W_RV64>; -def riscv_fcvt_x_rtz - : SDNode<"RISCVISD::FCVT_X_RTZ", SDT_RISCVFCVT_X>; -def riscv_fcvt_xu_rtz - : SDNode<"RISCVISD::FCVT_XU_RTZ", SDT_RISCVFCVT_X>; - -def riscv_strict_fcvt_w_rtz_rv64 - : SDNode<"RISCVISD::STRICT_FCVT_W_RTZ_RV64", SDT_RISCVFCVT_W_RV64, +def riscv_fcvt_w_rv64 + : SDNode<"RISCVISD::FCVT_W_RV64", SDT_RISCVFCVT_W_RV64>; +def riscv_fcvt_wu_rv64 + : SDNode<"RISCVISD::FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64>; +def riscv_fcvt_x + : SDNode<"RISCVISD::FCVT_X", SDT_RISCVFCVT_X>; +def riscv_fcvt_xu + : SDNode<"RISCVISD::FCVT_XU", SDT_RISCVFCVT_X>; + +def riscv_strict_fcvt_w_rv64 + : SDNode<"RISCVISD::STRICT_FCVT_W_RV64", SDT_RISCVFCVT_W_RV64, [SDNPHasChain]>; -def riscv_strict_fcvt_wu_rtz_rv64 - : SDNode<"RISCVISD::STRICT_FCVT_WU_RTZ_RV64", SDT_RISCVFCVT_W_RV64, +def riscv_strict_fcvt_wu_rv64 + : SDNode<"RISCVISD::STRICT_FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64, [SDNPHasChain]>; -def riscv_any_fcvt_w_rtz_rv64 : PatFrags<(ops node:$src), - [(riscv_strict_fcvt_w_rtz_rv64 node:$src), - (riscv_fcvt_w_rtz_rv64 node:$src)]>; -def riscv_any_fcvt_wu_rtz_rv64 : PatFrags<(ops node:$src), - [(riscv_strict_fcvt_wu_rtz_rv64 node:$src), - (riscv_fcvt_wu_rtz_rv64 node:$src)]>; +def riscv_any_fcvt_w_rv64 : PatFrags<(ops node:$src, node:$frm), + [(riscv_strict_fcvt_w_rv64 node:$src, node:$frm), + (riscv_fcvt_w_rv64 node:$src, node:$frm)]>; +def riscv_any_fcvt_wu_rv64 : PatFrags<(ops node:$src, node:$frm), + [(riscv_strict_fcvt_wu_rv64 node:$src, node:$frm), + (riscv_fcvt_wu_rv64 node:$src, node:$frm)]>; //===----------------------------------------------------------------------===// // Operand and SDNode transformation definitions. @@ -401,8 +403,8 @@ def : Pat<(i32 (any_fp_to_uint FPR32:$rs1)), (FCVT_WU_S $rs1, 0b001)>; // Saturating float->[u]int32. -def : Pat<(i32 (riscv_fcvt_x_rtz FPR32:$rs1)), (FCVT_W_S $rs1, 0b001)>; -def : Pat<(i32 (riscv_fcvt_xu_rtz FPR32:$rs1)), (FCVT_WU_S $rs1, 0b001)>; +def : Pat<(i32 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_W_S $rs1, timm:$frm)>; +def : Pat<(i32 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_WU_S $rs1, timm:$frm)>; // float->int32 with current rounding mode. def : Pat<(i32 (any_lrint FPR32:$rs1)), (FCVT_W_S $rs1, 0b111)>; @@ -425,16 +427,16 @@ // Use target specific isd nodes to help us remember the result is sign // extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be // duplicated if it has another user that didn't need the sign_extend. -def : Pat<(riscv_any_fcvt_w_rtz_rv64 FPR32:$rs1), (FCVT_W_S $rs1, 0b001)>; -def : Pat<(riscv_any_fcvt_wu_rtz_rv64 FPR32:$rs1), (FCVT_WU_S $rs1, 0b001)>; +def : Pat<(riscv_any_fcvt_w_rv64 FPR32:$rs1, timm:$frm), (FCVT_W_S $rs1, timm:$frm)>; +def : Pat<(riscv_any_fcvt_wu_rv64 FPR32:$rs1, timm:$frm), (FCVT_WU_S $rs1, timm:$frm)>; // float->[u]int64. Round-to-zero must be used. def : Pat<(i64 (any_fp_to_sint FPR32:$rs1)), (FCVT_L_S $rs1, 0b001)>; def : Pat<(i64 (any_fp_to_uint FPR32:$rs1)), (FCVT_LU_S $rs1, 0b001)>; // Saturating float->[u]int64. -def : Pat<(i64 (riscv_fcvt_x_rtz FPR32:$rs1)), (FCVT_L_S $rs1, 0b001)>; -def : Pat<(i64 (riscv_fcvt_xu_rtz FPR32:$rs1)), (FCVT_LU_S $rs1, 0b001)>; +def : Pat<(i64 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_L_S $rs1, timm:$frm)>; +def : Pat<(i64 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_LU_S $rs1, timm:$frm)>; // float->int64 with current rounding mode. def : Pat<(i64 (any_lrint FPR32:$rs1)), (FCVT_L_S $rs1, 0b111)>; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td @@ -283,8 +283,8 @@ def : Pat<(i32 (any_fp_to_uint FPR16:$rs1)), (FCVT_WU_H $rs1, 0b001)>; // Saturating float->[u]int32. -def : Pat<(i32 (riscv_fcvt_x_rtz FPR16:$rs1)), (FCVT_W_H $rs1, 0b001)>; -def : Pat<(i32 (riscv_fcvt_xu_rtz FPR16:$rs1)), (FCVT_WU_H $rs1, 0b001)>; +def : Pat<(i32 (riscv_fcvt_x FPR16:$rs1, timm:$frm)), (FCVT_W_H $rs1, timm:$frm)>; +def : Pat<(i32 (riscv_fcvt_xu FPR16:$rs1, timm:$frm)), (FCVT_WU_H $rs1, timm:$frm)>; // half->int32 with current rounding mode. def : Pat<(i32 (any_lrint FPR16:$rs1)), (FCVT_W_H $rs1, 0b111)>; @@ -301,16 +301,16 @@ // Use target specific isd nodes to help us remember the result is sign // extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be // duplicated if it has another user that didn't need the sign_extend. -def : Pat<(riscv_any_fcvt_w_rtz_rv64 FPR16:$rs1), (FCVT_W_H $rs1, 0b001)>; -def : Pat<(riscv_any_fcvt_wu_rtz_rv64 FPR16:$rs1), (FCVT_WU_H $rs1, 0b001)>; +def : Pat<(riscv_any_fcvt_w_rv64 FPR16:$rs1, timm:$frm), (FCVT_W_H $rs1, timm:$frm)>; +def : Pat<(riscv_any_fcvt_wu_rv64 FPR16:$rs1, timm:$frm), (FCVT_WU_H $rs1, timm:$frm)>; // half->[u]int64. Round-to-zero must be used. def : Pat<(i64 (any_fp_to_sint FPR16:$rs1)), (FCVT_L_H $rs1, 0b001)>; def : Pat<(i64 (any_fp_to_uint FPR16:$rs1)), (FCVT_LU_H $rs1, 0b001)>; // Saturating float->[u]int64. -def : Pat<(i64 (riscv_fcvt_x_rtz FPR16:$rs1)), (FCVT_L_H $rs1, 0b001)>; -def : Pat<(i64 (riscv_fcvt_xu_rtz FPR16:$rs1)), (FCVT_LU_H $rs1, 0b001)>; +def : Pat<(i64 (riscv_fcvt_x FPR16:$rs1, timm:$frm)), (FCVT_L_H $rs1, timm:$frm)>; +def : Pat<(i64 (riscv_fcvt_xu FPR16:$rs1, timm:$frm)), (FCVT_LU_H $rs1, timm:$frm)>; // half->int64 with current rounding mode. def : Pat<(i64 (any_lrint FPR16:$rs1)), (FCVT_L_H $rs1, 0b111)>;