[Mlir-commits] [mlir] [MLIR] Fix ErasedOpsListener false positives for newly created ops/blocks (PR #192291)
Mehdi Amini
llvmlistbot at llvm.org
Wed Apr 15 10:14:48 PDT 2026
joker-eph wrote:
The case I'm looking at:
func.func @vector_and_reduction() {
%v_mask = vector.constant_mask [1] : vector<2xi1>
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
%result = scf.parallel (%i) = (%c0) to (%c2) step (%c1) init(%v_mask) -> vector<2xi1> {
%val = vector.constant_mask [1] : vector<2xi1>
scf.reduce (%val : vector<2xi1>) {
^bb0(%lhs: vector<2xi1>, %rhs: vector<2xi1>):
%0 = arith.andi %lhs, %rhs : vector<2xi1>
scf.reduce.return %0 : vector<2xi1>
}
}
return
}
For SCFToOpenMP, to remove the scf.parallel we'll build a omp.parallel op first to move the body there:
"omp.parallel"() <{operandSegmentSizes = array<i32: 0, 0, 0, 0, 0, 0>}> ({
^bb0:
}) : () -> ()
%6 = "scf.parallel"(%1, %3, %2, %0) <{operandSegmentSizes = array<i32: 1, 1, 1, 1>}> ({
^bb0(%arg0: index, %arg1: !llvm.ptr):
%7 = "vector.constant_mask"() <{mask_dim_sizes = array<i64: 1>}> : () -> vector<2xi1>
%8 = "llvm.load"(%arg1) <{ordering = 0 : i64}> : (!llvm.ptr) -> vector<2xi1>
%9 = "arith.andi"(%8, %7) : (vector<2xi1>, vector<2xi1>) -> vector<2xi1>
"llvm.store"(%9, %arg1) <{ordering = 0 : i64}> : (vector<2xi1>, !llvm.ptr) -> ()
}) : (index, index, index, vector<2xi1>) -> vector<2xi1>then we move operations and restructure until we get to:
"omp.parallel"() <{operandSegmentSizes = array<i32: 0, 0, 0, 0, 0, 0>}> ({
"omp.wsloop"(%5) <{operandSegmentSizes = array<i32: 0, 0, 0, 0, 0, 1, 0>, reduction_byref = array<i1: false>, reduction_syms = [@__scf_reduction]}> ({
^bb0(%arg0: !llvm.ptr):
"omp.loop_nest"(%1, %3, %2) <{collapse_num_loops = 1 : i64}> ({
^bb0(%arg1: index):
^bb1: // no predecessors
%7 = "vector.constant_mask"() <{mask_dim_sizes = array<i64: 1>}> : () -> vector<2xi1>
%8 = "llvm.load"(%arg0) <{ordering = 0 : i64}> : (!llvm.ptr) -> vector<2xi1>
%9 = "arith.andi"(%8, %7) : (vector<2xi1>, vector<2xi1>) -> vector<2xi1>
"llvm.store"(%9, %arg0) <{ordering = 0 : i64}> : (vector<2xi1>, !llvm.ptr) -> ()
}) : (index, index, index) -> ()
}) : (!llvm.ptr) -> ()
"omp.terminator"() : () -> ()
}) : () -> ()
%6 = "scf.parallel"(%1, %3, %2, %0) <{operandSegmentSizes = array<i32: 1, 1, 1, 1>}> ({
}) : (index, index, index, vector<2xi1>) -> vector<2xi1>
The scf.parallel is empty, everything is under the omp.parallel. The next thing to do is to move things into a nested AllocaScopeOp inside the loop_nest op:
"omp.parallel"() <{operandSegmentSizes = array<i32: 0, 0, 0, 0, 0, 0>}> ({
"omp.wsloop"(%5) <{operandSegmentSizes = array<i32: 0, 0, 0, 0, 0, 1, 0>, reduction_byref = array<i1: false>, reduction_syms = [@__scf_reduction]}> ({
^bb0(%arg0: !llvm.ptr):
"omp.loop_nest"(%1, %3, %2) <{collapse_num_loops = 1 : i64}> ({
^bb0(%arg1: index):
"memref.alloca_scope"() ({
%7 = "vector.constant_mask"() <{mask_dim_sizes = array<i64: 1>}> : () -> vector<2xi1>
%8 = "llvm.load"(%arg0) <{ordering = 0 : i64}> : (!llvm.ptr) -> vector<2xi1>
%9 = "arith.andi"(%8, %7) : (vector<2xi1>, vector<2xi1>) -> vector<2xi1>
"llvm.store"(%9, %arg0) <{ordering = 0 : i64}> : (vector<2xi1>, !llvm.ptr) -> ()
"memref.alloca_scope.return"() : () -> ()
}) : () -> ()
"omp.yield"() : () -> ()
}) : (index, index, index) -> ()
}) : (!llvm.ptr) -> ()
"omp.terminator"() : () -> ()
}) : () -> ()
%6 = "scf.parallel"(%1, %3, %2, %0) <{operandSegmentSizes = array<i32: 1, 1, 1, 1>}> ({
}) : (index, index, index, vector<2xi1>) -> vector<2xi1>
However when we do this, we have to call rewriter.mergeBlocks to move the ops into the alloca_scope. When we do that we delete the old block, but its parent is omp.loop_nest/omp.parallel, not scf.parallel, and the check is then failing.
So the restriction on not deleting anything not nested under the visited root op seems be too strict here.
https://github.com/llvm/llvm-project/pull/192291
More information about the Mlir-commits
mailing list