Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO/Attributor.h" +#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -1031,6 +1032,124 @@ return ChangeStatus::CHANGED; } +/// ------------------------ Will-Return Attributes ---------------------------- + +struct AAWillReturnFunction : AbstractAttribute, BooleanState { + + /// See AbstractAttribute::AbstractAttribute(...). + AAWillReturnFunction(Function &F, InformationCache &InfoCache) + : AbstractAttribute(F, InfoCache) {} + + /// See AbstractAttribute::getState() + ///{ + AbstractState &getState() override { return *this; } + const AbstractState &getState() const override { return *this; } + ///} + + /// See AbstractAttribute::getManifestPosition(). + virtual ManifestPosition getManifestPosition() const override { + return MP_FUNCTION; + } + + /// See AbstractAttribute::getAsStr(). + virtual const std::string getAsStr() const override { + return getAssumed() ? "willreturn" : "maybe-noreturn"; + } + + /// See AbstractAttribute::initialize(...). + virtual void initialize(Attributor &A) override; + + /// See AbstractAttribute::updateImpl(...). + virtual ChangeStatus updateImpl(Attributor &A) override; + + /// Return the deduced attributes in \p Attrs. + virtual void + getDeducedAttributes(SmallVectorImpl &Attrs) const override { + LLVMContext &Ctx = AnchoredVal.getContext(); + Attrs.emplace_back(Attribute::get(Ctx, "willreturn")); + } + + /// See AbstractAttribute::getAttrKind(). + virtual Attribute::AttrKind getAttrKind() const override { + return Attribute::None; + } + + /// Return true if "willreturn" is assumed. + bool isAssumedWillReturn() const { return getAssumed(); } + + /// Return true if "willreturn" is known. + bool isKnownWillReturn() const { return getKnown(); } + + /// FIXME: I use Attribute::None + 2 for now. + static constexpr Attribute::AttrKind ID = + Attribute::AttrKind(Attribute::None + 2); +}; + +// Helper function that checks whether a function has any loop. +bool containsLoop(Function &F) { + SmallPtrSet Visited; + + // Traverse BB by dfs and check whether successor is already visited. + for (BasicBlock *BB : depth_first(&F)) { + Visited.insert(BB); + for (auto *SuccBB : make_range(succ_begin(BB), succ_end(BB))) { + if (Visited.count(SuccBB)) { + return true; + } + } + } + return false; +} + +// Helper function that checks the function have a loop which might become an +// endless loop +// FIXME: Any loop is regarded as endless loop for now. +// We have to allow some patterns. +bool containsPossiblyEndlessLoop(Function &F) { return containsLoop(F); } + +void AAWillReturnFunction::initialize(Attributor &A) { + Function &F = getAnchorScope(); + if (containsPossiblyEndlessLoop(F)) + indicatePessimisticFixpoint(); +} + +ChangeStatus AAWillReturnFunction::updateImpl(Attributor &A) { + Function &F = getAnchorScope(); + + // The map from instruction opcodes to those instructions in the function. + auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F); + + for (unsigned Opcode : + {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr, + (unsigned)Instruction::Call}) { + for (Instruction *I : OpcodeInstMap[Opcode]) { + // Assume that all intrinsic will return + if (isa(I)) + continue; + + auto ICS = ImmutableCallSite(I); + + auto *WillReturnAA = A.getAAFor(*this, *I); + if ((!WillReturnAA || !WillReturnAA->isValidState() || + !WillReturnAA->isAssumedWillReturn()) && + !ICS.hasFnAttr("willreturn")) { + indicatePessimisticFixpoint(); + return ChangeStatus::CHANGED; + } + + // FIXME: Prohibit any recursion for now + auto *NoRecurseAA = A.getAAFor(*this, *I); + if ((!NoRecurseAA || !NoRecurseAA->isValidState() || + !NoRecurseAA->isAssumedNoRecurse()) && + !ICS.hasFnAttr(Attribute::NoRecurse)) { + indicatePessimisticFixpoint(); + return ChangeStatus::CHANGED; + } + } + } + + return ChangeStatus::UNCHANGED; +} /// ---------------------------------------------------------------------------- /// Attributor @@ -1190,6 +1309,9 @@ // Every function might be "no-return". registerAA(*new AANoReturnFunction(F, InfoCache)); + // Every function might be "will-return". + registerAA(*new AAWillReturnFunction(F, InfoCache)); + // Walk all instructions to find more attribute opportunities and also // interesting instructions that might be queried by abstract attributes // during their initialization or update.