[llvm] 762253b - [DAE] Don't DAE if we musttail call a "live" (non-DAE-able) function
Mircea Trofin via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 16 13:59:34 PDT 2023
Author: Mircea Trofin
Date: 2023-03-16T13:36:11-07:00
New Revision: 762253b048e9f760624dea3537535c3657435902
URL: https://github.com/llvm/llvm-project/commit/762253b048e9f760624dea3537535c3657435902
DIFF: https://github.com/llvm/llvm-project/commit/762253b048e9f760624dea3537535c3657435902.diff
LOG: [DAE] Don't DAE if we musttail call a "live" (non-DAE-able) function
There are 2 such base cases: indirect calls and calls to functions external
to the module; and then any musttail calls to live functions (because of
the first 2 reasons or otherwise).
The IR validator reports, in these cases, that it "cannot guarantee tail
call due to mismatched parameter counts".
The fix is two-fold: first, we mark as "live" (i.e. non-DAE-able)
functions that make an indirect musttail call.
Then, we propagate live-ness to musttail callers of live functions.
Declared functions are already marked "live".
Differential Revision: https://reviews.llvm.org/D145209
Added:
llvm/test/Transforms/DeadArgElim/musttail-indirect.ll
Modified:
llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h
llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h b/llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h
index a71fa3bf404de..63e1ad043d49f 100644
--- a/llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h
+++ b/llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h
@@ -136,6 +136,7 @@ class DeadArgumentEliminationPass
bool removeDeadStuffFromFunction(Function *F);
bool deleteDeadVarargs(Function &F);
bool removeDeadArgumentsFromCallers(Function &F);
+ void propagateVirtMustcallLiveness(const Module &M);
};
} // end namespace llvm
diff --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
index bf2c65a2402cb..d6dc0f94bfcf0 100644
--- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
+++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
@@ -85,6 +85,11 @@ class DAE : public ModulePass {
virtual bool shouldHackArguments() const { return false; }
};
+bool isMustTailCalleeAnalyzable(const CallBase &CB) {
+ assert(CB.isMustTailCall());
+ return CB.getCalledFunction() && !CB.getCalledFunction()->isDeclaration();
+}
+
} // end anonymous namespace
char DAE::ID = 0;
@@ -520,8 +525,16 @@ void DeadArgumentEliminationPass::surveyFunction(const Function &F) {
for (const BasicBlock &BB : F) {
// If we have any returns of `musttail` results - the signature can't
// change
- if (BB.getTerminatingMustTailCall() != nullptr)
+ if (const auto *TC = BB.getTerminatingMustTailCall()) {
HasMustTailCalls = true;
+ // In addition, if the called function is not locally defined (or unknown,
+ // if this is an indirect call), we can't change the callsite and thus
+ // can't change this function's signature either.
+ if (!isMustTailCalleeAnalyzable(*TC)) {
+ markLive(F);
+ return;
+ }
+ }
}
if (HasMustTailCalls) {
@@ -1081,6 +1094,26 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
return true;
}
+void DeadArgumentEliminationPass::propagateVirtMustcallLiveness(
+ const Module &M) {
+ // If a function was marked "live", and it has musttail callers, they in turn
+ // can't change either.
+ LiveFuncSet NewLiveFuncs(LiveFunctions);
+ while (!NewLiveFuncs.empty()) {
+ LiveFuncSet Temp;
+ for (const auto *F : NewLiveFuncs)
+ for (const auto *U : F->users())
+ if (const auto *CB = dyn_cast<CallBase>(U))
+ if (CB->isMustTailCall())
+ if (!LiveFunctions.count(CB->getParent()->getParent()))
+ Temp.insert(CB->getParent()->getParent());
+ NewLiveFuncs.clear();
+ NewLiveFuncs.insert(Temp.begin(), Temp.end());
+ for (const auto *F : Temp)
+ markLive(*F);
+ }
+}
+
PreservedAnalyses DeadArgumentEliminationPass::run(Module &M,
ModuleAnalysisManager &) {
bool Changed = false;
@@ -1101,6 +1134,8 @@ PreservedAnalyses DeadArgumentEliminationPass::run(Module &M,
for (auto &F : M)
surveyFunction(F);
+ propagateVirtMustcallLiveness(M);
+
// Now, remove all dead arguments and return values from each function in
// turn. We use make_early_inc_range here because functions will probably get
// removed (i.e. replaced by new ones).
diff --git a/llvm/test/Transforms/DeadArgElim/musttail-indirect.ll b/llvm/test/Transforms/DeadArgElim/musttail-indirect.ll
new file mode 100644
index 0000000000000..cdcccb44c0c56
--- /dev/null
+++ b/llvm/test/Transforms/DeadArgElim/musttail-indirect.ll
@@ -0,0 +1,65 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature
+; RUN: opt -passes=deadargelim -S < %s | FileCheck %s
+
+define internal i32 @test_caller(ptr %fptr, i32 %a, i32 %b) {
+; CHECK-LABEL: define {{[^@]+}}@test_caller(ptr %fptr, i32 %a, i32 %b) {
+; CHECK-NEXT: %r = musttail call i32 @test(ptr %fptr, i32 %a, i32 poison)
+; CHECK-NEXT: ret i32 %r
+;
+ %r = musttail call i32 @test(ptr %fptr, i32 %a, i32 %b)
+ ret i32 %r
+}
+
+define internal i32 @test(ptr %fptr, i32 %a, i32 %b) {
+; CHECK-LABEL: define {{[^@]+}}@test(ptr %fptr, i32 %a, i32 %b) {
+; CHECK-NEXT: %r = musttail call i32 %fptr(ptr %fptr, i32 %a, i32 0)
+; CHECK-NEXT: ret i32 %r
+;
+ %r = musttail call i32 %fptr(ptr %fptr, i32 %a, i32 0)
+ ret i32 %r
+}
+
+define internal i32 @direct_test() {
+; CHECK-LABEL: define {{[^@]+}}@direct_test() {
+; CHECK-NEXT: %r = musttail call i32 @foo()
+; CHECK-NEXT: ret i32 %r
+;
+ %r = musttail call i32 @foo()
+ ret i32 %r
+}
+
+declare i32 @foo()
+
+define internal i32 @ping(i32 %x) {
+; CHECK-LABEL: define {{[^@]+}}@ping(i32 %x) {
+; CHECK-NEXT: %r = musttail call i32 @pong(i32 %x)
+; CHECK-NEXT: ret i32 %r
+;
+ %r = musttail call i32 @pong(i32 %x)
+ ret i32 %r
+}
+
+define internal i32 @pong(i32 %x) {
+; CHECK-LABEL: define {{[^@]+}}@pong(i32 %x) {
+; CHECK-NEXT: %cond = icmp eq i32 %x, 2
+; CHECK-NEXT: br i1 %cond, label %yes, label %no
+; CHECK: yes:
+; CHECK-NEXT: %r1 = musttail call i32 @ping(i32 %x)
+; CHECK-NEXT: ret i32 %r1
+; CHECK: no:
+; CHECK-NEXT: %r2 = musttail call i32 @bar(i32 %x)
+; CHECK-NEXT: ret i32 %r2
+;
+ %cond = icmp eq i32 %x, 2
+ br i1 %cond, label %yes, label %no
+
+yes:
+ %r1 = musttail call i32 @ping(i32 %x)
+ ret i32 %r1
+no:
+ %r2 = musttail call i32 @bar(i32 %x)
+ ret i32 %r2
+}
+
+declare i32 @bar(i32 %x)
+
More information about the llvm-commits
mailing list