[llvm] r367952 - [Attributor] Make abstract attributes stateless

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 5 16:32:31 PDT 2019


Author: jdoerfert
Date: Mon Aug  5 16:32:31 2019
New Revision: 367952

URL: http://llvm.org/viewvc/llvm-project?rev=367952&view=rev
Log:
[Attributor] Make abstract attributes stateless

To remove boilerplate, mostly passing through values to the
AbstractAttriubute base class, we extract the state into an IRPosition
helper. There is no function change intended but the IRPosition struct
will provide more functionality down the line.

Reviewers: sstefan1, uenoku

Subscribers: hiraditya, bollu, jfb, llvm-commits

Tags: #llvm

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

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=367952&r1=367951&r2=367952&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Mon Aug  5 16:32:31 2019
@@ -61,12 +61,11 @@
 //
 // Attribute manifestation is not mandatory. If desired, there is support to
 // generate a single LLVM-IR attribute already in the AbstractAttribute base
-// class. In the simplest case, a subclass overloads
-// `AbstractAttribute::getManifestPosition()` and
-// `AbstractAttribute::getAttrKind()` to return the appropriate values. The
-// Attributor manifestation framework will then create and place a new attribute
-// if it is allowed to do so (based on the abstract state). Other use cases can
-// be achieved by overloading other abstract attribute methods.
+// class. In the simplest case, a subclass initializes the IRPosition properly
+// and overloads `AbstractAttribute::getAttrKind()` to return the appropriate
+// value. The Attributor manifestation framework will then create and place a
+// new attribute if it is allowed to do so (based on the abstract state). Other
+// use cases can be achieved by overloading other abstract attribute methods.
 //
 //
 // The "mechanics" of adding a new "abstract attribute":
@@ -233,14 +232,14 @@ struct Attributor {
     // 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 &AnchoredVal = AA.getAnchoredValue();
+    Value &AnchorVal = AA.getIRPosition().getAnchorValue();
     if (ArgNo == -1)
-      if (auto *Arg = dyn_cast<Argument>(&AnchoredVal))
+      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[{&AnchoredVal, ArgNo}][&AAType::ID] = &AA;
+    AAMap[{&AnchorVal, ArgNo}][&AAType::ID] = &AA;
     AllAbstractAttributes.push_back(&AA);
     return AA;
   }
@@ -498,6 +497,136 @@ 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!");
+  }
+
+  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;
+};
+
 /// Base struct for all "concrete attribute" deductions.
 ///
 /// The abstract attribute is a minimal interface that allows the Attributor to
@@ -543,25 +672,6 @@ struct BooleanState : public IntegerStat
 ///       described in the file comment.
 struct AbstractAttribute {
 
-  /// The positions attributes can be manifested in.
-  enum ManifestPosition {
-    MP_ARGUMENT,           ///< An attribute for a function argument.
-    MP_CALL_SITE_ARGUMENT, ///< An attribute for a call site argument.
-    MP_FUNCTION,           ///< An attribute for a function as a whole.
-    MP_RETURNED,           ///< An attribute for the function return value.
-  };
-
-  /// An abstract attribute associated with \p AssociatedVal and anchored at
-  /// \p AnchoredVal.
-  ///
-  /// \param AssociatedVal The value this abstract attribute is associated with.
-  /// \param AnchoredVal The value this abstract attributes is anchored at.
-  AbstractAttribute(Value *AssociatedVal, Value &AnchoredVal)
-      : AssociatedVal(AssociatedVal), AnchoredVal(AnchoredVal) {}
-
-  /// An abstract attribute associated with and anchored at \p V.
-  AbstractAttribute(Value &V) : AbstractAttribute(&V, V) {}
-
   /// Virtual destructor.
   virtual ~AbstractAttribute() {}
 
@@ -578,43 +688,15 @@ struct AbstractAttribute {
   /// Return the internal abstract state for inspection.
   virtual const AbstractState &getState() const = 0;
 
-  /// 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 &getAnchoredValue() { return AnchoredVal; }
-  const Value &getAnchoredValue() const { return AnchoredVal; }
-  ///}
-
-  /// Return the llvm::Function surrounding the anchored value.
-  ///
-  ///{
-  Function &getAnchorScope();
-  const Function &getAnchorScope() const;
-  ///}
-
-  /// Return the value this abstract attribute is associated with.
-  ///
-  /// The abstract state usually represents this value.
-  ///
-  ///{
-  virtual Value *getAssociatedValue() { return AssociatedVal; }
-  virtual const Value *getAssociatedValue() const { return AssociatedVal; }
-  ///}
-
-  /// Return the position this abstract state is manifested in.
-  virtual ManifestPosition getManifestPosition() const = 0;
+  /// Return an IR position, see struct IRPosition.
+  virtual const IRPosition &getIRPosition() const = 0;
 
   /// Return the kind that identifies the abstract attribute implementation.
   virtual Attribute::AttrKind getAttrKind() const = 0;
 
   /// Return the deduced attributes in \p Attrs.
   virtual void getDeducedAttributes(SmallVectorImpl<Attribute> &Attrs) const {
-    LLVMContext &Ctx = AnchoredVal.getContext();
+    LLVMContext &Ctx = getIRPosition().getAnchorScope().getContext();
     Attrs.emplace_back(Attribute::get(Ctx, getAttrKind()));
   }
 
@@ -644,6 +726,8 @@ protected:
   ///
   /// \Return CHANGED if the IR was altered, otherwise UNCHANGED.
   virtual ChangeStatus manifest(Attributor &A);
+  /// Return an IR position, see struct IRPosition.
+  virtual IRPosition &getIRPosition() = 0;
 
   /// Return the internal abstract state for careful modification.
   virtual AbstractState &getState() = 0;
@@ -657,12 +741,6 @@ protected:
   /// \Return CHANGED if the internal state changed, otherwise UNCHANGED.
   virtual ChangeStatus updateImpl(Attributor &A,
                                   InformationCache &InfoCache) = 0;
-
-  /// The value this abstract attribute is associated with.
-  Value *AssociatedVal;
-
-  /// The value this abstract attribute is anchored at.
-  Value &AnchoredVal;
 };
 
 /// Forward declarations of output streams for debug purposes.
@@ -670,7 +748,8 @@ protected:
 ///{
 raw_ostream &operator<<(raw_ostream &OS, const AbstractAttribute &AA);
 raw_ostream &operator<<(raw_ostream &OS, ChangeStatus S);
-raw_ostream &operator<<(raw_ostream &OS, AbstractAttribute::ManifestPosition);
+raw_ostream &operator<<(raw_ostream &OS, IRPosition::Kind);
+raw_ostream &operator<<(raw_ostream &OS, const IRPosition &);
 raw_ostream &operator<<(raw_ostream &OS, const AbstractState &State);
 ///}
 
@@ -686,8 +765,6 @@ Pass *createAttributorLegacyPass();
 
 /// An abstract attribute for the returned values of a function.
 struct AAReturnedValues : public AbstractAttribute {
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AAReturnedValues(Function &F) : AbstractAttribute(F) {}
 
   /// Check \p Pred on all returned values.
   ///
@@ -708,8 +785,6 @@ struct AAReturnedValues : public Abstrac
 };
 
 struct AANoUnwind : public AbstractAttribute {
-  /// An abstract interface for all nosync attributes.
-  AANoUnwind(Value &V) : AbstractAttribute(V) {}
 
   /// See AbstractAttribute::getAttrKind()/
   Attribute::AttrKind getAttrKind() const override {
@@ -727,8 +802,6 @@ struct AANoUnwind : public AbstractAttri
 };
 
 struct AANoSync : public AbstractAttribute {
-  /// An abstract interface for all nosync attributes.
-  AANoSync(Value &V) : AbstractAttribute(V) {}
 
   /// See AbstractAttribute::getAttrKind().
   Attribute::AttrKind getAttrKind() const override { return Attribute::NoSync; }
@@ -746,13 +819,6 @@ struct AANoSync : public AbstractAttribu
 /// An abstract interface for all nonnull attributes.
 struct AANonNull : public AbstractAttribute {
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AANonNull(Value &V) : AbstractAttribute(V) {}
-
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AANonNull(Value *AssociatedVal, Value &AnchoredValue)
-      : AbstractAttribute(AssociatedVal, AnchoredValue) {}
-
   /// Return true if we assume that the underlying value is nonnull.
   virtual bool isAssumedNonNull() const = 0;
 
@@ -771,9 +837,6 @@ struct AANonNull : public AbstractAttrib
 /// An abstract attribute for norecurse.
 struct AANoRecurse : public AbstractAttribute {
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AANoRecurse(Value &V) : AbstractAttribute(V) {}
-
   /// See AbstractAttribute::getAttrKind()
   virtual Attribute::AttrKind getAttrKind() const override {
     return Attribute::NoRecurse;
@@ -792,9 +855,6 @@ struct AANoRecurse : public AbstractAttr
 /// An abstract attribute for willreturn.
 struct AAWillReturn : public AbstractAttribute {
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AAWillReturn(Value &V) : AbstractAttribute(V) {}
-
   /// See AbstractAttribute::getAttrKind()
   virtual Attribute::AttrKind getAttrKind() const override {
     return Attribute::WillReturn;
@@ -813,9 +873,6 @@ struct AAWillReturn : public AbstractAtt
 /// An abstract interface for all noalias attributes.
 struct AANoAlias : public AbstractAttribute {
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AANoAlias(Value &V) : AbstractAttribute(V) {}
-
   /// Return true if we assume that the underlying value is alias.
   virtual bool isAssumedNoAlias() const = 0;
 
@@ -834,9 +891,6 @@ struct AANoAlias : public AbstractAttrib
 /// An AbstractAttribute for noreturn.
 struct AANoReturn : public AbstractAttribute {
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AANoReturn(Value &V) : AbstractAttribute(V) {}
-
   /// Return true if the underlying object is known to never return.
   virtual bool isKnownNoReturn() const = 0;
 
@@ -855,9 +909,6 @@ struct AANoReturn : public AbstractAttri
 /// An abstract interface for liveness abstract attribute.
 struct AAIsDead : public AbstractAttribute {
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AAIsDead(Value &V) : AbstractAttribute(V) {}
-
   /// See AbstractAttribute::getAttrKind()
   Attribute::AttrKind getAttrKind() const override { return Attribute::None; }
 
@@ -877,7 +928,7 @@ struct AAIsDead : public AbstractAttribu
   /// of instructions is live.
   template <typename T> bool isLiveInstSet(T begin, T end) const {
     for (const auto &I : llvm::make_range(begin, end)) {
-      assert(I->getFunction() == &getAnchorScope() &&
+      assert(I->getFunction() == &getIRPosition().getAnchorScope() &&
              "Instruction must be in the same anchor scope function.");
 
       if (!isAssumedDead(I))
@@ -894,13 +945,6 @@ struct AAIsDead : public AbstractAttribu
 /// An abstract interface for all dereferenceable attribute.
 struct AADereferenceable : public AbstractAttribute {
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AADereferenceable(Value &V) : AbstractAttribute(V) {}
-
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AADereferenceable(Value *AssociatedVal, Value &AnchoredValue)
-      : AbstractAttribute(AssociatedVal, AnchoredValue) {}
-
   /// Return true if we assume that the underlying value is nonnull.
   virtual bool isAssumedNonNull() const = 0;
 
@@ -933,24 +977,17 @@ struct AADereferenceable : public Abstra
 /// An abstract interface for all align attributes.
 struct AAAlign : public AbstractAttribute {
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AAAlign(Value &V) : AbstractAttribute(V) {}
+  /// Return assumed alignment.
+  virtual unsigned getAssumedAlign() const = 0;
 
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AAAlign(Value *AssociatedVal, Value &AnchoredValue)
-      : AbstractAttribute(AssociatedVal, AnchoredValue) {}
+  /// Return known alignemnt.
+  virtual unsigned getKnownAlign() const = 0;
 
   /// See AbastractState::getAttrKind().
   Attribute::AttrKind getAttrKind() const override {
     return Attribute::Alignment;
   }
 
-  /// Return assumed alignment.
-  virtual unsigned getAssumedAlign() const = 0;
-
-  /// Return known alignemnt.
-  virtual unsigned getKnownAlign() const = 0;
-
   /// Unique ID (due to the unique address)
   static const char ID;
 };

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=367952&r1=367951&r2=367952&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Mon Aug  5 16:32:31 2019
@@ -114,21 +114,20 @@ ChangeStatus llvm::operator&(ChangeStatu
 ///}
 
 /// Helper to adjust the statistics.
-static void bookkeeping(AbstractAttribute::ManifestPosition MP,
-                        const Attribute &Attr) {
+static void bookkeeping(IRPosition::Kind PK, const Attribute &Attr) {
   if (!AreStatisticsEnabled())
     return;
 
   switch (Attr.getKindAsEnum()) {
   case Attribute::Alignment:
-    switch (MP) {
-    case AbstractAttribute::MP_RETURNED:
+    switch (PK) {
+    case IRPosition::IRP_RETURNED:
       NumFnReturnedAlign++;
       break;
-    case AbstractAttribute::MP_ARGUMENT:
+    case IRPosition::IRP_ARGUMENT:
       NumFnArgumentAlign++;
       break;
-    case AbstractAttribute::MP_CALL_SITE_ARGUMENT:
+    case IRPosition::IRP_CALL_SITE_ARGUMENT:
       NumCSArgumentAlign++;
       break;
     default:
@@ -136,14 +135,14 @@ static void bookkeeping(AbstractAttribut
     }
     break;
   case Attribute::Dereferenceable:
-    switch (MP) {
-    case AbstractAttribute::MP_RETURNED:
+    switch (PK) {
+    case IRPosition::IRP_RETURNED:
       NumFnReturnedDereferenceable++;
       break;
-    case AbstractAttribute::MP_ARGUMENT:
+    case IRPosition::IRP_ARGUMENT:
       NumFnArgumentDereferenceable++;
       break;
-    case AbstractAttribute::MP_CALL_SITE_ARGUMENT:
+    case IRPosition::IRP_CALL_SITE_ARGUMENT:
       NumCSArgumentDereferenceable++;
       break;
     default:
@@ -163,14 +162,14 @@ static void bookkeeping(AbstractAttribut
     NumFnNoFree++;
     break;
   case Attribute::NonNull:
-    switch (MP) {
-    case AbstractAttribute::MP_RETURNED:
+    switch (PK) {
+    case IRPosition::IRP_RETURNED:
       NumFnReturnedNonNull++;
       break;
-    case AbstractAttribute::MP_ARGUMENT:
+    case IRPosition::IRP_ARGUMENT:
       NumFnArgumentNonNull++;
       break;
-    case AbstractAttribute::MP_CALL_SITE_ARGUMENT:
+    case IRPosition::IRP_CALL_SITE_ARGUMENT:
       NumCSArgumentNonNull++;
       break;
     default:
@@ -274,21 +273,6 @@ static bool genericValueTraversal(
   return true;
 }
 
-/// Helper to identify the correct offset into an attribute list.
-static unsigned getAttrIndex(AbstractAttribute::ManifestPosition MP,
-                             unsigned ArgNo = 0) {
-  switch (MP) {
-  case AbstractAttribute::MP_ARGUMENT:
-  case AbstractAttribute::MP_CALL_SITE_ARGUMENT:
-    return ArgNo + AttributeList::FirstArgIndex;
-  case AbstractAttribute::MP_FUNCTION:
-    return AttributeList::FunctionIndex;
-  case AbstractAttribute::MP_RETURNED:
-    return AttributeList::ReturnIndex;
-  }
-  llvm_unreachable("Unknown manifest position!");
-}
-
 /// Return true if \p New is equal or worse than \p Old.
 static bool isEqualOrWorse(const Attribute &New, const Attribute &Old) {
   if (!Old.isIntAttribute())
@@ -299,12 +283,9 @@ static bool isEqualOrWorse(const Attribu
 
 /// Return true if the information provided by \p Attr was added to the
 /// attribute list \p Attrs. This is only the case if it was not already present
-/// in \p Attrs at the position describe by \p MP and \p ArgNo.
+/// in \p Attrs at the position describe by \p PK and \p AttrIdx.
 static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr,
-                             AttributeList &Attrs,
-                             AbstractAttribute::ManifestPosition MP,
-                             unsigned ArgNo = 0) {
-  unsigned AttrIdx = getAttrIndex(MP, ArgNo);
+                             AttributeList &Attrs, int AttrIdx) {
 
   if (Attr.isEnumAttribute()) {
     Attribute::AttrKind Kind = Attr.getKindAsEnum();
@@ -354,98 +335,73 @@ ChangeStatus AbstractAttribute::update(A
 ChangeStatus AbstractAttribute::manifest(Attributor &A) {
   assert(getState().isValidState() &&
          "Attempted to manifest an invalid state!");
-  assert(getAssociatedValue() &&
+  assert(getIRPosition().getAssociatedValue() &&
          "Attempted to manifest an attribute without associated value!");
 
   ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
-  SmallVector<Attribute, 4> DeducedAttrs;
-  getDeducedAttributes(DeducedAttrs);
 
-  Function &ScopeFn = getAnchorScope();
+  IRPosition &Pos = getIRPosition();
+  Function &ScopeFn = Pos.getAnchorScope();
   LLVMContext &Ctx = ScopeFn.getContext();
-  ManifestPosition MP = getManifestPosition();
+  IRPosition::Kind PK = Pos.getPositionKind();
 
-  AttributeList Attrs;
-  SmallVector<unsigned, 4> ArgNos;
+  SmallVector<Attribute, 4> DeducedAttrs;
+  getDeducedAttributes(DeducedAttrs);
 
   // In the following some generic code that will manifest attributes in
   // DeducedAttrs if they improve the current IR. Due to the different
   // annotation positions we use the underlying AttributeList interface.
-  // Note that MP_CALL_SITE_ARGUMENT can annotate multiple locations.
 
-  switch (MP) {
-  case MP_ARGUMENT:
-    ArgNos.push_back(cast<Argument>(getAssociatedValue())->getArgNo());
+  AttributeList Attrs;
+  switch (PK) {
+  case IRPosition::IRP_ARGUMENT:
+  case IRPosition::IRP_FUNCTION:
+  case IRPosition::IRP_RETURNED:
     Attrs = ScopeFn.getAttributes();
     break;
-  case MP_FUNCTION:
-  case MP_RETURNED:
-    ArgNos.push_back(0);
-    Attrs = ScopeFn.getAttributes();
+  case IRPosition::IRP_CALL_SITE_ARGUMENT:
+    Attrs = ImmutableCallSite(&Pos.getAnchorValue()).getAttributes();
     break;
-  case MP_CALL_SITE_ARGUMENT: {
-    CallSite CS(&getAnchoredValue());
-    for (unsigned u = 0, e = CS.getNumArgOperands(); u != e; u++)
-      if (CS.getArgOperand(u) == getAssociatedValue())
-        ArgNos.push_back(u);
-    Attrs = CS.getAttributes();
-  }
   }
 
   for (const Attribute &Attr : DeducedAttrs) {
-    for (unsigned ArgNo : ArgNos) {
-      if (!addIfNotExistent(Ctx, Attr, Attrs, MP, ArgNo))
-        continue;
+    if (!addIfNotExistent(Ctx, Attr, Attrs, Pos.getAttrIdx()))
+      continue;
 
-      HasChanged = ChangeStatus::CHANGED;
-      bookkeeping(MP, Attr);
-    }
+    HasChanged = ChangeStatus::CHANGED;
+    bookkeeping(PK, Attr);
   }
 
   if (HasChanged == ChangeStatus::UNCHANGED)
     return HasChanged;
 
-  switch (MP) {
-  case MP_ARGUMENT:
-  case MP_FUNCTION:
-  case MP_RETURNED:
+  switch (PK) {
+  case IRPosition::IRP_ARGUMENT:
+  case IRPosition::IRP_FUNCTION:
+  case IRPosition::IRP_RETURNED:
     ScopeFn.setAttributes(Attrs);
     break;
-  case MP_CALL_SITE_ARGUMENT:
-    CallSite(&getAnchoredValue()).setAttributes(Attrs);
+  case IRPosition::IRP_CALL_SITE_ARGUMENT:
+    CallSite(&Pos.getAnchorValue()).setAttributes(Attrs);
   }
 
   return HasChanged;
 }
 
-Function &AbstractAttribute::getAnchorScope() {
-  Value &V = getAnchoredValue();
-  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 &AbstractAttribute::getAnchorScope() const {
-  return const_cast<AbstractAttribute *>(this)->getAnchorScope();
-}
-
-// Helper function that returns argument index of value.
-// If the value is not an argument, this returns -1.
-static int getArgNo(Value &V) {
-  if (auto *Arg = dyn_cast<Argument>(&V))
-    return Arg->getArgNo();
-  return -1;
-}
-
 /// -----------------------NoUnwind Function Attribute--------------------------
 
-struct AANoUnwindFunction : AANoUnwind, BooleanState {
-
-  AANoUnwindFunction(Function &F) : AANoUnwind(F) {}
+#define IRPositionConstructorForward(NAME)                                     \
+  NAME(Argument &Arg) : IRPosition(Arg) {}                                     \
+  NAME(Function &Fn, IRPosition::Kind PK) : IRPosition(Fn, PK) {}              \
+  NAME(Value *AssociatedVal, Value &AnchorVal, unsigned ArgumentNo)            \
+      : IRPosition(AssociatedVal, AnchorVal, ArgumentNo) {}
+#define IRPositionGetter(IRP)                                                  \
+  IRPosition &getIRPosition() override { return IRP; }                         \
+  const IRPosition &getIRPosition() const override { return IRP; }
+
+struct AANoUnwindImpl : AANoUnwind, BooleanState, IRPosition {
+  IRPositionConstructorForward(AANoUnwindImpl);
+  IRPositionGetter(*this);
 
   /// See AbstractAttribute::getState()
   /// {
@@ -453,9 +409,6 @@ struct AANoUnwindFunction : AANoUnwind,
   const AbstractState &getState() const override { return *this; }
   /// }
 
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
-
   const std::string getAsStr() const override {
     return getAssumed() ? "nounwind" : "may-unwind";
   }
@@ -470,8 +423,12 @@ struct AANoUnwindFunction : AANoUnwind,
   bool isKnownNoUnwind() const override { return getKnown(); }
 };
 
-ChangeStatus AANoUnwindFunction::updateImpl(Attributor &A,
-                                            InformationCache &InfoCache) {
+struct AANoUnwindFunction final : public AANoUnwindImpl {
+  AANoUnwindFunction(Function &F) : AANoUnwindImpl(F, IRP_FUNCTION) {}
+};
+
+ChangeStatus AANoUnwindImpl::updateImpl(Attributor &A,
+                                        InformationCache &InfoCache) {
   Function &F = getAnchorScope();
 
   // The map from instruction opcodes to those instructions in the function.
@@ -508,7 +465,9 @@ ChangeStatus AANoUnwindFunction::updateI
 ///
 /// If there is a unique returned value R, the manifest method will:
 ///   - mark R with the "returned" attribute, if R is an argument.
-class AAReturnedValuesImpl final : public AAReturnedValues, AbstractState {
+class AAReturnedValuesImpl : public AAReturnedValues,
+                             public AbstractState,
+                             public IRPosition {
 
   /// Mapping of values potentially returned by the associated function to the
   /// return instructions that might return them.
@@ -545,11 +504,8 @@ class AAReturnedValuesImpl final : publi
   }
 
 public:
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AAReturnedValuesImpl(Function &F) : AAReturnedValues(F) {
-    // We do not have an associated argument yet.
-    AssociatedVal = nullptr;
-  }
+  IRPositionConstructorForward(AAReturnedValuesImpl);
+  IRPositionGetter(*this);
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override {
@@ -560,7 +516,7 @@ public:
     HasOverdefinedReturnedCalls = false;
     ReturnedValues.clear();
 
-    Function &F = cast<Function>(getAnchoredValue());
+    Function &F = cast<Function>(getAnchorValue());
 
     // The map from instruction opcodes to those instructions in the function.
     auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
@@ -596,9 +552,6 @@ public:
   /// See AbstractAttribute::getState(...).
   const AbstractState &getState() const override { return *this; }
 
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_ARGUMENT; }
-
   /// See AbstractAttribute::updateImpl(Attributor &A).
   ChangeStatus updateImpl(Attributor &A, InformationCache &InfoCache) override;
 
@@ -641,6 +594,11 @@ public:
   }
 };
 
+struct AAReturnedValuesFunction final : public AAReturnedValuesImpl {
+  AAReturnedValuesFunction(Function &F)
+      : AAReturnedValuesImpl(F, IRP_FUNCTION) {}
+};
+
 ChangeStatus AAReturnedValuesImpl::manifest(Attributor &A) {
   ChangeStatus Changed = ChangeStatus::UNCHANGED;
 
@@ -661,7 +619,8 @@ ChangeStatus AAReturnedValuesImpl::manif
 
   // If the assumed unique return value is an argument, annotate it.
   if (auto *UniqueRVArg = dyn_cast<Argument>(UniqueRV.getValue())) {
-    AssociatedVal = UniqueRVArg;
+    setAssociatedValue(UniqueRVArg);
+    setAttributeIdx(UniqueRVArg->getArgNo() + AttributeList::FirstArgIndex);
     Changed = AbstractAttribute::manifest(A) | Changed;
   }
 
@@ -862,9 +821,9 @@ ChangeStatus AAReturnedValuesImpl::updat
 
 /// ------------------------ NoSync Function Attribute -------------------------
 
-struct AANoSyncFunction : AANoSync, BooleanState {
-
-  AANoSyncFunction(Function &F) : AANoSync(F) {}
+struct AANoSyncImpl : AANoSync, BooleanState, IRPosition {
+  IRPositionConstructorForward(AANoSyncImpl);
+  IRPositionGetter(*this);
 
   /// See AbstractAttribute::getState()
   /// {
@@ -872,9 +831,6 @@ struct AANoSyncFunction : AANoSync, Bool
   const AbstractState &getState() const override { return *this; }
   /// }
 
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
-
   const std::string getAsStr() const override {
     return getAssumed() ? "nosync" : "may-sync";
   }
@@ -901,7 +857,11 @@ struct AANoSyncFunction : AANoSync, Bool
   static bool isNoSyncIntrinsic(Instruction *I);
 };
 
-bool AANoSyncFunction::isNonRelaxedAtomic(Instruction *I) {
+struct AANoSyncFunction final : public AANoSyncImpl {
+  AANoSyncFunction(Function &F) : AANoSyncImpl(F, IRP_FUNCTION) {}
+};
+
+bool AANoSyncImpl::isNonRelaxedAtomic(Instruction *I) {
   if (!I->isAtomic())
     return false;
 
@@ -950,7 +910,7 @@ bool AANoSyncFunction::isNonRelaxedAtomi
 
 /// Checks if an intrinsic is nosync. Currently only checks mem* intrinsics.
 /// FIXME: We should ipmrove the handling of intrinsics.
-bool AANoSyncFunction::isNoSyncIntrinsic(Instruction *I) {
+bool AANoSyncImpl::isNoSyncIntrinsic(Instruction *I) {
   if (auto *II = dyn_cast<IntrinsicInst>(I)) {
     switch (II->getIntrinsicID()) {
     /// Element wise atomic memory intrinsics are can only be unordered,
@@ -972,7 +932,7 @@ bool AANoSyncFunction::isNoSyncIntrinsic
   return false;
 }
 
-bool AANoSyncFunction::isVolatile(Instruction *I) {
+bool AANoSyncImpl::isVolatile(Instruction *I) {
   assert(!ImmutableCallSite(I) && !isa<CallBase>(I) &&
          "Calls should not be checked here");
 
@@ -990,8 +950,8 @@ bool AANoSyncFunction::isVolatile(Instru
   }
 }
 
-ChangeStatus AANoSyncFunction::updateImpl(Attributor &A,
-                                          InformationCache &InfoCache) {
+ChangeStatus AANoSyncImpl::updateImpl(Attributor &A,
+                                      InformationCache &InfoCache) {
   Function &F = getAnchorScope();
 
   auto *LivenessAA = A.getAAFor<AAIsDead>(*this, F);
@@ -1004,7 +964,7 @@ ChangeStatus AANoSyncFunction::updateImp
       continue;
 
     ImmutableCallSite ICS(I);
-    auto *NoSyncAA = A.getAAFor<AANoSyncFunction>(*this, *I);
+    auto *NoSyncAA = A.getAAFor<AANoSyncImpl>(*this, *I);
 
     if (isa<IntrinsicInst>(I) && isNoSyncIntrinsic(I))
       continue;
@@ -1051,10 +1011,9 @@ ChangeStatus AANoSyncFunction::updateImp
 
 /// ------------------------ No-Free Attributes ----------------------------
 
-struct AANoFreeFunction : AbstractAttribute, BooleanState {
-
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AANoFreeFunction(Function &F) : AbstractAttribute(F) {}
+struct AANoFreeImpl : AbstractAttribute, BooleanState, IRPosition {
+  IRPositionConstructorForward(AANoFreeImpl);
+  IRPositionGetter(*this);
 
   /// See AbstractAttribute::getState()
   ///{
@@ -1062,9 +1021,6 @@ struct AANoFreeFunction : AbstractAttrib
   const AbstractState &getState() const override { return *this; }
   ///}
 
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
-
   /// See AbstractAttribute::getAsStr().
   const std::string getAsStr() const override {
     return getAssumed() ? "nofree" : "may-free";
@@ -1086,8 +1042,12 @@ struct AANoFreeFunction : AbstractAttrib
   static const char ID;
 };
 
-ChangeStatus AANoFreeFunction::updateImpl(Attributor &A,
-                                          InformationCache &InfoCache) {
+struct AANoFreeFunction final : public AANoFreeImpl {
+  AANoFreeFunction(Function &F) : AANoFreeImpl(F, IRP_FUNCTION) {}
+};
+
+ChangeStatus AANoFreeImpl::updateImpl(Attributor &A,
+                                      InformationCache &InfoCache) {
   Function &F = getAnchorScope();
 
   auto *LivenessAA = A.getAAFor<AAIsDead>(*this, F);
@@ -1103,7 +1063,7 @@ ChangeStatus AANoFreeFunction::updateImp
       if (LivenessAA && LivenessAA->isAssumedDead(I))
         continue;
       auto ICS = ImmutableCallSite(I);
-      auto *NoFreeAA = A.getAAFor<AANoFreeFunction>(*this, *I);
+      auto *NoFreeAA = A.getAAFor<AANoFreeImpl>(*this, *I);
 
       if ((!NoFreeAA || !NoFreeAA->isAssumedNoFree()) &&
           !ICS.hasFnAttr(Attribute::NoFree))
@@ -1114,12 +1074,9 @@ ChangeStatus AANoFreeFunction::updateImp
 }
 
 /// ------------------------ NonNull Argument Attribute ------------------------
-struct AANonNullImpl : AANonNull, BooleanState {
-
-  AANonNullImpl(Value &V) : AANonNull(V) {}
-
-  AANonNullImpl(Value *AssociatedVal, Value &AnchoredValue)
-      : AANonNull(AssociatedVal, AnchoredValue) {}
+struct AANonNullImpl : AANonNull, BooleanState, IRPosition {
+  IRPositionConstructorForward(AANonNullImpl);
+  IRPositionGetter(*this);
 
   /// See AbstractAttribute::getState()
   /// {
@@ -1179,10 +1136,7 @@ AANonNullImpl::generatePredicate(Attribu
 /// NonNull attribute for function return value.
 struct AANonNullReturned : AANonNullImpl {
 
-  AANonNullReturned(Function &F) : AANonNullImpl(F) {}
-
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_RETURNED; }
+  AANonNullReturned(Function &F) : AANonNullImpl(F, IRP_RETURNED) {}
 
   /// See AbstractAttriubute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override {
@@ -1221,9 +1175,6 @@ struct AANonNullArgument : AANonNullImpl
 
   AANonNullArgument(Argument &A) : AANonNullImpl(A) {}
 
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_ARGUMENT; }
-
   /// See AbstractAttriubute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override {
     Argument *Arg = cast<Argument>(getAssociatedValue());
@@ -1240,14 +1191,13 @@ struct AANonNullCallSiteArgument : AANon
 
   /// See AANonNullImpl::AANonNullImpl(...).
   AANonNullCallSiteArgument(CallSite CS, unsigned ArgNo)
-      : AANonNullImpl(CS.getArgOperand(ArgNo), *CS.getInstruction()),
-        ArgNo(ArgNo) {}
+      : AANonNullImpl(CS.getArgOperand(ArgNo), *CS.getInstruction(), ArgNo) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override {
-    CallSite CS(&getAnchoredValue());
-    if (CS.paramHasAttr(ArgNo, getAttrKind()) ||
-        CS.paramHasAttr(ArgNo, Attribute::Dereferenceable) ||
+    CallSite CS(&getAnchorValue());
+    if (CS.paramHasAttr(getArgNo(), getAttrKind()) ||
+        CS.paramHasAttr(getArgNo(), Attribute::Dereferenceable) ||
         isKnownNonZero(getAssociatedValue(),
                        getAnchorScope().getParent()->getDataLayout()))
       indicateOptimisticFixpoint();
@@ -1255,23 +1205,12 @@ struct AANonNullCallSiteArgument : AANon
 
   /// See AbstractAttribute::updateImpl(Attributor &A).
   ChangeStatus updateImpl(Attributor &A, InformationCache &InfoCache) override;
-
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override {
-    return MP_CALL_SITE_ARGUMENT;
-  };
-
-  // Return argument index of associated value.
-  int getArgNo() const { return ArgNo; }
-
-private:
-  unsigned ArgNo;
 };
 
 ChangeStatus AANonNullArgument::updateImpl(Attributor &A,
                                            InformationCache &InfoCache) {
   Function &F = getAnchorScope();
-  Argument &Arg = cast<Argument>(getAnchoredValue());
+  Argument &Arg = cast<Argument>(getAnchorValue());
 
   unsigned ArgNo = Arg.getArgNo();
 
@@ -1283,7 +1222,7 @@ ChangeStatus AANonNullArgument::updateIm
 
     // Check that NonNullAA is AANonNullCallSiteArgument.
     if (NonNullAA) {
-      ImmutableCallSite ICS(&NonNullAA->getAnchoredValue());
+      ImmutableCallSite ICS(&NonNullAA->getIRPosition().getAnchorValue());
       if (ICS && CS.getInstruction() == ICS.getInstruction())
         return NonNullAA->isAssumedNonNull();
       return false;
@@ -1321,10 +1260,9 @@ AANonNullCallSiteArgument::updateImpl(At
 
 /// ------------------------ Will-Return Attributes ----------------------------
 
-struct AAWillReturnImpl : public AAWillReturn, BooleanState {
-
-  /// See AbstractAttribute::AbstractAttribute(...).
-  AAWillReturnImpl(Function &F) : AAWillReturn(F) {}
+struct AAWillReturnImpl : public AAWillReturn, BooleanState, IRPosition {
+  IRPositionConstructorForward(AAWillReturnImpl);
+  IRPositionGetter(*this);
 
   /// See AAWillReturn::isKnownWillReturn().
   bool isKnownWillReturn() const override { return getKnown(); }
@@ -1347,10 +1285,7 @@ struct AAWillReturnImpl : public AAWillR
 struct AAWillReturnFunction final : AAWillReturnImpl {
 
   /// See AbstractAttribute::AbstractAttribute(...).
-  AAWillReturnFunction(Function &F) : AAWillReturnImpl(F) {}
-
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
+  AAWillReturnFunction(Function &F) : AAWillReturnImpl(F, IRP_FUNCTION) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override;
@@ -1432,9 +1367,9 @@ ChangeStatus AAWillReturnFunction::updat
 
 /// ------------------------ NoAlias Argument Attribute ------------------------
 
-struct AANoAliasImpl : AANoAlias, BooleanState {
-
-  AANoAliasImpl(Value &V) : AANoAlias(V) {}
+struct AANoAliasImpl : AANoAlias, BooleanState, IRPosition {
+  IRPositionConstructorForward(AANoAliasImpl);
+  IRPositionGetter(*this);
 
   /// See AbstractAttribute::getState()
   /// {
@@ -1456,12 +1391,7 @@ struct AANoAliasImpl : AANoAlias, Boolea
 /// NoAlias attribute for function return value.
 struct AANoAliasReturned : AANoAliasImpl {
 
-  AANoAliasReturned(Function &F) : AANoAliasImpl(F) {}
-
-  /// See AbstractAttribute::getManifestPosition().
-  virtual ManifestPosition getManifestPosition() const override {
-    return MP_RETURNED;
-  }
+  AANoAliasReturned(Function &F) : AANoAliasImpl(F, IRP_RETURNED) {}
 
   /// See AbstractAttriubute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override {
@@ -1523,18 +1453,9 @@ ChangeStatus AANoAliasReturned::updateIm
 
 /// -------------------AAIsDead Function Attribute-----------------------
 
-struct AAIsDeadFunction : AAIsDead, BooleanState {
-
-  AAIsDeadFunction(Function &F) : AAIsDead(F) {}
-
-  /// See AbstractAttribute::getState()
-  /// {
-  AbstractState &getState() override { return *this; }
-  const AbstractState &getState() const override { return *this; }
-  /// }
-
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
+struct AAIsDeadImpl : public AAIsDead, BooleanState, IRPosition {
+  IRPositionConstructorForward(AAIsDeadImpl);
+  IRPositionGetter(*this);
 
   void initialize(Attributor &A, InformationCache &InfoCache) override {
     Function &F = getAnchorScope();
@@ -1672,6 +1593,12 @@ struct AAIsDeadFunction : AAIsDead, Bool
     return F.hasPersonalityFn() && !canSimplifyInvokeNoUnwind(&F);
   }
 
+  /// See AbstractAttribute::getState()
+  /// {
+  AbstractState &getState() override { return *this; }
+  const AbstractState &getState() const override { return *this; }
+  /// }
+
   /// Collection of to be explored paths.
   SmallSetVector<const Instruction *, 8> ToBeExploredPaths;
 
@@ -1682,7 +1609,11 @@ struct AAIsDeadFunction : AAIsDead, Bool
   SmallSetVector<const Instruction *, 4> NoReturnCalls;
 };
 
-bool AAIsDeadFunction::isAfterNoReturn(const Instruction *I) const {
+struct AAIsDeadFunction final : public AAIsDeadImpl {
+  AAIsDeadFunction(Function &F) : AAIsDeadImpl(F, IRP_FUNCTION) {}
+};
+
+bool AAIsDeadImpl::isAfterNoReturn(const Instruction *I) const {
   const Instruction *PrevI = I->getPrevNode();
   while (PrevI) {
     if (NoReturnCalls.count(PrevI))
@@ -1692,8 +1623,8 @@ bool AAIsDeadFunction::isAfterNoReturn(c
   return false;
 }
 
-const Instruction *AAIsDeadFunction::findNextNoReturn(Attributor &A,
-                                                      const Instruction *I) {
+const Instruction *AAIsDeadImpl::findNextNoReturn(Attributor &A,
+                                                  const Instruction *I) {
   const BasicBlock *BB = I->getParent();
   const Function &F = *BB->getParent();
 
@@ -1743,8 +1674,8 @@ const Instruction *AAIsDeadFunction::fin
   return nullptr;
 }
 
-ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A,
-                                          InformationCache &InfoCache) {
+ChangeStatus AAIsDeadImpl::updateImpl(Attributor &A,
+                                      InformationCache &InfoCache) {
   // Temporary collection to iterate over existing noreturn instructions. This
   // will alow easier modification of NoReturnCalls collection
   SmallVector<const Instruction *, 8> NoReturnChanged;
@@ -1843,12 +1774,10 @@ struct DerefState : AbstractState {
            this->NonNullGlobalState == R.NonNullGlobalState;
   }
 };
-struct AADereferenceableImpl : AADereferenceable, DerefState {
-
-  AADereferenceableImpl(Value &V) : AADereferenceable(V) {}
 
-  AADereferenceableImpl(Value *AssociatedVal, Value &AnchoredValue)
-      : AADereferenceable(AssociatedVal, AnchoredValue) {}
+struct AADereferenceableImpl : AADereferenceable, DerefState, IRPosition {
+  IRPositionConstructorForward(AADereferenceableImpl);
+  IRPositionGetter(*this);
 
   /// See AbstractAttribute::getState()
   /// {
@@ -1901,7 +1830,7 @@ struct AADereferenceableImpl : AADerefer
   }
 
   void getDeducedAttributes(SmallVectorImpl<Attribute> &Attrs) const override {
-    LLVMContext &Ctx = AnchoredVal.getContext();
+    LLVMContext &Ctx = AnchorVal.getContext();
 
     // TODO: Add *_globally support
     if (isAssumedNonNull())
@@ -1916,8 +1845,7 @@ struct AADereferenceableImpl : AADerefer
 
   void initialize(Attributor &A, InformationCache &InfoCache) override {
     Function &F = getAnchorScope();
-    unsigned AttrIdx =
-        getAttrIndex(getManifestPosition(), getArgNo(getAnchoredValue()));
+    unsigned AttrIdx = getIRPosition().getAttrIdx();
 
     for (Attribute::AttrKind AK :
          {Attribute::Dereferenceable, Attribute::DereferenceableOrNull})
@@ -1938,10 +1866,8 @@ struct AADereferenceableImpl : AADerefer
 };
 
 struct AADereferenceableReturned : AADereferenceableImpl {
-  AADereferenceableReturned(Function &F) : AADereferenceableImpl(F) {}
-
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_RETURNED; }
+  AADereferenceableReturned(Function &F)
+      : AADereferenceableImpl(F, IRP_RETURNED) {}
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A, InformationCache &InfoCache) override;
@@ -2027,9 +1953,6 @@ AADereferenceableReturned::updateImpl(At
 struct AADereferenceableArgument : AADereferenceableImpl {
   AADereferenceableArgument(Argument &A) : AADereferenceableImpl(A) {}
 
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_ARGUMENT; }
-
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A, InformationCache &InfoCache) override;
 };
@@ -2038,7 +1961,7 @@ ChangeStatus
 AADereferenceableArgument::updateImpl(Attributor &A,
                                       InformationCache &InfoCache) {
   Function &F = getAnchorScope();
-  Argument &Arg = cast<Argument>(getAnchoredValue());
+  Argument &Arg = cast<Argument>(getAnchorValue());
 
   auto BeforeState = static_cast<DerefState>(*this);
 
@@ -2056,7 +1979,8 @@ AADereferenceableArgument::updateImpl(At
     // Check that DereferenceableAA is AADereferenceableCallSiteArgument.
     if (auto *DereferenceableAA =
             A.getAAFor<AADereferenceable>(*this, *CS.getInstruction(), ArgNo)) {
-      ImmutableCallSite ICS(&DereferenceableAA->getAnchoredValue());
+      ImmutableCallSite ICS(
+          &DereferenceableAA->getIRPosition().getAnchorValue());
       if (ICS && CS.getInstruction() == ICS.getInstruction()) {
         takeAssumedDerefBytesMinimum(
             DereferenceableAA->getAssumedDereferenceableBytes());
@@ -2086,34 +2010,21 @@ struct AADereferenceableCallSiteArgument
 
   /// See AADereferenceableImpl::AADereferenceableImpl(...).
   AADereferenceableCallSiteArgument(CallSite CS, unsigned ArgNo)
-      : AADereferenceableImpl(CS.getArgOperand(ArgNo), *CS.getInstruction()),
-        ArgNo(ArgNo) {}
+      : AADereferenceableImpl(CS.getArgOperand(ArgNo), *CS.getInstruction(),
+                              ArgNo) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override {
-    CallSite CS(&getAnchoredValue());
-    if (CS.paramHasAttr(ArgNo, Attribute::Dereferenceable))
-      takeKnownDerefBytesMaximum(
-          CS.getDereferenceableBytes(ArgNo + AttributeList::FirstArgIndex));
-
-    if (CS.paramHasAttr(ArgNo, Attribute::DereferenceableOrNull))
-      takeKnownDerefBytesMaximum(CS.getDereferenceableOrNullBytes(
-          ArgNo + AttributeList::FirstArgIndex));
+    CallSite CS(&getAnchorValue());
+    if (CS.paramHasAttr(getArgNo(), Attribute::Dereferenceable))
+      takeKnownDerefBytesMaximum(CS.getDereferenceableBytes(getArgNo()));
+
+    if (CS.paramHasAttr(getArgNo(), Attribute::DereferenceableOrNull))
+      takeKnownDerefBytesMaximum(CS.getDereferenceableOrNullBytes(getArgNo()));
   }
 
   /// See AbstractAttribute::updateImpl(Attributor &A).
   ChangeStatus updateImpl(Attributor &A, InformationCache &InfoCache) override;
-
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override {
-    return MP_CALL_SITE_ARGUMENT;
-  };
-
-  // Return argument index of associated value.
-  int getArgNo() const { return ArgNo; }
-
-private:
-  unsigned ArgNo;
 };
 
 ChangeStatus
@@ -2127,7 +2038,7 @@ AADereferenceableCallSiteArgument::updat
 
   auto BeforeState = static_cast<DerefState>(*this);
 
-  syncNonNull(A.getAAFor<AANonNull>(*this, getAnchoredValue(), ArgNo));
+  syncNonNull(A.getAAFor<AANonNull>(*this, getAnchorValue(), getArgNo()));
   bool IsNonNull = isAssumedNonNull();
   bool IsGlobal = isKnownGlobal();
 
@@ -2141,16 +2052,13 @@ AADereferenceableCallSiteArgument::updat
 
 // ------------------------ Align Argument Attribute ------------------------
 
-struct AAAlignImpl : AAAlign, IntegerState {
+struct AAAlignImpl : AAAlign, IntegerState, IRPosition {
+  IRPositionConstructorForward(AAAlignImpl);
+  IRPositionGetter(*this);
 
   // Max alignemnt value allowed in IR
   static const unsigned MAX_ALIGN = 1U << 29;
 
-  AAAlignImpl(Value *AssociatedVal, Value &AnchoredValue)
-      : AAAlign(AssociatedVal, AnchoredValue), IntegerState(MAX_ALIGN) {}
-
-  AAAlignImpl(Value &V) : AAAlignImpl(&V, V) {}
-
   /// See AbstractAttribute::getState()
   /// {
   AbstractState &getState() override { return *this; }
@@ -2171,10 +2079,11 @@ struct AAAlignImpl : AAAlign, IntegerSta
 
   /// See AbstractAttriubute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override {
+    takeAssumedMinimum(MAX_ALIGN);
+
     Function &F = getAnchorScope();
 
-    unsigned AttrIdx =
-        getAttrIndex(getManifestPosition(), getArgNo(getAnchoredValue()));
+    unsigned AttrIdx = getIRPosition().getAttrIdx();
 
     // Already the function has align attribute on return value or argument.
     if (F.getAttributes().hasAttribute(AttrIdx, Attribute::Alignment))
@@ -2185,21 +2094,16 @@ struct AAAlignImpl : AAAlign, IntegerSta
   /// See AbstractAttribute::getDeducedAttributes
   virtual void
   getDeducedAttributes(SmallVectorImpl<Attribute> &Attrs) const override {
-    LLVMContext &Ctx = AnchoredVal.getContext();
+    LLVMContext &Ctx = AnchorVal.getContext();
 
     Attrs.emplace_back(Attribute::getWithAlignment(Ctx, getAssumedAlign()));
   }
 };
 
 /// Align attribute for function return value.
-struct AAAlignReturned : AAAlignImpl {
+struct AAAlignReturned final : AAAlignImpl {
 
-  AAAlignReturned(Function &F) : AAAlignImpl(F) {}
-
-  /// See AbstractAttribute::getManifestPosition().
-  virtual ManifestPosition getManifestPosition() const override {
-    return MP_RETURNED;
-  }
+  AAAlignReturned(Function &F) : AAAlignImpl(F, IRP_RETURNED) {}
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A, InformationCache &InfoCache) override;
@@ -2240,15 +2144,10 @@ ChangeStatus AAAlignReturned::updateImpl
 }
 
 /// Align attribute for function argument.
-struct AAAlignArgument : AAAlignImpl {
+struct AAAlignArgument final : AAAlignImpl {
 
   AAAlignArgument(Argument &A) : AAAlignImpl(A) {}
 
-  /// See AbstractAttribute::getManifestPosition().
-  virtual ManifestPosition getManifestPosition() const override {
-    return MP_ARGUMENT;
-  }
-
   /// See AbstractAttribute::updateImpl(...).
   virtual ChangeStatus updateImpl(Attributor &A,
                                   InformationCache &InfoCache) override;
@@ -2258,7 +2157,7 @@ ChangeStatus AAAlignArgument::updateImpl
                                          InformationCache &InfoCache) {
 
   Function &F = getAnchorScope();
-  Argument &Arg = cast<Argument>(getAnchoredValue());
+  Argument &Arg = cast<Argument>(getAnchorValue());
 
   unsigned ArgNo = Arg.getArgNo();
   const DataLayout &DL = F.getParent()->getDataLayout();
@@ -2273,7 +2172,7 @@ ChangeStatus AAAlignArgument::updateImpl
 
     // Check that AlignAA is AAAlignCallSiteArgument.
     if (AlignAA) {
-      ImmutableCallSite ICS(&AlignAA->getAnchoredValue());
+      ImmutableCallSite ICS(&AlignAA->getIRPosition().getAnchorValue());
       if (ICS && CS.getInstruction() == ICS.getInstruction()) {
         takeAssumedMinimum(AlignAA->getAssumedAlign());
         return isValidState();
@@ -2292,33 +2191,21 @@ ChangeStatus AAAlignArgument::updateImpl
                                      : ChangeStatus ::CHANGED;
 }
 
-struct AAAlignCallSiteArgument : AAAlignImpl {
+struct AAAlignCallSiteArgument final : AAAlignImpl {
 
   /// See AANonNullImpl::AANonNullImpl(...).
   AAAlignCallSiteArgument(CallSite CS, unsigned ArgNo)
-      : AAAlignImpl(CS.getArgOperand(ArgNo), *CS.getInstruction()),
-        ArgNo(ArgNo) {}
+      : AAAlignImpl(CS.getArgOperand(ArgNo), *CS.getInstruction(), ArgNo) {}
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A, InformationCache &InfoCache) override {
-    CallSite CS(&getAnchoredValue());
+    CallSite CS(&getAnchorValue());
     takeKnownMaximum(getAssociatedValue()->getPointerAlignment(
         getAnchorScope().getParent()->getDataLayout()));
   }
 
   /// See AbstractAttribute::updateImpl(Attributor &A).
   ChangeStatus updateImpl(Attributor &A, InformationCache &InfoCache) override;
-
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override {
-    return MP_CALL_SITE_ARGUMENT;
-  };
-
-  // Return argument index of associated value.
-  int getArgNo() const { return ArgNo; }
-
-private:
-  unsigned ArgNo;
 };
 
 ChangeStatus AAAlignCallSiteArgument::updateImpl(Attributor &A,
@@ -2342,9 +2229,9 @@ ChangeStatus AAAlignCallSiteArgument::up
 }
 
 /// ------------------ Function No-Return Attribute ----------------------------
-struct AANoReturnFunction final : public AANoReturn, BooleanState {
-
-  AANoReturnFunction(Function &F) : AANoReturn(F) {}
+struct AANoReturnImpl : public AANoReturn, BooleanState, IRPosition {
+  IRPositionConstructorForward(AANoReturnImpl);
+  IRPositionGetter(*this);
 
   /// See AbstractAttribute::getState()
   /// {
@@ -2358,9 +2245,6 @@ struct AANoReturnFunction final : public
   /// Return true if the underlying object is assumed to never return.
   bool isAssumedNoReturn() const override { return getAssumed(); }
 
-  /// See AbstractAttribute::getManifestPosition().
-  ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
-
   /// See AbstractAttribute::getAsStr().
   const std::string getAsStr() const override {
     return getAssumed() ? "noreturn" : "may-return";
@@ -2395,6 +2279,10 @@ struct AANoReturnFunction final : public
   }
 };
 
+struct AANoReturnFunction final : AANoReturnImpl {
+  AANoReturnFunction(Function &F) : AANoReturnImpl(F, IRP_FUNCTION) {}
+};
+
 /// ----------------------------------------------------------------------------
 ///                               Attributor
 /// ----------------------------------------------------------------------------
@@ -2607,7 +2495,7 @@ void Attributor::identifyDefaultAbstract
     // Argument attribute "returned" --- Create only one per function even
     // though it is an argument attribute.
     if (!Whitelist || Whitelist->count(&AAReturnedValues::ID))
-      registerAA(*new AAReturnedValuesImpl(F));
+      registerAA(*new AAReturnedValuesFunction(F));
 
     if (ReturnType->isPointerTy()) {
       // Every function with pointer return type might be marked align.
@@ -2710,21 +2598,27 @@ raw_ostream &llvm::operator<<(raw_ostrea
   return OS << (S == ChangeStatus::CHANGED ? "changed" : "unchanged");
 }
 
-raw_ostream &llvm::operator<<(raw_ostream &OS,
-                              AbstractAttribute::ManifestPosition AP) {
+raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) {
   switch (AP) {
-  case AbstractAttribute::MP_ARGUMENT:
+  case IRPosition::IRP_ARGUMENT:
     return OS << "arg";
-  case AbstractAttribute::MP_CALL_SITE_ARGUMENT:
+  case IRPosition::IRP_CALL_SITE_ARGUMENT:
     return OS << "cs_arg";
-  case AbstractAttribute::MP_FUNCTION:
+  case IRPosition::IRP_FUNCTION:
     return OS << "fn";
-  case AbstractAttribute::MP_RETURNED:
+  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") << " ["
+            << Pos.getAnchorValue().getName() << "@" << Pos.getArgNo() << "]}";
+}
+
 raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractState &S) {
   return OS << (!S.isValidState() ? "top" : (S.isAtFixpoint() ? "fix" : ""));
 }
@@ -2735,8 +2629,8 @@ raw_ostream &llvm::operator<<(raw_ostrea
 }
 
 void AbstractAttribute::print(raw_ostream &OS) const {
-  OS << "[" << getManifestPosition() << "][" << getAsStr() << "]["
-     << AnchoredVal.getName() << "]";
+  OS << "[P: " << getIRPosition() << "][" << getAsStr() << "][S: " << getState()
+     << "]";
 }
 ///}
 
@@ -2822,7 +2716,7 @@ char AttributorLegacyPass::ID = 0;
 const char AAReturnedValues::ID = 0;
 const char AANoUnwind::ID = 0;
 const char AANoSync::ID = 0;
-const char AANoFreeFunction::ID = 0;
+const char AANoFreeImpl::ID = 0;
 const char AANonNull::ID = 0;
 const char AANoRecurse::ID = 0;
 const char AAWillReturn::ID = 0;




More information about the llvm-commits mailing list