Skip to content

Commit add1925

Browse files
[AArch64] NFCI: Simplify LowerVectorFP_TO_INT_SAT (part 2) (#207199)
This simplifies the logic a bit more, such that the flow of the lowering is as follows: * Try to promote if necessary (fp16/bf16 types or src < dst) * Try to handle natively (satwidth == srcwidth == dstwidth) * Otherwise use min/max + truncate.
1 parent 922b1a9 commit add1925

1 file changed

Lines changed: 70 additions & 47 deletions

File tree

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5192,13 +5192,14 @@ AArch64TargetLowering::LowerVectorFP_TO_INT_SAT(SDValue Op,
51925192
// AArch64 FP-to-int conversions saturate to the destination element size, so
51935193
// we can lower common saturating conversions to simple instructions.
51945194
SDValue SrcVal = Op.getOperand(0);
5195-
EVT SrcVT = SrcVal.getValueType();
5196-
EVT DstVT = Op.getValueType();
5197-
EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
5198-
5199-
uint64_t SrcElementWidth = SrcVT.getScalarSizeInBits();
5200-
uint64_t DstElementWidth = DstVT.getScalarSizeInBits();
5201-
uint64_t SatWidth = SatVT.getScalarSizeInBits();
5195+
const EVT SrcVT = SrcVal.getValueType();
5196+
const EVT DstVT = Op.getValueType();
5197+
const EVT DstElementVT = DstVT.getVectorElementType();
5198+
const EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
5199+
5200+
const uint64_t SrcElementWidth = SrcVT.getScalarSizeInBits();
5201+
const uint64_t DstElementWidth = DstVT.getScalarSizeInBits();
5202+
const uint64_t SatWidth = SatVT.getScalarSizeInBits();
52025203
assert(SatWidth <= DstElementWidth &&
52035204
"Saturation width cannot exceed result width");
52045205

@@ -5208,54 +5209,76 @@ AArch64TargetLowering::LowerVectorFP_TO_INT_SAT(SDValue Op,
52085209
if (DstVT.isScalableVector())
52095210
return SDValue();
52105211

5211-
EVT SrcElementVT = SrcVT.getVectorElementType();
5212+
const EVT SrcElementVT = SrcVT.getVectorElementType();
5213+
if (SrcElementVT != MVT::f64 && SrcElementVT != MVT::f32 &&
5214+
SrcElementVT != MVT::f16 && SrcElementVT != MVT::bf16)
5215+
return SDValue();
5216+
5217+
// Returns true if the operation can be matched by an isel pattern directly.
5218+
auto CanHandleNatively = [&DstVT, &SatWidth](EVT SrcVT) -> bool {
5219+
return SrcVT.getScalarSizeInBits() == DstVT.getScalarSizeInBits() &&
5220+
SrcVT.getScalarSizeInBits() == SatWidth;
5221+
};
5222+
5223+
// Returns true if the operation is best expanded.
5224+
auto Expand = [&SatWidth, &CanHandleNatively](EVT SrcVT) -> bool {
5225+
return !CanHandleNatively(SrcVT) &&
5226+
(SrcVT.getScalarSizeInBits() < SatWidth ||
5227+
// NEON has no vector MIN/MAX for i64, so it's simpler to scalarize
5228+
// (at least until sqxtn is selected).
5229+
SrcVT.getVectorElementType() == MVT::f64);
5230+
};
5231+
5232+
// Try to promote the operation to a wider type if SrcVT < DstVT,
5233+
// or if type is bf16 or if the target has no +fullfp16.
5234+
std::optional<EVT> PromVT;
5235+
switch (SrcElementVT.getSimpleVT().SimpleTy) {
5236+
case MVT::f16:
5237+
case MVT::bf16:
5238+
if (DstElementVT == MVT::i32 || SrcElementVT == MVT::bf16 ||
5239+
!Subtarget->hasFullFP16()) {
5240+
PromVT = MVT::getVectorVT(MVT::f32, SrcVT.getVectorElementCount());
5241+
break;
5242+
}
5243+
[[fallthrough]];
5244+
case MVT::f32:
5245+
// Promote to f64
5246+
if (DstElementVT == MVT::i64) {
5247+
PromVT = MVT::getVectorVT(MVT::f64, SrcVT.getVectorElementCount());
5248+
break;
5249+
}
5250+
[[fallthrough]];
5251+
default:
5252+
break;
5253+
}
52125254

5213-
// In the absence of FP16 support, promote f16 to f32 and saturate the result.
5214-
// Note that SatWidth stays unchanged.
52155255
SDLoc DL(Op);
52165256
unsigned Opc = Op.getOpcode();
5217-
if ((SrcElementVT == MVT::f16 &&
5218-
(!Subtarget->hasFullFP16() || DstElementWidth > 16)) ||
5219-
SrcElementVT == MVT::bf16) {
5220-
MVT F32VT = MVT::getVectorVT(MVT::f32, SrcVT.getVectorNumElements());
5221-
SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, F32VT, SrcVal);
5222-
// If we are extending to a v8f32, split into two v4f32 to produce legal
5223-
// types.
5224-
if (F32VT == MVT::v8f32) {
5225-
auto [SrcValLo, SrcValHi] = DAG.SplitVector(SrcVal, DL);
5226-
SDValue Lo = DAG.getNode(Opc, DL, MVT::v4i32, SrcValLo, Op.getOperand(1));
5227-
SDValue Hi = DAG.getNode(Opc, DL, MVT::v4i32, SrcValHi, Op.getOperand(1));
5228-
Lo = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Lo);
5229-
Hi = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Hi);
5230-
return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Lo, Hi);
5231-
}
5232-
SrcVT = F32VT;
5233-
SrcElementVT = MVT::f32;
5234-
SrcElementWidth = 32;
5235-
} else if (SrcElementVT != MVT::f64 && SrcElementVT != MVT::f32 &&
5236-
SrcElementVT != MVT::f16 && SrcElementVT != MVT::bf16)
5237-
return SDValue();
5238-
5239-
// Expand to f64 if we are saturating to i64, to help keep the lanes the same
5240-
// width and produce a fcvtzu. Note that SatWidth stays unchanged.
5241-
if (SatWidth == 64 && SrcElementWidth < 64) {
5242-
MVT F64VT = MVT::getVectorVT(MVT::f64, SrcVT.getVectorNumElements());
5243-
SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, F64VT, SrcVal);
5244-
SrcVT = F64VT;
5245-
SrcElementVT = MVT::f64;
5246-
SrcElementWidth = 64;
5257+
if (PromVT && !Expand(*PromVT)) {
5258+
// When promoting the input type, SatWidth stays unchanged.
5259+
SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, *PromVT, SrcVal);
5260+
if (*PromVT != MVT::v8f32)
5261+
return DAG.getNode(Op.getOpcode(), DL, DstVT, SrcVal, Op.getOperand(1));
5262+
5263+
// If we are extending to a wider type (e.g. v8f16 -> v8f32) due to lack
5264+
// of fp16 support, then it's more efficient to split the operation
5265+
// into two v4f32 to produce legal types.
5266+
auto [SrcValLo, SrcValHi] = DAG.SplitVector(SrcVal, DL);
5267+
SDValue Lo = DAG.getNode(Opc, DL, MVT::v4i32, SrcValLo, Op.getOperand(1));
5268+
SDValue Hi = DAG.getNode(Opc, DL, MVT::v4i32, SrcValHi, Op.getOperand(1));
5269+
Lo = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Lo);
5270+
Hi = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Hi);
5271+
return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Lo, Hi);
52475272
}
5273+
52485274
// Cases that we can emit directly.
5249-
if (SrcElementWidth == DstElementWidth && SrcElementWidth == SatWidth)
5275+
if (CanHandleNatively(SrcVT)) {
5276+
assert(isTypeLegal(SrcVT) && "Expected SrcVT to be a legal type");
52505277
return DAG.getNode(Opc, DL, DstVT, SrcVal,
52515278
DAG.getValueType(DstVT.getScalarType()));
5252-
5253-
// Otherwise we emit a cvt that saturates to a higher BW, and saturate the
5254-
// result. This is only valid if the legal cvt is larger than the saturate
5255-
// width. For double, as we don't have MIN/MAX, it can be simpler to scalarize
5256-
// (at least until sqxtn is selected).
5257-
if (SrcElementWidth < SatWidth || SrcElementVT == MVT::f64)
5279+
} else if (Expand(SrcVT)) {
52585280
return SDValue();
5281+
}
52595282

52605283
assert((SrcElementWidth > DstElementWidth) ||
52615284
(SrcElementWidth == DstElementWidth && SatWidth < DstElementWidth));

0 commit comments

Comments
 (0)