104104#include " llvm/ADT/STLExtras.h"
105105#include " llvm/ADT/SetOperations.h"
106106#include " llvm/ADT/SetVector.h"
107+ #include " llvm/ADT/SmallPtrSet.h"
107108#include " llvm/ADT/SmallSet.h"
109+ #include " llvm/ADT/SmallVector.h"
108110#include " llvm/ADT/iterator.h"
109111#include " llvm/Analysis/AssumeBundleQueries.h"
110112#include " llvm/Analysis/CFG.h"
@@ -329,6 +331,10 @@ inline bool operator==(const RangeTy &A, const RangeTy &B) {
329331 return A.Offset == B.Offset && A.Size == B.Size ;
330332}
331333
334+ inline bool operator <(const RangeTy &A, const RangeTy &B) {
335+ return A.Offset < B.Offset ;
336+ }
337+
332338inline bool operator !=(const RangeTy &A, const RangeTy &B) { return !(A == B); }
333339
334340// / Return the initial value of \p Obj with type \p Ty if that is a constant.
@@ -5858,49 +5864,139 @@ struct AAPointerInfo : public AbstractAttribute {
58585864 // / list should be strictly ascending, but we ensure that only when we
58595865 // / actually translate the list of offsets to a RangeList.
58605866 struct OffsetInfo {
5861- using VecTy = SmallSet<int64_t , 4 >;
5867+ using VecTy = SmallVector<AA::RangeTy>;
5868+ // A map to store depth 1 predecessors per offset.
5869+ using OriginsTy = SmallVector<SmallPtrSet<Value *, 4 >>;
58625870 using const_iterator = VecTy::const_iterator;
5863- VecTy Offsets;
5871+ OriginsTy Origins;
5872+ VecTy Ranges;
58645873
5865- const_iterator begin () const { return Offsets .begin (); }
5866- const_iterator end () const { return Offsets .end (); }
5874+ const_iterator begin () const { return Ranges .begin (); }
5875+ const_iterator end () const { return Ranges .end (); }
58675876
58685877 bool operator ==(const OffsetInfo &RHS) const {
5869- return Offsets == RHS.Offsets ;
5878+ return Ranges == RHS.Ranges && Origins == RHS. Origins ;
58705879 }
58715880
58725881 bool operator !=(const OffsetInfo &RHS) const { return !(*this == RHS); }
58735882
5874- bool insert (int64_t Offset) { return Offsets.insert (Offset).second ; }
5875- bool isUnassigned () const { return Offsets.size () == 0 ; }
5883+ // Insert a new Range and Origin
5884+ void insert (AA::RangeTy Range, Value &V) {
5885+ auto *It = std::find (Ranges.begin (), Ranges.end (), Range);
5886+ // Offset exists in Offsets map
5887+ if (It != Ranges.end ()) {
5888+ size_t Index = It - Ranges.begin ();
5889+ if (Index < Origins.size ())
5890+ Origins[Index].insert (&V);
5891+ } else {
5892+ Ranges.push_back (Range);
5893+ Origins.emplace_back ();
5894+ Origins.back ().insert (&V);
5895+ }
5896+ }
5897+
5898+ // Set the size of the offset for all ranges.
5899+ void setSizeAll (uint64_t Size) {
5900+ for (auto &Range : Ranges)
5901+ Range.Size = Size;
5902+ }
5903+
5904+ // Helper function to get just the offsets from Ranges.
5905+ void getOnlyOffsets (SmallVector<int64_t > &Offsets) {
5906+ for (auto &Range : Ranges)
5907+ Offsets.push_back (Range.Offset );
5908+ // ensure unique
5909+ sort (Offsets.begin (), Offsets.end ());
5910+ Offsets.erase (std::unique (Offsets.begin (), Offsets.end ()), Offsets.end ());
5911+ }
5912+
5913+ bool isUnassigned () const { return Ranges.empty (); }
58765914
58775915 bool isUnknown () const {
58785916 if (isUnassigned ())
58795917 return false ;
5880- if (Offsets .size () == 1 )
5881- return *Offsets. begin () == AA::RangeTy::Unknown;
5918+ if (Ranges .size () == 1 )
5919+ return Ranges. front (). Offset == AA::RangeTy::Unknown;
58825920 return false ;
58835921 }
58845922
5885- void setUnknown () {
5886- Offsets.clear ();
5887- Offsets.insert (AA::RangeTy::Unknown);
5923+ void setUnknown (Value &V) {
5924+ Ranges.clear ();
5925+ Origins.clear ();
5926+ insert (AA::RangeTy{AA::RangeTy::Unknown, AA::RangeTy::Unknown}, V);
5927+ }
5928+
5929+ // Increment all ranges by Inc.
5930+ // Add an origin V to all offsets.
5931+ void addToAll (int64_t Inc, Value &V) {
5932+ for (auto &Range : Ranges)
5933+ Range.Offset += Inc;
5934+
5935+ if (!Origins.empty ()) {
5936+ for (auto &Origin : Origins)
5937+ Origin.insert (&V);
5938+ } else {
5939+ for (size_t Index = 0 ; Index < Ranges.size (); Index++) {
5940+ Origins.emplace_back ();
5941+ Origins[Index].insert (&V);
5942+ }
5943+ }
58885944 }
58895945
5946+ // Increment all ranges by Inc.
58905947 void addToAll (int64_t Inc) {
5891- VecTy NewOffsets;
5892- for (auto &Offset : Offsets)
5893- NewOffsets.insert (Offset + Inc);
5894- Offsets = std::move (NewOffsets);
5948+ for (auto &Range : Ranges)
5949+ Range.Offset += Inc;
58955950 }
58965951
58975952 // / Copy offsets from \p R into the current list.
58985953 // /
58995954 // / Ideally all lists should be strictly ascending, but we defer that to the
59005955 // / actual use of the list. So we just blindly append here.
5901- bool merge (const OffsetInfo &R) { return set_union (Offsets, R.Offsets ); }
5956+
5957+ bool merge (const OffsetInfo &R) {
5958+ bool Changed = set_union (Ranges, R.Ranges );
5959+ // ensure elements are unique.
5960+ sort (Ranges.begin (), Ranges.end ());
5961+ Ranges.erase (std::unique (Ranges.begin (), Ranges.end ()), Ranges.end ());
5962+
5963+ OriginsTy ToBeMergeOrigins = R.Origins ;
5964+ for (auto &Origin : ToBeMergeOrigins)
5965+ Origins.emplace_back (Origin);
5966+
5967+ return Changed;
5968+ }
5969+
5970+ // Merge two OffsetInfo structs.
5971+ // takes an additional origin argument
5972+ // and adds it to the corresponding offset in the
5973+ // origins map.
5974+ bool mergeWithOffset (const OffsetInfo &R, Value &CurPtr) {
5975+ bool Changed = set_union (Ranges, R.Ranges );
5976+ // ensure elements are unique.
5977+ sort (Ranges.begin (), Ranges.end ());
5978+ Ranges.erase (std::unique (Ranges.begin (), Ranges.end ()), Ranges.end ());
5979+ auto &ROffsets = R.Ranges ;
5980+ for (auto Offset : ROffsets) {
5981+ auto *It = std::find (Ranges.begin (), Ranges.end (), Offset);
5982+ if (It == Ranges.end ())
5983+ continue ;
5984+ size_t Index = It - Ranges.begin ();
5985+ if (Index >= Origins.size ()) {
5986+ Origins.emplace_back ();
5987+ Origins.back ().insert (&CurPtr);
5988+ } else {
5989+ Origins[Index].insert (&CurPtr);
5990+ }
5991+ }
5992+ return Changed;
5993+ }
59025994 };
59035995
5996+ using OffsetInfoMapTy = DenseMap<Value *, OffsetInfo>;
5997+ using AccessPathTy = SmallVector<Value *, 4 >;
5998+ using AccessPathSetTy = SmallPtrSet<AccessPathTy *, 4 >;
5999+
59046000 // / A container for a list of ranges.
59056001 struct RangeList {
59066002 // The set of ranges rarely contains more than one element, and is unlikely
@@ -6055,15 +6151,17 @@ struct AAPointerInfo : public AbstractAttribute {
60556151 // / An access description.
60566152 struct Access {
60576153 Access (Instruction *I, int64_t Offset, int64_t Size,
6058- std::optional<Value *> Content, AccessKind Kind, Type *Ty)
6154+ std::optional<Value *> Content, AccessKind Kind, Type *Ty,
6155+ AccessPathSetTy *AccessPaths)
60596156 : LocalI(I), RemoteI(I), Content(Content), Ranges(Offset, Size),
6060- Kind (Kind), Ty(Ty) {
6157+ Kind (Kind), Ty(Ty), AccessPaths(AccessPaths) {
60616158 verify ();
60626159 }
60636160 Access (Instruction *LocalI, Instruction *RemoteI, const RangeList &Ranges,
6064- std::optional<Value *> Content, AccessKind K, Type *Ty)
6161+ std::optional<Value *> Content, AccessKind K, Type *Ty,
6162+ AccessPathSetTy *AccessPaths)
60656163 : LocalI(LocalI), RemoteI(RemoteI), Content(Content), Ranges(Ranges),
6066- Kind(K), Ty(Ty) {
6164+ Kind(K), Ty(Ty), AccessPaths(AccessPaths) {
60676165 if (Ranges.size () > 1 ) {
60686166 Kind = AccessKind (Kind | AK_MAY);
60696167 Kind = AccessKind (Kind & ~AK_MUST);
@@ -6072,17 +6170,18 @@ struct AAPointerInfo : public AbstractAttribute {
60726170 }
60736171 Access (Instruction *LocalI, Instruction *RemoteI, int64_t Offset,
60746172 int64_t Size, std::optional<Value *> Content, AccessKind Kind,
6075- Type *Ty)
6173+ Type *Ty, AccessPathSetTy *AccessPaths )
60766174 : LocalI(LocalI), RemoteI(RemoteI), Content(Content),
6077- Ranges(Offset, Size), Kind(Kind), Ty(Ty) {
6175+ Ranges(Offset, Size), Kind(Kind), Ty(Ty), AccessPaths(AccessPaths) {
60786176 verify ();
60796177 }
60806178 Access (const Access &Other) = default;
60816179
60826180 Access &operator =(const Access &Other) = default ;
60836181 bool operator ==(const Access &R) const {
60846182 return LocalI == R.LocalI && RemoteI == R.RemoteI && Ranges == R.Ranges &&
6085- Content == R.Content && Kind == R.Kind ;
6183+ Content == R.Content && Kind == R.Kind &&
6184+ checkAccessPathsAreSame (R.AccessPaths );
60866185 }
60876186 bool operator !=(const Access &R) const { return !(*this == R); }
60886187
@@ -6194,11 +6293,53 @@ struct AAPointerInfo : public AbstractAttribute {
61946293 }
61956294 }
61966295
6296+ // Merge two access paths into one.
6297+ void mergeAccessPaths (const AccessPathSetTy *AccessPathsNew) const {
6298+ for (auto *Path : *AccessPathsNew)
6299+ if (!existsChain (Path))
6300+ AccessPaths->insert (Path);
6301+ }
6302+
6303+ // Check if the given access paths are same.
6304+ bool checkAccessPathsAreSame (const AccessPathSetTy *AccessPathsR) const {
6305+ bool IsSame = true ;
6306+ if (AccessPaths->size () != AccessPathsR->size ())
6307+ return false ;
6308+
6309+ for (auto *Path : *AccessPathsR) {
6310+ if (!existsChain (Path))
6311+ IsSame = false ;
6312+ }
6313+ return IsSame;
6314+ }
6315+
6316+ // Check if the chain exists in the AccessPathsSet.
6317+ bool existsChain (const AccessPathTy *NewPath) const {
6318+ for (auto *OldPath : *AccessPaths)
6319+ if (*OldPath == *NewPath)
6320+ return true ;
6321+
6322+ return false ;
6323+ }
6324+
6325+ void dumpAccessPaths (raw_ostream &O) const {
6326+ O << " Print all access paths found:"
6327+ << " \n " ;
6328+ for (auto *It : *AccessPaths) {
6329+ O << " Backtrack a unique access path:\n " ;
6330+ for (Value *Ins : *It) {
6331+ O << *Ins << " \n " ;
6332+ }
6333+ }
6334+ }
6335+
6336+ const AccessPathSetTy *getAccessChain () const { return AccessPaths; }
61976337 const RangeList &getRanges () const { return Ranges; }
61986338
61996339 using const_iterator = RangeList::const_iterator;
62006340 const_iterator begin () const { return Ranges.begin (); }
62016341 const_iterator end () const { return Ranges.end (); }
6342+ size_t size () const { return Ranges.size (); }
62026343
62036344 private:
62046345 // / The instruction responsible for the access with respect to the local
@@ -6221,6 +6362,10 @@ struct AAPointerInfo : public AbstractAttribute {
62216362 // / The type of the content, thus the type read/written, can be null if not
62226363 // / available.
62236364 Type *Ty;
6365+
6366+ // / The full chain of instructions that participate in the Access.
6367+ // / There may be more than one access chain.
6368+ AccessPathSetTy *AccessPaths;
62246369 };
62256370
62266371 // / Create an abstract attribute view for the position \p IRP.
0 commit comments