[llvm] 2fdeb27 - Revert "[AAPointerInfo] track multiple constant offsets for each use"

Sameer Sahasrabuddhe via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 12 02:09:46 PST 2022


Author: Sameer Sahasrabuddhe
Date: 2022-12-12T15:39:18+05:30
New Revision: 2fdeb2779006f2f60be18ed36681c082d0300832

URL: https://github.com/llvm/llvm-project/commit/2fdeb2779006f2f60be18ed36681c082d0300832
DIFF: https://github.com/llvm/llvm-project/commit/2fdeb2779006f2f60be18ed36681c082d0300832.diff

LOG: Revert "[AAPointerInfo] track multiple constant offsets for each use"

Assertion fired in openmp-offload-amdgpu-runtime:
https://lab.llvm.org/buildbot/#/builders/193/builds/23177

This reverts commit c2a0baad1fbb21fe111fef83ec93c2d7923b9b0c.

Added: 
    llvm/test/CodeGen/AMDGPU/attributor.ll

Modified: 
    llvm/include/llvm/Transforms/IPO/Attributor.h
    llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
    llvm/lib/Transforms/IPO/AttributorAttributes.cpp
    llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll
    llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll

Removed: 
    llvm/test/CodeGen/AMDGPU/implicitarg-attributes.ll
    llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 1d2b51cd96288..28cb568f081ea 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -266,13 +266,6 @@ struct RangeTy {
     return *this;
   }
 
-  /// Comparison for sorting ranges by offset.
-  ///
-  /// Returns true if the offset \p L is less than that of \p R.
-  inline static bool OffsetLessThan(const RangeTy &L, const RangeTy &R) {
-    return L.Offset < R.Offset;
-  }
-
   /// Constants used to represent special offsets or sizes.
   /// - This assumes that Offset and Size are non-negative.
   /// - The constants should not clash with DenseMapInfo, such as EmptyKey
@@ -281,11 +274,6 @@ struct RangeTy {
   static constexpr int64_t Unknown = -2;
 };
 
-inline raw_ostream &operator<<(raw_ostream &OS, const RangeTy &R) {
-  OS << "[" << R.Offset << ", " << R.Size << "]";
-  return OS;
-}
-
 inline bool operator==(const RangeTy &A, const RangeTy &B) {
   return A.Offset == B.Offset && A.Size == B.Size;
 }
@@ -5022,187 +5010,29 @@ struct AAPointerInfo : public AbstractAttribute {
     AK_MUST_READ_WRITE = AK_MUST | AK_R | AK_W,
   };
 
-  /// A container for a list of ranges.
-  struct RangeList {
-    // The set of ranges rarely contains more than one element, and is unlikely
-    // to contain more than say four elements. So we find the middle-ground with
-    // a sorted vector. This avoids hard-coding a rarely used number like "four"
-    // into every instance of a SmallSet.
-    using RangeTy = AA::RangeTy;
-    using VecTy = SmallVector<RangeTy>;
-    using iterator = VecTy::iterator;
-    using const_iterator = VecTy::const_iterator;
-    VecTy Ranges;
-
-    RangeList(const RangeTy &R) { Ranges.push_back(R); }
-    RangeList(ArrayRef<int64_t> Offsets, int64_t Size) {
-      Ranges.reserve(Offsets.size());
-      for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
-        assert(((i + 1 == e) || Offsets[i] < Offsets[i + 1]) &&
-               "Expected strictly ascending offsets.");
-        Ranges.emplace_back(Offsets[i], Size);
-      }
-    }
-    RangeList() = default;
-
-    iterator begin() { return Ranges.begin(); }
-    iterator end() { return Ranges.end(); }
-    const_iterator begin() const { return Ranges.begin(); }
-    const_iterator end() const { return Ranges.end(); }
-
-    // Helpers required for std::set_
diff erence
-    using value_type = RangeTy;
-    void push_back(const RangeTy &R) {
-      assert((Ranges.empty() || RangeTy::OffsetLessThan(Ranges.back(), R)) &&
-             "Ensure the last element is the greatest.");
-      Ranges.push_back(R);
-    }
-
-    /// Copy ranges from \p L that are not in \p R, into \p D.
-    static void set_
diff erence(const RangeList &L, const RangeList &R,
-                               RangeList &D) {
-      std::set_
diff erence(L.begin(), L.end(), R.begin(), R.end(),
-                          std::back_inserter(D), RangeTy::OffsetLessThan);
-    }
-
-    unsigned size() const { return Ranges.size(); }
-
-    bool operator==(const RangeList &OI) const { return Ranges == OI.Ranges; }
-
-    /// Merge the ranges in \p RHS into the current ranges.
-    /// - Merging a list of  unknown ranges makes the current list unknown.
-    /// - Ranges with the same offset are merged according to RangeTy::operator&
-    /// \return true if the current RangeList changed.
-    bool merge(const RangeList &RHS) {
-      if (isUnknown())
-        return false;
-      if (RHS.isUnknown()) {
-        setUnknown();
-        return true;
-      }
-
-      if (Ranges.empty()) {
-        Ranges = RHS.Ranges;
-        return true;
-      }
-
-      bool Changed = false;
-      auto LPos = Ranges.begin();
-      for (auto &R : RHS.Ranges) {
-        auto Result = insert(LPos, R);
-        if (isUnknown())
-          return true;
-        LPos = Result.first;
-        Changed |= Result.second;
-      }
-      return Changed;
-    }
-
-    /// Insert \p R at the given iterator \p Pos, and merge if necessary.
-    ///
-    /// This assumes that all ranges before \p Pos are OffsetLessThan \p R, and
-    /// then maintains the sorted order for the suffix list.
-    ///
-    /// \return The place of insertion and true iff anything changed.
-    std::pair<iterator, bool> insert(iterator Pos, const RangeTy &R) {
-      if (isUnknown())
-        return std::make_pair(Ranges.begin(), false);
-      if (R.offsetOrSizeAreUnknown()) {
-        return std::make_pair(setUnknown(), true);
-      }
-
-      // Maintain this as a sorted vector of unique entries.
-      auto LB = std::lower_bound(Pos, Ranges.end(), R, RangeTy::OffsetLessThan);
-      if (LB == Ranges.end() || LB->Offset != R.Offset)
-        return std::make_pair(Ranges.insert(LB, R), true);
-      bool Changed = *LB != R;
-      *LB &= R;
-      if (LB->offsetOrSizeAreUnknown())
-        return std::make_pair(setUnknown(), true);
-      return std::make_pair(LB, Changed);
-    }
-
-    /// Insert the given range \p R, maintaining sorted order.
-    ///
-    /// \return The place of insertion and true iff anything changed.
-    std::pair<iterator, bool> insert(const RangeTy &R) {
-      return insert(Ranges.begin(), R);
-    }
-
-    /// Add the increment \p Inc to the offset of every range.
-    void addToAllOffsets(int64_t Inc) {
-      assert(!isUnassigned() &&
-             "Cannot increment if the offset is not yet computed!");
-      if (isUnknown())
-        return;
-      for (auto &R : Ranges) {
-        R.Offset += Inc;
-      }
-    }
-
-    /// Return true iff there is exactly one range and it is known.
-    bool isUnique() const {
-      return Ranges.size() == 1 && !Ranges.front().offsetOrSizeAreUnknown();
-    }
-
-    /// Return the unique range, assuming it exists.
-    const RangeTy &getUnique() const {
-      assert(isUnique() && "No unique range to return!");
-      return Ranges.front();
-    }
-
-    /// Return true iff the list contains an unknown range.
-    bool isUnknown() const {
-      if (isUnassigned())
-        return false;
-      if (Ranges.front().offsetOrSizeAreUnknown()) {
-        assert(Ranges.size() == 1 && "Unknown is a singleton range.");
-        return true;
-      }
-      return false;
-    }
-
-    /// Discard all ranges and insert a single unknown range.
-    iterator setUnknown() {
-      Ranges.clear();
-      Ranges.push_back(RangeTy::getUnknown());
-      return Ranges.begin();
-    }
-
-    /// Return true if no ranges have been inserted.
-    bool isUnassigned() const { return Ranges.size() == 0; }
-  };
-
   /// An access description.
   struct Access {
     Access(Instruction *I, int64_t Offset, int64_t Size,
            std::optional<Value *> Content, AccessKind Kind, Type *Ty)
-        : LocalI(I), RemoteI(I), Content(Content), Ranges(Offset, Size),
+        : LocalI(I), RemoteI(I), Content(Content), Range(Offset, Size),
           Kind(Kind), Ty(Ty) {
       verify();
     }
-    Access(Instruction *LocalI, Instruction *RemoteI, const RangeList &Ranges,
-           std::optional<Value *> Content, AccessKind K, Type *Ty)
-        : LocalI(LocalI), RemoteI(RemoteI), Content(Content), Ranges(Ranges),
-          Kind(K), Ty(Ty) {
-      if (Ranges.size() > 1) {
-        Kind = AccessKind(Kind | AK_MAY);
-        Kind = AccessKind(Kind & ~AK_MUST);
-      }
-      verify();
-    }
     Access(Instruction *LocalI, Instruction *RemoteI, int64_t Offset,
            int64_t Size, std::optional<Value *> Content, AccessKind Kind,
            Type *Ty)
         : LocalI(LocalI), RemoteI(RemoteI), Content(Content),
-          Ranges(Offset, Size), Kind(Kind), Ty(Ty) {
+          Range(Offset, Size), Kind(Kind), Ty(Ty) {
       verify();
     }
     Access(const Access &Other) = default;
+    Access(const Access &&Other)
+        : LocalI(Other.LocalI), RemoteI(Other.RemoteI), Content(Other.Content),
+          Range(Other.Range), Kind(Other.Kind), Ty(Other.Ty) {}
 
     Access &operator=(const Access &Other) = default;
     bool operator==(const Access &R) const {
-      return LocalI == R.LocalI && RemoteI == R.RemoteI && Ranges == R.Ranges &&
+      return LocalI == R.LocalI && RemoteI == R.RemoteI && Range == R.Range &&
              Content == R.Content && Kind == R.Kind;
     }
     bool operator!=(const Access &R) const { return !(*this == R); }
@@ -5210,20 +5040,16 @@ struct AAPointerInfo : public AbstractAttribute {
     Access &operator&=(const Access &R) {
       assert(RemoteI == R.RemoteI && "Expected same instruction!");
       assert(LocalI == R.LocalI && "Expected same instruction!");
-
-      // Note that every Access object corresponds to a unique Value, and only
-      // accesses to the same Value are merged. Hence we assume that all ranges
-      // are the same size. If ranges can be 
diff erent size, then the contents
-      // must be dropped.
-      Ranges.merge(R.Ranges);
-      Content =
-          AA::combineOptionalValuesInAAValueLatice(Content, R.Content, Ty);
-
-      // Combine the access kind, which results in a bitwise union.
-      // - If MAY is present in the union, then any MUST needs to be removed.
-      // - If there is more than one range, then this must be a MAY.
       Kind = AccessKind(Kind | R.Kind);
-      if ((Kind & AK_MAY) || Ranges.size() > 1) {
+      auto Before = Range;
+      Range &= R.Range;
+      if (Before.isUnassigned() || Before == Range) {
+        Content =
+            AA::combineOptionalValuesInAAValueLatice(Content, R.Content, Ty);
+      } else {
+        // Since the Range information changed, set a conservative state -- drop
+        // the contents, and assume MayAccess rather than MustAccess.
+        setWrittenValueUnknown();
         Kind = AccessKind(Kind | AK_MAY);
         Kind = AccessKind(Kind & ~AK_MUST);
       }
@@ -5236,8 +5062,6 @@ struct AAPointerInfo : public AbstractAttribute {
              "Expect must or may access, not both.");
       assert(isAssumption() + isWrite() <= 1 &&
              "Expect assumption access or write access, never both.");
-      assert((isMayAccess() || Ranges.size() == 1) &&
-             "Cannot be a must access if there are multiple ranges.");
     }
 
     /// Return the access kind.
@@ -5255,19 +5079,8 @@ struct AAPointerInfo : public AbstractAttribute {
     /// Return true if this is an assumption access.
     bool isAssumption() const { return Kind == AK_ASSUMPTION; }
 
-    bool isMustAccess() const {
-      bool MustAccess = Kind & AK_MUST;
-      assert((!MustAccess || Ranges.size() < 2) &&
-             "Cannot be a must access if there are multiple ranges.");
-      return MustAccess;
-    }
-
-    bool isMayAccess() const {
-      bool MayAccess = Kind & AK_MAY;
-      assert((MayAccess || Ranges.size() < 2) &&
-             "Cannot be a must access if there are multiple ranges.");
-      return MayAccess;
-    }
+    bool isMustAccess() const { return Kind & AK_MUST; }
+    bool isMayAccess() const { return Kind & AK_MAY; }
 
     /// Return the instruction that causes the access with respect to the local
     /// scope of the associated attribute.
@@ -5301,25 +5114,11 @@ struct AAPointerInfo : public AbstractAttribute {
     /// determined.
     std::optional<Value *> getContent() const { return Content; }
 
-    bool hasUniqueRange() const { return Ranges.isUnique(); }
-    const AA::RangeTy &getUniqueRange() const { return Ranges.getUnique(); }
-
-    /// Add a range accessed by this Access.
-    ///
-    /// If there are multiple ranges, then this is a "may access".
-    void addRange(int64_t Offset, int64_t Size) {
-      Ranges.insert({Offset, Size});
-      if (!hasUniqueRange()) {
-        Kind = AccessKind(Kind | AK_MAY);
-        Kind = AccessKind(Kind & ~AK_MUST);
-      }
-    }
-
-    const RangeList &getRanges() const { return Ranges; }
+    /// Return the offset for this access.
+    int64_t getOffset() const { return Range.Offset; }
 
-    using const_iterator = RangeList::const_iterator;
-    const_iterator begin() const { return Ranges.begin(); }
-    const_iterator end() const { return Ranges.end(); }
+    /// Return the size for this access.
+    int64_t getSize() const { return Range.Size; }
 
   private:
     /// The instruction responsible for the access with respect to the local
@@ -5333,8 +5132,8 @@ struct AAPointerInfo : public AbstractAttribute {
     /// cannot be determined.
     std::optional<Value *> Content;
 
-    /// Set of potential ranges accessed from the base pointer.
-    RangeList Ranges;
+    /// The object accessed, in terms of an offset and size in bytes.
+    AA::RangeTy Range;
 
     /// The access kind, e.g., READ, as bitset (could be more than one).
     AccessKind Kind;

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
index b332054b4ccb3..11f83af394417 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
@@ -759,7 +759,7 @@ class AMDGPUAttributor : public ModulePass {
     DenseSet<const char *> Allowed(
         {&AAAMDAttributes::ID, &AAUniformWorkGroupSize::ID,
          &AAPotentialValues::ID, &AAAMDFlatWorkGroupSize::ID, &AACallEdges::ID,
-         &AAPointerInfo::ID, &AAPotentialConstantValues::ID});
+         &AAPointerInfo::ID});
 
     AttributorConfig AC(CGUpdater);
     AC.Allowed = &Allowed;

diff  --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 520a27b1d1a66..b5ca98d811a1b 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -819,7 +819,7 @@ struct AA::PointerInfo::State : public AbstractState {
   /// OffsetBin to the bin for its new offset.
   ///
   /// \Returns CHANGED, if the state changed, UNCHANGED otherwise.
-  ChangeStatus addAccess(Attributor &A, const AAPointerInfo::RangeList &Ranges,
+  ChangeStatus addAccess(Attributor &A, int64_t Offset, int64_t Size,
                          Instruction &I, std::optional<Value *> Content,
                          AAPointerInfo::AccessKind Kind, Type *Ty,
                          Instruction *RemoteI = nullptr);
@@ -865,7 +865,7 @@ struct AA::PointerInfo::State : public AbstractState {
       bool IsExact = Range == ItRange && !Range.offsetOrSizeAreUnknown();
       for (auto Index : It.getSecond()) {
         auto &Access = AccessList[Index];
-        if (!CB(Access, IsExact && Access.hasUniqueRange()))
+        if (!CB(Access, IsExact))
           return false;
       }
     }
@@ -885,12 +885,9 @@ struct AA::PointerInfo::State : public AbstractState {
       return true;
     }
 
-    for (unsigned Index : LocalList->getSecond()) {
-      for (auto &R : AccessList[Index]) {
-        Range &= R;
-        if (Range.offsetOrSizeAreUnknown())
-          break;
-      }
+    for (auto LI : LocalList->getSecond()) {
+      auto &Access = AccessList[LI];
+      Range &= {Access.getOffset(), Access.getSize()};
     }
     return forallInterferingAccesses(Range, CB);
   }
@@ -900,11 +897,13 @@ struct AA::PointerInfo::State : public AbstractState {
   BooleanState BS;
 };
 
-ChangeStatus AA::PointerInfo::State::addAccess(
-    Attributor &A, const AAPointerInfo::RangeList &Ranges, Instruction &I,
-    std::optional<Value *> Content, AAPointerInfo::AccessKind Kind, Type *Ty,
-    Instruction *RemoteI) {
+ChangeStatus AA::PointerInfo::State::addAccess(Attributor &A, int64_t Offset,
+                                               int64_t Size, Instruction &I,
+                                               std::optional<Value *> Content,
+                                               AAPointerInfo::AccessKind Kind,
+                                               Type *Ty, Instruction *RemoteI) {
   RemoteI = RemoteI ? RemoteI : &I;
+  AAPointerInfo::Access Acc(&I, RemoteI, Offset, Size, Content, Kind, Ty);
 
   // Check if we have an access for this instruction, if not, simply add it.
   auto &LocalList = RemoteIMap[RemoteI];
@@ -918,118 +917,48 @@ ChangeStatus AA::PointerInfo::State::addAccess(
       break;
     }
   }
-
-  auto AddToBins = [&](const AAPointerInfo::RangeList &ToAdd) {
-    LLVM_DEBUG(if (ToAdd.size()) dbgs()
-                   << "[AAPointerInfo] Inserting access in new offset bins\n";);
-
-    for (auto Key : ToAdd) {
-      LLVM_DEBUG(dbgs() << "    key " << Key << "\n");
-      OffsetBins[Key].insert(AccIndex);
-    }
-  };
-
   if (!AccExists) {
-    AccessList.emplace_back(&I, RemoteI, Ranges, Content, Kind, Ty);
-    assert((AccessList.size() == AccIndex + 1) &&
-           "New Access should have been at AccIndex");
+    AccessList.push_back(Acc);
     LocalList.push_back(AccIndex);
-    AddToBins(AccessList[AccIndex].getRanges());
-    return ChangeStatus::CHANGED;
-  }
-
-  // Combine the new Access with the existing Access, and then update the
-  // mapping in the offset bins.
-  AAPointerInfo::Access Acc(&I, RemoteI, Ranges, Content, Kind, Ty);
-  auto &Current = AccessList[AccIndex];
-  auto Before = Current;
-  Current &= Acc;
-  if (Current == Before)
-    return ChangeStatus::UNCHANGED;
-
-  auto &ExistingRanges = Before.getRanges();
-  auto &NewRanges = Current.getRanges();
-
-  // Ranges that are in the old access but not the new access need to be removed
-  // from the offset bins.
-  AAPointerInfo::RangeList ToRemove;
-  AAPointerInfo::RangeList::set_
diff erence(ExistingRanges, NewRanges, ToRemove);
-  LLVM_DEBUG(if (ToRemove.size()) dbgs()
-                 << "[AAPointerInfo] Removing access from old offset bins\n";);
+  } else {
+    // The new one will be combined with the existing one.
+    auto &Current = AccessList[AccIndex];
+    auto Before = Current;
+    Current &= Acc;
+    if (Current == Before)
+      return ChangeStatus::UNCHANGED;
 
-  for (auto Key : ToRemove) {
-    LLVM_DEBUG(dbgs() << "    key " << Key << "\n");
+    Acc = Current;
+    AA::RangeTy Key{Before.getOffset(), Before.getSize()};
     assert(OffsetBins.count(Key) && "Existing Access must be in some bin.");
     auto &Bin = OffsetBins[Key];
     assert(Bin.count(AccIndex) &&
            "Expected bin to actually contain the Access.");
+    LLVM_DEBUG(dbgs() << "[AAPointerInfo] Removing Access "
+                      << AccessList[AccIndex] << " with key {" << Key.Offset
+                      << ',' << Key.Size << "}\n");
     Bin.erase(AccIndex);
   }
 
-  // Ranges that are in the new access but not the old access need to be added
-  // to the offset bins.
-  AAPointerInfo::RangeList ToAdd;
-  AAPointerInfo::RangeList::set_
diff erence(NewRanges, ExistingRanges, ToAdd);
-  AddToBins(ToAdd);
+  AA::RangeTy Key{Acc.getOffset(), Acc.getSize()};
+  LLVM_DEBUG(dbgs() << "[AAPointerInfo] Inserting Access " << Acc
+                    << " with key {" << Key.Offset << ',' << Key.Size << "}\n");
+  OffsetBins[Key].insert(AccIndex);
   return ChangeStatus::CHANGED;
 }
 
 namespace {
 
-/// A helper containing a list of offsets computed for a Use. Ideally this
-/// list should be strictly ascending, but we ensure that only when we
-/// actually translate the list of offsets to a RangeList.
+/// Helper struct, will support ranges eventually.
+///
+/// FIXME: Tracks a single Offset until we have proper support for a list of
+/// RangeTy objects.
 struct OffsetInfo {
-  using VecTy = SmallVector<int64_t>;
-  using const_iterator = VecTy::const_iterator;
-  VecTy Offsets;
-
-  const_iterator begin() const { return Offsets.begin(); }
-  const_iterator end() const { return Offsets.end(); }
+  int64_t Offset = AA::RangeTy::Unassigned;
 
-  bool operator==(const OffsetInfo &RHS) const {
-    return Offsets == RHS.Offsets;
-  }
-
-  void insert(int64_t Offset) { Offsets.push_back(Offset); }
-  bool isUnassigned() const { return Offsets.size() == 0; }
-
-  bool isUnknown() const {
-    if (isUnassigned())
-      return false;
-    if (Offsets.size() == 1)
-      return Offsets.front() == AA::RangeTy::Unknown;
-    return false;
-  }
-
-  void setUnknown() {
-    Offsets.clear();
-    Offsets.push_back(AA::RangeTy::Unknown);
-  }
-
-  void addToAll(int64_t Inc) {
-    for (auto &Offset : Offsets) {
-      Offset += Inc;
-    }
-  }
-
-  /// Copy offsets from \p R into the current list.
-  ///
-  /// Ideally all lists should be strictly ascending, but we defer that to the
-  /// actual use of the list. So we just blindly append here.
-  void merge(const OffsetInfo &R) { Offsets.append(R.Offsets); }
+  bool operator==(const OffsetInfo &OI) const { return Offset == OI.Offset; }
 };
 
-static raw_ostream &operator<<(raw_ostream &OS, const OffsetInfo &OI) {
-  ListSeparator LS;
-  OS << "[";
-  for (auto Offset : OI) {
-    OS << LS << Offset;
-  }
-  OS << "]";
-  return OS;
-}
-
 struct AAPointerInfoImpl
     : public StateWrapper<AA::PointerInfo::State, AAPointerInfo> {
   using BaseTy = StateWrapper<AA::PointerInfo::State, AAPointerInfo>;
@@ -1251,16 +1180,16 @@ struct AAPointerInfoImpl
             RAcc.getContent(), CB, *this, UsedAssumedInformation);
         AK = AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));
         AK = AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));
-
-        Changed |= addAccess(A, RAcc.getRanges(), CB, Content, AK,
-                             RAcc.getType(), RAcc.getRemoteInst());
+        Changed =
+            Changed | addAccess(A, It.first.Offset, It.first.Size, CB, Content,
+                                AK, RAcc.getType(), RAcc.getRemoteInst());
       }
     }
     return Changed;
   }
 
   ChangeStatus translateAndAddState(Attributor &A, const AAPointerInfo &OtherAA,
-                                    const OffsetInfo &Offsets, CallBase &CB) {
+                                    int64_t Offset, CallBase &CB) {
     using namespace AA::PointerInfo;
     if (!OtherAA.getState().isValidState() || !isValidState())
       return indicatePessimisticFixpoint();
@@ -1271,19 +1200,17 @@ struct AAPointerInfoImpl
     ChangeStatus Changed = ChangeStatus::UNCHANGED;
     const auto &State = OtherAAImpl.getState();
     for (const auto &It : State) {
+      AA::RangeTy Range = AA::RangeTy::getUnknown();
+      if (Offset != AA::RangeTy::Unknown &&
+          !It.first.offsetOrSizeAreUnknown()) {
+        Range = AA::RangeTy(It.first.Offset + Offset, It.first.Size);
+      }
       for (auto Index : It.getSecond()) {
         const auto &RAcc = State.getAccess(Index);
-        for (auto Offset : Offsets) {
-          auto NewRanges = Offset == AA::RangeTy::Unknown
-                               ? AA::RangeTy::getUnknown()
-                               : RAcc.getRanges();
-          if (!NewRanges.isUnknown()) {
-            NewRanges.addToAllOffsets(Offset);
-          }
-          Changed |=
-              addAccess(A, NewRanges, CB, RAcc.getContent(), RAcc.getKind(),
-                        RAcc.getType(), RAcc.getRemoteInst());
-        }
+        AccessKind AK = RAcc.getKind();
+        Changed = Changed | addAccess(A, Range.Offset, Range.Size, CB,
+                                      RAcc.getContent(), AK, RAcc.getType(),
+                                      RAcc.getRemoteInst());
       }
     }
     return Changed;
@@ -1323,102 +1250,38 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
   /// Deal with an access and signal if it was handled successfully.
   bool handleAccess(Attributor &A, Instruction &I,
                     std::optional<Value *> Content, AccessKind Kind,
-                    SmallVectorImpl<int64_t> &Offsets, ChangeStatus &Changed,
-                    Type &Ty) {
+                    int64_t Offset, ChangeStatus &Changed, Type &Ty) {
     using namespace AA::PointerInfo;
     auto Size = AA::RangeTy::Unknown;
     const DataLayout &DL = A.getDataLayout();
     TypeSize AccessSize = DL.getTypeStoreSize(&Ty);
     if (!AccessSize.isScalable())
       Size = AccessSize.getFixedSize();
-
-    // Make a strictly ascending list of offsets as required by addAccess()
-    llvm::sort(Offsets);
-    auto Last = std::unique(Offsets.begin(), Offsets.end());
-    Offsets.erase(Last, Offsets.end());
-
-    Changed = Changed | addAccess(A, {Offsets, Size}, I, Content, Kind, &Ty);
+    Changed = Changed | addAccess(A, Offset, Size, I, Content, Kind, &Ty);
     return true;
   };
 
   /// See AbstractAttribute::updateImpl(...).
   ChangeStatus updateImpl(Attributor &A) override;
 
-  void collectConstantsForGEP(Attributor &A, const DataLayout &DL,
-                              OffsetInfo &UsrOI, const OffsetInfo &PtrOI,
-                              const GEPOperator *GEP, bool &Follow);
-
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override {
     AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
   }
 };
 
-/// If the indices to the GEP can be traced to constants, incorporate all
-/// of these into UsrOI.
-void AAPointerInfoFloating::collectConstantsForGEP(
-    Attributor &A, const DataLayout &DL, OffsetInfo &UsrOI,
-    const OffsetInfo &PtrOI, const GEPOperator *GEP, bool &Follow) {
-  unsigned BitWidth = DL.getIndexTypeSizeInBits(GEP->getType());
-  MapVector<Value *, APInt> VariableOffsets;
-  APInt ConstantOffset(BitWidth, 0);
-
-  Follow = true;
-
-  if (!GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset)) {
-    UsrOI.setUnknown();
-    return;
-  }
-
-  UsrOI = PtrOI;
-  if (VariableOffsets.empty()) {
-    LLVM_DEBUG(dbgs() << "[AAPointerInfo] GEP offset is constant " << *GEP
-                      << "\n");
-    UsrOI.addToAll(ConstantOffset.getSExtValue());
-    return;
-  }
-
-  auto Union = UsrOI;
-  Union.addToAll(ConstantOffset.getSExtValue());
-
-  // Each VI in VariableOffsets has a set of potential constant values. Every
-  // combination of elements, picked one each from these sets, is separately
-  // added to the original set of offsets, thus resulting in more offsets.
-  for (const auto &VI : VariableOffsets) {
-    auto &PotentialConstantsAA = A.getAAFor<AAPotentialConstantValues>(
-        *this, IRPosition::value(*VI.first), DepClassTy::OPTIONAL);
-    if (!PotentialConstantsAA.isValidState()) {
-      LLVM_DEBUG(dbgs() << "[AAPointerInfo] GEP offset is not constant " << *GEP
-                        << "\n");
-      UsrOI.setUnknown();
-      return;
-    }
-    OffsetInfo NewUnion;
-    for (const auto &ConstOffset : PotentialConstantsAA.getAssumedSet()) {
-      auto CopyPerOffset = Union;
-      CopyPerOffset.addToAll(ConstOffset.getSExtValue() *
-                             VI.second.getZExtValue());
-      NewUnion.merge(CopyPerOffset);
-    }
-    Union = NewUnion;
-  }
-
-  UsrOI = std::move(Union);
-  return;
-}
-
 ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
   using namespace AA::PointerInfo;
   ChangeStatus Changed = ChangeStatus::UNCHANGED;
-  const DataLayout &DL = A.getDataLayout();
   Value &AssociatedValue = getAssociatedValue();
 
+  const DataLayout &DL = A.getDataLayout();
   DenseMap<Value *, OffsetInfo> OffsetInfoMap;
-  OffsetInfoMap[&AssociatedValue].insert(0);
+  OffsetInfoMap[&AssociatedValue] = OffsetInfo{0};
 
   auto HandlePassthroughUser = [&](Value *Usr, const OffsetInfo &PtrOI,
                                    bool &Follow) {
-    assert(!PtrOI.isUnassigned() &&
+    assert(PtrOI.Offset != AA::RangeTy::Unassigned &&
            "Cannot pass through if the input Ptr was not visited!");
     OffsetInfoMap[Usr] = PtrOI;
     Follow = true;
@@ -1453,14 +1316,23 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
       // already in it though.
       auto &UsrOI = OffsetInfoMap[Usr];
       auto &PtrOI = OffsetInfoMap[CurPtr];
-      Follow = true;
+      UsrOI = PtrOI;
 
-      if (PtrOI.isUnknown()) {
-        UsrOI.setUnknown();
+      // TODO: Use range information.
+      APInt GEPOffset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
+      if (PtrOI.Offset == AA::RangeTy::Unknown ||
+          !GEP->accumulateConstantOffset(DL, GEPOffset)) {
+        LLVM_DEBUG(dbgs() << "[AAPointerInfo] GEP offset not constant " << *GEP
+                          << "\n");
+        UsrOI.Offset = AA::RangeTy::Unknown;
+        Follow = true;
         return true;
       }
 
-      collectConstantsForGEP(A, DL, UsrOI, PtrOI, GEP, Follow);
+      LLVM_DEBUG(dbgs() << "[AAPointerInfo] GEP offset is constant " << *GEP
+                        << "\n");
+      UsrOI.Offset = PtrOI.Offset + GEPOffset.getZExtValue();
+      Follow = true;
       return true;
     }
     if (isa<PtrToIntInst>(Usr))
@@ -1480,17 +1352,17 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
 
       // Check if the PHI operand has already an unknown offset as we can't
       // improve on that anymore.
-      if (PtrOI.isUnknown()) {
+      if (PtrOI.Offset == AA::RangeTy::Unknown) {
         LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI operand offset unknown "
                           << *CurPtr << " in " << *Usr << "\n");
-        Follow = !UsrOI.isUnknown();
-        UsrOI.setUnknown();
+        Follow = UsrOI.Offset != AA::RangeTy::Unknown;
+        UsrOI = PtrOI;
         return true;
       }
 
       // Check if the PHI is invariant (so far).
       if (UsrOI == PtrOI) {
-        assert(!PtrOI.isUnassigned() &&
+        assert(PtrOI.Offset != AA::RangeTy::Unassigned &&
                "Cannot assign if the current Ptr was not visited!");
         LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI is invariant (so far)");
         return true;
@@ -1504,13 +1376,9 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
           DL, Offset, /* AllowNonInbounds */ true);
       auto It = OffsetInfoMap.find(CurPtrBase);
       if (It != OffsetInfoMap.end()) {
-        auto BaseOI = It->getSecond();
-        BaseOI.addToAll(Offset.getZExtValue());
-        if (IsFirstPHIUser || BaseOI == UsrOI) {
-          LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI is invariant " << *CurPtr
-                            << " in " << *Usr << "\n");
+        Offset += It->getSecond().Offset;
+        if (IsFirstPHIUser || Offset == UsrOI.Offset)
           return HandlePassthroughUser(Usr, PtrOI, Follow);
-        }
         LLVM_DEBUG(
             dbgs() << "[AAPointerInfo] PHI operand pointer offset mismatch "
                    << *CurPtr << " in " << *Usr << "\n");
@@ -1520,7 +1388,8 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
       }
 
       // TODO: Approximate in case we know the direction of the recurrence.
-      UsrOI.setUnknown();
+      UsrOI = PtrOI;
+      UsrOI.Offset = AA::RangeTy::Unknown;
       Follow = true;
       return true;
     }
@@ -1534,7 +1403,7 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
       else
         AK = AccessKind(AK | AccessKind::AK_MAY);
       if (!handleAccess(A, *LoadI, /* Content */ nullptr, AK,
-                        OffsetInfoMap[CurPtr].Offsets, Changed,
+                        OffsetInfoMap[CurPtr].Offset, Changed,
                         *LoadI->getType()))
         return false;
 
@@ -1614,7 +1483,7 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
 
       return handleAccess(
           A, *Assumption.second, Assumption.first, AccessKind::AK_ASSUMPTION,
-          OffsetInfoMap[CurPtr].Offsets, Changed, *LoadI->getType());
+          OffsetInfoMap[CurPtr].Offset, Changed, *LoadI->getType());
     }
 
     auto HandleStoreLike = [&](Instruction &I, Value *ValueOp, Type &ValueTy,
@@ -1640,7 +1509,7 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
       if (ValueOp)
         Content = A.getAssumedSimplified(
             *ValueOp, *this, UsedAssumedInformation, AA::Interprocedural);
-      return handleAccess(A, I, Content, AK, OffsetInfoMap[CurPtr].Offsets,
+      return handleAccess(A, I, Content, AK, OffsetInfoMap[CurPtr].Offset,
                           Changed, ValueTy);
     };
 
@@ -1667,7 +1536,8 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
         const auto &CSArgPI = A.getAAFor<AAPointerInfo>(
             *this, IRPosition::callsite_argument(*CB, ArgNo),
             DepClassTy::REQUIRED);
-        Changed = translateAndAddState(A, CSArgPI, OffsetInfoMap[CurPtr], *CB) |
+        Changed = translateAndAddState(A, CSArgPI, OffsetInfoMap[CurPtr].Offset,
+                                       *CB) |
                   Changed;
         return isValidState();
       }
@@ -1686,8 +1556,8 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
       LLVM_DEBUG({
         if (!(OffsetInfoMap[NewU] == OffsetInfoMap[OldU])) {
           dbgs() << "[AAPointerInfo] Equivalent use callback failed: "
-                 << OffsetInfoMap[NewU] << " vs " << OffsetInfoMap[OldU]
-                 << "\n";
+                 << OffsetInfoMap[NewU].Offset << " vs "
+                 << OffsetInfoMap[OldU].Offset << "\n";
         }
       });
       return OffsetInfoMap[NewU] == OffsetInfoMap[OldU];
@@ -1767,7 +1637,7 @@ struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
         auto Kind =
             ArgNo == 0 ? AccessKind::AK_MUST_WRITE : AccessKind::AK_MUST_READ;
         Changed =
-            Changed | addAccess(A, {0, LengthVal}, *MI, nullptr, Kind, nullptr);
+            Changed | addAccess(A, 0, LengthVal, *MI, nullptr, Kind, nullptr);
       }
       LLVM_DEBUG({
         dbgs() << "Accesses by bin after update:\n";
@@ -1805,8 +1675,8 @@ struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
     bool ReadOnly = AA::isAssumedReadOnly(A, getIRPosition(), *this, IsKnown);
     auto Kind =
         ReadOnly ? AccessKind::AK_MAY_READ : AccessKind::AK_MAY_READ_WRITE;
-    return addAccess(A, AA::RangeTy::getUnknown(), *getCtxI(), nullptr, Kind,
-                     nullptr);
+    return addAccess(A, AA::RangeTy::Unknown, AA::RangeTy::Unknown, *getCtxI(),
+                     nullptr, Kind, nullptr);
   }
 
   /// See AbstractAttribute::trackStatistics()

diff  --git a/llvm/test/CodeGen/AMDGPU/implicitarg-attributes.ll b/llvm/test/CodeGen/AMDGPU/attributor.ll
similarity index 52%
rename from llvm/test/CodeGen/AMDGPU/implicitarg-attributes.ll
rename to llvm/test/CodeGen/AMDGPU/attributor.ll
index 0fba6abbc675b..b7a219958823a 100644
--- a/llvm/test/CodeGen/AMDGPU/implicitarg-attributes.ll
+++ b/llvm/test/CodeGen/AMDGPU/attributor.ll
@@ -6,12 +6,10 @@ target triple = "amdgcn-amd-amdhsa"
 ; offsets of the phi cannot be determined, and hence the attirbutor assumes that
 ; hostcall is in use.
 
-; CHECK-LABEL: amdhsa.kernels:
 ; CHECK: .value_kind:     hidden_hostcall_buffer
 ; CHECK: .value_kind:     hidden_multigrid_sync_arg
-; CHECK-LABEL: .name:           kernel_1
 
-define amdgpu_kernel void @kernel_1(i32 addrspace(1)* %a, i64 %index1, i64 %index2, i1 %cond)  {
+define amdgpu_kernel void @the_kernel(i32 addrspace(1)* %a, i64 %index1, i64 %index2, i1 %cond)  {
 entry:
   %tmp7 = tail call i8 addrspace(4)* @llvm.amdgcn.implicitarg.ptr()
   br i1 %cond, label %old, label %new
@@ -37,32 +35,6 @@ join:                                             ; preds = %new, %old
   ret void
 }
 
-; The call to intrinsic implicitarg_ptr is combined with an offset produced by
-; select'ing between two constants, before it is eventually used in a GEP to
-; form the address of a load. This test ensures that AAPointerInfo can look
-; through the select to maintain a set of indices, so that it can precisely
-; determine that hostcall and other expensive implicit args are not in use.
-
-; CHECK-NOT: hidden_hostcall_buffer
-; CHECK-NOT: hidden_multigrid_sync_arg
-; CHECK-LABEL: .name:           kernel_2
-
-define amdgpu_kernel void @kernel_2(i32 addrspace(1)* %a, i1 %cond)  {
-entry:
-  %tmp7 = tail call i8 addrspace(4)* @llvm.amdgcn.implicitarg.ptr()
-  %tmp5 = select i1 %cond, i64 12, i64 18
-  %tmp6 = getelementptr inbounds i8, i8 addrspace(4)* %tmp7, i64 %tmp5
-  %tmp8 = bitcast i8 addrspace(4)* %tmp6 to i16 addrspace(4)*
-
-  ;;; THIS USE is where multiple offsets are possible, relative to implicitarg_ptr
-  %tmp9 = load i16, i16 addrspace(4)* %tmp8, align 2
-
-  %idx.ext = sext i16 %tmp9 to i64
-  %add.ptr3 = getelementptr inbounds i32, i32 addrspace(1)* %a, i64 %idx.ext
-  %tmp16 = atomicrmw add i32 addrspace(1)* %add.ptr3, i32 15 syncscope("agent-one-as") monotonic, align 4
-  ret void
-}
-
 declare i32 @llvm.amdgcn.workitem.id.x()
 
 declare align 4 i8 addrspace(4)* @llvm.amdgcn.implicitarg.ptr()

diff  --git a/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll
index 8e2a3472cb381..a28b791f334da 100644
--- a/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll
+++ b/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll
@@ -17,12 +17,18 @@ entry:
 }
 
 define internal i8 @read_arg_index(i8* %p, i64 %index) {
+; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; TUNIT-LABEL: define {{[^@]+}}@read_arg_index
+; TUNIT-SAME: (i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[L:%.*]] = load i8, i8* [[P]], align 2
+; TUNIT-NEXT:    ret i8 [[L]]
+;
 ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
 ; CGSCC-LABEL: define {{[^@]+}}@read_arg_index
-; CGSCC-SAME: (i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[P:%.*]]) #[[ATTR0]] {
+; CGSCC-SAME: (i8* nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P:%.*]]) #[[ATTR0]] {
 ; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[G:%.*]] = getelementptr inbounds i8, i8* [[P]], i64 2
-; CGSCC-NEXT:    [[L:%.*]] = load i8, i8* [[G]], align 1
+; CGSCC-NEXT:    [[L:%.*]] = load i8, i8* [[P]], align 1
 ; CGSCC-NEXT:    ret i8 [[L]]
 ;
 entry:
@@ -34,7 +40,7 @@ entry:
 define i8 @call_simplifiable_1() {
 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
 ; TUNIT-LABEL: define {{[^@]+}}@call_simplifiable_1
-; TUNIT-SAME: () #[[ATTR0:[0-9]+]] {
+; TUNIT-SAME: () #[[ATTR1:[0-9]+]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
 ; TUNIT-NEXT:    [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
@@ -47,7 +53,7 @@ define i8 @call_simplifiable_1() {
 ; CGSCC-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
 ; CGSCC-NEXT:    [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
 ; CGSCC-NEXT:    store i8 2, i8* [[I0]], align 2
-; CGSCC-NEXT:    [[R:%.*]] = call i8 @read_arg(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]]) #[[ATTR4:[0-9]+]]
+; CGSCC-NEXT:    [[R:%.*]] = call i8 @read_arg(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]]) #[[ATTR3:[0-9]+]]
 ; CGSCC-NEXT:    ret i8 [[R]]
 ;
 entry:
@@ -77,8 +83,8 @@ define internal i8 @sum_two_same_loads(i8* %p) {
 ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(argmem: read)
 ; CGSCC-LABEL: define {{[^@]+}}@sum_two_same_loads
 ; CGSCC-SAME: (i8* nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P:%.*]]) #[[ATTR2:[0-9]+]] {
-; CGSCC-NEXT:    [[X:%.*]] = call i8 @read_arg_1(i8* nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P]]) #[[ATTR5:[0-9]+]]
-; CGSCC-NEXT:    [[Y:%.*]] = call i8 @read_arg_1(i8* nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P]]) #[[ATTR5]]
+; CGSCC-NEXT:    [[X:%.*]] = call i8 @read_arg_1(i8* nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P]]) #[[ATTR4:[0-9]+]]
+; CGSCC-NEXT:    [[Y:%.*]] = call i8 @read_arg_1(i8* nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P]]) #[[ATTR4]]
 ; CGSCC-NEXT:    [[Z:%.*]] = add nsw i8 [[X]], [[Y]]
 ; CGSCC-NEXT:    ret i8 [[Z]]
 ;
@@ -91,7 +97,7 @@ define internal i8 @sum_two_same_loads(i8* %p) {
 define i8 @call_simplifiable_2() {
 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
 ; TUNIT-LABEL: define {{[^@]+}}@call_simplifiable_2
-; TUNIT-SAME: () #[[ATTR0]] {
+; TUNIT-SAME: () #[[ATTR1]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
 ; TUNIT-NEXT:    [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
@@ -107,7 +113,7 @@ define i8 @call_simplifiable_2() {
 ; CGSCC-NEXT:    store i8 2, i8* [[I0]], align 2
 ; CGSCC-NEXT:    [[I1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 3
 ; CGSCC-NEXT:    store i8 3, i8* [[I1]], align 1
-; CGSCC-NEXT:    [[R:%.*]] = call i8 @sum_two_same_loads(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[R:%.*]] = call i8 @sum_two_same_loads(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]]) #[[ATTR3]]
 ; CGSCC-NEXT:    ret i8 [[R]]
 ;
 entry:
@@ -120,32 +126,32 @@ entry:
   ret i8 %r
 }
 
-define i8 @call_simplifiable_3() {
+define i8 @call_not_simplifiable_1() {
 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@call_simplifiable_3
-; TUNIT-SAME: () #[[ATTR0]] {
+; TUNIT-LABEL: define {{[^@]+}}@call_not_simplifiable_1
+; TUNIT-SAME: () #[[ATTR1]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; TUNIT-NEXT:    [[I2:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
-; TUNIT-NEXT:    ret i8 2
+; TUNIT-NEXT:    [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
+; TUNIT-NEXT:    store i8 2, i8* [[I0]], align 2
+; TUNIT-NEXT:    [[R:%.*]] = call i8 @read_arg_index(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]]) #[[ATTR2:[0-9]+]]
+; TUNIT-NEXT:    ret i8 [[R]]
 ;
 ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@call_simplifiable_3
+; CGSCC-LABEL: define {{[^@]+}}@call_not_simplifiable_1
 ; CGSCC-SAME: () #[[ATTR1]] {
 ; CGSCC-NEXT:  entry:
 ; CGSCC-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CGSCC-NEXT:    [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0
-; CGSCC-NEXT:    [[I2:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
-; CGSCC-NEXT:    store i8 2, i8* [[I2]], align 2
-; CGSCC-NEXT:    [[R:%.*]] = call i8 @read_arg_index(i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[I0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
+; CGSCC-NEXT:    store i8 2, i8* [[I0]], align 2
+; CGSCC-NEXT:    [[R:%.*]] = call i8 @read_arg_index(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]]) #[[ATTR3]]
 ; CGSCC-NEXT:    ret i8 [[R]]
 ;
 entry:
   %Bytes = alloca [1024 x i8], align 16
-  %i0 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 0
-  %i2 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 2
-  store i8 2, i8* %i2, align 1
-  %r = call i8 @read_arg_index(i8* %i0, i64 2)
+  %i0 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 2
+  store i8 2, i8* %i0, align 1
+  %r = call i8 @read_arg_index(i8* %i0, i64 0)
   ret i8 %r
 }
 
@@ -154,7 +160,7 @@ entry:
 define internal i8 @read_arg_2(i8* %p) {
 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
 ; TUNIT-LABEL: define {{[^@]+}}@read_arg_2
-; TUNIT-SAME: (i8* nocapture nofree noundef nonnull readonly dereferenceable(971) [[P:%.*]]) #[[ATTR1:[0-9]+]] {
+; TUNIT-SAME: (i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[P:%.*]]) #[[ATTR0]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[L:%.*]] = load i8, i8* [[P]], align 1
 ; TUNIT-NEXT:    ret i8 [[L]]
@@ -174,17 +180,17 @@ entry:
 define internal i8 @sum_two_
diff erent_loads(i8* %p, i8* %q) {
 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
 ; TUNIT-LABEL: define {{[^@]+}}@sum_two_
diff erent_loads
-; TUNIT-SAME: (i8* nocapture nofree nonnull readonly dereferenceable(972) [[P:%.*]], i8* nocapture nofree noundef nonnull readonly dereferenceable(971) [[Q:%.*]]) #[[ATTR1]] {
-; TUNIT-NEXT:    [[X:%.*]] = call i8 @read_arg_2(i8* nocapture nofree nonnull readonly dereferenceable(972) [[P]]) #[[ATTR3:[0-9]+]]
-; TUNIT-NEXT:    [[Y:%.*]] = call i8 @read_arg_2(i8* nocapture nofree noundef nonnull readonly dereferenceable(971) [[Q]]) #[[ATTR3]]
+; TUNIT-SAME: (i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[P:%.*]], i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[Q:%.*]]) #[[ATTR0]] {
+; TUNIT-NEXT:    [[X:%.*]] = call i8 @read_arg_2(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[P]]) #[[ATTR2]]
+; TUNIT-NEXT:    [[Y:%.*]] = call i8 @read_arg_2(i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[Q]]) #[[ATTR2]]
 ; TUNIT-NEXT:    [[Z:%.*]] = add nsw i8 [[X]], [[Y]]
 ; TUNIT-NEXT:    ret i8 [[Z]]
 ;
 ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(argmem: read)
 ; CGSCC-LABEL: define {{[^@]+}}@sum_two_
diff erent_loads
-; CGSCC-SAME: (i8* nocapture nofree noundef nonnull readonly dereferenceable(972) [[P:%.*]], i8* nocapture nofree noundef nonnull readonly dereferenceable(971) [[Q:%.*]]) #[[ATTR2]] {
-; CGSCC-NEXT:    [[X:%.*]] = call i8 @read_arg_2(i8* nocapture nofree noundef nonnull readonly dereferenceable(972) [[P]]) #[[ATTR5]]
-; CGSCC-NEXT:    [[Y:%.*]] = call i8 @read_arg_2(i8* nocapture nofree noundef nonnull readonly dereferenceable(971) [[Q]]) #[[ATTR5]]
+; CGSCC-SAME: (i8* nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P:%.*]], i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[Q:%.*]]) #[[ATTR2]] {
+; CGSCC-NEXT:    [[X:%.*]] = call i8 @read_arg_2(i8* nocapture nofree noundef nonnull readonly dereferenceable(1022) [[P]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[Y:%.*]] = call i8 @read_arg_2(i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[Q]]) #[[ATTR4]]
 ; CGSCC-NEXT:    [[Z:%.*]] = add nsw i8 [[X]], [[Y]]
 ; CGSCC-NEXT:    ret i8 [[Z]]
 ;
@@ -194,104 +200,52 @@ define internal i8 @sum_two_
diff erent_loads(i8* %p, i8* %q) {
   ret i8 %z
 }
 
-define i8 @call_partially_simplifiable_1() {
+define i8 @call_not_simplifiable_2() {
 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@call_partially_simplifiable_1
-; TUNIT-SAME: () #[[ATTR0]] {
+; TUNIT-LABEL: define {{[^@]+}}@call_not_simplifiable_2
+; TUNIT-SAME: () #[[ATTR1]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; TUNIT-NEXT:    [[I2:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
-; TUNIT-NEXT:    store i8 2, i8* [[I2]], align 2
-; TUNIT-NEXT:    [[I3:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 3
-; TUNIT-NEXT:    store i8 3, i8* [[I3]], align 1
-; TUNIT-NEXT:    [[I4:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 4
-; TUNIT-NEXT:    [[R:%.*]] = call i8 @sum_two_
diff erent_loads(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I2]], i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[I3]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
+; TUNIT-NEXT:    store i8 2, i8* [[I0]], align 2
+; TUNIT-NEXT:    [[I1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 3
+; TUNIT-NEXT:    store i8 3, i8* [[I1]], align 1
+; TUNIT-NEXT:    [[BASE:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0
+; TUNIT-NEXT:    [[R:%.*]] = call i8 @sum_two_
diff erent_loads(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]], i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[I1]]) #[[ATTR2]]
 ; TUNIT-NEXT:    ret i8 [[R]]
 ;
 ; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@call_partially_simplifiable_1
+; CGSCC-LABEL: define {{[^@]+}}@call_not_simplifiable_2
 ; CGSCC-SAME: () #[[ATTR1]] {
 ; CGSCC-NEXT:  entry:
 ; CGSCC-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CGSCC-NEXT:    [[I2:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
-; CGSCC-NEXT:    store i8 2, i8* [[I2]], align 2
-; CGSCC-NEXT:    [[I3:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 3
-; CGSCC-NEXT:    store i8 3, i8* [[I3]], align 1
-; CGSCC-NEXT:    [[I4:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 4
-; CGSCC-NEXT:    store i8 4, i8* [[I4]], align 4
-; CGSCC-NEXT:    [[R:%.*]] = call i8 @sum_two_
diff erent_loads(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I2]], i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[I3]]) #[[ATTR4]]
-; CGSCC-NEXT:    ret i8 [[R]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %i2 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 2
-  store i8 2, i8* %i2
-  %i3 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 3
-  store i8 3, i8* %i3
-  %i4 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 4
-  ;;; This store is redundant, hence removed.
-  store i8 4, i8* %i4
-  %r = call i8 @sum_two_
diff erent_loads(i8* %i2, i8* %i3)
-  ret i8 %r
-}
-
-define i8 @call_partially_simplifiable_2(i1 %cond) {
-; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn
-; TUNIT-LABEL: define {{[^@]+}}@call_partially_simplifiable_2
-; TUNIT-SAME: (i1 [[COND:%.*]]) #[[ATTR2:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; TUNIT-NEXT:    [[I51:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 51
-; TUNIT-NEXT:    [[I52:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 52
-; TUNIT-NEXT:    store i8 2, i8* [[I52]], align 4
-; TUNIT-NEXT:    [[I53:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 53
-; TUNIT-NEXT:    store i8 3, i8* [[I53]], align 1
-; TUNIT-NEXT:    [[I54:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 54
-; TUNIT-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8* [[I51]], i8* [[I52]]
-; TUNIT-NEXT:    [[R:%.*]] = call i8 @sum_two_
diff erent_loads(i8* nocapture nofree nonnull readonly dereferenceable(972) [[SEL]], i8* nocapture nofree noundef nonnull readonly dereferenceable(971) [[I53]]) #[[ATTR3]]
-; TUNIT-NEXT:    ret i8 [[R]]
-;
-; CGSCC: Function Attrs: nofree nosync nounwind willreturn
-; CGSCC-LABEL: define {{[^@]+}}@call_partially_simplifiable_2
-; CGSCC-SAME: (i1 [[COND:%.*]]) #[[ATTR3:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CGSCC-NEXT:    [[I51:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 51
-; CGSCC-NEXT:    [[I52:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 52
-; CGSCC-NEXT:    store i8 2, i8* [[I52]], align 4
-; CGSCC-NEXT:    [[I53:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 53
-; CGSCC-NEXT:    store i8 3, i8* [[I53]], align 1
-; CGSCC-NEXT:    [[I54:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 54
-; CGSCC-NEXT:    store i8 4, i8* [[I54]], align 2
-; CGSCC-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8* [[I51]], i8* [[I52]]
-; CGSCC-NEXT:    [[R:%.*]] = call i8 @sum_two_
diff erent_loads(i8* nocapture nofree noundef nonnull readonly dereferenceable(972) [[SEL]], i8* nocapture nofree noundef nonnull readonly dereferenceable(971) [[I53]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 2
+; CGSCC-NEXT:    store i8 2, i8* [[I0]], align 2
+; CGSCC-NEXT:    [[I1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 3
+; CGSCC-NEXT:    store i8 3, i8* [[I1]], align 1
+; CGSCC-NEXT:    [[BASE:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0
+; CGSCC-NEXT:    [[R:%.*]] = call i8 @sum_two_
diff erent_loads(i8* nocapture nofree noundef nonnull readonly align 2 dereferenceable(1022) [[I0]], i8* nocapture nofree noundef nonnull readonly dereferenceable(1021) [[I1]]) #[[ATTR3]]
 ; CGSCC-NEXT:    ret i8 [[R]]
 ;
 entry:
   %Bytes = alloca [1024 x i8], align 16
-  %i51 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 51
-  %i52 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 52
-  store i8 2, i8* %i52
-  %i53 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 53
-  store i8 3, i8* %i53
-  %i54 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 54
-  ;;; This store is redundant, hence removed. Not affected by the select.
-  store i8 4, i8* %i54
-  %sel = select i1 %cond, i8* %i51, i8 *%i52
-  %r = call i8 @sum_two_
diff erent_loads(i8* %sel, i8* %i53)
+  %i0 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 2
+  store i8 2, i8* %i0
+  %i1 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 3
+  store i8 3, i8* %i1
+  %base = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 0
+  %r = call i8 @sum_two_
diff erent_loads(i8* %i0, i8* %i1)
   ret i8 %r
 }
 
 ;.
-; TUNIT: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
-; TUNIT: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind willreturn }
-; TUNIT: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn }
+; TUNIT: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
+; TUNIT: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn }
 ;.
 ; CGSCC: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
 ; CGSCC: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn memory(none) }
 ; CGSCC: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn memory(argmem: read) }
-; CGSCC: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn }
-; CGSCC: attributes #[[ATTR4]] = { willreturn }
-; CGSCC: attributes #[[ATTR5]] = { willreturn memory(read) }
+; CGSCC: attributes #[[ATTR3]] = { willreturn }
+; CGSCC: attributes #[[ATTR4]] = { willreturn memory(read) }
 ;.

diff  --git a/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll b/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll
deleted file mode 100644
index 6669f34468695..0000000000000
--- a/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll
+++ /dev/null
@@ -1,342 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
-
-%struct.T = type { i32, [10 x [20 x i8]] }
-
-define i8 @select_offsets_simplifiable_1(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_1
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0:[0-9]+]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
-; CHECK-NEXT:    store i8 23, i8* [[GEP23]], align 4
-; CHECK-NEXT:    [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 29
-; CHECK-NEXT:    store i8 29, i8* [[GEP29]], align 4
-; CHECK-NEXT:    [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
-; CHECK-NEXT:    store i8 7, i8* [[GEP7]], align 4
-; CHECK-NEXT:    [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 31
-; CHECK-NEXT:    [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
-; CHECK-NEXT:    [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP_SEL]], align 4
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-
-  %gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
-  store i8 23, i8* %gep23, align 4
-  %gep29 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 29
-  store i8 29, i8* %gep29, align 4
-  %gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
-  store i8 7, i8* %gep7, align 4
-
-  ;; This store is redundant, hence removed.
-  %gep31 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 31
-  store i8 42, i8* %gep31, align 4
-
-  %sel0 = select i1 %cnd1, i64 23, i64 29
-  %sel1 = select i1 %cnd2, i64 %sel0, i64 7
-  %gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
-  %i = load i8, i8* %gep.sel, align 4
-  ret i8 %i
-}
-
-define i8 @select_offsets_simplifiable_2(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_2
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
-; CHECK-NEXT:    store i8 23, i8* [[GEP23]], align 4
-; CHECK-NEXT:    [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 29
-; CHECK-NEXT:    store i8 29, i8* [[GEP29]], align 4
-; CHECK-NEXT:    [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
-; CHECK-NEXT:    store i8 7, i8* [[GEP7]], align 4
-; CHECK-NEXT:    [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 31
-; CHECK-NEXT:    [[SEL0:%.*]] = select i1 [[CND1]], i64 20, i64 26
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 4
-; CHECK-NEXT:    [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
-; CHECK-NEXT:    [[GEP_PLUS:%.*]] = getelementptr inbounds i8, i8* [[GEP_SEL]], i64 3
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP_PLUS]], align 4
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-
-  %gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
-  store i8 23, i8* %gep23, align 4
-  %gep29 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 29
-  store i8 29, i8* %gep29, align 4
-  %gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
-  store i8 7, i8* %gep7, align 4
-
-  ;; This store is redundant, hence removed.
-  %gep31 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 31
-  store i8 42, i8* %gep31, align 4
-
-  ;; Adjust the offsets so that they match the stores after adding 3
-  %sel0 = select i1 %cnd1, i64 20, i64 26
-  %sel1 = select i1 %cnd2, i64 %sel0, i64 4
-  %gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
-  %gep.plus = getelementptr inbounds i8, i8* %gep.sel, i64 3
-  %i = load i8, i8* %gep.plus, align 4
-  ret i8 %i
-}
-
-define i8 @select_offsets_simplifiable_3(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_3
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BUNDLE:%.*]] = alloca [[STRUCT_T:%.*]], align 64
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CND1]], i64 1, i64 3
-; CHECK-NEXT:    [[SEL2:%.*]] = select i1 [[CND2]], i64 5, i64 11
-; CHECK-NEXT:    [[GEP_SEL:%.*]] = getelementptr inbounds [[STRUCT_T]], %struct.T* [[BUNDLE]], i64 0, i32 1, i64 [[SEL1]], i64 [[SEL2]]
-; CHECK-NEXT:    ret i8 100
-;
-entry:
-  %bundle = alloca %struct.T, align 64
-  %gep.fixed = getelementptr inbounds %struct.T, %struct.T* %bundle, i64 0, i32 1, i64 1, i64 1
-  store i8 100, i8* %gep.fixed, align 4
-  %sel1 = select i1 %cnd1, i64 1, i64 3
-  %sel2 = select i1 %cnd2, i64 5, i64 11
-  %gep.sel = getelementptr inbounds %struct.T, %struct.T* %bundle, i64 0, i32 1, i64 %sel1, i64 %sel2
-  store i8 42, i8* %gep.sel, align 4
-  %i = load i8, i8* %gep.fixed, align 4
-  ret i8 %i
-}
-
-define i8 @select_offsets_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_1
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
-; CHECK-NEXT:    [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
-; CHECK-NEXT:    store i8 100, i8* [[GEP23]], align 4
-; CHECK-NEXT:    [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP_SEL]], align 4
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %sel0 = select i1 %cnd1, i64 23, i64 29
-  %sel1 = select i1 %cnd2, i64 %sel0, i64 7
-  %gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
-  store i8 100, i8* %gep23, align 4
-  %gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
-  %i = load i8, i8* %gep.sel, align 4
-  ret i8 %i
-}
-
-define i8 @select_offsets_not_simplifiable_2(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_2
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
-; CHECK-NEXT:    [[GEP32:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 32
-; CHECK-NEXT:    store i8 100, i8* [[GEP32]], align 16
-; CHECK-NEXT:    [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
-; CHECK-NEXT:    [[GEP_PLUS:%.*]] = getelementptr inbounds i8, i8* [[GEP_SEL]], i64 3
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP_PLUS]], align 4
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %sel0 = select i1 %cnd1, i64 23, i64 29
-  %sel1 = select i1 %cnd2, i64 %sel0, i64 7
-  %gep32 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 32
-  store i8 100, i8* %gep32, align 4
-  %gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
-  %gep.plus = getelementptr inbounds i8, i8* %gep.sel, i64 3
-  %i = load i8, i8* %gep.plus, align 4
-  ret i8 %i
-}
-
-define i8 @select_offsets_not_simplifiable_3(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_3
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
-; CHECK-NEXT:    [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
-; CHECK-NEXT:    store i8 100, i8* [[GEP_SEL]], align 4
-; CHECK-NEXT:    [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 29
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP29]], align 4
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %sel0 = select i1 %cnd1, i64 23, i64 29
-  %sel1 = select i1 %cnd2, i64 %sel0, i64 7
-  %gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
-  store i8 100, i8* %gep.sel, align 4
-  %gep29 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 29
-  %i = load i8, i8* %gep29, align 4
-  ret i8 %i
-}
-
-define i8 @select_offsets_not_simplifiable_4(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_4
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
-; CHECK-NEXT:    [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
-; CHECK-NEXT:    [[GEP_PLUS:%.*]] = getelementptr inbounds i8, i8* [[GEP_SEL]], i64 3
-; CHECK-NEXT:    store i8 100, i8* [[GEP_PLUS]], align 4
-; CHECK-NEXT:    [[GEP32:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 32
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP32]], align 16
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %sel0 = select i1 %cnd1, i64 23, i64 29
-  %sel1 = select i1 %cnd2, i64 %sel0, i64 7
-  %gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
-  %gep.plus = getelementptr inbounds i8, i8* %gep.sel, i64 3
-  store i8 100, i8* %gep.plus, align 4
-  %gep32 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 32
-  %i = load i8, i8* %gep32, align 4
-  ret i8 %i
-}
-
-define i8 @select_offsets_not_simplifiable_5(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_5
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BUNDLE:%.*]] = alloca [[STRUCT_T:%.*]], align 64
-; CHECK-NEXT:    [[GEP_FIXED:%.*]] = getelementptr inbounds [[STRUCT_T]], %struct.T* [[BUNDLE]], i64 0, i32 1, i64 3, i64 5
-; CHECK-NEXT:    store i8 100, i8* [[GEP_FIXED]], align 4
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CND1]], i64 1, i64 3
-; CHECK-NEXT:    [[SEL2:%.*]] = select i1 [[CND2]], i64 5, i64 11
-; CHECK-NEXT:    [[GEP_SEL:%.*]] = getelementptr inbounds [[STRUCT_T]], %struct.T* [[BUNDLE]], i64 0, i32 1, i64 [[SEL1]], i64 [[SEL2]]
-; CHECK-NEXT:    store i8 42, i8* [[GEP_SEL]], align 4
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP_FIXED]], align 4
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %bundle = alloca %struct.T, align 64
-  %gep.fixed = getelementptr inbounds %struct.T, %struct.T* %bundle, i64 0, i32 1, i64 3, i64 5
-  store i8 100, i8* %gep.fixed, align 4
-  %sel1 = select i1 %cnd1, i64 1, i64 3
-  %sel2 = select i1 %cnd2, i64 5, i64 11
-  %gep.sel = getelementptr inbounds %struct.T, %struct.T* %bundle, i64 0, i32 1, i64 %sel1, i64 %sel2
-
-  ;; This store prevents the constant 100 from being propagated to ret
-  store i8 42, i8* %gep.sel, align 4
-
-  %i = load i8, i8* %gep.fixed, align 4
-  ret i8 %i
-}
-
-define i8 @select_gep_simplifiable_1(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(write)
-; CHECK-LABEL: define {{[^@]+}}@select_gep_simplifiable_1
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1:[0-9]+]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
-; CHECK-NEXT:    [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
-; CHECK-NEXT:    [[SEL_PTR:%.*]] = select i1 [[CND1]], i8* [[GEP7]], i8* [[GEP23]]
-; CHECK-NEXT:    store i8 42, i8* [[SEL_PTR]], align 4
-; CHECK-NEXT:    ret i8 21
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %gep3 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 3
-  store i8 21, i8* %gep3, align 4
-  %gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
-  %gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
-  %sel.ptr = select i1 %cnd1, i8* %gep7, i8* %gep23
-  store i8 42, i8* %sel.ptr, align 4
-  %i = load i8, i8* %gep3, align 4
-  ret i8 %i
-}
-
-define i8 @select_gep_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn
-; CHECK-LABEL: define {{[^@]+}}@select_gep_not_simplifiable_1
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR2:[0-9]+]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
-; CHECK-NEXT:    [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
-; CHECK-NEXT:    [[SEL_PTR:%.*]] = select i1 [[CND1]], i8* [[GEP7]], i8* [[GEP23]]
-; CHECK-NEXT:    store i8 42, i8* [[SEL_PTR]], align 4
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP7]], align 4
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
-  %gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
-  %sel.ptr = select i1 %cnd1, i8* %gep7, i8* %gep23
-  store i8 42, i8* %sel.ptr, align 4
-  %i = load i8, i8* %gep7, align 4
-  ret i8 %i
-}
-
-; FIXME: This should be simplifiable. See comment inside.
-
-define i8 @phi_offsets_fixme(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@phi_offsets_fixme
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[GEP_FIXED:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0
-; CHECK-NEXT:    store i8 100, i8* [[GEP_FIXED]], align 16
-; CHECK-NEXT:    br i1 [[CND1]], label [[THEN:%.*]], label [[ELSE:%.*]]
-; CHECK:       then:
-; CHECK-NEXT:    br label [[JOIN:%.*]]
-; CHECK:       else:
-; CHECK-NEXT:    br label [[JOIN]]
-; CHECK:       join:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ 3, [[THEN]] ], [ 11, [[ELSE]] ]
-; CHECK-NEXT:    [[GEP_PHI:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[PHI]]
-; CHECK-NEXT:    store i8 42, i8* [[GEP_PHI]], align 4
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP_FIXED]], align 16
-; CHECK-NEXT:    ret i8 [[I]]
-;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %gep.fixed = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 0
-  store i8 100, i8* %gep.fixed, align 4
-  br i1 %cnd1, label %then, label %else
-
-then:
-  br label %join
-
-else:
-  br label %join
-
-join:
-  ; FIXME: AAPotentialConstantValues does not detect the constant values for the
-  ; PHI below. It needs to rely on AAPotentialValues.
-  %phi = phi i64 [ 3, %then ], [ 11, %else ]
-  %gep.phi = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %phi
-  store i8 42, i8* %gep.phi, align 4
-  %i = load i8, i8* %gep.fixed, align 4
-  ret i8 %i
-}
-
-;.
-; CHECK: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(none) }
-; CHECK: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind willreturn memory(write) }
-; CHECK: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind willreturn }
-;.

diff  --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
index 9489132cc2bd5..6a1c527b3c3ff 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
@@ -3110,56 +3110,43 @@ define void @scope_value_traversal_helper(i32* %a, i1 %c) {
   ret void
 }
 
-define i8 @gep_index_from_binary_operator(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@gep_index_from_binary_operator
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[GEP_FIXED:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 12
-; CHECK-NEXT:    ret i8 100
+define i8 @multiple_offsets_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
+; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn
+; TUNIT-LABEL: define {{[^@]+}}@multiple_offsets_not_simplifiable_1
+; TUNIT-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR3]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
+; TUNIT-NEXT:    [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
+; TUNIT-NEXT:    [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
+; TUNIT-NEXT:    [[SEL_PTR:%.*]] = select i1 [[CND1]], i8* [[GEP7]], i8* [[GEP23]]
+; TUNIT-NEXT:    store i8 42, i8* [[SEL_PTR]], align 4
+; TUNIT-NEXT:    [[I:%.*]] = load i8, i8* [[GEP7]], align 4
+; TUNIT-NEXT:    ret i8 [[I]]
 ;
-entry:
-  %Bytes = alloca [1024 x i8], align 16
-  %offset = add i64 5, 7
-  %gep.fixed = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 12
-  %gep.sum = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %offset
-  store i8 100, i8* %gep.fixed, align 4
-  %i = load i8, i8* %gep.sum, align 4
-  ret i8 %i
-}
-
-; FIXME: This should be simplifiable. See comment inside.
-
-define i8 @gep_index_from_memory(i1 %cnd1, i1 %cnd2) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define {{[^@]+}}@gep_index_from_memory
-; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
-; CHECK-NEXT:    [[GEP_FIXED:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 12
-; CHECK-NEXT:    [[GEP_LOADED:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 12
-; CHECK-NEXT:    store i8 100, i8* [[GEP_LOADED]], align 4
-; CHECK-NEXT:    [[I:%.*]] = load i8, i8* [[GEP_FIXED]], align 4
-; CHECK-NEXT:    ret i8 [[I]]
+; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn
+; CGSCC-LABEL: define {{[^@]+}}@multiple_offsets_not_simplifiable_1
+; CGSCC-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR5]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[BYTES:%.*]] = alloca [1024 x i8], align 16
+; CGSCC-NEXT:    [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
+; CGSCC-NEXT:    [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
+; CGSCC-NEXT:    [[SEL_PTR:%.*]] = select i1 [[CND1]], i8* [[GEP7]], i8* [[GEP23]]
+; CGSCC-NEXT:    store i8 42, i8* [[SEL_PTR]], align 4
+; CGSCC-NEXT:    [[I:%.*]] = load i8, i8* [[GEP7]], align 4
+; CGSCC-NEXT:    ret i8 [[I]]
 ;
 entry:
   %Bytes = alloca [1024 x i8], align 16
-  %addr = alloca i64, align 16
-  %gep.addr = getelementptr inbounds i64, i64* %addr, i64 0
-  store i64 12, i64* %gep.addr, align 8
-  %offset = load i64, i64* %gep.addr, align 8
-  %gep.fixed = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 12
-
-  ; FIXME: AAPotentialConstantValues does not detect the constant offset being
-  ; passed to this GEP. It needs to rely on AAPotentialValues.
-  %gep.loaded = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %offset
-  store i8 100, i8* %gep.loaded, align 4
-
-  %i = load i8, i8* %gep.fixed, align 4
+  %gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
+  %gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
+  ; %phi.ptr = phi i8* [ %gep7, %then ], [ %gep23, %else ]
+  %sel.ptr = select i1 %cnd1, i8* %gep7, i8* %gep23
+  store i8 42, i8* %sel.ptr, align 4
+  %i = load i8, i8* %gep7, align 4
   ret i8 %i
 }
 
+
 !llvm.module.flags = !{!0, !1}
 !llvm.ident = !{!2}
 


        


More information about the llvm-commits mailing list