[MLIR][Affine] mlir-opt crashes with `--affine-loop-fusion`: operation destroyed but still has uses
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Sibling fusion merges two loops that read the same memref and then deletes the one it merged away. When that loop carries an `iter_arg`, it has a result, and the result may still be used — nothing checks before the erase.
### Reproducer
small.mlir
```mlir
func.func @f(%m: memref<4xi32>, %n: memref<4xi32>, %init: i32) -> i32 {
%a = affine.for %i = 0 to 4 iter_args(%x = %init) -> (i32) {
%v = affine.load %m[%i] : memref<4xi32>
%t = arith.addi %x, %v : i32
affine.yield %t : i32
}
affine.for %i = 0 to 4 {
%v = affine.load %m[%i] : memref<4xi32>
affine.store %v, %n[%i] : memref<4xi32>
}
return %a : i32
}
```
To reproduce:
```
mlir-opt small.mlir --affine-loop-fusion -o /dev/null
```
Crash:
```
small.mlir:4:8: error: 'affine.for' op operation destroyed but still has uses
%a = affine.for %i = 0 to 4 iter_args(%x = %init) -> (i32) {
^
small.mlir:4:8: note: see current operation:
%0 = "affine.for"(<>) <{lowerBoundMap = affine_map<() -> (0)>, operandSegmentSizes = array, step = 1 : index, upperBoundMap = affine_map<() -> (4)>}> ({
^bb0(%arg0: index, %arg1: i32):
%1 = "affine.load"(<>, %arg0) <{map = affine_map<(d0) -> (d0)>}> : (memref<4xi32>, index) -> i32
%2 = "arith.addi"(%arg1, %1) <{overflowFlags = #arith.overflow}> : (i32, i32) -> i32
"affine.yield"(%2) : (i32) -> ()
}) : (i32) -> i32
small.mlir:13:3: note: - use: "func.return"(<>) : (i32) -> ()
return %a : i32
^
LLVM ERROR: operation destroyed but still has uses
```
Stack dump:
```
0. Program arguments: mlir-opt small.mlir --affine-loop-fusion -o /dev/null
#0 0x0000aaaad3df6988 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /data/x27zhou/compiler-nightly/src/llvm-project/llvm/lib/Support/Unix/Signals.inc:935:3
#1 0x0000aaaad3df38fc llvm::sys::RunSignalHandlers() /data/x27zhou/compiler-nightly/src/llvm-project/llvm/lib/Support/Signals.cpp:109:18
#2 0x0000aaaad3df3fc8 SignalHandler(int, siginfo_t*, void*) /data/x27zhou/compiler-nightly/src/llvm-project/llvm/lib/Support/Unix/Signals.inc:474:14
#3 0x0000ffff97afb7dc (linux-vdso.so.1+0x7dc)
#4 0x0000ffff97662008 (/lib/aarch64-linux-gnu/libc.so.6+0x82008)
#5 0x0000ffff9761a83c gsignal (/lib/aarch64-linux-gnu/libc.so.6+0x3a83c)
#6 0x0000ffff97607134 abort (/lib/aarch64-linux-gnu/libc.so.6+0x27134)
#7 0x0000aaaad3ddb7d0 llvm::report_fatal_error(llvm::StringRef, bool) /data/x27zhou/compiler-nightly/src/llvm-project/llvm/lib/Support/ErrorHandling.cpp:99:68
#8 0x0000aaaad3ddb854 (/data/x27zhou/compiler-nightly/build/mlir/bin/mlir-opt+0x210b854)
#9 0x0000aaaadbb8aa30 llvm::detail::indexed_accessor_range_base::iterator std::__find_if::iterator, __gnu_cxx::__ops::_Iter_negate >(llvm::detail::indexed_accessor_range_base::iterator, llvm::detail::indexed_accessor_range_base::iterator, __gnu_cxx::__ops::_Iter_negate, std::random_access_iterator_tag) /usr/include/c++/11/bits/stl_algobase.h:2067:27
#10 0x0000aaaadbb8aa30 llvm::detail::indexed_accessor_range_base::iterator std::__find_if_not::iterator, __gnu_cxx::__ops::_Iter_pred >(llvm::detail::indexed_accessor_range_base::iterator, llvm::detail::indexed_accessor_range_base::iterator, __gnu_cxx::__ops::_Iter_pred) /usr/include/c++/11/bits/stl_algo.h:106:28
#11 0x0000aaaadbb8aa30 llvm::detail::indexed_accessor_range_base::iterator std::find_if_not::iterator, mlir::ResultRange::use_empty() const::'lambda'(mlir::OpResult)>(llvm::detail::indexed_accessor_range_base::iterator, llvm::detail::indexed_accessor_range_base::iterator, mlir::ResultRange::use_empty() const::'lambda'(mlir::OpResult)) /usr/include/c++/11/bits/stl_algo.h:513:32
#12 0x0000aaaadbb8aa30 bool std::all_of::iterator,mlir::ResultRange::use_empty() const::'lambda'(mlir::OpResult)>(llvm::detail::indexed_accessor_range_base::iterator, llvm::detail::indexed_accessor_range_base::iterator, mlir::ResultRange::use_empty() const::'lambda'(mlir::OpResult)) /usr/include/c++/11/bits/stl_algo.h:453:40
#13 0x0000aaaadbb8aa30 bool llvm::all_of(mlir::ResultRange const&, mlir::ResultRange::use_empty() const::'lambda'(mlir::OpResult)) /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/STLExtras.h:1740:21
#14 0x0000aaaadbb8aa30 mlir::ResultRange::use_empty() const /data/x27zhou/compiler-nightly/src/llvm-project/mlir/include/mlir/IR/ValueRange.h:279:24
#15 0x0000aaaadbb8aa30 mlir::Operation::use_empty() /data/x27zhou/compiler-nightly/src/llvm-project/mlir/include/mlir/IR/Operation.h:877:51
#16 0x0000aaaadbb8aa30 mlir::Operation::~Operation() /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/IR/Operation.cpp:178:17
#17 0x0000aaaadbb8aa94 mlir::Operation::destroy() /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/IR/Operation.cpp:208:69
#18 0x0000aaaad9eb38f4 llvm::SmallVectorTemplateCommon::end() /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/SmallVector.h:278:35
#19 0x0000aaaad9eb38f4 llvm::SmallVector::~SmallVector() /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/SmallVector.h:1242:24
#20 0x0000aaaad9eb38f4 (anonymous namespace)::GreedyFusion::fuseWithSiblingNodes(mlir::affine::MemRefDependenceGraph::Node*) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp:1355:5
#21 0x0000aaaad9eb42f4 (anonymous namespace)::GreedyFusion::fuseSiblingNodes() /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp:1195:27
#22 0x0000aaaad9eb466c runGreedyFusion /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp:833:30
#23 0x0000aaaad9eb466c runOnBlock /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp:1539:27
#24 0x0000aaaad9eb466c (anonymous namespace)::LoopFusion::runOnOperation()::'lambda'(mlir::Operation*)::operator()(mlir::Operation*) const /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp:1550:21
#25 0x0000aaaad3ebcb58 llvm::ilist_iterator, false, false>::operator++() /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/ilist_iterator.h:187:13
#26 0x0000aaaad3ebcb58 llvm::ilist_iterator, false, false>::operator++(int) /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/ilist_iterator.h:197:5
#27 0x0000aaaad3ebcb58 llvm::early_inc_iterator_impl, false, false> >::operator*() /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/STLExtras.h:598:22
#28 0x0000aaaad3ebcb58 void mlir::detail::walk(mlir::Operation*, llvm::function_ref, mlir::WalkOrder) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/include/mlir/IR/Visitors.h:146:7
#29 0x0000aaaad9eaa48c (anonymous namespace)::LoopFusion::runOnOperation() /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp:1554:1
#30 0x0000aaaadb8896a0 operator() /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Pass/Pass.cpp:612:33
#31 0x0000aaaadb8896a0 callback_fn > /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:46:52
#32 0x0000aaaadb8896a0 llvm::function_ref::operator()() const /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:69:12
#33 0x0000aaaadb8896a0 void mlir::MLIRContext::executeAction(llvm::function_ref, llvm::ArrayRef, mlir::Pass&) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/include/mlir/IR/MLIRContext.h:296:15
#34 0x0000aaaadb8896a0 mlir::detail::OpToOpPassAdaptor::run(mlir::Pass*, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Pass/Pass.cpp:606:57
#35 0x0000aaaadb88995c mlir::detail::OpToOpPassAdaptor::runPipeline(mlir::OpPassManager&, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int, mlir::PassInstrumentor*, mlir::PassInstrumentation::PipelineParentInfo const*) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Pass/Pass.cpp:688:5
#36 0x0000aaaadb88c734 mlir::PassManager::run(mlir::Operation*) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Pass/Pass.cpp:1102:69
#37 0x0000aaaad3e9ebdc performActions(llvm::raw_ostream&, std::shared_ptr const&, mlir::MLIRContext*, mlir::MlirOptMainConfig const&) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp:596:3
#38 0x0000aaaad3e9f500 processBuffer /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp:686:26
#39 0x0000aaaad3e9f500 operator() /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp:784:25
#40 0x0000aaaad3e9f500 llvm::LogicalResult llvm::function_ref >, llvm::MemoryBufferRef const&, llvm::raw_ostream&)>::callback_fn >, mlir::DialectRegistry&, mlir::MlirOptMainConfig const&)::'lambda'(std::unique_ptr >, llvm::MemoryBufferRef, llvm::raw_ostream&)>(long, std::unique_ptr >, llvm::MemoryBufferRef const&, llvm::raw_ostream&) /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:46:52
#41 0x0000aaaadbbd1678 llvm::function_ref >, llvm::MemoryBufferRef const&, llvm::raw_ostream&)>::operator()(std::unique_ptr >, llvm::MemoryBufferRef const&, llvm::raw_ostream&) const /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:69:12
#42 0x0000aaaadbbd1678 mlir::splitAndProcessBuffer(std::unique_ptr >, llvm::function_ref >, llvm::MemoryBufferRef const&, llvm::raw_ostream&)>, llvm::raw_ostream&, llvm::StringRef, llvm::StringRef) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Support/ToolUtilities.cpp:30:30
#43 0x0000aaaad3e98a28 mlir::MlirOptMain(llvm::raw_ostream&, std::unique_ptr >, mlir::DialectRegistry&, mlir::MlirOptMainConfig const&) (.part.0) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp:789:47
#44 0x0000aaaad3e9fb10 mlir::MlirOptMain(llvm::raw_ostream&, std::unique_ptr >, mlir::DialectRegistry&, mlir::MlirOptMainConfig const&) /data/x27zhou/compiler-nightly/src/llvm-project/llvm/include/llvm/Support/LogicalResult.h:62:42
#45 0x0000aaaad3e9fb10 mlir::MlirOptMain(int, char**, llvm::StringRef, llvm::StringRef, mlir::DialectRegistry&) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp:835:13
#46 0x0000aaaad3e9fcc0 mlir::MlirOptMain(int, char**, llvm::StringRef, mlir::DialectRegistry&) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp:851:21
#47 0x0000aaaad3d735ac mlir::asMainReturnCode(llvm::LogicalResult) /data/x27zhou/compiler-nightly/src/llvm-project/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h:436:24
#48 0x0000aaaad3d735ac main /data/x27zhou/compiler-nightly/src/llvm-project/mlir/tools/mlir-opt/mlir-opt.cpp:345:32
#49 0x0000ffff97607400 (/lib/aarch64-linux-gnu/libc.so.6+0x27400)
#50 0x0000ffff976074d8 __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x274d8)
#51 0x0000aaaad3ddaff0 _start (/data/x27zhou/compiler-nightly/build/mlir/bin/mlir-opt+0x210aff0)
```
Contributor guide
Research direction
Start in mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp, especially GreedyFusion::fuseWithSiblingNodes at the reported line near 1355. Run mlir-opt on the provided small.mlir reproducer and trace how sibling fusion handles the affine.for result before erasing it. Done means the reproducer no longer crashes and a regression test covers an iter_arg result that remains in use.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100