[llvm] Add the 'initializes' attribute langref and support (PR #84803)

Haopeng Liu via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 10 21:58:10 PDT 2024


https://github.com/haopliu updated https://github.com/llvm/llvm-project/pull/84803

>From 2554c821dfa3893213f934253ecbca5d9d43ceab Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Mon, 11 Mar 2024 17:47:08 +0000
Subject: [PATCH 01/31] Add 'initialized' attribute langref

---
 llvm/docs/LangRef.rst | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index b70220dec9261..39a555edfa80d 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1621,6 +1621,28 @@ Currently, only the following parameter attributes are defined:
     ``readonly`` or a ``memory`` attribute that does not contain
     ``argmem: write``.
 
+``initialized((Lo1,Hi1),...)``
+    This attribute is a list of const ranges in ascending order with no
+    overlapping or continuous. It indicates that the function initializes the
+    memory through the pointer argument, [%p+LoN, %p+HiN): there are no reads,
+    and no special accesses (such as volatile access or untrackable capture)
+    before the initialization in the function. LoN/HiN are 64-bit ints;
+    negative values are allowed in case a pointer to partway through the
+    allocation is passed to.
+
+    This attribute implies that the function initializes and does not read
+    before initialization through this pointer argument, even though it may
+    read the memory before initialization that the pointer points to, such
+    as through other arguments.
+
+    The ``writable`` or ``dereferenceable`` attribute does not imply
+    ``initialized`` attribute, and ``initialized`` does not imply ``writeonly``
+    since cases that read from the pointer after write, can be ``initialized``
+    but not ``writeonly``.
+
+    Note that this attribute does not apply to the unwind edge: the memory may
+    not actually be written to when unwinding happens.
+
 ``dead_on_unwind``
     At a high level, this attribute indicates that the pointer argument is dead
     if the call unwinds, in the sense that the caller will not depend on the

>From a9256bf15dd3e9bb836a467979f61569df98cf8e Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Tue, 12 Mar 2024 22:10:14 +0000
Subject: [PATCH 02/31] Update the LangRef

---
 llvm/docs/LangRef.rst | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 39a555edfa80d..0d0f21b8d203e 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1622,26 +1622,29 @@ Currently, only the following parameter attributes are defined:
     ``argmem: write``.
 
 ``initialized((Lo1,Hi1),...)``
-    This attribute is a list of const ranges in ascending order with no
-    overlapping or continuous. It indicates that the function initializes the
-    memory through the pointer argument, [%p+LoN, %p+HiN): there are no reads,
-    and no special accesses (such as volatile access or untrackable capture)
-    before the initialization in the function. LoN/HiN are 64-bit ints;
-    negative values are allowed in case a pointer to partway through the
-    allocation is passed to.
+    This attribute indicates that the function initializes the ranges of the
+    pointer parameter's memory, [%p+LoN, %p+HiN): there are no reads, and no
+    special accesses (such as volatile access or untrackable capture) before
+    the initialization write in the function.
 
     This attribute implies that the function initializes and does not read
     before initialization through this pointer argument, even though it may
     read the memory before initialization that the pointer points to, such
     as through other arguments.
 
-    The ``writable`` or ``dereferenceable`` attribute does not imply
+    Note that this attribute does not apply to the unwind edge: the
+    initializing function does not read the pointer before writing to it
+    regardless of unwinding or not, but the memory may not actually be
+    written to when unwinding happens.
+
+    The ``writable`` or ``dereferenceable`` attribute does not imply the
     ``initialized`` attribute, and ``initialized`` does not imply ``writeonly``
-    since cases that read from the pointer after write, can be ``initialized``
-    but not ``writeonly``.
+    since ``initialized`` allows reading from the pointer after writing.
 
-    Note that this attribute does not apply to the unwind edge: the memory may
-    not actually be written to when unwinding happens.
+    This attribute is a list of const ranges in ascending order with no
+    overlapping or adjoining list elements. LoN/HiN are 64-bit ints, and
+    negative values are allowed in case the argument points partway into
+    an allocation.
 
 ``dead_on_unwind``
     At a high level, this attribute indicates that the pointer argument is dead

>From 9150ece33c083b49efed2fca268b4539bf8996b6 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Tue, 12 Mar 2024 22:54:21 +0000
Subject: [PATCH 03/31] Refactor the argument uses collecting to a function

---
 llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 146 ++++++++++++----------
 1 file changed, 83 insertions(+), 63 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index 7ebf265e17ba1..a668dde567c01 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -580,45 +580,14 @@ struct ArgumentUsesTracker : public CaptureTracker {
   const SCCNodeSet &SCCNodes;
 };
 
-} // end anonymous namespace
-
-namespace llvm {
-
-template <> struct GraphTraits<ArgumentGraphNode *> {
-  using NodeRef = ArgumentGraphNode *;
-  using ChildIteratorType = SmallVectorImpl<ArgumentGraphNode *>::iterator;
-
-  static NodeRef getEntryNode(NodeRef A) { return A; }
-  static ChildIteratorType child_begin(NodeRef N) { return N->Uses.begin(); }
-  static ChildIteratorType child_end(NodeRef N) { return N->Uses.end(); }
-};
-
-template <>
-struct GraphTraits<ArgumentGraph *> : public GraphTraits<ArgumentGraphNode *> {
-  static NodeRef getEntryNode(ArgumentGraph *AG) { return AG->getEntryNode(); }
-
-  static ChildIteratorType nodes_begin(ArgumentGraph *AG) {
-    return AG->begin();
-  }
-
-  static ChildIteratorType nodes_end(ArgumentGraph *AG) { return AG->end(); }
-};
-
-} // end namespace llvm
-
-/// Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone.
-static Attribute::AttrKind
-determinePointerAccessAttrs(Argument *A,
-                            const SmallPtrSet<Argument *, 8> &SCCNodes) {
+/// Get all uses of an argument in the function and store them to different
+/// lists: Reads, Writes, and SpecialUses.
+std::tuple<SmallVector<Instruction *, 16>, SmallVector<Instruction *, 16>,
+           SmallVector<Instruction *, 16>>
+getArgumentUses(Argument *A, const SmallPtrSet<Argument *, 8> &SCCNodes) {
   SmallVector<Use *, 32> Worklist;
   SmallPtrSet<Use *, 32> Visited;
-
-  // inalloca arguments are always clobbered by the call.
-  if (A->hasInAllocaAttr() || A->hasPreallocatedAttr())
-    return Attribute::None;
-
-  bool IsRead = false;
-  bool IsWrite = false;
+  SmallVector<Instruction *, 16> Reads, Writes, SpecialUses;
 
   for (Use &U : A->uses()) {
     Visited.insert(&U);
@@ -626,10 +595,6 @@ determinePointerAccessAttrs(Argument *A,
   }
 
   while (!Worklist.empty()) {
-    if (IsWrite && IsRead)
-      // No point in searching further..
-      return Attribute::None;
-
     Use *U = Worklist.pop_back_val();
     Instruction *I = cast<Instruction>(U->getUser());
 
@@ -649,7 +614,7 @@ determinePointerAccessAttrs(Argument *A,
     case Instruction::Invoke: {
       CallBase &CB = cast<CallBase>(*I);
       if (CB.isCallee(U)) {
-        IsRead = true;
+        Reads.push_back(I);
         // Note that indirect calls do not capture, see comment in
         // CaptureTracking for context
         continue;
@@ -668,12 +633,15 @@ determinePointerAccessAttrs(Argument *A,
           if (Visited.insert(&UU).second)
             Worklist.push_back(&UU);
       } else if (!CB.doesNotCapture(UseIndex)) {
-        if (!CB.onlyReadsMemory())
+        if (!CB.onlyReadsMemory()) {
           // If the callee can save a copy into other memory, then simply
           // scanning uses of the call is insufficient.  We have no way
           // of tracking copies of the pointer through memory to see
-          // if a reloaded copy is written to, thus we must give up.
-          return Attribute::None;
+          // if a reloaded copy is written to, thus we treat it as special
+          // uses.
+          SpecialUses.push_back(I);
+          continue;
+        }
         // Push users for processing once we finish this one
         if (!I->getType()->isVoidTy())
           for (Use &UU : I->uses())
@@ -698,12 +666,12 @@ determinePointerAccessAttrs(Argument *A,
       if (CB.doesNotAccessMemory(UseIndex)) {
         /* nop */
       } else if (!isModSet(ArgMR) || CB.onlyReadsMemory(UseIndex)) {
-        IsRead = true;
+        Reads.push_back(I);
       } else if (!isRefSet(ArgMR) ||
                  CB.dataOperandHasImpliedAttr(UseIndex, Attribute::WriteOnly)) {
-        IsWrite = true;
+        Writes.push_back(I);
       } else {
-        return Attribute::None;
+        SpecialUses.push_back(I);
       }
       break;
     }
@@ -711,23 +679,29 @@ determinePointerAccessAttrs(Argument *A,
     case Instruction::Load:
       // A volatile load has side effects beyond what readonly can be relied
       // upon.
-      if (cast<LoadInst>(I)->isVolatile())
-        return Attribute::None;
+      if (cast<LoadInst>(I)->isVolatile()) {
+        SpecialUses.push_back(I);
+        continue;
+      }
 
-      IsRead = true;
+      Reads.push_back(I);
       break;
 
     case Instruction::Store:
-      if (cast<StoreInst>(I)->getValueOperand() == *U)
+      if (cast<StoreInst>(I)->getValueOperand() == *U) {
         // untrackable capture
-        return Attribute::None;
+        SpecialUses.push_back(I);
+        continue;
+      }
 
       // A volatile store has side effects beyond what writeonly can be relied
       // upon.
-      if (cast<StoreInst>(I)->isVolatile())
-        return Attribute::None;
+      if (cast<StoreInst>(I)->isVolatile()) {
+        SpecialUses.push_back(I);
+        continue;
+      }
 
-      IsWrite = true;
+      Writes.push_back(I);
       break;
 
     case Instruction::ICmp:
@@ -735,15 +709,55 @@ determinePointerAccessAttrs(Argument *A,
       break;
 
     default:
-      return Attribute::None;
+      SpecialUses.push_back(I);
     }
   }
+  return {Reads, Writes, SpecialUses};
+}
+
+} // end anonymous namespace
+
+namespace llvm {
+
+template <> struct GraphTraits<ArgumentGraphNode *> {
+  using NodeRef = ArgumentGraphNode *;
+  using ChildIteratorType = SmallVectorImpl<ArgumentGraphNode *>::iterator;
+
+  static NodeRef getEntryNode(NodeRef A) { return A; }
+  static ChildIteratorType child_begin(NodeRef N) { return N->Uses.begin(); }
+  static ChildIteratorType child_end(NodeRef N) { return N->Uses.end(); }
+};
+
+template <>
+struct GraphTraits<ArgumentGraph *> : public GraphTraits<ArgumentGraphNode *> {
+  static NodeRef getEntryNode(ArgumentGraph *AG) { return AG->getEntryNode(); }
+
+  static ChildIteratorType nodes_begin(ArgumentGraph *AG) {
+    return AG->begin();
+  }
+
+  static ChildIteratorType nodes_end(ArgumentGraph *AG) { return AG->end(); }
+};
+
+} // end namespace llvm
+
+/// Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone.
+static Attribute::AttrKind
+determinePointerAccessAttrs(Argument *A, SmallVector<Instruction *, 16> &Reads,
+                            SmallVector<Instruction *, 16> &Writes,
+                            SmallVector<Instruction *, 16> &SpecialUses) {
+  // inalloca arguments are always clobbered by the call.
+  if (A->hasInAllocaAttr() || A->hasPreallocatedAttr())
+    return Attribute::None;
+
+  if (!SpecialUses.empty())
+    return Attribute::None;
 
-  if (IsWrite && IsRead)
+  if (!Writes.empty() && !Reads.empty())
     return Attribute::None;
-  else if (IsRead)
+  else if (!Reads.empty())
     return Attribute::ReadOnly;
-  else if (IsWrite)
+  else if (!Writes.empty())
     return Attribute::WriteOnly;
   else
     return Attribute::ReadNone;
@@ -931,7 +945,9 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
         // functions in the SCC.
         SmallPtrSet<Argument *, 8> Self;
         Self.insert(&A);
-        Attribute::AttrKind R = determinePointerAccessAttrs(&A, Self);
+        auto [Reads, Writes, SpecialUses] = getArgumentUses(&A, Self);
+        Attribute::AttrKind R =
+            determinePointerAccessAttrs(&A, Reads, Writes, SpecialUses);
         if (R != Attribute::None)
           if (addAccessAttr(&A, R))
             Changed.insert(F);
@@ -963,7 +979,9 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
         // Infer the access attributes given the new nocapture one
         SmallPtrSet<Argument *, 8> Self;
         Self.insert(&*A);
-        Attribute::AttrKind R = determinePointerAccessAttrs(&*A, Self);
+        auto [Reads, Writes, SpecialUses] = getArgumentUses(&*A, Self);
+        Attribute::AttrKind R =
+            determinePointerAccessAttrs(&*A, Reads, Writes, SpecialUses);
         if (R != Attribute::None)
           addAccessAttr(A, R);
       }
@@ -1032,7 +1050,9 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
     Attribute::AttrKind AccessAttr = Attribute::ReadNone;
     for (ArgumentGraphNode *N : ArgumentSCC) {
       Argument *A = N->Definition;
-      Attribute::AttrKind K = determinePointerAccessAttrs(A, ArgumentSCCNodes);
+      auto [Reads, Writes, SpecialUses] = getArgumentUses(A, ArgumentSCCNodes);
+      Attribute::AttrKind K =
+          determinePointerAccessAttrs(A, Reads, Writes, SpecialUses);
       AccessAttr = meetAccessAttr(AccessAttr, K);
       if (AccessAttr == Attribute::None)
         break;

>From 206b707e028743d7b4d3d975db4fb5b3c527f0df Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 14 Mar 2024 16:50:21 +0000
Subject: [PATCH 04/31] Add 'initialized' attribute support and undo the
 FunctionAttrs refactoring.

---
 llvm/include/llvm/ADT/FoldingSet.h          |  15 ++
 llvm/include/llvm/AsmParser/LLParser.h      |   5 +
 llvm/include/llvm/Bitcode/LLVMBitCodes.h    |   1 +
 llvm/include/llvm/IR/Attributes.h           |  19 +++
 llvm/include/llvm/IR/Attributes.td          |   6 +
 llvm/lib/AsmParser/LLParser.cpp             |  65 +++++++++
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp   |  18 +++
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp   |  17 ++-
 llvm/lib/IR/AttributeImpl.h                 |  31 ++++-
 llvm/lib/IR/Attributes.cpp                  |  73 +++++++++-
 llvm/lib/IR/Verifier.cpp                    |  21 +++
 llvm/lib/Transforms/IPO/FunctionAttrs.cpp   | 146 +++++++++-----------
 llvm/lib/Transforms/Utils/CodeExtractor.cpp |   1 +
 llvm/utils/TableGen/Attributes.cpp          |  11 +-
 14 files changed, 336 insertions(+), 93 deletions(-)

diff --git a/llvm/include/llvm/ADT/FoldingSet.h b/llvm/include/llvm/ADT/FoldingSet.h
index ddc3e52255d6c..04d6f9df40ceb 100644
--- a/llvm/include/llvm/ADT/FoldingSet.h
+++ b/llvm/include/llvm/ADT/FoldingSet.h
@@ -362,6 +362,21 @@ class FoldingSetNodeID {
     }
   }
 
+  void AddRanges(const SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
+    unsigned Size = Ranges.size();
+
+    unsigned NumsToInsert = 1 + 2 * Size;
+    Bits.reserve(Bits.size() + NumsToInsert);
+    Bits.push_back(Size);
+    if (Size == 0)
+      return;
+
+    for (const auto &[Start, End] : Ranges) {
+      Bits.push_back(Start);
+      Bits.push_back(End);
+    }
+  }
+
   void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
   void AddString(StringRef String);
   void AddNodeID(const FoldingSetNodeID &ID);
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index e85728aa3c0da..104bf06cf6604 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -275,6 +275,7 @@ namespace llvm {
       Loc = Lex.getLoc();
       return parseUInt64(Val);
     }
+    bool parseInt64(int64_t &Val);
     bool parseFlag(unsigned &Val);
 
     bool parseStringAttribute(AttrBuilder &B);
@@ -307,6 +308,10 @@ namespace llvm {
                                 bool AllowParens = false);
     bool parseOptionalCodeModel(CodeModel::Model &model);
     bool parseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
+    bool parseConstRange(std::pair<int64_t, int64_t> &Range);
+    bool parseInitializedRanges(
+        lltok::Kind AttrKind,
+        SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges);
     bool parseOptionalUWTableKind(UWTableKind &Kind);
     bool parseAllocKind(AllocFnKind &Kind);
     std::optional<MemoryEffects> parseMemoryAttr();
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index c0a52d64a101d..b2f38716b86f0 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -725,6 +725,7 @@ enum AttributeKindCodes {
   ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
   ATTR_KIND_DEAD_ON_UNWIND = 91,
   ATTR_KIND_RANGE = 92,
+  ATTR_KIND_INITIALIZED = 93,
 };
 
 enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 0c2a02514ba0e..b9d479e9b85cb 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -94,6 +94,8 @@ class Attribute {
 
   static const unsigned NumIntAttrKinds = LastIntAttr - FirstIntAttr + 1;
   static const unsigned NumTypeAttrKinds = LastTypeAttr - FirstTypeAttr + 1;
+  static const unsigned NumConstRangeListAttrKinds =
+      LastConstRangeListAttr - FirstConstRangeListAttr + 1;
 
   static bool isEnumAttrKind(AttrKind Kind) {
     return Kind >= FirstEnumAttr && Kind <= LastEnumAttr;
@@ -107,6 +109,9 @@ class Attribute {
   static bool isConstantRangeAttrKind(AttrKind Kind) {
     return Kind >= FirstConstantRangeAttr && Kind <= LastConstantRangeAttr;
   }
+  static bool isConstRangeListAttrKind(AttrKind Kind) {
+    return Kind >= FirstConstRangeListAttr && Kind <= LastConstRangeListAttr;
+  }
 
   static bool canUseAsFnAttr(AttrKind Kind);
   static bool canUseAsParamAttr(AttrKind Kind);
@@ -131,6 +136,8 @@ class Attribute {
   static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
   static Attribute get(LLVMContext &Context, AttrKind Kind,
                        const ConstantRange &CR);
+  static Attribute get(LLVMContext &Context, AttrKind Kind,
+                       SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges);
 
   /// Return a uniquified Attribute object that has the specific
   /// alignment set.
@@ -186,6 +193,9 @@ class Attribute {
   /// Return true if the attribute is a type attribute.
   bool isTypeAttribute() const;
 
+  /// Return true if the attribute is a const range list attribute.
+  bool isConstRangeListAttribute() const;
+
   /// Return true if the attribute is a ConstantRange attribute.
   bool isConstantRangeAttribute() const;
 
@@ -226,6 +236,10 @@ class Attribute {
   /// attribute to be a ConstantRange attribute.
   ConstantRange getValueAsConstantRange() const;
 
+  /// Return the attribute's value as a const range list. This requires the
+  /// attribute to be a const range list attribute.
+  SmallVector<std::pair<int64_t, int64_t>, 16> getValueAsRanges() const;
+
   /// Returns the alignment field of an attribute as a byte alignment
   /// value.
   MaybeAlign getAlignment() const;
@@ -1169,6 +1183,11 @@ class AttrBuilder {
   /// Add a type attribute with the given type.
   AttrBuilder &addTypeAttr(Attribute::AttrKind Kind, Type *Ty);
 
+  /// Add a const range list attribute with the given ranges.
+  AttrBuilder &
+  addConstRangeListAttr(Attribute::AttrKind Kind,
+                        SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges);
+
   /// This turns a byval type into the form used internally in Attribute.
   AttrBuilder &addByValAttr(Type *Ty);
 
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index cef8b17769f0d..79df429a07ee4 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -38,6 +38,9 @@ class IntAttr<string S, list<AttrProperty> P> : Attr<S, P>;
 /// Type attribute.
 class TypeAttr<string S, list<AttrProperty> P> : Attr<S, P>;
 
+/// Const range list attribute.
+class ConstRangeListAttr<string S, list<AttrProperty> P>: Attr<S, P>;
+
 /// StringBool attribute.
 class StrBoolAttr<string S> : Attr<S, []>;
 
@@ -318,6 +321,9 @@ def Writable : EnumAttr<"writable", [ParamAttr]>;
 /// Function only writes to memory.
 def WriteOnly : EnumAttr<"writeonly", [ParamAttr]>;
 
+/// Pointer argument memory [%p+LoN, %p+HiN) is initialized.
+def Initialized : ConstRangeListAttr<"initialized", [ParamAttr]>;
+
 /// Zero extended before/after call.
 def ZExt : EnumAttr<"zeroext", [ParamAttr, RetAttr]>;
 
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 78bcd94e23fae..b8e8d29696a46 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -1566,6 +1566,13 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
     B.addDereferenceableOrNullAttr(Bytes);
     return false;
   }
+  case Attribute::Initialized: {
+    SmallVector<std::pair<int64_t, int64_t>, 16> Ranges;
+    if (parseInitializedRanges(lltok::kw_initialized, Ranges))
+      return true;
+    B.addConstRangeListAttr(Attribute::Initialized, Ranges);
+    return false;
+  }
   case Attribute::UWTable: {
     UWTableKind Kind;
     if (parseOptionalUWTableKind(Kind))
@@ -1850,6 +1857,16 @@ bool LLParser::parseUInt64(uint64_t &Val) {
   return false;
 }
 
+/// parseInt64
+///   ::= int64_t
+bool LLParser::parseInt64(int64_t &Val) {
+  if (Lex.getKind() != lltok::APSInt)
+    return tokError("expected signed integer");
+  Val = Lex.getAPSIntVal().extend(64).getSExtValue();
+  Lex.Lex();
+  return false;
+}
+
 /// parseTLSModel
 ///   := 'localdynamic'
 ///   := 'initialexec'
@@ -2364,6 +2381,54 @@ bool LLParser::parseOptionalDerefAttrBytes(lltok::Kind AttrKind,
   return false;
 }
 
+bool LLParser::parseConstRange(std::pair<int64_t, int64_t> &Range) {
+  LocTy LparenLoc = Lex.getLoc();
+  if (!EatIfPresent(lltok::lparen))
+    return error(LparenLoc, "expected'('");
+
+  if (parseInt64(Range.first))
+    return true;
+
+  if (EatIfPresent(lltok::comma)) {
+    if (parseInt64(Range.second)) {
+      return true;
+    }
+  }
+
+  LocTy RparenLoc = Lex.getLoc();
+  if (!EatIfPresent(lltok::rparen))
+    return error(RparenLoc, "expected ')'");
+
+  return false;
+}
+
+bool LLParser::parseInitializedRanges(
+    lltok::Kind AttrKind,
+    SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
+  assert(AttrKind == lltok::kw_initialized);
+  Ranges.clear();
+
+  if (!EatIfPresent(AttrKind))
+    return false;
+
+  LocTy LparenLoc = Lex.getLoc();
+  if (!EatIfPresent(lltok::lparen))
+    return error(LparenLoc, "expected '('");
+
+  // Parse each range.
+  do {
+    std::pair<int64_t, int64_t> Range;
+    if (parseConstRange(Range))
+      return true;
+    Ranges.push_back(Range);
+  } while (EatIfPresent(lltok::comma));
+
+  LocTy RparenLoc = Lex.getLoc();
+  if (!EatIfPresent(lltok::rparen))
+    return error(RparenLoc, "expected ')'");
+  return false;
+}
+
 bool LLParser::parseOptionalUWTableKind(UWTableKind &Kind) {
   Lex.Lex();
   Kind = UWTableKind::Default;
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 9c63116114f3c..45dd33f888449 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2129,6 +2129,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
     return Attribute::DeadOnUnwind;
   case bitc::ATTR_KIND_RANGE:
     return Attribute::Range;
+  case bitc::ATTR_KIND_INITIALIZED:
+    return Attribute::Initialized;
   }
 }
 
@@ -2313,6 +2315,22 @@ Error BitcodeReader::parseAttributeGroupBlock() {
           i--;
 
           B.addConstantRangeAttr(Kind, MaybeCR.get());
+        } else if (Record[i] == 8 || Record[i] == 9) {
+          Attribute::AttrKind Kind;
+          if (Error Err = parseAttrKind(Record[++i], &Kind))
+            return Err;
+          if (!Attribute::isConstRangeListAttrKind(Kind))
+            return error("Not a const range list attribute");
+
+          SmallVector<std::pair<int64_t, int64_t>, 16> Ranges;
+          int RangeSize = Record[++i];
+          for (int Idx = 0; Idx < RangeSize; ++Idx) {
+            int Start = Record[++i];
+            int End = Record[++i];
+            Ranges.push_back(std::make_pair(Start, End));
+          }
+
+          B.addConstRangeListAttr(Kind, Ranges);
         } else {
           return error("Invalid attribute group entry");
         }
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 597f49332fad2..027a9bf68abcb 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -846,6 +846,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
     return bitc::ATTR_KIND_DEAD_ON_UNWIND;
   case Attribute::Range:
     return bitc::ATTR_KIND_RANGE;
+  case Attribute::Initialized:
+    return bitc::ATTR_KIND_INITIALIZED;
   case Attribute::EndAttrKinds:
     llvm_unreachable("Can not encode end-attribute kinds marker.");
   case Attribute::None:
@@ -930,11 +932,24 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
         Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
         if (Ty)
           Record.push_back(VE.getTypeID(Attr.getValueAsType()));
-      } else {
+      } else if (Attr.isConstantRangeAttribute()) {
         assert(Attr.isConstantRangeAttribute());
         Record.push_back(7);
         Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
         emitConstantRange(Record, Attr.getValueAsConstantRange());
+      } else {
+        assert(Attr.isConstRangeListAttribute());
+        const auto &Ranges = Attr.getValueAsRanges();
+
+        Record.push_back(Ranges.empty() ? 8 : 9);
+        Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
+        Record.push_back(Ranges.size());
+        if (!Ranges.empty()) {
+          for (const auto &Range : Ranges) {
+            Record.push_back(Range.first);
+            Record.push_back(Range.second);
+          }
+        }
       }
     }
 
diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index 9a6427bbc3d55..0c4db637a49ac 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -48,6 +48,7 @@ class AttributeImpl : public FoldingSetNode {
     StringAttrEntry,
     TypeAttrEntry,
     ConstantRangeAttrEntry,
+    ConstRangeListAttrEntry,
   };
 
   AttributeImpl(AttrEntryKind KindID) : KindID(KindID) {}
@@ -64,6 +65,9 @@ class AttributeImpl : public FoldingSetNode {
   bool isConstantRangeAttribute() const {
     return KindID == ConstantRangeAttrEntry;
   }
+  bool isConstRangeListAttribute() const {
+    return KindID == ConstRangeListAttrEntry;
+  }
 
   bool hasAttribute(Attribute::AttrKind A) const;
   bool hasAttribute(StringRef Kind) const;
@@ -79,6 +83,8 @@ class AttributeImpl : public FoldingSetNode {
 
   ConstantRange getValueAsConstantRange() const;
 
+  SmallVector<std::pair<int64_t, int64_t>, 16> getValueAsRanges() const;
+
   /// Used when sorting the attributes.
   bool operator<(const AttributeImpl &AI) const;
 
@@ -91,8 +97,10 @@ class AttributeImpl : public FoldingSetNode {
       Profile(ID, getKindAsString(), getValueAsString());
     else if (isTypeAttribute())
       Profile(ID, getKindAsEnum(), getValueAsType());
-    else
+    else if (isConstantRangeAttribute())
       Profile(ID, getKindAsEnum(), getValueAsConstantRange());
+    else
+      Profile(ID, getKindAsEnum(), getValueAsRanges());
   }
 
   static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind) {
@@ -124,6 +132,13 @@ class AttributeImpl : public FoldingSetNode {
     ID.AddInteger(CR.getLower());
     ID.AddInteger(CR.getUpper());
   }
+
+  static void
+  Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
+          const SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
+    ID.AddInteger(Kind);
+    ID.AddRanges(Ranges);
+  }
 };
 
 static_assert(std::is_trivially_destructible<AttributeImpl>::value,
@@ -222,6 +237,20 @@ class ConstantRangeAttributeImpl : public EnumAttributeImpl {
   ConstantRange getConstantRangeValue() const { return CR; }
 };
 
+class ConstRangeListAttributeImpl : public EnumAttributeImpl {
+  SmallVector<std::pair<int64_t, int64_t>, 16> Ranges;
+
+public:
+  ConstRangeListAttributeImpl(
+      Attribute::AttrKind Kind,
+      SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges)
+      : EnumAttributeImpl(ConstRangeListAttrEntry, Kind), Ranges(Ranges) {}
+
+  SmallVector<std::pair<int64_t, int64_t>, 16> getRangesValue() const {
+    return Ranges;
+  }
+};
+
 class AttributeBitSet {
   /// Bitset with a bit for each available attribute Attribute::AttrKind.
   uint8_t AvailableAttrs[12] = {};
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index b2d9992cdc025..f7d99de908730 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -191,6 +191,29 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
   return Attribute(PA);
 }
 
+Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
+                         SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
+  assert(Attribute::isConstRangeListAttrKind(Kind) &&
+         "Not a const range list attribute");
+  LLVMContextImpl *pImpl = Context.pImpl;
+  FoldingSetNodeID ID;
+  ID.AddInteger(Kind);
+  ID.AddRanges(Ranges);
+
+  void *InsertPoint;
+  AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
+
+  if (!PA) {
+    // If we didn't find any existing attributes of the same shape then create a
+    // new one and insert it.
+    PA = new (pImpl->Alloc) ConstRangeListAttributeImpl(Kind, Ranges);
+    pImpl->AttrsSet.InsertNode(PA, InsertPoint);
+  }
+
+  // Return the Attribute that we found or created.
+  return Attribute(PA);
+}
+
 Attribute Attribute::getWithAlignment(LLVMContext &Context, Align A) {
   assert(A <= llvm::Value::MaximumAlignment && "Alignment too large.");
   return get(Context, Alignment, A.value());
@@ -317,10 +340,14 @@ bool Attribute::isConstantRangeAttribute() const {
   return pImpl && pImpl->isConstantRangeAttribute();
 }
 
+bool Attribute::isConstRangeListAttribute() const {
+  return pImpl && pImpl->isConstRangeListAttribute();
+}
+
 Attribute::AttrKind Attribute::getKindAsEnum() const {
   if (!pImpl) return None;
   assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
-          isConstantRangeAttribute()) &&
+          isConstantRangeAttribute() || isConstRangeListAttribute()) &&
          "Invalid attribute type to get the kind as an enum!");
   return pImpl->getKindAsEnum();
 }
@@ -366,6 +393,15 @@ ConstantRange Attribute::getValueAsConstantRange() const {
   return pImpl->getValueAsConstantRange();
 }
 
+SmallVector<std::pair<int64_t, int64_t>, 16>
+Attribute::getValueAsRanges() const {
+  if (!pImpl)
+    return {};
+  assert(isConstRangeListAttribute() &&
+         "Invalid attribute type to get the value as a const range list!");
+  return pImpl->getValueAsRanges();
+}
+
 bool Attribute::hasAttribute(AttrKind Kind) const {
   return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None);
 }
@@ -616,6 +652,23 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     return Result;
   }
 
+  if (hasAttribute(Attribute::Initialized)) {
+    auto Ranges = getValueAsRanges();
+    if (Ranges.empty())
+      return "";
+
+    std::string Result = "initialized(";
+    raw_string_ostream OS(Result);
+    for (size_t i = 0; i < Ranges.size(); i++) {
+      auto [Start, End] = Ranges[i];
+      OS << "(" << Start << "," << End << ")";
+      if (i != Ranges.size() - 1)
+        OS << ",";
+    }
+    OS << ")";
+    return Result;
+  }
+
   // Convert target-dependent attributes to strings of the form:
   //
   //   "kind"
@@ -706,7 +759,7 @@ bool AttributeImpl::hasAttribute(StringRef Kind) const {
 
 Attribute::AttrKind AttributeImpl::getKindAsEnum() const {
   assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
-         isConstantRangeAttribute());
+         isConstantRangeAttribute() || isConstRangeListAttribute());
   return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();
 }
 
@@ -741,6 +794,13 @@ ConstantRange AttributeImpl::getValueAsConstantRange() const {
       ->getConstantRangeValue();
 }
 
+SmallVector<std::pair<int64_t, int64_t>, 16>
+AttributeImpl::getValueAsRanges() const {
+  assert(isConstRangeListAttribute());
+  return static_cast<const ConstRangeListAttributeImpl *>(this)
+      ->getRangesValue();
+}
+
 bool AttributeImpl::operator<(const AttributeImpl &AI) const {
   if (this == &AI)
     return false;
@@ -1948,6 +2008,12 @@ AttrBuilder &AttrBuilder::addConstantRangeAttr(Attribute::AttrKind Kind,
   return addAttribute(Attribute::get(Ctx, Kind, CR));
 }
 
+AttrBuilder &AttrBuilder::addConstRangeListAttr(
+    Attribute::AttrKind Kind,
+    SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
+  return addAttribute(Attribute::get(Ctx, Kind, Ranges));
+}
+
 AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
   return addConstantRangeAttr(Attribute::Range, CR);
 }
@@ -2040,7 +2106,8 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
           .addAttribute(Attribute::Dereferenceable)
           .addAttribute(Attribute::DereferenceableOrNull)
           .addAttribute(Attribute::Writable)
-          .addAttribute(Attribute::DeadOnUnwind);
+          .addAttribute(Attribute::DeadOnUnwind)
+          .addAttribute(Attribute::Initialized);
     if (ASK & ASK_UNSAFE_TO_DROP)
       Incompatible.addAttribute(Attribute::Nest)
           .addAttribute(Attribute::SwiftError)
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 0e6c01802cfb8..c4946a54f7bfe 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1993,6 +1993,14 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
           Attrs.hasAttribute(Attribute::ReadOnly)),
         "Attributes writable and readonly are incompatible!", V);
 
+  Check(!(Attrs.hasAttribute(Attribute::Initialized) &&
+          Attrs.hasAttribute(Attribute::ReadNone)),
+        "Attributes initialized and readnone are incompatible!", V);
+
+  Check(!(Attrs.hasAttribute(Attribute::Initialized) &&
+          Attrs.hasAttribute(Attribute::ReadOnly)),
+        "Attributes initialized and readonly are incompatible!", V);
+
   AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
   for (Attribute Attr : Attrs) {
     if (!Attr.isStringAttribute() &&
@@ -2044,6 +2052,19 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
     Check(Ty->isIntOrIntVectorTy(CR.getBitWidth()),
           "Range bit width must match type bit width!", V);
   }
+  if (Attrs.hasAttribute(Attribute::Initialized)) {
+    auto Inits = Attrs.getAttribute(Attribute::Initialized).getValueAsRanges();
+    Check(!Inits.empty(), "Attribute 'initialized' does not support empty list",
+          V);
+
+    for (size_t i = 1; i < Inits.size(); i++) {
+      Check(Inits[i].first > Inits[i - 1].first,
+            "Attribute 'initialized' requires intervals in ascending order!",
+            V);
+      Check(Inits[i].first > Inits[i - 1].second,
+            "Attribute 'initialized' requires intervals merged!", V);
+    }
+  }
 }
 
 void Verifier::checkUnsignedBaseTenFuncAttr(AttributeList Attrs, StringRef Attr,
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index a668dde567c01..7ebf265e17ba1 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -580,14 +580,45 @@ struct ArgumentUsesTracker : public CaptureTracker {
   const SCCNodeSet &SCCNodes;
 };
 
-/// Get all uses of an argument in the function and store them to different
-/// lists: Reads, Writes, and SpecialUses.
-std::tuple<SmallVector<Instruction *, 16>, SmallVector<Instruction *, 16>,
-           SmallVector<Instruction *, 16>>
-getArgumentUses(Argument *A, const SmallPtrSet<Argument *, 8> &SCCNodes) {
+} // end anonymous namespace
+
+namespace llvm {
+
+template <> struct GraphTraits<ArgumentGraphNode *> {
+  using NodeRef = ArgumentGraphNode *;
+  using ChildIteratorType = SmallVectorImpl<ArgumentGraphNode *>::iterator;
+
+  static NodeRef getEntryNode(NodeRef A) { return A; }
+  static ChildIteratorType child_begin(NodeRef N) { return N->Uses.begin(); }
+  static ChildIteratorType child_end(NodeRef N) { return N->Uses.end(); }
+};
+
+template <>
+struct GraphTraits<ArgumentGraph *> : public GraphTraits<ArgumentGraphNode *> {
+  static NodeRef getEntryNode(ArgumentGraph *AG) { return AG->getEntryNode(); }
+
+  static ChildIteratorType nodes_begin(ArgumentGraph *AG) {
+    return AG->begin();
+  }
+
+  static ChildIteratorType nodes_end(ArgumentGraph *AG) { return AG->end(); }
+};
+
+} // end namespace llvm
+
+/// Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone.
+static Attribute::AttrKind
+determinePointerAccessAttrs(Argument *A,
+                            const SmallPtrSet<Argument *, 8> &SCCNodes) {
   SmallVector<Use *, 32> Worklist;
   SmallPtrSet<Use *, 32> Visited;
-  SmallVector<Instruction *, 16> Reads, Writes, SpecialUses;
+
+  // inalloca arguments are always clobbered by the call.
+  if (A->hasInAllocaAttr() || A->hasPreallocatedAttr())
+    return Attribute::None;
+
+  bool IsRead = false;
+  bool IsWrite = false;
 
   for (Use &U : A->uses()) {
     Visited.insert(&U);
@@ -595,6 +626,10 @@ getArgumentUses(Argument *A, const SmallPtrSet<Argument *, 8> &SCCNodes) {
   }
 
   while (!Worklist.empty()) {
+    if (IsWrite && IsRead)
+      // No point in searching further..
+      return Attribute::None;
+
     Use *U = Worklist.pop_back_val();
     Instruction *I = cast<Instruction>(U->getUser());
 
@@ -614,7 +649,7 @@ getArgumentUses(Argument *A, const SmallPtrSet<Argument *, 8> &SCCNodes) {
     case Instruction::Invoke: {
       CallBase &CB = cast<CallBase>(*I);
       if (CB.isCallee(U)) {
-        Reads.push_back(I);
+        IsRead = true;
         // Note that indirect calls do not capture, see comment in
         // CaptureTracking for context
         continue;
@@ -633,15 +668,12 @@ getArgumentUses(Argument *A, const SmallPtrSet<Argument *, 8> &SCCNodes) {
           if (Visited.insert(&UU).second)
             Worklist.push_back(&UU);
       } else if (!CB.doesNotCapture(UseIndex)) {
-        if (!CB.onlyReadsMemory()) {
+        if (!CB.onlyReadsMemory())
           // If the callee can save a copy into other memory, then simply
           // scanning uses of the call is insufficient.  We have no way
           // of tracking copies of the pointer through memory to see
-          // if a reloaded copy is written to, thus we treat it as special
-          // uses.
-          SpecialUses.push_back(I);
-          continue;
-        }
+          // if a reloaded copy is written to, thus we must give up.
+          return Attribute::None;
         // Push users for processing once we finish this one
         if (!I->getType()->isVoidTy())
           for (Use &UU : I->uses())
@@ -666,12 +698,12 @@ getArgumentUses(Argument *A, const SmallPtrSet<Argument *, 8> &SCCNodes) {
       if (CB.doesNotAccessMemory(UseIndex)) {
         /* nop */
       } else if (!isModSet(ArgMR) || CB.onlyReadsMemory(UseIndex)) {
-        Reads.push_back(I);
+        IsRead = true;
       } else if (!isRefSet(ArgMR) ||
                  CB.dataOperandHasImpliedAttr(UseIndex, Attribute::WriteOnly)) {
-        Writes.push_back(I);
+        IsWrite = true;
       } else {
-        SpecialUses.push_back(I);
+        return Attribute::None;
       }
       break;
     }
@@ -679,29 +711,23 @@ getArgumentUses(Argument *A, const SmallPtrSet<Argument *, 8> &SCCNodes) {
     case Instruction::Load:
       // A volatile load has side effects beyond what readonly can be relied
       // upon.
-      if (cast<LoadInst>(I)->isVolatile()) {
-        SpecialUses.push_back(I);
-        continue;
-      }
+      if (cast<LoadInst>(I)->isVolatile())
+        return Attribute::None;
 
-      Reads.push_back(I);
+      IsRead = true;
       break;
 
     case Instruction::Store:
-      if (cast<StoreInst>(I)->getValueOperand() == *U) {
+      if (cast<StoreInst>(I)->getValueOperand() == *U)
         // untrackable capture
-        SpecialUses.push_back(I);
-        continue;
-      }
+        return Attribute::None;
 
       // A volatile store has side effects beyond what writeonly can be relied
       // upon.
-      if (cast<StoreInst>(I)->isVolatile()) {
-        SpecialUses.push_back(I);
-        continue;
-      }
+      if (cast<StoreInst>(I)->isVolatile())
+        return Attribute::None;
 
-      Writes.push_back(I);
+      IsWrite = true;
       break;
 
     case Instruction::ICmp:
@@ -709,55 +735,15 @@ getArgumentUses(Argument *A, const SmallPtrSet<Argument *, 8> &SCCNodes) {
       break;
 
     default:
-      SpecialUses.push_back(I);
+      return Attribute::None;
     }
   }
-  return {Reads, Writes, SpecialUses};
-}
-
-} // end anonymous namespace
-
-namespace llvm {
-
-template <> struct GraphTraits<ArgumentGraphNode *> {
-  using NodeRef = ArgumentGraphNode *;
-  using ChildIteratorType = SmallVectorImpl<ArgumentGraphNode *>::iterator;
-
-  static NodeRef getEntryNode(NodeRef A) { return A; }
-  static ChildIteratorType child_begin(NodeRef N) { return N->Uses.begin(); }
-  static ChildIteratorType child_end(NodeRef N) { return N->Uses.end(); }
-};
-
-template <>
-struct GraphTraits<ArgumentGraph *> : public GraphTraits<ArgumentGraphNode *> {
-  static NodeRef getEntryNode(ArgumentGraph *AG) { return AG->getEntryNode(); }
-
-  static ChildIteratorType nodes_begin(ArgumentGraph *AG) {
-    return AG->begin();
-  }
-
-  static ChildIteratorType nodes_end(ArgumentGraph *AG) { return AG->end(); }
-};
-
-} // end namespace llvm
-
-/// Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone.
-static Attribute::AttrKind
-determinePointerAccessAttrs(Argument *A, SmallVector<Instruction *, 16> &Reads,
-                            SmallVector<Instruction *, 16> &Writes,
-                            SmallVector<Instruction *, 16> &SpecialUses) {
-  // inalloca arguments are always clobbered by the call.
-  if (A->hasInAllocaAttr() || A->hasPreallocatedAttr())
-    return Attribute::None;
-
-  if (!SpecialUses.empty())
-    return Attribute::None;
 
-  if (!Writes.empty() && !Reads.empty())
+  if (IsWrite && IsRead)
     return Attribute::None;
-  else if (!Reads.empty())
+  else if (IsRead)
     return Attribute::ReadOnly;
-  else if (!Writes.empty())
+  else if (IsWrite)
     return Attribute::WriteOnly;
   else
     return Attribute::ReadNone;
@@ -945,9 +931,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
         // functions in the SCC.
         SmallPtrSet<Argument *, 8> Self;
         Self.insert(&A);
-        auto [Reads, Writes, SpecialUses] = getArgumentUses(&A, Self);
-        Attribute::AttrKind R =
-            determinePointerAccessAttrs(&A, Reads, Writes, SpecialUses);
+        Attribute::AttrKind R = determinePointerAccessAttrs(&A, Self);
         if (R != Attribute::None)
           if (addAccessAttr(&A, R))
             Changed.insert(F);
@@ -979,9 +963,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
         // Infer the access attributes given the new nocapture one
         SmallPtrSet<Argument *, 8> Self;
         Self.insert(&*A);
-        auto [Reads, Writes, SpecialUses] = getArgumentUses(&*A, Self);
-        Attribute::AttrKind R =
-            determinePointerAccessAttrs(&*A, Reads, Writes, SpecialUses);
+        Attribute::AttrKind R = determinePointerAccessAttrs(&*A, Self);
         if (R != Attribute::None)
           addAccessAttr(A, R);
       }
@@ -1050,9 +1032,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
     Attribute::AttrKind AccessAttr = Attribute::ReadNone;
     for (ArgumentGraphNode *N : ArgumentSCC) {
       Argument *A = N->Definition;
-      auto [Reads, Writes, SpecialUses] = getArgumentUses(A, ArgumentSCCNodes);
-      Attribute::AttrKind K =
-          determinePointerAccessAttrs(A, Reads, Writes, SpecialUses);
+      Attribute::AttrKind K = determinePointerAccessAttrs(A, ArgumentSCCNodes);
       AccessAttr = meetAccessAttr(AccessAttr, K);
       if (AccessAttr == Attribute::None)
         break;
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index ab2d25c3f17c7..6928553f0bdd3 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -1000,6 +1000,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
       case Attribute::Writable:
       case Attribute::DeadOnUnwind:
       case Attribute::Range:
+      case Attribute::Initialized:
       //  These are not really attributes.
       case Attribute::None:
       case Attribute::EndAttrKinds:
diff --git a/llvm/utils/TableGen/Attributes.cpp b/llvm/utils/TableGen/Attributes.cpp
index d9fc7834416cf..a39b5774d8db4 100644
--- a/llvm/utils/TableGen/Attributes.cpp
+++ b/llvm/utils/TableGen/Attributes.cpp
@@ -53,7 +53,8 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
   };
 
   // Emit attribute enums in the same order llvm::Attribute::operator< expects.
-  Emit({"EnumAttr", "TypeAttr", "IntAttr", "ConstantRangeAttr"},
+  Emit({"EnumAttr", "TypeAttr", "IntAttr", "ConstantRangeAttr",
+        "ConstRangeListAttr"},
        "ATTRIBUTE_ENUM");
   Emit({"StrBoolAttr"}, "ATTRIBUTE_STRBOOL");
   Emit({"ComplexStrAttr"}, "ATTRIBUTE_COMPLEXSTR");
@@ -64,8 +65,8 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
   OS << "#ifdef GET_ATTR_ENUM\n";
   OS << "#undef GET_ATTR_ENUM\n";
   unsigned Value = 1; // Leave zero for AttrKind::None.
-  for (StringRef KindName :
-       {"EnumAttr", "TypeAttr", "IntAttr", "ConstantRangeAttr"}) {
+  for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr",
+                             "ConstantRangeAttr", "ConstRangeListAttr"}) {
     OS << "First" << KindName << " = " << Value << ",\n";
     for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
       OS << A->getName() << " = " << Value << ",\n";
@@ -119,8 +120,8 @@ void Attributes::emitAttributeProperties(raw_ostream &OS) {
   OS << "#ifdef GET_ATTR_PROP_TABLE\n";
   OS << "#undef GET_ATTR_PROP_TABLE\n";
   OS << "static const uint8_t AttrPropTable[] = {\n";
-  for (StringRef KindName :
-       {"EnumAttr", "TypeAttr", "IntAttr", "ConstantRangeAttr"}) {
+  for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr",
+                             "ConstantRangeAttr", "ConstRangeListAttr"}) {
     for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
       OS << "0";
       for (Init *P : *A->getValueAsListInit("Properties"))

>From eaf5ca04cb5fc36115b8141fd3dd02da93d66eba Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 14 Mar 2024 17:04:48 +0000
Subject: [PATCH 05/31] Update the LangRef (round 2)

---
 llvm/docs/LangRef.rst | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 0d0f21b8d203e..2b48322ee8f31 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1623,14 +1623,14 @@ Currently, only the following parameter attributes are defined:
 
 ``initialized((Lo1,Hi1),...)``
     This attribute indicates that the function initializes the ranges of the
-    pointer parameter's memory, [%p+LoN, %p+HiN): there are no reads, and no
-    special accesses (such as volatile access or untrackable capture) before
-    the initialization write in the function.
+    pointer parameter's memory, ``[%p+LoN, %p+HiN)``. Initialization of memory
+    means the first memory access is a non-volatile, non-atomic write. The
+    write must happen before the function returns. If the function unwinds,
+    the write may not happen.
 
-    This attribute implies that the function initializes and does not read
-    before initialization through this pointer argument, even though it may
-    read the memory before initialization that the pointer points to, such
-    as through other arguments.
+    This attribute only holds for the memory accessed via this pointer
+    parameter. Other arbitrary accesses to the same memory via other pointers
+    are allowed.
 
     Note that this attribute does not apply to the unwind edge: the
     initializing function does not read the pointer before writing to it
@@ -1638,11 +1638,11 @@ Currently, only the following parameter attributes are defined:
     written to when unwinding happens.
 
     The ``writable`` or ``dereferenceable`` attribute does not imply the
-    ``initialized`` attribute, and ``initialized`` does not imply ``writeonly``
+    ``initialized`` attribute. The ``initialized`` does not imply ``writeonly``
     since ``initialized`` allows reading from the pointer after writing.
 
-    This attribute is a list of const ranges in ascending order with no
-    overlapping or adjoining list elements. LoN/HiN are 64-bit ints, and
+    This attribute is a list of constant ranges in ascending order with no
+    overlapping or consecutive list elements. ``LoN/HiN`` are 64-bit ints, and
     negative values are allowed in case the argument points partway into
     an allocation.
 

>From 52cc649f5dd67a1acf6a8a0e7325260f6b0e77ae Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 14 Mar 2024 20:19:09 +0000
Subject: [PATCH 06/31] Update FoldingSet.h

---
 llvm/include/llvm/ADT/FoldingSet.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/ADT/FoldingSet.h b/llvm/include/llvm/ADT/FoldingSet.h
index 04d6f9df40ceb..9e694c106333b 100644
--- a/llvm/include/llvm/ADT/FoldingSet.h
+++ b/llvm/include/llvm/ADT/FoldingSet.h
@@ -363,7 +363,7 @@ class FoldingSetNodeID {
   }
 
   void AddRanges(const SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
-    unsigned Size = Ranges.size();
+    size_t Size = Ranges.size();
 
     unsigned NumsToInsert = 1 + 2 * Size;
     Bits.reserve(Bits.size() + NumsToInsert);
@@ -371,7 +371,7 @@ class FoldingSetNodeID {
     if (Size == 0)
       return;
 
-    for (const auto &[Start, End] : Ranges) {
+    for (auto [Start, End] : Ranges) {
       Bits.push_back(Start);
       Bits.push_back(End);
     }

>From f7fddb00d399abe65fbb8369b15d79b74899f3a2 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Fri, 5 Apr 2024 21:09:27 +0000
Subject: [PATCH 07/31] Change the attribute type to ConstantRangeList

---
 llvm/docs/LangRef.rst                       |   7 +-
 llvm/include/llvm/ADT/FoldingSet.h          |  15 ---
 llvm/include/llvm/AsmParser/LLParser.h      |   5 +-
 llvm/include/llvm/IR/Attributes.h           |  37 ++++---
 llvm/include/llvm/IR/Attributes.td          |  12 +--
 llvm/include/llvm/IR/ConstantRangeList.h    | 108 +++++++++++++++++++
 llvm/lib/AsmParser/LLParser.cpp             | 111 ++++++++------------
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp   |  18 ++--
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp   |  19 ++--
 llvm/lib/IR/AttributeImpl.h                 |  37 +++----
 llvm/lib/IR/Attributes.cpp                  |  86 ++++++++-------
 llvm/lib/IR/CMakeLists.txt                  |   1 +
 llvm/lib/IR/ConstantRangeList.cpp           |  44 ++++++++
 llvm/lib/IR/LLVMContextImpl.h               |   3 +
 llvm/lib/IR/Verifier.cpp                    |  46 ++++----
 llvm/unittests/IR/CMakeLists.txt            |   1 +
 llvm/unittests/IR/ConstantRangeListTest.cpp |  51 +++++++++
 llvm/utils/TableGen/Attributes.cpp          |   6 +-
 18 files changed, 397 insertions(+), 210 deletions(-)
 create mode 100644 llvm/include/llvm/IR/ConstantRangeList.h
 create mode 100644 llvm/lib/IR/ConstantRangeList.cpp
 create mode 100644 llvm/unittests/IR/ConstantRangeListTest.cpp

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 2b48322ee8f31..e600fea284eb6 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1632,11 +1632,6 @@ Currently, only the following parameter attributes are defined:
     parameter. Other arbitrary accesses to the same memory via other pointers
     are allowed.
 
-    Note that this attribute does not apply to the unwind edge: the
-    initializing function does not read the pointer before writing to it
-    regardless of unwinding or not, but the memory may not actually be
-    written to when unwinding happens.
-
     The ``writable`` or ``dereferenceable`` attribute does not imply the
     ``initialized`` attribute. The ``initialized`` does not imply ``writeonly``
     since ``initialized`` allows reading from the pointer after writing.
@@ -1644,7 +1639,7 @@ Currently, only the following parameter attributes are defined:
     This attribute is a list of constant ranges in ascending order with no
     overlapping or consecutive list elements. ``LoN/HiN`` are 64-bit ints, and
     negative values are allowed in case the argument points partway into
-    an allocation.
+    an allocation. An empty list is not allowed.
 
 ``dead_on_unwind``
     At a high level, this attribute indicates that the pointer argument is dead
diff --git a/llvm/include/llvm/ADT/FoldingSet.h b/llvm/include/llvm/ADT/FoldingSet.h
index 9e694c106333b..ddc3e52255d6c 100644
--- a/llvm/include/llvm/ADT/FoldingSet.h
+++ b/llvm/include/llvm/ADT/FoldingSet.h
@@ -362,21 +362,6 @@ class FoldingSetNodeID {
     }
   }
 
-  void AddRanges(const SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
-    size_t Size = Ranges.size();
-
-    unsigned NumsToInsert = 1 + 2 * Size;
-    Bits.reserve(Bits.size() + NumsToInsert);
-    Bits.push_back(Size);
-    if (Size == 0)
-      return;
-
-    for (auto [Start, End] : Ranges) {
-      Bits.push_back(Start);
-      Bits.push_back(End);
-    }
-  }
-
   void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
   void AddString(StringRef String);
   void AddNodeID(const FoldingSetNodeID &ID);
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index 104bf06cf6604..97a55bc506c85 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -275,7 +275,6 @@ namespace llvm {
       Loc = Lex.getLoc();
       return parseUInt64(Val);
     }
-    bool parseInt64(int64_t &Val);
     bool parseFlag(unsigned &Val);
 
     bool parseStringAttribute(AttrBuilder &B);
@@ -309,9 +308,6 @@ namespace llvm {
     bool parseOptionalCodeModel(CodeModel::Model &model);
     bool parseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
     bool parseConstRange(std::pair<int64_t, int64_t> &Range);
-    bool parseInitializedRanges(
-        lltok::Kind AttrKind,
-        SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges);
     bool parseOptionalUWTableKind(UWTableKind &Kind);
     bool parseAllocKind(AllocFnKind &Kind);
     std::optional<MemoryEffects> parseMemoryAttr();
@@ -375,6 +371,7 @@ namespace llvm {
                                     std::vector<unsigned> &FwdRefAttrGrps,
                                     bool inAttrGrp, LocTy &BuiltinLoc);
     bool parseRangeAttr(AttrBuilder &B);
+    bool parseInitializedAttr(AttrBuilder &B);
     bool parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
                                Attribute::AttrKind AttrKind);
 
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index b9d479e9b85cb..f39e59bc24b89 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -38,6 +38,7 @@ class AttributeImpl;
 class AttributeListImpl;
 class AttributeSetNode;
 class ConstantRange;
+class ConstantRangeList;
 class FoldingSetNodeID;
 class Function;
 class LLVMContext;
@@ -94,8 +95,6 @@ class Attribute {
 
   static const unsigned NumIntAttrKinds = LastIntAttr - FirstIntAttr + 1;
   static const unsigned NumTypeAttrKinds = LastTypeAttr - FirstTypeAttr + 1;
-  static const unsigned NumConstRangeListAttrKinds =
-      LastConstRangeListAttr - FirstConstRangeListAttr + 1;
 
   static bool isEnumAttrKind(AttrKind Kind) {
     return Kind >= FirstEnumAttr && Kind <= LastEnumAttr;
@@ -109,8 +108,9 @@ class Attribute {
   static bool isConstantRangeAttrKind(AttrKind Kind) {
     return Kind >= FirstConstantRangeAttr && Kind <= LastConstantRangeAttr;
   }
-  static bool isConstRangeListAttrKind(AttrKind Kind) {
-    return Kind >= FirstConstRangeListAttr && Kind <= LastConstRangeListAttr;
+  static bool isConstantRangeListAttrKind(AttrKind Kind) {
+    return Kind >= FirstConstantRangeListAttr &&
+           Kind <= LastConstantRangeListAttr;
   }
 
   static bool canUseAsFnAttr(AttrKind Kind);
@@ -137,7 +137,7 @@ class Attribute {
   static Attribute get(LLVMContext &Context, AttrKind Kind,
                        const ConstantRange &CR);
   static Attribute get(LLVMContext &Context, AttrKind Kind,
-                       SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges);
+                       const ConstantRangeList &CRL);
 
   /// Return a uniquified Attribute object that has the specific
   /// alignment set.
@@ -193,12 +193,12 @@ class Attribute {
   /// Return true if the attribute is a type attribute.
   bool isTypeAttribute() const;
 
-  /// Return true if the attribute is a const range list attribute.
-  bool isConstRangeListAttribute() const;
-
   /// Return true if the attribute is a ConstantRange attribute.
   bool isConstantRangeAttribute() const;
 
+  /// Return true if the attribute is a ConstantRangeList attribute.
+  bool isConstantRangeListAttribute() const;
+
   /// Return true if the attribute is any kind of attribute.
   bool isValid() const { return pImpl; }
 
@@ -236,9 +236,9 @@ class Attribute {
   /// attribute to be a ConstantRange attribute.
   ConstantRange getValueAsConstantRange() const;
 
-  /// Return the attribute's value as a const range list. This requires the
-  /// attribute to be a const range list attribute.
-  SmallVector<std::pair<int64_t, int64_t>, 16> getValueAsRanges() const;
+  /// Return the attribute's value as a ConstantRangeList. This requires the
+  /// attribute to be a ConstantRangeList attribute.
+  ConstantRangeList getValueAsConstantRangeList() const;
 
   /// Returns the alignment field of an attribute as a byte alignment
   /// value.
@@ -281,6 +281,9 @@ class Attribute {
   /// Returns the value of the range attribute.
   ConstantRange getRange() const;
 
+  /// Returns the value of the initialized attribute.
+  ConstantRangeList getInitialized() const;
+
   /// The Attribute is converted to a string of equivalent mnemonic. This
   /// is, presumably, for writing out the mnemonics for the assembly writer.
   std::string getAsString(bool InAttrGrp = false) const;
@@ -1183,11 +1186,6 @@ class AttrBuilder {
   /// Add a type attribute with the given type.
   AttrBuilder &addTypeAttr(Attribute::AttrKind Kind, Type *Ty);
 
-  /// Add a const range list attribute with the given ranges.
-  AttrBuilder &
-  addConstRangeListAttr(Attribute::AttrKind Kind,
-                        SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges);
-
   /// This turns a byval type into the form used internally in Attribute.
   AttrBuilder &addByValAttr(Type *Ty);
 
@@ -1231,6 +1229,13 @@ class AttrBuilder {
   /// Add range attribute.
   AttrBuilder &addRangeAttr(const ConstantRange &CR);
 
+  /// Add a ConstantRangeList attribute with the given range.
+  AttrBuilder &addConstantRangeListAttr(Attribute::AttrKind Kind,
+                                        const ConstantRangeList &CRL);
+
+  /// Add initialized attribute.
+  AttrBuilder &addInitializedAttr(const ConstantRangeList &CRL);
+
   ArrayRef<Attribute> attrs() const { return Attrs; }
 
   bool operator==(const AttrBuilder &B) const;
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 79df429a07ee4..911373020f954 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -38,9 +38,6 @@ class IntAttr<string S, list<AttrProperty> P> : Attr<S, P>;
 /// Type attribute.
 class TypeAttr<string S, list<AttrProperty> P> : Attr<S, P>;
 
-/// Const range list attribute.
-class ConstRangeListAttr<string S, list<AttrProperty> P>: Attr<S, P>;
-
 /// StringBool attribute.
 class StrBoolAttr<string S> : Attr<S, []>;
 
@@ -50,6 +47,9 @@ class ComplexStrAttr<string S, list<AttrProperty> P> : Attr<S, P>;
 /// ConstantRange attribute.
 class ConstantRangeAttr<string S, list<AttrProperty> P> : Attr<S, P>;
 
+/// ConstantRangeList attribute.
+class ConstantRangeListAttr<string S, list<AttrProperty> P> : Attr<S, P>;
+
 /// Target-independent enum attributes.
 
 /// Alignment of parameter (5 bits) stored as log2 of alignment with +1 bias.
@@ -115,6 +115,9 @@ def FnRetThunkExtern : EnumAttr<"fn_ret_thunk_extern", [FnAttr]>;
 /// Pass structure in an alloca.
 def InAlloca : TypeAttr<"inalloca", [ParamAttr]>;
 
+/// Pointer argument memory is initialized.
+def Initialized : ConstantRangeListAttr<"initialized", [ParamAttr]>;
+
 /// Source said inlining was desirable.
 def InlineHint : EnumAttr<"inlinehint", [FnAttr]>;
 
@@ -321,9 +324,6 @@ def Writable : EnumAttr<"writable", [ParamAttr]>;
 /// Function only writes to memory.
 def WriteOnly : EnumAttr<"writeonly", [ParamAttr]>;
 
-/// Pointer argument memory [%p+LoN, %p+HiN) is initialized.
-def Initialized : ConstRangeListAttr<"initialized", [ParamAttr]>;
-
 /// Zero extended before/after call.
 def ZExt : EnumAttr<"zeroext", [ParamAttr, RetAttr]>;
 
diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
new file mode 100644
index 0000000000000..f83c73d34afdd
--- /dev/null
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -0,0 +1,108 @@
+//===- ConstantRangeList.h - A list of constant range -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Represent a list of signed ConstantRange and do NOT support wrap around the
+// end of the numeric range. Ranges in the list should have the same bitwidth.
+// Each range's lower should be less than its upper. Special lists (take 8-bit
+// as an example):
+//
+// {[0, 0)}     = Empty set
+// {[255, 255)} = Full Set
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_CONSTANTRANGELIST_H
+#define LLVM_IR_CONSTANTRANGELIST_H
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/IR/ConstantRange.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+
+class raw_ostream;
+
+/// This class represents a list of constant ranges.
+class [[nodiscard]] ConstantRangeList {
+  SmallVector<ConstantRange, 2> Ranges;
+  // Whether the range list is sorted: [i].lower() < [i+1].lower()
+  bool Sorted = true;
+
+public:
+  /// Initialize a full or empty set for the specified bit width.
+  explicit ConstantRangeList(uint32_t BitWidth, bool isFullSet);
+
+  ConstantRangeList(int64_t Lower, int64_t Upper);
+
+  SmallVectorImpl<ConstantRange>::iterator begin() { return Ranges.begin(); }
+  SmallVectorImpl<ConstantRange>::iterator end() { return Ranges.end(); }
+  SmallVectorImpl<ConstantRange>::const_iterator begin() const {
+    return Ranges.begin();
+  }
+  SmallVectorImpl<ConstantRange>::const_iterator end() const {
+    return Ranges.end();
+  }
+  ConstantRange getRange(unsigned i) const {
+    assert(i < Ranges.size());
+    return Ranges[i];
+  }
+
+  /// Return true if this set contains no members.
+  bool isEmptySet() const {
+    return Ranges.size() == 1 && Ranges[0].isEmptySet();
+  }
+
+  /// Return true if this set contains all of the elements possible
+  /// for this data-type.
+  bool isFullSet() const { return Ranges.size() == 1 && Ranges[0].isFullSet(); }
+
+  /// Get the bit width of this ConstantRangeList.
+  uint32_t getBitWidth() const { return Ranges[0].getBitWidth(); }
+
+  size_t size() const { return Ranges.size(); }
+
+  void append(const ConstantRange &Range) {
+    assert(Range.getLower().slt(Range.getUpper()));
+    if (isFullSet())
+      return;
+    if (isEmptySet()) {
+      Ranges[0] = Range;
+      return;
+    }
+    if (Range.getLower().slt(Ranges[size() - 1].getLower()))
+      Sorted = false;
+    Ranges.push_back(Range);
+  }
+
+  void append(int64_t Lower, int64_t Upper) {
+    append(ConstantRange(APInt(64, StringRef(std::to_string(Lower)), 10),
+                         APInt(64, StringRef(std::to_string(Upper)), 10)));
+  }
+
+  /// Return true if this range is equal to another range.
+  bool operator==(const ConstantRangeList &CRL) const {
+    if (size() != CRL.size())
+      return false;
+    for (size_t i = 0; i < size(); ++i) {
+      if (Ranges[i] != CRL.Ranges[i])
+        return false;
+    }
+    return true;
+  }
+  bool operator!=(const ConstantRangeList &CRL) const {
+    return !operator==(CRL);
+  }
+
+  /// Print out the bounds to a stream.
+  void print(raw_ostream &OS) const;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_IR_CONSTANTRANGELIST_H
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index b8e8d29696a46..a834fbe203ff1 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -25,6 +25,7 @@
 #include "llvm/IR/CallingConv.h"
 #include "llvm/IR/Comdat.h"
 #include "llvm/IR/ConstantRange.h"
+#include "llvm/IR/ConstantRangeList.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DerivedTypes.h"
@@ -1566,13 +1567,6 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
     B.addDereferenceableOrNullAttr(Bytes);
     return false;
   }
-  case Attribute::Initialized: {
-    SmallVector<std::pair<int64_t, int64_t>, 16> Ranges;
-    if (parseInitializedRanges(lltok::kw_initialized, Ranges))
-      return true;
-    B.addConstRangeListAttr(Attribute::Initialized, Ranges);
-    return false;
-  }
   case Attribute::UWTable: {
     UWTableKind Kind;
     if (parseOptionalUWTableKind(Kind))
@@ -1605,6 +1599,8 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
   }
   case Attribute::Range:
     return parseRangeAttr(B);
+  case Attribute::Initialized:
+    return parseInitializedAttr(B);
   default:
     B.addAttribute(Attr);
     Lex.Lex();
@@ -1857,16 +1853,6 @@ bool LLParser::parseUInt64(uint64_t &Val) {
   return false;
 }
 
-/// parseInt64
-///   ::= int64_t
-bool LLParser::parseInt64(int64_t &Val) {
-  if (Lex.getKind() != lltok::APSInt)
-    return tokError("expected signed integer");
-  Val = Lex.getAPSIntVal().extend(64).getSExtValue();
-  Lex.Lex();
-  return false;
-}
-
 /// parseTLSModel
 ///   := 'localdynamic'
 ///   := 'initialexec'
@@ -2381,54 +2367,6 @@ bool LLParser::parseOptionalDerefAttrBytes(lltok::Kind AttrKind,
   return false;
 }
 
-bool LLParser::parseConstRange(std::pair<int64_t, int64_t> &Range) {
-  LocTy LparenLoc = Lex.getLoc();
-  if (!EatIfPresent(lltok::lparen))
-    return error(LparenLoc, "expected'('");
-
-  if (parseInt64(Range.first))
-    return true;
-
-  if (EatIfPresent(lltok::comma)) {
-    if (parseInt64(Range.second)) {
-      return true;
-    }
-  }
-
-  LocTy RparenLoc = Lex.getLoc();
-  if (!EatIfPresent(lltok::rparen))
-    return error(RparenLoc, "expected ')'");
-
-  return false;
-}
-
-bool LLParser::parseInitializedRanges(
-    lltok::Kind AttrKind,
-    SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
-  assert(AttrKind == lltok::kw_initialized);
-  Ranges.clear();
-
-  if (!EatIfPresent(AttrKind))
-    return false;
-
-  LocTy LparenLoc = Lex.getLoc();
-  if (!EatIfPresent(lltok::lparen))
-    return error(LparenLoc, "expected '('");
-
-  // Parse each range.
-  do {
-    std::pair<int64_t, int64_t> Range;
-    if (parseConstRange(Range))
-      return true;
-    Ranges.push_back(Range);
-  } while (EatIfPresent(lltok::comma));
-
-  LocTy RparenLoc = Lex.getLoc();
-  if (!EatIfPresent(lltok::rparen))
-    return error(RparenLoc, "expected ')'");
-  return false;
-}
-
 bool LLParser::parseOptionalUWTableKind(UWTableKind &Kind) {
   Lex.Lex();
   Kind = UWTableKind::Default;
@@ -3116,6 +3054,49 @@ bool LLParser::parseRangeAttr(AttrBuilder &B) {
   return false;
 }
 
+/// parseInitializedAttr
+///   ::= initialized((Lo1,Hi1),(Lo2,Hi2),...)
+bool LLParser::parseInitializedAttr(AttrBuilder &B) {
+  Lex.Lex();
+
+  auto ParseAPSInt = [&](APInt &Val) {
+    if (Lex.getKind() != lltok::APSInt)
+      return tokError("expected integer");
+    Val = Lex.getAPSIntVal().extend(64);
+    Lex.Lex();
+    return false;
+  };
+
+  if (parseToken(lltok::lparen, "expected '('"))
+    return true;
+
+  ConstantRangeList CRL(64, false);
+  // Parse each constant range.
+  do {
+    APInt Lower, Upper;
+    if (parseToken(lltok::lparen, "expected'('"))
+      return true;
+
+    if (ParseAPSInt(Lower) || parseToken(lltok::comma, "expected ','") ||
+        ParseAPSInt(Upper))
+      return true;
+
+    if (Lower == Upper)
+      return tokError("the range should not represent the full or empty set!");
+
+    if (parseToken(lltok::rparen, "expected ')'"))
+      return true;
+
+    CRL.append(ConstantRange(Lower, Upper));
+  } while (EatIfPresent(lltok::comma));
+
+  if (parseToken(lltok::rparen, "expected ')'"))
+    return true;
+
+  B.addInitializedAttr(CRL);
+  return false;
+}
+
 /// parseOptionalOperandBundles
 ///    ::= /*empty*/
 ///    ::= '[' OperandBundle [, OperandBundle ]* ']'
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 45dd33f888449..b67bccdd2582e 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -30,6 +30,7 @@
 #include "llvm/IR/CallingConv.h"
 #include "llvm/IR/Comdat.h"
 #include "llvm/IR/Constant.h"
+#include "llvm/IR/ConstantRangeList.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
@@ -2315,22 +2316,21 @@ Error BitcodeReader::parseAttributeGroupBlock() {
           i--;
 
           B.addConstantRangeAttr(Kind, MaybeCR.get());
-        } else if (Record[i] == 8 || Record[i] == 9) {
+        } else if (Record[i] == 8) {
           Attribute::AttrKind Kind;
           if (Error Err = parseAttrKind(Record[++i], &Kind))
             return Err;
-          if (!Attribute::isConstRangeListAttrKind(Kind))
-            return error("Not a const range list attribute");
+          if (!Attribute::isConstantRangeListAttrKind(Kind))
+            return error("Not a constant range list attribute");
 
-          SmallVector<std::pair<int64_t, int64_t>, 16> Ranges;
+          ConstantRangeList CRL(64, false);
           int RangeSize = Record[++i];
           for (int Idx = 0; Idx < RangeSize; ++Idx) {
-            int Start = Record[++i];
-            int End = Record[++i];
-            Ranges.push_back(std::make_pair(Start, End));
+            int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
+            int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
+            CRL.append(Start, End);
           }
-
-          B.addConstRangeListAttr(Kind, Ranges);
+          B.addConstantRangeListAttr(Kind, CRL);
         } else {
           return error("Invalid attribute group entry");
         }
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 027a9bf68abcb..cae78d5f0fd79 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -33,6 +33,7 @@
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Comdat.h"
 #include "llvm/IR/Constant.h"
+#include "llvm/IR/ConstantRangeList.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DebugLoc.h"
@@ -933,22 +934,18 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
         if (Ty)
           Record.push_back(VE.getTypeID(Attr.getValueAsType()));
       } else if (Attr.isConstantRangeAttribute()) {
-        assert(Attr.isConstantRangeAttribute());
         Record.push_back(7);
         Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
         emitConstantRange(Record, Attr.getValueAsConstantRange());
       } else {
-        assert(Attr.isConstRangeListAttribute());
-        const auto &Ranges = Attr.getValueAsRanges();
-
-        Record.push_back(Ranges.empty() ? 8 : 9);
+        assert(Attr.isConstantRangeListAttribute());
+        Record.push_back(8);
         Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
-        Record.push_back(Ranges.size());
-        if (!Ranges.empty()) {
-          for (const auto &Range : Ranges) {
-            Record.push_back(Range.first);
-            Record.push_back(Range.second);
-          }
+        ConstantRangeList CRL = Attr.getValueAsConstantRangeList();
+        Record.push_back(CRL.size());
+        for (auto &CR : CRL) {
+          emitSignedInt64(Record, CR.getLower().getSExtValue());
+          emitSignedInt64(Record, CR.getUpper().getSExtValue());
         }
       }
     }
diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index 0c4db637a49ac..2fae149e44eda 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -21,6 +21,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/ConstantRange.h"
+#include "llvm/IR/ConstantRangeList.h"
 #include "llvm/Support/TrailingObjects.h"
 #include <cassert>
 #include <cstddef>
@@ -48,7 +49,7 @@ class AttributeImpl : public FoldingSetNode {
     StringAttrEntry,
     TypeAttrEntry,
     ConstantRangeAttrEntry,
-    ConstRangeListAttrEntry,
+    ConstantRangeListAttrEntry,
   };
 
   AttributeImpl(AttrEntryKind KindID) : KindID(KindID) {}
@@ -65,8 +66,8 @@ class AttributeImpl : public FoldingSetNode {
   bool isConstantRangeAttribute() const {
     return KindID == ConstantRangeAttrEntry;
   }
-  bool isConstRangeListAttribute() const {
-    return KindID == ConstRangeListAttrEntry;
+  bool isConstantRangeListAttribute() const {
+    return KindID == ConstantRangeListAttrEntry;
   }
 
   bool hasAttribute(Attribute::AttrKind A) const;
@@ -83,7 +84,7 @@ class AttributeImpl : public FoldingSetNode {
 
   ConstantRange getValueAsConstantRange() const;
 
-  SmallVector<std::pair<int64_t, int64_t>, 16> getValueAsRanges() const;
+  ConstantRangeList getValueAsConstantRangeList() const;
 
   /// Used when sorting the attributes.
   bool operator<(const AttributeImpl &AI) const;
@@ -100,7 +101,7 @@ class AttributeImpl : public FoldingSetNode {
     else if (isConstantRangeAttribute())
       Profile(ID, getKindAsEnum(), getValueAsConstantRange());
     else
-      Profile(ID, getKindAsEnum(), getValueAsRanges());
+      Profile(ID, getKindAsEnum(), getValueAsConstantRangeList());
   }
 
   static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind) {
@@ -133,11 +134,14 @@ class AttributeImpl : public FoldingSetNode {
     ID.AddInteger(CR.getUpper());
   }
 
-  static void
-  Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
-          const SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
+  static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
+                      const ConstantRangeList &CRL) {
     ID.AddInteger(Kind);
-    ID.AddRanges(Ranges);
+    ID.AddInteger(CRL.size());
+    for (auto &CR : CRL) {
+      ID.AddInteger(CR.getLower());
+      ID.AddInteger(CR.getUpper());
+    }
   }
 };
 
@@ -237,18 +241,15 @@ class ConstantRangeAttributeImpl : public EnumAttributeImpl {
   ConstantRange getConstantRangeValue() const { return CR; }
 };
 
-class ConstRangeListAttributeImpl : public EnumAttributeImpl {
-  SmallVector<std::pair<int64_t, int64_t>, 16> Ranges;
+class ConstantRangeListAttributeImpl : public EnumAttributeImpl {
+  ConstantRangeList CRL;
 
 public:
-  ConstRangeListAttributeImpl(
-      Attribute::AttrKind Kind,
-      SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges)
-      : EnumAttributeImpl(ConstRangeListAttrEntry, Kind), Ranges(Ranges) {}
+  ConstantRangeListAttributeImpl(Attribute::AttrKind Kind,
+                                 const ConstantRangeList &CRL)
+      : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), CRL(CRL) {}
 
-  SmallVector<std::pair<int64_t, int64_t>, 16> getRangesValue() const {
-    return Ranges;
-  }
+  ConstantRangeList getConstantRangeListValue() const { return CRL; }
 };
 
 class AttributeBitSet {
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index f7d99de908730..5f0283ba76d21 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Config/llvm-config.h"
 #include "llvm/IR/AttributeMask.h"
 #include "llvm/IR/ConstantRange.h"
+#include "llvm/IR/ConstantRangeList.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Type.h"
@@ -192,13 +193,17 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
 }
 
 Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
-                         SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
-  assert(Attribute::isConstRangeListAttrKind(Kind) &&
-         "Not a const range list attribute");
+                         const ConstantRangeList &CRL) {
+  assert(Attribute::isConstantRangeListAttrKind(Kind) &&
+         "Not a ConstantRangeList attribute");
   LLVMContextImpl *pImpl = Context.pImpl;
   FoldingSetNodeID ID;
   ID.AddInteger(Kind);
-  ID.AddRanges(Ranges);
+  ID.AddInteger(CRL.size());
+  for (auto &CR : CRL) {
+    ID.AddInteger(CR.getLower());
+    ID.AddInteger(CR.getUpper());
+  }
 
   void *InsertPoint;
   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
@@ -206,7 +211,8 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
   if (!PA) {
     // If we didn't find any existing attributes of the same shape then create a
     // new one and insert it.
-    PA = new (pImpl->Alloc) ConstRangeListAttributeImpl(Kind, Ranges);
+    PA = new (pImpl->ConstantRangeListAttributeAlloc.Allocate())
+        ConstantRangeListAttributeImpl(Kind, CRL);
     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
   }
 
@@ -340,14 +346,14 @@ bool Attribute::isConstantRangeAttribute() const {
   return pImpl && pImpl->isConstantRangeAttribute();
 }
 
-bool Attribute::isConstRangeListAttribute() const {
-  return pImpl && pImpl->isConstRangeListAttribute();
+bool Attribute::isConstantRangeListAttribute() const {
+  return pImpl && pImpl->isConstantRangeListAttribute();
 }
 
 Attribute::AttrKind Attribute::getKindAsEnum() const {
   if (!pImpl) return None;
   assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
-          isConstantRangeAttribute() || isConstRangeListAttribute()) &&
+          isConstantRangeAttribute() || isConstantRangeListAttribute()) &&
          "Invalid attribute type to get the kind as an enum!");
   return pImpl->getKindAsEnum();
 }
@@ -393,13 +399,10 @@ ConstantRange Attribute::getValueAsConstantRange() const {
   return pImpl->getValueAsConstantRange();
 }
 
-SmallVector<std::pair<int64_t, int64_t>, 16>
-Attribute::getValueAsRanges() const {
-  if (!pImpl)
-    return {};
-  assert(isConstRangeListAttribute() &&
-         "Invalid attribute type to get the value as a const range list!");
-  return pImpl->getValueAsRanges();
+ConstantRangeList Attribute::getValueAsConstantRangeList() const {
+  assert(isConstantRangeListAttribute() &&
+         "Invalid attribute type to get the value as a ConstantRangeList!");
+  return pImpl->getValueAsConstantRangeList();
 }
 
 bool Attribute::hasAttribute(AttrKind Kind) const {
@@ -486,6 +489,12 @@ ConstantRange Attribute::getRange() const {
   return pImpl->getValueAsConstantRange();
 }
 
+ConstantRangeList Attribute::getInitialized() const {
+  assert(hasAttribute(Attribute::Initialized) &&
+         "Trying to get initialized attr from non-ConstantRangeList attribute");
+  return pImpl->getValueAsConstantRangeList();
+}
+
 static const char *getModRefStr(ModRefInfo MR) {
   switch (MR) {
   case ModRefInfo::NoModRef:
@@ -653,19 +662,19 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
   }
 
   if (hasAttribute(Attribute::Initialized)) {
-    auto Ranges = getValueAsRanges();
-    if (Ranges.empty())
-      return "";
-
-    std::string Result = "initialized(";
+    std::string Result;
     raw_string_ostream OS(Result);
-    for (size_t i = 0; i < Ranges.size(); i++) {
-      auto [Start, End] = Ranges[i];
-      OS << "(" << Start << "," << End << ")";
-      if (i != Ranges.size() - 1)
+    ConstantRangeList CRL = getValueAsConstantRangeList();
+    OS << "initialized(";
+    size_t i = 0;
+    for (auto &CR : CRL) {
+      OS << "(" << CR.getLower() << "," << CR.getUpper() << ")";
+      if (i != CRL.size() - 1)
         OS << ",";
+      i++;
     }
     OS << ")";
+    OS.flush();
     return Result;
   }
 
@@ -759,7 +768,7 @@ bool AttributeImpl::hasAttribute(StringRef Kind) const {
 
 Attribute::AttrKind AttributeImpl::getKindAsEnum() const {
   assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
-         isConstantRangeAttribute() || isConstRangeListAttribute());
+         isConstantRangeAttribute() || isConstantRangeListAttribute());
   return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();
 }
 
@@ -794,11 +803,10 @@ ConstantRange AttributeImpl::getValueAsConstantRange() const {
       ->getConstantRangeValue();
 }
 
-SmallVector<std::pair<int64_t, int64_t>, 16>
-AttributeImpl::getValueAsRanges() const {
-  assert(isConstRangeListAttribute());
-  return static_cast<const ConstRangeListAttributeImpl *>(this)
-      ->getRangesValue();
+ConstantRangeList AttributeImpl::getValueAsConstantRangeList() const {
+  assert(isConstantRangeListAttribute());
+  return static_cast<const ConstantRangeListAttributeImpl *>(this)
+      ->getConstantRangeListValue();
 }
 
 bool AttributeImpl::operator<(const AttributeImpl &AI) const {
@@ -815,6 +823,8 @@ bool AttributeImpl::operator<(const AttributeImpl &AI) const {
     assert(!AI.isEnumAttribute() && "Non-unique attribute");
     assert(!AI.isTypeAttribute() && "Comparison of types would be unstable");
     assert(!AI.isConstantRangeAttribute() && "Unclear how to compare ranges");
+    assert(!AI.isConstantRangeListAttribute() &&
+           "Unclear how to compare range list");
     // TODO: Is this actually needed?
     assert(AI.isIntAttribute() && "Only possibility left");
     return getValueAsInt() < AI.getValueAsInt();
@@ -2008,16 +2018,20 @@ AttrBuilder &AttrBuilder::addConstantRangeAttr(Attribute::AttrKind Kind,
   return addAttribute(Attribute::get(Ctx, Kind, CR));
 }
 
-AttrBuilder &AttrBuilder::addConstRangeListAttr(
-    Attribute::AttrKind Kind,
-    SmallVector<std::pair<int64_t, int64_t>, 16> &Ranges) {
-  return addAttribute(Attribute::get(Ctx, Kind, Ranges));
-}
-
 AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
   return addConstantRangeAttr(Attribute::Range, CR);
 }
 
+AttrBuilder &
+AttrBuilder::addConstantRangeListAttr(Attribute::AttrKind Kind,
+                                      const ConstantRangeList &CRL) {
+  return addAttribute(Attribute::get(Ctx, Kind, CRL));
+}
+
+AttrBuilder &AttrBuilder::addInitializedAttr(const ConstantRangeList &CRL) {
+  return addConstantRangeListAttr(Attribute::Initialized, CRL);
+}
+
 AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
   // TODO: Could make this O(n) as we're merging two sorted lists.
   for (const auto &I : B.attrs())
diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt
index f1668ee3be63b..f8de1aa28044b 100644
--- a/llvm/lib/IR/CMakeLists.txt
+++ b/llvm/lib/IR/CMakeLists.txt
@@ -9,6 +9,7 @@ add_llvm_component_library(LLVMCore
   Comdat.cpp
   ConstantFold.cpp
   ConstantRange.cpp
+  ConstantRangeList.cpp
   Constants.cpp
   ConvergenceVerifier.cpp
   Core.cpp
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
new file mode 100644
index 0000000000000..96304ade997d3
--- /dev/null
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -0,0 +1,44 @@
+//===- ConstantRangeList.cpp - ConstantRangeList implementation -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Represent a list of signed ConstantRange and do NOT support wrap around the
+// end of the numeric range. Ranges in the list should have the same bitwidth.
+// Each range's lower should be less than its upper. Special lists (take 8-bit
+// as an example):
+//
+// {[0, 0)}     = Empty set
+// {[255, 255)} = Full Set
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/ConstantRangeList.h"
+#include <cstddef>
+
+using namespace llvm;
+
+ConstantRangeList::ConstantRangeList(uint32_t BitWidth, bool Full) {
+  APInt Lower =
+      Full ? APInt::getMaxValue(BitWidth) : APInt::getMinValue(BitWidth);
+  Ranges.push_back(ConstantRange(Lower, Lower));
+}
+
+ConstantRangeList::ConstantRangeList(int64_t Lower, int64_t Upper) {
+  Ranges.push_back(
+      ConstantRange(APInt(64, StringRef(std::to_string(Lower)), 10),
+                    APInt(64, StringRef(std::to_string(Upper)), 10)));
+}
+
+void ConstantRangeList::print(raw_ostream &OS) const {
+  if (isFullSet())
+    OS << "full-set";
+  else if (isEmptySet())
+    OS << "empty-set";
+  else
+    for (const auto &Range : Ranges)
+      Range.print(OS);
+}
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 547a02a6490ea..04546b080babe 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -57,6 +57,7 @@ class AttributeListImpl;
 class AttributeSetNode;
 class BasicBlock;
 class ConstantRangeAttributeImpl;
+class ConstantRangeListAttributeImpl;
 struct DiagnosticHandler;
 class DPMarker;
 class ElementCount;
@@ -1565,6 +1566,8 @@ class LLVMContextImpl {
   UniqueStringSaver Saver{Alloc};
   SpecificBumpPtrAllocator<ConstantRangeAttributeImpl>
       ConstantRangeAttributeAlloc;
+  SpecificBumpPtrAllocator<ConstantRangeListAttributeImpl>
+      ConstantRangeListAttributeAlloc;
 
   DenseMap<unsigned, IntegerType *> IntegerTypes;
 
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index c4946a54f7bfe..fcdbc2d910865 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -72,6 +72,7 @@
 #include "llvm/IR/Comdat.h"
 #include "llvm/IR/Constant.h"
 #include "llvm/IR/ConstantRange.h"
+#include "llvm/IR/ConstantRangeList.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/ConvergenceVerifier.h"
 #include "llvm/IR/DataLayout.h"
@@ -1993,14 +1994,6 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
           Attrs.hasAttribute(Attribute::ReadOnly)),
         "Attributes writable and readonly are incompatible!", V);
 
-  Check(!(Attrs.hasAttribute(Attribute::Initialized) &&
-          Attrs.hasAttribute(Attribute::ReadNone)),
-        "Attributes initialized and readnone are incompatible!", V);
-
-  Check(!(Attrs.hasAttribute(Attribute::Initialized) &&
-          Attrs.hasAttribute(Attribute::ReadOnly)),
-        "Attributes initialized and readonly are incompatible!", V);
-
   AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
   for (Attribute Attr : Attrs) {
     if (!Attr.isStringAttribute() &&
@@ -2040,6 +2033,30 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
     }
   }
 
+  if (Attrs.hasAttribute(Attribute::Initialized)) {
+    auto Inits = Attrs.getAttribute(Attribute::Initialized)
+                     .getValueAsConstantRangeList();
+    Check(!Inits.isEmptySet(),
+          "Attribute 'initialized' does not support empty list", V);
+    Check(!Inits.isFullSet(),
+          "Attribute 'initialized' does not support full list", V);
+
+    Check(Inits.getRange(0).getLower().slt(Inits.getRange(0).getUpper()),
+          "Attribute 'initialized' requires interval lower less than upper", V);
+    for (size_t i = 1; i < Inits.size(); i++) {
+      auto Previous = Inits.getRange(i - 1);
+      auto Current = Inits.getRange(i);
+      Check(Current.getLower().slt(Current.getUpper()),
+            "Attribute 'initialized' requires interval lower less than upper",
+            V);
+      Check(Current.getLower().sge(Previous.getLower()),
+            "Attribute 'initialized' requires intervals in ascending order!",
+            V);
+      Check(Current.getLower().sge(Previous.getUpper()),
+            "Attribute 'initialized' requires intervals merged!", V);
+    }
+  }
+
   if (Attrs.hasAttribute(Attribute::NoFPClass)) {
     uint64_t Val = Attrs.getAttribute(Attribute::NoFPClass).getValueAsInt();
     Check(Val != 0, "Attribute 'nofpclass' must have at least one test bit set",
@@ -2052,19 +2069,6 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
     Check(Ty->isIntOrIntVectorTy(CR.getBitWidth()),
           "Range bit width must match type bit width!", V);
   }
-  if (Attrs.hasAttribute(Attribute::Initialized)) {
-    auto Inits = Attrs.getAttribute(Attribute::Initialized).getValueAsRanges();
-    Check(!Inits.empty(), "Attribute 'initialized' does not support empty list",
-          V);
-
-    for (size_t i = 1; i < Inits.size(); i++) {
-      Check(Inits[i].first > Inits[i - 1].first,
-            "Attribute 'initialized' requires intervals in ascending order!",
-            V);
-      Check(Inits[i].first > Inits[i - 1].second,
-            "Attribute 'initialized' requires intervals merged!", V);
-    }
-  }
 }
 
 void Verifier::checkUnsignedBaseTenFuncAttr(AttributeList Attrs, StringRef Attr,
diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt
index 803164b8f1eac..4ee95f9c7ae3c 100644
--- a/llvm/unittests/IR/CMakeLists.txt
+++ b/llvm/unittests/IR/CMakeLists.txt
@@ -17,6 +17,7 @@ add_llvm_unittest(IRTests
   BasicBlockDbgInfoTest.cpp
   CFGBuilder.cpp
   ConstantRangeTest.cpp
+  ConstantRangeListTest.cpp
   ConstantsTest.cpp
   DataLayoutTest.cpp
   DebugInfoTest.cpp
diff --git a/llvm/unittests/IR/ConstantRangeListTest.cpp b/llvm/unittests/IR/ConstantRangeListTest.cpp
new file mode 100644
index 0000000000000..db262a508a84a
--- /dev/null
+++ b/llvm/unittests/IR/ConstantRangeListTest.cpp
@@ -0,0 +1,51 @@
+//===- ConstantRangeListTest.cpp - ConstantRangeList tests ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/ConstantRangeList.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class ConstantRangeListTest : public ::testing::Test {
+public:
+  ConstantRangeList
+  GetCRL(SmallVectorImpl<std::pair<int64_t, int64_t>> &Ranges) {
+    ConstantRangeList Result(64, false);
+    for (const auto &[Start, End] : Ranges) {
+      Result.append(Start, End);
+    }
+    return Result;
+  }
+
+protected:
+  static ConstantRangeList Full;
+  static ConstantRangeList Empty;
+};
+
+ConstantRangeList ConstantRangeListTest::Full(64, true);
+ConstantRangeList ConstantRangeListTest::Empty(64, false);
+
+TEST_F(ConstantRangeListTest, Basics) {
+  EXPECT_TRUE(Full.isFullSet());
+  EXPECT_FALSE(Full.isEmptySet());
+
+  EXPECT_FALSE(Empty.isFullSet());
+  EXPECT_TRUE(Empty.isEmptySet());
+
+  ConstantRangeList Some1 = GetCRL({(0, 4), (8, 12)});
+  EXPECT_FALSE(Some1.isFullSet());
+  EXPECT_FALSE(Some1.isEmptySet());
+
+  ConstantRangeList Some2 = GetCRL({(0, 4), (8, 12)});
+  ConstantRangeList Some3 = GetCRL({(-4, 0), (8, 12)});
+  EXPECT_TRUE(Some1 == Some2 && Some1 != Some3);
+}
+
+} // anonymous namespace
diff --git a/llvm/utils/TableGen/Attributes.cpp b/llvm/utils/TableGen/Attributes.cpp
index a39b5774d8db4..c50316985ef09 100644
--- a/llvm/utils/TableGen/Attributes.cpp
+++ b/llvm/utils/TableGen/Attributes.cpp
@@ -54,7 +54,7 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
 
   // Emit attribute enums in the same order llvm::Attribute::operator< expects.
   Emit({"EnumAttr", "TypeAttr", "IntAttr", "ConstantRangeAttr",
-        "ConstRangeListAttr"},
+        "ConstantRangeListAttr"},
        "ATTRIBUTE_ENUM");
   Emit({"StrBoolAttr"}, "ATTRIBUTE_STRBOOL");
   Emit({"ComplexStrAttr"}, "ATTRIBUTE_COMPLEXSTR");
@@ -66,7 +66,7 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
   OS << "#undef GET_ATTR_ENUM\n";
   unsigned Value = 1; // Leave zero for AttrKind::None.
   for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr",
-                             "ConstantRangeAttr", "ConstRangeListAttr"}) {
+                             "ConstantRangeAttr", "ConstantRangeListAttr"}) {
     OS << "First" << KindName << " = " << Value << ",\n";
     for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
       OS << A->getName() << " = " << Value << ",\n";
@@ -121,7 +121,7 @@ void Attributes::emitAttributeProperties(raw_ostream &OS) {
   OS << "#undef GET_ATTR_PROP_TABLE\n";
   OS << "static const uint8_t AttrPropTable[] = {\n";
   for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr",
-                             "ConstantRangeAttr", "ConstRangeListAttr"}) {
+                             "ConstantRangeAttr", "ConstantRangeListAttr"}) {
     for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
       OS << "0";
       for (Init *P : *A->getValueAsListInit("Properties"))

>From 3b5955a7e0e75e26e69180a06dfadd6caec0a489 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Fri, 5 Apr 2024 21:41:15 +0000
Subject: [PATCH 08/31] Rename attr to initializes

---
 llvm/docs/LangRef.rst                       |  6 ++--
 llvm/include/llvm/AsmParser/LLParser.h      |  3 +-
 llvm/include/llvm/Bitcode/LLVMBitCodes.h    |  2 +-
 llvm/include/llvm/IR/Attributes.h           |  8 +++---
 llvm/include/llvm/IR/Attributes.td          |  2 +-
 llvm/lib/AsmParser/LLParser.cpp             | 12 ++++----
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp   |  4 +--
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp   |  4 +--
 llvm/lib/IR/Attributes.cpp                  | 16 +++++------
 llvm/lib/IR/Verifier.cpp                    | 16 +++++------
 llvm/lib/Transforms/Utils/CodeExtractor.cpp |  2 +-
 llvm/unittests/IR/ConstantRangeListTest.cpp | 32 ++++++++++-----------
 12 files changed, 52 insertions(+), 55 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index e600fea284eb6..3f7cef4f6493e 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1621,7 +1621,7 @@ Currently, only the following parameter attributes are defined:
     ``readonly`` or a ``memory`` attribute that does not contain
     ``argmem: write``.
 
-``initialized((Lo1,Hi1),...)``
+``initializes((Lo1,Hi1),...)``
     This attribute indicates that the function initializes the ranges of the
     pointer parameter's memory, ``[%p+LoN, %p+HiN)``. Initialization of memory
     means the first memory access is a non-volatile, non-atomic write. The
@@ -1633,8 +1633,8 @@ Currently, only the following parameter attributes are defined:
     are allowed.
 
     The ``writable`` or ``dereferenceable`` attribute does not imply the
-    ``initialized`` attribute. The ``initialized`` does not imply ``writeonly``
-    since ``initialized`` allows reading from the pointer after writing.
+    ``initializes`` attribute. The ``initializes`` does not imply ``writeonly``
+    since ``initializes`` allows reading from the pointer after writing.
 
     This attribute is a list of constant ranges in ascending order with no
     overlapping or consecutive list elements. ``LoN/HiN`` are 64-bit ints, and
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index 97a55bc506c85..24dad3157debe 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -307,7 +307,6 @@ namespace llvm {
                                 bool AllowParens = false);
     bool parseOptionalCodeModel(CodeModel::Model &model);
     bool parseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
-    bool parseConstRange(std::pair<int64_t, int64_t> &Range);
     bool parseOptionalUWTableKind(UWTableKind &Kind);
     bool parseAllocKind(AllocFnKind &Kind);
     std::optional<MemoryEffects> parseMemoryAttr();
@@ -371,7 +370,7 @@ namespace llvm {
                                     std::vector<unsigned> &FwdRefAttrGrps,
                                     bool inAttrGrp, LocTy &BuiltinLoc);
     bool parseRangeAttr(AttrBuilder &B);
-    bool parseInitializedAttr(AttrBuilder &B);
+    bool parseInitializesAttr(AttrBuilder &B);
     bool parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
                                Attribute::AttrKind AttrKind);
 
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index b2f38716b86f0..b925fe68072d2 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -725,7 +725,7 @@ enum AttributeKindCodes {
   ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
   ATTR_KIND_DEAD_ON_UNWIND = 91,
   ATTR_KIND_RANGE = 92,
-  ATTR_KIND_INITIALIZED = 93,
+  ATTR_KIND_INITIALIZES = 93,
 };
 
 enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index f39e59bc24b89..cb579746aa526 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -281,8 +281,8 @@ class Attribute {
   /// Returns the value of the range attribute.
   ConstantRange getRange() const;
 
-  /// Returns the value of the initialized attribute.
-  ConstantRangeList getInitialized() const;
+  /// Returns the value of the initializes attribute.
+  ConstantRangeList getInitializes() const;
 
   /// The Attribute is converted to a string of equivalent mnemonic. This
   /// is, presumably, for writing out the mnemonics for the assembly writer.
@@ -1233,8 +1233,8 @@ class AttrBuilder {
   AttrBuilder &addConstantRangeListAttr(Attribute::AttrKind Kind,
                                         const ConstantRangeList &CRL);
 
-  /// Add initialized attribute.
-  AttrBuilder &addInitializedAttr(const ConstantRangeList &CRL);
+  /// Add initializes attribute.
+  AttrBuilder &addInitializesAttr(const ConstantRangeList &CRL);
 
   ArrayRef<Attribute> attrs() const { return Attrs; }
 
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 911373020f954..f35ea40b5e94c 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -116,7 +116,7 @@ def FnRetThunkExtern : EnumAttr<"fn_ret_thunk_extern", [FnAttr]>;
 def InAlloca : TypeAttr<"inalloca", [ParamAttr]>;
 
 /// Pointer argument memory is initialized.
-def Initialized : ConstantRangeListAttr<"initialized", [ParamAttr]>;
+def Initializes : ConstantRangeListAttr<"initializes", [ParamAttr]>;
 
 /// Source said inlining was desirable.
 def InlineHint : EnumAttr<"inlinehint", [FnAttr]>;
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index a834fbe203ff1..28af496809578 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -1599,8 +1599,8 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
   }
   case Attribute::Range:
     return parseRangeAttr(B);
-  case Attribute::Initialized:
-    return parseInitializedAttr(B);
+  case Attribute::Initializes:
+    return parseInitializesAttr(B);
   default:
     B.addAttribute(Attr);
     Lex.Lex();
@@ -3054,9 +3054,9 @@ bool LLParser::parseRangeAttr(AttrBuilder &B) {
   return false;
 }
 
-/// parseInitializedAttr
-///   ::= initialized((Lo1,Hi1),(Lo2,Hi2),...)
-bool LLParser::parseInitializedAttr(AttrBuilder &B) {
+/// parseInitializesAttr
+///   ::= initializes((Lo1,Hi1),(Lo2,Hi2),...)
+bool LLParser::parseInitializesAttr(AttrBuilder &B) {
   Lex.Lex();
 
   auto ParseAPSInt = [&](APInt &Val) {
@@ -3093,7 +3093,7 @@ bool LLParser::parseInitializedAttr(AttrBuilder &B) {
   if (parseToken(lltok::rparen, "expected ')'"))
     return true;
 
-  B.addInitializedAttr(CRL);
+  B.addInitializesAttr(CRL);
   return false;
 }
 
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index b67bccdd2582e..41bfb92ac211a 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2130,8 +2130,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
     return Attribute::DeadOnUnwind;
   case bitc::ATTR_KIND_RANGE:
     return Attribute::Range;
-  case bitc::ATTR_KIND_INITIALIZED:
-    return Attribute::Initialized;
+  case bitc::ATTR_KIND_INITIALIZES:
+    return Attribute::Initializes;
   }
 }
 
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index cae78d5f0fd79..3b428d088282e 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -847,8 +847,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
     return bitc::ATTR_KIND_DEAD_ON_UNWIND;
   case Attribute::Range:
     return bitc::ATTR_KIND_RANGE;
-  case Attribute::Initialized:
-    return bitc::ATTR_KIND_INITIALIZED;
+  case Attribute::Initializes:
+    return bitc::ATTR_KIND_INITIALIZES;
   case Attribute::EndAttrKinds:
     llvm_unreachable("Can not encode end-attribute kinds marker.");
   case Attribute::None:
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 5f0283ba76d21..5729116897593 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -489,9 +489,9 @@ ConstantRange Attribute::getRange() const {
   return pImpl->getValueAsConstantRange();
 }
 
-ConstantRangeList Attribute::getInitialized() const {
-  assert(hasAttribute(Attribute::Initialized) &&
-         "Trying to get initialized attr from non-ConstantRangeList attribute");
+ConstantRangeList Attribute::getInitializes() const {
+  assert(hasAttribute(Attribute::Initializes) &&
+         "Trying to get initializes attr from non-ConstantRangeList attribute");
   return pImpl->getValueAsConstantRangeList();
 }
 
@@ -661,11 +661,11 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     return Result;
   }
 
-  if (hasAttribute(Attribute::Initialized)) {
+  if (hasAttribute(Attribute::Initializes)) {
     std::string Result;
     raw_string_ostream OS(Result);
     ConstantRangeList CRL = getValueAsConstantRangeList();
-    OS << "initialized(";
+    OS << "initializes(";
     size_t i = 0;
     for (auto &CR : CRL) {
       OS << "(" << CR.getLower() << "," << CR.getUpper() << ")";
@@ -2028,8 +2028,8 @@ AttrBuilder::addConstantRangeListAttr(Attribute::AttrKind Kind,
   return addAttribute(Attribute::get(Ctx, Kind, CRL));
 }
 
-AttrBuilder &AttrBuilder::addInitializedAttr(const ConstantRangeList &CRL) {
-  return addConstantRangeListAttr(Attribute::Initialized, CRL);
+AttrBuilder &AttrBuilder::addInitializesAttr(const ConstantRangeList &CRL) {
+  return addConstantRangeListAttr(Attribute::Initializes, CRL);
 }
 
 AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
@@ -2121,7 +2121,7 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
           .addAttribute(Attribute::DereferenceableOrNull)
           .addAttribute(Attribute::Writable)
           .addAttribute(Attribute::DeadOnUnwind)
-          .addAttribute(Attribute::Initialized);
+          .addAttribute(Attribute::Initializes);
     if (ASK & ASK_UNSAFE_TO_DROP)
       Incompatible.addAttribute(Attribute::Nest)
           .addAttribute(Attribute::SwiftError)
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index fcdbc2d910865..8af30fb8d6ff7 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2033,27 +2033,27 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
     }
   }
 
-  if (Attrs.hasAttribute(Attribute::Initialized)) {
-    auto Inits = Attrs.getAttribute(Attribute::Initialized)
+  if (Attrs.hasAttribute(Attribute::Initializes)) {
+    auto Inits = Attrs.getAttribute(Attribute::Initializes)
                      .getValueAsConstantRangeList();
     Check(!Inits.isEmptySet(),
-          "Attribute 'initialized' does not support empty list", V);
+          "Attribute 'initializes' does not support empty list", V);
     Check(!Inits.isFullSet(),
-          "Attribute 'initialized' does not support full list", V);
+          "Attribute 'initializes' does not support full list", V);
 
     Check(Inits.getRange(0).getLower().slt(Inits.getRange(0).getUpper()),
-          "Attribute 'initialized' requires interval lower less than upper", V);
+          "Attribute 'initializes' requires interval lower less than upper", V);
     for (size_t i = 1; i < Inits.size(); i++) {
       auto Previous = Inits.getRange(i - 1);
       auto Current = Inits.getRange(i);
       Check(Current.getLower().slt(Current.getUpper()),
-            "Attribute 'initialized' requires interval lower less than upper",
+            "Attribute 'initializes' requires interval lower less than upper",
             V);
       Check(Current.getLower().sge(Previous.getLower()),
-            "Attribute 'initialized' requires intervals in ascending order!",
+            "Attribute 'initializes' requires intervals in ascending order!",
             V);
       Check(Current.getLower().sge(Previous.getUpper()),
-            "Attribute 'initialized' requires intervals merged!", V);
+            "Attribute 'initializes' requires intervals merged!", V);
     }
   }
 
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 6928553f0bdd3..098c67eea1c36 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -1000,7 +1000,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
       case Attribute::Writable:
       case Attribute::DeadOnUnwind:
       case Attribute::Range:
-      case Attribute::Initialized:
+      case Attribute::Initializes:
       //  These are not really attributes.
       case Attribute::None:
       case Attribute::EndAttrKinds:
diff --git a/llvm/unittests/IR/ConstantRangeListTest.cpp b/llvm/unittests/IR/ConstantRangeListTest.cpp
index db262a508a84a..6e2506ec4b1f9 100644
--- a/llvm/unittests/IR/ConstantRangeListTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeListTest.cpp
@@ -14,16 +14,6 @@ using namespace llvm;
 namespace {
 
 class ConstantRangeListTest : public ::testing::Test {
-public:
-  ConstantRangeList
-  GetCRL(SmallVectorImpl<std::pair<int64_t, int64_t>> &Ranges) {
-    ConstantRangeList Result(64, false);
-    for (const auto &[Start, End] : Ranges) {
-      Result.append(Start, End);
-    }
-    return Result;
-  }
-
 protected:
   static ConstantRangeList Full;
   static ConstantRangeList Empty;
@@ -39,13 +29,21 @@ TEST_F(ConstantRangeListTest, Basics) {
   EXPECT_FALSE(Empty.isFullSet());
   EXPECT_TRUE(Empty.isEmptySet());
 
-  ConstantRangeList Some1 = GetCRL({(0, 4), (8, 12)});
-  EXPECT_FALSE(Some1.isFullSet());
-  EXPECT_FALSE(Some1.isEmptySet());
-
-  ConstantRangeList Some2 = GetCRL({(0, 4), (8, 12)});
-  ConstantRangeList Some3 = GetCRL({(-4, 0), (8, 12)});
-  EXPECT_TRUE(Some1 == Some2 && Some1 != Some3);
+  ConstantRangeList CRL1(64, false);
+  CRL1.append(0, 4);
+  CRL1.append(8, 12);
+  EXPECT_FALSE(CRL1.isFullSet());
+  EXPECT_FALSE(CRL1.isEmptySet());
+
+  ConstantRangeList CRL2(64, false);
+  CRL2.append(0, 4);
+  CRL2.append(8, 12);
+  EXPECT_TRUE(CRL1 == CRL2);
+
+  ConstantRangeList CRL3(64, false);
+  CRL3.append(-4, 0);
+  CRL3.append(8, 12);
+  EXPECT_TRUE(CRL1 != CRL3);
 }
 
 } // anonymous namespace

>From 6a1df7a305e36c8c5ea99bc49e3fb2100ded8279 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Tue, 9 Apr 2024 17:56:23 +0000
Subject: [PATCH 09/31] Update CRL about accessing the range of an
 EmptySet/FullSet

---
 llvm/include/llvm/IR/ConstantRangeList.h | 20 +++++++++++++++-----
 llvm/lib/IR/Verifier.cpp                 |  4 ++--
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index f83c73d34afdd..c64bf0dd66434 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -14,6 +14,9 @@
 // {[0, 0)}     = Empty set
 // {[255, 255)} = Full Set
 //
+// For EmptySet or FullSet, the list size is 1 but it's not allowed to access
+// the range.
+//
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_IR_CONSTANTRANGELIST_H
@@ -40,16 +43,21 @@ class [[nodiscard]] ConstantRangeList {
 
   ConstantRangeList(int64_t Lower, int64_t Upper);
 
-  SmallVectorImpl<ConstantRange>::iterator begin() { return Ranges.begin(); }
+  /// It's not allowed to access EmptySet's or FullSet's range.
+  SmallVectorImpl<ConstantRange>::iterator begin() {
+    assert(!isEmptySet() && !isFullSet());
+    return Ranges.begin();
+  }
   SmallVectorImpl<ConstantRange>::iterator end() { return Ranges.end(); }
   SmallVectorImpl<ConstantRange>::const_iterator begin() const {
+    assert(!isEmptySet() && !isFullSet());
     return Ranges.begin();
   }
   SmallVectorImpl<ConstantRange>::const_iterator end() const {
     return Ranges.end();
   }
   ConstantRange getRange(unsigned i) const {
-    assert(i < Ranges.size());
+    assert(!isEmptySet() && !isFullSet() && i < Ranges.size());
     return Ranges[i];
   }
 
@@ -65,10 +73,12 @@ class [[nodiscard]] ConstantRangeList {
   /// Get the bit width of this ConstantRangeList.
   uint32_t getBitWidth() const { return Ranges[0].getBitWidth(); }
 
+  /// For EmptySet or FullSet, the CRL size is 1 not 0.
   size_t size() const { return Ranges.size(); }
 
   void append(const ConstantRange &Range) {
     assert(Range.getLower().slt(Range.getUpper()));
+    assert(getBitWidth() == Range.getBitWidth());
     if (isFullSet())
       return;
     if (isEmptySet()) {
@@ -81,8 +91,8 @@ class [[nodiscard]] ConstantRangeList {
   }
 
   void append(int64_t Lower, int64_t Upper) {
-    append(ConstantRange(APInt(64, StringRef(std::to_string(Lower)), 10),
-                         APInt(64, StringRef(std::to_string(Upper)), 10)));
+    append(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
+                         APInt(64, Upper, /*isSigned=*/true)));
   }
 
   /// Return true if this range is equal to another range.
@@ -99,7 +109,7 @@ class [[nodiscard]] ConstantRangeList {
     return !operator==(CRL);
   }
 
-  /// Print out the bounds to a stream.
+  /// Print out the ranges to a stream.
   void print(raw_ostream &OS) const;
 };
 
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 8af30fb8d6ff7..a76a478a92866 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2049,10 +2049,10 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
       Check(Current.getLower().slt(Current.getUpper()),
             "Attribute 'initializes' requires interval lower less than upper",
             V);
-      Check(Current.getLower().sge(Previous.getLower()),
+      Check(Current.getLower().sgt(Previous.getLower()),
             "Attribute 'initializes' requires intervals in ascending order!",
             V);
-      Check(Current.getLower().sge(Previous.getUpper()),
+      Check(Current.getLower().sgt(Previous.getUpper()),
             "Attribute 'initializes' requires intervals merged!", V);
     }
   }

>From fe2e0a5302961248fe8c26ff07866e1639a22e2c Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Fri, 12 Apr 2024 04:45:34 +0000
Subject: [PATCH 10/31] Change CRL.insert to be ordered and no overlapping

---
 llvm/include/llvm/IR/ConstantRangeList.h    | 29 ++++-------
 llvm/lib/AsmParser/LLParser.cpp             |  2 +-
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp   |  3 +-
 llvm/lib/IR/ConstantRangeList.cpp           | 53 ++++++++++++++++++---
 llvm/unittests/IR/ConstantRangeListTest.cpp | 37 +++++++++++---
 5 files changed, 88 insertions(+), 36 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index c64bf0dd66434..7577aab5240bc 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -7,9 +7,9 @@
 //===----------------------------------------------------------------------===//
 //
 // Represent a list of signed ConstantRange and do NOT support wrap around the
-// end of the numeric range. Ranges in the list should have the same bitwidth.
-// Each range's lower should be less than its upper. Special lists (take 8-bit
-// as an example):
+// end of the numeric range. Ranges in the list are ordered and no overlapping.
+// Ranges should have the same bitwidth. Each range's lower should be less than
+// its upper. Special lists (take 8-bit as an example):
 //
 // {[0, 0)}     = Empty set
 // {[255, 255)} = Full Set
@@ -34,8 +34,6 @@ class raw_ostream;
 /// This class represents a list of constant ranges.
 class [[nodiscard]] ConstantRangeList {
   SmallVector<ConstantRange, 2> Ranges;
-  // Whether the range list is sorted: [i].lower() < [i+1].lower()
-  bool Sorted = true;
 
 public:
   /// Initialize a full or empty set for the specified bit width.
@@ -76,22 +74,11 @@ class [[nodiscard]] ConstantRangeList {
   /// For EmptySet or FullSet, the CRL size is 1 not 0.
   size_t size() const { return Ranges.size(); }
 
-  void append(const ConstantRange &Range) {
-    assert(Range.getLower().slt(Range.getUpper()));
-    assert(getBitWidth() == Range.getBitWidth());
-    if (isFullSet())
-      return;
-    if (isEmptySet()) {
-      Ranges[0] = Range;
-      return;
-    }
-    if (Range.getLower().slt(Ranges[size() - 1].getLower()))
-      Sorted = false;
-    Ranges.push_back(Range);
-  }
-
-  void append(int64_t Lower, int64_t Upper) {
-    append(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
+  /// Insert a range to Ranges. Keep the list ordered
+  /// and no overlapping (merge ranges if needed).
+  void insert(const ConstantRange &Range);
+  void insert(int64_t Lower, int64_t Upper) {
+    insert(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
                          APInt(64, Upper, /*isSigned=*/true)));
   }
 
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 28af496809578..090bba46cf1e3 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3087,7 +3087,7 @@ bool LLParser::parseInitializesAttr(AttrBuilder &B) {
     if (parseToken(lltok::rparen, "expected ')'"))
       return true;
 
-    CRL.append(ConstantRange(Lower, Upper));
+    CRL.insert(ConstantRange(Lower, Upper));
   } while (EatIfPresent(lltok::comma));
 
   if (parseToken(lltok::rparen, "expected ')'"))
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 41bfb92ac211a..6046d68652781 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2325,10 +2325,11 @@ Error BitcodeReader::parseAttributeGroupBlock() {
 
           ConstantRangeList CRL(64, false);
           int RangeSize = Record[++i];
+          assert(i + RangeSize < e);
           for (int Idx = 0; Idx < RangeSize; ++Idx) {
             int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
             int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
-            CRL.append(Start, End);
+            CRL.insert(Start, End);
           }
           B.addConstantRangeListAttr(Kind, CRL);
         } else {
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 96304ade997d3..845bad082bc3d 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -7,13 +7,16 @@
 //===----------------------------------------------------------------------===//
 //
 // Represent a list of signed ConstantRange and do NOT support wrap around the
-// end of the numeric range. Ranges in the list should have the same bitwidth.
-// Each range's lower should be less than its upper. Special lists (take 8-bit
-// as an example):
+// end of the numeric range. Ranges in the list are ordered and no overlapping.
+// Ranges should have the same bitwidth. Each range's lower should be less than
+// its upper. Special lists (take 8-bit as an example):
 //
 // {[0, 0)}     = Empty set
 // {[255, 255)} = Full Set
 //
+// For EmptySet or FullSet, the list size is 1 but it's not allowed to access
+// the range.
+//
 //===----------------------------------------------------------------------===//
 
 #include "llvm/IR/ConstantRangeList.h"
@@ -27,10 +30,46 @@ ConstantRangeList::ConstantRangeList(uint32_t BitWidth, bool Full) {
   Ranges.push_back(ConstantRange(Lower, Lower));
 }
 
-ConstantRangeList::ConstantRangeList(int64_t Lower, int64_t Upper) {
-  Ranges.push_back(
-      ConstantRange(APInt(64, StringRef(std::to_string(Lower)), 10),
-                    APInt(64, StringRef(std::to_string(Upper)), 10)));
+void ConstantRangeList::insert(const ConstantRange &Range) {
+  assert(Range.getLower().slt(Range.getUpper()));
+  assert(getBitWidth() == Range.getBitWidth());
+  if (isFullSet())
+    return;
+  if (isEmptySet()) {
+    Ranges[0] = Range;
+    return;
+  }
+
+  ConstantRange RangeToInsert = Range;
+  SmallVector<ConstantRange, 2> ExistingRanges(Ranges.begin(), Ranges.end());
+  Ranges.clear();
+  for (size_t i = 0; i < ExistingRanges.size(); i++) {
+    const ConstantRange &CurRange = ExistingRanges[i];
+    if (CurRange.getUpper().slt(RangeToInsert.getLower())) {
+      // Case1: No overlap and CurRange is before ToInsert.
+      // |--CurRange--|
+      //                 |--ToInsert--|
+      Ranges.push_back(CurRange);
+      continue;
+    } else if (RangeToInsert.getUpper().slt(CurRange.getLower())) {
+      // Case2: No overlap and CurRange is after ToInsert.
+      //                                 |--CurRange--|
+      //                 |--ToInsert--|
+      // insert the range.
+      Ranges.push_back(RangeToInsert);
+      for (size_t j = i; j < ExistingRanges.size(); j++)
+        Ranges.push_back(ExistingRanges[j]);
+      return;
+    } else {
+      // Case3: Overlap.
+      APInt NewLower =
+          APIntOps::smin(CurRange.getLower(), RangeToInsert.getLower());
+      APInt NewUpper =
+          APIntOps::smax(CurRange.getUpper(), RangeToInsert.getUpper());
+      RangeToInsert = ConstantRange(NewLower, NewUpper);
+    }
+  }
+  Ranges.push_back(RangeToInsert);
 }
 
 void ConstantRangeList::print(raw_ostream &OS) const {
diff --git a/llvm/unittests/IR/ConstantRangeListTest.cpp b/llvm/unittests/IR/ConstantRangeListTest.cpp
index 6e2506ec4b1f9..10c9a791b7bb7 100644
--- a/llvm/unittests/IR/ConstantRangeListTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeListTest.cpp
@@ -30,20 +30,45 @@ TEST_F(ConstantRangeListTest, Basics) {
   EXPECT_TRUE(Empty.isEmptySet());
 
   ConstantRangeList CRL1(64, false);
-  CRL1.append(0, 4);
-  CRL1.append(8, 12);
+  CRL1.insert(0, 4);
+  CRL1.insert(8, 12);
   EXPECT_FALSE(CRL1.isFullSet());
   EXPECT_FALSE(CRL1.isEmptySet());
 
   ConstantRangeList CRL2(64, false);
-  CRL2.append(0, 4);
-  CRL2.append(8, 12);
+  CRL2.insert(0, 4);
+  CRL2.insert(8, 12);
   EXPECT_TRUE(CRL1 == CRL2);
 
   ConstantRangeList CRL3(64, false);
-  CRL3.append(-4, 0);
-  CRL3.append(8, 12);
+  CRL3.insert(-4, 0);
+  CRL3.insert(8, 12);
   EXPECT_TRUE(CRL1 != CRL3);
 }
 
+TEST_F(ConstantRangeListTest, Insert) {
+  ConstantRangeList CRL(64, false);
+  CRL.insert(0, 4);
+  CRL.insert(8, 12);
+  // No overlap, left
+  CRL.insert(-8, -4);
+  // No overlap, right
+  CRL.insert(16, 20);
+  // No overlap, middle
+  CRL.insert(13, 15);
+  // Overlap with left
+  CRL.insert(-6, -2);
+  // Overlap with right
+  CRL.insert(5, 9);
+  // Overlap with left and right
+  CRL.insert(14, 18);
+  // Overlap cross ranges
+  CRL.insert(2, 14);
+
+  ConstantRangeList Expected(64, false);
+  Expected.insert(-8, -2);
+  Expected.insert(0, 20);
+  EXPECT_TRUE(CRL == Expected);
+}
+
 } // anonymous namespace

>From f73df045295136b3fe64bc0193a738b9a9721ee4 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Tue, 16 Apr 2024 22:46:24 +0000
Subject: [PATCH 11/31] Optimize CRL::insert for common cases

---
 llvm/include/llvm/IR/ConstantRangeList.h  |  2 +-
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |  2 +-
 llvm/lib/IR/ConstantRangeList.cpp         | 65 +++++++++++++----------
 3 files changed, 38 insertions(+), 31 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index 7577aab5240bc..d778ab4a2c09b 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -76,7 +76,7 @@ class [[nodiscard]] ConstantRangeList {
 
   /// Insert a range to Ranges. Keep the list ordered
   /// and no overlapping (merge ranges if needed).
-  void insert(const ConstantRange &Range);
+  void insert(const ConstantRange &NewRange);
   void insert(int64_t Lower, int64_t Upper) {
     insert(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
                          APInt(64, Upper, /*isSigned=*/true)));
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 6046d68652781..ffb0122a3803f 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2325,7 +2325,7 @@ Error BitcodeReader::parseAttributeGroupBlock() {
 
           ConstantRangeList CRL(64, false);
           int RangeSize = Record[++i];
-          assert(i + RangeSize < e);
+          assert(i + 2 * RangeSize < e);
           for (int Idx = 0; Idx < RangeSize; ++Idx) {
             int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
             int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 845bad082bc3d..07b1661db0e30 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -30,46 +30,53 @@ ConstantRangeList::ConstantRangeList(uint32_t BitWidth, bool Full) {
   Ranges.push_back(ConstantRange(Lower, Lower));
 }
 
-void ConstantRangeList::insert(const ConstantRange &Range) {
-  assert(Range.getLower().slt(Range.getUpper()));
-  assert(getBitWidth() == Range.getBitWidth());
+void ConstantRangeList::insert(const ConstantRange &NewRange) {
+  assert(NewRange.getLower().slt(NewRange.getUpper()));
+  assert(getBitWidth() == NewRange.getBitWidth());
+  // Handle common cases.
   if (isFullSet())
     return;
   if (isEmptySet()) {
-    Ranges[0] = Range;
+    Ranges[0] = NewRange;
+    return;
+  }
+  if (Ranges.back().getUpper().slt(NewRange.getLower())) {
+    Ranges.push_back(NewRange);
+    return;
+  }
+  if (NewRange.getUpper().slt(Ranges.front().getLower())) {
+    Ranges.insert(Ranges.begin(), NewRange);
     return;
   }
 
-  ConstantRange RangeToInsert = Range;
+  // Slow insert.
   SmallVector<ConstantRange, 2> ExistingRanges(Ranges.begin(), Ranges.end());
-  Ranges.clear();
-  for (size_t i = 0; i < ExistingRanges.size(); i++) {
-    const ConstantRange &CurRange = ExistingRanges[i];
-    if (CurRange.getUpper().slt(RangeToInsert.getLower())) {
-      // Case1: No overlap and CurRange is before ToInsert.
-      // |--CurRange--|
-      //                 |--ToInsert--|
-      Ranges.push_back(CurRange);
-      continue;
-    } else if (RangeToInsert.getUpper().slt(CurRange.getLower())) {
-      // Case2: No overlap and CurRange is after ToInsert.
-      //                                 |--CurRange--|
-      //                 |--ToInsert--|
-      // insert the range.
-      Ranges.push_back(RangeToInsert);
-      for (size_t j = i; j < ExistingRanges.size(); j++)
-        Ranges.push_back(ExistingRanges[j]);
-      return;
+  auto LowerBound =
+      std::lower_bound(ExistingRanges.begin(), ExistingRanges.end(), NewRange,
+                       [](const ConstantRange &a, const ConstantRange &b) {
+                         return a.getLower().slt(b.getLower());
+                       });
+  Ranges.erase(Ranges.begin() + (LowerBound - ExistingRanges.begin()),
+               Ranges.end());
+  if (!Ranges.empty() && NewRange.getLower().slt(Ranges.back().getUpper())) {
+    APInt NewLower = Ranges.back().getLower();
+    APInt NewUpper =
+        APIntOps::smax(NewRange.getUpper(), Ranges.back().getUpper());
+    Ranges.back() = ConstantRange(NewLower, NewUpper);
+  } else {
+    Ranges.push_back(NewRange);
+  }
+  for (auto Iter = LowerBound; Iter != ExistingRanges.end(); Iter++) {
+    if (Ranges.back().getUpper().slt(Iter->getLower())) {
+      Ranges.push_back(*Iter);
     } else {
-      // Case3: Overlap.
-      APInt NewLower =
-          APIntOps::smin(CurRange.getLower(), RangeToInsert.getLower());
+      APInt NewLower = Ranges.back().getLower();
       APInt NewUpper =
-          APIntOps::smax(CurRange.getUpper(), RangeToInsert.getUpper());
-      RangeToInsert = ConstantRange(NewLower, NewUpper);
+          APIntOps::smax(Iter->getUpper(), Ranges.back().getUpper());
+      Ranges.back() = ConstantRange(NewLower, NewUpper);
     }
   }
-  Ranges.push_back(RangeToInsert);
+  return;
 }
 
 void ConstantRangeList::print(raw_ostream &OS) const {

>From 63c45f681a1d2c0c02cf2d14c71d239d2e12a967 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Tue, 16 Apr 2024 23:58:56 +0000
Subject: [PATCH 12/31] Update ConstantRangeList

---
 llvm/include/llvm/IR/ConstantRangeList.h    | 49 +++++----------------
 llvm/lib/AsmParser/LLParser.cpp             |  2 +-
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp   |  2 +-
 llvm/lib/IR/Attributes.cpp                  |  8 +---
 llvm/lib/IR/ConstantRangeList.cpp           | 34 +++-----------
 llvm/lib/IR/Verifier.cpp                    |  6 +--
 llvm/unittests/IR/ConstantRangeListTest.cpp | 28 +++---------
 7 files changed, 30 insertions(+), 99 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index d778ab4a2c09b..cf473d1da8298 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -9,13 +9,7 @@
 // Represent a list of signed ConstantRange and do NOT support wrap around the
 // end of the numeric range. Ranges in the list are ordered and no overlapping.
 // Ranges should have the same bitwidth. Each range's lower should be less than
-// its upper. Special lists (take 8-bit as an example):
-//
-// {[0, 0)}     = Empty set
-// {[255, 255)} = Full Set
-//
-// For EmptySet or FullSet, the list size is 1 but it's not allowed to access
-// the range.
+// its upper.
 //
 //===----------------------------------------------------------------------===//
 
@@ -36,61 +30,38 @@ class [[nodiscard]] ConstantRangeList {
   SmallVector<ConstantRange, 2> Ranges;
 
 public:
-  /// Initialize a full or empty set for the specified bit width.
-  explicit ConstantRangeList(uint32_t BitWidth, bool isFullSet);
-
-  ConstantRangeList(int64_t Lower, int64_t Upper);
-
-  /// It's not allowed to access EmptySet's or FullSet's range.
-  SmallVectorImpl<ConstantRange>::iterator begin() {
-    assert(!isEmptySet() && !isFullSet());
-    return Ranges.begin();
-  }
+  SmallVectorImpl<ConstantRange>::iterator begin() { return Ranges.begin(); }
   SmallVectorImpl<ConstantRange>::iterator end() { return Ranges.end(); }
   SmallVectorImpl<ConstantRange>::const_iterator begin() const {
-    assert(!isEmptySet() && !isFullSet());
     return Ranges.begin();
   }
   SmallVectorImpl<ConstantRange>::const_iterator end() const {
     return Ranges.end();
   }
   ConstantRange getRange(unsigned i) const {
-    assert(!isEmptySet() && !isFullSet() && i < Ranges.size());
+    assert(i < Ranges.size());
     return Ranges[i];
   }
 
-  /// Return true if this set contains no members.
-  bool isEmptySet() const {
-    return Ranges.size() == 1 && Ranges[0].isEmptySet();
-  }
-
-  /// Return true if this set contains all of the elements possible
-  /// for this data-type.
-  bool isFullSet() const { return Ranges.size() == 1 && Ranges[0].isFullSet(); }
+  /// Return true if this list contains no members.
+  bool empty() const { return Ranges.empty(); }
 
   /// Get the bit width of this ConstantRangeList.
-  uint32_t getBitWidth() const { return Ranges[0].getBitWidth(); }
+  uint32_t getBitWidth() const { return 64; }
 
-  /// For EmptySet or FullSet, the CRL size is 1 not 0.
+  /// Return the size of this ConstantRangeList.
   size_t size() const { return Ranges.size(); }
 
-  /// Insert a range to Ranges. Keep the list ordered
-  /// and no overlapping (merge ranges if needed).
+  /// Insert a new range to Ranges.
   void insert(const ConstantRange &NewRange);
   void insert(int64_t Lower, int64_t Upper) {
     insert(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
                          APInt(64, Upper, /*isSigned=*/true)));
   }
 
-  /// Return true if this range is equal to another range.
+  /// Return true if this range list is equal to another range list.
   bool operator==(const ConstantRangeList &CRL) const {
-    if (size() != CRL.size())
-      return false;
-    for (size_t i = 0; i < size(); ++i) {
-      if (Ranges[i] != CRL.Ranges[i])
-        return false;
-    }
-    return true;
+    return Ranges == CRL.Ranges;
   }
   bool operator!=(const ConstantRangeList &CRL) const {
     return !operator==(CRL);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 090bba46cf1e3..030fee0b65b3a 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3070,7 +3070,7 @@ bool LLParser::parseInitializesAttr(AttrBuilder &B) {
   if (parseToken(lltok::lparen, "expected '('"))
     return true;
 
-  ConstantRangeList CRL(64, false);
+  ConstantRangeList CRL;
   // Parse each constant range.
   do {
     APInt Lower, Upper;
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index ffb0122a3803f..bcad43bdd30bf 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2323,7 +2323,7 @@ Error BitcodeReader::parseAttributeGroupBlock() {
           if (!Attribute::isConstantRangeListAttrKind(Kind))
             return error("Not a constant range list attribute");
 
-          ConstantRangeList CRL(64, false);
+          ConstantRangeList CRL;
           int RangeSize = Record[++i];
           assert(i + 2 * RangeSize < e);
           for (int Idx = 0; Idx < RangeSize; ++Idx) {
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 5729116897593..cc809f8b90473 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -666,13 +666,9 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     raw_string_ostream OS(Result);
     ConstantRangeList CRL = getValueAsConstantRangeList();
     OS << "initializes(";
-    size_t i = 0;
-    for (auto &CR : CRL) {
+    interleaveComma(CRL, OS, [&](ConstantRange CR) {
       OS << "(" << CR.getLower() << "," << CR.getUpper() << ")";
-      if (i != CRL.size() - 1)
-        OS << ",";
-      i++;
-    }
+    });
     OS << ")";
     OS.flush();
     return Result;
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 07b1661db0e30..51e56fdb24d4f 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -9,13 +9,7 @@
 // Represent a list of signed ConstantRange and do NOT support wrap around the
 // end of the numeric range. Ranges in the list are ordered and no overlapping.
 // Ranges should have the same bitwidth. Each range's lower should be less than
-// its upper. Special lists (take 8-bit as an example):
-//
-// {[0, 0)}     = Empty set
-// {[255, 255)} = Full Set
-//
-// For EmptySet or FullSet, the list size is 1 but it's not allowed to access
-// the range.
+// its upper.
 //
 //===----------------------------------------------------------------------===//
 
@@ -24,23 +18,14 @@
 
 using namespace llvm;
 
-ConstantRangeList::ConstantRangeList(uint32_t BitWidth, bool Full) {
-  APInt Lower =
-      Full ? APInt::getMaxValue(BitWidth) : APInt::getMinValue(BitWidth);
-  Ranges.push_back(ConstantRange(Lower, Lower));
-}
-
 void ConstantRangeList::insert(const ConstantRange &NewRange) {
+  if (NewRange.isEmptySet())
+    return;
+  assert(!NewRange.isFullSet() && "Do not support full set");
   assert(NewRange.getLower().slt(NewRange.getUpper()));
   assert(getBitWidth() == NewRange.getBitWidth());
   // Handle common cases.
-  if (isFullSet())
-    return;
-  if (isEmptySet()) {
-    Ranges[0] = NewRange;
-    return;
-  }
-  if (Ranges.back().getUpper().slt(NewRange.getLower())) {
+  if (empty() || Ranges.back().getUpper().slt(NewRange.getLower())) {
     Ranges.push_back(NewRange);
     return;
   }
@@ -80,11 +65,6 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
 }
 
 void ConstantRangeList::print(raw_ostream &OS) const {
-  if (isFullSet())
-    OS << "full-set";
-  else if (isEmptySet())
-    OS << "empty-set";
-  else
-    for (const auto &Range : Ranges)
-      Range.print(OS);
+  for (const auto &Range : Ranges)
+    Range.print(OS);
 }
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index a76a478a92866..9082dc7878811 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2036,10 +2036,8 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
   if (Attrs.hasAttribute(Attribute::Initializes)) {
     auto Inits = Attrs.getAttribute(Attribute::Initializes)
                      .getValueAsConstantRangeList();
-    Check(!Inits.isEmptySet(),
-          "Attribute 'initializes' does not support empty list", V);
-    Check(!Inits.isFullSet(),
-          "Attribute 'initializes' does not support full list", V);
+    Check(!Inits.empty(), "Attribute 'initializes' does not support empty list",
+          V);
 
     Check(Inits.getRange(0).getLower().slt(Inits.getRange(0).getUpper()),
           "Attribute 'initializes' requires interval lower less than upper", V);
diff --git a/llvm/unittests/IR/ConstantRangeListTest.cpp b/llvm/unittests/IR/ConstantRangeListTest.cpp
index 10c9a791b7bb7..1b66de0f996d3 100644
--- a/llvm/unittests/IR/ConstantRangeListTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeListTest.cpp
@@ -13,41 +13,27 @@ using namespace llvm;
 
 namespace {
 
-class ConstantRangeListTest : public ::testing::Test {
-protected:
-  static ConstantRangeList Full;
-  static ConstantRangeList Empty;
-};
-
-ConstantRangeList ConstantRangeListTest::Full(64, true);
-ConstantRangeList ConstantRangeListTest::Empty(64, false);
+using ConstantRangeListTest = ::testing::Test;
 
 TEST_F(ConstantRangeListTest, Basics) {
-  EXPECT_TRUE(Full.isFullSet());
-  EXPECT_FALSE(Full.isEmptySet());
-
-  EXPECT_FALSE(Empty.isFullSet());
-  EXPECT_TRUE(Empty.isEmptySet());
-
-  ConstantRangeList CRL1(64, false);
+  ConstantRangeList CRL1;
   CRL1.insert(0, 4);
   CRL1.insert(8, 12);
-  EXPECT_FALSE(CRL1.isFullSet());
-  EXPECT_FALSE(CRL1.isEmptySet());
+  EXPECT_FALSE(CRL1.empty());
 
-  ConstantRangeList CRL2(64, false);
+  ConstantRangeList CRL2;
   CRL2.insert(0, 4);
   CRL2.insert(8, 12);
   EXPECT_TRUE(CRL1 == CRL2);
 
-  ConstantRangeList CRL3(64, false);
+  ConstantRangeList CRL3;
   CRL3.insert(-4, 0);
   CRL3.insert(8, 12);
   EXPECT_TRUE(CRL1 != CRL3);
 }
 
 TEST_F(ConstantRangeListTest, Insert) {
-  ConstantRangeList CRL(64, false);
+  ConstantRangeList CRL;
   CRL.insert(0, 4);
   CRL.insert(8, 12);
   // No overlap, left
@@ -65,7 +51,7 @@ TEST_F(ConstantRangeListTest, Insert) {
   // Overlap cross ranges
   CRL.insert(2, 14);
 
-  ConstantRangeList Expected(64, false);
+  ConstantRangeList Expected;
   Expected.insert(-8, -2);
   Expected.insert(0, 20);
   EXPECT_TRUE(CRL == Expected);

>From dcc2b387763a062083049f97bf6f9993120a088e Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Wed, 17 Apr 2024 04:16:11 +0000
Subject: [PATCH 13/31] Add unit tests for BitcodeReader/Verifier/Assembler

---
 llvm/include/llvm/IR/ConstantRangeList.h      | 10 ++-
 llvm/lib/AsmParser/LLParser.cpp               |  4 +-
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp     |  2 +-
 llvm/lib/IR/Attributes.cpp                    |  9 ++-
 .../initializes-attribute-invalid.ll          | 71 +++++++++++++++++++
 llvm/test/Bitcode/attributes.ll               |  5 ++
 llvm/test/Verifier/initializes-attr.ll        | 31 ++++++++
 7 files changed, 125 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/Assembler/initializes-attribute-invalid.ll
 create mode 100644 llvm/test/Verifier/initializes-attr.ll

diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index cf473d1da8298..e1f3ee3b2726b 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -52,13 +52,21 @@ class [[nodiscard]] ConstantRangeList {
   /// Return the size of this ConstantRangeList.
   size_t size() const { return Ranges.size(); }
 
-  /// Insert a new range to Ranges.
+  /// Insert a new range to Ranges and keep the list ordered.
   void insert(const ConstantRange &NewRange);
   void insert(int64_t Lower, int64_t Upper) {
     insert(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
                          APInt(64, Upper, /*isSigned=*/true)));
   }
 
+  // Append a new Range to Ranges. Caller should make sure
+  // the list is still ordered after appending.
+  void append(const ConstantRange &Range) { Ranges.push_back(Range); }
+  void append(int64_t Lower, int64_t Upper) {
+    append(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
+                         APInt(64, Upper, /*isSigned=*/true)));
+  }
+
   /// Return true if this range list is equal to another range list.
   bool operator==(const ConstantRangeList &CRL) const {
     return Ranges == CRL.Ranges;
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 030fee0b65b3a..9656f8b14b18e 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3074,7 +3074,7 @@ bool LLParser::parseInitializesAttr(AttrBuilder &B) {
   // Parse each constant range.
   do {
     APInt Lower, Upper;
-    if (parseToken(lltok::lparen, "expected'('"))
+    if (parseToken(lltok::lparen, "expected '('"))
       return true;
 
     if (ParseAPSInt(Lower) || parseToken(lltok::comma, "expected ','") ||
@@ -3087,7 +3087,7 @@ bool LLParser::parseInitializesAttr(AttrBuilder &B) {
     if (parseToken(lltok::rparen, "expected ')'"))
       return true;
 
-    CRL.insert(ConstantRange(Lower, Upper));
+    CRL.append(ConstantRange(Lower, Upper));
   } while (EatIfPresent(lltok::comma));
 
   if (parseToken(lltok::rparen, "expected ')'"))
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index bcad43bdd30bf..7bcc3e211b8df 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2329,7 +2329,7 @@ Error BitcodeReader::parseAttributeGroupBlock() {
           for (int Idx = 0; Idx < RangeSize; ++Idx) {
             int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
             int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
-            CRL.insert(Start, End);
+            CRL.append(Start, End);
           }
           B.addConstantRangeListAttr(Kind, CRL);
         } else {
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index cc809f8b90473..f61c1b08df8f0 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -666,9 +666,12 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     raw_string_ostream OS(Result);
     ConstantRangeList CRL = getValueAsConstantRangeList();
     OS << "initializes(";
-    interleaveComma(CRL, OS, [&](ConstantRange CR) {
-      OS << "(" << CR.getLower() << "," << CR.getUpper() << ")";
-    });
+    interleave(
+        CRL, OS,
+        [&](ConstantRange CR) {
+          OS << "(" << CR.getLower() << "," << CR.getUpper() << ")";
+        },
+        ",");
     OS << ")";
     OS.flush();
     return Result;
diff --git a/llvm/test/Assembler/initializes-attribute-invalid.ll b/llvm/test/Assembler/initializes-attribute-invalid.ll
new file mode 100644
index 0000000000000..842d67b2fb5cc
--- /dev/null
+++ b/llvm/test/Assembler/initializes-attribute-invalid.ll
@@ -0,0 +1,71 @@
+; RUN: split-file %s %t
+; RUN: not llvm-as < %s %t/outer_left_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=OUTER-LEFT
+; RUN: not llvm-as < %s %t/inner_left_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=INNER-LEFT
+; RUN: not llvm-as < %s %t/inner_right_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=OUTER-RIGHT
+; RUN: not llvm-as < %s %t/outer_right_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=OUTER-RIGHT
+; RUN: not llvm-as < %s %t/integer.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=INTEGER
+; RUN: not llvm-as < %s %t/lower_equal_upper.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=LOWER-EQUAL-UPPER
+; RUN: not llvm-as < %s %t/inner_comma.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=INNER-COMMA
+; RUN: not llvm-as < %s %t/outer_comma.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=OUTER-COMMA
+; RUN: not llvm-as < %s %t/empty1.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=EMPTY1
+; RUN: not llvm-as < %s %t/empty2.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=EMPTY2
+
+;--- outer_left_parenthesis.ll
+; OUTER-LEFT: expected '('
+define void @foo(ptr initializes 0,4 %a) {
+  ret void
+}
+
+;--- inner_left_parenthesis.ll
+; INNER-LEFT: expected '('
+define void @foo(ptr initializes(0,4 %a) {
+  ret void
+}
+
+;--- inner_right_parenthesis.ll
+; INNER-RIGHT: expected ')'
+define void @foo(ptr initializes((0,4 %a) {
+  ret void
+}
+
+;--- outer_right_parenthesis.ll
+; OUTER-RIGHT: expected ')'
+define void @foo(ptr initializes((0,4) %a) {
+  ret void
+}
+
+;--- integer.ll
+; INTEGER: expected integer
+define void @foo(ptr initializes((0.5,4)) %a) {
+  ret void
+}
+
+;--- lower_equal_upper.ll
+; LOWER-EQUAL-UPPER: the range should not represent the full or empty set!
+define void @foo(ptr initializes((4,4)) %a) {
+  ret void
+}
+
+;--- inner_comma.ll
+; INNER-COMMA: expected ','
+define void @foo(ptr initializes((0 4)) %a) {
+  ret void
+}
+
+;--- outer_comma.ll
+; OUTER-COMMA: expected ')'
+define void @foo(ptr initializes((0,4) (8,12)) %a) {
+  ret void
+}
+
+;--- empty1.ll
+; EMPTY1: expected '('
+define void @foo(ptr initializes() %a) {
+  ret void
+}
+
+;--- empty2.ll
+; EMPTY2: expected integer
+define void @foo(ptr initializes(()) %a) {
+  ret void
+}
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index 26163b4d38c89..c81c5779a45b4 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -536,6 +536,11 @@ define void @wide_range_attribute(i128 range(i128 618970019642690137449562111, 6
   ret void
 }
 
+; CHECK: define void @initializes(ptr initializes((-4,0),(4,8)) %a)
+define void @initializes(ptr initializes((-4,0),(4,8)) %a) {
+  ret void
+}
+
 ; CHECK: attributes #0 = { noreturn }
 ; CHECK: attributes #1 = { nounwind }
 ; CHECK: attributes #2 = { memory(none) }
diff --git a/llvm/test/Verifier/initializes-attr.ll b/llvm/test/Verifier/initializes-attr.ll
new file mode 100644
index 0000000000000..5992da4dfde9e
--- /dev/null
+++ b/llvm/test/Verifier/initializes-attr.ll
@@ -0,0 +1,31 @@
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+; CHECK: Attribute 'initializes' requires interval lower less than upper
+; CHECK-NEXT: ptr @lower_greater_than_upper1
+define void @lower_greater_than_upper1(ptr initializes((4,0)) %a) {
+  ret void
+}
+
+; CHECK: Attribute 'initializes' requires interval lower less than upper
+; CHECK-NEXT: ptr @lower_greater_than_upper2
+define void @lower_greater_than_upper2(ptr initializes((0,4),(8,6)) %a) {
+  ret void
+}
+
+; CHECK: Attribute 'initializes' requires intervals in ascending order!
+; CHECK-NEXT: ptr @descending_order
+define void @descending_order(ptr initializes((8,12),(0,4)) %a) {
+  ret void
+}
+
+; CHECK: Attribute 'initializes' requires intervals merged!
+; CHECK-NEXT: ptr @overlapping1
+define void @overlapping1(ptr initializes((0,4),(4,8)) %a) {
+  ret void
+}
+
+; CHECK: Attribute 'initializes' requires intervals merged!
+; CHECK-NEXT: ptr @overlapping2
+define void @overlapping2(ptr initializes((0,4),(2,8)) %a) {
+  ret void
+}

>From 97233222a58ee71f3f64177867178eaf0d1932ba Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Wed, 17 Apr 2024 22:03:10 +0000
Subject: [PATCH 14/31] Add a space after commas

---
 llvm/docs/LangRef.rst                              |  2 +-
 llvm/lib/IR/Attributes.cpp                         |  9 +++------
 llvm/lib/IR/ConstantRangeList.cpp                  |  9 ++++-----
 .../Assembler/initializes-attribute-invalid.ll     | 14 +++++++-------
 llvm/test/Bitcode/attributes.ll                    |  4 ++--
 llvm/test/Verifier/initializes-attr.ll             | 10 +++++-----
 6 files changed, 22 insertions(+), 26 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 3f7cef4f6493e..8a0a5e0d234d6 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1621,7 +1621,7 @@ Currently, only the following parameter attributes are defined:
     ``readonly`` or a ``memory`` attribute that does not contain
     ``argmem: write``.
 
-``initializes((Lo1,Hi1),...)``
+``initializes((Lo1, Hi1), ...)``
     This attribute indicates that the function initializes the ranges of the
     pointer parameter's memory, ``[%p+LoN, %p+HiN)``. Initialization of memory
     means the first memory access is a non-volatile, non-atomic write. The
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index f61c1b08df8f0..f4d91bbbc8b2e 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -666,12 +666,9 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     raw_string_ostream OS(Result);
     ConstantRangeList CRL = getValueAsConstantRangeList();
     OS << "initializes(";
-    interleave(
-        CRL, OS,
-        [&](ConstantRange CR) {
-          OS << "(" << CR.getLower() << "," << CR.getUpper() << ")";
-        },
-        ",");
+    interleaveComma(CRL, OS, [&](ConstantRange CR) {
+      OS << "(" << CR.getLower() << ", " << CR.getUpper() << ")";
+    });
     OS << ")";
     OS.flush();
     return Result;
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 51e56fdb24d4f..ce600de02bdb4 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -35,14 +35,13 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
   }
 
   // Slow insert.
-  SmallVector<ConstantRange, 2> ExistingRanges(Ranges.begin(), Ranges.end());
   auto LowerBound =
-      std::lower_bound(ExistingRanges.begin(), ExistingRanges.end(), NewRange,
+      std::lower_bound(Ranges.begin(), Ranges.end(), NewRange,
                        [](const ConstantRange &a, const ConstantRange &b) {
                          return a.getLower().slt(b.getLower());
                        });
-  Ranges.erase(Ranges.begin() + (LowerBound - ExistingRanges.begin()),
-               Ranges.end());
+  SmallVector<ConstantRange, 2> ExistingTail(LowerBound, Ranges.end());
+  Ranges.erase(LowerBound, Ranges.end());
   if (!Ranges.empty() && NewRange.getLower().slt(Ranges.back().getUpper())) {
     APInt NewLower = Ranges.back().getLower();
     APInt NewUpper =
@@ -51,7 +50,7 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
   } else {
     Ranges.push_back(NewRange);
   }
-  for (auto Iter = LowerBound; Iter != ExistingRanges.end(); Iter++) {
+  for (auto Iter = ExistingTail.begin(); Iter != ExistingTail.end(); Iter++) {
     if (Ranges.back().getUpper().slt(Iter->getLower())) {
       Ranges.push_back(*Iter);
     } else {
diff --git a/llvm/test/Assembler/initializes-attribute-invalid.ll b/llvm/test/Assembler/initializes-attribute-invalid.ll
index 842d67b2fb5cc..4ba54ec56f67a 100644
--- a/llvm/test/Assembler/initializes-attribute-invalid.ll
+++ b/llvm/test/Assembler/initializes-attribute-invalid.ll
@@ -12,37 +12,37 @@
 
 ;--- outer_left_parenthesis.ll
 ; OUTER-LEFT: expected '('
-define void @foo(ptr initializes 0,4 %a) {
+define void @foo(ptr initializes 0, 4 %a) {
   ret void
 }
 
 ;--- inner_left_parenthesis.ll
 ; INNER-LEFT: expected '('
-define void @foo(ptr initializes(0,4 %a) {
+define void @foo(ptr initializes(0, 4 %a) {
   ret void
 }
 
 ;--- inner_right_parenthesis.ll
 ; INNER-RIGHT: expected ')'
-define void @foo(ptr initializes((0,4 %a) {
+define void @foo(ptr initializes((0, 4 %a) {
   ret void
 }
 
 ;--- outer_right_parenthesis.ll
 ; OUTER-RIGHT: expected ')'
-define void @foo(ptr initializes((0,4) %a) {
+define void @foo(ptr initializes((0, 4) %a) {
   ret void
 }
 
 ;--- integer.ll
 ; INTEGER: expected integer
-define void @foo(ptr initializes((0.5,4)) %a) {
+define void @foo(ptr initializes((0.5, 4)) %a) {
   ret void
 }
 
 ;--- lower_equal_upper.ll
 ; LOWER-EQUAL-UPPER: the range should not represent the full or empty set!
-define void @foo(ptr initializes((4,4)) %a) {
+define void @foo(ptr initializes((4, 4)) %a) {
   ret void
 }
 
@@ -54,7 +54,7 @@ define void @foo(ptr initializes((0 4)) %a) {
 
 ;--- outer_comma.ll
 ; OUTER-COMMA: expected ')'
-define void @foo(ptr initializes((0,4) (8,12)) %a) {
+define void @foo(ptr initializes((0, 4) (8, 12)) %a) {
   ret void
 }
 
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index c81c5779a45b4..006855b25564d 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -536,8 +536,8 @@ define void @wide_range_attribute(i128 range(i128 618970019642690137449562111, 6
   ret void
 }
 
-; CHECK: define void @initializes(ptr initializes((-4,0),(4,8)) %a)
-define void @initializes(ptr initializes((-4,0),(4,8)) %a) {
+; CHECK: define void @initializes(ptr initializes((-4, 0), (4, 8)) %a)
+define void @initializes(ptr initializes((-4, 0), (4, 8)) %a) {
   ret void
 }
 
diff --git a/llvm/test/Verifier/initializes-attr.ll b/llvm/test/Verifier/initializes-attr.ll
index 5992da4dfde9e..4c36493a2cbc4 100644
--- a/llvm/test/Verifier/initializes-attr.ll
+++ b/llvm/test/Verifier/initializes-attr.ll
@@ -2,30 +2,30 @@
 
 ; CHECK: Attribute 'initializes' requires interval lower less than upper
 ; CHECK-NEXT: ptr @lower_greater_than_upper1
-define void @lower_greater_than_upper1(ptr initializes((4,0)) %a) {
+define void @lower_greater_than_upper1(ptr initializes((4, 0)) %a) {
   ret void
 }
 
 ; CHECK: Attribute 'initializes' requires interval lower less than upper
 ; CHECK-NEXT: ptr @lower_greater_than_upper2
-define void @lower_greater_than_upper2(ptr initializes((0,4),(8,6)) %a) {
+define void @lower_greater_than_upper2(ptr initializes((0, 4), (8, 6)) %a) {
   ret void
 }
 
 ; CHECK: Attribute 'initializes' requires intervals in ascending order!
 ; CHECK-NEXT: ptr @descending_order
-define void @descending_order(ptr initializes((8,12),(0,4)) %a) {
+define void @descending_order(ptr initializes((8, 12), (0, 4)) %a) {
   ret void
 }
 
 ; CHECK: Attribute 'initializes' requires intervals merged!
 ; CHECK-NEXT: ptr @overlapping1
-define void @overlapping1(ptr initializes((0,4),(4,8)) %a) {
+define void @overlapping1(ptr initializes((0, 4), (4, 8)) %a) {
   ret void
 }
 
 ; CHECK: Attribute 'initializes' requires intervals merged!
 ; CHECK-NEXT: ptr @overlapping2
-define void @overlapping2(ptr initializes((0,4),(2,8)) %a) {
+define void @overlapping2(ptr initializes((0, 4), (2, 8)) %a) {
   ret void
 }

>From e70988d7f5d3272f53be0860e43ccd24738fbb95 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 18 Apr 2024 22:12:41 +0000
Subject: [PATCH 15/31] Update CRL and unit tests

---
 llvm/include/llvm/IR/ConstantRangeList.h             | 2 +-
 llvm/lib/IR/Attributes.cpp                           | 4 +---
 llvm/lib/IR/ConstantRangeList.cpp                    | 9 ++++++---
 llvm/test/Assembler/initializes-attribute-invalid.ll | 2 +-
 llvm/unittests/IR/ConstantRangeListTest.cpp          | 2 ++
 5 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index e1f3ee3b2726b..fc452e661c631 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -49,7 +49,7 @@ class [[nodiscard]] ConstantRangeList {
   /// Get the bit width of this ConstantRangeList.
   uint32_t getBitWidth() const { return 64; }
 
-  /// Return the size of this ConstantRangeList.
+  /// Return the number of ranges in this ConstantRangeList.
   size_t size() const { return Ranges.size(); }
 
   /// Insert a new range to Ranges and keep the list ordered.
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index f4d91bbbc8b2e..aaca563d93e2a 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -666,9 +666,7 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     raw_string_ostream OS(Result);
     ConstantRangeList CRL = getValueAsConstantRangeList();
     OS << "initializes(";
-    interleaveComma(CRL, OS, [&](ConstantRange CR) {
-      OS << "(" << CR.getLower() << ", " << CR.getUpper() << ")";
-    });
+    CRL.print(OS);
     OS << ")";
     OS.flush();
     return Result;
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index ce600de02bdb4..880325468d5e9 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -33,6 +33,9 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
     Ranges.insert(Ranges.begin(), NewRange);
     return;
   }
+  if (std::find(Ranges.begin(), Ranges.end(), NewRange) != Ranges.end()) {
+    return;
+  }
 
   // Slow insert.
   auto LowerBound =
@@ -60,10 +63,10 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
       Ranges.back() = ConstantRange(NewLower, NewUpper);
     }
   }
-  return;
 }
 
 void ConstantRangeList::print(raw_ostream &OS) const {
-  for (const auto &Range : Ranges)
-    Range.print(OS);
+  interleaveComma(Ranges, OS, [&](ConstantRange CR) {
+    OS << "(" << CR.getLower() << ", " << CR.getUpper() << ")";
+  });
 }
diff --git a/llvm/test/Assembler/initializes-attribute-invalid.ll b/llvm/test/Assembler/initializes-attribute-invalid.ll
index 4ba54ec56f67a..5413d24548440 100644
--- a/llvm/test/Assembler/initializes-attribute-invalid.ll
+++ b/llvm/test/Assembler/initializes-attribute-invalid.ll
@@ -1,7 +1,7 @@
 ; RUN: split-file %s %t
 ; RUN: not llvm-as < %s %t/outer_left_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=OUTER-LEFT
 ; RUN: not llvm-as < %s %t/inner_left_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=INNER-LEFT
-; RUN: not llvm-as < %s %t/inner_right_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=OUTER-RIGHT
+; RUN: not llvm-as < %s %t/inner_right_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=INNER-RIGHT
 ; RUN: not llvm-as < %s %t/outer_right_parenthesis.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=OUTER-RIGHT
 ; RUN: not llvm-as < %s %t/integer.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=INTEGER
 ; RUN: not llvm-as < %s %t/lower_equal_upper.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=LOWER-EQUAL-UPPER
diff --git a/llvm/unittests/IR/ConstantRangeListTest.cpp b/llvm/unittests/IR/ConstantRangeListTest.cpp
index 1b66de0f996d3..566899ee95a4f 100644
--- a/llvm/unittests/IR/ConstantRangeListTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeListTest.cpp
@@ -50,6 +50,8 @@ TEST_F(ConstantRangeListTest, Insert) {
   CRL.insert(14, 18);
   // Overlap cross ranges
   CRL.insert(2, 14);
+  // An existing range
+  CRL.insert(0, 20);
 
   ConstantRangeList Expected;
   Expected.insert(-8, -2);

>From 9782c318fb68e556b8581f2734fdf485d38bc252 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Tue, 23 Apr 2024 18:11:02 +0000
Subject: [PATCH 16/31] Update CRL to merge consecutive ranges

---
 llvm/lib/IR/ConstantRangeList.cpp           |  3 ++-
 llvm/unittests/IR/ConstantRangeListTest.cpp | 28 +++++++++++++--------
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 880325468d5e9..cdac3daa3039d 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -45,7 +45,8 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
                        });
   SmallVector<ConstantRange, 2> ExistingTail(LowerBound, Ranges.end());
   Ranges.erase(LowerBound, Ranges.end());
-  if (!Ranges.empty() && NewRange.getLower().slt(Ranges.back().getUpper())) {
+  // "sle" instead of "slt" to merge consecutive ranges.
+  if (!Ranges.empty() && NewRange.getLower().sle(Ranges.back().getUpper())) {
     APInt NewLower = Ranges.back().getLower();
     APInt NewUpper =
         APIntOps::smax(NewRange.getUpper(), Ranges.back().getUpper());
diff --git a/llvm/unittests/IR/ConstantRangeListTest.cpp b/llvm/unittests/IR/ConstantRangeListTest.cpp
index 566899ee95a4f..8bdab1d0e39fe 100644
--- a/llvm/unittests/IR/ConstantRangeListTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeListTest.cpp
@@ -16,20 +16,26 @@ namespace {
 using ConstantRangeListTest = ::testing::Test;
 
 TEST_F(ConstantRangeListTest, Basics) {
-  ConstantRangeList CRL1;
-  CRL1.insert(0, 4);
-  CRL1.insert(8, 12);
-  EXPECT_FALSE(CRL1.empty());
+  ConstantRangeList CRL1a;
+  CRL1a.insert(0, 12);
+  EXPECT_FALSE(CRL1a.empty());
+
+  ConstantRangeList CRL1b;
+  CRL1b.insert(0, 4);
+  CRL1b.insert(4, 8);
+  CRL1b.insert(8, 12);
+  EXPECT_TRUE(CRL1a == CRL1b);
+
+  ConstantRangeList CRL1c;
+  CRL1c.insert(0, 4);
+  CRL1c.insert(8, 12);
+  CRL1c.insert(4, 8);
+  EXPECT_TRUE(CRL1a == CRL1c);
 
   ConstantRangeList CRL2;
-  CRL2.insert(0, 4);
+  CRL2.insert(-4, 0);
   CRL2.insert(8, 12);
-  EXPECT_TRUE(CRL1 == CRL2);
-
-  ConstantRangeList CRL3;
-  CRL3.insert(-4, 0);
-  CRL3.insert(8, 12);
-  EXPECT_TRUE(CRL1 != CRL3);
+  EXPECT_TRUE(CRL1a != CRL2);
 }
 
 TEST_F(ConstantRangeListTest, Insert) {

>From a924dd38279508a438d4b90d2e4bce8d6f0fe1f0 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Tue, 23 Apr 2024 20:16:59 +0000
Subject: [PATCH 17/31] Handle a common case in CRL::insert and add CRL::dump

---
 llvm/include/llvm/IR/ConstantRangeList.h |  1 +
 llvm/lib/IR/ConstantRangeList.cpp        | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index fc452e661c631..7f87700519309 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -77,6 +77,7 @@ class [[nodiscard]] ConstantRangeList {
 
   /// Print out the ranges to a stream.
   void print(raw_ostream &OS) const;
+  void dump() const;
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index cdac3daa3039d..239aee65bfa37 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -36,6 +36,16 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
   if (std::find(Ranges.begin(), Ranges.end(), NewRange) != Ranges.end()) {
     return;
   }
+  if (size() == 1) {
+    // With all above checks (front/back/size), this branch means "NewRanges"
+    // overlaps with the singleton range in the list.
+    const ConstantRange &CurRange = Ranges.front();
+    APInt NewLower = APIntOps::smin(CurRange.getLower(), NewRange.getLower());
+    APInt NewUpper = APIntOps::smax(CurRange.getUpper(), NewRange.getUpper());
+    Ranges.clear();
+    Ranges.push_back(ConstantRange(NewLower, NewUpper));
+    return;
+  }
 
   // Slow insert.
   auto LowerBound =
@@ -71,3 +81,10 @@ void ConstantRangeList::print(raw_ostream &OS) const {
     OS << "(" << CR.getLower() << ", " << CR.getUpper() << ")";
   });
 }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void ConstantRangeList::dump() const {
+  print(dbgs());
+  dbgs() << '\n';
+}
+#endif

>From 45cdc34e110ffac9140ac2220dd7f39336ce8e0c Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Wed, 24 Apr 2024 18:09:07 +0000
Subject: [PATCH 18/31] Nit: change dbgs() to llvm::dbgs()

---
 llvm/lib/IR/ConstantRangeList.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 239aee65bfa37..d870d73a49f6a 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -84,7 +84,7 @@ void ConstantRangeList::print(raw_ostream &OS) const {
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 LLVM_DUMP_METHOD void ConstantRangeList::dump() const {
-  print(dbgs());
-  dbgs() << '\n';
+  print(llvm::dbgs());
+  llvm::dbgs() << '\n';
 }
 #endif

>From 4eeba08747fc098258104fb2a0abe81672fd6f53 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 25 Apr 2024 21:02:50 +0000
Subject: [PATCH 19/31] Change the attr impl to TrailingObjects<ConstantRange>

---
 llvm/include/llvm/IR/Attributes.h         | 10 +++---
 llvm/include/llvm/IR/ConstantRangeList.h  | 17 +++++-----
 llvm/lib/AsmParser/LLParser.cpp           |  6 ++--
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |  7 ++--
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp |  6 ++--
 llvm/lib/IR/AttributeImpl.h               | 41 ++++++++++++++++++-----
 llvm/lib/IR/Attributes.cpp                | 26 +++++++-------
 llvm/lib/IR/Verifier.cpp                  |  3 +-
 8 files changed, 71 insertions(+), 45 deletions(-)

diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index cb579746aa526..da064bc9c6c03 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -137,7 +137,7 @@ class Attribute {
   static Attribute get(LLVMContext &Context, AttrKind Kind,
                        const ConstantRange &CR);
   static Attribute get(LLVMContext &Context, AttrKind Kind,
-                       const ConstantRangeList &CRL);
+                       ArrayRef<ConstantRange> Val);
 
   /// Return a uniquified Attribute object that has the specific
   /// alignment set.
@@ -236,9 +236,9 @@ class Attribute {
   /// attribute to be a ConstantRange attribute.
   ConstantRange getValueAsConstantRange() const;
 
-  /// Return the attribute's value as a ConstantRangeList. This requires the
+  /// Return the attribute's value as a ConstantRange array. This requires the
   /// attribute to be a ConstantRangeList attribute.
-  ConstantRangeList getValueAsConstantRangeList() const;
+  ArrayRef<ConstantRange> getValueAsConstantRangeList() const;
 
   /// Returns the alignment field of an attribute as a byte alignment
   /// value.
@@ -1229,9 +1229,9 @@ class AttrBuilder {
   /// Add range attribute.
   AttrBuilder &addRangeAttr(const ConstantRange &CR);
 
-  /// Add a ConstantRangeList attribute with the given range.
+  /// Add a ConstantRangeList attribute with the given ranges.
   AttrBuilder &addConstantRangeListAttr(Attribute::AttrKind Kind,
-                                        const ConstantRangeList &CRL);
+                                        ArrayRef<ConstantRange> Val);
 
   /// Add initializes attribute.
   AttrBuilder &addInitializesAttr(const ConstantRangeList &CRL);
diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index 7f87700519309..f031d3d032ed0 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -18,6 +18,7 @@
 
 #include "llvm/ADT/APInt.h"
 #include "llvm/IR/ConstantRange.h"
+#include "llvm/Support/Debug.h"
 #include <cstddef>
 #include <cstdint>
 
@@ -30,6 +31,14 @@ class [[nodiscard]] ConstantRangeList {
   SmallVector<ConstantRange, 2> Ranges;
 
 public:
+  ConstantRangeList() = default;
+  ConstantRangeList(ArrayRef<ConstantRange> RangesRef) {
+    for (const ConstantRange &R : RangesRef) {
+      assert(R.getBitWidth() == getBitWidth());
+      Ranges.push_back(R);
+    }
+  }
+  ArrayRef<ConstantRange> rangesRef() const { return Ranges; }
   SmallVectorImpl<ConstantRange>::iterator begin() { return Ranges.begin(); }
   SmallVectorImpl<ConstantRange>::iterator end() { return Ranges.end(); }
   SmallVectorImpl<ConstantRange>::const_iterator begin() const {
@@ -59,14 +68,6 @@ class [[nodiscard]] ConstantRangeList {
                          APInt(64, Upper, /*isSigned=*/true)));
   }
 
-  // Append a new Range to Ranges. Caller should make sure
-  // the list is still ordered after appending.
-  void append(const ConstantRange &Range) { Ranges.push_back(Range); }
-  void append(int64_t Lower, int64_t Upper) {
-    append(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
-                         APInt(64, Upper, /*isSigned=*/true)));
-  }
-
   /// Return true if this range list is equal to another range list.
   bool operator==(const ConstantRangeList &CRL) const {
     return Ranges == CRL.Ranges;
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 9656f8b14b18e..2d089a1bcef3b 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3070,7 +3070,7 @@ bool LLParser::parseInitializesAttr(AttrBuilder &B) {
   if (parseToken(lltok::lparen, "expected '('"))
     return true;
 
-  ConstantRangeList CRL;
+  SmallVector<ConstantRange, 2> RangeList;
   // Parse each constant range.
   do {
     APInt Lower, Upper;
@@ -3087,13 +3087,13 @@ bool LLParser::parseInitializesAttr(AttrBuilder &B) {
     if (parseToken(lltok::rparen, "expected ')'"))
       return true;
 
-    CRL.append(ConstantRange(Lower, Upper));
+    RangeList.push_back(ConstantRange(Lower, Upper));
   } while (EatIfPresent(lltok::comma));
 
   if (parseToken(lltok::rparen, "expected ')'"))
     return true;
 
-  B.addInitializesAttr(CRL);
+  B.addInitializesAttr(ConstantRangeList(RangeList));
   return false;
 }
 
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 7bcc3e211b8df..b253cf75083ab 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2323,15 +2323,16 @@ Error BitcodeReader::parseAttributeGroupBlock() {
           if (!Attribute::isConstantRangeListAttrKind(Kind))
             return error("Not a constant range list attribute");
 
-          ConstantRangeList CRL;
+          SmallVector<ConstantRange, 2> Val;
           int RangeSize = Record[++i];
           assert(i + 2 * RangeSize < e);
           for (int Idx = 0; Idx < RangeSize; ++Idx) {
             int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
             int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
-            CRL.append(Start, End);
+            Val.push_back(
+                ConstantRange(APInt(64, Start, true), APInt(64, End, true)));
           }
-          B.addConstantRangeListAttr(Kind, CRL);
+          B.addConstantRangeListAttr(Kind, Val);
         } else {
           return error("Invalid attribute group entry");
         }
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 3b428d088282e..bd80665c1f379 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -941,9 +941,9 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
         assert(Attr.isConstantRangeListAttribute());
         Record.push_back(8);
         Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
-        ConstantRangeList CRL = Attr.getValueAsConstantRangeList();
-        Record.push_back(CRL.size());
-        for (auto &CR : CRL) {
+        ArrayRef<ConstantRange> Val = Attr.getValueAsConstantRangeList();
+        Record.push_back(Val.size());
+        for (auto &CR : Val) {
           emitSignedInt64(Record, CR.getLower().getSExtValue());
           emitSignedInt64(Record, CR.getUpper().getSExtValue());
         }
diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index 2fae149e44eda..489fcac2f626c 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -84,7 +84,7 @@ class AttributeImpl : public FoldingSetNode {
 
   ConstantRange getValueAsConstantRange() const;
 
-  ConstantRangeList getValueAsConstantRangeList() const;
+  ArrayRef<ConstantRange> getValueAsConstantRangeList() const;
 
   /// Used when sorting the attributes.
   bool operator<(const AttributeImpl &AI) const;
@@ -135,10 +135,10 @@ class AttributeImpl : public FoldingSetNode {
   }
 
   static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
-                      const ConstantRangeList &CRL) {
+                      ArrayRef<ConstantRange> Val) {
     ID.AddInteger(Kind);
-    ID.AddInteger(CRL.size());
-    for (auto &CR : CRL) {
+    ID.AddInteger(Val.size());
+    for (auto &CR : Val) {
       ID.AddInteger(CR.getLower());
       ID.AddInteger(CR.getUpper());
     }
@@ -241,15 +241,38 @@ class ConstantRangeAttributeImpl : public EnumAttributeImpl {
   ConstantRange getConstantRangeValue() const { return CR; }
 };
 
-class ConstantRangeListAttributeImpl : public EnumAttributeImpl {
-  ConstantRangeList CRL;
+class ConstantRangeListAttributeImpl final
+    : public EnumAttributeImpl,
+      private TrailingObjects<ConstantRangeListAttributeImpl, ConstantRange> {
+  friend TrailingObjects;
+
+  unsigned ValSize;
+  size_t numTrailingObjects(OverloadToken<ConstantRange>) const {
+    return ValSize;
+  }
 
 public:
   ConstantRangeListAttributeImpl(Attribute::AttrKind Kind,
-                                 const ConstantRangeList &CRL)
-      : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), CRL(CRL) {}
+                                 ArrayRef<ConstantRange> Val)
+      : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind),
+        ValSize(Val.size()) {
+    ConstantRange *TrailingCR = getTrailingObjects<ConstantRange>();
+    assert(ValSize > 0);
+    unsigned BitWidth = Val.front().getLower().getBitWidth();
+    for (unsigned I = 0; I != ValSize; ++I) {
+      assert(BitWidth == Val[I].getLower().getBitWidth());
+      new (&TrailingCR[I]) ConstantRange(BitWidth, false);
+    }
+    llvm::copy(Val, TrailingCR);
+  }
 
-  ConstantRangeList getConstantRangeListValue() const { return CRL; }
+  ArrayRef<ConstantRange> getConstantRangeListValue() const {
+    return ArrayRef(getTrailingObjects<ConstantRange>(), ValSize);
+  }
+
+  static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) {
+    return TrailingObjects::totalSizeToAlloc<ConstantRange>(Val.size());
+  }
 };
 
 class AttributeBitSet {
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index aaca563d93e2a..e48ccf686e7ee 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -193,14 +193,14 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
 }
 
 Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
-                         const ConstantRangeList &CRL) {
+                         ArrayRef<ConstantRange> Val) {
   assert(Attribute::isConstantRangeListAttrKind(Kind) &&
          "Not a ConstantRangeList attribute");
   LLVMContextImpl *pImpl = Context.pImpl;
   FoldingSetNodeID ID;
   ID.AddInteger(Kind);
-  ID.AddInteger(CRL.size());
-  for (auto &CR : CRL) {
+  ID.AddInteger(Val.size());
+  for (auto &CR : Val) {
     ID.AddInteger(CR.getLower());
     ID.AddInteger(CR.getUpper());
   }
@@ -211,8 +211,10 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
   if (!PA) {
     // If we didn't find any existing attributes of the same shape then create a
     // new one and insert it.
-    PA = new (pImpl->ConstantRangeListAttributeAlloc.Allocate())
-        ConstantRangeListAttributeImpl(Kind, CRL);
+    void *Mem = pImpl->Alloc.Allocate(
+        ConstantRangeListAttributeImpl::totalSizeToAlloc(Val),
+        alignof(ConstantRangeListAttributeImpl));
+    PA = new (Mem) ConstantRangeListAttributeImpl(Kind, Val);
     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
   }
 
@@ -399,7 +401,7 @@ ConstantRange Attribute::getValueAsConstantRange() const {
   return pImpl->getValueAsConstantRange();
 }
 
-ConstantRangeList Attribute::getValueAsConstantRangeList() const {
+ArrayRef<ConstantRange> Attribute::getValueAsConstantRangeList() const {
   assert(isConstantRangeListAttribute() &&
          "Invalid attribute type to get the value as a ConstantRangeList!");
   return pImpl->getValueAsConstantRangeList();
@@ -492,7 +494,7 @@ ConstantRange Attribute::getRange() const {
 ConstantRangeList Attribute::getInitializes() const {
   assert(hasAttribute(Attribute::Initializes) &&
          "Trying to get initializes attr from non-ConstantRangeList attribute");
-  return pImpl->getValueAsConstantRangeList();
+  return ConstantRangeList(pImpl->getValueAsConstantRangeList());
 }
 
 static const char *getModRefStr(ModRefInfo MR) {
@@ -664,7 +666,7 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
   if (hasAttribute(Attribute::Initializes)) {
     std::string Result;
     raw_string_ostream OS(Result);
-    ConstantRangeList CRL = getValueAsConstantRangeList();
+    ConstantRangeList CRL = getInitializes();
     OS << "initializes(";
     CRL.print(OS);
     OS << ")";
@@ -797,7 +799,7 @@ ConstantRange AttributeImpl::getValueAsConstantRange() const {
       ->getConstantRangeValue();
 }
 
-ConstantRangeList AttributeImpl::getValueAsConstantRangeList() const {
+ArrayRef<ConstantRange> AttributeImpl::getValueAsConstantRangeList() const {
   assert(isConstantRangeListAttribute());
   return static_cast<const ConstantRangeListAttributeImpl *>(this)
       ->getConstantRangeListValue();
@@ -2018,12 +2020,12 @@ AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
 
 AttrBuilder &
 AttrBuilder::addConstantRangeListAttr(Attribute::AttrKind Kind,
-                                      const ConstantRangeList &CRL) {
-  return addAttribute(Attribute::get(Ctx, Kind, CRL));
+                                      ArrayRef<ConstantRange> Val) {
+  return addAttribute(Attribute::get(Ctx, Kind, Val));
 }
 
 AttrBuilder &AttrBuilder::addInitializesAttr(const ConstantRangeList &CRL) {
-  return addConstantRangeListAttr(Attribute::Initializes, CRL);
+  return addConstantRangeListAttr(Attribute::Initializes, CRL.rangesRef());
 }
 
 AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 9082dc7878811..22e038985904d 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2034,8 +2034,7 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
   }
 
   if (Attrs.hasAttribute(Attribute::Initializes)) {
-    auto Inits = Attrs.getAttribute(Attribute::Initializes)
-                     .getValueAsConstantRangeList();
+    auto Inits = Attrs.getAttribute(Attribute::Initializes).getInitializes();
     Check(!Inits.empty(), "Attribute 'initializes' does not support empty list",
           V);
 

>From 502e062ab774d3f0c35f295840f3b6a4ce42a3a9 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Fri, 26 Apr 2024 16:56:57 +0000
Subject: [PATCH 20/31] Update LLVMContextImpl.h

---
 llvm/lib/IR/AttributeImpl.h       | 15 ++++++---------
 llvm/lib/IR/ConstantRangeList.cpp | 18 ++++--------------
 llvm/lib/IR/LLVMContextImpl.h     |  3 ---
 3 files changed, 10 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index 489fcac2f626c..2176b435e0e82 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -246,20 +246,17 @@ class ConstantRangeListAttributeImpl final
       private TrailingObjects<ConstantRangeListAttributeImpl, ConstantRange> {
   friend TrailingObjects;
 
-  unsigned ValSize;
-  size_t numTrailingObjects(OverloadToken<ConstantRange>) const {
-    return ValSize;
-  }
+  unsigned Size;
+  size_t numTrailingObjects(OverloadToken<ConstantRange>) const { return Size; }
 
 public:
   ConstantRangeListAttributeImpl(Attribute::AttrKind Kind,
                                  ArrayRef<ConstantRange> Val)
-      : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind),
-        ValSize(Val.size()) {
+      : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), Size(Val.size()) {
     ConstantRange *TrailingCR = getTrailingObjects<ConstantRange>();
-    assert(ValSize > 0);
+    assert(Size > 0);
     unsigned BitWidth = Val.front().getLower().getBitWidth();
-    for (unsigned I = 0; I != ValSize; ++I) {
+    for (unsigned I = 0; I != Size; ++I) {
       assert(BitWidth == Val[I].getLower().getBitWidth());
       new (&TrailingCR[I]) ConstantRange(BitWidth, false);
     }
@@ -267,7 +264,7 @@ class ConstantRangeListAttributeImpl final
   }
 
   ArrayRef<ConstantRange> getConstantRangeListValue() const {
-    return ArrayRef(getTrailingObjects<ConstantRange>(), ValSize);
+    return ArrayRef(getTrailingObjects<ConstantRange>(), Size);
   }
 
   static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) {
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index d870d73a49f6a..e462d2eaa41f2 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -33,26 +33,16 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
     Ranges.insert(Ranges.begin(), NewRange);
     return;
   }
-  if (std::find(Ranges.begin(), Ranges.end(), NewRange) != Ranges.end()) {
-    return;
-  }
-  if (size() == 1) {
-    // With all above checks (front/back/size), this branch means "NewRanges"
-    // overlaps with the singleton range in the list.
-    const ConstantRange &CurRange = Ranges.front();
-    APInt NewLower = APIntOps::smin(CurRange.getLower(), NewRange.getLower());
-    APInt NewUpper = APIntOps::smax(CurRange.getUpper(), NewRange.getUpper());
-    Ranges.clear();
-    Ranges.push_back(ConstantRange(NewLower, NewUpper));
-    return;
-  }
 
-  // Slow insert.
   auto LowerBound =
       std::lower_bound(Ranges.begin(), Ranges.end(), NewRange,
                        [](const ConstantRange &a, const ConstantRange &b) {
                          return a.getLower().slt(b.getLower());
                        });
+  if (LowerBound != Ranges.end() && *LowerBound == NewRange)
+    return;
+
+  // Slow insert.
   SmallVector<ConstantRange, 2> ExistingTail(LowerBound, Ranges.end());
   Ranges.erase(LowerBound, Ranges.end());
   // "sle" instead of "slt" to merge consecutive ranges.
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 04546b080babe..547a02a6490ea 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -57,7 +57,6 @@ class AttributeListImpl;
 class AttributeSetNode;
 class BasicBlock;
 class ConstantRangeAttributeImpl;
-class ConstantRangeListAttributeImpl;
 struct DiagnosticHandler;
 class DPMarker;
 class ElementCount;
@@ -1566,8 +1565,6 @@ class LLVMContextImpl {
   UniqueStringSaver Saver{Alloc};
   SpecificBumpPtrAllocator<ConstantRangeAttributeImpl>
       ConstantRangeAttributeAlloc;
-  SpecificBumpPtrAllocator<ConstantRangeListAttributeImpl>
-      ConstantRangeListAttributeAlloc;
 
   DenseMap<unsigned, IntegerType *> IntegerTypes;
 

>From ea3e7c5709f746b6baa98902320a4a4c8a0fd944 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Wed, 8 May 2024 21:07:12 +0000
Subject: [PATCH 21/31] Rebase to the latest main

---
 llvm/lib/IR/AttributeImpl.h | 4 ++--
 llvm/lib/IR/Attributes.cpp  | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index 28dfde8f807d1..c8aa01aa0e4bc 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -139,8 +139,8 @@ class AttributeImpl : public FoldingSetNode {
     ID.AddInteger(Kind);
     ID.AddInteger(Val.size());
     for (auto &CR : Val) {
-      ID.AddInteger(CR.getLower());
-      ID.AddInteger(CR.getUpper());
+      CR.getLower().Profile(ID);
+      CR.getUpper().Profile(ID);
     }
   }
 };
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 7f42dad086595..337c89fa1313a 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -201,8 +201,8 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
   ID.AddInteger(Kind);
   ID.AddInteger(Val.size());
   for (auto &CR : Val) {
-    ID.AddInteger(CR.getLower());
-    ID.AddInteger(CR.getUpper());
+    CR.getLower().Profile(ID);
+    CR.getUpper().Profile(ID);
   }
 
   void *InsertPoint;

>From 7630510cdcc3f19d6bde95137952436afee508ee Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Wed, 8 May 2024 21:16:15 +0000
Subject: [PATCH 22/31] Change getInitializes() to return
 ArrayRef<ConstantRange>

---
 llvm/include/llvm/IR/Attributes.h | 2 +-
 llvm/lib/IR/Attributes.cpp        | 4 ++--
 llvm/lib/IR/Verifier.cpp          | 6 +++---
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 3e98f4c934bcd..5a80a072dbbd2 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -282,7 +282,7 @@ class Attribute {
   const ConstantRange &getRange() const;
 
   /// Returns the value of the initializes attribute.
-  ConstantRangeList getInitializes() const;
+  ArrayRef<ConstantRange> getInitializes() const;
 
   /// The Attribute is converted to a string of equivalent mnemonic. This
   /// is, presumably, for writing out the mnemonics for the assembly writer.
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 337c89fa1313a..a3786bd0c343d 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -491,10 +491,10 @@ const ConstantRange &Attribute::getRange() const {
   return pImpl->getValueAsConstantRange();
 }
 
-ConstantRangeList Attribute::getInitializes() const {
+ArrayRef<ConstantRange> Attribute::getInitializes() const {
   assert(hasAttribute(Attribute::Initializes) &&
          "Trying to get initializes attr from non-ConstantRangeList attribute");
-  return ConstantRangeList(pImpl->getValueAsConstantRangeList());
+  return pImpl->getValueAsConstantRangeList();
 }
 
 static const char *getModRefStr(ModRefInfo MR) {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 4e8806c4a233a..cbd92107ff797 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2063,11 +2063,11 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
     Check(!Inits.empty(), "Attribute 'initializes' does not support empty list",
           V);
 
-    Check(Inits.getRange(0).getLower().slt(Inits.getRange(0).getUpper()),
+    Check(Inits[0].getLower().slt(Inits[0].getUpper()),
           "Attribute 'initializes' requires interval lower less than upper", V);
     for (size_t i = 1; i < Inits.size(); i++) {
-      auto Previous = Inits.getRange(i - 1);
-      auto Current = Inits.getRange(i);
+      auto Previous = Inits[i - 1];
+      auto Current = Inits[i];
       Check(Current.getLower().slt(Current.getUpper()),
             "Attribute 'initializes' requires interval lower less than upper",
             V);

>From a604b4f570e2ec8cc094b24e58629c695e1dee2c Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Wed, 8 May 2024 21:17:38 +0000
Subject: [PATCH 23/31] Remove llvm::

---
 llvm/lib/IR/ConstantRangeList.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index e462d2eaa41f2..684773937a9f7 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -74,7 +74,7 @@ void ConstantRangeList::print(raw_ostream &OS) const {
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 LLVM_DUMP_METHOD void ConstantRangeList::dump() const {
-  print(llvm::dbgs());
-  llvm::dbgs() << '\n';
+  print(dbgs());
+  dbgs() << '\n';
 }
 #endif

>From f941b242f8ae38b04955bb503ee765c642125988 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 9 May 2024 14:34:39 +0000
Subject: [PATCH 24/31] Update LangRef and ConstantRangeList

---
 llvm/docs/LangRef.rst                    | 11 ++++++-----
 llvm/include/llvm/IR/ConstantRangeList.h | 12 ++++++------
 llvm/lib/IR/ConstantRangeList.cpp        |  7 -------
 3 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 6c0e378e79d5b..b0a9ff8f89d7f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1632,13 +1632,14 @@ Currently, only the following parameter attributes are defined:
     parameter. Other arbitrary accesses to the same memory via other pointers
     are allowed.
 
-    The ``writable`` or ``dereferenceable`` attribute does not imply the
-    ``initializes`` attribute. The ``initializes`` does not imply ``writeonly``
-    since ``initializes`` allows reading from the pointer after writing.
+    The ``writable`` or ``dereferenceable`` attribute do not imply the
+    ``initializes`` attribute. The ``initializes`` attribute does not imply
+    ``writeonly`` since ``initializes`` allows reading from the pointer
+    after writing.
 
     This attribute is a list of constant ranges in ascending order with no
-    overlapping or consecutive list elements. ``LoN/HiN`` are 64-bit ints, and
-    negative values are allowed in case the argument points partway into
+    overlapping or consecutive list elements. ``LoN/HiN`` are 64-bit integers,
+    and negative values are allowed in case the argument points partway into
     an allocation. An empty list is not allowed.
 
 ``dead_on_unwind``
diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index f031d3d032ed0..6d8fea28b3af9 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -1,4 +1,4 @@
-//===- ConstantRangeList.h - A list of constant range -----------*- C++ -*-===//
+//===- ConstantRangeList.h - A list of constant ranges ----------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 //
 // Represent a list of signed ConstantRange and do NOT support wrap around the
-// end of the numeric range. Ranges in the list are ordered and no overlapping.
+// end of the numeric range. Ranges in the list are ordered and not overlapping.
 // Ranges should have the same bitwidth. Each range's lower should be less than
 // its upper.
 //
@@ -47,10 +47,7 @@ class [[nodiscard]] ConstantRangeList {
   SmallVectorImpl<ConstantRange>::const_iterator end() const {
     return Ranges.end();
   }
-  ConstantRange getRange(unsigned i) const {
-    assert(i < Ranges.size());
-    return Ranges[i];
-  }
+  ConstantRange getRange(unsigned i) const { return Ranges[i]; }
 
   /// Return true if this list contains no members.
   bool empty() const { return Ranges.empty(); }
@@ -78,7 +75,10 @@ class [[nodiscard]] ConstantRangeList {
 
   /// Print out the ranges to a stream.
   void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
   void dump() const;
+#endif
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 684773937a9f7..8228bf3a3ba1b 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -5,13 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// Represent a list of signed ConstantRange and do NOT support wrap around the
-// end of the numeric range. Ranges in the list are ordered and no overlapping.
-// Ranges should have the same bitwidth. Each range's lower should be less than
-// its upper.
-//
-//===----------------------------------------------------------------------===//
 
 #include "llvm/IR/ConstantRangeList.h"
 #include <cstddef>

>From e52fd9d4bd879d4e8d70713f4eadaa326bf6b314 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 9 May 2024 14:56:14 +0000
Subject: [PATCH 25/31] Update BitCodeReader/Writer

---
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |  7 ++++---
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 13 +++++++------
 2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 961d6c6b7e2d0..536eff0478fb5 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2343,9 +2343,10 @@ Error BitcodeReader::parseAttributeGroupBlock() {
             return error("Not a constant range list attribute");
 
           SmallVector<ConstantRange, 2> Val;
-          int RangeSize = Record[++i];
-          assert(i + 2 * RangeSize < e);
-          for (int Idx = 0; Idx < RangeSize; ++Idx) {
+          unsigned RangeSize = Record[++i];
+          if (i + 2 * RangeSize >= e)
+            return error("Incomplete constant range list");
+          for (unsigned Idx = 0; Idx < RangeSize; ++Idx) {
             int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
             int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
             Val.push_back(
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 65355f89d22fb..6011aa72789ac 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -893,9 +893,10 @@ static void emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, const APInt &A) {
 }
 
 static void emitConstantRange(SmallVectorImpl<uint64_t> &Record,
-                              const ConstantRange &CR) {
+                              const ConstantRange &CR, bool EmitBitWidth) {
   unsigned BitWidth = CR.getBitWidth();
-  Record.push_back(BitWidth);
+  if (EmitBitWidth)
+    Record.push_back(BitWidth);
   if (BitWidth > 64) {
     Record.push_back(CR.getLower().getActiveWords() |
                      (uint64_t(CR.getUpper().getActiveWords()) << 32));
@@ -949,7 +950,8 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
       } else if (Attr.isConstantRangeAttribute()) {
         Record.push_back(7);
         Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
-        emitConstantRange(Record, Attr.getValueAsConstantRange());
+        emitConstantRange(Record, Attr.getValueAsConstantRange(),
+                          /*EmitBitWidth=*/true);
       } else {
         assert(Attr.isConstantRangeListAttribute());
         Record.push_back(8);
@@ -957,8 +959,7 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
         ArrayRef<ConstantRange> Val = Attr.getValueAsConstantRangeList();
         Record.push_back(Val.size());
         for (auto &CR : Val) {
-          emitSignedInt64(Record, CR.getLower().getSExtValue());
-          emitSignedInt64(Record, CR.getUpper().getSExtValue());
+          emitConstantRange(Record, CR, /*EmitBitWidth=*/false);
         }
       }
     }
@@ -2782,7 +2783,7 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
         if (std::optional<ConstantRange> Range = GO->getInRange()) {
           Code = bitc::CST_CODE_CE_GEP_WITH_INRANGE;
           Record.push_back(GO->isInBounds());
-          emitConstantRange(Record, *Range);
+          emitConstantRange(Record, *Range, /*EmitBitWidth=*/true);
         } else if (GO->isInBounds())
           Code = bitc::CST_CODE_CE_INBOUNDS_GEP;
         for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) {

>From 8e64fa980b0e021a74d3e0e0f0f879b0f74028af Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 9 May 2024 17:43:28 +0000
Subject: [PATCH 26/31] Encode bitwidth once for ConstantRangeList kind attr

---
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 5 +++--
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 1 +
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 536eff0478fb5..f63e058217d88 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2344,13 +2344,14 @@ Error BitcodeReader::parseAttributeGroupBlock() {
 
           SmallVector<ConstantRange, 2> Val;
           unsigned RangeSize = Record[++i];
+          unsigned BitWidth = Record[++i];
           if (i + 2 * RangeSize >= e)
             return error("Incomplete constant range list");
           for (unsigned Idx = 0; Idx < RangeSize; ++Idx) {
             int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
             int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
-            Val.push_back(
-                ConstantRange(APInt(64, Start, true), APInt(64, End, true)));
+            Val.push_back(ConstantRange(APInt(BitWidth, Start, true),
+                                        APInt(BitWidth, End, true)));
           }
           B.addConstantRangeListAttr(Kind, Val);
         } else {
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 6011aa72789ac..e9d6afb49cd9e 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -958,6 +958,7 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
         Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
         ArrayRef<ConstantRange> Val = Attr.getValueAsConstantRangeList();
         Record.push_back(Val.size());
+        Record.push_back(Val[0].getBitWidth());
         for (auto &CR : Val) {
           emitConstantRange(Record, CR, /*EmitBitWidth=*/false);
         }

>From 9ae0fcaa9ad002c567d76211c39481d5765fb8e1 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 16 May 2024 23:56:07 +0000
Subject: [PATCH 27/31] Use SpecificBumpPtrAllocator to allocate mem and make
 sure to call destructors

---
 llvm/lib/IR/Attributes.cpp        | 7 +++----
 llvm/lib/IR/ConstantRangeList.cpp | 2 +-
 llvm/lib/IR/LLVMContextImpl.h     | 3 +++
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index a3786bd0c343d..95425f8cac382 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -211,10 +211,9 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
   if (!PA) {
     // If we didn't find any existing attributes of the same shape then create a
     // new one and insert it.
-    void *Mem = pImpl->Alloc.Allocate(
-        ConstantRangeListAttributeImpl::totalSizeToAlloc(Val),
-        alignof(ConstantRangeListAttributeImpl));
-    PA = new (Mem) ConstantRangeListAttributeImpl(Kind, Val);
+    PA = new (pImpl->ConstantRangeListAttributeAlloc.Allocate(
+        ConstantRangeListAttributeImpl::totalSizeToAlloc(Val)))
+        ConstantRangeListAttributeImpl(Kind, Val);
     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
   }
 
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 8228bf3a3ba1b..9b0dcf9297a68 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -38,7 +38,7 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
   // Slow insert.
   SmallVector<ConstantRange, 2> ExistingTail(LowerBound, Ranges.end());
   Ranges.erase(LowerBound, Ranges.end());
-  // "sle" instead of "slt" to merge consecutive ranges.
+  // Merge consecutive ranges.
   if (!Ranges.empty() && NewRange.getLower().sle(Ranges.back().getUpper())) {
     APInt NewLower = Ranges.back().getLower();
     APInt NewUpper =
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 399fe0dad26c7..8d67bfaa28c35 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -57,6 +57,7 @@ class AttributeListImpl;
 class AttributeSetNode;
 class BasicBlock;
 class ConstantRangeAttributeImpl;
+class ConstantRangeListAttributeImpl;
 struct DiagnosticHandler;
 class DbgMarker;
 class ElementCount;
@@ -1581,6 +1582,8 @@ class LLVMContextImpl {
   UniqueStringSaver Saver{Alloc};
   SpecificBumpPtrAllocator<ConstantRangeAttributeImpl>
       ConstantRangeAttributeAlloc;
+  SpecificBumpPtrAllocator<ConstantRangeListAttributeImpl>
+      ConstantRangeListAttributeAlloc;
 
   DenseMap<unsigned, IntegerType *> IntegerTypes;
 

>From d4809abeb3f2fb4502418431a374ccf8ef4a9316 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Fri, 17 May 2024 17:20:22 +0000
Subject: [PATCH 28/31] Refactor readConstantRange and update BitcodeReader

---
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 31 ++++++++++++++++-------
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index f63e058217d88..b96b530789338 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -835,10 +835,10 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
   }
 
   Expected<ConstantRange> readConstantRange(ArrayRef<uint64_t> Record,
-                                            unsigned &OpNum) {
-    if (Record.size() - OpNum < 3)
+                                            unsigned &OpNum,
+                                            unsigned BitWidth) {
+    if (Record.size() - OpNum < 2)
       return error("Too few records for range");
-    unsigned BitWidth = Record[OpNum++];
     if (BitWidth > 64) {
       unsigned LowerActiveWords = Record[OpNum];
       unsigned UpperActiveWords = Record[OpNum++] >> 32;
@@ -858,6 +858,14 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
     }
   }
 
+  Expected<ConstantRange>
+  readBitWidthAndConstantRange(ArrayRef<uint64_t> Record, unsigned &OpNum) {
+    if (Record.size() - OpNum < 3)
+      return error("Too few records for range");
+    unsigned BitWidth = Record[OpNum++];
+    return readConstantRange(Record, OpNum, BitWidth);
+  }
+
   /// Upgrades old-style typeless byval/sret/inalloca attributes by adding the
   /// corresponding argument's pointee type. Also upgrades intrinsics that now
   /// require an elementtype attribute.
@@ -2329,7 +2337,8 @@ Error BitcodeReader::parseAttributeGroupBlock() {
           if (!Attribute::isConstantRangeAttrKind(Kind))
             return error("Not a ConstantRange attribute");
 
-          Expected<ConstantRange> MaybeCR = readConstantRange(Record, i);
+          Expected<ConstantRange> MaybeCR =
+              readBitWidthAndConstantRange(Record, i);
           if (!MaybeCR)
             return MaybeCR.takeError();
           i--;
@@ -2348,10 +2357,13 @@ Error BitcodeReader::parseAttributeGroupBlock() {
           if (i + 2 * RangeSize >= e)
             return error("Incomplete constant range list");
           for (unsigned Idx = 0; Idx < RangeSize; ++Idx) {
-            int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
-            int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
-            Val.push_back(ConstantRange(APInt(BitWidth, Start, true),
-                                        APInt(BitWidth, End, true)));
+            i++;
+            Expected<ConstantRange> MaybeCR =
+                readConstantRange(Record, i, BitWidth);
+            if (!MaybeCR)
+              return MaybeCR.takeError();
+            i--;
+            Val.push_back(MaybeCR.get());
           }
           B.addConstantRangeListAttr(Kind, Val);
         } else {
@@ -3367,7 +3379,8 @@ Error BitcodeReader::parseConstants() {
       } else if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE) {
         uint64_t Op = Record[OpNum++];
         InBounds = Op & 1;
-        Expected<ConstantRange> MaybeInRange = readConstantRange(Record, OpNum);
+        Expected<ConstantRange> MaybeInRange =
+            readBitWidthAndConstantRange(Record, OpNum);
         if (!MaybeInRange)
           return MaybeInRange.takeError();
         InRange = MaybeInRange.get();

>From 96191cd5984c21d68d5eb09b5372af0c496c3117 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 30 May 2024 21:54:37 +0000
Subject: [PATCH 29/31] Change the attr imple back to ConstantRangeList

---
 llvm/include/llvm/IR/Attributes.h         | 10 +++---
 llvm/include/llvm/IR/ConstantRangeList.h  |  3 +-
 llvm/lib/AsmParser/LLParser.cpp           |  5 ++-
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 21 ++++++++----
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp |  9 +++---
 llvm/lib/IR/AttributeImpl.h               | 39 ++++++-----------------
 llvm/lib/IR/Attributes.cpp                | 23 +++++++------
 llvm/lib/IR/ConstantRangeList.cpp         | 22 +++++++++++++
 llvm/lib/IR/Verifier.cpp                  |  6 ++--
 llvm/test/Verifier/initializes-attr.ll    | 27 +++++++++-------
 10 files changed, 90 insertions(+), 75 deletions(-)

diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 5a80a072dbbd2..3b62a10aa98f7 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -137,7 +137,7 @@ class Attribute {
   static Attribute get(LLVMContext &Context, AttrKind Kind,
                        const ConstantRange &CR);
   static Attribute get(LLVMContext &Context, AttrKind Kind,
-                       ArrayRef<ConstantRange> Val);
+                       const ConstantRangeList &CRL);
 
   /// Return a uniquified Attribute object that has the specific
   /// alignment set.
@@ -236,9 +236,9 @@ class Attribute {
   /// attribute to be a ConstantRange attribute.
   const ConstantRange &getValueAsConstantRange() const;
 
-  /// Return the attribute's value as a ConstantRange array. This requires the
+  /// Return the attribute's value as a ConstantRangeList. This requires the
   /// attribute to be a ConstantRangeList attribute.
-  ArrayRef<ConstantRange> getValueAsConstantRangeList() const;
+  ConstantRangeList getValueAsConstantRangeList() const;
 
   /// Returns the alignment field of an attribute as a byte alignment
   /// value.
@@ -282,7 +282,7 @@ class Attribute {
   const ConstantRange &getRange() const;
 
   /// Returns the value of the initializes attribute.
-  ArrayRef<ConstantRange> getInitializes() const;
+  ConstantRangeList getInitializes() const;
 
   /// The Attribute is converted to a string of equivalent mnemonic. This
   /// is, presumably, for writing out the mnemonics for the assembly writer.
@@ -1241,7 +1241,7 @@ class AttrBuilder {
 
   /// Add a ConstantRangeList attribute with the given ranges.
   AttrBuilder &addConstantRangeListAttr(Attribute::AttrKind Kind,
-                                        ArrayRef<ConstantRange> Val);
+                                        const ConstantRangeList &CRL);
 
   /// Add initializes attribute.
   AttrBuilder &addInitializesAttr(const ConstantRangeList &CRL);
diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index 6d8fea28b3af9..f9b7dda03693f 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -38,7 +38,8 @@ class [[nodiscard]] ConstantRangeList {
       Ranges.push_back(R);
     }
   }
-  ArrayRef<ConstantRange> rangesRef() const { return Ranges; }
+  static std::optional<ConstantRangeList>
+  getConstantRangeList(ArrayRef<ConstantRange> RangesRef);
   SmallVectorImpl<ConstantRange>::iterator begin() { return Ranges.begin(); }
   SmallVectorImpl<ConstantRange>::iterator end() { return Ranges.end(); }
   SmallVectorImpl<ConstantRange>::const_iterator begin() const {
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 1e3558dd539b4..6d42c549501fa 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3141,7 +3141,10 @@ bool LLParser::parseInitializesAttr(AttrBuilder &B) {
   if (parseToken(lltok::rparen, "expected ')'"))
     return true;
 
-  B.addInitializesAttr(ConstantRangeList(RangeList));
+  auto CRLOrNull = ConstantRangeList::getConstantRangeList(RangeList);
+  if (!CRLOrNull.has_value())
+    return tokError("Invalid (unordered or overlapping) range list");
+  B.addInitializesAttr(*CRLOrNull);
   return false;
 }
 
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 4bd2f948924b1..e2a98bda1375a 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2357,26 +2357,33 @@ Error BitcodeReader::parseAttributeGroupBlock() {
           B.addConstantRangeAttr(Kind, MaybeCR.get());
         } else if (Record[i] == 8) {
           Attribute::AttrKind Kind;
-          if (Error Err = parseAttrKind(Record[++i], &Kind))
+
+          i++;
+          if (Error Err = parseAttrKind(Record[i++], &Kind))
             return Err;
           if (!Attribute::isConstantRangeListAttrKind(Kind))
             return error("Not a constant range list attribute");
 
           SmallVector<ConstantRange, 2> Val;
-          unsigned RangeSize = Record[++i];
-          unsigned BitWidth = Record[++i];
-          if (i + 2 * RangeSize >= e)
+          if (i + 2 > e)
+            return error("Too few records for constant range list");
+          unsigned RangeSize = Record[i++];
+          unsigned BitWidth = Record[i++];
+          if (i + 2 * RangeSize > e)
             return error("Incomplete constant range list");
           for (unsigned Idx = 0; Idx < RangeSize; ++Idx) {
-            i++;
             Expected<ConstantRange> MaybeCR =
                 readConstantRange(Record, i, BitWidth);
             if (!MaybeCR)
               return MaybeCR.takeError();
-            i--;
             Val.push_back(MaybeCR.get());
           }
-          B.addConstantRangeListAttr(Kind, Val);
+          i--;
+
+          auto CRLOrNull = ConstantRangeList::getConstantRangeList(Val);
+          if (!CRLOrNull.has_value())
+            return error("Invalid (unordered or overlapping) range list");
+          B.addConstantRangeListAttr(Kind, *CRLOrNull);
         } else {
           return error("Invalid attribute group entry");
         }
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 206a31a3f6b07..53e41287775a6 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -966,12 +966,11 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
         assert(Attr.isConstantRangeListAttribute());
         Record.push_back(8);
         Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
-        ArrayRef<ConstantRange> Val = Attr.getValueAsConstantRangeList();
-        Record.push_back(Val.size());
-        Record.push_back(Val[0].getBitWidth());
-        for (auto &CR : Val) {
+        ConstantRangeList CRL = Attr.getValueAsConstantRangeList();
+        Record.push_back(CRL.size());
+        Record.push_back(CRL.getBitWidth());
+        for (auto &CR : CRL)
           emitConstantRange(Record, CR, /*EmitBitWidth=*/false);
-        }
       }
     }
 
diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index c8aa01aa0e4bc..9d9f729bbc493 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -84,7 +84,7 @@ class AttributeImpl : public FoldingSetNode {
 
   const ConstantRange &getValueAsConstantRange() const;
 
-  ArrayRef<ConstantRange> getValueAsConstantRangeList() const;
+  ConstantRangeList getValueAsConstantRangeList() const;
 
   /// Used when sorting the attributes.
   bool operator<(const AttributeImpl &AI) const;
@@ -135,10 +135,10 @@ class AttributeImpl : public FoldingSetNode {
   }
 
   static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
-                      ArrayRef<ConstantRange> Val) {
+                      const ConstantRangeList &CRL) {
     ID.AddInteger(Kind);
-    ID.AddInteger(Val.size());
-    for (auto &CR : Val) {
+    ID.AddInteger(CRL.size());
+    for (auto &CR : CRL) {
       CR.getLower().Profile(ID);
       CR.getUpper().Profile(ID);
     }
@@ -241,35 +241,14 @@ class ConstantRangeAttributeImpl : public EnumAttributeImpl {
   const ConstantRange &getConstantRangeValue() const { return CR; }
 };
 
-class ConstantRangeListAttributeImpl final
-    : public EnumAttributeImpl,
-      private TrailingObjects<ConstantRangeListAttributeImpl, ConstantRange> {
-  friend TrailingObjects;
-
-  unsigned Size;
-  size_t numTrailingObjects(OverloadToken<ConstantRange>) const { return Size; }
+class ConstantRangeListAttributeImpl : public EnumAttributeImpl {
+  ConstantRangeList CRL;
 
 public:
   ConstantRangeListAttributeImpl(Attribute::AttrKind Kind,
-                                 ArrayRef<ConstantRange> Val)
-      : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), Size(Val.size()) {
-    ConstantRange *TrailingCR = getTrailingObjects<ConstantRange>();
-    assert(Size > 0);
-    unsigned BitWidth = Val.front().getLower().getBitWidth();
-    for (unsigned I = 0; I != Size; ++I) {
-      assert(BitWidth == Val[I].getLower().getBitWidth());
-      new (&TrailingCR[I]) ConstantRange(BitWidth, false);
-    }
-    llvm::copy(Val, TrailingCR);
-  }
-
-  ArrayRef<ConstantRange> getConstantRangeListValue() const {
-    return ArrayRef(getTrailingObjects<ConstantRange>(), Size);
-  }
-
-  static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) {
-    return TrailingObjects::totalSizeToAlloc<ConstantRange>(Val.size());
-  }
+                                 const ConstantRangeList &CRL)
+      : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), CRL(CRL) {}
+  ConstantRangeList getConstantRangeListValue() const { return CRL; }
 };
 
 class AttributeBitSet {
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 95425f8cac382..53476aaacb867 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -193,14 +193,14 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
 }
 
 Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
-                         ArrayRef<ConstantRange> Val) {
+                         const ConstantRangeList &CRL) {
   assert(Attribute::isConstantRangeListAttrKind(Kind) &&
          "Not a ConstantRangeList attribute");
   LLVMContextImpl *pImpl = Context.pImpl;
   FoldingSetNodeID ID;
   ID.AddInteger(Kind);
-  ID.AddInteger(Val.size());
-  for (auto &CR : Val) {
+  ID.AddInteger(CRL.size());
+  for (auto &CR : CRL) {
     CR.getLower().Profile(ID);
     CR.getUpper().Profile(ID);
   }
@@ -211,9 +211,8 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
   if (!PA) {
     // If we didn't find any existing attributes of the same shape then create a
     // new one and insert it.
-    PA = new (pImpl->ConstantRangeListAttributeAlloc.Allocate(
-        ConstantRangeListAttributeImpl::totalSizeToAlloc(Val)))
-        ConstantRangeListAttributeImpl(Kind, Val);
+    PA = new (pImpl->ConstantRangeListAttributeAlloc.Allocate())
+        ConstantRangeListAttributeImpl(Kind, CRL);
     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
   }
 
@@ -400,7 +399,7 @@ const ConstantRange &Attribute::getValueAsConstantRange() const {
   return pImpl->getValueAsConstantRange();
 }
 
-ArrayRef<ConstantRange> Attribute::getValueAsConstantRangeList() const {
+ConstantRangeList Attribute::getValueAsConstantRangeList() const {
   assert(isConstantRangeListAttribute() &&
          "Invalid attribute type to get the value as a ConstantRangeList!");
   return pImpl->getValueAsConstantRangeList();
@@ -490,7 +489,7 @@ const ConstantRange &Attribute::getRange() const {
   return pImpl->getValueAsConstantRange();
 }
 
-ArrayRef<ConstantRange> Attribute::getInitializes() const {
+ConstantRangeList Attribute::getInitializes() const {
   assert(hasAttribute(Attribute::Initializes) &&
          "Trying to get initializes attr from non-ConstantRangeList attribute");
   return pImpl->getValueAsConstantRangeList();
@@ -798,7 +797,7 @@ const ConstantRange &AttributeImpl::getValueAsConstantRange() const {
       ->getConstantRangeValue();
 }
 
-ArrayRef<ConstantRange> AttributeImpl::getValueAsConstantRangeList() const {
+ConstantRangeList AttributeImpl::getValueAsConstantRangeList() const {
   assert(isConstantRangeListAttribute());
   return static_cast<const ConstantRangeListAttributeImpl *>(this)
       ->getConstantRangeListValue();
@@ -2026,12 +2025,12 @@ AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
 
 AttrBuilder &
 AttrBuilder::addConstantRangeListAttr(Attribute::AttrKind Kind,
-                                      ArrayRef<ConstantRange> Val) {
-  return addAttribute(Attribute::get(Ctx, Kind, Val));
+                                      const ConstantRangeList &CRL) {
+  return addAttribute(Attribute::get(Ctx, Kind, CRL));
 }
 
 AttrBuilder &AttrBuilder::addInitializesAttr(const ConstantRangeList &CRL) {
-  return addConstantRangeListAttr(Attribute::Initializes, CRL.rangesRef());
+  return addConstantRangeListAttr(Attribute::Initializes, CRL);
 }
 
 AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 9b0dcf9297a68..24dfea479ab2d 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -11,6 +11,28 @@
 
 using namespace llvm;
 
+std::optional<ConstantRangeList>
+ConstantRangeList::getConstantRangeList(ArrayRef<ConstantRange> RangesRef) {
+  if (RangesRef.empty())
+    return ConstantRangeList();
+  auto Range = RangesRef[0];
+  if (Range.getLower().sge(Range.getUpper()))
+    return std::nullopt;
+  if (RangesRef.size() == 1)
+    return ConstantRangeList(RangesRef);
+  for (unsigned i = 1; i < RangesRef.size(); i++) {
+    auto CurRange = RangesRef[i];
+    auto PreRange = RangesRef[i - 1];
+    if (CurRange.getLower().sge(CurRange.getUpper()))
+      return std::nullopt;
+    if (CurRange.getLower().sle(PreRange.getUpper()))
+      return std::nullopt;
+    if (CurRange.getLower().sle(PreRange.getUpper()))
+      return std::nullopt;
+  }
+  return ConstantRangeList(RangesRef);
+}
+
 void ConstantRangeList::insert(const ConstantRange &NewRange) {
   if (NewRange.isEmptySet())
     return;
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index cbd92107ff797..4e8806c4a233a 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2063,11 +2063,11 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
     Check(!Inits.empty(), "Attribute 'initializes' does not support empty list",
           V);
 
-    Check(Inits[0].getLower().slt(Inits[0].getUpper()),
+    Check(Inits.getRange(0).getLower().slt(Inits.getRange(0).getUpper()),
           "Attribute 'initializes' requires interval lower less than upper", V);
     for (size_t i = 1; i < Inits.size(); i++) {
-      auto Previous = Inits[i - 1];
-      auto Current = Inits[i];
+      auto Previous = Inits.getRange(i - 1);
+      auto Current = Inits.getRange(i);
       Check(Current.getLower().slt(Current.getUpper()),
             "Attribute 'initializes' requires interval lower less than upper",
             V);
diff --git a/llvm/test/Verifier/initializes-attr.ll b/llvm/test/Verifier/initializes-attr.ll
index 4c36493a2cbc4..b097bbd890a14 100644
--- a/llvm/test/Verifier/initializes-attr.ll
+++ b/llvm/test/Verifier/initializes-attr.ll
@@ -1,31 +1,36 @@
-; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+; RUN: split-file %s %t
+; RUN: not llvm-as < %s %t/lower_greater_than_upper1.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=Lower-GT-Upper1
+; RUN: not llvm-as < %s %t/lower_greater_than_upper2.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=Lower-GT-Upper2
+; RUN: not llvm-as < %s %t/descending_order.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=DescOrder
+; RUN: not llvm-as < %s %t/overlapping1.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=Overlapping1
+; RUN: not llvm-as < %s %t/overlapping2.ll -o /dev/null 2>&1 | FileCheck %s --check-prefix=Overlapping2
 
-; CHECK: Attribute 'initializes' requires interval lower less than upper
-; CHECK-NEXT: ptr @lower_greater_than_upper1
+;--- lower_greater_than_upper1.ll
+; Lower-GT-Upper1: error: Invalid (unordered or overlapping) range list
 define void @lower_greater_than_upper1(ptr initializes((4, 0)) %a) {
   ret void
 }
 
-; CHECK: Attribute 'initializes' requires interval lower less than upper
-; CHECK-NEXT: ptr @lower_greater_than_upper2
+;--- lower_greater_than_upper2.ll
+; Lower-GT-Upper2: error: Invalid (unordered or overlapping) range list
 define void @lower_greater_than_upper2(ptr initializes((0, 4), (8, 6)) %a) {
   ret void
 }
 
-; CHECK: Attribute 'initializes' requires intervals in ascending order!
-; CHECK-NEXT: ptr @descending_order
+;--- descending_order.ll
+; DescOrder: error: Invalid (unordered or overlapping) range list
 define void @descending_order(ptr initializes((8, 12), (0, 4)) %a) {
   ret void
 }
 
-; CHECK: Attribute 'initializes' requires intervals merged!
-; CHECK-NEXT: ptr @overlapping1
+;--- overlapping1.ll
+; Overlapping1: error: Invalid (unordered or overlapping) range list
 define void @overlapping1(ptr initializes((0, 4), (4, 8)) %a) {
   ret void
 }
 
-; CHECK: Attribute 'initializes' requires intervals merged!
-; CHECK-NEXT: ptr @overlapping2
+;--- overlapping2.ll
+; Overlapping2: error: Invalid (unordered or overlapping) range list
 define void @overlapping2(ptr initializes((0, 4), (2, 8)) %a) {
   ret void
 }

>From 645f5776898eb95b1f8275e869bbf4673a72fbde Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Thu, 30 May 2024 23:15:30 +0000
Subject: [PATCH 30/31] Add getConstantRangeList unittest

---
 llvm/lib/IR/ConstantRangeList.cpp           |  2 +-
 llvm/unittests/IR/ConstantRangeListTest.cpp | 29 +++++++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index 24dfea479ab2d..eefefbcc2f500 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -25,7 +25,7 @@ ConstantRangeList::getConstantRangeList(ArrayRef<ConstantRange> RangesRef) {
     auto PreRange = RangesRef[i - 1];
     if (CurRange.getLower().sge(CurRange.getUpper()))
       return std::nullopt;
-    if (CurRange.getLower().sle(PreRange.getUpper()))
+    if (CurRange.getLower().sle(PreRange.getLower()))
       return std::nullopt;
     if (CurRange.getLower().sle(PreRange.getUpper()))
       return std::nullopt;
diff --git a/llvm/unittests/IR/ConstantRangeListTest.cpp b/llvm/unittests/IR/ConstantRangeListTest.cpp
index 8bdab1d0e39fe..144b5ccdc1fc0 100644
--- a/llvm/unittests/IR/ConstantRangeListTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeListTest.cpp
@@ -38,6 +38,35 @@ TEST_F(ConstantRangeListTest, Basics) {
   EXPECT_TRUE(CRL1a != CRL2);
 }
 
+TEST_F(ConstantRangeListTest, getConstantRangeList) {
+  SmallVector<ConstantRange, 2> Empty;
+  EXPECT_TRUE(ConstantRangeList::getConstantRangeList(Empty).has_value());
+
+  SmallVector<ConstantRange, 2> Valid;
+  Valid.push_back(ConstantRange(APInt(64, 0, true), APInt(64, 4, true)));
+  Valid.push_back(ConstantRange(APInt(64, 8, true), APInt(64, 12, true)));
+  EXPECT_TRUE(ConstantRangeList::getConstantRangeList(Valid).has_value());
+
+  SmallVector<ConstantRange, 2> Invalid1;
+  Invalid1.push_back(ConstantRange(APInt(64, 4, true), APInt(64, 0, true)));
+  EXPECT_EQ(ConstantRangeList::getConstantRangeList(Invalid1), std::nullopt);
+
+  SmallVector<ConstantRange, 2> Invalid2;
+  Invalid2.push_back(ConstantRange(APInt(64, 0, true), APInt(64, 4, true)));
+  Invalid2.push_back(ConstantRange(APInt(64, 12, true), APInt(64, 8, true)));
+  EXPECT_EQ(ConstantRangeList::getConstantRangeList(Invalid2), std::nullopt);
+
+  SmallVector<ConstantRange, 2> Invalid3;
+  Invalid3.push_back(ConstantRange(APInt(64, 0, true), APInt(64, 4, true)));
+  Invalid3.push_back(ConstantRange(APInt(64, 4, true), APInt(64, 8, true)));
+  EXPECT_EQ(ConstantRangeList::getConstantRangeList(Invalid3), std::nullopt);
+
+  SmallVector<ConstantRange, 2> Invalid4;
+  Invalid4.push_back(ConstantRange(APInt(64, 0, true), APInt(64, 12, true)));
+  Invalid4.push_back(ConstantRange(APInt(64, 8, true), APInt(64, 16, true)));
+  EXPECT_EQ(ConstantRangeList::getConstantRangeList(Invalid4), std::nullopt);
+}
+
 TEST_F(ConstantRangeListTest, Insert) {
   ConstantRangeList CRL;
   CRL.insert(0, 4);

>From 2a8ea9a15fc8fecc1322cf7640080b9382f3f6c0 Mon Sep 17 00:00:00 2001
From: Haopeng Liu <haopliu at google.com>
Date: Tue, 11 Jun 2024 04:52:45 +0000
Subject: [PATCH 31/31] Add Bitwidth in FoldingSetNodeId

---
 llvm/include/llvm/IR/ConstantRangeList.h  |  5 +++++
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |  2 +-
 llvm/lib/IR/AttributeImpl.h               |  1 +
 llvm/lib/IR/Attributes.cpp                |  1 +
 llvm/lib/IR/ConstantRangeList.cpp         | 26 ++++++++++++-----------
 5 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRangeList.h b/llvm/include/llvm/IR/ConstantRangeList.h
index f9b7dda03693f..7bd25ede0aa17 100644
--- a/llvm/include/llvm/IR/ConstantRangeList.h
+++ b/llvm/include/llvm/IR/ConstantRangeList.h
@@ -33,13 +33,18 @@ class [[nodiscard]] ConstantRangeList {
 public:
   ConstantRangeList() = default;
   ConstantRangeList(ArrayRef<ConstantRange> RangesRef) {
+    assert(isOrderedRanges(RangesRef));
     for (const ConstantRange &R : RangesRef) {
       assert(R.getBitWidth() == getBitWidth());
       Ranges.push_back(R);
     }
   }
+
+  // Return true if the ranges are non-overlapping and increasing.
+  static bool isOrderedRanges(ArrayRef<ConstantRange> RangesRef);
   static std::optional<ConstantRangeList>
   getConstantRangeList(ArrayRef<ConstantRange> RangesRef);
+
   SmallVectorImpl<ConstantRange>::iterator begin() { return Ranges.begin(); }
   SmallVectorImpl<ConstantRange>::iterator end() { return Ranges.end(); }
   SmallVectorImpl<ConstantRange>::const_iterator begin() const {
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index e2a98bda1375a..960ce299dec30 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -861,7 +861,7 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
 
   Expected<ConstantRange>
   readBitWidthAndConstantRange(ArrayRef<uint64_t> Record, unsigned &OpNum) {
-    if (Record.size() - OpNum < 3)
+    if (Record.size() - OpNum < 1)
       return error("Too few records for range");
     unsigned BitWidth = Record[OpNum++];
     return readConstantRange(Record, OpNum, BitWidth);
diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index 9d9f729bbc493..340880b71530a 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -138,6 +138,7 @@ class AttributeImpl : public FoldingSetNode {
                       const ConstantRangeList &CRL) {
     ID.AddInteger(Kind);
     ID.AddInteger(CRL.size());
+    ID.AddInteger(CRL.getBitWidth());
     for (auto &CR : CRL) {
       CR.getLower().Profile(ID);
       CR.getUpper().Profile(ID);
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 53476aaacb867..9b9ba0f0a269d 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -200,6 +200,7 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
   FoldingSetNodeID ID;
   ID.AddInteger(Kind);
   ID.AddInteger(CRL.size());
+  ID.AddInteger(CRL.getBitWidth());
   for (auto &CR : CRL) {
     CR.getLower().Profile(ID);
     CR.getUpper().Profile(ID);
diff --git a/llvm/lib/IR/ConstantRangeList.cpp b/llvm/lib/IR/ConstantRangeList.cpp
index eefefbcc2f500..9328b2fb8b8ca 100644
--- a/llvm/lib/IR/ConstantRangeList.cpp
+++ b/llvm/lib/IR/ConstantRangeList.cpp
@@ -11,25 +11,27 @@
 
 using namespace llvm;
 
-std::optional<ConstantRangeList>
-ConstantRangeList::getConstantRangeList(ArrayRef<ConstantRange> RangesRef) {
+bool ConstantRangeList::isOrderedRanges(ArrayRef<ConstantRange> RangesRef) {
   if (RangesRef.empty())
-    return ConstantRangeList();
+    return true;
   auto Range = RangesRef[0];
   if (Range.getLower().sge(Range.getUpper()))
-    return std::nullopt;
-  if (RangesRef.size() == 1)
-    return ConstantRangeList(RangesRef);
+    return false;
   for (unsigned i = 1; i < RangesRef.size(); i++) {
     auto CurRange = RangesRef[i];
     auto PreRange = RangesRef[i - 1];
-    if (CurRange.getLower().sge(CurRange.getUpper()))
-      return std::nullopt;
-    if (CurRange.getLower().sle(PreRange.getLower()))
-      return std::nullopt;
-    if (CurRange.getLower().sle(PreRange.getUpper()))
-      return std::nullopt;
+    if (CurRange.getLower().sge(CurRange.getUpper()) ||
+        CurRange.getLower().sle(PreRange.getLower()) ||
+        CurRange.getLower().sle(PreRange.getUpper()))
+      return false;
   }
+  return true;
+}
+
+std::optional<ConstantRangeList>
+ConstantRangeList::getConstantRangeList(ArrayRef<ConstantRange> RangesRef) {
+  if (!isOrderedRanges(RangesRef))
+    return std::nullopt;
   return ConstantRangeList(RangesRef);
 }
 



More information about the llvm-commits mailing list