Skip to content

Commit 5978bb2

Browse files
authored
[DeadArgElim] fix verifier failure when changing musttail's function signature (#127366)
This commit is for #107569 and #126817. Stop changing musttail's caller and callee's function signature when calling convention is not swifttailcc nor tailcc. Verifier makes sure musttail's caller and callee shares exactly the same signature, see commit 9ff2eb1 and #54964. Otherwise just make sure the return type is the same and then process musttail like usual calls. close #107569, #126817
1 parent b042887 commit 5978bb2

File tree

4 files changed

+132
-84
lines changed

4 files changed

+132
-84
lines changed

llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,16 @@ class DeadArgumentEliminationPass
106106
UseMap Uses;
107107

108108
using LiveSet = std::set<RetOrArg>;
109-
using LiveFuncSet = std::set<const Function *>;
109+
using FuncSet = std::set<const Function *>;
110110

111111
/// This set contains all values that have been determined to be live.
112112
LiveSet LiveValues;
113113

114-
/// This set contains all values that are cannot be changed in any way.
115-
LiveFuncSet LiveFunctions;
114+
/// This set contains all functions that cannot be changed in any way.
115+
FuncSet FrozenFunctions;
116+
117+
/// This set contains all functions that cannot change return type;
118+
FuncSet FrozenRetTyFunctions;
116119

117120
using UseVector = SmallVector<RetOrArg, 5>;
118121

@@ -131,12 +134,13 @@ class DeadArgumentEliminationPass
131134
void markValue(const RetOrArg &RA, Liveness L,
132135
const UseVector &MaybeLiveUses);
133136
void markLive(const RetOrArg &RA);
134-
void markLive(const Function &F);
137+
void markFrozen(const Function &F);
138+
void markRetTyFrozen(const Function &F);
139+
bool markFnOrRetTyFrozenOnMusttail(const Function &F);
135140
void propagateLiveness(const RetOrArg &RA);
136141
bool removeDeadStuffFromFunction(Function *F);
137142
bool deleteDeadVarargs(Function &F);
138143
bool removeDeadArgumentsFromCallers(Function &F);
139-
void propagateVirtMustcallLiveness(const Module &M);
140144
};
141145

142146
} // end namespace llvm

llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp

Lines changed: 47 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ class DAE : public ModulePass {
8787
virtual bool shouldHackArguments() const { return false; }
8888
};
8989

90-
bool isMustTailCalleeAnalyzable(const CallBase &CB) {
91-
assert(CB.isMustTailCall());
92-
return CB.getCalledFunction() && !CB.getCalledFunction()->isDeclaration();
93-
}
94-
9590
} // end anonymous namespace
9691

9792
char DAE::ID = 0;
@@ -280,7 +275,7 @@ bool DeadArgumentEliminationPass::removeDeadArgumentsFromCallers(Function &F) {
280275
// they are fully alive (e.g., called indirectly) and except for the fragile
281276
// (variadic) ones. In these cases, we may still be able to improve their
282277
// statically known call sites.
283-
if ((F.hasLocalLinkage() && !LiveFunctions.count(&F)) &&
278+
if ((F.hasLocalLinkage() && !FrozenFunctions.count(&F)) &&
284279
!F.getFunctionType()->isVarArg())
285280
return false;
286281

@@ -496,15 +491,15 @@ void DeadArgumentEliminationPass::surveyFunction(const Function &F) {
496491
// particular register and memory layout.
497492
if (F.getAttributes().hasAttrSomewhere(Attribute::InAlloca) ||
498493
F.getAttributes().hasAttrSomewhere(Attribute::Preallocated)) {
499-
markLive(F);
494+
markFrozen(F);
500495
return;
501496
}
502497

503498
// Don't touch naked functions. The assembly might be using an argument, or
504499
// otherwise rely on the frame layout in a way that this analysis will not
505500
// see.
506501
if (F.hasFnAttribute(Attribute::Naked)) {
507-
markLive(F);
502+
markFrozen(F);
508503
return;
509504
}
510505

@@ -522,29 +517,17 @@ void DeadArgumentEliminationPass::surveyFunction(const Function &F) {
522517
// MaybeLive. Initialized to a list of RetCount empty lists.
523518
RetUses MaybeLiveRetUses(RetCount);
524519

525-
bool HasMustTailCalls = false;
526520
for (const BasicBlock &BB : F) {
527-
// If we have any returns of `musttail` results - the signature can't
528-
// change
529-
if (const auto *TC = BB.getTerminatingMustTailCall()) {
530-
HasMustTailCalls = true;
531-
// In addition, if the called function is not locally defined (or unknown,
532-
// if this is an indirect call), we can't change the callsite and thus
533-
// can't change this function's signature either.
534-
if (!isMustTailCalleeAnalyzable(*TC)) {
535-
markLive(F);
521+
if (BB.getTerminatingMustTailCall()) {
522+
LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - " << F.getName()
523+
<< " has musttail calls\n");
524+
if (markFnOrRetTyFrozenOnMusttail(F))
536525
return;
537-
}
538526
}
539527
}
540528

541-
if (HasMustTailCalls) {
542-
LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - " << F.getName()
543-
<< " has musttail calls\n");
544-
}
545-
546529
if (!F.hasLocalLinkage() && (!ShouldHackArguments || F.isIntrinsic())) {
547-
markLive(F);
530+
markFrozen(F);
548531
return;
549532
}
550533

@@ -555,23 +538,23 @@ void DeadArgumentEliminationPass::surveyFunction(const Function &F) {
555538
// of them turn out to be live.
556539
unsigned NumLiveRetVals = 0;
557540

558-
bool HasMustTailCallers = false;
559-
560541
// Loop all uses of the function.
561542
for (const Use &U : F.uses()) {
562543
// If the function is PASSED IN as an argument, its address has been
563544
// taken.
564545
const auto *CB = dyn_cast<CallBase>(U.getUser());
565546
if (!CB || !CB->isCallee(&U) ||
566547
CB->getFunctionType() != F.getFunctionType()) {
567-
markLive(F);
548+
markFrozen(F);
568549
return;
569550
}
570551

571-
// The number of arguments for `musttail` call must match the number of
572-
// arguments of the caller
573-
if (CB->isMustTailCall())
574-
HasMustTailCallers = true;
552+
if (CB->isMustTailCall()) {
553+
LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - " << F.getName()
554+
<< " has musttail callers\n");
555+
if (markFnOrRetTyFrozenOnMusttail(F))
556+
return;
557+
}
575558

576559
// If we end up here, we are looking at a direct call to our function.
577560

@@ -610,11 +593,6 @@ void DeadArgumentEliminationPass::surveyFunction(const Function &F) {
610593
}
611594
}
612595

613-
if (HasMustTailCallers) {
614-
LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - " << F.getName()
615-
<< " has musttail callers\n");
616-
}
617-
618596
// Now we've inspected all callers, record the liveness of our return values.
619597
for (unsigned Ri = 0; Ri != RetCount; ++Ri)
620598
markValue(createRet(&F, Ri), RetValLiveness[Ri], MaybeLiveRetUses[Ri]);
@@ -628,19 +606,12 @@ void DeadArgumentEliminationPass::surveyFunction(const Function &F) {
628606
for (Function::const_arg_iterator AI = F.arg_begin(), E = F.arg_end();
629607
AI != E; ++AI, ++ArgI) {
630608
Liveness Result;
631-
if (F.getFunctionType()->isVarArg() || HasMustTailCallers ||
632-
HasMustTailCalls) {
609+
if (F.getFunctionType()->isVarArg()) {
633610
// Variadic functions will already have a va_arg function expanded inside
634611
// them, making them potentially very sensitive to ABI changes resulting
635612
// from removing arguments entirely, so don't. For example AArch64 handles
636613
// register and stack HFAs very differently, and this is reflected in the
637614
// IR which has already been generated.
638-
//
639-
// `musttail` calls to this function restrict argument removal attempts.
640-
// The signature of the caller must match the signature of the function.
641-
//
642-
// `musttail` calls in this function prevents us from changing its
643-
// signature
644615
Result = Live;
645616
} else {
646617
// See what the effect of this use is (recording any uses that cause
@@ -680,14 +651,30 @@ void DeadArgumentEliminationPass::markValue(const RetOrArg &RA, Liveness L,
680651
}
681652
}
682653

654+
/// Return true if we freeze the whole function.
655+
/// If the calling convention is not swifttailcc or tailcc, the caller and
656+
/// callee of musttail must have exactly the same signature. Otherwise we
657+
/// only needs to guarantee they have the same return type.
658+
bool DeadArgumentEliminationPass::markFnOrRetTyFrozenOnMusttail(
659+
const Function &F) {
660+
if (F.getCallingConv() != CallingConv::SwiftTail ||
661+
F.getCallingConv() != CallingConv::Tail) {
662+
markFrozen(F);
663+
return true;
664+
} else {
665+
markRetTyFrozen(F);
666+
return false;
667+
}
668+
}
669+
683670
/// Mark the given Function as alive, meaning that it cannot be changed in any
684671
/// way. Additionally, mark any values that are used as this function's
685672
/// parameters or by its return values (according to Uses) live as well.
686-
void DeadArgumentEliminationPass::markLive(const Function &F) {
687-
LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - Intrinsically live fn: "
673+
void DeadArgumentEliminationPass::markFrozen(const Function &F) {
674+
LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - frozen fn: "
688675
<< F.getName() << "\n");
689-
// Mark the function as live.
690-
LiveFunctions.insert(&F);
676+
// Mark the function as frozen.
677+
FrozenFunctions.insert(&F);
691678
// Mark all arguments as live.
692679
for (unsigned ArgI = 0, E = F.arg_size(); ArgI != E; ++ArgI)
693680
propagateLiveness(createArg(&F, ArgI));
@@ -696,6 +683,12 @@ void DeadArgumentEliminationPass::markLive(const Function &F) {
696683
propagateLiveness(createRet(&F, Ri));
697684
}
698685

686+
void DeadArgumentEliminationPass::markRetTyFrozen(const Function &F) {
687+
LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - frozen return type fn: "
688+
<< F.getName() << "\n");
689+
FrozenRetTyFunctions.insert(&F);
690+
}
691+
699692
/// Mark the given return value or argument as live. Additionally, mark any
700693
/// values that are used by this value (according to Uses) live as well.
701694
void DeadArgumentEliminationPass::markLive(const RetOrArg &RA) {
@@ -710,7 +703,7 @@ void DeadArgumentEliminationPass::markLive(const RetOrArg &RA) {
710703
}
711704

712705
bool DeadArgumentEliminationPass::isLive(const RetOrArg &RA) {
713-
return LiveFunctions.count(RA.F) || LiveValues.count(RA);
706+
return FrozenFunctions.count(RA.F) || LiveValues.count(RA);
714707
}
715708

716709
/// Given that RA is a live value, propagate it's liveness to any other values
@@ -734,8 +727,8 @@ void DeadArgumentEliminationPass::propagateLiveness(const RetOrArg &RA) {
734727
/// Transform the function and all the callees of the function to not have these
735728
/// arguments and return values.
736729
bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
737-
// Don't modify fully live functions
738-
if (LiveFunctions.count(F))
730+
// Don't modify frozen functions
731+
if (FrozenFunctions.count(F))
739732
return false;
740733

741734
// Start by computing a new prototype for the function, which is the same as
@@ -807,7 +800,8 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
807800
// performance win, so the second option can just be used always for now.
808801
//
809802
// This should be revisited if 'returned' is ever applied more liberally.
810-
if (RetTy->isVoidTy() || HasLiveReturnedArg) {
803+
if (RetTy->isVoidTy() || HasLiveReturnedArg ||
804+
FrozenRetTyFunctions.count(F)) {
811805
NRetTy = RetTy;
812806
} else {
813807
// Look at each of the original return values individually.
@@ -1109,26 +1103,6 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
11091103
return true;
11101104
}
11111105

1112-
void DeadArgumentEliminationPass::propagateVirtMustcallLiveness(
1113-
const Module &M) {
1114-
// If a function was marked "live", and it has musttail callers, they in turn
1115-
// can't change either.
1116-
LiveFuncSet NewLiveFuncs(LiveFunctions);
1117-
while (!NewLiveFuncs.empty()) {
1118-
LiveFuncSet Temp;
1119-
for (const auto *F : NewLiveFuncs)
1120-
for (const auto *U : F->users())
1121-
if (const auto *CB = dyn_cast<CallBase>(U))
1122-
if (CB->isMustTailCall())
1123-
if (!LiveFunctions.count(CB->getParent()->getParent()))
1124-
Temp.insert(CB->getParent()->getParent());
1125-
NewLiveFuncs.clear();
1126-
NewLiveFuncs.insert(Temp.begin(), Temp.end());
1127-
for (const auto *F : Temp)
1128-
markLive(*F);
1129-
}
1130-
}
1131-
11321106
PreservedAnalyses DeadArgumentEliminationPass::run(Module &M,
11331107
ModuleAnalysisManager &) {
11341108
bool Changed = false;
@@ -1149,8 +1123,6 @@ PreservedAnalyses DeadArgumentEliminationPass::run(Module &M,
11491123
for (auto &F : M)
11501124
surveyFunction(F);
11511125

1152-
propagateVirtMustcallLiveness(M);
1153-
11541126
// Now, remove all dead arguments and return values from each function in
11551127
// turn. We use make_early_inc_range here because functions will probably get
11561128
// removed (i.e. replaced by new ones).
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
12
; RUN: opt -passes=deadargelim -S < %s | FileCheck %s
23
; PR36441
34
; Dead arguments should not be removed in presence of `musttail` calls.
45

5-
; CHECK-LABEL: define internal void @test(i32 %a, i32 %b)
6-
; CHECK: musttail call void @foo(i32 %a, i32 0)
7-
; FIXME: we should replace those with `undef`s
86
define internal void @test(i32 %a, i32 %b) {
7+
; CHECK-LABEL: define internal void @test(
8+
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
9+
; CHECK-NEXT: musttail call void @foo(i32 poison, i32 poison)
10+
; CHECK-NEXT: ret void
11+
;
912
musttail call void @foo(i32 %a, i32 0)
1013
ret void
1114
}
1215

13-
; CHECK-LABEL: define internal void @foo(i32 %a, i32 %b)
1416
define internal void @foo(i32 %a, i32 %b) {
17+
; CHECK-LABEL: define internal void @foo(
18+
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
19+
; CHECK-NEXT: ret void
20+
;
1521
ret void
1622
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; Testcases comes from PR126817 and PR107569
3+
; See PR54964 and langref for more information about how llvm deal with musttail currently
4+
; RUN: opt -passes=deadargelim -S < %s | FileCheck %s
5+
6+
define i64 @A() {
7+
; CHECK-LABEL: define i64 @A() {
8+
; CHECK-NEXT: [[ENTRY:.*:]]
9+
; CHECK-NEXT: [[V2660:%.*]] = musttail call i64 @B()
10+
; CHECK-NEXT: ret i64 [[V2660]]
11+
;
12+
entry:
13+
%v2660 = musttail call i64 @B()
14+
ret i64 %v2660
15+
}
16+
17+
define internal i64 @B() {
18+
; CHECK-LABEL: define internal i64 @B() {
19+
; CHECK-NEXT: [[ENTRY:.*:]]
20+
; CHECK-NEXT: ret i64 0
21+
;
22+
entry:
23+
ret i64 0
24+
}
25+
26+
define internal i64 @C() {
27+
; CHECK-LABEL: define internal i64 @C() {
28+
; CHECK-NEXT: [[ENTRY:.*:]]
29+
; CHECK-NEXT: [[V30543:%.*]] = musttail call i64 @B()
30+
; CHECK-NEXT: ret i64 [[V30543]]
31+
;
32+
entry:
33+
%v30543 = musttail call i64 @B()
34+
ret i64 %v30543
35+
}
36+
37+
%struct.S = type { double }
38+
39+
define internal %struct.S @F38() {
40+
; CHECK-LABEL: define internal %struct.S @F38() {
41+
; CHECK-NEXT: ret [[STRUCT_S:%.*]] zeroinitializer
42+
;
43+
ret %struct.S { double 0.0 }
44+
}
45+
46+
define internal %struct.S @F36() {
47+
; CHECK-LABEL: define internal %struct.S @F36() {
48+
; CHECK-NEXT: [[TMP1:%.*]] = alloca [[STRUCT_S:%.*]], align 8
49+
; CHECK-NEXT: [[TMP2:%.*]] = musttail call [[STRUCT_S]] @[[F38:[a-zA-Z0-9_$\"\\.-]*[a-zA-Z_$\"\\.-][a-zA-Z0-9_$\"\\.-]*]]()
50+
; CHECK-NEXT: ret [[STRUCT_S]] [[TMP2]]
51+
;
52+
%1 = alloca %struct.S, align 8
53+
%3 = musttail call %struct.S @F38()
54+
ret %struct.S %3
55+
}
56+
57+
define double @foo() {
58+
; CHECK-LABEL: define double @foo() {
59+
; CHECK-NEXT: [[TMP1:%.*]] = call [[STRUCT_S:%.*]] @[[F36:[a-zA-Z0-9_$\"\\.-]*[a-zA-Z_$\"\\.-][a-zA-Z0-9_$\"\\.-]*]]()
60+
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue [[STRUCT_S]] [[TMP1]], 0
61+
; CHECK-NEXT: ret double [[TMP2]]
62+
;
63+
%3 = call %struct.S @F36()
64+
%5 = extractvalue %struct.S %3, 0
65+
ret double %5
66+
}

0 commit comments

Comments
 (0)