Skip to content

Commit 73a836a

Browse files
authored
[Attributor] Look through indirect calls (#65197)
Through the new `Attributor::checkForAllCallees` we can look through indirect calls and visit all potential callees if they are known. Most AAs will do that implicitly now via `AACalleeToCallSite`, thus, most AAs are able to deal with missing callees for call site IR positions. Differential Revision: https://reviews.llvm.org/D112290
1 parent a560d21 commit 73a836a

File tree

6 files changed

+124
-113
lines changed

6 files changed

+124
-113
lines changed

llvm/include/llvm/Transforms/IPO/Attributor.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,6 +2125,15 @@ struct Attributor {
21252125
const AAIsDead *FnLivenessAA,
21262126
DepClassTy DepClass = DepClassTy::OPTIONAL);
21272127

2128+
/// Check \p Pred on all potential Callees of \p CB.
2129+
///
2130+
/// This method will evaluate \p Pred with all potential callees of \p CB as
2131+
/// input and return true if \p Pred does. If some callees might be unknown
2132+
/// this function will return false.
2133+
bool checkForAllCallees(
2134+
function_ref<bool(ArrayRef<const Function *> Callees)> Pred,
2135+
const AbstractAttribute &QueryingAA, const CallBase &CB);
2136+
21282137
/// Check \p Pred on all (transitive) uses of \p V.
21292138
///
21302139
/// This method will evaluate \p Pred on all (transitive) uses of the
@@ -3295,7 +3304,7 @@ struct AbstractAttribute : public IRPosition, public AADepGraphNode {
32953304

32963305
/// Return true if this AA requires a "callee" (or an associted function) for
32973306
/// a call site positon. Default is optimistic to minimize AAs.
3298-
static bool requiresCalleeForCallBase() { return true; }
3307+
static bool requiresCalleeForCallBase() { return false; }
32993308

33003309
/// Return true if this AA requires non-asm "callee" for a call site positon.
33013310
static bool requiresNonAsmForCallBase() { return true; }
@@ -3852,9 +3861,6 @@ struct AANoAlias
38523861
Attribute::AttrKind ImpliedAttributeKind,
38533862
bool IgnoreSubsumingPositions = false);
38543863

3855-
/// See AbstractAttribute::requiresCalleeForCallBase
3856-
static bool requiresCalleeForCallBase() { return false; }
3857-
38583864
/// See AbstractAttribute::requiresCallersForArgOrFunction
38593865
static bool requiresCallersForArgOrFunction() { return true; }
38603866

@@ -4699,6 +4705,9 @@ struct AAMemoryLocation
46994705

47004706
AAMemoryLocation(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}
47014707

4708+
/// See AbstractAttribute::requiresCalleeForCallBase.
4709+
static bool requiresCalleeForCallBase() { return true; }
4710+
47024711
/// See AbstractAttribute::hasTrivialInitializer.
47034712
static bool hasTrivialInitializer() { return false; }
47044713

@@ -5481,10 +5490,6 @@ struct AACallEdges : public StateWrapper<BooleanState, AbstractAttribute>,
54815490
AACallEdges(const IRPosition &IRP, Attributor &A)
54825491
: Base(IRP), AACallGraphNode(A) {}
54835492

5484-
/// The callee value is tracked beyond a simple stripPointerCasts, so we allow
5485-
/// unknown callees.
5486-
static bool requiresCalleeForCallBase() { return false; }
5487-
54885493
/// See AbstractAttribute::requiresNonAsmForCallBase.
54895494
static bool requiresNonAsmForCallBase() { return false; }
54905495

@@ -6310,9 +6315,6 @@ struct AAIndirectCallInfo
63106315
AAIndirectCallInfo(const IRPosition &IRP, Attributor &A)
63116316
: StateWrapper<BooleanState, AbstractAttribute>(IRP) {}
63126317

6313-
/// The point is to derive callees, after all.
6314-
static bool requiresCalleeForCallBase() { return false; }
6315-
63166318
/// See AbstractAttribute::isValidIRPositionForInit
63176319
static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
63186320
if (IRP.getPositionKind() != IRPosition::IRP_CALL_SITE)

llvm/lib/Transforms/IPO/Attributor.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,21 @@ bool Attributor::isAssumedDead(const BasicBlock &BB,
17331733
return false;
17341734
}
17351735

1736+
bool Attributor::checkForAllCallees(
1737+
function_ref<bool(ArrayRef<const Function *>)> Pred,
1738+
const AbstractAttribute &QueryingAA, const CallBase &CB) {
1739+
if (const Function *Callee = dyn_cast<Function>(CB.getCalledOperand()))
1740+
return Pred(Callee);
1741+
1742+
const auto *CallEdgesAA = getAAFor<AACallEdges>(
1743+
QueryingAA, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL);
1744+
if (!CallEdgesAA || CallEdgesAA->hasUnknownCallee())
1745+
return false;
1746+
1747+
const auto &Callees = CallEdgesAA->getOptimisticEdges();
1748+
return Pred(Callees.getArrayRef());
1749+
}
1750+
17361751
bool Attributor::checkForAllUses(
17371752
function_ref<bool(const Use &, bool &)> Pred,
17381753
const AbstractAttribute &QueryingAA, const Value &V,

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -604,36 +604,42 @@ struct AACalleeToCallSite : public BaseType {
604604
"returned positions!");
605605
auto &S = this->getState();
606606

607-
const Function *AssociatedFunction =
608-
this->getIRPosition().getAssociatedFunction();
609-
if (!AssociatedFunction)
610-
return S.indicatePessimisticFixpoint();
611-
612607
CallBase &CB = cast<CallBase>(this->getAnchorValue());
613608
if (IntroduceCallBaseContext)
614609
LLVM_DEBUG(dbgs() << "[Attributor] Introducing call base context:" << CB
615610
<< "\n");
616611

617-
IRPosition FnPos =
618-
IRPKind == llvm::IRPosition::IRP_CALL_SITE_RETURNED
619-
? IRPosition::returned(*AssociatedFunction,
620-
IntroduceCallBaseContext ? &CB : nullptr)
621-
: IRPosition::function(*AssociatedFunction,
622-
IntroduceCallBaseContext ? &CB : nullptr);
623-
624-
// If possible, use the hasAssumedIRAttr interface.
625-
if (Attribute::isEnumAttrKind(IRAttributeKind)) {
626-
bool IsKnown;
627-
if (!AA::hasAssumedIRAttr<IRAttributeKind>(A, this, FnPos,
628-
DepClassTy::REQUIRED, IsKnown))
629-
return S.indicatePessimisticFixpoint();
630-
return ChangeStatus::UNCHANGED;
631-
}
612+
ChangeStatus Changed = ChangeStatus::UNCHANGED;
613+
auto CalleePred = [&](ArrayRef<const Function *> Callees) {
614+
for (const Function *Callee : Callees) {
615+
IRPosition FnPos =
616+
IRPKind == llvm::IRPosition::IRP_CALL_SITE_RETURNED
617+
? IRPosition::returned(*Callee,
618+
IntroduceCallBaseContext ? &CB : nullptr)
619+
: IRPosition::function(
620+
*Callee, IntroduceCallBaseContext ? &CB : nullptr);
621+
// If possible, use the hasAssumedIRAttr interface.
622+
if (Attribute::isEnumAttrKind(IRAttributeKind)) {
623+
bool IsKnown;
624+
if (!AA::hasAssumedIRAttr<IRAttributeKind>(
625+
A, this, FnPos, DepClassTy::REQUIRED, IsKnown))
626+
return false;
627+
continue;
628+
}
632629

633-
const AAType *AA = A.getAAFor<AAType>(*this, FnPos, DepClassTy::REQUIRED);
634-
if (!AA)
630+
const AAType *AA =
631+
A.getAAFor<AAType>(*this, FnPos, DepClassTy::REQUIRED);
632+
if (!AA)
633+
return false;
634+
Changed |= clampStateAndIndicateChange(S, AA->getState());
635+
if (S.isAtFixpoint())
636+
return S.isValidState();
637+
}
638+
return true;
639+
};
640+
if (!A.checkForAllCallees(CalleePred, *this, CB))
635641
return S.indicatePessimisticFixpoint();
636-
return clampStateAndIndicateChange(S, AA->getState());
642+
return Changed;
637643
}
638644
};
639645

llvm/test/Transforms/Attributor/liveness.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,12 +2359,12 @@ define void @call_via_pointer_with_dead_args(ptr %a, ptr %b, ptr %fp) {
23592359
define internal void @call_via_pointer_with_dead_args_internal_a(ptr %a, ptr %b, ptr %fp) {
23602360
; TUNIT-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a
23612361
; TUNIT-SAME: (ptr [[A:%.*]], ptr noundef nonnull align 128 dereferenceable(4) [[B:%.*]]) {
2362-
; TUNIT-NEXT: call void @called_via_pointer(ptr [[A]], ptr [[B]], ptr [[A]], i64 -1, ptr null)
2362+
; TUNIT-NEXT: call void @called_via_pointer(ptr [[A]], ptr nonnull align 128 dereferenceable(4) [[B]], ptr [[A]], i64 -1, ptr null)
23632363
; TUNIT-NEXT: ret void
23642364
;
23652365
; CGSCC-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a
23662366
; CGSCC-SAME: (ptr [[A:%.*]], ptr noundef nonnull align 128 dereferenceable(4) [[B:%.*]]) {
2367-
; CGSCC-NEXT: call void @called_via_pointer(ptr [[A]], ptr nocapture nofree noundef nonnull [[B]], ptr nocapture nofree [[A]], i64 noundef -1, ptr nofree noundef null)
2367+
; CGSCC-NEXT: call void @called_via_pointer(ptr [[A]], ptr nocapture nofree noundef nonnull align 128 dereferenceable(4) [[B]], ptr nocapture nofree [[A]], i64 noundef -1, ptr nofree noundef null)
23682368
; CGSCC-NEXT: ret void
23692369
;
23702370
call void %fp(ptr %a, ptr %b, ptr %a, i64 -1, ptr null)
@@ -2373,7 +2373,7 @@ define internal void @call_via_pointer_with_dead_args_internal_a(ptr %a, ptr %b,
23732373
define internal void @call_via_pointer_with_dead_args_internal_b(ptr %a, ptr %b, ptr %fp) {
23742374
; TUNIT-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b
23752375
; TUNIT-SAME: (ptr [[A:%.*]], ptr noundef nonnull align 128 dereferenceable(4) [[B:%.*]]) {
2376-
; TUNIT-NEXT: call void @called_via_pointer_internal_2(ptr [[A]], ptr [[B]], ptr [[A]], i64 -1, ptr null)
2376+
; TUNIT-NEXT: call void @called_via_pointer_internal_2(ptr [[A]], ptr nonnull align 128 dereferenceable(4) [[B]], ptr [[A]], i64 -1, ptr null)
23772377
; TUNIT-NEXT: ret void
23782378
;
23792379
; CGSCC-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b

llvm/test/Transforms/Attributor/nounwind.ll

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -151,27 +151,14 @@ define i32 @catch_thing_user() {
151151
}
152152

153153
define void @two_potential_callees_pos1(i1 %c) {
154-
; TUNIT: Function Attrs: norecurse
154+
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
155155
; TUNIT-LABEL: define {{[^@]+}}@two_potential_callees_pos1
156-
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR3:[0-9]+]] {
157-
; TUNIT-NEXT: [[FP:%.*]] = select i1 [[C]], ptr @foo1, ptr @scc1_foo
158-
; TUNIT-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @scc1_foo
159-
; TUNIT-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
160-
; TUNIT: 2:
161-
; TUNIT-NEXT: call void @scc1_foo()
162-
; TUNIT-NEXT: br label [[TMP6:%.*]]
163-
; TUNIT: 3:
164-
; TUNIT-NEXT: br i1 true, label [[TMP4:%.*]], label [[TMP5:%.*]]
165-
; TUNIT: 4:
166-
; TUNIT-NEXT: call void @foo1()
167-
; TUNIT-NEXT: br label [[TMP6]]
168-
; TUNIT: 5:
169-
; TUNIT-NEXT: unreachable
170-
; TUNIT: 6:
156+
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
171157
; TUNIT-NEXT: ret void
172158
;
159+
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
173160
; CGSCC-LABEL: define {{[^@]+}}@two_potential_callees_pos1
174-
; CGSCC-SAME: (i1 [[C:%.*]]) {
161+
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
175162
; CGSCC-NEXT: [[FP:%.*]] = select i1 [[C]], ptr @foo1, ptr @scc1_foo
176163
; CGSCC-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @scc1_foo
177164
; CGSCC-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
@@ -193,8 +180,9 @@ define void @two_potential_callees_pos1(i1 %c) {
193180
ret void
194181
}
195182
define void @two_potential_callees_pos2(i1 %c) {
183+
; CHECK: Function Attrs: nounwind
196184
; CHECK-LABEL: define {{[^@]+}}@two_potential_callees_pos2
197-
; CHECK-SAME: (i1 [[C:%.*]]) {
185+
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
198186
; CHECK-NEXT: [[FP:%.*]] = select i1 [[C]], ptr @foo2, ptr @scc1_foo
199187
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @scc1_foo
200188
; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
@@ -248,8 +236,8 @@ declare void @__cxa_end_catch()
248236
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
249237
; TUNIT: attributes #[[ATTR1]] = { nounwind }
250238
; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
251-
; TUNIT: attributes #[[ATTR3]] = { norecurse }
252239
;.
253240
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
254241
; CGSCC: attributes #[[ATTR1]] = { nounwind }
242+
; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn }
255243
;.

0 commit comments

Comments
 (0)