[llvm] r368919 - [Attributor] Use IRPosition consistently

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 14 14:18:01 PDT 2019


Author: jdoerfert
Date: Wed Aug 14 14:18:01 2019
New Revision: 368919

URL: http://llvm.org/viewvc/llvm-project?rev=368919&view=rev
Log:
[Attributor] Use IRPosition consistently

Summary:
The next attempt to clean up the Attributor interface before we grow it
further.

Before, we used a combination of two values (associated + anchor) and an
argument number (or -1) to determine a location. This was very fragile.
The new system uses exclusively IR positions and we restrict the
generation of IR positions to special constructor methods that verify
internal constraints we have. This will catch misuse early.

The auto-conversion, e.g., in getAAFor, is now performed through the
SubsumingPositionIterator. This iterator takes an IR position and allows
to visit all IR positions that "subsume" the given one, e.g., function
attributes "subsume" argument attributes of that function. For a
detailed breakdown see the class comment of SubsumingPositionIterator.

This patch also introduces the IRPosition::getAttrs() to extract IR
attributes at a certain position. The method knows how to look up in
different positions that are equivalent, e.g., the argument position for
call site arguments. We also introduce three new positions kinds such
that we have all IR positions where attributes can be placed and one for
"floating" values.

Reviewers: sstefan1, uenoku

Subscribers: hiraditya, bollu, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D65977

Modified:
    llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp

Modified: llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/Attributor.h?rev=368919&r1=368918&r2=368919&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Wed Aug 14 14:18:01 2019
@@ -119,6 +119,368 @@ ChangeStatus operator|(ChangeStatus l, C
 ChangeStatus operator&(ChangeStatus l, ChangeStatus r);
 ///}
 
+/// Helper to describe and deal with positions in the LLVM-IR.
+///
+/// A position in the IR is described by an anchor value and an "offset" that
+/// could be the argument number, for call sites and arguments, or an indicator
+/// of the "position kind". The kinds, specified in the Kind enum below, include
+/// the locations in the attribute list, i.a., function scope and return value,
+/// as well as a distinction between call sites and functions. Finally, there
+/// are floating values that do not have a corresponding attribute list
+/// position.
+struct IRPosition {
+  virtual ~IRPosition() {}
+
+  /// The positions we distinguish in the IR.
+  ///
+  /// The values are chosen such that the KindOrArgNo member has a value >= 1
+  /// if it is an argument or call site argument while a value < 1 indicates the
+  /// respective kind of that value.
+  enum Kind : int {
+    IRP_INVALID = -6, ///< An invalid position.
+    IRP_FLOAT = -5, ///< A position that is not associated with a spot suitable
+                    ///< for attributes. This could be any value or instruction.
+    IRP_RETURNED = -4, ///< An attribute for the function return value.
+    IRP_CALL_SITE_RETURNED = -3, ///< An attribute for a call site return value.
+    IRP_FUNCTION = -2,           ///< An attribute for a function (scope).
+    IRP_CALL_SITE = -1, ///< An attribute for a call site (function scope).
+    IRP_ARGUMENT = 0,   ///< An attribute for a function argument.
+    IRP_CALL_SITE_ARGUMENT = 1, ///< An attribute for a call site argument.
+  };
+
+  /// Default constructor available to create invalid positions implicitly. All
+  /// other positions need to be created explicitly through the appropriate
+  /// static member function.
+  IRPosition() : AnchorVal(nullptr), KindOrArgNo(IRP_INVALID) { verify(); }
+
+  /// Create a position describing the value of \p V.
+  static const IRPosition value(const Value &V) {
+    if (auto *Arg = dyn_cast<Argument>(&V))
+      return IRPosition::argument(*Arg);
+    if (auto *CB = dyn_cast<CallBase>(&V))
+      return IRPosition::callsite_returned(*CB);
+    return IRPosition(const_cast<Value &>(V), IRP_FLOAT);
+  }
+
+  /// Create a position describing the function scope of \p F.
+  static const IRPosition function(const Function &F) {
+    return IRPosition(const_cast<Function &>(F), IRP_FUNCTION);
+  }
+
+  /// Create a position describing the returned value of \p F.
+  static const IRPosition returned(const Function &F) {
+    return IRPosition(const_cast<Function &>(F), IRP_RETURNED);
+  }
+
+  /// Create a position describing the argument \p Arg.
+  static const IRPosition argument(const Argument &Arg) {
+    return IRPosition(const_cast<Argument &>(Arg), Kind(Arg.getArgNo()));
+  }
+
+  /// Create a position describing the function scope of \p CB.
+  static const IRPosition callsite_function(const CallBase &CB) {
+    return IRPosition(const_cast<CallBase &>(CB), IRP_CALL_SITE);
+  }
+
+  /// Create a position describing the returned value of \p CB.
+  static const IRPosition callsite_returned(const CallBase &CB) {
+    return IRPosition(const_cast<CallBase &>(CB), IRP_CALL_SITE_RETURNED);
+  }
+
+  /// Create a position describing the argument of \p CB at position \p ArgNo.
+  static const IRPosition callsite_argument(const CallBase &CB,
+                                            unsigned ArgNo) {
+    return IRPosition(const_cast<CallBase &>(CB), Kind(ArgNo));
+  }
+
+  /// Create a position describing the function scope of \p ICS.
+  static const IRPosition callsite_function(ImmutableCallSite ICS) {
+    return IRPosition::callsite_function(cast<CallBase>(*ICS.getInstruction()));
+  }
+
+  /// Create a position describing the returned value of \p ICS.
+  static const IRPosition callsite_returned(ImmutableCallSite ICS) {
+    return IRPosition::callsite_returned(cast<CallBase>(*ICS.getInstruction()));
+  }
+
+  /// Create a position describing the argument of \p ICS at position \p ArgNo.
+  static const IRPosition callsite_argument(ImmutableCallSite ICS,
+                                            unsigned ArgNo) {
+    return IRPosition::callsite_argument(cast<CallBase>(*ICS.getInstruction()),
+                                         ArgNo);
+  }
+
+  /// Create a position with function scope matching the "context" of \p IRP.
+  /// 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) {
+    if (IRP.isAnyCallSitePosition()) {
+      return IRPosition::callsite_function(
+          cast<CallBase>(IRP.getAnchorValue()));
+    }
+    assert(IRP.getAssociatedFunction());
+    return IRPosition::function(*IRP.getAssociatedFunction());
+  }
+
+  bool operator==(const IRPosition &RHS) const {
+    return (AnchorVal == RHS.AnchorVal) && (KindOrArgNo == RHS.KindOrArgNo);
+  }
+  bool operator!=(const IRPosition &RHS) const { return !(*this == RHS); }
+
+  /// Return the value this abstract attribute is anchored with.
+  ///
+  /// The anchor value might not be the associated value if the latter is not
+  /// sufficient to determine where arguments will be manifested. This is, so
+  /// far, only the case for call site arguments as the value is not sufficient
+  /// to pinpoint them. Instead, we can use the call site as an anchor.
+  ///
+  ///{
+  Value &getAnchorValue() {
+    assert(KindOrArgNo != IRP_INVALID &&
+           "Invalid position does not have an anchor value!");
+    return *AnchorVal;
+  }
+  const Value &getAnchorValue() const {
+    return const_cast<IRPosition *>(this)->getAnchorValue();
+  }
+  ///}
+
+  /// Return the associated function, if any.
+  ///
+  ///{
+  Function *getAssociatedFunction() {
+    if (auto *CB = dyn_cast<CallBase>(AnchorVal))
+      return CB->getCalledFunction();
+    assert(KindOrArgNo != IRP_INVALID &&
+           "Invalid position does not have an anchor scope!");
+    Value &V = getAnchorValue();
+    if (isa<Function>(V))
+      return &cast<Function>(V);
+    if (isa<Argument>(V))
+      return cast<Argument>(V).getParent();
+    if (isa<Instruction>(V))
+      return cast<Instruction>(V).getFunction();
+    return nullptr;
+  }
+  const Function *getAssociatedFunction() const {
+    return const_cast<IRPosition *>(this)->getAssociatedFunction();
+  }
+  ///}
+
+  /// Return the Function surrounding the anchor value.
+  ///
+  ///{
+  Function &getAnchorScope() {
+    Value &V = getAnchorValue();
+    if (isa<Function>(V))
+      return cast<Function>(V);
+    if (isa<Argument>(V))
+      return *cast<Argument>(V).getParent();
+    if (isa<Instruction>(V))
+      return *cast<Instruction>(V).getFunction();
+    llvm_unreachable("No anchor scope");
+  }
+  const Function &getAnchorScope() const {
+    return const_cast<IRPosition *>(this)->getAnchorScope();
+  }
+  ///}
+
+  /// Return the context instruction, if any.
+  ///
+  ///{
+  Instruction *getCtxI() {
+    Value &V = getAnchorValue();
+    if (auto *I = dyn_cast<Instruction>(&V))
+      return I;
+    if (auto *Arg = dyn_cast<Argument>(&V))
+      if (!Arg->getParent()->isDeclaration())
+        return &Arg->getParent()->getEntryBlock().front();
+    return nullptr;
+  }
+  const Instruction *getCtxI() const {
+    return const_cast<IRPosition *>(this)->getCtxI();
+  }
+  ///}
+
+  /// Return the value this abstract attribute is associated with.
+  ///
+  ///{
+  Value &getAssociatedValue() {
+    assert(KindOrArgNo != IRP_INVALID &&
+           "Invalid position does not have an associated value!");
+    if (getArgNo() < 0 || isa<Argument>(AnchorVal))
+      return *AnchorVal;
+    assert(isa<CallBase>(AnchorVal) && "Expected a call base!");
+    return *cast<CallBase>(AnchorVal)->getArgOperand(getArgNo());
+  }
+  const Value &getAssociatedValue() const {
+    return const_cast<IRPosition *>(this)->getAssociatedValue();
+  }
+  ///}
+
+  /// Return the argument number of the associated value if it is an argument or
+  /// call site argument, otherwise a negative value.
+  int getArgNo() const { return KindOrArgNo; }
+
+  /// Return the index in the attribute list for this position.
+  unsigned getAttrIdx() const {
+    switch (getPositionKind()) {
+    case IRPosition::IRP_INVALID:
+    case IRPosition::IRP_FLOAT:
+      break;
+    case IRPosition::IRP_FUNCTION:
+    case IRPosition::IRP_CALL_SITE:
+      return AttributeList::FunctionIndex;
+    case IRPosition::IRP_RETURNED:
+    case IRPosition::IRP_CALL_SITE_RETURNED:
+      return AttributeList::ReturnIndex;
+    case IRPosition::IRP_ARGUMENT:
+    case IRPosition::IRP_CALL_SITE_ARGUMENT:
+      return KindOrArgNo + AttributeList::FirstArgIndex;
+    }
+    llvm_unreachable(
+        "There is no attribute index for a floating or invalid position!");
+  }
+
+  /// Return the associated position kind.
+  Kind getPositionKind() const {
+    if (getArgNo() >= 0) {
+      assert(((isa<Argument>(getAnchorValue()) &&
+               isa<Argument>(getAssociatedValue())) ||
+              isa<CallBase>(getAnchorValue())) &&
+             "Expected argument or call base due to argument number!");
+      if (isa<CallBase>(getAnchorValue()))
+        return IRP_CALL_SITE_ARGUMENT;
+      return IRP_ARGUMENT;
+    }
+
+    assert(KindOrArgNo < 0 &&
+           "Expected (call site) arguments to never reach this point!");
+    assert(!isa<Argument>(getAnchorValue()) &&
+           "Expected arguments to have an associated argument position!");
+    return Kind(KindOrArgNo);
+  }
+
+  /// TODO: Figure out if the attribute related helper functions should live
+  ///       here or somewhere else.
+
+  /// Return true if any kind in \p AKs existing in the IR at a position that
+  /// will affect this one. See also getAttrs(...).
+  bool hasAttr(ArrayRef<Attribute::AttrKind> AKs) const;
+
+  /// Return the attributes of any kind in \p AKs existing in the IR at a
+  /// position that will affect this one. While each position can only have a
+  /// single attribute of any kind in \p AKs, there are "subsuming" positions
+  /// that could have an attribute as well. This method returns all attributes
+  /// found in \p Attrs.
+  void getAttrs(ArrayRef<Attribute::AttrKind> AKs,
+                SmallVectorImpl<Attribute> &Attrs) const;
+
+  /// Return the attribute of kind \p AK existing in the IR at this position.
+  Attribute getAttr(Attribute::AttrKind AK) const {
+    if (getPositionKind() == IRP_INVALID || getPositionKind() == IRP_FLOAT)
+      return Attribute();
+
+    AttributeList AttrList;
+    if (ImmutableCallSite ICS = ImmutableCallSite(&getAnchorValue()))
+      AttrList = ICS.getAttributes();
+    else
+      AttrList = getAssociatedFunction()->getAttributes();
+
+    if (AttrList.hasAttribute(getAttrIdx(), AK))
+      return AttrList.getAttribute(getAttrIdx(), AK);
+    return Attribute();
+  }
+
+  bool isAnyCallSitePosition() const {
+    switch (getPositionKind()) {
+    case IRPosition::IRP_CALL_SITE:
+    case IRPosition::IRP_CALL_SITE_RETURNED:
+    case IRPosition::IRP_CALL_SITE_ARGUMENT:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  /// Special DenseMap key values.
+  ///
+  ///{
+  static const IRPosition EmptyKey;
+  static const IRPosition TombstoneKey;
+  ///}
+
+private:
+  /// Private constructor for special values only!
+  explicit IRPosition(int KindOrArgNo)
+      : AnchorVal(0), KindOrArgNo(KindOrArgNo) {}
+
+  /// IRPosition anchored at \p AnchorVal with kind/argument numbet \p PK.
+  explicit IRPosition(Value &AnchorVal, Kind PK)
+      : AnchorVal(&AnchorVal), KindOrArgNo(PK) {
+    verify();
+  }
+
+  /// Verify internal invariants.
+  void verify();
+
+  /// The value this position is anchored at.
+  Value *AnchorVal;
+
+  /// The argument number, if non-negative, or the position "kind".
+  int KindOrArgNo;
+};
+
+/// Helper that allows IRPosition as a key in a DenseMap.
+template <> struct DenseMapInfo<IRPosition> {
+  static inline IRPosition getEmptyKey() { return IRPosition::EmptyKey; }
+  static inline IRPosition getTombstoneKey() {
+    return IRPosition::TombstoneKey;
+  }
+  static unsigned getHashValue(const IRPosition &IRP) {
+    return (DenseMapInfo<Value *>::getHashValue(&IRP.getAnchorValue()) << 4) ^
+           (unsigned(IRP.getArgNo()));
+  }
+  static bool isEqual(const IRPosition &LHS, const IRPosition &RHS) {
+    return LHS == RHS;
+  }
+};
+
+/// A visitor class for IR positions.
+///
+/// Given a position P, the SubsumingPositionIterator allows to visit "subsuming
+/// positions" wrt. attributes/information. Thus, if a piece of information
+/// holds for a subsuming position, it also holds for the position P.
+///
+/// The subsuming positions always include the initial position and then,
+/// depending on the position kind, additionally the following ones:
+/// - for IRP_RETURNED:
+///   - the function (IRP_FUNCTION)
+/// - for IRP_ARGUMENT:
+///   - the function (IRP_FUNCTION)
+/// - for IRP_CALL_SITE:
+///   - the callee (IRP_FUNCTION), if known
+/// - for IRP_CALL_SITE_RETURNED:
+///   - the callee (IRP_RETURNED), if known
+///   - the call site (IRP_FUNCTION)
+///   - the callee (IRP_FUNCTION), if known
+/// - for IRP_CALL_SITE_ARGUMENT:
+///   - the argument of the callee (IRP_ARGUMENT), if known
+///   - the callee (IRP_FUNCTION), if known
+///   - the position the call site argument is associated with if it is not
+///     anchored to the call site, e.g., if it is an arugment then the argument
+///     (IRP_ARGUMENT)
+class SubsumingPositionIterator {
+  SmallVector<IRPosition, 4> IRPositions;
+  using iterator = decltype(IRPositions)::iterator;
+
+public:
+  SubsumingPositionIterator(const IRPosition &IRP);
+  iterator begin() { return IRPositions.begin(); }
+  iterator end() { return IRPositions.end(); }
+};
+
 /// Data structure to hold cached (LLVM-IR) information.
 ///
 /// All attributes are given an InformationCache object at creation time to
@@ -212,10 +574,11 @@ struct Attributor {
   /// \Returns CHANGED if the IR was changed, otherwise UNCHANGED.
   ChangeStatus run();
 
-  /// Lookup an abstract attribute of type \p AAType anchored at value \p V and
-  /// argument number \p ArgNo. If no attribute is found and \p V is a call base
-  /// instruction, the called function is tried as a value next. Thus, the
-  /// returned abstract attribute might be anchored at the callee of \p V.
+  /// Lookup an abstract attribute of type \p AAType at position \p IRP. While
+  /// no abstract attribute is found equivalent positions are checked, see
+  /// SubsumingPositionIterator. Thus, the returned abstract attribute
+  /// might be anchored at a different position, e.g., the callee if \p IRP is a
+  /// call base.
   ///
   /// This method is the only (supported) way an abstract attribute can retrieve
   /// information from another abstract attribute. As an example, take an
@@ -225,46 +588,30 @@ struct Attributor {
   /// the one reasoning about the "captured" state for the argument or the one
   /// reasoning on the memory access behavior of the function as a whole.
   template <typename AAType>
-  const AAType *getAAFor(const AbstractAttribute &QueryingAA, const Value &V,
-                         int ArgNo = -1) {
+  const AAType *getAAFor(const AbstractAttribute &QueryingAA,
+                         const IRPosition &IRP) {
     static_assert(std::is_base_of<AbstractAttribute, AAType>::value,
                   "Cannot query an attribute with a type not derived from "
                   "'AbstractAttribute'!");
 
-    // Determine the argument number automatically for llvm::Arguments if none
-    // is set. Do not override a given one as it could be a use of the argument
-    // in a call site.
-    if (ArgNo == -1)
-      if (auto *Arg = dyn_cast<Argument>(&V))
-        ArgNo = Arg->getArgNo();
-
-    // If a function was given together with an argument number, perform the
-    // lookup for the actual argument instead. Don't do it for variadic
-    // arguments.
-    if (ArgNo >= 0 && isa<Function>(&V) &&
-        cast<Function>(&V)->arg_size() > (size_t)ArgNo)
-      return getAAFor<AAType>(
-          QueryingAA, *(cast<Function>(&V)->arg_begin() + ArgNo), ArgNo);
-
-    // 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({&V, ArgNo});
-    if (AAType *AA = static_cast<AAType *>(
-            KindToAbstractAttributeMap.lookup(&AAType::ID))) {
-      // Do not return an attribute with an invalid state. This minimizes checks
-      // at the calls sites and allows the fallback below to kick in.
-      if (AA->getState().isValidState()) {
-        QueryMap[AA].insert(const_cast<AbstractAttribute *>(&QueryingAA));
-        return AA;
+    // Let's try an equivalent position if available, see
+    // SubsumingPositionIterator for more information.
+    for (const IRPosition &EquivIRP : SubsumingPositionIterator(IRP)) {
+      // 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<IRPosition &>(EquivIRP));
+      if (AAType *AA = static_cast<AAType *>(
+              KindToAbstractAttributeMap.lookup(&AAType::ID))) {
+        // Do not return an attribute with an invalid state. This minimizes
+        // checks at the calls sites and allows the fallback below to kick in.
+        if (AA->getState().isValidState()) {
+          QueryMap[AA].insert(const_cast<AbstractAttribute *>(&QueryingAA));
+          return AA;
+        }
       }
     }
 
-    // If no abstract attribute was found and we look for a call site argument,
-    // defer to the actual argument instead.
-    ImmutableCallSite ICS(&V);
-    if (ICS && ICS.getCalledValue())
-      return getAAFor<AAType>(QueryingAA, *ICS.getCalledValue(), ArgNo);
-
     // No matching attribute found
     return nullptr;
   }
@@ -274,27 +621,16 @@ struct Attributor {
   /// Note that ownership of the attribute is given to the Attributor. It will
   /// invoke delete for the Attributor on destruction of the Attributor.
   ///
-  /// Attributes are identified by
-  ///  (1) their anchored value (see AA.getAnchoredValue()),
-  ///  (2) their argument number (\p ArgNo, or Argument::getArgNo()), and
-  ///  (3) the address of their static member (see AAType::ID).
-  template <typename AAType> AAType &registerAA(AAType &AA, int ArgNo = -1) {
+  /// Attributes are identified by their IR position (AAType::getIRPosition())
+  /// and the address of their static member (see AAType::ID).
+  template <typename AAType> AAType &registerAA(AAType &AA) {
     static_assert(std::is_base_of<AbstractAttribute, AAType>::value,
                   "Cannot register an attribute with a type not derived from "
                   "'AbstractAttribute'!");
-
-    // Determine the anchor value and the argument number which are used to
-    // lookup the attribute together with AAType::ID. If passed an argument,
-    // use its argument number but do not override a given one as it could be a
-    // use of the argument at a call site.
-    Value &AnchorVal = AA.getIRPosition().getAnchorValue();
-    if (ArgNo == -1)
-      if (auto *Arg = dyn_cast<Argument>(&AnchorVal))
-        ArgNo = Arg->getArgNo();
-
     // Put the attribute in the lookup map structure and the container we use to
     // keep track of all attributes.
-    AAMap[{&AnchorVal, ArgNo}][&AAType::ID] = &AA;
+    IRPosition &IRP = AA.getIRPosition();
+    AAMap[IRP][&AAType::ID] = &AA;
     AllAbstractAttributes.push_back(&AA);
     return AA;
   }
@@ -321,34 +657,33 @@ struct Attributor {
   /// This method will evaluate \p Pred on call sites and return
   /// true if \p Pred holds in every call sites. However, this is only possible
   /// all call sites are known, hence the function has internal linkage.
-  bool checkForAllCallSites(Function &F, std::function<bool(CallSite)> &Pred,
+  bool checkForAllCallSites(const function_ref<bool(CallSite)> &Pred,
                             const AbstractAttribute &QueryingAA,
                             bool RequireAllCallSites);
 
   /// Check \p Pred on all values potentially returned by \p F.
   ///
   /// This method will evaluate \p Pred on all values potentially returned by
-  /// \p F associated to their respective return instructions. Return true if
-  /// \p Pred holds on all of them.
+  /// the function associated with \p QueryingAA. The returned values are
+  /// matched with their respective return instructions. Returns true if \p Pred
+  /// holds on all of them.
   bool checkForAllReturnedValuesAndReturnInsts(
-      const Function &F,
       const function_ref<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)>
           &Pred,
       const AbstractAttribute &QueryingAA);
 
-  /// Check \p Pred on all values potentially returned by \p F.
+  /// Check \p Pred on all values potentially returned by the function
+  /// associated with \p QueryingAA.
   ///
   /// This is the context insensitive version of the method above.
-  bool checkForAllReturnedValues(const Function &F,
-                                 const function_ref<bool(Value &)> &Pred,
+  bool checkForAllReturnedValues(const function_ref<bool(Value &)> &Pred,
                                  const AbstractAttribute &QueryingAA);
 
   /// Check \p Pred on all instructions with an opcode present in \p Opcodes.
   ///
   /// This method will evaluate \p Pred on all instructions with an opcode
   /// present in \p Opcode and return true if \p Pred holds on all of them.
-  bool checkForAllInstructions(const Function &F,
-                               const function_ref<bool(Instruction &)> &Pred,
+  bool checkForAllInstructions(const function_ref<bool(Instruction &)> &Pred,
                                const AbstractAttribute &QueryingAA,
                                const ArrayRef<unsigned> &Opcodes);
 
@@ -356,10 +691,9 @@ struct Attributor {
   ///
   /// See checkForAllCallLikeInstructions(...) for more information.
   bool
-  checkForAllCallLikeInstructions(const Function &F,
-                                  const function_ref<bool(Instruction &)> &Pred,
+  checkForAllCallLikeInstructions(const function_ref<bool(Instruction &)> &Pred,
                                   const AbstractAttribute &QueryingAA) {
-    return checkForAllInstructions(F, Pred, QueryingAA,
+    return checkForAllInstructions(Pred, QueryingAA,
                                    {(unsigned)Instruction::Invoke,
                                     (unsigned)Instruction::CallBr,
                                     (unsigned)Instruction::Call});
@@ -371,7 +705,7 @@ struct Attributor {
   /// to memory present in the information cache and return true if \p Pred
   /// holds on all of them.
   bool checkForAllReadWriteInstructions(
-      const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred,
+      const llvm::function_ref<bool(Instruction &)> &Pred,
       AbstractAttribute &QueryingAA);
 
   /// Return the data layout associated with the anchor scope.
@@ -384,13 +718,13 @@ private:
   AAVector AllAbstractAttributes;
   ///}
 
-  /// A nested map to lookup abstract attributes based on the anchored value and
-  /// an argument positions (or -1) on the outer level, and the addresses of the
-  /// static member (AAType::ID) on the inner level.
+  /// A nested map to lookup abstract attributes based on the argument position
+  /// on the outer level, and the addresses of the static member (AAType::ID) on
+  /// the inner level.
   ///{
   using KindToAbstractAttributeMap =
       DenseMap<const char *, AbstractAttribute *>;
-  DenseMap<std::pair<const Value *, int>, KindToAbstractAttributeMap> AAMap;
+  DenseMap<IRPosition, KindToAbstractAttributeMap> AAMap;
   ///}
 
   /// A map from abstract attributes to the ones that queried them through calls
@@ -560,142 +894,6 @@ struct BooleanState : public IntegerStat
   BooleanState() : IntegerState(1){};
 };
 
-/// Struct to encode the position in the LLVM-IR with regards to the associated
-/// value but also the attribute lists.
-struct IRPosition {
-
-  /// The positions attributes can be manifested in.
-  enum Kind {
-    IRP_FUNCTION = AttributeList::FunctionIndex, ///< An attribute for a
-                                                 ///< function as a whole.
-    IRP_RETURNED = AttributeList::ReturnIndex,   ///< An attribute for the
-                                                 ///< function return value.
-    IRP_ARGUMENT,           ///< An attribute for a function argument.
-    IRP_CALL_SITE_ARGUMENT, ///< An attribute for a call site argument.
-  };
-
-  /// Create an IRPosition for an argument.
-  explicit IRPosition(Argument &Arg) : IRPosition(&Arg, Arg, Arg.getArgNo()) {}
-
-  /// Create an IRPosition for a function return or function body position.
-  ///
-  /// \param Fn The value this abstract attributes is anchored at and
-  ///            associated with.
-  /// \param PK  The kind of attribute position, can not be a (call site)
-  ///            argument.
-  explicit IRPosition(Function &Fn, Kind PK)
-      : AssociatedVal(&Fn), AnchorVal(Fn), AttributeIdx(PK) {
-    assert((PK == IRP_RETURNED || PK == IRP_FUNCTION) &&
-           "Expected non-argument position!");
-  }
-
-  /// An abstract attribute associated with \p AssociatedVal and anchored at
-  /// \p AnchorVal.
-  ///
-  /// \param AssociatedVal The value this abstract attribute is associated with.
-  /// \param AnchorVal The value this abstract attributes is anchored at.
-  /// \param ArgumentNo The index in the attribute list, encodes also the
-  ///                     argument number if this is one.
-  explicit IRPosition(Value *AssociatedVal, Value &AnchorVal,
-                      unsigned ArgumentNo)
-      : AssociatedVal(AssociatedVal), AnchorVal(AnchorVal),
-        AttributeIdx(ArgumentNo + AttributeList::FirstArgIndex) {
-    assert(((isa<CallBase>(&AnchorVal) &&
-             cast<CallBase>(&AnchorVal)->arg_size() > ArgumentNo) ||
-            (isa<Argument>(AnchorVal) &&
-             cast<Argument>(AnchorVal).getArgNo() == ArgumentNo)) &&
-           "Expected a valid argument index!");
-  }
-
-#define IRPositionConstructorForward(NAME, BASE)                               \
-  explicit NAME(Argument &Arg) : BASE(Arg) {}                                  \
-  explicit NAME(Function &Fn, IRPosition::Kind PK) : BASE(Fn, PK) {}           \
-  NAME(Value *AssociatedVal, Value &AnchorVal, unsigned ArgumentNo)            \
-      : BASE(AssociatedVal, AnchorVal, ArgumentNo) {}
-
-  IRPosition(const IRPosition &AAP)
-      : IRPosition(AAP.AssociatedVal, AAP.AnchorVal, AAP.AttributeIdx) {}
-
-  /// Virtual destructor.
-  virtual ~IRPosition() {}
-
-  /// Return the value this abstract attribute is anchored with.
-  ///
-  /// The anchored value might not be the associated value if the latter is not
-  /// sufficient to determine where arguments will be manifested. This is mostly
-  /// the case for call site arguments as the value is not sufficient to
-  /// pinpoint them. Instead, we can use the call site as an anchor.
-  ///
-  ///{
-  Value &getAnchorValue() { return AnchorVal; }
-  const Value &getAnchorValue() const { return AnchorVal; }
-  ///}
-
-  /// Return the llvm::Function surrounding the anchored value.
-  ///
-  ///{
-  Function &getAnchorScope() {
-    Value &V = getAnchorValue();
-    if (isa<Function>(V))
-      return cast<Function>(V);
-    if (isa<Argument>(V))
-      return *cast<Argument>(V).getParent();
-    if (isa<Instruction>(V))
-      return *cast<Instruction>(V).getFunction();
-    llvm_unreachable("No scope for anchored value found!");
-  }
-  const Function &getAnchorScope() const {
-    return const_cast<IRPosition *>(this)->getAnchorScope();
-  }
-  ///}
-
-  /// Return the value this abstract attribute is associated with.
-  ///
-  /// The abstract state usually represents this value.
-  ///
-  ///{
-  Value *getAssociatedValue() { return AssociatedVal; }
-  const Value *getAssociatedValue() const { return AssociatedVal; }
-  ///}
-
-  /// Return the argument number of the associated value if it is an argument or
-  /// call site argument, otherwise a negative value.
-  int getArgNo() const { return AttributeIdx - AttributeList::FirstArgIndex; }
-
-  /// Return the position this abstract state is manifested in.
-  Kind getPositionKind() const {
-    if (getArgNo() >= 0) {
-      if (isa<CallBase>(getAnchorValue()))
-        return IRP_CALL_SITE_ARGUMENT;
-      assert((isa<Argument>(getAnchorValue()) ||
-              isa_and_nonnull<Argument>(getAssociatedValue()) ||
-              (!getAssociatedValue() && isa<Function>(getAnchorValue()))) &&
-             "Expected argument or call base due to argument number!");
-      return IRP_ARGUMENT;
-    }
-    return (Kind)AttributeIdx;
-  }
-
-  /// Return the index in the attribute list for this position.
-  int getAttrIdx() const { return AttributeIdx; }
-
-  /// Change the associated value.
-  void setAssociatedValue(Value *V) { AssociatedVal = V; }
-
-  /// Change the associated attribue list position.
-  void setAttributeIdx(int AttrIdx) { AttributeIdx = AttrIdx; }
-
-protected:
-  /// The value this abstract attribute is associated with.
-  Value *AssociatedVal;
-
-  /// The value this abstract attribute is anchored at.
-  Value &AnchorVal;
-
-  /// The index in the attribute list.
-  int AttributeIdx;
-};
-
 /// Helper struct necessary as the modular build fails if the virtual method
 /// IRAttribute::manifest is defined in the Attributor.cpp.
 struct IRAttributeManifest {
@@ -719,18 +917,13 @@ struct StateWrapper : public StateTy, pu
 /// Helper class that provides common functionality to manifest IR attributes.
 template <Attribute::AttrKind AK, typename Base>
 struct IRAttribute : public IRPosition, public Base {
+  IRAttribute(const IRPosition &IRP) : IRPosition(IRP) {}
   ~IRAttribute() {}
 
-  /// Constructors for the IRPosition.
-  ///
-  ///{
-  IRPositionConstructorForward(IRAttribute, IRPosition);
-  ///}
-
   /// See AbstractAttribute::manifest(...).
-  ChangeStatus manifest(Attributor &A) {
+  ChangeStatus manifest(Attributor &A) override {
     SmallVector<Attribute, 4> DeducedAttrs;
-    getDeducedAttributes(getAnchorScope().getContext(), DeducedAttrs);
+    getDeducedAttributes(getAnchorValue().getContext(), DeducedAttrs);
     return IRAttributeManifest::manifestAttrs(A, getIRPosition(), DeducedAttrs);
   }
 
@@ -746,8 +939,8 @@ struct IRAttribute : public IRPosition,
   /// Return an IR position, see struct IRPosition.
   ///
   ///{
-  IRPosition &getIRPosition() { return *this; }
-  const IRPosition &getIRPosition() const { return *this; }
+  IRPosition &getIRPosition() override { return *this; }
+  const IRPosition &getIRPosition() const override { return *this; }
   ///}
 };
 
@@ -890,7 +1083,7 @@ Pass *createAttributorLegacyPass();
 /// An abstract attribute for the returned values of a function.
 struct AAReturnedValues
     : public IRAttribute<Attribute::Returned, AbstractAttribute> {
-  IRPositionConstructorForward(AAReturnedValues, IRAttribute);
+  AAReturnedValues(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Check \p Pred on all returned values.
   ///
@@ -911,7 +1104,7 @@ struct AAReturnedValues
 struct AANoUnwind
     : public IRAttribute<Attribute::NoUnwind,
                          StateWrapper<BooleanState, AbstractAttribute>> {
-  IRPositionConstructorForward(AANoUnwind, IRAttribute);
+  AANoUnwind(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Returns true if nounwind is assumed.
   bool isAssumedNoUnwind() const { return getAssumed(); }
@@ -926,7 +1119,7 @@ struct AANoUnwind
 struct AANoSync
     : public IRAttribute<Attribute::NoSync,
                          StateWrapper<BooleanState, AbstractAttribute>> {
-  IRPositionConstructorForward(AANoSync, IRAttribute);
+  AANoSync(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Returns true if "nosync" is assumed.
   bool isAssumedNoSync() const { return getAssumed(); }
@@ -942,7 +1135,7 @@ struct AANoSync
 struct AANonNull
     : public IRAttribute<Attribute::NonNull,
                          StateWrapper<BooleanState, AbstractAttribute>> {
-  IRPositionConstructorForward(AANonNull, IRAttribute);
+  AANonNull(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Return true if we assume that the underlying value is nonnull.
   bool isAssumedNonNull() const { return getAssumed(); }
@@ -958,7 +1151,7 @@ struct AANonNull
 struct AANoRecurse
     : public IRAttribute<Attribute::NoRecurse,
                          StateWrapper<BooleanState, AbstractAttribute>> {
-  IRPositionConstructorForward(AANoRecurse, IRAttribute);
+  AANoRecurse(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Return true if "norecurse" is assumed.
   bool isAssumedNoRecurse() const { return getAssumed(); }
@@ -974,7 +1167,7 @@ struct AANoRecurse
 struct AAWillReturn
     : public IRAttribute<Attribute::WillReturn,
                          StateWrapper<BooleanState, AbstractAttribute>> {
-  IRPositionConstructorForward(AAWillReturn, IRAttribute);
+  AAWillReturn(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Return true if "willreturn" is assumed.
   bool isAssumedWillReturn() const { return getAssumed(); }
@@ -990,7 +1183,7 @@ struct AAWillReturn
 struct AANoAlias
     : public IRAttribute<Attribute::NoAlias,
                          StateWrapper<BooleanState, AbstractAttribute>> {
-  IRPositionConstructorForward(AANoAlias, IRAttribute);
+  AANoAlias(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Return true if we assume that the underlying value is alias.
   bool isAssumedNoAlias() const { return getAssumed(); }
@@ -1006,7 +1199,7 @@ struct AANoAlias
 struct AANoFree
     : public IRAttribute<Attribute::NoFree,
                          StateWrapper<BooleanState, AbstractAttribute>> {
-  IRPositionConstructorForward(AANoFree, IRAttribute);
+  AANoFree(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Return true if "nofree" is assumed.
   bool isAssumedNoFree() const { return getAssumed(); }
@@ -1022,7 +1215,7 @@ struct AANoFree
 struct AANoReturn
     : public IRAttribute<Attribute::NoReturn,
                          StateWrapper<BooleanState, AbstractAttribute>> {
-  IRPositionConstructorForward(AANoReturn, IRAttribute);
+  AANoReturn(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Return true if the underlying object is assumed to never return.
   bool isAssumedNoReturn() const { return getAssumed(); }
@@ -1037,7 +1230,7 @@ struct AANoReturn
 /// An abstract interface for liveness abstract attribute.
 struct AAIsDead : public StateWrapper<BooleanState, AbstractAttribute>,
                   public IRPosition {
-  IRPositionConstructorForward(AAIsDead, IRPosition);
+  AAIsDead(const IRPosition &IRP) : IRPosition(IRP) {}
 
   /// Returns true if \p BB is assumed dead.
   virtual bool isAssumedDead(const BasicBlock *BB) const = 0;
@@ -1079,7 +1272,7 @@ struct AAIsDead : public StateWrapper<Bo
 /// An abstract interface for all dereferenceable attribute.
 struct AADereferenceable
     : public IRAttribute<Attribute::Dereferenceable, AbstractAttribute> {
-  IRPositionConstructorForward(AADereferenceable, IRAttribute);
+  AADereferenceable(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Return true if we assume that the underlying value is nonnull.
   virtual bool isAssumedNonNull() const = 0;
@@ -1109,7 +1302,7 @@ struct AADereferenceable
 struct AAAlign
     : public IRAttribute<Attribute::Alignment,
                          StateWrapper<IntegerState, AbstractAttribute>> {
-  IRPositionConstructorForward(AAAlign, IRAttribute);
+  AAAlign(const IRPosition &IRP) : IRAttribute(IRP) {}
 
   /// Return assumed alignment.
   unsigned getAssumedAlign() const { return getAssumed(); }

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=368919&r1=368918&r2=368919&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Wed Aug 14 14:18:01 2019
@@ -265,13 +265,9 @@ ChangeStatus AbstractAttribute::update(A
 ChangeStatus
 IRAttributeManifest::manifestAttrs(Attributor &A, IRPosition &IRP,
                                    const ArrayRef<Attribute> &DeducedAttrs) {
-  assert(IRP.getAssociatedValue() &&
-         "Attempted to manifest an attribute without associated value!");
-
   ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
 
-  Function &ScopeFn = IRP.getAnchorScope();
-  LLVMContext &Ctx = ScopeFn.getContext();
+  Function *ScopeFn = IRP.getAssociatedFunction();
   IRPosition::Kind PK = IRP.getPositionKind();
 
   // In the following some generic code that will manifest attributes in
@@ -280,16 +276,22 @@ IRAttributeManifest::manifestAttrs(Attri
 
   AttributeList Attrs;
   switch (PK) {
+  case IRPosition::IRP_INVALID:
+  case IRPosition::IRP_FLOAT:
+    llvm_unreachable("Cannot manifest at a floating or invalid position!");
   case IRPosition::IRP_ARGUMENT:
   case IRPosition::IRP_FUNCTION:
   case IRPosition::IRP_RETURNED:
-    Attrs = ScopeFn.getAttributes();
+    Attrs = ScopeFn->getAttributes();
     break;
+  case IRPosition::IRP_CALL_SITE:
+  case IRPosition::IRP_CALL_SITE_RETURNED:
   case IRPosition::IRP_CALL_SITE_ARGUMENT:
     Attrs = ImmutableCallSite(&IRP.getAnchorValue()).getAttributes();
     break;
   }
 
+  LLVMContext &Ctx = IRP.getAnchorValue().getContext();
   for (const Attribute &Attr : DeducedAttrs) {
     if (!addIfNotExistent(Ctx, Attr, Attrs, IRP.getAttrIdx()))
       continue;
@@ -304,19 +306,147 @@ IRAttributeManifest::manifestAttrs(Attri
   case IRPosition::IRP_ARGUMENT:
   case IRPosition::IRP_FUNCTION:
   case IRPosition::IRP_RETURNED:
-    ScopeFn.setAttributes(Attrs);
+    ScopeFn->setAttributes(Attrs);
     break;
+  case IRPosition::IRP_CALL_SITE:
+  case IRPosition::IRP_CALL_SITE_RETURNED:
   case IRPosition::IRP_CALL_SITE_ARGUMENT:
     CallSite(&IRP.getAnchorValue()).setAttributes(Attrs);
+  case IRPosition::IRP_FLOAT:
+  case IRPosition::IRP_INVALID:
+    break;
   }
 
   return HasChanged;
 }
 
+const IRPosition IRPosition::EmptyKey(255);
+const IRPosition IRPosition::TombstoneKey(256);
+
+SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) {
+  IRPositions.emplace_back(IRP);
+
+  ImmutableCallSite ICS(&IRP.getAnchorValue());
+  switch (IRP.getPositionKind()) {
+  case IRPosition::IRP_INVALID:
+  case IRPosition::IRP_FLOAT:
+  case IRPosition::IRP_FUNCTION:
+    return;
+  case IRPosition::IRP_ARGUMENT:
+  case IRPosition::IRP_RETURNED:
+    IRPositions.emplace_back(
+        IRPosition::function(*IRP.getAssociatedFunction()));
+    return;
+  case IRPosition::IRP_CALL_SITE:
+    assert(ICS && "Expected call site!");
+    // TODO: We need to look at the operand bundles similar to the redirection
+    //       in CallBase.
+    if (!ICS.hasOperandBundles())
+      if (const Function *Callee = ICS.getCalledFunction())
+        IRPositions.emplace_back(IRPosition::function(*Callee));
+    return;
+  case IRPosition::IRP_CALL_SITE_RETURNED:
+    assert(ICS && "Expected call site!");
+    // TODO: We need to look at the operand bundles similar to the redirection
+    //       in CallBase.
+    if (!ICS.hasOperandBundles()) {
+      if (const Function *Callee = ICS.getCalledFunction()) {
+        IRPositions.emplace_back(IRPosition::returned(*Callee));
+        IRPositions.emplace_back(IRPosition::function(*Callee));
+      }
+    }
+    IRPositions.emplace_back(
+        IRPosition::callsite_function(cast<CallBase>(*ICS.getInstruction())));
+    return;
+  case IRPosition::IRP_CALL_SITE_ARGUMENT: {
+    int ArgNo = IRP.getArgNo();
+    assert(ICS && ArgNo >= 0 && "Expected call site!");
+    // TODO: We need to look at the operand bundles similar to the redirection
+    //       in CallBase.
+    if (!ICS.hasOperandBundles()) {
+      const Function *Callee = ICS.getCalledFunction();
+      if (Callee && Callee->arg_size() > unsigned(ArgNo))
+        IRPositions.emplace_back(IRPosition::argument(*Callee->getArg(ArgNo)));
+      if (Callee)
+        IRPositions.emplace_back(IRPosition::function(*Callee));
+    }
+    IRPositions.emplace_back(IRPosition::value(IRP.getAssociatedValue()));
+    return;
+  }
+  }
+}
+
+bool IRPosition::hasAttr(ArrayRef<Attribute::AttrKind> AKs) const {
+  for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this))
+    for (Attribute::AttrKind AK : AKs)
+      if (EquivIRP.getAttr(AK).getKindAsEnum() == AK)
+        return true;
+  return false;
+}
+
+void IRPosition::getAttrs(ArrayRef<Attribute::AttrKind> AKs,
+                          SmallVectorImpl<Attribute> &Attrs) const {
+  for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this))
+    for (Attribute::AttrKind AK : AKs) {
+      const Attribute &Attr = EquivIRP.getAttr(AK);
+      if (Attr.getKindAsEnum() == AK)
+        Attrs.push_back(Attr);
+    }
+}
+
+void IRPosition::verify() {
+  switch (KindOrArgNo) {
+  default:
+    assert(KindOrArgNo >= 0 && "Expected argument or call site argument!");
+    assert((isa<CallBase>(AnchorVal) || isa<Argument>(AnchorVal)) &&
+           "Expected call base or argument for positive attribute index!");
+    if (auto *Arg = dyn_cast<Argument>(AnchorVal)) {
+      assert(Arg->getArgNo() == unsigned(getArgNo()) &&
+             "Argument number mismatch!");
+      assert(Arg == &getAssociatedValue() && "Associated value mismatch!");
+    } else {
+      auto &CB = cast<CallBase>(*AnchorVal);
+      assert(CB.arg_size() > unsigned(getArgNo()) &&
+             "Call site argument number mismatch!");
+      assert(CB.getArgOperand(getArgNo()) == &getAssociatedValue() &&
+             "Associated value mismatch!");
+    }
+    break;
+  case IRP_INVALID:
+    assert(!AnchorVal && "Expected no value for an invalid position!");
+    break;
+  case IRP_FLOAT:
+    assert((!isa<CallBase>(&getAssociatedValue()) &&
+            !isa<Argument>(&getAssociatedValue())) &&
+           "Expected specialized kind for call base and argument values!");
+    break;
+  case IRP_RETURNED:
+    assert(isa<Function>(AnchorVal) &&
+           "Expected function for a 'returned' position!");
+    assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!");
+    break;
+  case IRP_CALL_SITE_RETURNED:
+    assert((isa<CallBase>(AnchorVal)) &&
+           "Expected call base for 'call site returned' position!");
+    assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!");
+    break;
+  case IRP_CALL_SITE:
+    assert((isa<CallBase>(AnchorVal)) &&
+           "Expected call base for 'call site function' position!");
+    assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!");
+    break;
+  case IRP_FUNCTION:
+    assert(isa<Function>(AnchorVal) &&
+           "Expected function for a 'function' position!");
+    assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!");
+    break;
+  }
+}
+
 /// -----------------------NoUnwind Function Attribute--------------------------
 
 struct AANoUnwindImpl : AANoUnwind {
-  IRPositionConstructorForward(AANoUnwindImpl, AANoUnwind);
+  AANoUnwindImpl(const IRPosition &IRP) : AANoUnwind(IRP) {}
 
   const std::string getAsStr() const override {
     return getAssumed() ? "nounwind" : "may-unwind";
@@ -327,7 +457,7 @@ struct AANoUnwindImpl : AANoUnwind {
 };
 
 struct AANoUnwindFunction final : public AANoUnwindImpl {
-  AANoUnwindFunction(Function &F) : AANoUnwindImpl(F, IRP_FUNCTION) {}
+  AANoUnwindFunction(const IRPosition &IRP) : AANoUnwindImpl(IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override {
@@ -336,7 +466,6 @@ struct AANoUnwindFunction final : public
 };
 
 ChangeStatus AANoUnwindImpl::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
 
   // The map from instruction opcodes to those instructions in the function.
   auto Opcodes = {
@@ -348,11 +477,11 @@ ChangeStatus AANoUnwindImpl::updateImpl(
     if (!I.mayThrow())
       return true;
 
-    auto *NoUnwindAA = A.getAAFor<AANoUnwind>(*this, I);
+    auto *NoUnwindAA = A.getAAFor<AANoUnwind>(*this, IRPosition::value(I));
     return NoUnwindAA && NoUnwindAA->isAssumedNoUnwind();
   };
 
-  if (!A.checkForAllInstructions(F, CheckForNoUnwind, *this, Opcodes))
+  if (!A.checkForAllInstructions(CheckForNoUnwind, *this, Opcodes))
     return indicatePessimisticFixpoint();
 
   return ChangeStatus::UNCHANGED;
@@ -405,12 +534,11 @@ class AAReturnedValuesImpl : public AARe
   }
 
 public:
-  IRPositionConstructorForward(AAReturnedValuesImpl, AAReturnedValues);
+  AAReturnedValuesImpl(const IRPosition &IRP) : AAReturnedValues(IRP) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
     // Reset the state.
-    setAssociatedValue(nullptr);
     IsFixed = false;
     IsValidState = true;
     HasOverdefinedReturnedCalls = false;
@@ -494,8 +622,7 @@ public:
 };
 
 struct AAReturnedValuesFunction final : public AAReturnedValuesImpl {
-  AAReturnedValuesFunction(Function &F)
-      : AAReturnedValuesImpl(F, IRP_FUNCTION) {}
+  AAReturnedValuesFunction(const IRPosition &IRP) : AAReturnedValuesImpl(IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override {
@@ -523,8 +650,7 @@ ChangeStatus AAReturnedValuesImpl::manif
 
   // If the assumed unique return value is an argument, annotate it.
   if (auto *UniqueRVArg = dyn_cast<Argument>(UniqueRV.getValue())) {
-    setAssociatedValue(UniqueRVArg);
-    setAttributeIdx(UniqueRVArg->getArgNo() + AttributeList::FirstArgIndex);
+    getIRPosition() = IRPosition::argument(*UniqueRVArg);
     Changed = IRAttribute::manifest(A) | Changed;
   }
 
@@ -563,7 +689,7 @@ AAReturnedValuesImpl::getAssumedUniqueRe
     return true;
   };
 
-  if (!A.checkForAllReturnedValues(getAnchorScope(), Pred, *this))
+  if (!A.checkForAllReturnedValues(Pred, *this))
     UniqueRV = nullptr;
 
   return UniqueRV;
@@ -608,7 +734,7 @@ ChangeStatus AAReturnedValuesImpl::updat
   // Keep track of any change to trigger updates on dependent attributes.
   ChangeStatus Changed = ChangeStatus::UNCHANGED;
 
-  auto *LivenessAA = A.getAAFor<AAIsDead>(*this, getAnchorScope());
+  auto *LivenessAA = A.getAAFor<AAIsDead>(*this, getIRPosition());
 
   // Look at all returned call sites.
   for (auto &It : ReturnedValues) {
@@ -637,7 +763,8 @@ ChangeStatus AAReturnedValuesImpl::updat
     }
 
     // Try to find a assumed unique return value for the called function.
-    auto *RetCSAA = A.getAAFor<AAReturnedValuesImpl>(*this, *RV);
+    auto *RetCSAA = A.getAAFor<AAReturnedValuesImpl>(
+        *this, IRPosition::callsite_returned(RetCS));
     if (!RetCSAA) {
       if (!HasOverdefinedReturnedCalls)
         Changed = ChangeStatus::CHANGED;
@@ -653,9 +780,9 @@ ChangeStatus AAReturnedValuesImpl::updat
 
     // If no assumed unique return value was found due to the lack of
     // candidates, we may need to resolve more calls (through more update
-    // iterations) or the called function will not return. Either way, we simply
-    // stick with the call sites as return values. Because there were not
-    // multiple possibilities, we do not treat it as overdefined.
+    // iterations) or the called function will not return. Either way, we
+    // simply stick with the call sites as return values. Because there were
+    // not multiple possibilities, we do not treat it as overdefined.
     if (!AssumedUniqueRV.hasValue())
       continue;
 
@@ -682,8 +809,9 @@ ChangeStatus AAReturnedValuesImpl::updat
 
     // If the assumed unique return value is an argument, lookup the matching
     // call site operand and recursively collect new returned values.
-    // If it is not an argument, it is just put into the set of returned values
-    // as we would have already looked through casts, phis, and similar values.
+    // If it is not an argument, it is just put into the set of returned
+    // values as we would have already looked through casts, phis, and similar
+    // values.
     if (Argument *AssumedRetArg = dyn_cast<Argument>(AssumedRetVal))
       collectValuesRecursively(A,
                                RetCS.getArgOperand(AssumedRetArg->getArgNo()),
@@ -715,7 +843,7 @@ ChangeStatus AAReturnedValuesImpl::updat
 /// ------------------------ NoSync Function Attribute -------------------------
 
 struct AANoSyncImpl : AANoSync {
-  IRPositionConstructorForward(AANoSyncImpl, AANoSync);
+  AANoSyncImpl(const IRPosition &IRP) : AANoSync(IRP) {}
 
   const std::string getAsStr() const override {
     return getAssumed() ? "nosync" : "may-sync";
@@ -738,7 +866,7 @@ struct AANoSyncImpl : AANoSync {
 };
 
 struct AANoSyncFunction final : public AANoSyncImpl {
-  AANoSyncFunction(Function &F) : AANoSyncImpl(F, IRP_FUNCTION) {}
+  AANoSyncFunction(const IRPosition &IRP) : AANoSyncImpl(IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override { STATS_DECL_AND_TRACK_FN_ATTR(nosync) }
@@ -834,24 +962,24 @@ bool AANoSyncImpl::isVolatile(Instructio
 }
 
 ChangeStatus AANoSyncImpl::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
 
   auto CheckRWInstForNoSync = [&](Instruction &I) {
     /// We are looking for volatile instructions or Non-Relaxed atomics.
     /// FIXME: We should ipmrove the handling of intrinsics.
 
-    ImmutableCallSite ICS(&I);
-    auto *NoSyncAA = A.getAAFor<AANoSyncImpl>(*this, I);
-
     if (isa<IntrinsicInst>(&I) && isNoSyncIntrinsic(&I))
       return true;
 
-    if (ICS && (!NoSyncAA || !NoSyncAA->isAssumedNoSync()) &&
-        !ICS.hasFnAttr(Attribute::NoSync))
-      return false;
+    if (ImmutableCallSite ICS = ImmutableCallSite(&I)) {
+      if (ICS.hasFnAttr(Attribute::NoSync))
+        return true;
 
-    if (ICS)
-      return true;
+      auto *NoSyncAA =
+          A.getAAFor<AANoSyncImpl>(*this, IRPosition::callsite_function(ICS));
+      if (NoSyncAA && NoSyncAA->isAssumedNoSync())
+        return true;
+      return false;
+    }
 
     if (!isVolatile(&I) && !isNonRelaxedAtomic(&I))
       return true;
@@ -869,8 +997,8 @@ ChangeStatus AANoSyncImpl::updateImpl(At
     return !ImmutableCallSite(&I).isConvergent();
   };
 
-  if (!A.checkForAllReadWriteInstructions(F, CheckRWInstForNoSync, *this) ||
-      !A.checkForAllCallLikeInstructions(F, CheckForNoSync, *this))
+  if (!A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *this) ||
+      !A.checkForAllCallLikeInstructions(CheckForNoSync, *this))
     return indicatePessimisticFixpoint();
 
   return ChangeStatus::UNCHANGED;
@@ -879,7 +1007,7 @@ ChangeStatus AANoSyncImpl::updateImpl(At
 /// ------------------------ No-Free Attributes ----------------------------
 
 struct AANoFreeImpl : public AANoFree {
-  IRPositionConstructorForward(AANoFreeImpl, AANoFree);
+  AANoFreeImpl(const IRPosition &IRP) : AANoFree(IRP) {}
 
   /// See AbstractAttribute::getAsStr().
   const std::string getAsStr() const override {
@@ -891,37 +1019,44 @@ struct AANoFreeImpl : public AANoFree {
 };
 
 struct AANoFreeFunction final : public AANoFreeImpl {
-  AANoFreeFunction(Function &F) : AANoFreeImpl(F, IRP_FUNCTION) {}
+  AANoFreeFunction(const IRPosition &IRP) : AANoFreeImpl(IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override { STATS_DECL_AND_TRACK_FN_ATTR(nofree) }
 };
 
 ChangeStatus AANoFreeImpl::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
 
   auto CheckForNoFree = [&](Instruction &I) {
-    if (ImmutableCallSite(&I).hasFnAttr(Attribute::NoFree))
+    ImmutableCallSite ICS(&I);
+    if (ICS.hasFnAttr(Attribute::NoFree))
       return true;
 
-    auto *NoFreeAA = A.getAAFor<AANoFreeImpl>(*this, I);
+    auto *NoFreeAA =
+        A.getAAFor<AANoFreeImpl>(*this, IRPosition::callsite_function(ICS));
     return NoFreeAA && NoFreeAA->isAssumedNoFree();
   };
 
-  if (!A.checkForAllCallLikeInstructions(F, CheckForNoFree, *this))
+  if (!A.checkForAllCallLikeInstructions(CheckForNoFree, *this))
     return indicatePessimisticFixpoint();
   return ChangeStatus::UNCHANGED;
 }
 
 /// ------------------------ NonNull Argument Attribute ------------------------
 struct AANonNullImpl : AANonNull {
-  IRPositionConstructorForward(AANonNullImpl, AANonNull);
+  AANonNullImpl(const IRPosition &IRP) : AANonNull(IRP) {}
 
   /// See AbstractAttribute::getAsStr().
   const std::string getAsStr() const override {
     return getAssumed() ? "nonnull" : "may-null";
   }
 
+  /// See AbstractAttribute::initialize(...).
+  void initialize(Attributor &A) override {
+    if (hasAttr({Attribute::NonNull, Attribute::Dereferenceable}))
+      indicateOptimisticFixpoint();
+  }
+
   /// Generate a predicate that checks if a given value is assumed nonnull.
   /// The generated function returns true if a value satisfies any of
   /// following conditions.
@@ -945,15 +1080,12 @@ AANonNullImpl::generatePredicate(Attribu
     if (isKnownNonZero(&RV, A.getDataLayout()))
       return true;
 
-    auto *NonNullAA = A.getAAFor<AANonNull>(*this, RV);
-
-    ImmutableCallSite ICS(&RV);
-
-    if ((!NonNullAA || !NonNullAA->isAssumedNonNull()) &&
-        (!ICS || !ICS.hasRetAttr(Attribute::NonNull)))
-      return false;
+    if (ImmutableCallSite ICS = ImmutableCallSite(&RV))
+      if (ICS.hasRetAttr(Attribute::NonNull))
+        return true;
 
-    return true;
+    auto *NonNullAA = A.getAAFor<AANonNull>(*this, IRPosition::value(RV));
+    return (NonNullAA && NonNullAA->isAssumedNonNull());
   };
 
   return Pred;
@@ -961,19 +1093,7 @@ AANonNullImpl::generatePredicate(Attribu
 
 /// NonNull attribute for function return value.
 struct AANonNullReturned final : AANonNullImpl {
-  AANonNullReturned(Function &F) : AANonNullImpl(F, IRP_RETURNED) {}
-
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    Function &F = getAnchorScope();
-
-    // Already nonnull.
-    if (F.getAttributes().hasAttribute(AttributeList::ReturnIndex,
-                                       Attribute::NonNull) ||
-        F.getAttributes().hasAttribute(AttributeList::ReturnIndex,
-                                       Attribute::Dereferenceable))
-      indicateOptimisticFixpoint();
-  }
+  AANonNullReturned(const IRPosition &IRP) : AANonNullImpl(IRP) {}
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override;
@@ -985,26 +1105,18 @@ struct AANonNullReturned final : AANonNu
 };
 
 ChangeStatus AANonNullReturned::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
 
   std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> Pred =
       this->generatePredicate(A);
 
-  if (!A.checkForAllReturnedValuesAndReturnInsts(F, Pred, *this))
+  if (!A.checkForAllReturnedValuesAndReturnInsts(Pred, *this))
     return indicatePessimisticFixpoint();
   return ChangeStatus::UNCHANGED;
 }
 
 /// NonNull attribute for function argument.
 struct AANonNullArgument final : AANonNullImpl {
-  AANonNullArgument(Argument &A) : AANonNullImpl(A) {}
-
-  /// See AbstractAttriubute::initialize(...).
-  void initialize(Attributor &A) override {
-    Argument *Arg = cast<Argument>(getAssociatedValue());
-    if (Arg->hasNonNullAttr())
-      indicateOptimisticFixpoint();
-  }
+  AANonNullArgument(const IRPosition &IRP) : AANonNullImpl(IRP) {}
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override;
@@ -1017,15 +1129,13 @@ struct AANonNullArgument final : AANonNu
 
 /// NonNull attribute for a call site argument.
 struct AANonNullCallSiteArgument final : AANonNullImpl {
-  AANonNullCallSiteArgument(Instruction &I, unsigned ArgNo)
-      : AANonNullImpl(CallSite(&I).getArgOperand(ArgNo), I, ArgNo) {}
+  AANonNullCallSiteArgument(const IRPosition &IRP) : AANonNullImpl(IRP) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
-    CallSite CS(&getAnchorValue());
-    if (CS.paramHasAttr(getArgNo(), getAttrKind()) ||
-        CS.paramHasAttr(getArgNo(), Attribute::Dereferenceable) ||
-        isKnownNonZero(getAssociatedValue(), A.getDataLayout()))
+    AANonNullImpl::initialize(A);
+    if (!isKnownNonNull() &&
+        isKnownNonZero(&getAssociatedValue(), A.getDataLayout()))
       indicateOptimisticFixpoint();
   }
 
@@ -1039,34 +1149,31 @@ struct AANonNullCallSiteArgument final :
 };
 
 ChangeStatus AANonNullArgument::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
   unsigned ArgNo = getArgNo();
 
   // Callback function
   std::function<bool(CallSite)> CallSiteCheck = [&](CallSite CS) {
     assert(CS && "Sanity check: Call site was not initialized properly!");
 
-    auto *NonNullAA =
-        A.getAAFor<AANonNullImpl>(*this, *CS.getInstruction(), ArgNo);
+    IRPosition CSArgPos = IRPosition::callsite_argument(CS, ArgNo);
+    if (CSArgPos.hasAttr({Attribute::NonNull, Attribute::Dereferenceable}))
+      return true;
 
     // Check that NonNullAA is AANonNullCallSiteArgument.
-    if (NonNullAA) {
+    if (auto *NonNullAA = A.getAAFor<AANonNullImpl>(*this, CSArgPos)) {
       ImmutableCallSite ICS(&NonNullAA->getAnchorValue());
       if (ICS && CS.getInstruction() == ICS.getInstruction())
         return NonNullAA->isAssumedNonNull();
       return false;
     }
 
-    if (CS.paramHasAttr(ArgNo, Attribute::NonNull))
-      return true;
-
     Value *V = CS.getArgOperand(ArgNo);
     if (isKnownNonZero(V, A.getDataLayout()))
       return true;
 
     return false;
   };
-  if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true))
+  if (!A.checkForAllCallSites(CallSiteCheck, *this, true))
     return indicatePessimisticFixpoint();
   return ChangeStatus::UNCHANGED;
 }
@@ -1075,9 +1182,8 @@ ChangeStatus AANonNullCallSiteArgument::
   // NOTE: Never look at the argument of the callee in this method.
   //       If we do this, "nonnull" is always deduced because of the assumption.
 
-  Value &V = *getAssociatedValue();
-
-  auto *NonNullAA = A.getAAFor<AANonNull>(*this, V);
+  Value &V = getAssociatedValue();
+  auto *NonNullAA = A.getAAFor<AANonNull>(*this, IRPosition::value(V));
 
   if (!NonNullAA || !NonNullAA->isAssumedNonNull())
     return indicatePessimisticFixpoint();
@@ -1088,7 +1194,7 @@ ChangeStatus AANonNullCallSiteArgument::
 /// ------------------------ Will-Return Attributes ----------------------------
 
 struct AAWillReturnImpl : public AAWillReturn {
-  IRPositionConstructorForward(AAWillReturnImpl, AAWillReturn);
+  AAWillReturnImpl(const IRPosition &IRP) : AAWillReturn(IRP) {}
 
   /// See AbstractAttribute::getAsStr()
   const std::string getAsStr() const override {
@@ -1097,7 +1203,7 @@ struct AAWillReturnImpl : public AAWillR
 };
 
 struct AAWillReturnFunction final : AAWillReturnImpl {
-  AAWillReturnFunction(Function &F) : AAWillReturnImpl(F, IRP_FUNCTION) {}
+  AAWillReturnFunction(const IRPosition &IRP) : AAWillReturnImpl(IRP) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override;
@@ -1141,7 +1247,6 @@ void AAWillReturnFunction::initialize(At
 }
 
 ChangeStatus AAWillReturnFunction::updateImpl(Attributor &A) {
-  const Function &F = getAnchorScope();
   // The map from instruction opcodes to those instructions in the function.
 
   auto CheckForWillReturn = [&](Instruction &I) {
@@ -1149,7 +1254,8 @@ ChangeStatus AAWillReturnFunction::updat
     if (ICS.hasFnAttr(Attribute::WillReturn))
       return true;
 
-    auto *WillReturnAA = A.getAAFor<AAWillReturn>(*this, I);
+    IRPosition IPos = IRPosition::callsite_function(ICS);
+    auto *WillReturnAA = A.getAAFor<AAWillReturn>(*this, IPos);
     if (!WillReturnAA || !WillReturnAA->isAssumedWillReturn())
       return false;
 
@@ -1157,11 +1263,11 @@ ChangeStatus AAWillReturnFunction::updat
     if (ICS.hasFnAttr(Attribute::NoRecurse))
       return true;
 
-    auto *NoRecurseAA = A.getAAFor<AANoRecurse>(*this, I);
+    auto *NoRecurseAA = A.getAAFor<AANoRecurse>(*this, IPos);
     return NoRecurseAA && NoRecurseAA->isAssumedNoRecurse();
   };
 
-  if (!A.checkForAllCallLikeInstructions(F, CheckForWillReturn, *this))
+  if (!A.checkForAllCallLikeInstructions(CheckForWillReturn, *this))
     return indicatePessimisticFixpoint();
 
   return ChangeStatus::UNCHANGED;
@@ -1170,7 +1276,7 @@ ChangeStatus AAWillReturnFunction::updat
 /// ------------------------ NoAlias Argument Attribute ------------------------
 
 struct AANoAliasImpl : AANoAlias {
-  IRPositionConstructorForward(AANoAliasImpl, AANoAlias);
+  AANoAliasImpl(const IRPosition &IRP) : AANoAlias(IRP) {}
 
   const std::string getAsStr() const override {
     return getAssumed() ? "noalias" : "may-alias";
@@ -1179,7 +1285,7 @@ struct AANoAliasImpl : AANoAlias {
 
 /// NoAlias attribute for function return value.
 struct AANoAliasReturned final : AANoAliasImpl {
-  AANoAliasReturned(Function &F) : AANoAliasImpl(F, IRP_RETURNED) {}
+  AANoAliasReturned(const IRPosition &IRP) : AANoAliasImpl(IRP) {}
 
   /// See AbstractAttriubute::initialize(...).
   void initialize(Attributor &A) override {
@@ -1202,7 +1308,6 @@ struct AANoAliasReturned final : AANoAli
 };
 
 ChangeStatus AANoAliasReturned::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
 
   auto CheckReturnValue = [&](Value &RV) -> bool {
     if (Constant *C = dyn_cast<Constant>(&RV))
@@ -1216,7 +1321,8 @@ ChangeStatus AANoAliasReturned::updateIm
       return false;
 
     if (!ICS.returnDoesNotAlias()) {
-      auto *NoAliasAA = A.getAAFor<AANoAlias>(*this, RV);
+      auto *NoAliasAA =
+          A.getAAFor<AANoAlias>(*this, IRPosition::callsite_returned(ICS));
       if (!NoAliasAA || !NoAliasAA->isAssumedNoAlias())
         return false;
     }
@@ -1231,7 +1337,7 @@ ChangeStatus AANoAliasReturned::updateIm
     return true;
   };
 
-  if (!A.checkForAllReturnedValues(F, CheckReturnValue, *this))
+  if (!A.checkForAllReturnedValues(CheckReturnValue, *this))
     return indicatePessimisticFixpoint();
 
   return ChangeStatus::UNCHANGED;
@@ -1240,7 +1346,7 @@ ChangeStatus AANoAliasReturned::updateIm
 /// -------------------AAIsDead Function Attribute-----------------------
 
 struct AAIsDeadImpl : public AAIsDead {
-  IRPositionConstructorForward(AAIsDeadImpl, AAIsDead);
+  AAIsDeadImpl(const IRPosition &IRP) : AAIsDead(IRP) {}
 
   void initialize(Attributor &A) override {
     const Function &F = getAnchorScope();
@@ -1299,7 +1405,8 @@ struct AAIsDeadImpl : public AAIsDead {
         /// and only place an unreachable in the normal successor.
         if (Invoke2CallAllowed) {
           if (Function *Callee = II->getCalledFunction()) {
-            auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, *Callee);
+            auto *AANoUnw =
+                A.getAAFor<AANoUnwind>(*this, IRPosition::function(*Callee));
             if (Callee->hasFnAttribute(Attribute::NoUnwind) ||
                 (AANoUnw && AANoUnw->isAssumedNoUnwind())) {
               LLVM_DEBUG(dbgs()
@@ -1391,7 +1498,7 @@ struct AAIsDeadImpl : public AAIsDead {
 };
 
 struct AAIsDeadFunction final : public AAIsDeadImpl {
-  AAIsDeadFunction(Function &F) : AAIsDeadImpl(F, IRP_FUNCTION) {}
+  AAIsDeadFunction(const IRPosition &IRP) : AAIsDeadImpl(IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override {
@@ -1434,12 +1541,13 @@ const Instruction *AAIsDeadImpl::findNex
     ImmutableCallSite ICS(I);
 
     if (ICS) {
+      const IRPosition &IPos = IRPosition::callsite_function(ICS);
       // Regarless of the no-return property of an invoke instruction we only
       // learn that the regular successor is not reachable through this
       // instruction but the unwind block might still be.
       if (auto *Invoke = dyn_cast<InvokeInst>(I)) {
         // Use nounwind to justify the unwind block is dead as well.
-        auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, *Invoke);
+        auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, IPos);
         if (!Invoke2CallAllowed ||
             (!AANoUnw || !AANoUnw->isAssumedNoUnwind())) {
           AssumedLiveBlocks.insert(Invoke->getUnwindDest());
@@ -1447,7 +1555,7 @@ const Instruction *AAIsDeadImpl::findNex
         }
       }
 
-      auto *NoReturnAA = A.getAAFor<AANoReturn>(*this, *I);
+      auto *NoReturnAA = A.getAAFor<AANoReturn>(*this, IPos);
       if (ICS.hasFnAttr(Attribute::NoReturn) ||
           (NoReturnAA && NoReturnAA->isAssumedNoReturn()))
         return I;
@@ -1577,7 +1685,7 @@ struct DerefState : AbstractState {
 };
 
 struct AADereferenceableImpl : AADereferenceable, DerefState {
-  IRPositionConstructorForward(AADereferenceableImpl, AADereferenceable);
+  AADereferenceableImpl(const IRPosition &IRP) : AADereferenceable(IRP) {}
   using StateType = DerefState;
 
   /// See AbstractAttribute::getState()
@@ -1644,13 +1752,11 @@ struct AADereferenceableImpl : AADerefer
                                             bool &IsNonNull, bool &IsGlobal);
 
   void initialize(Attributor &A) override {
-    Function &F = getAnchorScope();
-    unsigned AttrIdx = getIRPosition().getAttrIdx();
-
-    for (Attribute::AttrKind AK :
-         {Attribute::Dereferenceable, Attribute::DereferenceableOrNull})
-      if (F.getAttributes().hasAttribute(AttrIdx, AK))
-        takeKnownDerefBytesMaximum(F.getAttribute(AttrIdx, AK).getValueAsInt());
+    SmallVector<Attribute, 4> Attrs;
+    getAttrs({Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
+             Attrs);
+    for (const Attribute &Attr : Attrs)
+      takeKnownDerefBytesMaximum(Attr.getValueAsInt());
   }
 
   /// See AbstractAttribute::getAsStr().
@@ -1666,8 +1772,8 @@ struct AADereferenceableImpl : AADerefer
 };
 
 struct AADereferenceableReturned final : AADereferenceableImpl {
-  AADereferenceableReturned(Function &F)
-      : AADereferenceableImpl(F, IRP_RETURNED) {}
+  AADereferenceableReturned(const IRPosition &IRP)
+      : AADereferenceableImpl(IRP) {}
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override;
@@ -1692,7 +1798,8 @@ uint64_t AADereferenceableImpl::computeA
   IsGlobal = false;
 
   // First, we try to get information about V from Attributor.
-  if (auto *DerefAA = A.getAAFor<AADereferenceable>(*this, V)) {
+  if (auto *DerefAA =
+          A.getAAFor<AADereferenceable>(*this, IRPosition::value(V))) {
     IsNonNull &= DerefAA->isAssumedNonNull();
     return DerefAA->getAssumedDereferenceableBytes();
   }
@@ -1704,7 +1811,8 @@ uint64_t AADereferenceableImpl::computeA
   APInt Offset(IdxWidth, 0);
   Value *Base = V.stripAndAccumulateInBoundsConstantOffsets(DL, Offset);
 
-  if (auto *BaseDerefAA = A.getAAFor<AADereferenceable>(*this, *Base)) {
+  if (auto *BaseDerefAA =
+          A.getAAFor<AADereferenceable>(*this, IRPosition::value(*Base))) {
     IsNonNull &= Offset != 0;
     return calcDifferenceIfBaseIsNonNull(
         BaseDerefAA->getAssumedDereferenceableBytes(), Offset.getSExtValue(),
@@ -1725,10 +1833,9 @@ uint64_t AADereferenceableImpl::computeA
 }
 
 ChangeStatus AADereferenceableReturned::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
   auto BeforeState = static_cast<DerefState>(*this);
 
-  syncNonNull(A.getAAFor<AANonNull>(*this, F));
+  syncNonNull(A.getAAFor<AANonNull>(*this, getIRPosition()));
 
   bool IsNonNull = isAssumedNonNull();
   bool IsGlobal = isAssumedGlobal();
@@ -1739,7 +1846,7 @@ ChangeStatus AADereferenceableReturned::
     return isValidState();
   };
 
-  if (A.checkForAllReturnedValues(F, CheckReturnValue, *this)) {
+  if (A.checkForAllReturnedValues(CheckReturnValue, *this)) {
     updateAssumedNonNullGlobalState(IsNonNull, IsGlobal);
     return BeforeState == static_cast<DerefState>(*this)
                ? ChangeStatus::UNCHANGED
@@ -1749,7 +1856,8 @@ ChangeStatus AADereferenceableReturned::
 }
 
 struct AADereferenceableArgument final : AADereferenceableImpl {
-  AADereferenceableArgument(Argument &A) : AADereferenceableImpl(A) {}
+  AADereferenceableArgument(const IRPosition &IRP)
+      : AADereferenceableImpl(IRP) {}
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override;
@@ -1761,14 +1869,13 @@ struct AADereferenceableArgument final :
 };
 
 ChangeStatus AADereferenceableArgument::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
   Argument &Arg = cast<Argument>(getAnchorValue());
 
   auto BeforeState = static_cast<DerefState>(*this);
 
   unsigned ArgNo = Arg.getArgNo();
 
-  syncNonNull(A.getAAFor<AANonNull>(*this, F, ArgNo));
+  syncNonNull(A.getAAFor<AANonNull>(*this, getIRPosition()));
 
   bool IsNonNull = isAssumedNonNull();
   bool IsGlobal = isAssumedGlobal();
@@ -1778,8 +1885,8 @@ ChangeStatus AADereferenceableArgument::
     assert(CS && "Sanity check: Call site was not initialized properly!");
 
     // Check that DereferenceableAA is AADereferenceableCallSiteArgument.
-    if (auto *DereferenceableAA =
-            A.getAAFor<AADereferenceable>(*this, *CS.getInstruction(), ArgNo)) {
+    if (auto *DereferenceableAA = A.getAAFor<AADereferenceable>(
+            *this, IRPosition::callsite_argument(CS, ArgNo))) {
       ImmutableCallSite ICS(
           &DereferenceableAA->getIRPosition().getAnchorValue());
       if (ICS && CS.getInstruction() == ICS.getInstruction()) {
@@ -1797,7 +1904,7 @@ ChangeStatus AADereferenceableArgument::
     return isValidState();
   };
 
-  if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true))
+  if (!A.checkForAllCallSites(CallSiteCheck, *this, true))
     return indicatePessimisticFixpoint();
 
   updateAssumedNonNullGlobalState(IsNonNull, IsGlobal);
@@ -1808,18 +1915,8 @@ ChangeStatus AADereferenceableArgument::
 
 /// Dereferenceable attribute for a call site argument.
 struct AADereferenceableCallSiteArgument final : AADereferenceableImpl {
-  AADereferenceableCallSiteArgument(Instruction &I, unsigned ArgNo)
-      : AADereferenceableImpl(CallSite(&I).getArgOperand(ArgNo), I, ArgNo) {}
-
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    CallSite CS(&getAnchorValue());
-    if (CS.paramHasAttr(getArgNo(), Attribute::Dereferenceable))
-      takeKnownDerefBytesMaximum(CS.getDereferenceableBytes(getArgNo()));
-
-    if (CS.paramHasAttr(getArgNo(), Attribute::DereferenceableOrNull))
-      takeKnownDerefBytesMaximum(CS.getDereferenceableOrNullBytes(getArgNo()));
-  }
+  AADereferenceableCallSiteArgument(const IRPosition &IRP)
+      : AADereferenceableImpl(IRP) {}
 
   /// See AbstractAttribute::updateImpl(Attributor &A).
   ChangeStatus updateImpl(Attributor &A) override;
@@ -1835,11 +1932,11 @@ ChangeStatus AADereferenceableCallSiteAr
   //       If we do this, "dereferenceable" is always deduced because of the
   //       assumption.
 
-  Value &V = *getAssociatedValue();
+  Value &V = getAssociatedValue();
 
   auto BeforeState = static_cast<DerefState>(*this);
 
-  syncNonNull(A.getAAFor<AANonNull>(*this, getAnchorValue(), getArgNo()));
+  syncNonNull(A.getAAFor<AANonNull>(*this, getIRPosition()));
   bool IsNonNull = isAssumedNonNull();
   bool IsGlobal = isKnownGlobal();
 
@@ -1854,7 +1951,7 @@ ChangeStatus AADereferenceableCallSiteAr
 // ------------------------ Align Argument Attribute ------------------------
 
 struct AAAlignImpl : AAAlign {
-  IRPositionConstructorForward(AAAlignImpl, AAAlign);
+  AAAlignImpl(const IRPosition &IRP) : AAAlign(IRP) {}
 
   // Max alignemnt value allowed in IR
   static const unsigned MAX_ALIGN = 1U << 29;
@@ -1869,13 +1966,10 @@ struct AAAlignImpl : AAAlign {
   void initialize(Attributor &A) override {
     takeAssumedMinimum(MAX_ALIGN);
 
-    Function &F = getAnchorScope();
-
-    unsigned AttrIdx = getAttrIdx();
-    // Already the function has align attribute on return value or argument.
-    if (F.getAttributes().hasAttribute(AttrIdx, Attribute::Alignment))
-      addKnownBits(
-          F.getAttribute(AttrIdx, Attribute::Alignment).getAlignment());
+    SmallVector<Attribute, 4> Attrs;
+    getAttrs({Attribute::Alignment}, Attrs);
+    for (const Attribute &Attr : Attrs)
+      takeKnownMaximum(Attr.getValueAsInt());
   }
 
   /// See AbstractAttribute::getDeducedAttributes
@@ -1888,7 +1982,7 @@ struct AAAlignImpl : AAAlign {
 
 /// Align attribute for function return value.
 struct AAAlignReturned final : AAAlignImpl {
-  AAAlignReturned(Function &F) : AAAlignImpl(F, IRP_RETURNED) {}
+  AAAlignReturned(const IRPosition &IRP) : AAAlignImpl(IRP) {}
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override;
@@ -1900,7 +1994,6 @@ struct AAAlignReturned final : AAAlignIm
 };
 
 ChangeStatus AAAlignReturned::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
 
   // Currently, align<n> is deduced if alignments in return values are assumed
   // as greater than n. We reach pessimistic fixpoint if any of the return value
@@ -1910,7 +2003,7 @@ ChangeStatus AAAlignReturned::updateImpl
   base_t BeforeState = getAssumed();
   auto CheckReturnValue =
       [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &RetInsts) -> bool {
-    auto *AlignAA = A.getAAFor<AAAlign>(*this, RV);
+    auto *AlignAA = A.getAAFor<AAAlign>(*this, IRPosition::value(RV));
 
     if (AlignAA)
       takeAssumedMinimum(AlignAA->getAssumedAlign());
@@ -1921,7 +2014,7 @@ ChangeStatus AAAlignReturned::updateImpl
     return isValidState();
   };
 
-  if (!A.checkForAllReturnedValuesAndReturnInsts(F, CheckReturnValue, *this))
+  if (!A.checkForAllReturnedValuesAndReturnInsts(CheckReturnValue, *this))
     return indicatePessimisticFixpoint();
 
   return (getAssumed() != BeforeState) ? ChangeStatus::CHANGED
@@ -1930,7 +2023,7 @@ ChangeStatus AAAlignReturned::updateImpl
 
 /// Align attribute for function argument.
 struct AAAlignArgument final : AAAlignImpl {
-  AAAlignArgument(Argument &A) : AAAlignImpl(A) {}
+  AAAlignArgument(const IRPosition &IRP) : AAAlignImpl(IRP) {}
 
   /// See AbstractAttribute::updateImpl(...).
   virtual ChangeStatus updateImpl(Attributor &A) override;
@@ -1941,7 +2034,6 @@ struct AAAlignArgument final : AAAlignIm
 
 ChangeStatus AAAlignArgument::updateImpl(Attributor &A) {
 
-  Function &F = getAnchorScope();
   Argument &Arg = cast<Argument>(getAnchorValue());
 
   unsigned ArgNo = Arg.getArgNo();
@@ -1953,7 +2045,8 @@ ChangeStatus AAAlignArgument::updateImpl
   std::function<bool(CallSite)> CallSiteCheck = [&](CallSite CS) {
     assert(CS && "Sanity check: Call site was not initialized properly!");
 
-    auto *AlignAA = A.getAAFor<AAAlign>(*this, *CS.getInstruction(), ArgNo);
+    auto *AlignAA =
+        A.getAAFor<AAAlign>(*this, IRPosition::callsite_argument(CS, ArgNo));
 
     // Check that AlignAA is AAAlignCallSiteArgument.
     if (AlignAA) {
@@ -1969,7 +2062,7 @@ ChangeStatus AAAlignArgument::updateImpl
     return isValidState();
   };
 
-  if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true))
+  if (!A.checkForAllCallSites(CallSiteCheck, *this, true))
     indicatePessimisticFixpoint();
 
   return BeforeState == getAssumed() ? ChangeStatus::UNCHANGED
@@ -1977,14 +2070,12 @@ ChangeStatus AAAlignArgument::updateImpl
 }
 
 struct AAAlignCallSiteArgument final : AAAlignImpl {
-  AAAlignCallSiteArgument(Instruction &I, unsigned ArgNo)
-      : AAAlignImpl(CallSite(&I).getArgOperand(ArgNo), I, ArgNo) {}
+  AAAlignCallSiteArgument(const IRPosition &IRP) : AAAlignImpl(IRP) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
-    CallSite CS(&getAnchorValue());
     takeKnownMaximum(
-        getAssociatedValue()->getPointerAlignment(A.getDataLayout()));
+        getAssociatedValue().getPointerAlignment(A.getDataLayout()));
   }
 
   /// See AbstractAttribute::updateImpl(Attributor &A).
@@ -2002,9 +2093,8 @@ ChangeStatus AAAlignCallSiteArgument::up
 
   auto BeforeState = getAssumed();
 
-  Value &V = *getAssociatedValue();
-
-  auto *AlignAA = A.getAAFor<AAAlign>(*this, V);
+  Value &V = getAssociatedValue();
+  auto *AlignAA = A.getAAFor<AAAlign>(*this, IRPosition::value(V));
 
   if (AlignAA)
     takeAssumedMinimum(AlignAA->getAssumedAlign());
@@ -2017,7 +2107,7 @@ ChangeStatus AAAlignCallSiteArgument::up
 
 /// ------------------ Function No-Return Attribute ----------------------------
 struct AANoReturnImpl : public AANoReturn {
-  IRPositionConstructorForward(AANoReturnImpl, AANoReturn);
+  AANoReturnImpl(const IRPosition &IRP) : AANoReturn(IRP) {}
 
   /// See AbstractAttribute::getAsStr().
   const std::string getAsStr() const override {
@@ -2026,16 +2116,14 @@ struct AANoReturnImpl : public AANoRetur
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
-    Function &F = getAnchorScope();
-    if (F.hasFnAttribute(getAttrKind()))
+    if (hasAttr({getAttrKind()}))
       indicateOptimisticFixpoint();
   }
 
   /// See AbstractAttribute::updateImpl(Attributor &A).
   virtual ChangeStatus updateImpl(Attributor &A) override {
-    const Function &F = getAnchorScope();
     auto CheckForNoReturn = [](Instruction &) { return false; };
-    if (!A.checkForAllInstructions(F, CheckForNoReturn, *this,
+    if (!A.checkForAllInstructions(CheckForNoReturn, *this,
                                    {(unsigned)Instruction::Ret}))
       return indicatePessimisticFixpoint();
     return ChangeStatus::UNCHANGED;
@@ -2043,7 +2131,7 @@ struct AANoReturnImpl : public AANoRetur
 };
 
 struct AANoReturnFunction final : AANoReturnImpl {
-  AANoReturnFunction(Function &F) : AANoReturnImpl(F, IRP_FUNCTION) {}
+  AANoReturnFunction(const IRPosition &IRP) : AANoReturnImpl(IRP) {}
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override {
@@ -2055,26 +2143,31 @@ struct AANoReturnFunction final : AANoRe
 ///                               Attributor
 /// ----------------------------------------------------------------------------
 
-bool Attributor::checkForAllCallSites(Function &F,
-                                      std::function<bool(CallSite)> &Pred,
+bool Attributor::checkForAllCallSites(const function_ref<bool(CallSite)> &Pred,
                                       const AbstractAttribute &QueryingAA,
                                       bool RequireAllCallSites) {
   // We can try to determine information from
   // the call sites. However, this is only possible all call sites are known,
   // hence the function has internal linkage.
-  if (RequireAllCallSites && !F.hasInternalLinkage()) {
+  const IRPosition &IRP = QueryingAA.getIRPosition();
+  const Function *AssociatedFunction = IRP.getAssociatedFunction();
+  if (!AssociatedFunction)
+    return false;
+
+  if (RequireAllCallSites && !AssociatedFunction->hasInternalLinkage()) {
     LLVM_DEBUG(
         dbgs()
-        << "Attributor: Function " << F.getName()
+        << "Attributor: Function " << AssociatedFunction->getName()
         << " has no internal linkage, hence not all call sites are known\n");
     return false;
   }
 
-  for (const Use &U : F.uses()) {
+  for (const Use &U : AssociatedFunction->uses()) {
     Instruction *I = cast<Instruction>(U.getUser());
-    Function *AnchorValue = I->getParent()->getParent();
+    Function *Caller = I->getFunction();
 
-    auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, *AnchorValue);
+    auto *LivenessAA =
+        getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*Caller));
 
     // Skip dead calls.
     if (LivenessAA && LivenessAA->isAssumedDead(I))
@@ -2086,7 +2179,8 @@ bool Attributor::checkForAllCallSites(Fu
         continue;
 
       LLVM_DEBUG(dbgs() << "Attributor: User " << *U.getUser()
-                        << " is an invalid use of " << F.getName() << "\n");
+                        << " is an invalid use of "
+                        << AssociatedFunction->getName() << "\n");
       return false;
     }
 
@@ -2102,16 +2196,26 @@ bool Attributor::checkForAllCallSites(Fu
 }
 
 bool Attributor::checkForAllReturnedValuesAndReturnInsts(
-    const Function &F,
     const function_ref<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)>
         &Pred,
     const AbstractAttribute &QueryingAA) {
 
-  auto *AARetVal = getAAFor<AAReturnedValues>(QueryingAA, F);
-  if (!AARetVal)
+  const IRPosition &IRP = QueryingAA.getIRPosition();
+  // Since we need to provide return instructions we have to have an exact
+  // definition.
+  const Function *AssociatedFunction = IRP.getAssociatedFunction();
+  if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition())
+    return false;
+
+  // If this is a call site query we use the call site specific return values
+  // and liveness information.
+  const IRPosition &QueryIRP = IRPosition::function_scope(IRP);
+  const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP);
+  if (!AARetVal || !AARetVal->getState().isValidState())
     return false;
 
-  auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);
+  auto *LivenessAA =
+      getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*AssociatedFunction));
   if (!LivenessAA)
     return AARetVal->checkForAllReturnedValuesAndReturnInsts(Pred);
 
@@ -2130,14 +2234,21 @@ bool Attributor::checkForAllReturnedValu
 }
 
 bool Attributor::checkForAllReturnedValues(
-    const Function &F, const function_ref<bool(Value &)> &Pred,
+    const function_ref<bool(Value &)> &Pred,
     const AbstractAttribute &QueryingAA) {
 
-  auto *AARetVal = getAAFor<AAReturnedValues>(QueryingAA, F);
-  if (!AARetVal)
+  const IRPosition &IRP = QueryingAA.getIRPosition();
+  const Function *AssociatedFunction = IRP.getAssociatedFunction();
+  if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition())
     return false;
 
-  auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);
+  const IRPosition &QueryIRP = IRPosition::function_scope(IRP);
+  const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP);
+  if (!AARetVal || !AARetVal->getState().isValidState())
+    return false;
+
+  auto *LivenessAA =
+      getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*AssociatedFunction));
   if (!LivenessAA)
     return AARetVal->checkForAllReturnedValuesAndReturnInsts(
         [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &) {
@@ -2155,12 +2266,20 @@ bool Attributor::checkForAllReturnedValu
 }
 
 bool Attributor::checkForAllInstructions(
-    const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred,
+    const llvm::function_ref<bool(Instruction &)> &Pred,
     const AbstractAttribute &QueryingAA, const ArrayRef<unsigned> &Opcodes) {
 
-  auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);
+  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())
+    return false;
 
-  auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
+  const IRPosition &QueryIRP = IRPosition::function_scope(IRP);
+  const auto &LivenessAA = getAAFor<AAIsDead>(QueryingAA, QueryIRP);
+
+  auto &OpcodeInstMap =
+      InfoCache.getOpcodeInstMapForFunction(*AssociatedFunction);
   for (unsigned Opcode : Opcodes) {
     for (Instruction *I : OpcodeInstMap[Opcode]) {
       // Skip dead instructions.
@@ -2176,12 +2295,19 @@ bool Attributor::checkForAllInstructions
 }
 
 bool Attributor::checkForAllReadWriteInstructions(
-    const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred,
+    const llvm::function_ref<bool(Instruction &)> &Pred,
     AbstractAttribute &QueryingAA) {
 
-  auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);
+  const Function *AssociatedFunction =
+      QueryingAA.getIRPosition().getAssociatedFunction();
+  if (!AssociatedFunction)
+    return false;
+
+  const auto &LivenessAA =
+      getAAFor<AAIsDead>(QueryingAA, QueryingAA.getIRPosition());
 
-  for (Instruction *I : InfoCache.getReadOrWriteInstsForFunction(F)) {
+  for (Instruction *I :
+       InfoCache.getReadOrWriteInstsForFunction(*AssociatedFunction)) {
     // Skip dead instructions.
     if (LivenessAA && LivenessAA->isAssumedDead(I))
       continue;
@@ -2331,83 +2457,83 @@ ChangeStatus Attributor::run() {
 }
 
 /// Helper function that checks if an abstract attribute of type \p AAType
-/// should be created for \p V (with argument number \p ArgNo) and if so creates
-/// and registers it with the Attributor \p A.
+/// 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 <typename AAType, typename ValueType, typename... ArgsTy>
-static AAType *checkAndRegisterAA(const Function &F, Attributor &A,
-                                  DenseSet<const char *> *Whitelist,
-                                  ValueType &V, int ArgNo, ArgsTy... Args) {
+template <typename AAType>
+static AAType *checkAndRegisterAA(IRPosition &IRP, Attributor &A,
+                                  DenseSet<const char *> *Whitelist) {
   if (Whitelist && !Whitelist->count(&AAType::ID))
     return nullptr;
 
-  return &A.registerAA<AAType>(*new AAType(V, Args...), ArgNo);
+  return &A.registerAA<AAType>(*new AAType(IRP));
 }
 
 void Attributor::identifyDefaultAbstractAttributes(
     Function &F, DenseSet<const char *> *Whitelist) {
 
+  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<AAIsDeadFunction>(F, *this, /* Whitelist */ nullptr, F,
-                                       -1);
+  checkAndRegisterAA<AAIsDeadFunction>(FPos, *this, /* Whitelist */ nullptr);
 
   // Every function might be "will-return".
-  checkAndRegisterAA<AAWillReturnFunction>(F, *this, Whitelist, F, -1);
+  checkAndRegisterAA<AAWillReturnFunction>(FPos, *this, Whitelist);
 
   // Every function can be nounwind.
-  checkAndRegisterAA<AANoUnwindFunction>(F, *this, Whitelist, F, -1);
+  checkAndRegisterAA<AANoUnwindFunction>(FPos, *this, Whitelist);
 
   // Every function might be marked "nosync"
-  checkAndRegisterAA<AANoSyncFunction>(F, *this, Whitelist, F, -1);
+  checkAndRegisterAA<AANoSyncFunction>(FPos, *this, Whitelist);
 
   // Every function might be "no-free".
-  checkAndRegisterAA<AANoFreeFunction>(F, *this, Whitelist, F, -1);
+  checkAndRegisterAA<AANoFreeFunction>(FPos, *this, Whitelist);
 
   // Every function might be "no-return".
-  checkAndRegisterAA<AANoReturnFunction>(F, *this, Whitelist, F, -1);
+  checkAndRegisterAA<AANoReturnFunction>(FPos, *this, Whitelist);
 
   // 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<AAReturnedValuesFunction>(F, *this, Whitelist, F, -1);
+    checkAndRegisterAA<AAReturnedValuesFunction>(FPos, *this, Whitelist);
 
     if (ReturnType->isPointerTy()) {
+      IRPosition RetPos = IRPosition::returned(F);
+
       // Every function with pointer return type might be marked align.
-      checkAndRegisterAA<AAAlignReturned>(F, *this, Whitelist, F, -1);
+      checkAndRegisterAA<AAAlignReturned>(RetPos, *this, Whitelist);
 
       // Every function with pointer return type might be marked nonnull.
-      checkAndRegisterAA<AANonNullReturned>(F, *this, Whitelist, F, -1);
+      checkAndRegisterAA<AANonNullReturned>(RetPos, *this, Whitelist);
 
       // Every function with pointer return type might be marked noalias.
-      checkAndRegisterAA<AANoAliasReturned>(F, *this, Whitelist, F, -1);
+      checkAndRegisterAA<AANoAliasReturned>(RetPos, *this, Whitelist);
 
       // Every function with pointer return type might be marked
       // dereferenceable.
-      checkAndRegisterAA<AADereferenceableReturned>(F, *this, Whitelist, F, -1);
+      checkAndRegisterAA<AADereferenceableReturned>(RetPos, *this, Whitelist);
     }
   }
 
   for (Argument &Arg : F.args()) {
     if (Arg.getType()->isPointerTy()) {
+      IRPosition ArgPos = IRPosition::argument(Arg);
       // Every argument with pointer type might be marked nonnull.
-      checkAndRegisterAA<AANonNullArgument>(F, *this, Whitelist, Arg,
-                                            Arg.getArgNo());
+      checkAndRegisterAA<AANonNullArgument>(ArgPos, *this, Whitelist);
 
       // Every argument with pointer type might be marked dereferenceable.
-      checkAndRegisterAA<AADereferenceableArgument>(F, *this, Whitelist, Arg,
-                                                    Arg.getArgNo());
+      checkAndRegisterAA<AADereferenceableArgument>(ArgPos, *this, Whitelist);
 
       // Every argument with pointer type might be marked align.
-      checkAndRegisterAA<AAAlignArgument>(F, *this, Whitelist, Arg,
-                                          Arg.getArgNo());
+      checkAndRegisterAA<AAAlignArgument>(ArgPos, *this, Whitelist);
     }
   }
 
@@ -2450,18 +2576,18 @@ void Attributor::identifyDefaultAbstract
       for (int i = 0, e = CS.getCalledFunction()->arg_size(); i < e; i++) {
         if (!CS.getArgument(i)->getType()->isPointerTy())
           continue;
+        IRPosition CSArgPos = IRPosition::callsite_argument(CS, i);
 
         // Call site argument attribute "non-null".
-        checkAndRegisterAA<AANonNullCallSiteArgument>(F, *this, Whitelist, I, i,
-                                                      i);
+        checkAndRegisterAA<AANonNullCallSiteArgument>(CSArgPos, *this,
+                                                      Whitelist);
 
         // Call site argument attribute "dereferenceable".
-        checkAndRegisterAA<AADereferenceableCallSiteArgument>(
-            F, *this, Whitelist, I, i, i);
+        checkAndRegisterAA<AADereferenceableCallSiteArgument>(CSArgPos, *this,
+                                                              Whitelist);
 
         // Call site argument attribute "align".
-        checkAndRegisterAA<AAAlignCallSiteArgument>(F, *this, Whitelist, I, i,
-                                                    i);
+        checkAndRegisterAA<AAAlignCallSiteArgument>(CSArgPos, *this, Whitelist);
       }
     }
   }
@@ -2476,22 +2602,29 @@ raw_ostream &llvm::operator<<(raw_ostrea
 
 raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) {
   switch (AP) {
+  case IRPosition::IRP_INVALID:
+    return OS << "inv";
+  case IRPosition::IRP_FLOAT:
+    return OS << "flt";
+  case IRPosition::IRP_RETURNED:
+    return OS << "fn_ret";
+  case IRPosition::IRP_CALL_SITE_RETURNED:
+    return OS << "cs_ret";
+  case IRPosition::IRP_FUNCTION:
+    return OS << "fn";
+  case IRPosition::IRP_CALL_SITE:
+    return OS << "cs";
   case IRPosition::IRP_ARGUMENT:
     return OS << "arg";
   case IRPosition::IRP_CALL_SITE_ARGUMENT:
     return OS << "cs_arg";
-  case IRPosition::IRP_FUNCTION:
-    return OS << "fn";
-  case IRPosition::IRP_RETURNED:
-    return OS << "fn_ret";
   }
   llvm_unreachable("Unknown attribute position!");
 }
 
 raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) {
-  const Value *AV = Pos.getAssociatedValue();
-  return OS << "{" << Pos.getPositionKind() << ":"
-            << (AV ? AV->getName() : "n/a") << " ["
+  const Value &AV = Pos.getAssociatedValue();
+  return OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " ["
             << Pos.getAnchorValue().getName() << "@" << Pos.getArgNo() << "]}";
 }
 




More information about the llvm-commits mailing list