[llvm] [AArch64] Prefer SVE2 for fixed-length i64 [S|U][MIN|MAX] reductions (PR #181161)
Benjamin Maxwell via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 17 09:48:48 PST 2026
================
@@ -31564,22 +31445,93 @@ 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))
+ if ((PairwiseOpIID = getPairwiseOpForReduction(RdxOp.getOpcode())))
+ UseSVE = true;
+
+ return UseSVE;
----------------
MacDue wrote:
I'll update some checks (since there's nothing testing this), but this suggestion would actually incorrectly cause us to lower to SVE when NEON should be preferred.
For example, this case would use the pairwise op with ` -aarch64-sve-vector-bits-min=256 -mattr=+sve2`:
```
; Don't use SVE for 64-bit vectors.
define i32 @smaxv_v2i32(<2 x i32> %a) vscale_range(2,0) #0 {
%res = call i32 @llvm.vector.reduce.smax.v2i32(<2 x i32> %a)
ret i32 %res
}
```
https://github.com/llvm/llvm-project/pull/181161
More information about the llvm-commits
mailing list