Index: llvm/trunk/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h +++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h @@ -606,8 +606,11 @@ /// the abstract attributes. /// \param DepRecomputeInterval Number of iterations until the dependences /// between abstract attributes are recomputed. - Attributor(InformationCache &InfoCache, unsigned DepRecomputeInterval) - : InfoCache(InfoCache), DepRecomputeInterval(DepRecomputeInterval) {} + /// \param Whitelist If not null, a set limiting the attribute opportunities. + Attributor(InformationCache &InfoCache, unsigned DepRecomputeInterval, + DenseSet *Whitelist = nullptr) + : InfoCache(InfoCache), DepRecomputeInterval(DepRecomputeInterval), + Whitelist(Whitelist) {} ~Attributor() { DeleteContainerPointers(AllAbstractAttributes); } @@ -642,33 +645,7 @@ template const AAType &getAAFor(const AbstractAttribute &QueryingAA, const IRPosition &IRP, bool TrackDependence = true) { - static_assert(std::is_base_of::value, - "Cannot query an attribute with a type not derived from " - "'AbstractAttribute'!"); - - // Lookup the abstract attribute of type AAType. If found, return it after - // registering a dependence of QueryingAA on the one returned attribute. - const auto &KindToAbstractAttributeMap = - AAMap.lookup(const_cast(IRP)); - if (AAType *AA = static_cast( - KindToAbstractAttributeMap.lookup(&AAType::ID))) { - // Do not registr a dependence on an attribute with an invalid state. - if (TrackDependence && AA->getState().isValidState()) - QueryMap[AA].insert(const_cast(&QueryingAA)); - return *AA; - } - - // No matching attribute found, create one. - auto &AA = AAType::createForPosition(IRP, *this); - registerAA(AA); - - // Bootstrap the new attribute with an initial update to propagate - // information, e.g., function -> call site. - AA.update(*this); - - if (TrackDependence && AA.getState().isValidState()) - QueryMap[&AA].insert(const_cast(&QueryingAA)); - return AA; + return getOrCreateAAFor(IRP, &QueryingAA, TrackDependence); } /// Explicitly record a dependence from \p FromAA to \p ToAA, that is if @@ -709,15 +686,13 @@ /// abstract attribute objects for them. /// /// \param F The function that is checked for attribute opportunities. - /// \param Whitelist If not null, a set limiting the attribute opportunities. /// /// Note that abstract attribute instances are generally created even if the /// IR already contains the information they would deduce. The most important /// reason for this is the single interface, the one of the abstract attribute /// instance, which can be queried without the need to look at the IR in /// various places. - void identifyDefaultAbstractAttributes( - Function &F, DenseSet *Whitelist = nullptr); + void identifyDefaultAbstractAttributes(Function &F); /// Record that \p I is deleted after information was manifested. void deleteAfterManifest(Instruction &I) { ToBeDeletedInsts.insert(&I); } @@ -793,6 +768,61 @@ const DataLayout &getDataLayout() const { return InfoCache.DL; } private: + + /// The private version of getAAFor that allows to omit a querying abstract + /// attribute. See also the public getAAFor method. + template + const AAType &getOrCreateAAFor(const IRPosition &IRP, + const AbstractAttribute *QueryingAA = nullptr, + bool TrackDependence = false) { + if (const AAType *AAPtr = + lookupAAFor(IRP, QueryingAA, TrackDependence)) + return *AAPtr; + + // No matching attribute found, create one. + // Use the static create method. + auto &AA = AAType::createForPosition(IRP, *this); + registerAA(AA); + AA.initialize(*this); + + // Bootstrap the new attribute with an initial update to propagate + // information, e.g., function -> call site. If it is not on a given + // whitelist we will not perform updates at all. + if (Whitelist && !Whitelist->count(&AAType::ID)) + AA.getState().indicatePessimisticFixpoint(); + else + AA.update(*this); + + if (TrackDependence && AA.getState().isValidState()) + QueryMap[&AA].insert(const_cast(QueryingAA)); + return AA; + } + + /// Return the attribute of \p AAType for \p IRP if existing. + template + const AAType *lookupAAFor(const IRPosition &IRP, + const AbstractAttribute *QueryingAA = nullptr, + bool TrackDependence = false) { + static_assert(std::is_base_of::value, + "Cannot query an attribute with a type not derived from " + "'AbstractAttribute'!"); + assert((QueryingAA || !TrackDependence) && + "Cannot track dependences without a QueryingAA!"); + + // Lookup the abstract attribute of type AAType. If found, return it after + // registering a dependence of QueryingAA on the one returned attribute. + const auto &KindToAbstractAttributeMap = + AAMap.lookup(const_cast(IRP)); + if (AAType *AA = static_cast( + KindToAbstractAttributeMap.lookup(&AAType::ID))) { + // Do not register a dependence on an attribute with an invalid state. + if (TrackDependence && AA->getState().isValidState()) + QueryMap[AA].insert(const_cast(QueryingAA)); + return AA; + } + return nullptr; + } + /// The set of all abstract attributes. ///{ using AAVector = SmallVector; @@ -823,6 +853,9 @@ /// recomputed. const unsigned DepRecomputeInterval; + /// If not null, a set limiting the attribute opportunities. + const DenseSet *Whitelist; + /// Functions, blocks, and instructions we delete after manifest is done. /// ///{ Index: llvm/trunk/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/Attributor.cpp +++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp @@ -1790,16 +1790,8 @@ void initialize(Attributor &A) override { const Function *F = getAssociatedFunction(); - - if (F->hasInternalLinkage()) - return; - - if (!F || !F->hasExactDefinition()) { - indicatePessimisticFixpoint(); - return; - } - - exploreFromEntry(A, F); + if (F && !F->isDeclaration()) + exploreFromEntry(A, F); } void exploreFromEntry(Attributor &A, const Function *F) { @@ -2355,6 +2347,11 @@ getAttrs({Attribute::Alignment}, Attrs); for (const Attribute &Attr : Attrs) takeKnownMaximum(Attr.getValueAsInt()); + + if (getIRPosition().isFnInterfaceKind() && + (!getAssociatedFunction() || + !getAssociatedFunction()->hasExactDefinition())) + indicatePessimisticFixpoint(); } /// See AbstractAttribute::manifest(...). @@ -3311,70 +3308,52 @@ return ManifestChange; } -/// Helper function that checks if an abstract attribute of type \p AAType -/// should be created for IR position \p IRP and if so creates and registers it -/// with the Attributor \p A. -/// -/// This method will look at the provided whitelist. If one is given and the -/// kind \p AAType::ID is not contained, no abstract attribute is created. -/// -/// \returns The created abstract argument, or nullptr if none was created. -template -static const AAType *checkAndRegisterAA(const IRPosition &IRP, Attributor &A, - DenseSet *Whitelist) { - if (Whitelist && !Whitelist->count(&AAType::ID)) - return nullptr; - - return &A.registerAA(*new AAType(IRP)); -} - -void Attributor::identifyDefaultAbstractAttributes( - Function &F, DenseSet *Whitelist) { +void Attributor::identifyDefaultAbstractAttributes(Function &F) { IRPosition FPos = IRPosition::function(F); // Check for dead BasicBlocks in every function. // We need dead instruction detection because we do not want to deal with // broken IR in which SSA rules do not apply. - checkAndRegisterAA(FPos, *this, /* Whitelist */ nullptr); + getOrCreateAAFor(FPos); // Every function might be "will-return". - checkAndRegisterAA(FPos, *this, Whitelist); + getOrCreateAAFor(FPos); // Every function can be nounwind. - checkAndRegisterAA(FPos, *this, Whitelist); + getOrCreateAAFor(FPos); // Every function might be marked "nosync" - checkAndRegisterAA(FPos, *this, Whitelist); + getOrCreateAAFor(FPos); // Every function might be "no-free". - checkAndRegisterAA(FPos, *this, Whitelist); + getOrCreateAAFor(FPos); // Every function might be "no-return". - checkAndRegisterAA(FPos, *this, Whitelist); + getOrCreateAAFor(FPos); // Return attributes are only appropriate if the return type is non void. Type *ReturnType = F.getReturnType(); if (!ReturnType->isVoidTy()) { // Argument attribute "returned" --- Create only one per function even // though it is an argument attribute. - checkAndRegisterAA(FPos, *this, Whitelist); + getOrCreateAAFor(FPos); if (ReturnType->isPointerTy()) { IRPosition RetPos = IRPosition::returned(F); // Every function with pointer return type might be marked align. - checkAndRegisterAA(RetPos, *this, Whitelist); + getOrCreateAAFor(RetPos); // Every function with pointer return type might be marked nonnull. - checkAndRegisterAA(RetPos, *this, Whitelist); + getOrCreateAAFor(RetPos); // Every function with pointer return type might be marked noalias. - checkAndRegisterAA(RetPos, *this, Whitelist); + getOrCreateAAFor(RetPos); // Every function with pointer return type might be marked // dereferenceable. - checkAndRegisterAA(RetPos, *this, Whitelist); + getOrCreateAAFor(RetPos); } } @@ -3382,19 +3361,19 @@ if (Arg.getType()->isPointerTy()) { IRPosition ArgPos = IRPosition::argument(Arg); // Every argument with pointer type might be marked nonnull. - checkAndRegisterAA(ArgPos, *this, Whitelist); + getOrCreateAAFor(ArgPos); // Every argument with pointer type might be marked noalias. - checkAndRegisterAA(ArgPos, *this, Whitelist); + getOrCreateAAFor(ArgPos); // Every argument with pointer type might be marked dereferenceable. - checkAndRegisterAA(ArgPos, *this, Whitelist); + getOrCreateAAFor(ArgPos); // Every argument with pointer type might be marked align. - checkAndRegisterAA(ArgPos, *this, Whitelist); + getOrCreateAAFor(ArgPos); // Every argument with pointer type might be marked nocapture. - checkAndRegisterAA(ArgPos, *this, Whitelist); + getOrCreateAAFor(ArgPos); } } @@ -3420,15 +3399,13 @@ break; case Instruction::Load: // The alignment of a pointer is interesting for loads. - checkAndRegisterAA( - IRPosition::value(*cast(I).getPointerOperand()), *this, - Whitelist); + getOrCreateAAFor( + IRPosition::value(*cast(I).getPointerOperand())); break; case Instruction::Store: // The alignment of a pointer is interesting for stores. - checkAndRegisterAA( - IRPosition::value(*cast(I).getPointerOperand()), *this, - Whitelist); + getOrCreateAAFor( + IRPosition::value(*cast(I).getPointerOperand())); break; case Instruction::Call: case Instruction::CallBr: @@ -3452,19 +3429,16 @@ IRPosition CSArgPos = IRPosition::callsite_argument(CS, i); // Call site argument attribute "non-null". - checkAndRegisterAA(CSArgPos, *this, - Whitelist); + getOrCreateAAFor(CSArgPos); // Call site argument attribute "no-alias". - checkAndRegisterAA(CSArgPos, *this, - Whitelist); + getOrCreateAAFor(CSArgPos); // Call site argument attribute "dereferenceable". - checkAndRegisterAA(CSArgPos, *this, - Whitelist); + getOrCreateAAFor(CSArgPos); // Call site argument attribute "align". - checkAndRegisterAA(CSArgPos, *this, Whitelist); + getOrCreateAAFor(CSArgPos); } } } @@ -3633,7 +3607,6 @@ SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \ SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \ } \ - AA->initialize(A); \ return *AA; \ } @@ -3650,7 +3623,6 @@ SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \ SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \ } \ - AA->initialize(A); \ return *AA; \ } Index: llvm/trunk/test/Transforms/FunctionAttrs/align.ll =================================================================== --- llvm/trunk/test/Transforms/FunctionAttrs/align.ll +++ llvm/trunk/test/Transforms/FunctionAttrs/align.ll @@ -1,4 +1,4 @@ -; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR +; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -88,7 +88,7 @@ br i1 %2, label %3, label %5 ;