diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -593,8 +593,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); } @@ -629,33 +632,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 @@ -696,15 +673,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); } @@ -780,6 +755,53 @@ 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) { + 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 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. + // 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 or if the associated function is unknown or if it does not have + // an exact definition, we give up. + const Function *F = IRP.getAssociatedFunction(); + if (!F || !F->hasExactDefinition() || + (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; + } + /// The set of all abstract attributes. ///{ using AAVector = SmallVector; @@ -810,6 +832,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. /// ///{ 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 @@ -688,14 +688,6 @@ struct AANoUnwindCallSite final : AANoUnwindImpl { AANoUnwindCallSite(const IRPosition &IRP) : AANoUnwindImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AANoUnwindImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -752,10 +744,8 @@ ReturnedValues.clear(); Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) { - indicatePessimisticFixpoint(); + if (!F) return; - } // The map from instruction opcodes to those instructions in the function. auto &OpcodeInstMap = A.getInfoCache().getOpcodeInstMapForFunction(*F); @@ -1306,14 +1296,6 @@ struct AANoSyncCallSite final : AANoSyncImpl { AANoSyncCallSite(const IRPosition &IRP) : AANoSyncImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AANoSyncImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -1376,14 +1358,6 @@ struct AANoFreeCallSite final : AANoFreeImpl { AANoFreeCallSite(const IRPosition &IRP) : AANoFreeImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AANoFreeImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -1544,14 +1518,6 @@ struct AANoRecurseCallSite final : AANoRecurseImpl { AANoRecurseCallSite(const IRPosition &IRP) : AANoRecurseImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AANoRecurseImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -1647,14 +1613,6 @@ struct AAWillReturnCallSite final : AAWillReturnImpl { AAWillReturnCallSite(const IRPosition &IRP) : AAWillReturnImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AAWillReturnImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -1773,14 +1731,6 @@ struct AANoAliasCallSiteReturned final : AANoAliasImpl { AANoAliasCallSiteReturned(const IRPosition &IRP) : AANoAliasImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AANoAliasImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -1804,17 +1754,8 @@ AAIsDeadImpl(const IRPosition &IRP) : AAIsDead(IRP) {} void initialize(Attributor &A) override { - const Function *F = getAssociatedFunction(); - - if (F->hasInternalLinkage()) - return; - - if (!F || !F->hasExactDefinition()) { - indicatePessimisticFixpoint(); - return; - } - - exploreFromEntry(A, F); + if (const Function *F = getAssociatedFunction()) + exploreFromEntry(A, F); } void exploreFromEntry(Attributor &A, const Function *F) { @@ -2321,14 +2262,6 @@ AADereferenceableCallSiteReturned(const IRPosition &IRP) : AADereferenceableImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AADereferenceableImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -2489,14 +2422,6 @@ struct AAAlignCallSiteReturned final : AAAlignImpl { AAAlignCallSiteReturned(const IRPosition &IRP) : AAAlignImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AAAlignImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -2550,14 +2475,6 @@ struct AANoReturnCallSite final : AANoReturnImpl { AANoReturnCallSite(const IRPosition &IRP) : AANoReturnImpl(IRP) {} - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - AANoReturnImpl::initialize(A); - Function *F = getAssociatedFunction(); - if (!F || !F->hasExactDefinition()) - indicatePessimisticFixpoint(); - } - /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -2596,8 +2513,7 @@ // Check what state the associated function can actually capture. if (F) determineFunctionCaptureCapabilities(*F, *this); - - if (!F || !F->hasExactDefinition()) + else indicatePessimisticFixpoint(); } @@ -3014,7 +2930,7 @@ // Since we need to provide return instructions we have to have an exact // definition. const Function *AssociatedFunction = IRP.getAssociatedFunction(); - if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition()) + if (!AssociatedFunction) return false; // If this is a call site query we use the call site specific return values @@ -3034,7 +2950,7 @@ const IRPosition &IRP = QueryingAA.getIRPosition(); const Function *AssociatedFunction = IRP.getAssociatedFunction(); - if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition()) + if (!AssociatedFunction) return false; // TODO: use the function scope once we have call site AAReturnedValues. @@ -3056,7 +2972,7 @@ const IRPosition &IRP = QueryingAA.getIRPosition(); // Since we need to provide instructions we have to have an exact definition. const Function *AssociatedFunction = IRP.getAssociatedFunction(); - if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition()) + if (!AssociatedFunction) return false; // TODO: use the function scope once we have call site AAReturnedValues. @@ -3330,70 +3246,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); } } @@ -3401,16 +3299,16 @@ 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 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); } } @@ -3436,15 +3334,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: @@ -3468,15 +3364,13 @@ IRPosition CSArgPos = IRPosition::callsite_argument(CS, i); // Call site argument attribute "non-null". - 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); } } } @@ -3655,7 +3549,6 @@ SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \ SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \ } \ - AA->initialize(A); \ return *AA; \ } @@ -3672,7 +3565,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; \ }