103
103
#include " llvm/ADT/STLExtras.h"
104
104
#include " llvm/ADT/SetOperations.h"
105
105
#include " llvm/ADT/SetVector.h"
106
+ #include " llvm/ADT/SmallPtrSet.h"
106
107
#include " llvm/ADT/SmallSet.h"
108
+ #include " llvm/ADT/SmallVector.h"
109
+ #include " llvm/ADT/StringExtras.h"
107
110
#include " llvm/ADT/iterator.h"
108
111
#include " llvm/Analysis/AssumeBundleQueries.h"
109
112
#include " llvm/Analysis/CFG.h"
141
144
#include < limits>
142
145
#include < map>
143
146
#include < optional>
147
+ #include < tuple>
144
148
145
149
namespace llvm {
146
150
@@ -320,6 +324,10 @@ inline bool operator==(const RangeTy &A, const RangeTy &B) {
320
324
return A.Offset == B.Offset && A.Size == B.Size ;
321
325
}
322
326
327
+ inline bool operator <(const RangeTy &A, const RangeTy &B) {
328
+ return A.Offset < B.Offset ;
329
+ }
330
+
323
331
inline bool operator !=(const RangeTy &A, const RangeTy &B) { return !(A == B); }
324
332
325
333
// / Return the initial value of \p Obj with type \p Ty if that is a constant.
@@ -5785,6 +5793,136 @@ struct AAPointerInfo : public AbstractAttribute {
5785
5793
AK_MUST_READ_WRITE = AK_MUST | AK_R | AK_W,
5786
5794
};
5787
5795
5796
+ // / A helper containing a list of offsets computed for a Use. Ideally this
5797
+ // / list should be strictly ascending, but we ensure that only when we
5798
+ // / actually translate the list of offsets to a RangeList.
5799
+ struct OffsetInfo {
5800
+ using VecTy = SmallVector<AA::RangeTy>;
5801
+ // A map to store depth 1 predecessors per offset.
5802
+ using OriginsTy = SmallVector<SmallPtrSet<Value *, 4 >>;
5803
+ using const_iterator = VecTy::const_iterator;
5804
+ OriginsTy Origins;
5805
+ VecTy Ranges;
5806
+
5807
+ const_iterator begin () const { return Ranges.begin (); }
5808
+ const_iterator end () const { return Ranges.end (); }
5809
+
5810
+ bool operator ==(const OffsetInfo &RHS) const {
5811
+ return Ranges == RHS.Ranges && Origins == RHS.Origins ;
5812
+ }
5813
+
5814
+ bool operator !=(const OffsetInfo &RHS) const { return !(*this == RHS); }
5815
+
5816
+ void insert (AA::RangeTy Range, Value &V) {
5817
+
5818
+ auto *It = std::find (Ranges.begin (), Ranges.end (), Range);
5819
+
5820
+ // Offset exists in Offsets map
5821
+ if (It != Ranges.end ()) {
5822
+ size_t Index = It - Ranges.begin ();
5823
+ if (Index < Origins.size ())
5824
+ Origins[Index].insert (&V);
5825
+ } else {
5826
+ Ranges.push_back (Range);
5827
+ Origins.emplace_back ();
5828
+ Origins.back ().insert (&V);
5829
+ }
5830
+ }
5831
+
5832
+ void setSizeAll (uint64_t Size ) {
5833
+ for (auto &Range : Ranges)
5834
+ Range.Size = Size ;
5835
+ }
5836
+
5837
+ void getOnlyOffsets (SmallVector<int64_t > &Offsets) {
5838
+
5839
+ for (auto &Range : Ranges)
5840
+ Offsets.push_back (Range.Offset );
5841
+
5842
+ // ensure unique
5843
+ sort (Offsets.begin (), Offsets.end ());
5844
+ Offsets.erase (std::unique (Offsets.begin (), Offsets.end ()), Offsets.end ());
5845
+ }
5846
+
5847
+ bool isUnassigned () const { return Ranges.empty (); }
5848
+
5849
+ bool isUnknown () const {
5850
+ if (isUnassigned ())
5851
+ return false ;
5852
+ if (Ranges.size () == 1 )
5853
+ return Ranges.front ().Offset == AA::RangeTy::Unknown;
5854
+ return false ;
5855
+ }
5856
+
5857
+ void setUnknown (Value &V) {
5858
+ Ranges.clear ();
5859
+ Origins.clear ();
5860
+ insert (AA::RangeTy{AA::RangeTy::Unknown, AA::RangeTy::Unknown}, V);
5861
+ }
5862
+
5863
+ void addToAll (int64_t Inc, Value &V) {
5864
+ for (auto &Range : Ranges)
5865
+ Range.Offset += Inc;
5866
+
5867
+ if (!Origins.empty ()) {
5868
+ for (auto &Origin : Origins)
5869
+ Origin.insert (&V);
5870
+ } else {
5871
+ for (size_t Index = 0 ; Index < Ranges.size (); Index++) {
5872
+ Origins.emplace_back ();
5873
+ Origins[Index].insert (&V);
5874
+ }
5875
+ }
5876
+ }
5877
+
5878
+ void addToAll (int64_t Inc) {
5879
+ for (auto &Range : Ranges)
5880
+ Range.Offset += Inc;
5881
+ }
5882
+
5883
+ // / Copy offsets from \p R into the current list.
5884
+ // /
5885
+ // / Ideally all lists should be strictly ascending, but we defer that to the
5886
+ // / actual use of the list. So we just blindly append here.
5887
+ void merge (const OffsetInfo &R) {
5888
+ Ranges.append (R.Ranges );
5889
+ // ensure elements are unique.
5890
+ sort (Ranges.begin (), Ranges.end ());
5891
+ Ranges.erase (std::unique (Ranges.begin (), Ranges.end ()), Ranges.end ());
5892
+
5893
+ OriginsTy ToBeMergeOrigins = R.Origins ;
5894
+ for (auto &Origin : ToBeMergeOrigins)
5895
+ Origins.emplace_back (Origin);
5896
+ }
5897
+
5898
+ void mergeWithOffset (const OffsetInfo &R, Value &CurPtr) {
5899
+
5900
+ Ranges.append (R.Ranges );
5901
+ // ensure elements are unique.
5902
+ sort (Ranges.begin (), Ranges.end ());
5903
+ Ranges.erase (std::unique (Ranges.begin (), Ranges.end ()), Ranges.end ());
5904
+
5905
+ auto &ROffsets = R.Ranges ;
5906
+ for (auto Offset : ROffsets) {
5907
+
5908
+ auto *It = std::find (Ranges.begin (), Ranges.end (), Offset);
5909
+ if (It == Ranges.end ())
5910
+ continue ;
5911
+
5912
+ size_t Index = It - Ranges.begin ();
5913
+
5914
+ if (Index >= Origins.size ()) {
5915
+ Origins.emplace_back ();
5916
+ Origins.back ().insert (&CurPtr);
5917
+ } else {
5918
+ Origins[Index].insert (&CurPtr);
5919
+ }
5920
+ }
5921
+ }
5922
+ };
5923
+
5924
+ using OffsetInfoMapTy = DenseMap<Value *, OffsetInfo>;
5925
+
5788
5926
// / A container for a list of ranges.
5789
5927
struct RangeList {
5790
5928
// The set of ranges rarely contains more than one element, and is unlikely
@@ -5938,16 +6076,21 @@ struct AAPointerInfo : public AbstractAttribute {
5938
6076
5939
6077
// / An access description.
5940
6078
struct Access {
6079
+ using AccessPathTy = SmallVector<Value *, 4 >;
6080
+ using AccessPathSetTy = SmallPtrSet<AccessPathTy *, 4 >;
6081
+
5941
6082
Access (Instruction *I, int64_t Offset, int64_t Size ,
5942
- std::optional<Value *> Content, AccessKind Kind, Type *Ty)
6083
+ std::optional<Value *> Content, AccessKind Kind, Type *Ty,
6084
+ AccessPathSetTy *AccessPaths)
5943
6085
: LocalI(I), RemoteI(I), Content(Content), Ranges(Offset, Size ),
5944
- Kind (Kind), Ty(Ty) {
6086
+ Kind (Kind), Ty(Ty), AccessPaths(AccessPaths) {
5945
6087
verify ();
5946
6088
}
5947
6089
Access (Instruction *LocalI, Instruction *RemoteI, const RangeList &Ranges,
5948
- std::optional<Value *> Content, AccessKind K, Type *Ty)
6090
+ std::optional<Value *> Content, AccessKind K, Type *Ty,
6091
+ AccessPathSetTy *AccessPaths)
5949
6092
: LocalI(LocalI), RemoteI(RemoteI), Content(Content), Ranges(Ranges),
5950
- Kind(K), Ty(Ty) {
6093
+ Kind(K), Ty(Ty), AccessPaths(AccessPaths) {
5951
6094
if (Ranges.size () > 1 ) {
5952
6095
Kind = AccessKind (Kind | AK_MAY);
5953
6096
Kind = AccessKind (Kind & ~AK_MUST);
@@ -5956,17 +6099,18 @@ struct AAPointerInfo : public AbstractAttribute {
5956
6099
}
5957
6100
Access (Instruction *LocalI, Instruction *RemoteI, int64_t Offset,
5958
6101
int64_t Size , std::optional<Value *> Content, AccessKind Kind,
5959
- Type *Ty)
6102
+ Type *Ty, AccessPathSetTy *AccessPaths )
5960
6103
: LocalI(LocalI), RemoteI(RemoteI), Content(Content),
5961
- Ranges(Offset, Size ), Kind(Kind), Ty(Ty) {
6104
+ Ranges(Offset, Size ), Kind(Kind), Ty(Ty), AccessPaths(AccessPaths) {
5962
6105
verify ();
5963
6106
}
5964
6107
Access (const Access &Other) = default;
5965
6108
5966
6109
Access &operator =(const Access &Other) = default ;
5967
6110
bool operator ==(const Access &R) const {
5968
6111
return LocalI == R.LocalI && RemoteI == R.RemoteI && Ranges == R.Ranges &&
5969
- Content == R.Content && Kind == R.Kind ;
6112
+ Content == R.Content && Kind == R.Kind &&
6113
+ checkAccessPathsAreSame (R.AccessPaths );
5970
6114
}
5971
6115
bool operator !=(const Access &R) const { return !(*this == R); }
5972
6116
@@ -6078,11 +6222,56 @@ struct AAPointerInfo : public AbstractAttribute {
6078
6222
}
6079
6223
}
6080
6224
6225
+ void mergeAccessPaths (const AccessPathSetTy *AccessPathsNew) const {
6226
+
6227
+ for (auto *Path : *AccessPathsNew)
6228
+ if (!existsChain (Path))
6229
+ AccessPaths->insert (Path);
6230
+ }
6231
+
6232
+ bool checkAccessPathsAreSame (const AccessPathSetTy *AccessPathsR) const {
6233
+
6234
+ bool IsSame = true ;
6235
+
6236
+ if (AccessPaths->size () != AccessPathsR->size ())
6237
+ return false ;
6238
+
6239
+ for (auto *Path : *AccessPathsR) {
6240
+ if (!existsChain (Path))
6241
+ IsSame = false ;
6242
+ }
6243
+ return IsSame;
6244
+ }
6245
+
6246
+ bool existsChain (const AccessPathTy *NewPath) const {
6247
+
6248
+ for (auto *OldPath : *AccessPaths)
6249
+ if (*OldPath == *NewPath)
6250
+ return true ;
6251
+
6252
+ return false ;
6253
+ }
6254
+
6255
+ void dumpAccessPaths (raw_ostream &O) {
6256
+
6257
+ O << " Print all access paths found:"
6258
+ << " \n " ;
6259
+ for (auto *It : *AccessPaths) {
6260
+ O << " Backtrack a unique access path:\n " ;
6261
+ for (Value *Ins : *It) {
6262
+ O << *Ins << " \n " ;
6263
+ }
6264
+ }
6265
+ }
6266
+
6267
+ const AccessPathSetTy *getAccessChain () const { return AccessPaths; }
6268
+
6081
6269
const RangeList &getRanges () const { return Ranges; }
6082
6270
6083
6271
using const_iterator = RangeList::const_iterator;
6084
6272
const_iterator begin () const { return Ranges.begin (); }
6085
6273
const_iterator end () const { return Ranges.end (); }
6274
+ size_t size () const { return Ranges.size (); }
6086
6275
6087
6276
private:
6088
6277
// / The instruction responsible for the access with respect to the local
@@ -6105,6 +6294,10 @@ struct AAPointerInfo : public AbstractAttribute {
6105
6294
// / The type of the content, thus the type read/written, can be null if not
6106
6295
// / available.
6107
6296
Type *Ty;
6297
+
6298
+ // / The full chain of instructions that participate in the Access.
6299
+ // / There may be more than one access chain.
6300
+ AccessPathSetTy *AccessPaths;
6108
6301
};
6109
6302
6110
6303
// / Create an abstract attribute view for the position \p IRP.
0 commit comments