Index: llvm/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/include/llvm/Transforms/IPO/Attributor.h +++ llvm/include/llvm/Transforms/IPO/Attributor.h @@ -154,6 +154,7 @@ /// are floating values that do not have a corresponding attribute list /// position. struct IRPosition { + using CallBaseContext = CallBase; /// The positions we distinguish in the IR. enum Kind : char { @@ -171,30 +172,37 @@ /// Default constructor available to create invalid positions implicitly. All /// other positions need to be created explicitly through the appropriate /// static member function. - IRPosition() : Enc(nullptr, ENC_VALUE) { verify(); } + IRPosition() : Enc(nullptr, ENC_VALUE), CBContext(nullptr) { verify(); } /// Create a position describing the value of \p V. - static const IRPosition value(const Value &V) { + static const IRPosition value(const Value &V, + CallBaseContext *CBContext = nullptr) { if (auto *Arg = dyn_cast(&V)) - return IRPosition::argument(*Arg); + return IRPosition::argument(*Arg, CBContext); if (auto *CB = dyn_cast(&V)) return IRPosition::callsite_returned(*CB); - return IRPosition(const_cast(V), IRP_FLOAT); + return IRPosition(const_cast(V), IRP_FLOAT, CBContext); } /// Create a position describing the function scope of \p F. - static const IRPosition function(const Function &F) { - return IRPosition(const_cast(F), IRP_FUNCTION); + /// \p CBContext is used for call base specific analysis. + static const IRPosition function(const Function &F, + CallBaseContext *CBContext = nullptr) { + return IRPosition(const_cast(F), IRP_FUNCTION, CBContext); } /// Create a position describing the returned value of \p F. - static const IRPosition returned(const Function &F) { - return IRPosition(const_cast(F), IRP_RETURNED); + /// \p CBContext is used for call base specific analysis. + static const IRPosition returned(const Function &F, + CallBaseContext *CBContext = nullptr) { + return IRPosition(const_cast(F), IRP_RETURNED, CBContext); } /// Create a position describing the argument \p Arg. - static const IRPosition argument(const Argument &Arg) { - return IRPosition(const_cast(Arg), IRP_ARGUMENT); + /// \p CBContext is used for call base specific analysis. + static const IRPosition argument(const Argument &Arg, + CallBaseContext *CBContext = nullptr) { + return IRPosition(const_cast(Arg), IRP_ARGUMENT, CBContext); } /// Create a position describing the function scope of \p CB. @@ -230,16 +238,19 @@ /// If \p IRP is a call site (see isAnyCallSitePosition()) then the result /// will be a call site position, otherwise the function position of the /// associated function. - static const IRPosition function_scope(const IRPosition &IRP) { + static const IRPosition function_scope(const IRPosition &IRP, + CallBaseContext *CBContext = nullptr) { if (IRP.isAnyCallSitePosition()) { return IRPosition::callsite_function( cast(IRP.getAnchorValue())); } assert(IRP.getAssociatedFunction()); - return IRPosition::function(*IRP.getAssociatedFunction()); + return IRPosition::function(*IRP.getAssociatedFunction(), CBContext); } - bool operator==(const IRPosition &RHS) const { return Enc == RHS.Enc; } + bool operator==(const IRPosition &RHS) const { + return Enc == RHS.Enc && RHS.CBContext == CBContext; + } bool operator!=(const IRPosition &RHS) const { return !(*this == RHS); } /// Return the value this abstract attribute is anchored with. @@ -439,6 +450,16 @@ } } + IRPosition stripCallBaseContext() const { + IRPosition result; + result.Enc = Enc; + return result; + } + + const CallBaseContext *getCallBaseContext() const { return CBContext; } + + bool hasCallBaseContext() const { return CBContext != nullptr; } + /// Special DenseMap key values. /// ///{ @@ -451,10 +472,15 @@ private: /// Private constructor for special values only! - explicit IRPosition(void *Ptr) { Enc.setFromOpaqueValue(Ptr); } + explicit IRPosition(void *Ptr, CallBaseContext *CBContext = nullptr) + : CBContext(CBContext) { + Enc.setFromOpaqueValue(Ptr); + } /// IRPosition anchored at \p AnchorVal with kind/argument numbet \p PK. - explicit IRPosition(Value &AnchorVal, Kind PK) { + explicit IRPosition(Value &AnchorVal, Kind PK, + CallBaseContext *CBContext = nullptr) + : CBContext(CBContext) { switch (PK) { case IRPosition::IRP_INVALID: llvm_unreachable("Cannot create invalid IRP with an anchor value!"); @@ -557,16 +583,27 @@ PointerIntPair Enc; ///} + /// CallBase context. Used for callsite specific analysis. + const CallBaseContext *CBContext; + /// Return the encoding bits. char getEncodingBits() const { return Enc.getInt(); } }; /// Helper that allows IRPosition as a key in a DenseMap. -template <> struct DenseMapInfo : DenseMapInfo { +template <> struct DenseMapInfo { static inline IRPosition getEmptyKey() { return IRPosition::EmptyKey; } static inline IRPosition getTombstoneKey() { return IRPosition::TombstoneKey; } + static unsigned getHashValue(const IRPosition &IRP) { + return (DenseMapInfo::getHashValue(IRP) << 4) ^ + (DenseMapInfo::getHashValue(IRP.getCallBaseContext())); + } + + static bool isEqual(const IRPosition &a, const IRPosition &b) { + return a == b; + } }; /// A visitor class for IR positions. @@ -1249,6 +1286,9 @@ const AbstractAttribute *QueryingAA, bool &AllCallSitesKnown); + /// Determine if CallBase context in \p IRP should be propagated. + bool shouldPropagateCallBaseContext(const IRPosition &IRP); + /// The private version of getAAFor that allows to omit a querying abstract /// attribute. See also the public getAAFor method. template @@ -1257,7 +1297,22 @@ bool TrackDependence = false, DepClassTy DepClass = DepClassTy::OPTIONAL, bool ForceUpdate = false) { - if (AAType *AAPtr = lookupAAFor(IRP, QueryingAA, TrackDependence)) { +#ifdef EXPENSIVE_CHECKS + // Don't allow callbase information to leak. + if (auto CBContext = IRP.getCallBaseContext()) { + assert( + ((CBContext->getCalledFunction() == IRP.getAnchorScope() || + QueryingAA || + !QueryingAA.getIRPosition().isAnyCallSitePosition())) && + "non callsite positions are not allowed to propagate CallBaseContext " + "across functions"); + } +#endif + const IRPosition RealIRP = + shouldPropagateCallBaseContext(IRP) ? IRP : IRP.stripCallBaseContext(); + + if (AAType *AAPtr = + lookupAAFor(RealIRP, QueryingAA, TrackDependence)) { if (ForceUpdate) updateAA(*AAPtr); return *AAPtr; @@ -1265,7 +1320,7 @@ // No matching attribute found, create one. // Use the static create method. - auto &AA = AAType::createForPosition(IRP, *this); + auto &AA = AAType::createForPosition(RealIRP, *this); registerAA(AA); // For now we ignore naked and optnone functions. Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -77,6 +77,11 @@ "wrappers for non-exact definitions."), cl::init(false)); +static cl::opt EnableCallSiteSpecific( + "attributor-enalbe-call-site-specific", cl::Hidden, + cl::desc("Allow the Attributor to do call site specific analysis"), + cl::init(false)); + /// Logic operators for the change status enum class. /// ///{ @@ -404,6 +409,8 @@ #ifdef EXPENSIVE_CHECKS switch (getPositionKind()) { case IRP_INVALID: + assert((CBContext == nullptr) && + "Invalid position must not have CallBaseContext!"); assert(!Enc.getOpaqueValue() && "Expected a nullptr for an invalid position!"); return; @@ -419,12 +426,16 @@ "Associated value mismatch!"); return; case IRP_CALL_SITE_RETURNED: + assert((CBContext == nullptr) && + "'call site returned' position must not have CallBaseContext!"); assert((isa(getAsValuePtr())) && "Expected call base for 'call site returned' position!"); assert(getAsValuePtr() == &getAssociatedValue() && "Associated value mismatch!"); return; case IRP_CALL_SITE: + assert((CBContext == nullptr) && + "'call site function' position must not have CcallBaseContext!"); assert((isa(getAsValuePtr())) && "Expected call base for 'call site function' position!"); assert(getAsValuePtr() == &getAssociatedValue() && @@ -443,6 +454,8 @@ "Associated value mismatch!"); return; case IRP_CALL_SITE_ARGUMENT: { + assert((CBContext == nullptr) && + "'call site argument' position must not have CallBaseContext!"); Use *U = getAsUsePtr(); assert(U && "Expected use for a 'call site argument' position!"); assert(isa(U->getUser()) && @@ -777,6 +790,13 @@ return true; } +bool Attributor::shouldPropagateCallBaseContext(const IRPosition &IRP) { + // TODO: Maintain a cache of Values that are on the pathway from a Argument to + // a + // Instruction that would effect the liveness/return state etc. + return EnableCallSiteSpecific; +} + bool Attributor::checkForAllReturnedValuesAndReturnInsts( function_ref &)> Pred, const AbstractAttribute &QueryingAA) { @@ -1044,6 +1064,9 @@ if (!State.isAtFixpoint()) State.indicateOptimisticFixpoint(); + // We must not manifest Attributes that use Callbase info. + if (AA->hasCallBaseContext()) + continue; // If the state is invalid, we do not try to manifest it. if (!State.isValidState()) continue; @@ -1984,8 +2007,12 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) { const Value &AV = Pos.getAssociatedValue(); - return OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " [" - << Pos.getAnchorValue().getName() << "@" << Pos.getArgNo() << "]}"; + OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " [" + << Pos.getAnchorValue().getName() << "@" << Pos.getArgNo() << "]"; + + if (Pos.hasCallBaseContext()) + OS << "[cb_context:" << Pos.getCallBaseContext() << "]"; + return OS << "}"; } raw_ostream &llvm::operator<<(raw_ostream &OS, const IntegerRangeState &S) {