[llvm] [LLVM][InstCombine][SVE] Refactor sve.mul/fmul combines. (PR #134116)
Paul Walker via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 3 04:52:11 PDT 2025
================
@@ -2206,45 +2229,63 @@ static std::optional<Instruction *> instCombineSVEVectorSub(InstCombiner &IC,
return std::nullopt;
}
-static std::optional<Instruction *> instCombineSVEVectorMul(InstCombiner &IC,
- IntrinsicInst &II) {
- auto *OpPredicate = II.getOperand(0);
- auto *OpMultiplicand = II.getOperand(1);
- auto *OpMultiplier = II.getOperand(2);
+// Simplify `V` by only considering the operations that affect active lanes.
+// This function should only return existing Values or newly created Constants.
+static Value *stripInactiveLanes(Value *V, const Value *Pg) {
+ auto *Dup = dyn_cast<IntrinsicInst>(V);
+ if (Dup && Dup->getIntrinsicID() == Intrinsic::aarch64_sve_dup &&
+ Dup->getOperand(1) == Pg && isa<Constant>(Dup->getOperand(2)))
+ return ConstantVector::getSplat(
+ cast<VectorType>(V->getType())->getElementCount(),
+ cast<Constant>(Dup->getOperand(2)));
+
+ return V;
+}
- // Return true if a given instruction is a unit splat value, false otherwise.
- auto IsUnitSplat = [](auto *I) {
- auto *SplatValue = getSplatValue(I);
- if (!SplatValue)
- return false;
- return match(SplatValue, m_FPOne()) || match(SplatValue, m_One());
- };
+static std::optional<Instruction *>
+instCombineSVEVectorMul(InstCombiner &IC, IntrinsicInst &II,
+ const SVEIntrinsicInfo &IInfo) {
+ const unsigned Opc = IInfo.getMatchingIROpode();
+ if (!Instruction::isBinaryOp(Opc))
+ return std::nullopt;
- // Return true if a given instruction is an aarch64_sve_dup intrinsic call
- // with a unit splat value, false otherwise.
- auto IsUnitDup = [](auto *I) {
- auto *IntrI = dyn_cast<IntrinsicInst>(I);
- if (!IntrI || IntrI->getIntrinsicID() != Intrinsic::aarch64_sve_dup)
- return false;
+ Value *Pg = II.getOperand(0);
+ Value *Op1 = II.getOperand(1);
+ Value *Op2 = II.getOperand(2);
+ const DataLayout &DL = II.getDataLayout();
- auto *SplatValue = IntrI->getOperand(2);
- return match(SplatValue, m_FPOne()) || match(SplatValue, m_One());
- };
+ // Canonicalise constants to the RHS.
+ if (Instruction::isCommutative(Opc) && IInfo.inactiveLanesAreNotDefined() &&
+ isa<Constant>(Op1) && !isa<Constant>(Op2)) {
+ IC.replaceOperand(II, 1, Op2);
+ IC.replaceOperand(II, 2, Op1);
+ return &II;
+ }
- if (IsUnitSplat(OpMultiplier)) {
- // [f]mul pg %n, (dupx 1) => %n
- OpMultiplicand->takeName(&II);
- return IC.replaceInstUsesWith(II, OpMultiplicand);
- } else if (IsUnitDup(OpMultiplier)) {
- // [f]mul pg %n, (dup pg 1) => %n
- auto *DupInst = cast<IntrinsicInst>(OpMultiplier);
- auto *DupPg = DupInst->getOperand(1);
- // TODO: this is naive. The optimization is still valid if DupPg
- // 'encompasses' OpPredicate, not only if they're the same predicate.
- if (OpPredicate == DupPg) {
- OpMultiplicand->takeName(&II);
- return IC.replaceInstUsesWith(II, OpMultiplicand);
- }
+ // Only active lanes matter when simplifying the operation.
+ Op1 = stripInactiveLanes(Op1, Pg);
+ Op2 = stripInactiveLanes(Op2, Pg);
----------------
paulwalker-arm wrote:
The canonicalisation does not relate to `simplifyBinOp` so I don't think so.
The benefit would be to simplify the writing of future combines to remove the need to check both operands. Is this something you want me to implement now or defer until such combines exist?
https://github.com/llvm/llvm-project/pull/134116
More information about the llvm-commits
mailing list