[Attributor] Add all missing attribute definitions/symbols

As a preparation to "on-demand" abstract attribute generation we need
implementations for all attributes (as they can be queried and then
created on-demand where we now fail to find one).

Reviewers: uenoku, sstefan1

Subscribers: hiraditya, bollu, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D66129

llvm-svn: 369155
This commit is contained in:
Johannes Doerfert 2019-08-16 21:31:11 +00:00
parent f4bdbea02f
commit 6dedc78d9d
1 changed files with 117 additions and 35 deletions

View File

@ -1359,6 +1359,39 @@ struct AANonNullCallSiteArgument final : AANonNullImpl {
/// NonNull attribute deduction for a call sites.
using AANonNullCallSiteReturned = AANonNullReturned;
/// ------------------------ No-Recurse Attributes ----------------------------
struct AANoRecurseImpl : public AANoRecurse {
AANoRecurseImpl(const IRPosition &IRP) : AANoRecurse(IRP) {}
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override {
if (hasAttr({getAttrKind()})) {
indicateOptimisticFixpoint();
return;
}
}
/// See AbstractAttribute::getAsStr()
const std::string getAsStr() const override {
return getAssumed() ? "norecurse" : "may-recurse";
}
};
struct AANoRecurseFunction final : AANoRecurseImpl {
AANoRecurseFunction(const IRPosition &IRP) : AANoRecurseImpl(IRP) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
// TODO: Implement this.
return indicatePessimisticFixpoint();
}
void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(norecurse) }
};
using AANoRecurseCallSite = AANoRecurseFunction;
/// ------------------------ Will-Return Attributes ----------------------------
// Helper function that checks whether a function has any cycle.
@ -1381,34 +1414,27 @@ static bool containsCycle(Function &F) {
// endless loop
// FIXME: Any cycle is regarded as endless loop for now.
// We have to allow some patterns.
static bool containsPossiblyEndlessLoop(Function &F) {
return containsCycle(F);
static bool containsPossiblyEndlessLoop(Function *F) {
return !F || !F->hasExactDefinition() || containsCycle(*F);
}
struct AAWillReturnImpl : public AAWillReturn {
AAWillReturnImpl(const IRPosition &IRP) : AAWillReturn(IRP) {}
/// See AbstractAttribute::getAsStr()
const std::string getAsStr() const override {
return getAssumed() ? "willreturn" : "may-noreturn";
}
};
struct AAWillReturnFunction final : AAWillReturnImpl {
AAWillReturnFunction(const IRPosition &IRP) : AAWillReturnImpl(IRP) {}
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override {
Function &F = *getAnchorScope();
if (hasAttr({Attribute::WillReturn})) {
indicateOptimisticFixpoint();
return;
}
Function *F = getAssociatedFunction();
if (containsPossiblyEndlessLoop(F))
indicatePessimisticFixpoint();
}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
// The map from instruction opcodes to those instructions in the function.
auto CheckForWillReturn = [&](Instruction &I) {
ImmutableCallSite ICS(&I);
if (ICS.hasFnAttr(Attribute::WillReturn))
@ -1433,8 +1459,17 @@ struct AAWillReturnFunction final : AAWillReturnImpl {
return ChangeStatus::UNCHANGED;
}
/// See AbstractAttribute::getAsStr()
const std::string getAsStr() const override {
return getAssumed() ? "willreturn" : "may-noreturn";
}
};
struct AAWillReturnFunction final : AAWillReturnImpl {
AAWillReturnFunction(const IRPosition &IRP) : AAWillReturnImpl(IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(norecurse) }
void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(willreturn) }
};
/// WillReturn attribute deduction for a call sites.
@ -1445,26 +1480,64 @@ using AAWillReturnCallSite = AAWillReturnFunction;
struct AANoAliasImpl : AANoAlias {
AANoAliasImpl(const IRPosition &IRP) : AANoAlias(IRP) {}
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override {
if (hasAttr({Attribute::NoAlias}))
indicateOptimisticFixpoint();
}
const std::string getAsStr() const override {
return getAssumed() ? "noalias" : "may-alias";
}
};
/// NoAlias attribute for a floating value.
struct AANoAliasFloating final : AANoAliasImpl {
AANoAliasFloating(const IRPosition &IRP) : AANoAliasImpl(IRP) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
// TODO: Implement this.
return indicatePessimisticFixpoint();
}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override {
STATS_DECLTRACK_FLOATING_ATTR(noalias)
}
};
/// NoAlias attribute for an argument.
struct AANoAliasArgument final : AANoAliasImpl {
AANoAliasArgument(const IRPosition &IRP) : AANoAliasImpl(IRP) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
// TODO: Implement this.
return indicatePessimisticFixpoint();
}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(noalias) }
};
struct AANoAliasCallSiteArgument final : AANoAliasImpl {
AANoAliasCallSiteArgument(const IRPosition &IRP) : AANoAliasImpl(IRP) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
// TODO: Implement this.
return indicatePessimisticFixpoint();
}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(noalias) }
};
/// NoAlias attribute for function return value.
struct AANoAliasReturned final : AANoAliasImpl {
AANoAliasReturned(const IRPosition &IRP) : AANoAliasImpl(IRP) {}
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override {
Function &F = *getAnchorScope();
// Already noalias.
if (F.returnDoesNotAlias()) {
indicateOptimisticFixpoint();
return;
}
}
/// See AbstractAttribute::updateImpl(...).
virtual ChangeStatus updateImpl(Attributor &A) override {
@ -1515,10 +1588,14 @@ struct AAIsDeadImpl : public AAIsDead {
AAIsDeadImpl(const IRPosition &IRP) : AAIsDead(IRP) {}
void initialize(Attributor &A) override {
const Function &F = *getAnchorScope();
const Function *F = getAssociatedFunction();
if (!F || !F->hasExactDefinition()) {
indicatePessimisticFixpoint();
return;
}
ToBeExploredPaths.insert(&(F.getEntryBlock().front()));
AssumedLiveBlocks.insert(&(F.getEntryBlock()));
ToBeExploredPaths.insert(&(F->getEntryBlock().front()));
AssumedLiveBlocks.insert(&(F->getEntryBlock()));
for (size_t i = 0; i < ToBeExploredPaths.size(); ++i)
if (const Instruction *NextNoReturnI =
findNextNoReturn(A, ToBeExploredPaths[i]))
@ -1538,7 +1615,7 @@ struct AAIsDeadImpl : public AAIsDead {
/// See AbstractAttribute::getAsStr().
const std::string getAsStr() const override {
return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) + "/" +
std::to_string(getAnchorScope()->size()) + "][#NRI " +
std::to_string(getAssociatedFunction()->size()) + "][#NRI " +
std::to_string(NoReturnCalls.size()) + "]";
}
@ -1610,7 +1687,7 @@ struct AAIsDeadImpl : public AAIsDead {
/// See AAIsDead::isAssumedDead(BasicBlock *).
bool isAssumedDead(const BasicBlock *BB) const override {
assert(BB->getParent() == getAnchorScope() &&
assert(BB->getParent() == getAssociatedFunction() &&
"BB must be in the same anchor scope function.");
if (!getAssumed())
@ -1625,7 +1702,7 @@ struct AAIsDeadImpl : public AAIsDead {
/// See AAIsDead::isAssumed(Instruction *I).
bool isAssumedDead(const Instruction *I) const override {
assert(I->getParent()->getParent() == getAnchorScope() &&
assert(I->getParent()->getParent() == getAssociatedFunction() &&
"Instruction must be in the same anchor scope function.");
if (!getAssumed())
@ -1671,7 +1748,7 @@ struct AAIsDeadFunction final : public AAIsDeadImpl {
STATS_DECL(DeadBlocks, Function,
"Number of basic blocks classified as dead");
BUILD_STAT_NAME(DeadBlocks, Function) +=
getAnchorScope()->size() - AssumedLiveBlocks.size();
getAssociatedFunction()->size() - AssumedLiveBlocks.size();
STATS_DECL(PartiallyDeadBlocks, Function,
"Number of basic blocks classified as partially dead");
BUILD_STAT_NAME(PartiallyDeadBlocks, Function) += NoReturnCalls.size();
@ -1771,11 +1848,11 @@ ChangeStatus AAIsDeadImpl::updateImpl(Attributor &A) {
LLVM_DEBUG(dbgs() << "[AAIsDead] AssumedLiveBlocks: "
<< AssumedLiveBlocks.size() << " Total number of blocks: "
<< getAnchorScope()->size() << "\n");
<< getAssociatedFunction()->size() << "\n");
// If we know everything is live there is no need to query for liveness.
if (NoReturnCalls.empty() &&
getAnchorScope()->size() == AssumedLiveBlocks.size()) {
getAssociatedFunction()->size() == AssumedLiveBlocks.size()) {
// Indicating a pessimistic fixpoint will cause the state to be "invalid"
// which will cause the Attributor to not return the AAIsDead on request,
// which will prevent us from querying isAssumedDead().
@ -1787,6 +1864,11 @@ ChangeStatus AAIsDeadImpl::updateImpl(Attributor &A) {
}
/// Liveness information for a call sites.
//
// TODO: Once we have call site specific value information we can provide call
// site specific liveness liveness information and then it makes sense to
// specialize attributes for call sites instead of redirecting requests to
// the callee.
using AAIsDeadCallSite = AAIsDeadFunction;
/// -------------------- Dereferenceable Argument Attribute --------------------