[Mlir-commits] [mlir] 2f672e2 - [mlir] Don't inline calls from dead SCCs

Alex Zinenko llvmlistbot at llvm.org
Mon Jan 10 03:07:22 PST 2022


Author: Alex Zinenko
Date: 2022-01-10T12:07:14+01:00
New Revision: 2f672e2ffa22d8c10279569de123a1e60d3aa00e

URL: https://github.com/llvm/llvm-project/commit/2f672e2ffa22d8c10279569de123a1e60d3aa00e
DIFF: https://github.com/llvm/llvm-project/commit/2f672e2ffa22d8c10279569de123a1e60d3aa00e.diff

LOG: [mlir] Don't inline calls from dead SCCs

During iterative inlining of the functions in a multi-step call chain, the
inliner could add the same call operation several times to the worklist, which
led to use-after-free when this op was considered more than once.

Closes #52887.

Reviewed By: wsmoses

Differential Revision: https://reviews.llvm.org/D116820

Added: 
    mlir/test/Transforms/inlining-repeated-use.mlir

Modified: 
    mlir/lib/Transforms/Inliner.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Transforms/Inliner.cpp b/mlir/lib/Transforms/Inliner.cpp
index c0befb76eed0a..d1587d650f14a 100644
--- a/mlir/lib/Transforms/Inliner.cpp
+++ b/mlir/lib/Transforms/Inliner.cpp
@@ -435,7 +435,7 @@ static LogicalResult inlineCallsInSCC(Inliner &inliner, CGUseList &useList,
   auto &calls = inliner.calls;
 
   // A set of dead nodes to remove after inlining.
-  SmallVector<CallGraphNode *, 1> deadNodes;
+  llvm::SmallSetVector<CallGraphNode *, 1> deadNodes;
 
   // Collect all of the direct calls within the nodes of the current SCC. We
   // don't traverse nested callgraph nodes, because they are handled separately
@@ -446,7 +446,7 @@ static LogicalResult inlineCallsInSCC(Inliner &inliner, CGUseList &useList,
 
     // Don't collect calls if the node is already dead.
     if (useList.isDead(node)) {
-      deadNodes.push_back(node);
+      deadNodes.insert(node);
     } else {
       collectCallOps(*node->getCallableRegion(), node, cg, inliner.symbolTable,
                      calls, /*traverseNestedCGNodes=*/false);
@@ -457,6 +457,8 @@ static LogicalResult inlineCallsInSCC(Inliner &inliner, CGUseList &useList,
   // here as more calls may be added during inlining.
   bool inlinedAnyCalls = false;
   for (unsigned i = 0; i != calls.size(); ++i) {
+    if (deadNodes.contains(calls[i].sourceNode))
+      continue;
     ResolvedCall it = calls[i];
     bool doInline = shouldInline(it);
     CallOpInterface call = it.call;
@@ -493,7 +495,7 @@ static LogicalResult inlineCallsInSCC(Inliner &inliner, CGUseList &useList,
     // If we inlined in place, mark the node for deletion.
     if (inlineInPlace) {
       useList.eraseNode(it.targetNode);
-      deadNodes.push_back(it.targetNode);
+      deadNodes.insert(it.targetNode);
     }
   }
 

diff  --git a/mlir/test/Transforms/inlining-repeated-use.mlir b/mlir/test/Transforms/inlining-repeated-use.mlir
new file mode 100644
index 0000000000000..72ea2f7e5236a
--- /dev/null
+++ b/mlir/test/Transforms/inlining-repeated-use.mlir
@@ -0,0 +1,48 @@
+// RUN: mlir-opt -inline %s | FileCheck %s
+
+// This could crash the inliner, make sure it does not.
+
+func @A() {
+  call @B() { inA } : () -> ()
+  return
+}
+
+func @B() {
+  call @E() : () -> ()
+  return
+}
+
+func @C() {
+  call @D() : () -> ()
+  return
+}
+
+func private @D() {
+  call @B() { inD } : () -> ()
+  return
+}
+
+func @E() {
+  call @fabsf() : () -> ()
+  return
+}
+
+func private @fabsf()
+
+// CHECK: func @A() {
+// CHECK:   call @fabsf() : () -> ()
+// CHECK:   return
+// CHECK: }
+// CHECK: func @B() {
+// CHECK:   call @fabsf() : () -> ()
+// CHECK:   return
+// CHECK: }
+// CHECK: func @C() {
+// CHECK:   call @fabsf() : () -> ()
+// CHECK:   return
+// CHECK: }
+// CHECK: func @E() {
+// CHECK:   call @fabsf() : () -> ()
+// CHECK:   return
+// CHECK: }
+// CHECK: func private @fabsf()


        


More information about the Mlir-commits mailing list