Skip to content

Commit 5a4ca51

Browse files
authored
[mlir] notify insertion of parent op first when cloning (llvm#73806)
When cloning an operation with a region, the builder was currently notifying about the insertion of the cloned operations inside the region before the cloned operation itself. When using cloning inside rewrite pass, this could cause issues if a pattern is expected to be applied on a cloned parent operation before trying to apply patterns on the cloned operations it contains (the patterns are attempted in order of notifications for the cloned operations).
1 parent d55692d commit 5a4ca51

File tree

3 files changed

+31
-7
lines changed

3 files changed

+31
-7
lines changed

mlir/lib/IR/Builders.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,17 +527,18 @@ LogicalResult OpBuilder::tryFold(Operation *op,
527527

528528
Operation *OpBuilder::clone(Operation &op, IRMapping &mapper) {
529529
Operation *newOp = op.clone(mapper);
530-
// The `insert` call below handles the notification for inserting `newOp`
530+
newOp = insert(newOp);
531+
// The `insert` call above handles the notification for inserting `newOp`
531532
// itself. But if `newOp` has any regions, we need to notify the listener
532533
// about any ops that got inserted inside those regions as part of cloning.
533534
if (listener) {
534535
auto walkFn = [&](Operation *walkedOp) {
535536
listener->notifyOperationInserted(walkedOp);
536537
};
537538
for (Region &region : newOp->getRegions())
538-
region.walk(walkFn);
539+
region.walk<WalkOrder::PreOrder>(walkFn);
539540
}
540-
return insert(newOp);
541+
return newOp;
541542
}
542543

543544
Operation *OpBuilder::clone(Operation &op) {

mlir/test/IR/test-clone.mlir

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
1-
// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline="builtin.module(func.func(test-clone))" -split-input-file
1+
// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline="builtin.module(func.func(test-clone))" | FileCheck %s
22

33
module {
44
func.func @fixpoint(%arg1 : i32) -> i32 {
55
%r = "test.use"(%arg1) ({
6-
"test.yield"(%arg1) : (i32) -> ()
6+
%r2 = "test.use2"(%arg1) ({
7+
"test.yield2"(%arg1) : (i32) -> ()
8+
}) : (i32) -> i32
9+
"test.yield"(%r2) : (i32) -> ()
710
}) : (i32) -> i32
811
return %r : i32
912
}
1013
}
1114

15+
// CHECK: notifyOperationInserted: test.use
16+
// CHECK-NEXT: notifyOperationInserted: test.use2
17+
// CHECK-NEXT: notifyOperationInserted: test.yield2
18+
// CHECK-NEXT: notifyOperationInserted: test.yield
19+
// CHECK-NEXT: notifyOperationInserted: func.return
20+
1221
// CHECK: func @fixpoint(%[[arg0:.+]]: i32) -> i32 {
1322
// CHECK-NEXT: %[[i0:.+]] = "test.use"(%[[arg0]]) ({
14-
// CHECK-NEXT: "test.yield"(%arg0) : (i32) -> ()
23+
// CHECK-NEXT: %[[r2:.+]] = "test.use2"(%[[arg0]]) ({
24+
// CHECK-NEXT: "test.yield2"(%[[arg0]]) : (i32) -> ()
25+
// CHECK-NEXT: }) : (i32) -> i32
26+
// CHECK-NEXT: "test.yield"(%[[r2]]) : (i32) -> ()
1527
// CHECK-NEXT: }) : (i32) -> i32
1628
// CHECK-NEXT: %[[i1:.+]] = "test.use"(%[[i0]]) ({
17-
// CHECK-NEXT: "test.yield"(%[[i0]]) : (i32) -> ()
29+
// CHECK-NEXT: %[[r2:.+]] = "test.use2"(%[[i0]]) ({
30+
// CHECK-NEXT: "test.yield2"(%[[i0]]) : (i32) -> ()
31+
// CHECK-NEXT: }) : (i32) -> i32
32+
// CHECK-NEXT: "test.yield"(%[[r2]]) : (i32) -> ()
1833
// CHECK-NEXT: }) : (i32) -> i32
1934
// CHECK-NEXT: return %[[i1]] : i32
2035
// CHECK-NEXT: }

mlir/test/lib/IR/TestClone.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ using namespace mlir;
1414

1515
namespace {
1616

17+
struct DumpNotifications : public OpBuilder::Listener {
18+
void notifyOperationInserted(Operation *op) override {
19+
llvm::outs() << "notifyOperationInserted: " << op->getName() << "\n";
20+
}
21+
};
22+
1723
/// This is a test pass which clones the body of a function. Specifically
1824
/// this pass replaces f(x) to instead return f(f(x)) in which the cloned body
1925
/// takes the result of the first operation return as an input.
@@ -50,6 +56,8 @@ struct ClonePass
5056
}
5157

5258
OpBuilder builder(op->getContext());
59+
DumpNotifications dumpNotifications;
60+
builder.setListener(&dumpNotifications);
5361
builder.setInsertionPointToEnd(&regionEntry);
5462
SmallVector<Operation *> toClone;
5563
for (Operation &inst : regionEntry)

0 commit comments

Comments
 (0)