Skip to content

Commit 8142501

Browse files
committed
[RISCV] Add vector legalization for fmaximum/fminimum.
Reviewed By: fakepaper56 Differential Revision: https://reviews.llvm.org/D156937
1 parent beb339c commit 8142501

File tree

6 files changed

+1286
-50
lines changed

6 files changed

+1286
-50
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
835835
setCondCodeAction(VFPCCToExpand, VT, Expand);
836836

837837
setOperationAction({ISD::FMINNUM, ISD::FMAXNUM}, VT, Legal);
838+
setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, VT, Custom);
838839

839840
setOperationAction({ISD::FTRUNC, ISD::FCEIL, ISD::FFLOOR, ISD::FROUND,
840841
ISD::FROUNDEVEN, ISD::FRINT, ISD::FNEARBYINT,
@@ -1106,7 +1107,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
11061107
setOperationAction({ISD::FADD, ISD::FSUB, ISD::FMUL, ISD::FDIV,
11071108
ISD::FNEG, ISD::FABS, ISD::FCOPYSIGN, ISD::FSQRT,
11081109
ISD::FMA, ISD::FMINNUM, ISD::FMAXNUM,
1109-
ISD::IS_FPCLASS},
1110+
ISD::IS_FPCLASS, ISD::FMAXIMUM, ISD::FMINIMUM},
11101111
VT, Custom);
11111112

11121113
setOperationAction({ISD::FP_ROUND, ISD::FP_EXTEND}, VT, Custom);
@@ -4679,33 +4680,74 @@ SDValue RISCVTargetLowering::LowerIS_FPCLASS(SDValue Op,
46794680
static SDValue lowerFMAXIMUM_FMINIMUM(SDValue Op, SelectionDAG &DAG,
46804681
const RISCVSubtarget &Subtarget) {
46814682
SDLoc DL(Op);
4682-
EVT VT = Op.getValueType();
4683+
MVT VT = Op.getSimpleValueType();
46834684

46844685
SDValue X = Op.getOperand(0);
46854686
SDValue Y = Op.getOperand(1);
46864687

4687-
MVT XLenVT = Subtarget.getXLenVT();
4688+
if (!VT.isVector()) {
4689+
MVT XLenVT = Subtarget.getXLenVT();
4690+
4691+
// If X is a nan, replace Y with X. If Y is a nan, replace X with Y. This
4692+
// ensures that when one input is a nan, the other will also be a nan
4693+
// allowing the nan to propagate. If both inputs are nan, this will swap the
4694+
// inputs which is harmless.
46884695

4689-
// If X is a nan, replace Y with X. If Y is a nan, replace X with Y. This
4690-
// ensures that when one input is a nan, the other will also be a nan allowing
4691-
// the nan to propagate. If both inputs are nan, this will swap the inputs
4692-
// which is harmless.
4696+
SDValue NewY = Y;
4697+
if (!Op->getFlags().hasNoNaNs() && !DAG.isKnownNeverNaN(X)) {
4698+
SDValue XIsNonNan = DAG.getSetCC(DL, XLenVT, X, X, ISD::SETOEQ);
4699+
NewY = DAG.getSelect(DL, VT, XIsNonNan, Y, X);
4700+
}
46934701

4694-
SDValue NewY = Y;;
4695-
if (!Op->getFlags().hasNoNaNs() && !DAG.isKnownNeverNaN(X)) {
4696-
SDValue XIsNonNan = DAG.getSetCC(DL, XLenVT, X, X, ISD::SETOEQ);
4697-
NewY = DAG.getSelect(DL, VT, XIsNonNan, Y, X);
4702+
SDValue NewX = X;
4703+
if (!Op->getFlags().hasNoNaNs() && !DAG.isKnownNeverNaN(Y)) {
4704+
SDValue YIsNonNan = DAG.getSetCC(DL, XLenVT, Y, Y, ISD::SETOEQ);
4705+
NewX = DAG.getSelect(DL, VT, YIsNonNan, X, Y);
4706+
}
4707+
4708+
unsigned Opc =
4709+
Op.getOpcode() == ISD::FMAXIMUM ? RISCVISD::FMAX : RISCVISD::FMIN;
4710+
return DAG.getNode(Opc, DL, VT, NewX, NewY);
4711+
}
4712+
4713+
// Check no NaNs before converting to fixed vector scalable.
4714+
bool XIsNeverNan = Op->getFlags().hasNoNaNs() || DAG.isKnownNeverNaN(X);
4715+
bool YIsNeverNan = Op->getFlags().hasNoNaNs() || DAG.isKnownNeverNaN(Y);
4716+
4717+
MVT ContainerVT = VT;
4718+
if (VT.isFixedLengthVector()) {
4719+
ContainerVT = getContainerForFixedLengthVector(DAG, VT, Subtarget);
4720+
X = convertToScalableVector(ContainerVT, X, DAG, Subtarget);
4721+
Y = convertToScalableVector(ContainerVT, Y, DAG, Subtarget);
4722+
}
4723+
4724+
auto [Mask, VL] = getDefaultVLOps(VT, ContainerVT, DL, DAG, Subtarget);
4725+
4726+
SDValue NewY = Y;
4727+
if (!XIsNeverNan) {
4728+
SDValue XIsNonNan = DAG.getNode(RISCVISD::SETCC_VL, DL, Mask.getValueType(),
4729+
{X, X, DAG.getCondCode(ISD::SETOEQ),
4730+
DAG.getUNDEF(ContainerVT), Mask, VL});
4731+
NewY =
4732+
DAG.getNode(RISCVISD::VSELECT_VL, DL, ContainerVT, XIsNonNan, Y, X, VL);
46984733
}
46994734

47004735
SDValue NewX = X;
4701-
if (!Op->getFlags().hasNoNaNs() && !DAG.isKnownNeverNaN(Y)) {
4702-
SDValue YIsNonNan = DAG.getSetCC(DL, XLenVT, Y, Y, ISD::SETOEQ);
4703-
NewX = DAG.getSelect(DL, VT, YIsNonNan, X, Y);
4736+
if (!YIsNeverNan) {
4737+
SDValue YIsNonNan = DAG.getNode(RISCVISD::SETCC_VL, DL, Mask.getValueType(),
4738+
{Y, Y, DAG.getCondCode(ISD::SETOEQ),
4739+
DAG.getUNDEF(ContainerVT), Mask, VL});
4740+
NewX =
4741+
DAG.getNode(RISCVISD::VSELECT_VL, DL, ContainerVT, YIsNonNan, X, Y, VL);
47044742
}
47054743

47064744
unsigned Opc =
4707-
Op.getOpcode() == ISD::FMAXIMUM ? RISCVISD::FMAX : RISCVISD::FMIN;
4708-
return DAG.getNode(Opc, DL, VT, NewX, NewY);
4745+
Op.getOpcode() == ISD::FMAXIMUM ? RISCVISD::VFMAX_VL : RISCVISD::VFMIN_VL;
4746+
SDValue Res = DAG.getNode(Opc, DL, ContainerVT, NewX, NewY,
4747+
DAG.getUNDEF(ContainerVT), Mask, VL);
4748+
if (VT.isFixedLengthVector())
4749+
Res = convertFromScalableVector(VT, Res, DAG, Subtarget);
4750+
return Res;
47094751
}
47104752

47114753
/// Get a RISCV target specified VL op for a given SDNode.

llvm/test/Analysis/CostModel/RISCV/fp-min-max-abs.ll

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -158,24 +158,24 @@ define void @maxnum() {
158158
define void @minimum() {
159159
; CHECK-LABEL: 'minimum'
160160
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %1 = call float @llvm.minimum.f32(float undef, float undef)
161-
; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %2 = call <2 x float> @llvm.minimum.v2f32(<2 x float> undef, <2 x float> undef)
162-
; CHECK-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %3 = call <4 x float> @llvm.minimum.v4f32(<4 x float> undef, <4 x float> undef)
163-
; CHECK-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %4 = call <8 x float> @llvm.minimum.v8f32(<8 x float> undef, <8 x float> undef)
164-
; CHECK-NEXT: Cost Model: Found an estimated cost of 63 for instruction: %5 = call <16 x float> @llvm.minimum.v16f32(<16 x float> undef, <16 x float> undef)
165-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %6 = call <vscale x 1 x float> @llvm.minimum.nxv1f32(<vscale x 1 x float> undef, <vscale x 1 x float> undef)
166-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %7 = call <vscale x 2 x float> @llvm.minimum.nxv2f32(<vscale x 2 x float> undef, <vscale x 2 x float> undef)
167-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %8 = call <vscale x 4 x float> @llvm.minimum.nxv4f32(<vscale x 4 x float> undef, <vscale x 4 x float> undef)
168-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %9 = call <vscale x 8 x float> @llvm.minimum.nxv8f32(<vscale x 8 x float> undef, <vscale x 8 x float> undef)
169-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %10 = call <vscale x 16 x float> @llvm.minimum.nxv16f32(<vscale x 16 x float> undef, <vscale x 16 x float> undef)
161+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %2 = call <2 x float> @llvm.minimum.v2f32(<2 x float> undef, <2 x float> undef)
162+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %3 = call <4 x float> @llvm.minimum.v4f32(<4 x float> undef, <4 x float> undef)
163+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %4 = call <8 x float> @llvm.minimum.v8f32(<8 x float> undef, <8 x float> undef)
164+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %5 = call <16 x float> @llvm.minimum.v16f32(<16 x float> undef, <16 x float> undef)
165+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %6 = call <vscale x 1 x float> @llvm.minimum.nxv1f32(<vscale x 1 x float> undef, <vscale x 1 x float> undef)
166+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %7 = call <vscale x 2 x float> @llvm.minimum.nxv2f32(<vscale x 2 x float> undef, <vscale x 2 x float> undef)
167+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %8 = call <vscale x 4 x float> @llvm.minimum.nxv4f32(<vscale x 4 x float> undef, <vscale x 4 x float> undef)
168+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %9 = call <vscale x 8 x float> @llvm.minimum.nxv8f32(<vscale x 8 x float> undef, <vscale x 8 x float> undef)
169+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %10 = call <vscale x 16 x float> @llvm.minimum.nxv16f32(<vscale x 16 x float> undef, <vscale x 16 x float> undef)
170170
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %11 = call double @llvm.minimum.f64(double undef, double undef)
171-
; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %12 = call <2 x double> @llvm.minimum.v2f64(<2 x double> undef, <2 x double> undef)
172-
; CHECK-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %13 = call <4 x double> @llvm.minimum.v4f64(<4 x double> undef, <4 x double> undef)
173-
; CHECK-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %14 = call <8 x double> @llvm.minimum.v8f64(<8 x double> undef, <8 x double> undef)
174-
; CHECK-NEXT: Cost Model: Found an estimated cost of 63 for instruction: %15 = call <16 x double> @llvm.minimum.v16f64(<16 x double> undef, <16 x double> undef)
175-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %16 = call <vscale x 1 x double> @llvm.minimum.nxv1f64(<vscale x 1 x double> undef, <vscale x 1 x double> undef)
176-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %17 = call <vscale x 2 x double> @llvm.minimum.nxv2f64(<vscale x 2 x double> undef, <vscale x 2 x double> undef)
177-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %18 = call <vscale x 4 x double> @llvm.minimum.nxv4f64(<vscale x 4 x double> undef, <vscale x 4 x double> undef)
178-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %19 = call <vscale x 8 x double> @llvm.minimum.nxv8f64(<vscale x 8 x double> undef, <vscale x 8 x double> undef)
171+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %12 = call <2 x double> @llvm.minimum.v2f64(<2 x double> undef, <2 x double> undef)
172+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %13 = call <4 x double> @llvm.minimum.v4f64(<4 x double> undef, <4 x double> undef)
173+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %14 = call <8 x double> @llvm.minimum.v8f64(<8 x double> undef, <8 x double> undef)
174+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %15 = call <16 x double> @llvm.minimum.v16f64(<16 x double> undef, <16 x double> undef)
175+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %16 = call <vscale x 1 x double> @llvm.minimum.nxv1f64(<vscale x 1 x double> undef, <vscale x 1 x double> undef)
176+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %17 = call <vscale x 2 x double> @llvm.minimum.nxv2f64(<vscale x 2 x double> undef, <vscale x 2 x double> undef)
177+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %18 = call <vscale x 4 x double> @llvm.minimum.nxv4f64(<vscale x 4 x double> undef, <vscale x 4 x double> undef)
178+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %19 = call <vscale x 8 x double> @llvm.minimum.nxv8f64(<vscale x 8 x double> undef, <vscale x 8 x double> undef)
179179
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret void
180180
;
181181
call float @llvm.minimum.f32(float undef, float undef)
@@ -203,24 +203,24 @@ define void @minimum() {
203203
define void @maximum() {
204204
; CHECK-LABEL: 'maximum'
205205
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %1 = call float @llvm.maximum.f32(float undef, float undef)
206-
; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %2 = call <2 x float> @llvm.maximum.v2f32(<2 x float> undef, <2 x float> undef)
207-
; CHECK-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %3 = call <4 x float> @llvm.maximum.v4f32(<4 x float> undef, <4 x float> undef)
208-
; CHECK-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %4 = call <8 x float> @llvm.maximum.v8f32(<8 x float> undef, <8 x float> undef)
209-
; CHECK-NEXT: Cost Model: Found an estimated cost of 63 for instruction: %5 = call <16 x float> @llvm.maximum.v16f32(<16 x float> undef, <16 x float> undef)
210-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %6 = call <vscale x 1 x float> @llvm.maximum.nxv1f32(<vscale x 1 x float> undef, <vscale x 1 x float> undef)
211-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %7 = call <vscale x 2 x float> @llvm.maximum.nxv2f32(<vscale x 2 x float> undef, <vscale x 2 x float> undef)
212-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %8 = call <vscale x 4 x float> @llvm.maximum.nxv4f32(<vscale x 4 x float> undef, <vscale x 4 x float> undef)
213-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %9 = call <vscale x 8 x float> @llvm.maximum.nxv8f32(<vscale x 8 x float> undef, <vscale x 8 x float> undef)
214-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %10 = call <vscale x 16 x float> @llvm.maximum.nxv16f32(<vscale x 16 x float> undef, <vscale x 16 x float> undef)
206+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %2 = call <2 x float> @llvm.maximum.v2f32(<2 x float> undef, <2 x float> undef)
207+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %3 = call <4 x float> @llvm.maximum.v4f32(<4 x float> undef, <4 x float> undef)
208+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %4 = call <8 x float> @llvm.maximum.v8f32(<8 x float> undef, <8 x float> undef)
209+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %5 = call <16 x float> @llvm.maximum.v16f32(<16 x float> undef, <16 x float> undef)
210+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %6 = call <vscale x 1 x float> @llvm.maximum.nxv1f32(<vscale x 1 x float> undef, <vscale x 1 x float> undef)
211+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %7 = call <vscale x 2 x float> @llvm.maximum.nxv2f32(<vscale x 2 x float> undef, <vscale x 2 x float> undef)
212+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %8 = call <vscale x 4 x float> @llvm.maximum.nxv4f32(<vscale x 4 x float> undef, <vscale x 4 x float> undef)
213+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %9 = call <vscale x 8 x float> @llvm.maximum.nxv8f32(<vscale x 8 x float> undef, <vscale x 8 x float> undef)
214+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %10 = call <vscale x 16 x float> @llvm.maximum.nxv16f32(<vscale x 16 x float> undef, <vscale x 16 x float> undef)
215215
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %11 = call double @llvm.maximum.f64(double undef, double undef)
216-
; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %12 = call <2 x double> @llvm.maximum.v2f64(<2 x double> undef, <2 x double> undef)
217-
; CHECK-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %13 = call <4 x double> @llvm.maximum.v4f64(<4 x double> undef, <4 x double> undef)
218-
; CHECK-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %14 = call <8 x double> @llvm.maximum.v8f64(<8 x double> undef, <8 x double> undef)
219-
; CHECK-NEXT: Cost Model: Found an estimated cost of 63 for instruction: %15 = call <16 x double> @llvm.maximum.v16f64(<16 x double> undef, <16 x double> undef)
220-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %16 = call <vscale x 1 x double> @llvm.maximum.nxv1f64(<vscale x 1 x double> undef, <vscale x 1 x double> undef)
221-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %17 = call <vscale x 2 x double> @llvm.maximum.nxv2f64(<vscale x 2 x double> undef, <vscale x 2 x double> undef)
222-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %18 = call <vscale x 4 x double> @llvm.maximum.nxv4f64(<vscale x 4 x double> undef, <vscale x 4 x double> undef)
223-
; CHECK-NEXT: Cost Model: Invalid cost for instruction: %19 = call <vscale x 8 x double> @llvm.maximum.nxv8f64(<vscale x 8 x double> undef, <vscale x 8 x double> undef)
216+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %12 = call <2 x double> @llvm.maximum.v2f64(<2 x double> undef, <2 x double> undef)
217+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %13 = call <4 x double> @llvm.maximum.v4f64(<4 x double> undef, <4 x double> undef)
218+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %14 = call <8 x double> @llvm.maximum.v8f64(<8 x double> undef, <8 x double> undef)
219+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %15 = call <16 x double> @llvm.maximum.v16f64(<16 x double> undef, <16 x double> undef)
220+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %16 = call <vscale x 1 x double> @llvm.maximum.nxv1f64(<vscale x 1 x double> undef, <vscale x 1 x double> undef)
221+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %17 = call <vscale x 2 x double> @llvm.maximum.nxv2f64(<vscale x 2 x double> undef, <vscale x 2 x double> undef)
222+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %18 = call <vscale x 4 x double> @llvm.maximum.nxv4f64(<vscale x 4 x double> undef, <vscale x 4 x double> undef)
223+
; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %19 = call <vscale x 8 x double> @llvm.maximum.nxv8f64(<vscale x 8 x double> undef, <vscale x 8 x double> undef)
224224
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret void
225225
;
226226
call float @llvm.maximum.f32(float undef, float undef)

0 commit comments

Comments
 (0)