[Mlir-commits] [mlir] [mlir][Transforms] Fix crash in `CFGToSCF` when conversion fails (PR #173590)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Dec 25 19:45:48 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-core

@llvm/pr-subscribers-mlir

Author: NohHyeon Kwon (swote-git)

<details>
<summary>Changes</summary>

## Summary

Fix a crash in `transformToStructuredCFBranches` when `createStructuredBranchRegionOp` fails for unsupported control flow operations.

## Problem

When the conversion fails (e.g., for `spirv.BranchConditional` which doesn't implement the required SCF interface), the blocks moved into `conditionalRegions` are still referenced as successors by `regionEntry`'s terminator. 

When `conditionalRegions` goes out of scope and its destructor runs, it tries to delete these blocks while they still have uses, triggering:
```
Assertion `use_empty() && "Cannot destroy a value that still has uses!"' failed.
```

## Solution

Call `dropAllReferences()` on the terminator before returning failure.

## Testing

Added `cf-to-scf-cycle-cleanup.mlir` to verify the pass.
It reports an error instead of crashing when encountering unsupported ops in a cycle.

Fixes #<!-- -->173566

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


2 Files Affected:

- (modified) mlir/lib/Transforms/Utils/CFGToSCF.cpp (+3-1) 
- (added) mlir/test/Conversion/ControlFlowToSCF/cf-to-scf-cycle-cleanup.mlir (+27) 


``````````diff
diff --git a/mlir/lib/Transforms/Utils/CFGToSCF.cpp b/mlir/lib/Transforms/Utils/CFGToSCF.cpp
index dbde75e17b3b8..38df3bb85ffd8 100644
--- a/mlir/lib/Transforms/Utils/CFGToSCF.cpp
+++ b/mlir/lib/Transforms/Utils/CFGToSCF.cpp
@@ -1156,8 +1156,10 @@ static FailureOr<SmallVector<Block *>> transformToStructuredCFBranches(
     FailureOr<Operation *> result = interface.createStructuredBranchRegionOp(
         opBuilder, regionEntry->getTerminator(),
         continuation->getArgumentTypes(), conditionalRegions);
-    if (failed(result))
+    if (failed(result)) {
+      regionEntry->getTerminator()->dropAllReferences();
       return failure();
+    }
     structuredCondOp = *result;
     regionEntry->getTerminator()->erase();
   }
diff --git a/mlir/test/Conversion/ControlFlowToSCF/cf-to-scf-cycle-cleanup.mlir b/mlir/test/Conversion/ControlFlowToSCF/cf-to-scf-cycle-cleanup.mlir
new file mode 100644
index 0000000000000..4cfa19e355011
--- /dev/null
+++ b/mlir/test/Conversion/ControlFlowToSCF/cf-to-scf-cycle-cleanup.mlir
@@ -0,0 +1,27 @@
+// RUN: not mlir-opt %s -lift-cf-to-scf 2>&1 | FileCheck %s
+
+// This test verifies that the pass does not crash when encountering unsupported
+// control flow operations within a cycle (e.g., SPIR-V loops). (issue #173566)
+// It ensures that temporary regions are cleaned up correctly upon failure.
+
+// CHECK: Cannot convert unknown control flow op to structured control flow
+module {
+  func.func @spirv_loop_crash_repro(%arg0: index) {
+    %0 = builtin.unrealized_conversion_cast %arg0 : index to i32
+    %cst8 = spirv.Constant 8 : i32
+    
+    // spirv.mlir.loop creates a CFG cycle. 
+    spirv.mlir.loop {
+      spirv.Branch ^bb1(%0 : i32)
+    ^bb1(%2: i32):
+      %3 = spirv.SLessThan %2, %cst8 : i32
+      spirv.BranchConditional %3, ^bb2, ^bb3
+    ^bb2:
+      %4 = spirv.IAdd %2, %0 : i32
+      spirv.Branch ^bb1(%4 : i32)
+    ^bb3:
+      spirv.mlir.merge
+    }
+    spirv.Return
+  }
+}

``````````

</details>


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


More information about the Mlir-commits mailing list