Skip to content

Commit 498887a

Browse files
committed
[Attributor] Introduce the closed world flag
The Attributor user can now set the closed world flag (`AttributorConfig.IsClosedWorldModule` or `-attributor-assume-closed-world`) in order to specialize call edges based only on available callees. That means, we assume all functions are known and hence all potential callees must be declared/defined in the module. We will use this for GPUs and LTO cases, but for now the user has to set it via a flag.
1 parent 9366610 commit 498887a

File tree

4 files changed

+269
-52
lines changed

4 files changed

+269
-52
lines changed

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,11 @@ struct InformationCache {
13161316
return TargetTriple.isAMDGPU() || TargetTriple.isNVPTX();
13171317
}
13181318

1319+
/// Return all functions that might be called indirectly, only valid for
1320+
/// closed world modules (see isClosedWorldModule).
1321+
const ArrayRef<Function *>
1322+
getIndirectlyCallableFunctions(Attributor &A) const;
1323+
13191324
private:
13201325
struct FunctionInfo {
13211326
~FunctionInfo();
@@ -1348,6 +1353,10 @@ struct InformationCache {
13481353
return *FI;
13491354
}
13501355

1356+
/// Vector of functions that might be callable indirectly, i.a., via a
1357+
/// function pointer.
1358+
SmallVector<Function *> IndirectlyCallableFunctions;
1359+
13511360
/// Initialize the function information cache \p FI for the function \p F.
13521361
///
13531362
/// This method needs to be called for all function that might be looked at
@@ -1413,6 +1422,10 @@ struct AttributorConfig {
14131422
/// Flag to determine if we should skip all liveness checks early on.
14141423
bool UseLiveness = true;
14151424

1425+
/// Flag to indicate if the entire world is contained in this module, that
1426+
/// is, no outside functions exist.
1427+
bool IsClosedWorldModule = false;
1428+
14161429
/// Callback function to be invoked on internal functions marked live.
14171430
std::function<void(Attributor &A, const Function &F)> InitializationCallback =
14181431
nullptr;
@@ -1483,9 +1496,7 @@ struct Attributor {
14831496
/// \param Configuration The Attributor configuration which determines what
14841497
/// generic features to use.
14851498
Attributor(SetVector<Function *> &Functions, InformationCache &InfoCache,
1486-
AttributorConfig Configuration)
1487-
: Allocator(InfoCache.Allocator), Functions(Functions),
1488-
InfoCache(InfoCache), Configuration(Configuration) {}
1499+
AttributorConfig Configuration);
14891500

14901501
~Attributor();
14911502

@@ -1704,6 +1715,10 @@ struct Attributor {
17041715
: true;
17051716
}
17061717

1718+
/// Return true if the module contains the whole world, thus, no outside
1719+
/// functions exist.
1720+
bool isClosedWorldModule() const;
1721+
17071722
/// Return true if we derive attributes for \p Fn
17081723
bool isRunOn(Function &Fn) const { return isRunOn(&Fn); }
17091724
bool isRunOn(Function *Fn) const {

llvm/lib/Transforms/IPO/Attributor.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ static cl::opt<bool> SimplifyAllLoads("attributor-simplify-all-loads",
175175
cl::desc("Try to simplify all loads."),
176176
cl::init(true));
177177

178+
static cl::opt<bool> CloseWorldAssumption(
179+
"attributor-assume-closed-world", cl::Hidden,
180+
cl::desc("Should a closed world be assumed, or not. Default if not set."));
181+
178182
/// Logic operators for the change status enum class.
179183
///
180184
///{
@@ -1057,6 +1061,21 @@ ChangeStatus AbstractAttribute::update(Attributor &A) {
10571061
return HasChanged;
10581062
}
10591063

1064+
Attributor::Attributor(SetVector<Function *> &Functions,
1065+
InformationCache &InfoCache,
1066+
AttributorConfig Configuration)
1067+
: Allocator(InfoCache.Allocator), Functions(Functions),
1068+
InfoCache(InfoCache), Configuration(Configuration) {
1069+
if (!isClosedWorldModule())
1070+
return;
1071+
for (Function *Fn : Functions)
1072+
if (Fn->hasAddressTaken(/*PutOffender=*/nullptr,
1073+
/*IgnoreCallbackUses=*/false,
1074+
/*IgnoreAssumeLikeCalls=*/true,
1075+
/*IgnoreLLVMUsed=*/true))
1076+
InfoCache.IndirectlyCallableFunctions.push_back(Fn);
1077+
}
1078+
10601079
bool Attributor::getAttrsFromAssumes(const IRPosition &IRP,
10611080
Attribute::AttrKind AK,
10621081
SmallVectorImpl<Attribute> &Attrs) {
@@ -3251,6 +3270,12 @@ InformationCache::FunctionInfo::~FunctionInfo() {
32513270
It.getSecond()->~InstructionVectorTy();
32523271
}
32533272

3273+
const ArrayRef<Function *>
3274+
InformationCache::getIndirectlyCallableFunctions(Attributor &A) const {
3275+
assert(A.isClosedWorldModule() && "Cannot see all indirect callees!");
3276+
return IndirectlyCallableFunctions;
3277+
}
3278+
32543279
void Attributor::recordDependence(const AbstractAttribute &FromAA,
32553280
const AbstractAttribute &ToAA,
32563281
DepClassTy DepClass) {
@@ -3586,6 +3611,12 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) {
35863611
assert(Success && "Expected the check call to be successful!");
35873612
}
35883613

3614+
bool Attributor::isClosedWorldModule() const {
3615+
if (CloseWorldAssumption.getNumOccurrences())
3616+
return CloseWorldAssumption;
3617+
return isModulePass() && Configuration.IsClosedWorldModule;
3618+
}
3619+
35893620
/// Helpers to ease debugging through output streams and print calls.
35903621
///
35913622
///{

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12065,11 +12065,22 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
1206512065
/// See AbstractAttribute::initialize(...).
1206612066
void initialize(Attributor &A) override {
1206712067
auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12068-
if (!MD)
12068+
if (!MD && !A.isClosedWorldModule())
1206912069
return;
12070-
for (const auto &Op : MD->operands())
12071-
if (Function *Callee = mdconst::dyn_extract_or_null<Function>(Op))
12072-
PotentialCallees.insert(Callee);
12070+
12071+
if (MD) {
12072+
for (const auto &Op : MD->operands())
12073+
if (Function *Callee = mdconst::dyn_extract_or_null<Function>(Op))
12074+
PotentialCallees.insert(Callee);
12075+
} else if (A.isClosedWorldModule()) {
12076+
ArrayRef<Function *> IndirectlyCallableFunctions =
12077+
A.getInfoCache().getIndirectlyCallableFunctions(A);
12078+
PotentialCallees.insert(IndirectlyCallableFunctions.begin(),
12079+
IndirectlyCallableFunctions.end());
12080+
}
12081+
12082+
if (PotentialCallees.empty())
12083+
indicateOptimisticFixpoint();
1207312084
}
1207412085

1207512086
ChangeStatus updateImpl(Attributor &A) override {

0 commit comments

Comments
 (0)