[llvm] [AArch64] Prefer SVE2 for fixed-length i64 [S|U][MIN|MAX] reductions (PR #181161)
Paul Walker via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 17 07:47:19 PST 2026
================
@@ -31564,22 +31445,95 @@ SDValue AArch64TargetLowering::LowerPredReductionToSVE(SDValue ReduceOp,
return SDValue();
}
-SDValue AArch64TargetLowering::LowerReductionToSVE(unsigned Opcode,
- SDValue ScalarOp,
- SelectionDAG &DAG) const {
- SDLoc DL(ScalarOp);
- SDValue VecOp = ScalarOp.getOperand(0);
- EVT SrcVT = VecOp.getValueType();
+/// Returns the pairwise SVE2 op that could be used for a v2<ty> reduction.
+static std::optional<Intrinsic::ID> getPairwiseOpForReduction(unsigned Op) {
+ switch (Op) {
+ case ISD::VECREDUCE_SMIN:
+ return Intrinsic::aarch64_sve_sminp;
+ case ISD::VECREDUCE_SMAX:
+ return Intrinsic::aarch64_sve_smaxp;
+ case ISD::VECREDUCE_UMIN:
+ return Intrinsic::aarch64_sve_uminp;
+ case ISD::VECREDUCE_UMAX:
+ return Intrinsic::aarch64_sve_umaxp;
+ default:
+ return std::nullopt;
+ }
+}
- if (useSVEForFixedLengthVectorVT(
- SrcVT,
- /*OverrideNEON=*/Subtarget->useSVEForFixedLengthVectors())) {
- EVT ContainerVT = getContainerForFixedLengthVector(DAG, SrcVT);
- VecOp = convertToScalableVector(DAG, ContainerVT, VecOp);
+/// Returns the corresponding predicated SVE reduction opcode for a VECREDUCE_*.
+static unsigned getPredicatedReductionOpcode(unsigned Op) {
+ switch (Op) {
+ case ISD::VECREDUCE_ADD:
+ return AArch64ISD::UADDV_PRED;
+ case ISD::VECREDUCE_AND:
+ return AArch64ISD::ANDV_PRED;
+ case ISD::VECREDUCE_OR:
+ return AArch64ISD::ORV_PRED;
+ case ISD::VECREDUCE_SMAX:
+ return AArch64ISD::SMAXV_PRED;
+ case ISD::VECREDUCE_SMIN:
+ return AArch64ISD::SMINV_PRED;
+ case ISD::VECREDUCE_UMAX:
+ return AArch64ISD::UMAXV_PRED;
+ case ISD::VECREDUCE_UMIN:
+ return AArch64ISD::UMINV_PRED;
+ case ISD::VECREDUCE_XOR:
+ return AArch64ISD::EORV_PRED;
+ case ISD::VECREDUCE_FADD:
+ return AArch64ISD::FADDV_PRED;
+ case ISD::VECREDUCE_FMAX:
+ return AArch64ISD::FMAXNMV_PRED;
+ case ISD::VECREDUCE_FMIN:
+ return AArch64ISD::FMINNMV_PRED;
+ case ISD::VECREDUCE_FMAXIMUM:
+ return AArch64ISD::FMAXV_PRED;
+ case ISD::VECREDUCE_FMINIMUM:
+ return AArch64ISD::FMINV_PRED;
+ default:
+ llvm_unreachable("unexpected opcode");
+ }
+}
+
+bool AArch64TargetLowering::shouldLowerReductionToSVE(
+ SDValue RdxOp, std::optional<Intrinsic::ID> &PairwiseOpIID) const {
+ EVT SrcVT = RdxOp.getOperand(0).getValueType();
+ if (SrcVT.isScalableVector())
+ return true;
+
+ bool OverrideNEON = !Subtarget->isNeonAvailable() ||
+ RdxOp.getOpcode() == ISD::VECREDUCE_AND ||
+ RdxOp.getOpcode() == ISD::VECREDUCE_OR ||
+ RdxOp.getOpcode() == ISD::VECREDUCE_XOR ||
+ RdxOp.getOpcode() == ISD::VECREDUCE_FADD ||
+ (RdxOp.getOpcode() != ISD::VECREDUCE_ADD &&
+ SrcVT.getVectorElementType() == MVT::i64);
+
+ bool UseSVE = useSVEForFixedLengthVectorVT(
+ SrcVT, OverrideNEON && Subtarget->useSVEForFixedLengthVectors());
+
+ // Always lower v2i64 vectors to pairwise SVE2 operations when possible as
+ // NEON does not natively support reductions on v2i64. Lower v2i32 to pairwise
+ // SVE2 operations when UseSVE is true, as the pairwise ops are likely to be
+ // cheaper than a full reduction.
+ if (Subtarget->hasSVE2() || Subtarget->isStreamingSVEAvailable()) {
+ if (SrcVT == MVT::v2i64 || (UseSVE && SrcVT == MVT::v2i32)) {
+ PairwiseOpIID = getPairwiseOpForReduction(RdxOp.getOpcode());
+ UseSVE |= PairwiseOpIID.has_value();
+ }
}
----------------
paulwalker-arm wrote:
```suggestion
if (Subtarget->hasSVE2() || Subtarget->isStreamingSVEAvailable())
if (SrcVT == MVT::v2i64 || (UseSVE && SrcVT == MVT::v2i32))
if (PairwiseOpIID = getPairwiseOpForReduction(RdxOp.getOpcode()))
UseSVE = true;
```
https://github.com/llvm/llvm-project/pull/181161
More information about the llvm-commits
mailing list