[llvm] [SLP] Normalize copyable operand order via majority voting (PR #191631)

Alexey Bataev via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 16 08:05:48 PDT 2026


================
@@ -11931,12 +11931,76 @@ class InstructionsCompatibilityAnalysis {
     if (S.areInstructionsWithCopyableElements()) {
       MainOp = S.getMainOp();
       MainOpcode = S.getOpcode();
+      const bool IsCommutative =
+          isCommutative(MainOp) && MainOp->getNumOperands() == 2;
       Operands.assign(MainOp->getNumOperands(),
                       BoUpSLP::ValueList(VL.size(), nullptr));
+      // Build operands and simultaneously count (ID0, ID1) pair
+      // frequencies for commutative operand normalization. Pairs and
+      // their inverses are tracked under a canonical key so that
+      // (Load, Add) and (Add, Load) contribute to the same bucket.
+      struct PairInfo {
+        unsigned FwdCount = 0;
+        unsigned RevCount = 0;
+        unsigned MinID = 0;
+        unsigned MaxID = 0;
+      };
+      SmallMapVector<std::pair<unsigned, unsigned>, PairInfo, 8> PairCounts;
+      unsigned MajID0 = 0, MajID1 = 0;
       for (auto [Idx, V] : enumerate(VL)) {
         SmallVector<Value *> OperandsForValue = getOperands(S, V);
         for (auto [OperandIdx, Operand] : enumerate(OperandsForValue))
           Operands[OperandIdx][Idx] = Operand;
+        if (!IsCommutative || S.isCopyableElement(V) || isa<PoisonValue>(V))
+          continue;
+        unsigned ID0 = OperandsForValue[0]->getValueID();
+        unsigned ID1 = OperandsForValue[1]->getValueID();
+        if (ID0 == ID1)
+          continue;
+        unsigned MinID = std::min(ID0, ID1);
+        unsigned MaxID = std::max(ID0, ID1);
+        auto [It, Inserted] =
+            PairCounts.try_emplace(std::make_pair(MinID, MaxID));
+        PairInfo &Info = It->second;
+        if (Inserted) {
+          Info.MinID = MinID;
+          Info.MaxID = MaxID;
+        }
+        if (ID0 < ID1)
+          ++Info.FwdCount;
+        else
+          ++Info.RevCount;
+      }
+      // Find the most frequent (ID0, ID1) pair across non-copyable
+      // lanes. Select the orientation (original or inverse) that has
+      // more votes as the majority pattern.
+      unsigned BestCount = 0;
+      for (const auto &P : PairCounts) {
+        const PairInfo &Info = P.second;
+        unsigned Total = Info.FwdCount + Info.RevCount;
+        if (Total > BestCount) {
+          BestCount = Total;
+          if (Info.FwdCount >= Info.RevCount) {
+            MajID0 = Info.MinID;
+            MajID1 = Info.MaxID;
+          } else {
+            MajID0 = Info.MaxID;
+            MajID1 = Info.MinID;
+          }
+        }
+      }
+      // For commutative ops, swap lanes whose operand types are the
+      // exact inverse of the majority pattern, making the non-copyable
----------------
alexey-bataev wrote:

Just another heuristic, which does not pessimize the vectorization result

https://github.com/llvm/llvm-project/pull/191631


More information about the llvm-commits mailing list