[llvm] add1925 - [AArch64] NFCI: Simplify LowerVectorFP_TO_INT_SAT (part 2) (#207199)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 02:20:20 PDT 2026
Author: Sander de Smalen
Date: 2026-07-14T10:20:15+01:00
New Revision: add1925e5ee942794d7d6e8b4d65b32c959d472a
URL: https://github.com/llvm/llvm-project/commit/add1925e5ee942794d7d6e8b4d65b32c959d472a
DIFF: https://github.com/llvm/llvm-project/commit/add1925e5ee942794d7d6e8b4d65b32c959d472a.diff
LOG: [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.
Added:
Modified:
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 93b4b33043755..ffd16b16a4e84 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -5192,13 +5192,14 @@ AArch64TargetLowering::LowerVectorFP_TO_INT_SAT(SDValue Op,
// AArch64 FP-to-int conversions saturate to the destination element size, so
// we can lower common saturating conversions to simple instructions.
SDValue SrcVal = Op.getOperand(0);
- EVT SrcVT = SrcVal.getValueType();
- EVT DstVT = Op.getValueType();
- EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
-
- uint64_t SrcElementWidth = SrcVT.getScalarSizeInBits();
- uint64_t DstElementWidth = DstVT.getScalarSizeInBits();
- uint64_t SatWidth = SatVT.getScalarSizeInBits();
+ const EVT SrcVT = SrcVal.getValueType();
+ const EVT DstVT = Op.getValueType();
+ const EVT DstElementVT = DstVT.getVectorElementType();
+ const EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
+
+ const uint64_t SrcElementWidth = SrcVT.getScalarSizeInBits();
+ const uint64_t DstElementWidth = DstVT.getScalarSizeInBits();
+ const uint64_t SatWidth = SatVT.getScalarSizeInBits();
assert(SatWidth <= DstElementWidth &&
"Saturation width cannot exceed result width");
@@ -5208,54 +5209,76 @@ AArch64TargetLowering::LowerVectorFP_TO_INT_SAT(SDValue Op,
if (DstVT.isScalableVector())
return SDValue();
- EVT SrcElementVT = SrcVT.getVectorElementType();
+ const EVT SrcElementVT = SrcVT.getVectorElementType();
+ if (SrcElementVT != MVT::f64 && SrcElementVT != MVT::f32 &&
+ SrcElementVT != MVT::f16 && SrcElementVT != MVT::bf16)
+ return SDValue();
+
+ // Returns true if the operation can be matched by an isel pattern directly.
+ auto CanHandleNatively = [&DstVT, &SatWidth](EVT SrcVT) -> bool {
+ return SrcVT.getScalarSizeInBits() == DstVT.getScalarSizeInBits() &&
+ SrcVT.getScalarSizeInBits() == SatWidth;
+ };
+
+ // Returns true if the operation is best expanded.
+ auto Expand = [&SatWidth, &CanHandleNatively](EVT SrcVT) -> bool {
+ return !CanHandleNatively(SrcVT) &&
+ (SrcVT.getScalarSizeInBits() < SatWidth ||
+ // NEON has no vector MIN/MAX for i64, so it's simpler to scalarize
+ // (at least until sqxtn is selected).
+ SrcVT.getVectorElementType() == MVT::f64);
+ };
+
+ // Try to promote the operation to a wider type if SrcVT < DstVT,
+ // or if type is bf16 or if the target has no +fullfp16.
+ std::optional<EVT> PromVT;
+ switch (SrcElementVT.getSimpleVT().SimpleTy) {
+ case MVT::f16:
+ case MVT::bf16:
+ if (DstElementVT == MVT::i32 || SrcElementVT == MVT::bf16 ||
+ !Subtarget->hasFullFP16()) {
+ PromVT = MVT::getVectorVT(MVT::f32, SrcVT.getVectorElementCount());
+ break;
+ }
+ [[fallthrough]];
+ case MVT::f32:
+ // Promote to f64
+ if (DstElementVT == MVT::i64) {
+ PromVT = MVT::getVectorVT(MVT::f64, SrcVT.getVectorElementCount());
+ break;
+ }
+ [[fallthrough]];
+ default:
+ break;
+ }
- // In the absence of FP16 support, promote f16 to f32 and saturate the result.
- // Note that SatWidth stays unchanged.
SDLoc DL(Op);
unsigned Opc = Op.getOpcode();
- if ((SrcElementVT == MVT::f16 &&
- (!Subtarget->hasFullFP16() || DstElementWidth > 16)) ||
- SrcElementVT == MVT::bf16) {
- MVT F32VT = MVT::getVectorVT(MVT::f32, SrcVT.getVectorNumElements());
- SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, F32VT, SrcVal);
- // If we are extending to a v8f32, split into two v4f32 to produce legal
- // types.
- if (F32VT == MVT::v8f32) {
- auto [SrcValLo, SrcValHi] = DAG.SplitVector(SrcVal, DL);
- SDValue Lo = DAG.getNode(Opc, DL, MVT::v4i32, SrcValLo, Op.getOperand(1));
- SDValue Hi = DAG.getNode(Opc, DL, MVT::v4i32, SrcValHi, Op.getOperand(1));
- Lo = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Lo);
- Hi = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Hi);
- return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Lo, Hi);
- }
- SrcVT = F32VT;
- SrcElementVT = MVT::f32;
- SrcElementWidth = 32;
- } else if (SrcElementVT != MVT::f64 && SrcElementVT != MVT::f32 &&
- SrcElementVT != MVT::f16 && SrcElementVT != MVT::bf16)
- return SDValue();
-
- // Expand to f64 if we are saturating to i64, to help keep the lanes the same
- // width and produce a fcvtzu. Note that SatWidth stays unchanged.
- if (SatWidth == 64 && SrcElementWidth < 64) {
- MVT F64VT = MVT::getVectorVT(MVT::f64, SrcVT.getVectorNumElements());
- SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, F64VT, SrcVal);
- SrcVT = F64VT;
- SrcElementVT = MVT::f64;
- SrcElementWidth = 64;
+ if (PromVT && !Expand(*PromVT)) {
+ // When promoting the input type, SatWidth stays unchanged.
+ SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, *PromVT, SrcVal);
+ if (*PromVT != MVT::v8f32)
+ return DAG.getNode(Op.getOpcode(), DL, DstVT, SrcVal, Op.getOperand(1));
+
+ // If we are extending to a wider type (e.g. v8f16 -> v8f32) due to lack
+ // of fp16 support, then it's more efficient to split the operation
+ // into two v4f32 to produce legal types.
+ auto [SrcValLo, SrcValHi] = DAG.SplitVector(SrcVal, DL);
+ SDValue Lo = DAG.getNode(Opc, DL, MVT::v4i32, SrcValLo, Op.getOperand(1));
+ SDValue Hi = DAG.getNode(Opc, DL, MVT::v4i32, SrcValHi, Op.getOperand(1));
+ Lo = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Lo);
+ Hi = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Hi);
+ return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Lo, Hi);
}
+
// Cases that we can emit directly.
- if (SrcElementWidth == DstElementWidth && SrcElementWidth == SatWidth)
+ if (CanHandleNatively(SrcVT)) {
+ assert(isTypeLegal(SrcVT) && "Expected SrcVT to be a legal type");
return DAG.getNode(Opc, DL, DstVT, SrcVal,
DAG.getValueType(DstVT.getScalarType()));
-
- // Otherwise we emit a cvt that saturates to a higher BW, and saturate the
- // result. This is only valid if the legal cvt is larger than the saturate
- // width. For double, as we don't have MIN/MAX, it can be simpler to scalarize
- // (at least until sqxtn is selected).
- if (SrcElementWidth < SatWidth || SrcElementVT == MVT::f64)
+ } else if (Expand(SrcVT)) {
return SDValue();
+ }
assert((SrcElementWidth > DstElementWidth) ||
(SrcElementWidth == DstElementWidth && SatWidth < DstElementWidth));
More information about the llvm-commits
mailing list