[llvm] [SPIR-V][NewPM] Register SPIRVStructurizer with the new pass manager (PR #209965)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 02:09:14 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/209965

>From b452fc2625cced18f997a3f722845dbd6a064077 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 16 Jul 2026 07:10:00 +0200
Subject: [PATCH 1/2] [SPIRV][NewPM] Register SPIRVStructurizer with the new
 pass manager

---
 llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp | 64 ++++++++++++---------
 1 file changed, 37 insertions(+), 27 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
index f02bd261244aa..df1ee0bc13076 100644
--- a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
@@ -23,7 +23,6 @@
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsSPIRV.h"
-#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Transforms/Utils.h"
 #include "llvm/Transforms/Utils/Cloning.h"
@@ -282,7 +281,10 @@ static void replaceBranchTargets(BasicBlock *BB, BasicBlock *OldTarget,
 namespace {
 // Given a reducible CFG, produces a structurized CFG in the SPIR-V sense,
 // adding merge instructions when required.
-class SPIRVStructurizer : public FunctionPass {
+class SPIRVStructurizerImpl {
+  LoopInfo &LI;
+  ConvergenceRegionInfo &RegionInfo;
+
   struct DivergentConstruct;
   // Represents a list of condition/loops/switch constructs.
   // See SPIR-V 2.11.2. Structured Control-flow Constructs for the list of
@@ -514,11 +516,7 @@ class SPIRVStructurizer : public FunctionPass {
 
   // Add OpLoopMerge instruction on cycles.
   bool addMergeForLoops(Function &F) {
-    LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
-    auto *TopLevelRegion =
-        getAnalysis<SPIRVConvergenceRegionAnalysisWrapperPass>()
-            .getRegionInfo()
-            .getTopLevelRegion();
+    auto *TopLevelRegion = RegionInfo.getTopLevelRegion();
 
     bool Modified = false;
     for (auto &BB : F) {
@@ -875,7 +873,6 @@ class SPIRVStructurizer : public FunctionPass {
   }
 
   bool splitCriticalEdges(Function &F) {
-    LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
     Splitter S(F, LI);
 
     DivergentConstruct Root;
@@ -1070,11 +1067,10 @@ class SPIRVStructurizer : public FunctionPass {
   }
 
 public:
-  static char ID;
+  SPIRVStructurizerImpl(LoopInfo &LI, ConvergenceRegionInfo &RegionInfo)
+      : LI(LI), RegionInfo(RegionInfo) {}
 
-  SPIRVStructurizer() : FunctionPass(ID) {}
-
-  bool runOnFunction(Function &F) override {
+  bool run(Function &F) {
     bool Modified = false;
 
     // In LLVM, Switches are allowed to have several cases branching to the same
@@ -1140,15 +1136,6 @@ class SPIRVStructurizer : public FunctionPass {
     return Modified;
   }
 
-  void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<DominatorTreeWrapperPass>();
-    AU.addRequired<LoopInfoWrapperPass>();
-    AU.addRequired<SPIRVConvergenceRegionAnalysisWrapperPass>();
-
-    AU.addPreserved<SPIRVConvergenceRegionAnalysisWrapperPass>();
-    FunctionPass::getAnalysisUsage(AU);
-  }
-
   void createOpSelectMerge(IRBuilder<> *Builder, BlockAddress *MergeAddress) {
     Instruction *BBTerminatorInst = Builder->GetInsertBlock()->getTerminator();
 
@@ -1168,6 +1155,30 @@ class SPIRVStructurizer : public FunctionPass {
                              {MergeAddress->getType()}, Args);
   }
 };
+
+class SPIRVStructurizer : public FunctionPass {
+public:
+  static char ID;
+
+  SPIRVStructurizer() : FunctionPass(ID) {}
+
+  bool runOnFunction(Function &F) override {
+    LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+    ConvergenceRegionInfo &RegionInfo =
+        getAnalysis<SPIRVConvergenceRegionAnalysisWrapperPass>()
+            .getRegionInfo();
+    return SPIRVStructurizerImpl(LI, RegionInfo).run(F);
+  }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequired<DominatorTreeWrapperPass>();
+    AU.addRequired<LoopInfoWrapperPass>();
+    AU.addRequired<SPIRVConvergenceRegionAnalysisWrapperPass>();
+
+    AU.addPreserved<SPIRVConvergenceRegionAnalysisWrapperPass>();
+    FunctionPass::getAnalysisUsage(AU);
+  }
+};
 } // anonymous namespace
 
 char SPIRVStructurizer::ID = 0;
@@ -1187,12 +1198,11 @@ FunctionPass *llvm::createSPIRVStructurizerPass() {
 }
 
 PreservedAnalyses SPIRVStructurizerWrapper::run(Function &F,
-                                                FunctionAnalysisManager &AF) {
-
-  auto FPM = legacy::FunctionPassManager(F.getParent());
-  FPM.add(createSPIRVStructurizerPass());
-
-  if (!FPM.run(F))
+                                                FunctionAnalysisManager &AM) {
+  LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
+  ConvergenceRegionInfo &RegionInfo =
+      AM.getResult<SPIRVConvergenceRegionAnalysis>(F);
+  if (!SPIRVStructurizerImpl(LI, RegionInfo).run(F))
     return PreservedAnalyses::all();
   PreservedAnalyses PA;
   PA.preserveSet<CFGAnalyses>();

>From 9abdd52b6d16a67dbdd93701d99129e4de69848a Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 16 Jul 2026 11:08:20 +0200
Subject: [PATCH 2/2] Address comment and add newpm test

---
 llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp              | 8 +++-----
 .../SPIRV/structurizer/HLSLControlFlowHint-pass-check.ll | 9 +++++++++
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
index df1ee0bc13076..0e6f5ecab1437 100644
--- a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
@@ -1202,9 +1202,7 @@ PreservedAnalyses SPIRVStructurizerWrapper::run(Function &F,
   LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
   ConvergenceRegionInfo &RegionInfo =
       AM.getResult<SPIRVConvergenceRegionAnalysis>(F);
-  if (!SPIRVStructurizerImpl(LI, RegionInfo).run(F))
-    return PreservedAnalyses::all();
-  PreservedAnalyses PA;
-  PA.preserveSet<CFGAnalyses>();
-  return PA;
+  return SPIRVStructurizerImpl(LI, RegionInfo).run(F)
+             ? PreservedAnalyses::none()
+             : PreservedAnalyses::all();
 }
diff --git a/llvm/test/CodeGen/SPIRV/structurizer/HLSLControlFlowHint-pass-check.ll b/llvm/test/CodeGen/SPIRV/structurizer/HLSLControlFlowHint-pass-check.ll
index 9911b3119ce52..07a31b6c26f52 100644
--- a/llvm/test/CodeGen/SPIRV/structurizer/HLSLControlFlowHint-pass-check.ll
+++ b/llvm/test/CodeGen/SPIRV/structurizer/HLSLControlFlowHint-pass-check.ll
@@ -1,5 +1,14 @@
 ; RUN: opt -passes='spirv-structurizer' -S -mtriple=spirv-unknown-unknown %s | FileCheck %s
 
+; The structurizer modifies the CFG, so it must not claim to preserve
+; CFG-dependent analyses in the new pass manager.
+; RUN: opt -passes='spirv-structurizer' -disable-output -debug-pass-manager \
+; RUN:   -mtriple=spirv-unknown-unknown %s 2>&1 | FileCheck %s --check-prefix=INVALIDATE
+; INVALIDATE: Running pass: SPIRVStructurizerWrapper on test_branch
+; INVALIDATE: Invalidating analysis: DominatorTreeAnalysis on test_branch
+; INVALIDATE: Invalidating analysis: LoopAnalysis on test_branch
+; INVALIDATE: Invalidating analysis: SPIRVConvergenceRegionAnalysis on test_branch
+
 ; CHECK-LABEL: define spir_func noundef i32 @test_branch
 ; CHECK: call void @llvm.spv.selection.merge.p0(ptr blockaddress(@test_branch, %if.end), i32 1)
 ; CHECK-NEXT: br i1 %cmp, label %if.then, label %if.else, !hlsl.controlflow.hint !{{[0-9]+}}



More information about the llvm-commits mailing list