[llvm] [SLP][modularisation][NFC] Move reduction match helpers to SLPReductionUtils (PR #222052)

Madhur Amilkanthwar via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 19:54:33 PDT 2026


https://github.com/madhur13490 updated https://github.com/llvm/llvm-project/pull/222052

>From 4fd28a77bd44bfcc79b8c90a8cc73e35ae63efba Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Tue, 8 Sep 2026 09:32:38 -0700
Subject: [PATCH 1/2] [SLP][modularisation][NFC] Move reduction match helpers
 to SLPReductionUtils

Move the following BoUpSLP-independent reduction pattern-match helpers out
of SLPVectorizer.cpp into a new SLPVectorizer/SLPReductionUtils.{h,cpp}:

  getNonPhiOperand
  isReductionCandidate

matchRdxBop, used only by these two, moves alongside them and stays
file-local. Behavior is unchanged.

Part of the SLPVectorizer.cpp modularization effort:
https://discourse.llvm.org/t/modularizing-slpvectorizer-cpp/90922
---
 llvm/lib/Transforms/Vectorize/CMakeLists.txt  |  1 +
 .../Transforms/Vectorize/SLPVectorizer.cpp    | 41 +------------
 .../SLPVectorizer/SLPReductionUtils.cpp       | 57 +++++++++++++++++++
 .../SLPVectorizer/SLPReductionUtils.h         | 35 ++++++++++++
 .../llvm/lib/Transforms/Vectorize/BUILD.gn    |  1 +
 5 files changed, 95 insertions(+), 40 deletions(-)
 create mode 100644 llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.cpp
 create mode 100644 llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h

diff --git a/llvm/lib/Transforms/Vectorize/CMakeLists.txt b/llvm/lib/Transforms/Vectorize/CMakeLists.txt
index 7334830c422f8..9073211280886 100644
--- a/llvm/lib/Transforms/Vectorize/CMakeLists.txt
+++ b/llvm/lib/Transforms/Vectorize/CMakeLists.txt
@@ -26,6 +26,7 @@ add_llvm_component_library(LLVMVectorize
   SLPVectorizer/SLPCompatibilityAnalysis.cpp
   SLPVectorizer/SLPCostAnalysis.cpp
   SLPVectorizer/SLPMemoryUtils.cpp
+  SLPVectorizer/SLPReductionUtils.cpp
   SLPVectorizer/SLPTypeUtils.cpp
   SLPVectorizer/SLPUtils.cpp
   SLPVectorizer.cpp
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 950297eb31cc4..881033817b74a 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -20,6 +20,7 @@
 #include "SLPVectorizer/SLPCompatibilityAnalysis.h"
 #include "SLPVectorizer/SLPCostAnalysis.h"
 #include "SLPVectorizer/SLPMemoryUtils.h"
+#include "SLPVectorizer/SLPReductionUtils.h"
 #include "SLPVectorizer/SLPTypeUtils.h"
 #include "SLPVectorizer/SLPUtils.h"
 #include "llvm/ADT/DenseMap.h"
@@ -33060,28 +33061,6 @@ static Instruction *getReductionInstr(const DominatorTree *DT, PHINode *P,
   return nullptr;
 }
 
-static bool matchRdxBop(Instruction *I, Value *&V0, Value *&V1) {
-  if (match(I, m_BinOp(m_Value(V0), m_Value(V1))))
-    return true;
-  if (match(I, m_FMaxNum(m_Value(V0), m_Value(V1))))
-    return true;
-  if (match(I, m_FMinNum(m_Value(V0), m_Value(V1))))
-    return true;
-  if (match(I, m_FMaximum(m_Value(V0), m_Value(V1))))
-    return true;
-  if (match(I, m_FMinimum(m_Value(V0), m_Value(V1))))
-    return true;
-  if (match(I, m_Intrinsic<Intrinsic::smax>(m_Value(V0), m_Value(V1))))
-    return true;
-  if (match(I, m_Intrinsic<Intrinsic::smin>(m_Value(V0), m_Value(V1))))
-    return true;
-  if (match(I, m_Intrinsic<Intrinsic::umax>(m_Value(V0), m_Value(V1))))
-    return true;
-  if (match(I, m_Intrinsic<Intrinsic::umin>(m_Value(V0), m_Value(V1))))
-    return true;
-  return false;
-}
-
 /// We could have an initial reduction that is not an add.
 ///  r *= v1 + v2 + v3 + v4
 /// In such a case start looking for a tree rooted in the first '+'.
@@ -33102,24 +33081,6 @@ static Instruction *tryGetSecondaryReductionRoot(PHINode *Phi,
   return nullptr;
 }
 
-/// \p Returns the first operand of \p I that does not match \p Phi. If
-/// operand is not an instruction it returns nullptr.
-static Instruction *getNonPhiOperand(Instruction *I, PHINode *Phi) {
-  Value *Op0 = nullptr;
-  Value *Op1 = nullptr;
-  if (!matchRdxBop(I, Op0, Op1))
-    return nullptr;
-  return dyn_cast<Instruction>(Op0 == Phi ? Op1 : Op0);
-}
-
-/// \Returns true if \p I is a candidate instruction for reduction vectorization.
-static bool isReductionCandidate(Instruction *I) {
-  bool IsSelect = match(I, m_Select(m_Value(), m_Value(), m_Value()));
-  Value *B0 = nullptr, *B1 = nullptr;
-  bool IsBinop = matchRdxBop(I, B0, B1);
-  return IsBinop || IsSelect;
-}
-
 bool SLPVectorizerPass::vectorizeHorReduction(
     PHINode *P, Instruction *Root, BasicBlock *BB, BoUpSLP &R,
     SmallVectorImpl<WeakTrackingVH> &PostponedInsts) {
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.cpp
new file mode 100644
index 0000000000000..94080e4e28ebb
--- /dev/null
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.cpp
@@ -0,0 +1,57 @@
+//===- SLPReductionUtils.cpp - SLP reduction match helpers ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SLPReductionUtils.h"
+
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/PatternMatch.h"
+
+using namespace llvm;
+using namespace llvm::PatternMatch;
+
+namespace llvm::slpvectorizer {
+
+static bool matchRdxBop(Instruction *I, Value *&V0, Value *&V1) {
+  if (match(I, m_BinOp(m_Value(V0), m_Value(V1))))
+    return true;
+  if (match(I, m_FMaxNum(m_Value(V0), m_Value(V1))))
+    return true;
+  if (match(I, m_FMinNum(m_Value(V0), m_Value(V1))))
+    return true;
+  if (match(I, m_FMaximum(m_Value(V0), m_Value(V1))))
+    return true;
+  if (match(I, m_FMinimum(m_Value(V0), m_Value(V1))))
+    return true;
+  if (match(I, m_Intrinsic<Intrinsic::smax>(m_Value(V0), m_Value(V1))))
+    return true;
+  if (match(I, m_Intrinsic<Intrinsic::smin>(m_Value(V0), m_Value(V1))))
+    return true;
+  if (match(I, m_Intrinsic<Intrinsic::umax>(m_Value(V0), m_Value(V1))))
+    return true;
+  if (match(I, m_Intrinsic<Intrinsic::umin>(m_Value(V0), m_Value(V1))))
+    return true;
+  return false;
+}
+
+Instruction *getNonPhiOperand(Instruction *I, PHINode *Phi) {
+  Value *Op0 = nullptr;
+  Value *Op1 = nullptr;
+  if (!matchRdxBop(I, Op0, Op1))
+    return nullptr;
+  return dyn_cast<Instruction>(Op0 == Phi ? Op1 : Op0);
+}
+
+bool isReductionCandidate(Instruction *I) {
+  bool IsSelect = match(I, m_Select(m_Value(), m_Value(), m_Value()));
+  Value *B0 = nullptr, *B1 = nullptr;
+  bool IsBinop = matchRdxBop(I, B0, B1);
+  return IsBinop || IsSelect;
+}
+
+} // namespace llvm::slpvectorizer
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h
new file mode 100644
index 0000000000000..21e02b4143da8
--- /dev/null
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h
@@ -0,0 +1,35 @@
+//===- SLPReductionUtils.h - SLP reduction match helpers -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Internal header used by SLPVectorizer.cpp. It declares free reduction
+// pattern-match helpers that do not depend on BoUpSLP or any other SLP-private
+// type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPREDUCTIONUTILS_H
+#define LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPREDUCTIONUTILS_H
+
+namespace llvm {
+class Instruction;
+class PHINode;
+} // namespace llvm
+
+namespace llvm::slpvectorizer {
+
+/// \p Returns the first operand of \p I that does not match \p Phi. If
+/// operand is not an instruction it returns nullptr.
+Instruction *getNonPhiOperand(Instruction *I, PHINode *Phi);
+
+/// \Returns true if \p I is a candidate instruction for reduction
+/// vectorization.
+bool isReductionCandidate(Instruction *I);
+
+} // namespace llvm::slpvectorizer
+
+#endif // LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPREDUCTIONUTILS_H
diff --git a/llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn
index 3a6fce2c029e9..0ffc24ec855f7 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn
@@ -17,6 +17,7 @@ static_library("Vectorize") {
     "SLPVectorizer/SLPCompatibilityAnalysis.cpp",
     "SLPVectorizer/SLPCostAnalysis.cpp",
     "SLPVectorizer/SLPMemoryUtils.cpp",
+    "SLPVectorizer/SLPReductionUtils.cpp",
     "SLPVectorizer/SLPTypeUtils.cpp",
     "SLPVectorizer/SLPUtils.cpp",
     "SandboxVectorizer/DependencyGraph.cpp",

>From c9a0d23ddb4242645c34765ec9a2d6b28cea0f62 Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Tue, 8 Sep 2026 19:52:41 -0700
Subject: [PATCH 2/2] fixup! fix comments

---
 .../Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h  | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h
index 21e02b4143da8..1ba4af797b628 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPReductionUtils.h
@@ -22,11 +22,11 @@ class PHINode;
 
 namespace llvm::slpvectorizer {
 
-/// \p Returns the first operand of \p I that does not match \p Phi. If
-/// operand is not an instruction it returns nullptr.
+/// \returns the first operand of \p I that does not match \p Phi. If
+/// the operand is not an instruction, returns nullptr.
 Instruction *getNonPhiOperand(Instruction *I, PHINode *Phi);
 
-/// \Returns true if \p I is a candidate instruction for reduction
+/// \returns true if \p I is a candidate instruction for reduction
 /// vectorization.
 bool isReductionCandidate(Instruction *I);
 



More information about the llvm-commits mailing list