[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

llvm-svn: 368919
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index ba76262..33a49a5 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -265,13 +265,9 @@
 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 @@
 
   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 @@
   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 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 @@
 };
 
 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 @@
     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 @@
   }
 
 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 @@
 };
 
 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 @@
 
   // 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 @@
     return true;
   };
 
-  if (!A.checkForAllReturnedValues(getAnchorScope(), Pred, *this))
+  if (!A.checkForAllReturnedValues(Pred, *this))
     UniqueRV = nullptr;
 
   return UniqueRV;
@@ -608,7 +734,7 @@
   // 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 @@
     }
 
     // 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 @@
 
     // 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 @@
 
     // 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 @@
 /// ------------------------ 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 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 @@
 }
 
 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 @@
     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 @@
 /// ------------------------ 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 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 @@
     if (isKnownNonZero(&RV, A.getDataLayout()))
       return true;
 
-    auto *NonNullAA = A.getAAFor<AANonNull>(*this, RV);
+    if (ImmutableCallSite ICS = ImmutableCallSite(&RV))
+      if (ICS.hasRetAttr(Attribute::NonNull))
+        return true;
 
-    ImmutableCallSite ICS(&RV);
-
-    if ((!NonNullAA || !NonNullAA->isAssumedNonNull()) &&
-        (!ICS || !ICS.hasRetAttr(Attribute::NonNull)))
-      return false;
-
-    return true;
+    auto *NonNullAA = A.getAAFor<AANonNull>(*this, IRPosition::value(RV));
+    return (NonNullAA && NonNullAA->isAssumedNonNull());
   };
 
   return Pred;
@@ -961,19 +1093,7 @@
 
 /// 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 @@
 };
 
 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 @@
 
 /// 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 @@
 };
 
 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 @@
   // 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 @@
 /// ------------------------ 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 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 @@
 }
 
 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 @@
     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 @@
     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 @@
 /// ------------------------ 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 @@
 
 /// 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 @@
 };
 
 ChangeStatus AANoAliasReturned::updateImpl(Attributor &A) {
-  Function &F = getAnchorScope();
 
   auto CheckReturnValue = [&](Value &RV) -> bool {
     if (Constant *C = dyn_cast<Constant>(&RV))
@@ -1216,7 +1321,8 @@
       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 @@
     return true;
   };
 
-  if (!A.checkForAllReturnedValues(F, CheckReturnValue, *this))
+  if (!A.checkForAllReturnedValues(CheckReturnValue, *this))
     return indicatePessimisticFixpoint();
 
   return ChangeStatus::UNCHANGED;
@@ -1240,7 +1346,7 @@
 /// -------------------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 @@
         /// 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 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 @@
     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 @@
         }
       }
 
-      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 AADereferenceableImpl : AADereferenceable, DerefState {
-  IRPositionConstructorForward(AADereferenceableImpl, AADereferenceable);
+  AADereferenceableImpl(const IRPosition &IRP) : AADereferenceable(IRP) {}
   using StateType = DerefState;
 
   /// See AbstractAttribute::getState()
@@ -1644,13 +1752,11 @@
                                             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 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 @@
   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 @@
   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 @@
 }
 
 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 @@
     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 @@
 }
 
 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 @@
 };
 
 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 @@
     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 @@
     return isValidState();
   };
 
-  if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true))
+  if (!A.checkForAllCallSites(CallSiteCheck, *this, true))
     return indicatePessimisticFixpoint();
 
   updateAssumedNonNullGlobalState(IsNonNull, IsGlobal);
@@ -1808,18 +1915,8 @@
 
 /// 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 @@
   //       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 @@
 // ------------------------ 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 @@
   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 @@
 
 /// 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 @@
 };
 
 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 @@
   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 @@
     return isValidState();
   };
 
-  if (!A.checkForAllReturnedValuesAndReturnInsts(F, CheckReturnValue, *this))
+  if (!A.checkForAllReturnedValuesAndReturnInsts(CheckReturnValue, *this))
     return indicatePessimisticFixpoint();
 
   return (getAssumed() != BeforeState) ? ChangeStatus::CHANGED
@@ -1930,7 +2023,7 @@
 
 /// 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 @@
 
 ChangeStatus AAAlignArgument::updateImpl(Attributor &A) {
 
-  Function &F = getAnchorScope();
   Argument &Arg = cast<Argument>(getAnchorValue());
 
   unsigned ArgNo = Arg.getArgNo();
@@ -1953,7 +2045,8 @@
   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 @@
     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 @@
 }
 
 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 @@
 
   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 @@
 
 /// ------------------ 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 @@
 
   /// 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 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 @@
 ///                               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 @@
         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::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;
 
-  auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F);
+  // 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, IRPosition::function(*AssociatedFunction));
   if (!LivenessAA)
     return AARetVal->checkForAllReturnedValuesAndReturnInsts(Pred);
 
@@ -2130,14 +2234,21 @@
 }
 
 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::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::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;
 
-  for (Instruction *I : InfoCache.getReadOrWriteInstsForFunction(F)) {
+  const auto &LivenessAA =
+      getAAFor<AAIsDead>(QueryingAA, QueryingAA.getIRPosition());
+
+  for (Instruction *I :
+       InfoCache.getReadOrWriteInstsForFunction(*AssociatedFunction)) {
     // Skip dead instructions.
     if (LivenessAA && LivenessAA->isAssumedDead(I))
       continue;
@@ -2331,83 +2457,83 @@
 }
 
 /// 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 @@
       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_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() << "]}";
 }