Skip to content

[mlir][spirv] Allow disabling control flow structurization #140561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 3, 2025

Conversation

IgWod-IMG
Copy link
Contributor

Currently some control flow patterns cannot be structurized into existing SPIR-V MLIR constructs, e.g., conditional early exits (break). Since the support for early exit cannot be currently added (#138688 (review) in see #138688) this patch enables structurizer to be disabled to keep the control flow unstructurized. By default, the control flow is structurized.

Currently some control flow patterns cannot be structurized
into current SPIR-V MLIR constructs, e.g., conditional early exits
(break). Since the support for early exit cannot be currently added
(llvm#138688 (review)
in see llvm#138688) this patch enables structurizer to be disabled to
keep the control flow unstructurized. By default, the control flow
is structurized.
@llvmbot
Copy link
Member

llvmbot commented May 19, 2025

@llvm/pr-subscribers-mlir-spirv

@llvm/pr-subscribers-mlir

Author: Igor Wodiany (IgWod-IMG)

Changes

Currently some control flow patterns cannot be structurized into existing SPIR-V MLIR constructs, e.g., conditional early exits (break). Since the support for early exit cannot be currently added (#138688 (review) in see #138688) this patch enables structurizer to be disabled to keep the control flow unstructurized. By default, the control flow is structurized.


Full diff: https://github.com/llvm/llvm-project/pull/140561.diff

5 Files Affected:

  • (modified) mlir/include/mlir/Target/SPIRV/Deserialization.h (+3-2)
  • (modified) mlir/lib/Target/SPIRV/Deserialization/Deserialization.cpp (+4-3)
  • (modified) mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp (+14-2)
  • (modified) mlir/lib/Target/SPIRV/Deserialization/Deserializer.h (+7-1)
  • (modified) mlir/lib/Target/SPIRV/TranslateRegistration.cpp (+11-3)
diff --git a/mlir/include/mlir/Target/SPIRV/Deserialization.h b/mlir/include/mlir/Target/SPIRV/Deserialization.h
index a346a7fd1e5f7..adff26298c4cc 100644
--- a/mlir/include/mlir/Target/SPIRV/Deserialization.h
+++ b/mlir/include/mlir/Target/SPIRV/Deserialization.h
@@ -27,8 +27,9 @@ class ModuleOp;
 /// in the given `context`. Returns the ModuleOp on success; otherwise, reports
 /// errors to the error handler registered with `context` and returns a null
 /// module.
-OwningOpRef<spirv::ModuleOp> deserialize(ArrayRef<uint32_t> binary,
-                                         MLIRContext *context);
+OwningOpRef<spirv::ModuleOp>
+deserialize(ArrayRef<uint32_t> binary, MLIRContext *context,
+            bool enableControlFlowStructurization = true);
 
 } // namespace spirv
 } // namespace mlir
diff --git a/mlir/lib/Target/SPIRV/Deserialization/Deserialization.cpp b/mlir/lib/Target/SPIRV/Deserialization/Deserialization.cpp
index 7bb8762660599..11a9de91060a8 100644
--- a/mlir/lib/Target/SPIRV/Deserialization/Deserialization.cpp
+++ b/mlir/lib/Target/SPIRV/Deserialization/Deserialization.cpp
@@ -12,9 +12,10 @@
 
 using namespace mlir;
 
-OwningOpRef<spirv::ModuleOp> spirv::deserialize(ArrayRef<uint32_t> binary,
-                                                MLIRContext *context) {
-  Deserializer deserializer(binary, context);
+OwningOpRef<spirv::ModuleOp>
+spirv::deserialize(ArrayRef<uint32_t> binary, MLIRContext *context,
+                   bool enableControlFlowStructurization) {
+  Deserializer deserializer(binary, context, enableControlFlowStructurization);
 
   if (failed(deserializer.deserialize()))
     return nullptr;
diff --git a/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp b/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
index 7afd6e9b25b77..1aa647485496d 100644
--- a/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
+++ b/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
@@ -49,9 +49,11 @@ static inline bool isFnEntryBlock(Block *block) {
 //===----------------------------------------------------------------------===//
 
 spirv::Deserializer::Deserializer(ArrayRef<uint32_t> binary,
-                                  MLIRContext *context)
+                                  MLIRContext *context,
+                                  bool enableControlFlowStructurization)
     : binary(binary), context(context), unknownLoc(UnknownLoc::get(context)),
-      module(createModuleOp()), opBuilder(module->getRegion())
+      module(createModuleOp()), opBuilder(module->getRegion()),
+      enableControlFlowStructurization(enableControlFlowStructurization)
 #ifndef NDEBUG
       ,
       logger(llvm::dbgs())
@@ -2361,6 +2363,16 @@ LogicalResult spirv::Deserializer::splitConditionalBlocks() {
 }
 
 LogicalResult spirv::Deserializer::structurizeControlFlow() {
+  if (!enableControlFlowStructurization) {
+    LLVM_DEBUG(
+        {
+          logger.startLine()
+              << "//----- [cf] skip structurizing control flow -----//\n";
+          logger.indent();
+        });
+    return success();
+  }
+
   LLVM_DEBUG({
     logger.startLine()
         << "//----- [cf] start structurizing control flow -----//\n";
diff --git a/mlir/lib/Target/SPIRV/Deserialization/Deserializer.h b/mlir/lib/Target/SPIRV/Deserialization/Deserializer.h
index bcc78e3e6508d..c1df77ba7b647 100644
--- a/mlir/lib/Target/SPIRV/Deserialization/Deserializer.h
+++ b/mlir/lib/Target/SPIRV/Deserialization/Deserializer.h
@@ -121,7 +121,10 @@ class Deserializer {
 public:
   /// Creates a deserializer for the given SPIR-V `binary` module.
   /// The SPIR-V ModuleOp will be created into `context.
-  explicit Deserializer(ArrayRef<uint32_t> binary, MLIRContext *context);
+  /// `enableControlFlowStructurization` is used to enable control flow
+  /// structurization.
+  explicit Deserializer(ArrayRef<uint32_t> binary, MLIRContext *context,
+                        bool enableControlFlowStructurization);
 
   /// Deserializes the remembered SPIR-V binary module.
   LogicalResult deserialize();
@@ -622,6 +625,9 @@ class Deserializer {
   /// A list of all structs which have unresolved member types.
   SmallVector<DeferredStructTypeInfo, 0> deferredStructTypesInfos;
 
+  /// A flag to enable or disable structurizer
+  bool enableControlFlowStructurization;
+
 #ifndef NDEBUG
   /// A logger used to emit information during the deserialzation process.
   llvm::ScopedPrinter logger;
diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp
index ff34f02d07b73..90e5b684607be 100644
--- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp
+++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp
@@ -37,7 +37,8 @@ using namespace mlir;
 // Deserializes the SPIR-V binary module stored in the file named as
 // `inputFilename` and returns a module containing the SPIR-V module.
 static OwningOpRef<Operation *>
-deserializeModule(const llvm::MemoryBuffer *input, MLIRContext *context) {
+deserializeModule(const llvm::MemoryBuffer *input, MLIRContext *context,
+                  bool enableControlFlowStructurization) {
   context->loadDialect<spirv::SPIRVDialect>();
 
   // Make sure the input stream can be treated as a stream of SPIR-V words
@@ -51,17 +52,24 @@ deserializeModule(const llvm::MemoryBuffer *input, MLIRContext *context) {
 
   auto binary = llvm::ArrayRef(reinterpret_cast<const uint32_t *>(start),
                                size / sizeof(uint32_t));
-  return spirv::deserialize(binary, context);
+  return spirv::deserialize(binary, context, enableControlFlowStructurization);
 }
 
 namespace mlir {
 void registerFromSPIRVTranslation() {
+  static llvm::cl::opt<bool> noControlFlowStructurization(
+      "spirv-no-control-flow-structurization",
+      llvm::cl::desc("Disable control flow structurization to enable "
+                     "deserialization of early exits (see #138688)"),
+      llvm::cl::init(false));
+
   TranslateToMLIRRegistration fromBinary(
       "deserialize-spirv", "deserializes the SPIR-V module",
       [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
         assert(sourceMgr.getNumBuffers() == 1 && "expected one buffer");
         return deserializeModule(
-            sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID()), context);
+            sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID()), context,
+            !noControlFlowStructurization);
       });
 }
 } // namespace mlir

@IgWod-IMG IgWod-IMG merged commit 7797824 into llvm:main Jun 3, 2025
11 checks passed
@IgWod-IMG IgWod-IMG deleted the img_disable-structurization branch June 3, 2025 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants