diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -1322,11 +1322,40 @@ : AACallSiteReturnedFromReturned { AANonNullCallSiteReturned(const IRPosition &IRP) : AACallSiteReturnedFromReturned(IRP) {} - - /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(nonnull) } }; +/// ------------------------ 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) } +}; + /// ------------------------ Will-Return Attributes ---------------------------- // Helper function that checks whether a function has any cycle. @@ -1349,34 +1378,27 @@ // 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)) @@ -1401,8 +1423,17 @@ 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. @@ -1413,26 +1444,64 @@ 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 function return value. -struct AANoAliasReturned final : AANoAliasImpl { - AANoAliasReturned(const IRPosition &IRP) : AANoAliasImpl(IRP) {} +/// NoAlias attribute for a floating value. +struct AANoAliasFloating final : AANoAliasImpl { + AANoAliasFloating(const IRPosition &IRP) : AANoAliasImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - Function &F = *getAnchorScope(); + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + // TODO: Implement this. + return indicatePessimisticFixpoint(); + } - // Already noalias. - if (F.returnDoesNotAlias()) { - indicateOptimisticFixpoint(); - return; - } + /// 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::updateImpl(...). virtual ChangeStatus updateImpl(Attributor &A) override { @@ -1483,10 +1552,14 @@ 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])) @@ -1506,7 +1579,7 @@ /// 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()) + "]"; } @@ -1578,7 +1651,7 @@ /// 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()) @@ -1593,7 +1666,7 @@ /// 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()) @@ -1639,7 +1712,7 @@ 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(); @@ -1739,11 +1812,11 @@ 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(). @@ -1755,6 +1828,11 @@ } /// 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 --------------------