Skip to content

Commit 6f0ca01

Browse files
committed
[Attributor] Introduce AAGlobalValueInfo to track global value uses
GlobalValues are often interesting, especially if they have local linkage. We now track all uses of those and refine potential callees with it. Effectively, if an internal function cannot reach an indirect call site, it cannot be a potential callee, even if it has its address taken.
1 parent 498887a commit 6f0ca01

File tree

3 files changed

+269
-24
lines changed

3 files changed

+269
-24
lines changed

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
#include "llvm/IR/Attributes.h"
119119
#include "llvm/IR/ConstantRange.h"
120120
#include "llvm/IR/Constants.h"
121+
#include "llvm/IR/GlobalValue.h"
121122
#include "llvm/IR/InstIterator.h"
122123
#include "llvm/IR/Instruction.h"
123124
#include "llvm/IR/Instructions.h"
@@ -3948,6 +3949,14 @@ struct AAIsDead
39483949
using Base = StateWrapper<BitIntegerState<uint8_t, 3, 0>, AbstractAttribute>;
39493950
AAIsDead(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
39503951

3952+
/// See AbstractAttribute::isValidIRPositionForInit
3953+
static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
3954+
if (IRP.getPositionKind() == IRPosition::IRP_FUNCTION)
3955+
return isa<Function>(IRP.getAnchorValue()) &&
3956+
!cast<Function>(IRP.getAnchorValue()).isDeclaration();
3957+
return true;
3958+
}
3959+
39513960
/// State encoding bits. A set bit in the state means the property holds.
39523961
enum {
39533962
HAS_NO_EFFECT = 1 << 0,
@@ -6139,6 +6148,45 @@ struct AAAddressSpace : public StateWrapper<BooleanState, AbstractAttribute> {
61396148
static const char ID;
61406149
};
61416150

6151+
/// An abstract interface for llvm::GlobalValue information interference.
6152+
struct AAGlobalValueInfo
6153+
: public StateWrapper<BooleanState, AbstractAttribute> {
6154+
AAGlobalValueInfo(const IRPosition &IRP, Attributor &A)
6155+
: StateWrapper<BooleanState, AbstractAttribute>(IRP) {}
6156+
6157+
/// See AbstractAttribute::isValidIRPositionForInit
6158+
static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) {
6159+
if (IRP.getPositionKind() != IRPosition::IRP_FLOAT)
6160+
return false;
6161+
auto *GV = dyn_cast<GlobalValue>(&IRP.getAnchorValue());
6162+
if (!GV)
6163+
return false;
6164+
return GV->hasLocalLinkage();
6165+
}
6166+
6167+
/// Create an abstract attribute view for the position \p IRP.
6168+
static AAGlobalValueInfo &createForPosition(const IRPosition &IRP,
6169+
Attributor &A);
6170+
6171+
/// Return true iff \p U is a potential use of the associated global value.
6172+
virtual bool isPotentialUse(const Use &U) const = 0;
6173+
6174+
/// See AbstractAttribute::getName()
6175+
const std::string getName() const override { return "AAGlobalValueInfo"; }
6176+
6177+
/// See AbstractAttribute::getIdAddr()
6178+
const char *getIdAddr() const override { return &ID; }
6179+
6180+
/// This function should return true if the type of the \p AA is
6181+
/// AAGlobalValueInfo
6182+
static bool classof(const AbstractAttribute *AA) {
6183+
return (AA->getIdAddr() == &ID);
6184+
}
6185+
6186+
/// Unique ID (due to the unique address)
6187+
static const char ID;
6188+
};
6189+
61426190
/// An abstract interface for indirect call information interference.
61436191
struct AAIndirectCallInfo
61446192
: public StateWrapper<BooleanState, AbstractAttribute> {

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 163 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ PIPE_OPERATOR(AAAssumptionInfo)
193193
PIPE_OPERATOR(AAUnderlyingObjects)
194194
PIPE_OPERATOR(AAAddressSpace)
195195
PIPE_OPERATOR(AAIndirectCallInfo)
196+
PIPE_OPERATOR(AAGlobalValueInfo)
196197

197198
#undef PIPE_OPERATOR
198199

@@ -12056,6 +12057,134 @@ struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
1205612057
};
1205712058
} // namespace
1205812059

12060+
/// ------------------------ Global Value Info -------------------------------
12061+
namespace {
12062+
struct AAGlobalValueInfoFloating : public AAGlobalValueInfo {
12063+
AAGlobalValueInfoFloating(const IRPosition &IRP, Attributor &A)
12064+
: AAGlobalValueInfo(IRP, A) {}
12065+
12066+
/// See AbstractAttribute::initialize(...).
12067+
void initialize(Attributor &A) override {}
12068+
12069+
bool checkUse(Attributor &A, const Use &U, bool &Follow,
12070+
SmallVectorImpl<const Value *> &Worklist) {
12071+
Instruction *UInst = dyn_cast<Instruction>(U.getUser());
12072+
if (!UInst) {
12073+
Follow = true;
12074+
return true;
12075+
}
12076+
12077+
LLVM_DEBUG(dbgs() << "[AAGlobalValueInfo] Check use: " << *U.get() << " in "
12078+
<< *UInst << "\n");
12079+
12080+
if (auto *Cmp = dyn_cast<ICmpInst>(U.getUser())) {
12081+
int Idx = &Cmp->getOperandUse(0) == &U;
12082+
if (isa<Constant>(Cmp->getOperand(Idx)))
12083+
return true;
12084+
return U == &getAnchorValue();
12085+
}
12086+
12087+
// Explicitly catch return instructions.
12088+
if (isa<ReturnInst>(UInst)) {
12089+
auto CallSitePred = [&](AbstractCallSite ACS) {
12090+
Worklist.push_back(ACS.getInstruction());
12091+
return true;
12092+
};
12093+
bool UsedAssumedInformation = false;
12094+
// TODO: We should traverse the uses or add a "non-call-site" CB.
12095+
if (!A.checkForAllCallSites(CallSitePred, *UInst->getFunction(),
12096+
/*RequireAllCallSites=*/true, this,
12097+
UsedAssumedInformation))
12098+
return false;
12099+
return true;
12100+
}
12101+
12102+
// For now we only use special logic for call sites. However, the tracker
12103+
// itself knows about a lot of other non-capturing cases already.
12104+
auto *CB = dyn_cast<CallBase>(UInst);
12105+
if (!CB)
12106+
return false;
12107+
// Direct calls are OK uses.
12108+
if (CB->isCallee(&U))
12109+
return true;
12110+
// Non-argument uses are scary.
12111+
if (!CB->isArgOperand(&U))
12112+
return false;
12113+
// TODO: Iterate callees.
12114+
auto *Fn = dyn_cast<Function>(CB->getCalledOperand());
12115+
if (!Fn || !A.isFunctionIPOAmendable(*Fn))
12116+
return false;
12117+
12118+
unsigned ArgNo = CB->getArgOperandNo(&U);
12119+
Worklist.push_back(Fn->getArg(ArgNo));
12120+
return true;
12121+
}
12122+
12123+
ChangeStatus updateImpl(Attributor &A) override {
12124+
unsigned NumUsesBefore = Uses.size();
12125+
12126+
SmallPtrSet<const Value *, 8> Visited;
12127+
SmallVector<const Value *> Worklist;
12128+
Worklist.push_back(&getAnchorValue());
12129+
12130+
auto UsePred = [&](const Use &U, bool &Follow) -> bool {
12131+
Uses.insert(&U);
12132+
switch (DetermineUseCaptureKind(U, nullptr)) {
12133+
case UseCaptureKind::NO_CAPTURE:
12134+
return checkUse(A, U, Follow, Worklist);
12135+
case UseCaptureKind::MAY_CAPTURE:
12136+
return checkUse(A, U, Follow, Worklist);
12137+
case UseCaptureKind::PASSTHROUGH:
12138+
Follow = true;
12139+
return true;
12140+
}
12141+
return true;
12142+
};
12143+
auto EquivalentUseCB = [&](const Use &OldU, const Use &NewU) {
12144+
Uses.insert(&OldU);
12145+
return true;
12146+
};
12147+
12148+
while (!Worklist.empty()) {
12149+
const Value *V = Worklist.pop_back_val();
12150+
if (!Visited.insert(V).second)
12151+
continue;
12152+
if (!A.checkForAllUses(UsePred, *this, *V,
12153+
/* CheckBBLivenessOnly */ true,
12154+
DepClassTy::OPTIONAL,
12155+
/* IgnoreDroppableUses */ true, EquivalentUseCB)) {
12156+
return indicatePessimisticFixpoint();
12157+
}
12158+
}
12159+
12160+
return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12161+
: ChangeStatus::CHANGED;
12162+
}
12163+
12164+
bool isPotentialUse(const Use &U) const override {
12165+
return !isValidState() || Uses.contains(&U);
12166+
}
12167+
12168+
/// See AbstractAttribute::manifest(...).
12169+
ChangeStatus manifest(Attributor &A) override {
12170+
return ChangeStatus::UNCHANGED;
12171+
}
12172+
12173+
/// See AbstractAttribute::getAsStr().
12174+
const std::string getAsStr(Attributor *A) const override {
12175+
return "[" + std::to_string(Uses.size()) + " uses]";
12176+
}
12177+
12178+
void trackStatistics() const override {
12179+
STATS_DECLTRACK_FLOATING_ATTR(GlobalValuesTracked);
12180+
}
12181+
12182+
private:
12183+
/// Set of (transitive) uses of this GlobalValue.
12184+
SmallPtrSet<const Use *, 8> Uses;
12185+
};
12186+
} // namespace
12187+
1205912188
/// ------------------------ Indirect Call Info -------------------------------
1206012189
namespace {
1206112190
struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
@@ -12085,11 +12214,30 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
1208512214

1208612215
ChangeStatus updateImpl(Attributor &A) override {
1208712216
CallBase *CB = cast<CallBase>(getCtxI());
12217+
const Use &CalleeUse = CB->getCalledOperandUse();
1208812218
Value *FP = CB->getCalledOperand();
1208912219

1209012220
SmallSetVector<Function *, 4> AssumedCalleesNow;
1209112221
bool AllCalleesKnownNow = AllCalleesKnown;
1209212222

12223+
auto CheckPotentialCalleeUse = [&](Function &PotentialCallee,
12224+
bool &UsedAssumedInformation) {
12225+
const auto *GIAA = A.getAAFor<AAGlobalValueInfo>(
12226+
*this, IRPosition::value(PotentialCallee), DepClassTy::OPTIONAL);
12227+
if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12228+
return true;
12229+
UsedAssumedInformation = !GIAA->isAtFixpoint();
12230+
return false;
12231+
};
12232+
12233+
auto AddPotentialCallees = [&]() {
12234+
for (auto *PotentialCallee : PotentialCallees) {
12235+
bool UsedAssumedInformation = false;
12236+
if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12237+
AssumedCalleesNow.insert(PotentialCallee);
12238+
}
12239+
};
12240+
1209312241
// Use simplification to find potential callees, if !callees was present,
1209412242
// fallback to that set if necessary.
1209512243
bool UsedAssumedInformation = false;
@@ -12099,7 +12247,7 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
1209912247
UsedAssumedInformation)) {
1210012248
if (PotentialCallees.empty())
1210112249
return indicatePessimisticFixpoint();
12102-
AssumedCalleesNow.set_union(PotentialCallees);
12250+
AddPotentialCallees();
1210312251
}
1210412252

1210512253
// Try to find a reason for \p Fn not to be a potential callee. If none was
@@ -12112,6 +12260,13 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
1211212260
if (CachedResult.has_value())
1211312261
return CachedResult.value();
1211412262

12263+
bool UsedAssumedInformation = false;
12264+
if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12265+
if (!UsedAssumedInformation)
12266+
CachedResult = false;
12267+
return false;
12268+
}
12269+
1211512270
int NumFnArgs = Fn.arg_size();
1211612271
int NumCBArgs = CB->arg_size();
1211712272

@@ -12147,16 +12302,12 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
1214712302
continue;
1214812303
}
1214912304
if (!PotentialCallees.empty()) {
12150-
AssumedCalleesNow.set_union(PotentialCallees);
12305+
AddPotentialCallees();
1215112306
break;
1215212307
}
1215312308
AllCalleesKnownNow = false;
1215412309
}
1215512310

12156-
// If we can't specialize at all, give up now.
12157-
if (!AllCalleesKnownNow && AssumedCalleesNow.empty())
12158-
return indicatePessimisticFixpoint();
12159-
1216012311
if (AssumedCalleesNow == AssumedCallees &&
1216112312
AllCalleesKnown == AllCalleesKnownNow)
1216212313
return ChangeStatus::UNCHANGED;
@@ -12168,6 +12319,9 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
1216812319

1216912320
/// See AbstractAttribute::manifest(...).
1217012321
ChangeStatus manifest(Attributor &A) override {
12322+
// If we can't specialize at all, give up now.
12323+
if (!AllCalleesKnown && AssumedCallees.empty())
12324+
return ChangeStatus::UNCHANGED;
1217112325

1217212326
ChangeStatus Changed = ChangeStatus::UNCHANGED;
1217312327
CallBase *CB = cast<CallBase>(getCtxI());
@@ -12550,6 +12704,7 @@ const char AAAssumptionInfo::ID = 0;
1255012704
const char AAUnderlyingObjects::ID = 0;
1255112705
const char AAAddressSpace::ID = 0;
1255212706
const char AAIndirectCallInfo::ID = 0;
12707+
const char AAGlobalValueInfo::ID = 0;
1255312708

1255412709
// Macro magic to create the static generator function for attributes that
1255512710
// follow the naming scheme.
@@ -12688,6 +12843,8 @@ CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUnderlyingObjects)
1268812843

1268912844
CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(IRP_CALL_SITE, CallSite,
1269012845
AAIndirectCallInfo)
12846+
CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(IRP_FLOAT, Floating,
12847+
AAGlobalValueInfo)
1269112848

1269212849
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack)
1269312850
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUndefinedBehavior)

0 commit comments

Comments
 (0)