-
Notifications
You must be signed in to change notification settings - Fork 15k
[mlir] Enable remove-dead-values to delete unused private function #161471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[mlir] Enable remove-dead-values to delete unused private function #161471
Conversation
|
@llvm/pr-subscribers-mlir @llvm/pr-subscribers-mlir-core Author: lonely eagle (linuxlonelyeagle) ChangesFix #158760. If a private functionOpInterface has no users and there is no callOpInterface in its region, it is a useless function, and the remove-dead-values pass will delete this function. Full diff: https://github.com/llvm/llvm-project/pull/161471.diff 2 Files Affected:
diff --git a/mlir/lib/Transforms/RemoveDeadValues.cpp b/mlir/lib/Transforms/RemoveDeadValues.cpp
index e0c65b0e09774..18c6006f04788 100644
--- a/mlir/lib/Transforms/RemoveDeadValues.cpp
+++ b/mlir/lib/Transforms/RemoveDeadValues.cpp
@@ -297,6 +297,17 @@ static void processFuncOp(FunctionOpInterface funcOp, Operation *module,
return;
}
+ // If a private function has neither users and function calls, it is a useless
+ // function.
+ SymbolTable::UseRange uses = *funcOp.getSymbolUses(module);
+ auto callSites = funcOp.getFunctionBody().getOps<CallOpInterface>();
+ if (uses.empty() && callSites.empty()) {
+ LDBG() << "Delete function op: "
+ << OpWithFlags(funcOp, OpPrintingFlags().skipRegions());
+ funcOp.erase();
+ return;
+ }
+
// Get the list of unnecessary (non-live) arguments in `nonLiveArgs`.
SmallVector<Value> arguments(funcOp.getArguments());
BitVector nonLiveArgs = markLives(arguments, nonLiveSet, la);
@@ -312,7 +323,6 @@ static void processFuncOp(FunctionOpInterface funcOp, Operation *module,
// Do (2). (Skip creating generic operand cleanup entries for call ops.
// Call arguments will be removed in the call-site specific segment-aware
// cleanup, avoiding generic eraseOperands bitvector mechanics.)
- SymbolTable::UseRange uses = *funcOp.getSymbolUses(module);
for (SymbolTable::SymbolUse use : uses) {
Operation *callOp = use.getUser();
assert(isa<CallOpInterface>(callOp) && "expected a call-like user");
@@ -881,9 +891,12 @@ void RemoveDeadValues::runOnOperation() {
// end of this pass.
RDVFinalCleanupList finalCleanupList;
+ module->walk([&](FunctionOpInterface op) {
+ processFuncOp(op, module, la, deadVals, finalCleanupList);
+ });
module->walk([&](Operation *op) {
if (auto funcOp = dyn_cast<FunctionOpInterface>(op)) {
- processFuncOp(funcOp, module, la, deadVals, finalCleanupList);
+ // The FunctionOpInterface has been processed in advance.
} else if (auto regionBranchOp = dyn_cast<RegionBranchOpInterface>(op)) {
processRegionBranchOp(regionBranchOp, la, deadVals, finalCleanupList);
} else if (auto branchOp = dyn_cast<BranchOpInterface>(op)) {
diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir
index 56449469dc29f..b8ad762c52ddf 100644
--- a/mlir/test/Transforms/remove-dead-values.mlir
+++ b/mlir/test/Transforms/remove-dead-values.mlir
@@ -649,3 +649,18 @@ func.func @callee(%arg0: index, %arg1: index, %arg2: index) -> index {
%res = call @mutl_parameter(%arg0, %arg1, %arg2) : (index, index, index) -> (index)
return %res : index
}
+
+// -----
+
+// CHECK-NOT: func private @single_private_func
+func.func private @single_private_func(%arg0: i64) -> (i64) {
+ %c0_i64 = arith.constant 0 : i64
+ %2 = arith.cmpi eq, %arg0, %c0_i64 : i64
+ cf.cond_br %2, ^bb1, ^bb2
+ ^bb1: // pred: ^bb0
+ %c1_i64 = arith.constant 1 : i64
+ return %c1_i64 : i64
+ ^bb2: // pred: ^bb0
+ %c3_i64 = arith.constant 3 : i64
+ return %c3_i64 : i64
+}
\ No newline at end of file
|
5bb13ee to
cee600a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this fixes the bug in question, just removes the function that contained the bug. We also have a dead symbol elimination pass that handles such cases generically.
https://mlir.llvm.org/docs/Passes/ I didn't see the dead symbol elimination pass. Looking at this from another angle, the private function is actually dead, so I introduced this. |
Can you describe a bit more the underlying issue? |
11eb3f8 to
16af35c
Compare
Why did the above result occur in the liveness analysis? |
|
That does not really explain the crash though: why wasn't the cond_branch also dead and removed? |
Good question. Give me a moment to look into the code. |
The liveness lattice will by default set the SSA values without a liveness lattice to dead. Why isn't the br.cond op explicitly set to dead? Because its operand, which is the result of arith.cmpi, is explicitly set to dead. In fact, it is dead. |
#161117 This PR maybe also need you.Thank you. |
16af35c to
8f974c9
Compare
|
@ftynse @joker-eph I've rewritten the code, and I think this should fix the issue nicely. |
| if (funcOp.isPublic() || funcOp.isExternal()) | ||
| return; | ||
|
|
||
| SymbolTable::UseRange uses = *funcOp.getSymbolUses(module); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this super expensive to build?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It certainly feels super expensive.I've updated the code so that it now only runs on functions that are likely to be dead functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I accidentally discovered that the -symbol-dce pass includes the functionality of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was mentioned to you earlier actually: #161471 (review)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I must admit I wasn't particularly well-versed in many of the MLIR passes, but I've gained a much better understanding now. Ha ha.😘
Actually, I just took another look at the code for this pass. The most immediate issue stems from directly deleting the operands of cond_br. The underlying problem remains the data flow analysis issue mentioned earlier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit of a pity that -symbol-dce isn't implemented via patterns; otherwise, it might have been possible to incorporate it into remove-dead-values.To be perfectly honest, I know what the best fix is.Indeed, deleting dead functions is not the best approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think perhaps we could wrap the logic of symbol-dce in a function and then use it in remove-dead-values.
Fix #158760. Introduce the deleteDeadFunction function, which is used to delete dead functions.