diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h b/llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h
--- a/llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h
@@ -339,11 +339,11 @@
   /// \p OpIdx is the index in \p Attrs to add flags from.
   void addArgFlagsFromAttributes(ISD::ArgFlagsTy &Flags,
                                  const AttributeList &Attrs,
-                                 unsigned OpIdx) const;
+                                 AttributeList::Index OpIdx) const;
 
   template <typename FuncInfoTy>
-  void setArgFlags(ArgInfo &Arg, unsigned OpIdx, const DataLayout &DL,
-                   const FuncInfoTy &FuncInfo) const;
+  void setArgFlags(ArgInfo &Arg, AttributeList::Index OpIdx,
+                   const DataLayout &DL, const FuncInfoTy &FuncInfo) const;
 
   /// Break \p OrigArgInfo into one or more pieces the calling convention can
   /// process, returned in \p SplitArgs. For example, this should break structs
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -17,6 +17,7 @@
 
 #include "llvm-c/Types.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
@@ -384,12 +385,65 @@
 /// index `AttributeList::FirstArgIndex'.
 class AttributeList {
 public:
-  enum AttrIndex : unsigned {
-    ReturnIndex = 0U,
-    FunctionIndex = ~0U,
-    FirstArgIndex = 1,
+  //===--------------------------------------------------------------------===//
+  /// \class
+  /// This class act as an indexing type for the AttributeList.
+  class Index {
+  public:
+    Index() = default;
+    Index(unsigned Value) : Value(Value) {}
+
+    bool operator<(Index Other) const { return Value < Other.Value; }
+    bool operator==(Index Other) const { return Value == Other.Value; }
+    bool operator!=(Index Other) const { return Value != Other.Value; }
+
+    Index &operator++() {
+      ++Value;
+      return *this;
+    }
+
+    /// Whether this index refers to an Argument.
+    bool isArg() const {
+      return Value != ReturnIndex && Value != FunctionIndex;
+    }
+
+    /// When this index refers to an Argument, the position of the argument in
+    /// the function arguments list.
+    unsigned toArgNo() const {
+      assert(isArg() && "Not an argument");
+      return Value - FirstArgIndex;
+    }
+
+    /// The internal encoded representation of this Index.
+    /// Use with caution as it's an implementation detail.
+    unsigned rawValue() const { return Value; }
+
+  private:
+    static constexpr unsigned FirstArgIndex = 1;
+    static constexpr unsigned ReturnIndex = 0;
+    static constexpr unsigned FunctionIndex = ~0;
+
+    unsigned Value = 0;
+
+    /// Creates an Index representing the ArgNo argument in the function
+    /// arguments list.
+    static Index fromArgNo(unsigned ArgNo) { return {ArgNo + FirstArgIndex}; }
+
+    /// Map from AttributeList index to the internal array index. Adding one
+    /// happens to work, because -1 wraps around to 0.
+    unsigned arrayIndex() const { return Value + 1; }
+    static Index fromArrayIndex(unsigned Value) { return {Value - 1}; }
+
+    friend class AttributeList;
+    friend class AttributeListImpl;
   };
 
+  /// Creates an Index representing the ArgNo argument in the function arguments
+  /// list.
+  static Index getArgIndex(unsigned ArgNo) { return Index::fromArgNo(ArgNo); }
+  static const Index ReturnIndex;
+  static const Index FunctionIndex;
+
 private:
   friend class AttrBuilder;
   friend class AttributeListImpl;
@@ -404,9 +458,9 @@
 public:
   /// Create an AttributeList with the specified parameters in it.
   static AttributeList get(LLVMContext &C,
-                           ArrayRef<std::pair<unsigned, Attribute>> Attrs);
+                           ArrayRef<std::pair<Index, Attribute>> Attrs);
   static AttributeList get(LLVMContext &C,
-                           ArrayRef<std::pair<unsigned, AttributeSet>> Attrs);
+                           ArrayRef<std::pair<Index, AttributeSet>> Attrs);
 
   /// Create an AttributeList from attribute sets for a function, its
   /// return value, and all of its arguments.
@@ -419,7 +473,7 @@
 
   static AttributeList getImpl(LLVMContext &C, ArrayRef<AttributeSet> AttrSets);
 
-  AttributeList setAttributes(LLVMContext &C, unsigned Index,
+  AttributeList setAttributes(LLVMContext &C, Index Index,
                               AttributeSet Attrs) const;
 
 public:
@@ -431,42 +485,41 @@
 
   /// Return an AttributeList with the specified parameters in it.
   static AttributeList get(LLVMContext &C, ArrayRef<AttributeList> Attrs);
-  static AttributeList get(LLVMContext &C, unsigned Index,
+  static AttributeList get(LLVMContext &C, Index Index,
                            ArrayRef<Attribute::AttrKind> Kinds);
-  static AttributeList get(LLVMContext &C, unsigned Index,
+  static AttributeList get(LLVMContext &C, Index Index,
                            ArrayRef<Attribute::AttrKind> Kinds,
                            ArrayRef<uint64_t> Values);
-  static AttributeList get(LLVMContext &C, unsigned Index,
+  static AttributeList get(LLVMContext &C, Index Index,
                            ArrayRef<StringRef> Kind);
-  static AttributeList get(LLVMContext &C, unsigned Index,
-                           const AttrBuilder &B);
+  static AttributeList get(LLVMContext &C, Index Index, const AttrBuilder &B);
 
   /// Add an attribute to the attribute set at the given index.
   /// Returns a new list because attribute lists are immutable.
-  LLVM_NODISCARD AttributeList addAttribute(LLVMContext &C, unsigned Index,
+  LLVM_NODISCARD AttributeList addAttribute(LLVMContext &C, Index Index,
                                             Attribute::AttrKind Kind) const;
 
   /// Add an attribute to the attribute set at the given index.
   /// Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList
-  addAttribute(LLVMContext &C, unsigned Index, StringRef Kind,
+  addAttribute(LLVMContext &C, Index Index, StringRef Kind,
                StringRef Value = StringRef()) const;
 
   /// Add an attribute to the attribute set at the given index.
   /// Returns a new list because attribute lists are immutable.
-  LLVM_NODISCARD AttributeList addAttribute(LLVMContext &C, unsigned Index,
+  LLVM_NODISCARD AttributeList addAttribute(LLVMContext &C, Index Index,
                                             Attribute A) const;
 
   /// Add attributes to the attribute set at the given index.
   /// Returns a new list because attribute lists are immutable.
-  LLVM_NODISCARD AttributeList addAttributes(LLVMContext &C, unsigned Index,
+  LLVM_NODISCARD AttributeList addAttributes(LLVMContext &C, Index Index,
                                              const AttrBuilder &B) const;
 
   /// Add an argument attribute to the list. Returns a new list because
   /// attribute lists are immutable.
   LLVM_NODISCARD AttributeList addParamAttribute(
       LLVMContext &C, unsigned ArgNo, Attribute::AttrKind Kind) const {
-    return addAttribute(C, ArgNo + FirstArgIndex, Kind);
+    return addAttribute(C, getArgIndex(ArgNo), Kind);
   }
 
   /// Add an argument attribute to the list. Returns a new list because
@@ -474,7 +527,7 @@
   LLVM_NODISCARD AttributeList
   addParamAttribute(LLVMContext &C, unsigned ArgNo, StringRef Kind,
                     StringRef Value = StringRef()) const {
-    return addAttribute(C, ArgNo + FirstArgIndex, Kind, Value);
+    return addAttribute(C, getArgIndex(ArgNo), Kind, Value);
   }
 
   /// Add an attribute to the attribute list at the given arg indices. Returns a
@@ -488,34 +541,34 @@
   LLVM_NODISCARD AttributeList addParamAttributes(LLVMContext &C,
                                                   unsigned ArgNo,
                                                   const AttrBuilder &B) const {
-    return addAttributes(C, ArgNo + FirstArgIndex, B);
+    return addAttributes(C, getArgIndex(ArgNo), B);
   }
 
   /// Remove the specified attribute at the specified index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
-  LLVM_NODISCARD AttributeList removeAttribute(LLVMContext &C, unsigned Index,
+  LLVM_NODISCARD AttributeList removeAttribute(LLVMContext &C, Index Index,
                                                Attribute::AttrKind Kind) const;
 
   /// Remove the specified attribute at the specified index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
-  LLVM_NODISCARD AttributeList removeAttribute(LLVMContext &C, unsigned Index,
+  LLVM_NODISCARD AttributeList removeAttribute(LLVMContext &C, Index Index,
                                                StringRef Kind) const;
 
   /// Remove the specified attributes at the specified index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList removeAttributes(
-      LLVMContext &C, unsigned Index, const AttrBuilder &AttrsToRemove) const;
+      LLVMContext &C, Index Index, const AttrBuilder &AttrsToRemove) const;
 
   /// Remove all attributes at the specified index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList removeAttributes(LLVMContext &C,
-                                                unsigned Index) const;
+                                                Index Index) const;
 
   /// Remove the specified attribute at the specified arg index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList removeParamAttribute(
       LLVMContext &C, unsigned ArgNo, Attribute::AttrKind Kind) const {
-    return removeAttribute(C, ArgNo + FirstArgIndex, Kind);
+    return removeAttribute(C, getArgIndex(ArgNo), Kind);
   }
 
   /// Remove the specified attribute at the specified arg index from this
@@ -523,14 +576,14 @@
   LLVM_NODISCARD AttributeList removeParamAttribute(LLVMContext &C,
                                                     unsigned ArgNo,
                                                     StringRef Kind) const {
-    return removeAttribute(C, ArgNo + FirstArgIndex, Kind);
+    return removeAttribute(C, getArgIndex(ArgNo), Kind);
   }
 
   /// Remove the specified attribute at the specified arg index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList removeParamAttributes(
       LLVMContext &C, unsigned ArgNo, const AttrBuilder &AttrsToRemove) const {
-    return removeAttributes(C, ArgNo + FirstArgIndex, AttrsToRemove);
+    return removeAttributes(C, getArgIndex(ArgNo), AttrsToRemove);
   }
 
   /// Remove noundef attribute and other attributes that imply undefined
@@ -543,7 +596,7 @@
   /// attribute list. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList removeParamAttributes(LLVMContext &C,
                                                      unsigned ArgNo) const {
-    return removeAttributes(C, ArgNo + FirstArgIndex);
+    return removeAttributes(C, getArgIndex(ArgNo));
   }
 
   /// Replace the type contained by attribute \p AttrKind at index \p ArgNo wih
@@ -560,33 +613,33 @@
   /// \brief Add the dereferenceable attribute to the attribute set at the given
   /// index. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList addDereferenceableAttr(LLVMContext &C,
-                                                      unsigned Index,
+                                                      Index Index,
                                                       uint64_t Bytes) const;
 
   /// \brief Add the dereferenceable attribute to the attribute set at the given
   /// arg index. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList addDereferenceableParamAttr(
       LLVMContext &C, unsigned ArgNo, uint64_t Bytes) const {
-    return addDereferenceableAttr(C, ArgNo + FirstArgIndex, Bytes);
+    return addDereferenceableAttr(C, getArgIndex(ArgNo), Bytes);
   }
 
   /// Add the dereferenceable_or_null attribute to the attribute set at
   /// the given index. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList addDereferenceableOrNullAttr(
-      LLVMContext &C, unsigned Index, uint64_t Bytes) const;
+      LLVMContext &C, Index Index, uint64_t Bytes) const;
 
   /// Add the dereferenceable_or_null attribute to the attribute set at
   /// the given arg index. Returns a new list because attribute lists are
   /// immutable.
   LLVM_NODISCARD AttributeList addDereferenceableOrNullParamAttr(
       LLVMContext &C, unsigned ArgNo, uint64_t Bytes) const {
-    return addDereferenceableOrNullAttr(C, ArgNo + FirstArgIndex, Bytes);
+    return addDereferenceableOrNullAttr(C, getArgIndex(ArgNo), Bytes);
   }
 
   /// Add the allocsize attribute to the attribute set at the given index.
   /// Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList
-  addAllocSizeAttr(LLVMContext &C, unsigned Index, unsigned ElemSizeArg,
+  addAllocSizeAttr(LLVMContext &C, Index Index, unsigned ElemSizeArg,
                    const Optional<unsigned> &NumElemsArg);
 
   /// Add the allocsize attribute to the attribute set at the given arg index.
@@ -594,13 +647,12 @@
   LLVM_NODISCARD AttributeList
   addAllocSizeParamAttr(LLVMContext &C, unsigned ArgNo, unsigned ElemSizeArg,
                         const Optional<unsigned> &NumElemsArg) {
-    return addAllocSizeAttr(C, ArgNo + FirstArgIndex, ElemSizeArg, NumElemsArg);
+    return addAllocSizeAttr(C, getArgIndex(ArgNo), ElemSizeArg, NumElemsArg);
   }
 
   /// Add the vscale_range attribute to the attribute set at the given index.
   /// Returns a new list because attribute lists are immutable.
-  LLVM_NODISCARD AttributeList addVScaleRangeAttr(LLVMContext &C,
-                                                  unsigned Index,
+  LLVM_NODISCARD AttributeList addVScaleRangeAttr(LLVMContext &C, Index Index,
                                                   unsigned MinValue,
                                                   unsigned MaxValue);
 
@@ -609,7 +661,7 @@
   //===--------------------------------------------------------------------===//
 
   /// The attributes for the specified index are returned.
-  AttributeSet getAttributes(unsigned Index) const;
+  AttributeSet getAttributes(Index Index) const;
 
   /// The attributes for the argument or parameter at the given index are
   /// returned.
@@ -622,27 +674,27 @@
   AttributeSet getFnAttributes() const;
 
   /// Return true if the attribute exists at the given index.
-  bool hasAttribute(unsigned Index, Attribute::AttrKind Kind) const;
+  bool hasAttribute(Index Index, Attribute::AttrKind Kind) const;
 
   /// Return true if the attribute exists at the given index.
-  bool hasAttribute(unsigned Index, StringRef Kind) const;
+  bool hasAttribute(Index Index, StringRef Kind) const;
 
   /// Return true if attribute exists at the given index.
-  bool hasAttributes(unsigned Index) const;
+  bool hasAttributes(Index Index) const;
 
   /// Return true if the attribute exists for the given argument
   bool hasParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
-    return hasAttribute(ArgNo + FirstArgIndex, Kind);
+    return hasAttribute(getArgIndex(ArgNo), Kind);
   }
 
   /// Return true if the attribute exists for the given argument
   bool hasParamAttr(unsigned ArgNo, StringRef Kind) const {
-    return hasAttribute(ArgNo + FirstArgIndex, Kind);
+    return hasAttribute(getArgIndex(ArgNo), Kind);
   }
 
   /// Return true if attributes exists for the given argument
   bool hasParamAttrs(unsigned ArgNo) const {
-    return hasAttributes(ArgNo + FirstArgIndex);
+    return hasAttributes(getArgIndex(ArgNo));
   }
 
   /// Equivalent to hasAttribute(AttributeList::FunctionIndex, Kind) but
@@ -653,29 +705,28 @@
   /// may be faster.
   bool hasFnAttribute(StringRef Kind) const;
 
-  /// Equivalent to hasAttribute(ArgNo + FirstArgIndex, Kind).
+  /// Equivalent to hasAttribute(getArgIndex(ArgNo), Kind).
   bool hasParamAttribute(unsigned ArgNo, Attribute::AttrKind Kind) const;
 
   /// Return true if the specified attribute is set for at least one
   /// parameter or for the return value. If Index is not nullptr, the index
   /// of a parameter with the specified attribute is provided.
-  bool hasAttrSomewhere(Attribute::AttrKind Kind,
-                        unsigned *Index = nullptr) const;
+  bool hasAttrSomewhere(Attribute::AttrKind Kind, Index *Index = nullptr) const;
 
   /// Return the attribute object that exists at the given index.
-  Attribute getAttribute(unsigned Index, Attribute::AttrKind Kind) const;
+  Attribute getAttribute(Index Index, Attribute::AttrKind Kind) const;
 
   /// Return the attribute object that exists at the given index.
-  Attribute getAttribute(unsigned Index, StringRef Kind) const;
+  Attribute getAttribute(Index Index, StringRef Kind) const;
 
   /// Return the attribute object that exists at the arg index.
   Attribute getParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
-    return getAttribute(ArgNo + FirstArgIndex, Kind);
+    return getAttribute(getArgIndex(ArgNo), Kind);
   }
 
   /// Return the attribute object that exists at the given index.
   Attribute getParamAttr(unsigned ArgNo, StringRef Kind) const {
-    return getAttribute(ArgNo + FirstArgIndex, Kind);
+    return getAttribute(getArgIndex(ArgNo), Kind);
   }
 
   /// Return the alignment of the return value.
@@ -703,36 +754,35 @@
   Type *getParamInAllocaType(unsigned ArgNo) const;
 
   /// Get the stack alignment.
-  MaybeAlign getStackAlignment(unsigned Index) const;
+  MaybeAlign getStackAlignment(Index Index) const;
 
   /// Get the number of dereferenceable bytes (or zero if unknown).
-  uint64_t getDereferenceableBytes(unsigned Index) const;
+  uint64_t getDereferenceableBytes(Index Index) const;
 
   /// Get the number of dereferenceable bytes (or zero if unknown) of an
   /// arg.
   uint64_t getParamDereferenceableBytes(unsigned ArgNo) const {
-    return getDereferenceableBytes(ArgNo + FirstArgIndex);
+    return getDereferenceableBytes(getArgIndex(ArgNo));
   }
 
   /// Get the number of dereferenceable_or_null bytes (or zero if
   /// unknown).
-  uint64_t getDereferenceableOrNullBytes(unsigned Index) const;
+  uint64_t getDereferenceableOrNullBytes(Index Index) const;
 
   /// Get the number of dereferenceable_or_null bytes (or zero if
   /// unknown) of an arg.
   uint64_t getParamDereferenceableOrNullBytes(unsigned ArgNo) const {
-    return getDereferenceableOrNullBytes(ArgNo + FirstArgIndex);
+    return getDereferenceableOrNullBytes(getArgIndex(ArgNo));
   }
 
   /// Get the allocsize argument numbers (or pair(0, 0) if unknown).
-  std::pair<unsigned, Optional<unsigned>>
-  getAllocSizeArgs(unsigned Index) const;
+  std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs(Index Index) const;
 
   /// Get the vscale_range argument numbers (or pair(0, 0) if unknown).
-  std::pair<unsigned, unsigned> getVScaleRangeArgs(unsigned Index) const;
+  std::pair<unsigned, unsigned> getVScaleRangeArgs(Index Index) const;
 
   /// Return the attributes at the index as a string.
-  std::string getAsString(unsigned Index, bool InAttrGrp = false) const;
+  std::string getAsString(Index Index, bool InAttrGrp = false) const;
 
   /// Return true if this attribute list belongs to the LLVMContext.
   bool hasParentContext(LLVMContext &C) const;
@@ -749,8 +799,8 @@
   unsigned getNumAttrSets() const;
 
   /// Use these to iterate over the valid attribute indices.
-  unsigned index_begin() const { return AttributeList::FunctionIndex; }
-  unsigned index_end() const { return getNumAttrSets() - 1; }
+  Index index_begin() const { return FunctionIndex; }
+  Index index_end() const { return {getNumAttrSets() - 1}; }
 
   /// operator==/!= - Provide equality predicates.
   bool operator==(const AttributeList &RHS) const { return pImpl == RHS.pImpl; }
@@ -795,6 +845,27 @@
   }
 };
 
+//===----------------------------------------------------------------------===//
+/// \class
+/// Provide DenseMapInfo for AttributeList::Index.
+template <> struct DenseMapInfo<AttributeList::Index> {
+  static AttributeList::Index getEmptyKey() {
+    return AttributeList::Index(DenseMapInfo<unsigned>::getEmptyKey());
+  }
+
+  static AttributeList::Index getTombstoneKey() {
+    return AttributeList::Index(DenseMapInfo<unsigned>::getTombstoneKey());
+  }
+
+  static unsigned getHashValue(AttributeList::Index AS) {
+    return DenseMapInfo<unsigned>::getHashValue(AS.rawValue());
+  }
+
+  static bool isEqual(AttributeList::Index LHS, AttributeList::Index RHS) {
+    return LHS == RHS;
+  }
+};
+
 //===----------------------------------------------------------------------===//
 /// \class
 /// This class is used in conjunction with the Attribute::get method to
@@ -823,7 +894,7 @@
     addAttribute(A);
   }
 
-  AttrBuilder(AttributeList AS, unsigned Idx);
+  AttrBuilder(AttributeList AS, AttributeList::Index Idx);
   AttrBuilder(AttributeSet AS);
 
   void clear();
@@ -848,7 +919,8 @@
   AttrBuilder &removeAttribute(Attribute::AttrKind Val);
 
   /// Remove the attributes from the builder.
-  AttrBuilder &removeAttributes(AttributeList A, uint64_t WithoutIndex);
+  AttrBuilder &removeAttributes(AttributeList A,
+                                AttributeList::Index WithoutIndex);
 
   /// Remove the target-dependent attribute to the builder.
   AttrBuilder &removeAttribute(StringRef A);
@@ -878,7 +950,7 @@
 
   /// Return true if the builder has any attribute that's in the
   /// specified attribute.
-  bool hasAttributes(AttributeList A, uint64_t Index) const;
+  bool hasAttributes(AttributeList A, AttributeList::Index Index) const;
 
   /// Return true if the builder has an alignment attribute.
   bool hasAlignmentAttr() const;
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -401,13 +401,13 @@
   bool hasStackProtectorFnAttr() const;
 
   /// adds the attribute to the list of attributes.
-  void addAttribute(unsigned i, Attribute::AttrKind Kind);
+  void addAttribute(AttributeList::Index I, Attribute::AttrKind Kind);
 
   /// adds the attribute to the list of attributes.
-  void addAttribute(unsigned i, Attribute Attr);
+  void addAttribute(AttributeList::Index I, Attribute Attr);
 
   /// adds the attributes to the list of attributes.
-  void addAttributes(unsigned i, const AttrBuilder &Attrs);
+  void addAttributes(AttributeList::Index I, const AttrBuilder &Attrs);
 
   /// adds the attribute to the list of attributes for the given arg.
   void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
@@ -419,13 +419,13 @@
   void addParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs);
 
   /// removes the attribute from the list of attributes.
-  void removeAttribute(unsigned i, Attribute::AttrKind Kind);
+  void removeAttribute(AttributeList::Index I, Attribute::AttrKind Kind);
 
   /// removes the attribute from the list of attributes.
-  void removeAttribute(unsigned i, StringRef Kind);
+  void removeAttribute(AttributeList::Index I, StringRef Kind);
 
   /// removes the attributes from the list of attributes.
-  void removeAttributes(unsigned i, const AttrBuilder &Attrs);
+  void removeAttributes(AttributeList::Index I, const AttrBuilder &Attrs);
 
   /// removes the attribute from the list of attributes.
   void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
@@ -441,8 +441,8 @@
   void removeParamUndefImplyingAttrs(unsigned ArgNo);
 
   /// check if an attributes is in the list of attributes.
-  bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const {
-    return getAttributes().hasAttribute(i, Kind);
+  bool hasAttribute(AttributeList::Index I, Attribute::AttrKind Kind) const {
+    return getAttributes().hasAttribute(I, Kind);
   }
 
   /// check if an attributes is in the list of attributes.
@@ -456,17 +456,18 @@
   }
 
   /// gets the attribute from the list of attributes.
-  Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const {
-    return AttributeSets.getAttribute(i, Kind);
+  Attribute getAttribute(AttributeList::Index I,
+                         Attribute::AttrKind Kind) const {
+    return AttributeSets.getAttribute(I, Kind);
   }
 
   /// gets the attribute from the list of attributes.
-  Attribute getAttribute(unsigned i, StringRef Kind) const {
-    return AttributeSets.getAttribute(i, Kind);
+  Attribute getAttribute(AttributeList::Index I, StringRef Kind) const {
+    return AttributeSets.getAttribute(I, Kind);
   }
 
   /// adds the dereferenceable attribute to the list of attributes.
-  void addDereferenceableAttr(unsigned i, uint64_t Bytes);
+  void addDereferenceableAttr(AttributeList::Index I, uint64_t Bytes);
 
   /// adds the dereferenceable attribute to the list of attributes for
   /// the given arg.
@@ -474,7 +475,7 @@
 
   /// adds the dereferenceable_or_null attribute to the list of
   /// attributes.
-  void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes);
+  void addDereferenceableOrNullAttr(AttributeList::Index I, uint64_t Bytes);
 
   /// adds the dereferenceable_or_null attribute to the list of
   /// attributes for the given arg.
@@ -520,8 +521,8 @@
   /// Extract the number of dereferenceable bytes for a call or
   /// parameter (0=unknown).
   /// @param i AttributeList index, referring to a return value or argument.
-  uint64_t getDereferenceableBytes(unsigned i) const {
-    return AttributeSets.getDereferenceableBytes(i);
+  uint64_t getDereferenceableBytes(AttributeList::Index I) const {
+    return AttributeSets.getDereferenceableBytes(I);
   }
 
   /// Extract the number of dereferenceable bytes for a parameter.
@@ -533,8 +534,8 @@
   /// Extract the number of dereferenceable_or_null bytes for a call or
   /// parameter (0=unknown).
   /// @param i AttributeList index, referring to a return value or argument.
-  uint64_t getDereferenceableOrNullBytes(unsigned i) const {
-    return AttributeSets.getDereferenceableOrNullBytes(i);
+  uint64_t getDereferenceableOrNullBytes(AttributeList::Index I) const {
+    return AttributeSets.getDereferenceableOrNullBytes(I);
   }
 
   /// Extract the number of dereferenceable_or_null bytes for a
diff --git a/llvm/include/llvm/IR/GlobalVariable.h b/llvm/include/llvm/IR/GlobalVariable.h
--- a/llvm/include/llvm/IR/GlobalVariable.h
+++ b/llvm/include/llvm/IR/GlobalVariable.h
@@ -224,13 +224,13 @@
     return Attrs;
   }
 
-  /// Return attribute set as list with index.
+  /// Return attribute set as list with Index.
   /// FIXME: This may not be required once ValueEnumerators
   /// in bitcode-writer can enumerate attribute-set.
-  AttributeList getAttributesAsList(unsigned index) const {
+  AttributeList getAttributesAsList(AttributeList::Index Index) const {
     if (!hasAttributes())
       return AttributeList();
-    std::pair<unsigned, AttributeSet> AS[1] = {{index, Attrs}};
+    std::pair<AttributeList::Index, AttributeSet> AS[1] = {{Index, Attrs}};
     return AttributeList::get(getContext(), AS);
   }
 
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -1489,16 +1489,16 @@
   bool hasFnAttr(StringRef Kind) const { return hasFnAttrImpl(Kind); }
 
   /// adds the attribute to the list of attributes.
-  void addAttribute(unsigned i, Attribute::AttrKind Kind) {
+  void addAttribute(AttributeList::Index I, Attribute::AttrKind Kind) {
     AttributeList PAL = getAttributes();
-    PAL = PAL.addAttribute(getContext(), i, Kind);
+    PAL = PAL.addAttribute(getContext(), I, Kind);
     setAttributes(PAL);
   }
 
   /// adds the attribute to the list of attributes.
-  void addAttribute(unsigned i, Attribute Attr) {
+  void addAttribute(AttributeList::Index I, Attribute Attr) {
     AttributeList PAL = getAttributes();
-    PAL = PAL.addAttribute(getContext(), i, Attr);
+    PAL = PAL.addAttribute(getContext(), I, Attr);
     setAttributes(PAL);
   }
 
@@ -1519,22 +1519,22 @@
   }
 
   /// removes the attribute from the list of attributes.
-  void removeAttribute(unsigned i, Attribute::AttrKind Kind) {
+  void removeAttribute(AttributeList::Index I, Attribute::AttrKind Kind) {
     AttributeList PAL = getAttributes();
-    PAL = PAL.removeAttribute(getContext(), i, Kind);
+    PAL = PAL.removeAttribute(getContext(), I, Kind);
     setAttributes(PAL);
   }
 
   /// removes the attribute from the list of attributes.
-  void removeAttribute(unsigned i, StringRef Kind) {
+  void removeAttribute(AttributeList::Index I, StringRef Kind) {
     AttributeList PAL = getAttributes();
-    PAL = PAL.removeAttribute(getContext(), i, Kind);
+    PAL = PAL.removeAttribute(getContext(), I, Kind);
     setAttributes(PAL);
   }
 
-  void removeAttributes(unsigned i, const AttrBuilder &Attrs) {
+  void removeAttributes(AttributeList::Index I, const AttrBuilder &Attrs) {
     AttributeList PAL = getAttributes();
-    PAL = PAL.removeAttributes(getContext(), i, Attrs);
+    PAL = PAL.removeAttributes(getContext(), I, Attrs);
     setAttributes(PAL);
   }
 
@@ -1571,17 +1571,17 @@
   }
 
   /// adds the dereferenceable attribute to the list of attributes.
-  void addDereferenceableAttr(unsigned i, uint64_t Bytes) {
+  void addDereferenceableAttr(AttributeList::Index I, uint64_t Bytes) {
     AttributeList PAL = getAttributes();
-    PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes);
+    PAL = PAL.addDereferenceableAttr(getContext(), I, Bytes);
     setAttributes(PAL);
   }
 
   /// adds the dereferenceable_or_null attribute to the list of
   /// attributes.
-  void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) {
+  void addDereferenceableOrNullAttr(AttributeList::Index I, uint64_t Bytes) {
     AttributeList PAL = getAttributes();
-    PAL = PAL.addDereferenceableOrNullAttr(getContext(), i, Bytes);
+    PAL = PAL.addDereferenceableOrNullAttr(getContext(), I, Bytes);
     setAttributes(PAL);
   }
 
@@ -1596,13 +1596,14 @@
   bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const;
 
   /// Get the attribute of a given kind at a position.
-  Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const {
-    return getAttributes().getAttribute(i, Kind);
+  Attribute getAttribute(AttributeList::Index I,
+                         Attribute::AttrKind Kind) const {
+    return getAttributes().getAttribute(I, Kind);
   }
 
   /// Get the attribute of a given kind at a position.
-  Attribute getAttribute(unsigned i, StringRef Kind) const {
-    return getAttributes().getAttribute(i, Kind);
+  Attribute getAttribute(AttributeList::Index I, StringRef Kind) const {
+    return getAttributes().getAttribute(I, Kind);
   }
 
   /// Get the attribute of a given kind from a given arg
@@ -1639,7 +1640,7 @@
     // question is a call argument; or be indirectly implied by the kind of its
     // containing operand bundle, if the operand is a bundle operand.
 
-    if (i == AttributeList::ReturnIndex)
+    if (AttributeList::Index(i) == AttributeList::ReturnIndex)
       return hasRetAttr(Kind);
 
     // FIXME: Avoid these i - 1 calculations and update the API to use
@@ -1740,14 +1741,14 @@
 
   /// Extract the number of dereferenceable bytes for a call or
   /// parameter (0=unknown).
-  uint64_t getDereferenceableBytes(unsigned i) const {
-    return Attrs.getDereferenceableBytes(i);
+  uint64_t getDereferenceableBytes(AttributeList::Index I) const {
+    return Attrs.getDereferenceableBytes(I);
   }
 
   /// Extract the number of dereferenceable_or_null bytes for a call or
   /// parameter (0=unknown).
-  uint64_t getDereferenceableOrNullBytes(unsigned i) const {
-    return Attrs.getDereferenceableOrNullBytes(i);
+  uint64_t getDereferenceableOrNullBytes(AttributeList::Index I) const {
+    return Attrs.getDereferenceableOrNullBytes(I);
   }
 
   /// Return true if the return value is known to be not null.
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -469,7 +469,7 @@
   }
 
   /// Return the index in the attribute list for this position.
-  unsigned getAttrIdx() const {
+  AttributeList::Index getAttrIdx() const {
     switch (getPositionKind()) {
     case IRPosition::IRP_INVALID:
     case IRPosition::IRP_FLOAT:
@@ -482,7 +482,7 @@
       return AttributeList::ReturnIndex;
     case IRPosition::IRP_ARGUMENT:
     case IRPosition::IRP_CALL_SITE_ARGUMENT:
-      return getCallSiteArgNo() + AttributeList::FirstArgIndex;
+      return AttributeList::getArgIndex(getCallSiteArgNo());
     }
     llvm_unreachable(
         "There is no attribute index for a floating or invalid position!");
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -783,10 +783,10 @@
 
   SmallVector<uint64_t, 64> Record;
   for (ValueEnumerator::IndexAndAttrSet Pair : AttrGrps) {
-    unsigned AttrListIndex = Pair.first;
+    AttributeList::Index AttrListIndex = Pair.first;
     AttributeSet AS = Pair.second;
     Record.push_back(VE.getAttributeGroupID(Pair));
-    Record.push_back(AttrListIndex);
+    Record.push_back(AttrListIndex.rawValue());
 
     for (Attribute Attr : AS) {
       if (Attr.isEnumAttribute()) {
@@ -833,10 +833,11 @@
   SmallVector<uint64_t, 64> Record;
   for (unsigned i = 0, e = Attrs.size(); i != e; ++i) {
     AttributeList AL = Attrs[i];
-    for (unsigned i = AL.index_begin(), e = AL.index_end(); i != e; ++i) {
-      AttributeSet AS = AL.getAttributes(i);
+    for (AttributeList::Index I = AL.index_begin(), E = AL.index_end(); I != E;
+         ++I) {
+      AttributeSet AS = AL.getAttributes(I);
       if (AS.hasAttributes())
-        Record.push_back(VE.getAttributeGroupID({i, AS}));
+        Record.push_back(VE.getAttributeGroupID({I, AS}));
     }
 
     Stream.EmitRecord(bitc::PARAMATTR_CODE_ENTRY, Record);
diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.h b/llvm/lib/Bitcode/Writer/ValueEnumerator.h
--- a/llvm/lib/Bitcode/Writer/ValueEnumerator.h
+++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.h
@@ -49,7 +49,7 @@
 
   /// Attribute groups as encoded in bitcode are almost AttributeSets, but they
   /// include the AttributeList index, so we have to track that in our map.
-  using IndexAndAttrSet = std::pair<unsigned, AttributeSet>;
+  using IndexAndAttrSet = std::pair<AttributeList::Index, AttributeSet>;
 
   UseListOrderStack UseListOrders;
 
diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
--- a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
+++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
@@ -1036,11 +1036,12 @@
   }
 
   // Do lookups for all attribute groups.
-  for (unsigned i = PAL.index_begin(), e = PAL.index_end(); i != e; ++i) {
-    AttributeSet AS = PAL.getAttributes(i);
+  for (AttributeList::Index I = PAL.index_begin(), E = PAL.index_end(); I != E;
+       ++I) {
+    AttributeSet AS = PAL.getAttributes(I);
     if (!AS.hasAttributes())
       continue;
-    IndexAndAttrSet Pair = {i, AS};
+    IndexAndAttrSet Pair = {I, AS};
     unsigned &Entry = AttributeGroupMap[Pair];
     if (Entry == 0) {
       AttributeGroups.push_back(Pair);
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
--- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
@@ -71,7 +71,7 @@
 
 void CallLowering::addArgFlagsFromAttributes(ISD::ArgFlagsTy &Flags,
                                              const AttributeList &Attrs,
-                                             unsigned OpIdx) const {
+                                             AttributeList::Index OpIdx) const {
   addFlagsUsingAttrFn(Flags, [&Attrs, &OpIdx](Attribute::AttrKind Attr) {
     return Attrs.hasAttribute(OpIdx, Attr);
   });
@@ -116,7 +116,7 @@
   for (auto &Arg : CB.args()) {
     ArgInfo OrigArg{ArgRegs[i], *Arg.get(), getAttributesForArgIdx(CB, i),
                     i < NumFixedArgs};
-    setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, CB);
+    setArgFlags(OrigArg, AttributeList::getArgIndex(i), DL, CB);
 
     // If we have an explicit sret argument that is an Instruction, (i.e., it
     // might point to function-local memory), we can't meaningfully tail-call.
@@ -149,8 +149,8 @@
 }
 
 template <typename FuncInfoTy>
-void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx,
-                               const DataLayout &DL,
+void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg,
+                               AttributeList::Index OpIdx, const DataLayout &DL,
                                const FuncInfoTy &FuncInfo) const {
   auto &Flags = Arg.Flags[0];
   const AttributeList &Attrs = FuncInfo.getAttributes();
@@ -158,7 +158,7 @@
 
   Align MemAlign = DL.getABITypeAlign(Arg.Ty);
   if (Flags.isByVal() || Flags.isInAlloca() || Flags.isPreallocated()) {
-    assert(OpIdx >= AttributeList::FirstArgIndex);
+    assert(OpIdx.isArg());
     Type *ElementTy = cast<PointerType>(Arg.Ty)->getElementType();
 
     auto Ty = Attrs.getAttribute(OpIdx, Attribute::ByVal).getValueAsType();
@@ -166,17 +166,14 @@
 
     // For ByVal, alignment should be passed from FE.  BE will guess if
     // this info is not there but there are cases it cannot get right.
-    if (auto ParamAlign =
-            FuncInfo.getParamStackAlign(OpIdx - AttributeList::FirstArgIndex))
+    if (auto ParamAlign = FuncInfo.getParamStackAlign(OpIdx.toArgNo()))
       MemAlign = *ParamAlign;
-    else if ((ParamAlign =
-                  FuncInfo.getParamAlign(OpIdx - AttributeList::FirstArgIndex)))
+    else if ((ParamAlign = FuncInfo.getParamAlign(OpIdx.toArgNo())))
       MemAlign = *ParamAlign;
     else
       MemAlign = Align(getTLI()->getByValTypeAlignment(ElementTy, DL));
-  } else if (OpIdx >= AttributeList::FirstArgIndex) {
-    if (auto ParamAlign =
-            FuncInfo.getParamStackAlign(OpIdx - AttributeList::FirstArgIndex))
+  } else if (OpIdx.isArg()) {
+    if (auto ParamAlign = FuncInfo.getParamStackAlign(OpIdx.toArgNo()))
       MemAlign = *ParamAlign;
   }
   Flags.setMemAlign(MemAlign);
@@ -188,15 +185,13 @@
     Flags.setReturned(false);
 }
 
-template void
-CallLowering::setArgFlags<Function>(CallLowering::ArgInfo &Arg, unsigned OpIdx,
-                                    const DataLayout &DL,
-                                    const Function &FuncInfo) const;
+template void CallLowering::setArgFlags<Function>(
+    CallLowering::ArgInfo &Arg, AttributeList::Index OpIdx,
+    const DataLayout &DL, const Function &FuncInfo) const;
 
-template void
-CallLowering::setArgFlags<CallBase>(CallLowering::ArgInfo &Arg, unsigned OpIdx,
-                                    const DataLayout &DL,
-                                    const CallBase &FuncInfo) const;
+template void CallLowering::setArgFlags<CallBase>(
+    CallLowering::ArgInfo &Arg, AttributeList::Index OpIdx,
+    const DataLayout &DL, const CallBase &FuncInfo) const;
 
 void CallLowering::splitToValueTypes(const ArgInfo &OrigArg,
                                      SmallVectorImpl<ArgInfo> &SplitArgs,
diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -313,7 +313,7 @@
   /// parameter or for the return value. If Index is not nullptr, the index
   /// of a parameter with the specified attribute is provided.
   bool hasAttrSomewhere(Attribute::AttrKind Kind,
-                        unsigned *Index = nullptr) const;
+                        AttributeList::Index *Index = nullptr) const;
 
   using iterator = const AttributeSet *;
 
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -1117,12 +1117,6 @@
 // AttributeListImpl Definition
 //===----------------------------------------------------------------------===//
 
-/// Map from AttributeList index to the internal array index. Adding one happens
-/// to work, because -1 wraps around to 0.
-static unsigned attrIdxToArrayIdx(unsigned Index) {
-  return Index + 1;
-}
-
 AttributeListImpl::AttributeListImpl(ArrayRef<AttributeSet> Sets)
     : NumAttrSets(Sets.size()) {
   assert(!Sets.empty() && "pointless AttributeListImpl");
@@ -1132,7 +1126,7 @@
 
   // Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs
   // summary bitsets.
-  for (const auto &I : Sets[attrIdxToArrayIdx(AttributeList::FunctionIndex)])
+  for (const auto &I : Sets[AttributeList::FunctionIndex.arrayIndex()])
     if (!I.isStringAttribute())
       AvailableFunctionAttrs.addAttribute(I.getKindAsEnum());
 
@@ -1153,14 +1147,14 @@
 }
 
 bool AttributeListImpl::hasAttrSomewhere(Attribute::AttrKind Kind,
-                                        unsigned *Index) const {
+                                         AttributeList::Index *Index) const {
   if (!AvailableSomewhereAttrs.hasAttribute(Kind))
     return false;
 
   if (Index) {
     for (unsigned I = 0, E = NumAttrSets; I != E; ++I) {
       if (begin()[I].hasAttribute(Kind)) {
-        *Index = I - 1;
+        *Index = AttributeList::Index::fromArrayIndex(I);
         break;
       }
     }
@@ -1169,7 +1163,6 @@
   return true;
 }
 
-
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 LLVM_DUMP_METHOD void AttributeListImpl::dump() const {
   AttributeList(const_cast<AttributeListImpl *>(this)).dump();
@@ -1180,6 +1173,11 @@
 // AttributeList Construction and Mutation Methods
 //===----------------------------------------------------------------------===//
 
+const AttributeList::Index
+    AttributeList::ReturnIndex(AttributeList::Index::ReturnIndex);
+const AttributeList::Index
+    AttributeList::FunctionIndex(AttributeList::Index::FunctionIndex);
+
 AttributeList AttributeList::getImpl(LLVMContext &C,
                                      ArrayRef<AttributeSet> AttrSets) {
   assert(!AttrSets.empty() && "pointless AttributeListImpl");
@@ -1207,31 +1205,31 @@
   return AttributeList(PA);
 }
 
-AttributeList
-AttributeList::get(LLVMContext &C,
-                   ArrayRef<std::pair<unsigned, Attribute>> Attrs) {
+AttributeList AttributeList::get(LLVMContext &C,
+                                 ArrayRef<std::pair<Index, Attribute>> Attrs) {
   // If there are no attributes then return a null AttributesList pointer.
   if (Attrs.empty())
     return {};
 
   assert(llvm::is_sorted(Attrs,
-                         [](const std::pair<unsigned, Attribute> &LHS,
-                            const std::pair<unsigned, Attribute> &RHS) {
+                         [](const std::pair<Index, Attribute> &LHS,
+                            const std::pair<Index, Attribute> &RHS) {
                            return LHS.first < RHS.first;
                          }) &&
          "Misordered Attributes list!");
   assert(llvm::all_of(Attrs,
-                      [](const std::pair<unsigned, Attribute> &Pair) {
+                      [](const std::pair<Index, Attribute> &Pair) {
                         return Pair.second.isValid();
                       }) &&
          "Pointless attribute!");
 
-  // Create a vector if (unsigned, AttributeSetNode*) pairs from the attributes
+  // Create a vector if (Index, AttributeSetNode*) pairs from the attributes
   // list.
-  SmallVector<std::pair<unsigned, AttributeSet>, 8> AttrPairVec;
-  for (ArrayRef<std::pair<unsigned, Attribute>>::iterator I = Attrs.begin(),
-         E = Attrs.end(); I != E; ) {
-    unsigned Index = I->first;
+  SmallVector<std::pair<Index, AttributeSet>, 8> AttrPairVec;
+  for (ArrayRef<std::pair<Index, Attribute>>::iterator I = Attrs.begin(),
+                                                       E = Attrs.end();
+       I != E;) {
+    Index Index = I->first;
     SmallVector<Attribute, 4> AttrVec;
     while (I != E && I->first == Index) {
       AttrVec.push_back(I->second);
@@ -1246,32 +1244,32 @@
 
 AttributeList
 AttributeList::get(LLVMContext &C,
-                   ArrayRef<std::pair<unsigned, AttributeSet>> Attrs) {
+                   ArrayRef<std::pair<Index, AttributeSet>> Attrs) {
   // If there are no attributes then return a null AttributesList pointer.
   if (Attrs.empty())
     return {};
 
   assert(llvm::is_sorted(Attrs,
-                         [](const std::pair<unsigned, AttributeSet> &LHS,
-                            const std::pair<unsigned, AttributeSet> &RHS) {
+                         [](const std::pair<Index, AttributeSet> &LHS,
+                            const std::pair<Index, AttributeSet> &RHS) {
                            return LHS.first < RHS.first;
                          }) &&
          "Misordered Attributes list!");
   assert(llvm::none_of(Attrs,
-                       [](const std::pair<unsigned, AttributeSet> &Pair) {
+                       [](const std::pair<Index, AttributeSet> &Pair) {
                          return !Pair.second.hasAttributes();
                        }) &&
          "Pointless attribute!");
 
-  unsigned MaxIndex = Attrs.back().first;
+  Index MaxIndex = Attrs.back().first;
   // If the MaxIndex is FunctionIndex and there are other indices in front
   // of it, we need to use the largest of those to get the right size.
   if (MaxIndex == FunctionIndex && Attrs.size() > 1)
     MaxIndex = Attrs[Attrs.size() - 2].first;
 
-  SmallVector<AttributeSet, 4> AttrVec(attrIdxToArrayIdx(MaxIndex) + 1);
+  SmallVector<AttributeSet, 4> AttrVec(MaxIndex.arrayIndex() + 1);
   for (const auto &Pair : Attrs)
-    AttrVec[attrIdxToArrayIdx(Pair.first)] = Pair.second;
+    AttrVec[Pair.first.arrayIndex()] = Pair.second;
 
   return getImpl(C, AttrVec);
 }
@@ -1317,40 +1315,40 @@
   return getImpl(C, AttrSets);
 }
 
-AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::get(LLVMContext &C, Index Idx,
                                  const AttrBuilder &B) {
   if (!B.hasAttributes())
     return {};
-  Index = attrIdxToArrayIdx(Index);
-  SmallVector<AttributeSet, 8> AttrSets(Index + 1);
-  AttrSets[Index] = AttributeSet::get(C, B);
+  const unsigned ArrayIdx = Idx.arrayIndex();
+  SmallVector<AttributeSet, 8> AttrSets(ArrayIdx + 1);
+  AttrSets[ArrayIdx] = AttributeSet::get(C, B);
   return getImpl(C, AttrSets);
 }
 
-AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::get(LLVMContext &C, Index Idx,
                                  ArrayRef<Attribute::AttrKind> Kinds) {
-  SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
+  SmallVector<std::pair<Index, Attribute>, 8> Attrs;
   for (const auto K : Kinds)
-    Attrs.emplace_back(Index, Attribute::get(C, K));
+    Attrs.emplace_back(Idx, Attribute::get(C, K));
   return get(C, Attrs);
 }
 
-AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::get(LLVMContext &C, Index Idx,
                                  ArrayRef<Attribute::AttrKind> Kinds,
                                  ArrayRef<uint64_t> Values) {
   assert(Kinds.size() == Values.size() && "Mismatched attribute values.");
-  SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
+  SmallVector<std::pair<Index, Attribute>, 8> Attrs;
   auto VI = Values.begin();
   for (const auto K : Kinds)
-    Attrs.emplace_back(Index, Attribute::get(C, K, *VI++));
+    Attrs.emplace_back(Idx, Attribute::get(C, K, *VI++));
   return get(C, Attrs);
 }
 
-AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::get(LLVMContext &C, Index Idx,
                                  ArrayRef<StringRef> Kinds) {
-  SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
+  SmallVector<std::pair<Index, Attribute>, 8> Attrs;
   for (const auto &K : Kinds)
-    Attrs.emplace_back(Index, Attribute::get(C, K));
+    Attrs.emplace_back(Idx, Attribute::get(C, K));
   return get(C, Attrs);
 }
 
@@ -1380,7 +1378,7 @@
   return getImpl(C, NewAttrSets);
 }
 
-AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::addAttribute(LLVMContext &C, Index Index,
                                           Attribute::AttrKind Kind) const {
   if (hasAttribute(Index, Kind)) return *this;
   AttributeSet Attrs = getAttributes(Index);
@@ -1390,7 +1388,7 @@
   return setAttributes(C, Index, AttributeSet::get(C, NewAttrs));
 }
 
-AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::addAttribute(LLVMContext &C, Index Index,
                                           StringRef Kind,
                                           StringRef Value) const {
   AttrBuilder B;
@@ -1398,24 +1396,24 @@
   return addAttributes(C, Index, B);
 }
 
-AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::addAttribute(LLVMContext &C, Index Index,
                                           Attribute A) const {
   AttrBuilder B;
   B.addAttribute(A);
   return addAttributes(C, Index, B);
 }
 
-AttributeList AttributeList::setAttributes(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::setAttributes(LLVMContext &C, Index Index,
                                            AttributeSet Attrs) const {
-  Index = attrIdxToArrayIdx(Index);
   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
-  if (Index >= AttrSets.size())
-    AttrSets.resize(Index + 1);
-  AttrSets[Index] = Attrs;
+  const unsigned ArrayIdx = Index.arrayIndex();
+  if (ArrayIdx >= AttrSets.size())
+    AttrSets.resize(ArrayIdx + 1);
+  AttrSets[ArrayIdx] = Attrs;
   return AttributeList::getImpl(C, AttrSets);
 }
 
-AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::addAttributes(LLVMContext &C, Index Index,
                                            const AttrBuilder &B) const {
   if (!B.hasAttributes())
     return *this;
@@ -1443,12 +1441,12 @@
   assert(llvm::is_sorted(ArgNos));
 
   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
-  unsigned MaxIndex = attrIdxToArrayIdx(ArgNos.back() + FirstArgIndex);
+  unsigned MaxIndex = getArgIndex(ArgNos.back()).arrayIndex();
   if (MaxIndex >= AttrSets.size())
     AttrSets.resize(MaxIndex + 1);
 
   for (unsigned ArgNo : ArgNos) {
-    unsigned Index = attrIdxToArrayIdx(ArgNo + FirstArgIndex);
+    unsigned Index = getArgIndex(ArgNo).arrayIndex();
     AttrBuilder B(AttrSets[Index]);
     B.addAttribute(A);
     AttrSets[Index] = AttributeSet::get(C, B);
@@ -1457,34 +1455,34 @@
   return getImpl(C, AttrSets);
 }
 
-AttributeList AttributeList::removeAttribute(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::removeAttribute(LLVMContext &C, Index Index,
                                              Attribute::AttrKind Kind) const {
   if (!hasAttribute(Index, Kind)) return *this;
 
-  Index = attrIdxToArrayIdx(Index);
   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
-  assert(Index < AttrSets.size());
+  const unsigned ArrayIdx = Index.arrayIndex();
+  assert(ArrayIdx < AttrSets.size());
 
-  AttrSets[Index] = AttrSets[Index].removeAttribute(C, Kind);
+  AttrSets[ArrayIdx] = AttrSets[ArrayIdx].removeAttribute(C, Kind);
 
   return getImpl(C, AttrSets);
 }
 
-AttributeList AttributeList::removeAttribute(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::removeAttribute(LLVMContext &C, Index Index,
                                              StringRef Kind) const {
   if (!hasAttribute(Index, Kind)) return *this;
 
-  Index = attrIdxToArrayIdx(Index);
   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
-  assert(Index < AttrSets.size());
+  const unsigned ArrayIdx = Index.arrayIndex();
+  assert(ArrayIdx < AttrSets.size());
 
-  AttrSets[Index] = AttrSets[Index].removeAttribute(C, Kind);
+  AttrSets[ArrayIdx] = AttrSets[ArrayIdx].removeAttribute(C, Kind);
 
   return getImpl(C, AttrSets);
 }
 
 AttributeList
-AttributeList::removeAttributes(LLVMContext &C, unsigned Index,
+AttributeList::removeAttributes(LLVMContext &C, Index Index,
                                 const AttrBuilder &AttrsToRemove) const {
   AttributeSet Attrs = getAttributes(Index);
   AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove);
@@ -1495,14 +1493,14 @@
 }
 
 AttributeList AttributeList::removeAttributes(LLVMContext &C,
-                                              unsigned WithoutIndex) const {
+                                              Index WithoutIndex) const {
   if (!pImpl)
     return {};
-  WithoutIndex = attrIdxToArrayIdx(WithoutIndex);
-  if (WithoutIndex >= getNumAttrSets())
+  const unsigned WithoutArrayIdx = WithoutIndex.arrayIndex();
+  if (WithoutArrayIdx >= getNumAttrSets())
     return *this;
   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
-  AttrSets[WithoutIndex] = AttributeSet();
+  AttrSets[WithoutArrayIdx] = AttributeSet();
   return getImpl(C, AttrSets);
 }
 
@@ -1517,8 +1515,7 @@
   return removeParamAttributes(C, ArgNo, B);
 }
 
-AttributeList AttributeList::addDereferenceableAttr(LLVMContext &C,
-                                                    unsigned Index,
+AttributeList AttributeList::addDereferenceableAttr(LLVMContext &C, Index Index,
                                                     uint64_t Bytes) const {
   AttrBuilder B;
   B.addDereferenceableAttr(Bytes);
@@ -1526,7 +1523,7 @@
 }
 
 AttributeList
-AttributeList::addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index,
+AttributeList::addDereferenceableOrNullAttr(LLVMContext &C, Index Index,
                                             uint64_t Bytes) const {
   AttrBuilder B;
   B.addDereferenceableOrNullAttr(Bytes);
@@ -1534,7 +1531,7 @@
 }
 
 AttributeList
-AttributeList::addAllocSizeAttr(LLVMContext &C, unsigned Index,
+AttributeList::addAllocSizeAttr(LLVMContext &C, Index Index,
                                 unsigned ElemSizeArg,
                                 const Optional<unsigned> &NumElemsArg) {
   AttrBuilder B;
@@ -1542,7 +1539,7 @@
   return addAttributes(C, Index, B);
 }
 
-AttributeList AttributeList::addVScaleRangeAttr(LLVMContext &C, unsigned Index,
+AttributeList AttributeList::addVScaleRangeAttr(LLVMContext &C, Index Index,
                                                 unsigned MinValue,
                                                 unsigned MaxValue) {
   AttrBuilder B;
@@ -1555,7 +1552,7 @@
 //===----------------------------------------------------------------------===//
 
 AttributeSet AttributeList::getParamAttributes(unsigned ArgNo) const {
-  return getAttributes(ArgNo + FirstArgIndex);
+  return getAttributes(getArgIndex(ArgNo));
 }
 
 AttributeSet AttributeList::getRetAttributes() const {
@@ -1566,16 +1563,15 @@
   return getAttributes(FunctionIndex);
 }
 
-bool AttributeList::hasAttribute(unsigned Index,
-                                 Attribute::AttrKind Kind) const {
+bool AttributeList::hasAttribute(Index Index, Attribute::AttrKind Kind) const {
   return getAttributes(Index).hasAttribute(Kind);
 }
 
-bool AttributeList::hasAttribute(unsigned Index, StringRef Kind) const {
+bool AttributeList::hasAttribute(Index Index, StringRef Kind) const {
   return getAttributes(Index).hasAttribute(Kind);
 }
 
-bool AttributeList::hasAttributes(unsigned Index) const {
+bool AttributeList::hasAttributes(Index Index) const {
   return getAttributes(Index).hasAttributes();
 }
 
@@ -1589,20 +1585,20 @@
 
 bool AttributeList::hasParamAttribute(unsigned ArgNo,
                                       Attribute::AttrKind Kind) const {
-  return hasAttribute(ArgNo + FirstArgIndex, Kind);
+  return hasAttribute(getArgIndex(ArgNo), Kind);
 }
 
 bool AttributeList::hasAttrSomewhere(Attribute::AttrKind Attr,
-                                     unsigned *Index) const {
+                                     Index *Index) const {
   return pImpl && pImpl->hasAttrSomewhere(Attr, Index);
 }
 
-Attribute AttributeList::getAttribute(unsigned Index,
+Attribute AttributeList::getAttribute(Index Index,
                                       Attribute::AttrKind Kind) const {
   return getAttributes(Index).getAttribute(Kind);
 }
 
-Attribute AttributeList::getAttribute(unsigned Index, StringRef Kind) const {
+Attribute AttributeList::getAttribute(Index Index, StringRef Kind) const {
   return getAttributes(Index).getAttribute(Kind);
 }
 
@@ -1611,64 +1607,63 @@
 }
 
 MaybeAlign AttributeList::getParamAlignment(unsigned ArgNo) const {
-  return getAttributes(ArgNo + FirstArgIndex).getAlignment();
+  return getAttributes(getArgIndex(ArgNo)).getAlignment();
 }
 
 MaybeAlign AttributeList::getParamStackAlignment(unsigned ArgNo) const {
-  return getAttributes(ArgNo + FirstArgIndex).getStackAlignment();
+  return getAttributes(getArgIndex(ArgNo)).getStackAlignment();
 }
 
 Type *AttributeList::getParamByValType(unsigned Index) const {
-  return getAttributes(Index+FirstArgIndex).getByValType();
+  return getAttributes(getArgIndex(Index)).getByValType();
 }
 
 Type *AttributeList::getParamStructRetType(unsigned Index) const {
-  return getAttributes(Index + FirstArgIndex).getStructRetType();
+  return getAttributes(getArgIndex(Index)).getStructRetType();
 }
 
 Type *AttributeList::getParamByRefType(unsigned Index) const {
-  return getAttributes(Index + FirstArgIndex).getByRefType();
+  return getAttributes(getArgIndex(Index)).getByRefType();
 }
 
 Type *AttributeList::getParamPreallocatedType(unsigned Index) const {
-  return getAttributes(Index + FirstArgIndex).getPreallocatedType();
+  return getAttributes(getArgIndex(Index)).getPreallocatedType();
 }
 
 Type *AttributeList::getParamInAllocaType(unsigned Index) const {
-  return getAttributes(Index + FirstArgIndex).getInAllocaType();
+  return getAttributes(getArgIndex(Index)).getInAllocaType();
 }
 
-MaybeAlign AttributeList::getStackAlignment(unsigned Index) const {
+MaybeAlign AttributeList::getStackAlignment(Index Index) const {
   return getAttributes(Index).getStackAlignment();
 }
 
-uint64_t AttributeList::getDereferenceableBytes(unsigned Index) const {
+uint64_t AttributeList::getDereferenceableBytes(Index Index) const {
   return getAttributes(Index).getDereferenceableBytes();
 }
 
-uint64_t AttributeList::getDereferenceableOrNullBytes(unsigned Index) const {
+uint64_t AttributeList::getDereferenceableOrNullBytes(Index Index) const {
   return getAttributes(Index).getDereferenceableOrNullBytes();
 }
 
 std::pair<unsigned, Optional<unsigned>>
-AttributeList::getAllocSizeArgs(unsigned Index) const {
+AttributeList::getAllocSizeArgs(Index Index) const {
   return getAttributes(Index).getAllocSizeArgs();
 }
 
 std::pair<unsigned, unsigned>
-AttributeList::getVScaleRangeArgs(unsigned Index) const {
+AttributeList::getVScaleRangeArgs(Index Index) const {
   return getAttributes(Index).getVScaleRangeArgs();
 }
 
-std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const {
+std::string AttributeList::getAsString(Index Index, bool InAttrGrp) const {
   return getAttributes(Index).getAsString(InAttrGrp);
 }
 
-AttributeSet AttributeList::getAttributes(unsigned Index) const {
-  Index = attrIdxToArrayIdx(Index);
-  if (!pImpl || Index >= getNumAttrSets())
+AttributeSet AttributeList::getAttributes(Index Index) const {
+  if (!pImpl || Index.arrayIndex() >= getNumAttrSets())
     return {};
-  return pImpl->begin()[Index];
+  return pImpl->begin()[Index.arrayIndex()];
 }
 
 bool AttributeList::hasParentContext(LLVMContext &C) const {
@@ -1698,21 +1693,18 @@
 void AttributeList::print(raw_ostream &O) const {
   O << "AttributeList[\n";
 
-  for (unsigned i = index_begin(), e = index_end(); i != e; ++i) {
-    if (!getAttributes(i).hasAttributes())
+  for (Index I = index_begin(), E = index_end(); I != E; ++I) {
+    if (!getAttributes(I).hasAttributes())
       continue;
     O << "  { ";
-    switch (i) {
-    case AttrIndex::ReturnIndex:
+    if (I == ReturnIndex) {
       O << "return";
-      break;
-    case AttrIndex::FunctionIndex:
+    } else if (I == FunctionIndex) {
       O << "function";
-      break;
-    default:
-      O << "arg(" << i - AttrIndex::FirstArgIndex << ")";
+    } else {
+      O << "arg(" << I.toArgNo() << ")";
     }
-    O << " => " << getAsString(i) << " }\n";
+    O << " => " << getAsString(I) << " }\n";
   }
 
   O << "]\n";
@@ -1727,7 +1719,7 @@
 //===----------------------------------------------------------------------===//
 
 // FIXME: Remove this ctor, use AttributeSet.
-AttrBuilder::AttrBuilder(AttributeList AL, unsigned Index) {
+AttrBuilder::AttrBuilder(AttributeList AL, AttributeList::Index Index) {
   AttributeSet AS = AL.getAttributes(Index);
   for (const auto &A : AS)
     addAttribute(A);
@@ -1822,7 +1814,8 @@
   return *this;
 }
 
-AttrBuilder &AttrBuilder::removeAttributes(AttributeList A, uint64_t Index) {
+AttrBuilder &AttrBuilder::removeAttributes(AttributeList A,
+                                           AttributeList::Index Index) {
   remove(A.getAttributes(Index));
   return *this;
 }
@@ -2052,7 +2045,8 @@
   return !Attrs.none() || !TargetDepAttrs.empty();
 }
 
-bool AttrBuilder::hasAttributes(AttributeList AL, uint64_t Index) const {
+bool AttrBuilder::hasAttributes(AttributeList AL,
+                                AttributeList::Index Index) const {
   AttributeSet AS = AL.getAttributes(Index);
 
   for (const auto &Attr : AS) {
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -529,21 +529,21 @@
   clearMetadata();
 }
 
-void Function::addAttribute(unsigned i, Attribute::AttrKind Kind) {
+void Function::addAttribute(AttributeList::Index I, Attribute::AttrKind Kind) {
   AttributeList PAL = getAttributes();
-  PAL = PAL.addAttribute(getContext(), i, Kind);
+  PAL = PAL.addAttribute(getContext(), I, Kind);
   setAttributes(PAL);
 }
 
-void Function::addAttribute(unsigned i, Attribute Attr) {
+void Function::addAttribute(AttributeList::Index I, Attribute Attr) {
   AttributeList PAL = getAttributes();
-  PAL = PAL.addAttribute(getContext(), i, Attr);
+  PAL = PAL.addAttribute(getContext(), I, Attr);
   setAttributes(PAL);
 }
 
-void Function::addAttributes(unsigned i, const AttrBuilder &Attrs) {
+void Function::addAttributes(AttributeList::Index I, const AttrBuilder &Attrs) {
   AttributeList PAL = getAttributes();
-  PAL = PAL.addAttributes(getContext(), i, Attrs);
+  PAL = PAL.addAttributes(getContext(), I, Attrs);
   setAttributes(PAL);
 }
 
@@ -565,21 +565,23 @@
   setAttributes(PAL);
 }
 
-void Function::removeAttribute(unsigned i, Attribute::AttrKind Kind) {
+void Function::removeAttribute(AttributeList::Index I,
+                               Attribute::AttrKind Kind) {
   AttributeList PAL = getAttributes();
-  PAL = PAL.removeAttribute(getContext(), i, Kind);
+  PAL = PAL.removeAttribute(getContext(), I, Kind);
   setAttributes(PAL);
 }
 
-void Function::removeAttribute(unsigned i, StringRef Kind) {
+void Function::removeAttribute(AttributeList::Index I, StringRef Kind) {
   AttributeList PAL = getAttributes();
-  PAL = PAL.removeAttribute(getContext(), i, Kind);
+  PAL = PAL.removeAttribute(getContext(), I, Kind);
   setAttributes(PAL);
 }
 
-void Function::removeAttributes(unsigned i, const AttrBuilder &Attrs) {
+void Function::removeAttributes(AttributeList::Index I,
+                                const AttrBuilder &Attrs) {
   AttributeList PAL = getAttributes();
-  PAL = PAL.removeAttributes(getContext(), i, Attrs);
+  PAL = PAL.removeAttributes(getContext(), I, Attrs);
   setAttributes(PAL);
 }
 
@@ -607,9 +609,9 @@
   setAttributes(PAL);
 }
 
-void Function::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
+void Function::addDereferenceableAttr(AttributeList::Index I, uint64_t Bytes) {
   AttributeList PAL = getAttributes();
-  PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes);
+  PAL = PAL.addDereferenceableAttr(getContext(), I, Bytes);
   setAttributes(PAL);
 }
 
@@ -619,9 +621,10 @@
   setAttributes(PAL);
 }
 
-void Function::addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) {
+void Function::addDereferenceableOrNullAttr(AttributeList::Index I,
+                                            uint64_t Bytes) {
   AttributeList PAL = getAttributes();
-  PAL = PAL.addDereferenceableOrNullAttr(getContext(), i, Bytes);
+  PAL = PAL.addDereferenceableOrNullAttr(getContext(), I, Bytes);
   setAttributes(PAL);
 }
 
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -323,14 +323,14 @@
 }
 
 Value *CallBase::getReturnedArgOperand() const {
-  unsigned Index;
+  AttributeList::Index Index;
 
-  if (Attrs.hasAttrSomewhere(Attribute::Returned, &Index) && Index)
-    return getArgOperand(Index - AttributeList::FirstArgIndex);
+  if (Attrs.hasAttrSomewhere(Attribute::Returned, &Index) && Index.isArg())
+    return getArgOperand(Index.toArgNo());
   if (const Function *F = getCalledFunction())
     if (F->getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) &&
-        Index)
-      return getArgOperand(Index - AttributeList::FirstArgIndex);
+        Index.isArg())
+      return getArgOperand(Index.toArgNo());
 
   return nullptr;
 }
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
--- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
@@ -534,7 +534,7 @@
       continue;
 
     ArgInfo OrigArg{VRegs[i], Arg};
-    setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, F);
+    setArgFlags(OrigArg, AttributeList::getArgIndex(i), DL, F);
 
     if (Arg.hasAttribute(Attribute::SwiftAsync))
       MF.getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp
--- a/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp
@@ -638,8 +638,7 @@
     }
 
     ArgInfo OrigArg(VRegs[Idx], Arg);
-    const unsigned OrigArgIdx = Idx + AttributeList::FirstArgIndex;
-    setArgFlags(OrigArg, OrigArgIdx, DL, F);
+    setArgFlags(OrigArg, AttributeList::getArgIndex(Idx), DL, F);
 
     splitToValueTypes(OrigArg, SplitArgs, DL, CC);
     ++Idx;
diff --git a/llvm/lib/Target/ARM/ARMCallLowering.cpp b/llvm/lib/Target/ARM/ARMCallLowering.cpp
--- a/llvm/lib/Target/ARM/ARMCallLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMCallLowering.cpp
@@ -390,7 +390,7 @@
   for (auto &Arg : F.args()) {
     ArgInfo OrigArgInfo(VRegs[Idx], Arg.getType());
 
-    setArgFlags(OrigArgInfo, Idx + AttributeList::FirstArgIndex, DL, F);
+    setArgFlags(OrigArgInfo, AttributeList::getArgIndex(Idx), DL, F);
     splitToValueTypes(OrigArgInfo, SplitArgInfos, DL, F.getCallingConv());
 
     Idx++;
diff --git a/llvm/lib/Target/Mips/MipsCallLowering.cpp b/llvm/lib/Target/Mips/MipsCallLowering.cpp
--- a/llvm/lib/Target/Mips/MipsCallLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsCallLowering.cpp
@@ -437,7 +437,7 @@
   unsigned i = 0;
   for (auto &Arg : F.args()) {
     ArgInfo AInfo(VRegs[i], Arg.getType());
-    setArgFlags(AInfo, i + AttributeList::FirstArgIndex, DL, F);
+    setArgFlags(AInfo, AttributeList::getArgIndex(i), DL, F);
     ArgInfos.push_back(AInfo);
     OrigArgIndices.push_back(i);
     ++i;
diff --git a/llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp b/llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp
--- a/llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp
+++ b/llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp
@@ -64,7 +64,7 @@
       continue;
 
     ArgInfo OrigArg{VRegs[I], Arg};
-    setArgFlags(OrigArg, I + AttributeList::FirstArgIndex, DL, F);
+    setArgFlags(OrigArg, AttributeList::getArgIndex(I), DL, F);
     splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv());
     ++I;
   }
diff --git a/llvm/lib/Target/X86/X86CallLowering.cpp b/llvm/lib/Target/X86/X86CallLowering.cpp
--- a/llvm/lib/Target/X86/X86CallLowering.cpp
+++ b/llvm/lib/Target/X86/X86CallLowering.cpp
@@ -262,7 +262,7 @@
       return false;
 
     ArgInfo OrigArg(VRegs[Idx], Arg.getType());
-    setArgFlags(OrigArg, Idx + AttributeList::FirstArgIndex, DL, F);
+    setArgFlags(OrigArg, AttributeList::getArgIndex(Idx), DL, F);
     splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv());
     Idx++;
   }
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -231,7 +231,8 @@
 /// attribute list \p Attrs. This is only the case if it was not already present
 /// in \p Attrs at the position describe by \p PK and \p AttrIdx.
 static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr,
-                             AttributeList &Attrs, int AttrIdx) {
+                             AttributeList &Attrs,
+                             AttributeList::Index AttrIdx) {
 
   if (Attr.isEnumAttribute()) {
     Attribute::AttrKind Kind = Attr.getKindAsEnum();
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1639,7 +1639,7 @@
 
 static AttributeList StripAttr(LLVMContext &C, AttributeList Attrs,
                                Attribute::AttrKind A) {
-  unsigned AttrIndex;
+  AttributeList::Index AttrIndex;
   if (Attrs.hasAttrSomewhere(A, &AttrIndex))
     return Attrs.removeAttribute(C, AttrIndex, A);
   return Attrs;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2676,9 +2676,9 @@
     // In this case we have more arguments than the new function type, but we
     // won't be dropping them.  Check that these extra arguments have attributes
     // that are compatible with being a vararg call argument.
-    unsigned SRetIdx;
+    AttributeList::Index SRetIdx;
     if (CallerPAL.hasAttrSomewhere(Attribute::StructRet, &SRetIdx) &&
-        SRetIdx > FT->getNumParams())
+        SRetIdx.toArgNo() > FT->getNumParams())
       return false;
   }
 
diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -814,21 +814,23 @@
        AccessSizeIndex++) {
     unsigned AccessSize = 1 << AccessSizeIndex;
     std::string FunctionName = "__msan_maybe_warning_" + itostr(AccessSize);
-    SmallVector<std::pair<unsigned, Attribute>, 2> MaybeWarningFnAttrs;
+    SmallVector<std::pair<AttributeList::Index, Attribute>, 2>
+        MaybeWarningFnAttrs;
     MaybeWarningFnAttrs.push_back(std::make_pair(
-        AttributeList::FirstArgIndex, Attribute::get(*C, Attribute::ZExt)));
+        AttributeList::getArgIndex(0), Attribute::get(*C, Attribute::ZExt)));
     MaybeWarningFnAttrs.push_back(std::make_pair(
-        AttributeList::FirstArgIndex + 1, Attribute::get(*C, Attribute::ZExt)));
+        AttributeList::getArgIndex(1), Attribute::get(*C, Attribute::ZExt)));
     MaybeWarningFn[AccessSizeIndex] = M.getOrInsertFunction(
         FunctionName, AttributeList::get(*C, MaybeWarningFnAttrs),
         IRB.getVoidTy(), IRB.getIntNTy(AccessSize * 8), IRB.getInt32Ty());
 
     FunctionName = "__msan_maybe_store_origin_" + itostr(AccessSize);
-    SmallVector<std::pair<unsigned, Attribute>, 2> MaybeStoreOriginFnAttrs;
+    SmallVector<std::pair<AttributeList::Index, Attribute>, 2>
+        MaybeStoreOriginFnAttrs;
     MaybeStoreOriginFnAttrs.push_back(std::make_pair(
-        AttributeList::FirstArgIndex, Attribute::get(*C, Attribute::ZExt)));
+        AttributeList::getArgIndex(0), Attribute::get(*C, Attribute::ZExt)));
     MaybeStoreOriginFnAttrs.push_back(std::make_pair(
-        AttributeList::FirstArgIndex + 2, Attribute::get(*C, Attribute::ZExt)));
+        AttributeList::getArgIndex(2), Attribute::get(*C, Attribute::ZExt)));
     MaybeStoreOriginFn[AccessSizeIndex] = M.getOrInsertFunction(
         FunctionName, AttributeList::get(*C, MaybeStoreOriginFnAttrs),
         IRB.getVoidTy(), IRB.getIntNTy(AccessSize * 8), IRB.getInt8PtrTy(),
diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
--- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
+++ b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
@@ -2659,7 +2659,7 @@
 // Handles both return values and arguments for Functions and calls.
 template <typename AttrHolder>
 static void RemoveNonValidAttrAtIndex(LLVMContext &Ctx, AttrHolder &AH,
-                                      unsigned Index) {
+                                      AttributeList::Index Index) {
   AttrBuilder R;
   if (AH.getDereferenceableBytes(Index))
     R.addAttribute(Attribute::get(Ctx, Attribute::Dereferenceable,
@@ -2691,7 +2691,7 @@
   for (Argument &A : F.args())
     if (isa<PointerType>(A.getType()))
       RemoveNonValidAttrAtIndex(Ctx, F,
-                                A.getArgNo() + AttributeList::FirstArgIndex);
+                                AttributeList::getArgIndex(A.getArgNo()));
 
   if (isa<PointerType>(F.getReturnType()))
     RemoveNonValidAttrAtIndex(Ctx, F, AttributeList::ReturnIndex);
@@ -2765,8 +2765,7 @@
     if (auto *Call = dyn_cast<CallBase>(&I)) {
       for (int i = 0, e = Call->arg_size(); i != e; i++)
         if (isa<PointerType>(Call->getArgOperand(i)->getType()))
-          RemoveNonValidAttrAtIndex(Ctx, *Call,
-                                    i + AttributeList::FirstArgIndex);
+          RemoveNonValidAttrAtIndex(Ctx, *Call, AttributeList::getArgIndex(i));
       if (isa<PointerType>(Call->getType()))
         RemoveNonValidAttrAtIndex(Ctx, *Call, AttributeList::ReturnIndex);
     }
diff --git a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
--- a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
+++ b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
@@ -204,14 +204,18 @@
 
   void addCall(const CallBase *Call) {
     auto addAttrList = [&](AttributeList AttrList) {
-      for (unsigned Idx = AttributeList::FirstArgIndex;
-           Idx < AttrList.getNumAttrSets(); Idx++)
+      for (AttributeList::Index Idx = AttrList.index_begin(),
+                                EndIdx = AttrList.index_end();
+           Idx != EndIdx; ++Idx) {
+        if (!Idx.isArg())
+          continue;
         for (Attribute Attr : AttrList.getAttributes(Idx)) {
           bool IsPoisonAttr = Attr.hasAttribute(Attribute::NonNull) ||
                               Attr.hasAttribute(Attribute::Alignment);
-          if (!IsPoisonAttr || Call->isPassingUndefUB(Idx - 1))
-            addAttribute(Attr, Call->getArgOperand(Idx - 1));
+          if (!IsPoisonAttr || Call->isPassingUndefUB(Idx.toArgNo()))
+            addAttribute(Attr, Call->getArgOperand(Idx.toArgNo()));
         }
+      }
       for (Attribute Attr : AttrList.getFnAttributes())
         addAttribute(Attr, nullptr);
     };
diff --git a/llvm/lib/Transforms/Utils/FunctionComparator.cpp b/llvm/lib/Transforms/Utils/FunctionComparator.cpp
--- a/llvm/lib/Transforms/Utils/FunctionComparator.cpp
+++ b/llvm/lib/Transforms/Utils/FunctionComparator.cpp
@@ -110,7 +110,8 @@
   if (int Res = cmpNumbers(L.getNumAttrSets(), R.getNumAttrSets()))
     return Res;
 
-  for (unsigned i = L.index_begin(), e = L.index_end(); i != e; ++i) {
+  for (AttributeList::Index i = L.index_begin(), e = L.index_end(); i != e;
+       ++i) {
     AttributeSet LAS = L.getAttributes(i);
     AttributeSet RAS = R.getAttributes(i);
     AttributeSet::iterator LI = LAS.begin(), LE = LAS.end();
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -142,11 +142,11 @@
     unsigned AS = CI->getArgOperand(ArgNo)->getType()->getPointerAddressSpace();
     if (!llvm::NullPointerIsDefined(F, AS) ||
         CI->paramHasAttr(ArgNo, Attribute::NonNull))
-      DerefBytes = std::max(CI->getDereferenceableOrNullBytes(
-                                ArgNo + AttributeList::FirstArgIndex),
-                            DereferenceableBytes);
-  
-    if (CI->getDereferenceableBytes(ArgNo + AttributeList::FirstArgIndex) <
+      DerefBytes = std::max(
+          CI->getDereferenceableOrNullBytes(AttributeList::getArgIndex(ArgNo)),
+          DereferenceableBytes);
+
+    if (CI->getDereferenceableBytes(AttributeList::getArgIndex(ArgNo)) <
         DerefBytes) {
       CI->removeParamAttr(ArgNo, Attribute::Dereferenceable);
       if (!llvm::NullPointerIsDefined(F, AS) ||
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp b/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp
--- a/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp
@@ -43,7 +43,7 @@
 namespace {
 
 using AttrPtrVecTy = std::vector<const Attribute *>;
-using AttrPtrIdxVecVecTy = std::pair<unsigned, AttrPtrVecTy>;
+using AttrPtrIdxVecVecTy = std::pair<AttributeList::Index, AttrPtrVecTy>;
 using AttrPtrVecVecTy = SmallVector<AttrPtrIdxVecVecTy, 3>;
 
 /// Given ChunksToKeep, produce a map of global variables/functions/calls
@@ -84,7 +84,9 @@
                           AttrPtrVecVecTy &AttributeSetsToPreserve) {
     assert(AttributeSetsToPreserve.empty() && "Should not be sharing vectors.");
     AttributeSetsToPreserve.reserve(AL.getNumAttrSets());
-    for (unsigned SetIdx : seq(AL.index_begin(), AL.index_end())) {
+    for (AttributeList::Index SetIdx = AL.index_begin(),
+                              SetEndIdx = AL.index_end();
+         SetIdx != SetEndIdx; ++SetIdx) {
       AttrPtrIdxVecVecTy AttributesToPreserve;
       AttributesToPreserve.first = SetIdx;
       visitAttributeSet(AL.getAttributes(AttributesToPreserve.first),
@@ -149,7 +151,7 @@
 
 AttributeList convertAttributeRefVecToAttributeList(
     LLVMContext &C, ArrayRef<AttrPtrIdxVecVecTy> AttributeSets) {
-  std::vector<std::pair<unsigned, AttributeSet>> SetVec;
+  std::vector<std::pair<AttributeList::Index, AttributeSet>> SetVec;
   SetVec.reserve(AttributeSets.size());
 
   transform(AttributeSets, std::back_inserter(SetVec),
@@ -158,8 +160,8 @@
                   V.first, convertAttributeRefToAttributeSet(C, V.second));
             });
 
-  sort(SetVec, [](const std::pair<unsigned, AttributeSet> &LHS,
-                  const std::pair<unsigned, AttributeSet> &RHS) {
+  sort(SetVec, [](const std::pair<AttributeList::Index, AttributeSet> &LHS,
+                  const std::pair<AttributeList::Index, AttributeSet> &RHS) {
     return LHS.first < RHS.first; // All values are unique.
   });
 
diff --git a/llvm/unittests/IR/AttributesTest.cpp b/llvm/unittests/IR/AttributesTest.cpp
--- a/llvm/unittests/IR/AttributesTest.cpp
+++ b/llvm/unittests/IR/AttributesTest.cpp
@@ -141,9 +141,9 @@
 TEST(Attributes, AddMatchingAlignAttr) {
   LLVMContext C;
   AttributeList AL;
-  AL = AL.addAttribute(C, AttributeList::FirstArgIndex,
+  AL = AL.addAttribute(C, AttributeList::getArgIndex(0),
                        Attribute::getWithAlignment(C, Align(8)));
-  AL = AL.addAttribute(C, AttributeList::FirstArgIndex + 1,
+  AL = AL.addAttribute(C, AttributeList::getArgIndex(1),
                        Attribute::getWithAlignment(C, Align(32)));
   EXPECT_EQ(Align(8), AL.getParamAlignment(0));
   EXPECT_EQ(Align(32), AL.getParamAlignment(1));
@@ -151,7 +151,7 @@
   AttrBuilder B;
   B.addAttribute(Attribute::NonNull);
   B.addAlignmentAttr(8);
-  AL = AL.addAttributes(C, AttributeList::FirstArgIndex, B);
+  AL = AL.addAttributes(C, AttributeList::getArgIndex(0), B);
   EXPECT_EQ(Align(8), AL.getParamAlignment(0));
   EXPECT_EQ(Align(32), AL.getParamAlignment(1));
   EXPECT_TRUE(AL.hasParamAttribute(0, Attribute::NonNull));
@@ -166,8 +166,9 @@
 
 TEST(Attributes, OverflowGet) {
   LLVMContext C;
-  std::pair<unsigned, Attribute> Attrs[] = { { AttributeList::ReturnIndex, Attribute::get(C, Attribute::SExt) },
-                                             { AttributeList::FunctionIndex, Attribute::get(C, Attribute::ReadOnly) } };
+  std::pair<AttributeList::Index, Attribute> Attrs[] = {
+      {AttributeList::ReturnIndex, Attribute::get(C, Attribute::SExt)},
+      {AttributeList::FunctionIndex, Attribute::get(C, Attribute::ReadOnly)}};
   AttributeList AL = AttributeList::get(C, Attrs);
   EXPECT_EQ(2U, AL.getNumAttrSets());
 }