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,135 @@ 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
+ // Insert a new Range and Origin
5817
+ void insert (AA::RangeTy Range, Value &V) {
5818
+ auto *It = std::find (Ranges.begin (), Ranges.end (), Range);
5819
+ // Offset exists in Offsets map
5820
+ if (It != Ranges.end ()) {
5821
+ size_t Index = It - Ranges.begin ();
5822
+ if (Index < Origins.size ())
5823
+ Origins[Index].insert (&V);
5824
+ } else {
5825
+ Ranges.push_back (Range);
5826
+ Origins.emplace_back ();
5827
+ Origins.back ().insert (&V);
5828
+ }
5829
+ }
5830
+
5831
+ void setSizeAll (uint64_t Size ) {
5832
+ for (auto &Range : Ranges)
5833
+ Range.Size = Size ;
5834
+ }
5835
+
5836
+ // Helper function to get just the offsets from Ranges.
5837
+ void getOnlyOffsets (SmallVector<int64_t > &Offsets) {
5838
+ for (auto &Range : Ranges)
5839
+ Offsets.push_back (Range.Offset );
5840
+ // ensure unique
5841
+ sort (Offsets.begin (), Offsets.end ());
5842
+ Offsets.erase (std::unique (Offsets.begin (), Offsets.end ()), Offsets.end ());
5843
+ }
5844
+
5845
+ bool isUnassigned () const { return Ranges.empty (); }
5846
+
5847
+ bool isUnknown () const {
5848
+ if (isUnassigned ())
5849
+ return false ;
5850
+ if (Ranges.size () == 1 )
5851
+ return Ranges.front ().Offset == AA::RangeTy::Unknown;
5852
+ return false ;
5853
+ }
5854
+
5855
+ void setUnknown (Value &V) {
5856
+ Ranges.clear ();
5857
+ Origins.clear ();
5858
+ insert (AA::RangeTy{AA::RangeTy::Unknown, AA::RangeTy::Unknown}, V);
5859
+ }
5860
+
5861
+ void addToAll (int64_t Inc, Value &V) {
5862
+ for (auto &Range : Ranges)
5863
+ Range.Offset += Inc;
5864
+
5865
+ if (!Origins.empty ()) {
5866
+ for (auto &Origin : Origins)
5867
+ Origin.insert (&V);
5868
+ } else {
5869
+ for (size_t Index = 0 ; Index < Ranges.size (); Index++) {
5870
+ Origins.emplace_back ();
5871
+ Origins[Index].insert (&V);
5872
+ }
5873
+ }
5874
+ }
5875
+
5876
+ void addToAll (int64_t Inc) {
5877
+ for (auto &Range : Ranges)
5878
+ Range.Offset += Inc;
5879
+ }
5880
+
5881
+ // / Copy offsets from \p R into the current list.
5882
+ // /
5883
+ // / Ideally all lists should be strictly ascending, but we defer that to the
5884
+ // / actual use of the list. So we just blindly append here.
5885
+ void merge (const OffsetInfo &R) {
5886
+ Ranges.append (R.Ranges );
5887
+ // ensure elements are unique.
5888
+ sort (Ranges.begin (), Ranges.end ());
5889
+ Ranges.erase (std::unique (Ranges.begin (), Ranges.end ()), Ranges.end ());
5890
+
5891
+ OriginsTy ToBeMergeOrigins = R.Origins ;
5892
+ for (auto &Origin : ToBeMergeOrigins)
5893
+ Origins.emplace_back (Origin);
5894
+ }
5895
+
5896
+ // Merge two OffsetInfo structs.
5897
+ // takes an additional origin argument
5898
+ // and adds it to the corresponding offset in the
5899
+ // origins map.
5900
+ void mergeWithOffset (const OffsetInfo &R, Value &CurPtr) {
5901
+ Ranges.append (R.Ranges );
5902
+ // ensure elements are unique.
5903
+ sort (Ranges.begin (), Ranges.end ());
5904
+ Ranges.erase (std::unique (Ranges.begin (), Ranges.end ()), Ranges.end ());
5905
+ auto &ROffsets = R.Ranges ;
5906
+ for (auto Offset : ROffsets) {
5907
+ auto *It = std::find (Ranges.begin (), Ranges.end (), Offset);
5908
+ if (It == Ranges.end ())
5909
+ continue ;
5910
+ size_t Index = It - Ranges.begin ();
5911
+ if (Index >= Origins.size ()) {
5912
+ Origins.emplace_back ();
5913
+ Origins.back ().insert (&CurPtr);
5914
+ } else {
5915
+ Origins[Index].insert (&CurPtr);
5916
+ }
5917
+ }
5918
+ }
5919
+ };
5920
+
5921
+ using OffsetInfoMapTy = DenseMap<Value *, OffsetInfo>;
5922
+ using AccessPathTy = SmallVector<Value *, 4 >;
5923
+ using AccessPathSetTy = SmallPtrSet<AccessPathTy *, 4 >;
5924
+
5788
5925
// / A container for a list of ranges.
5789
5926
struct RangeList {
5790
5927
// The set of ranges rarely contains more than one element, and is unlikely
@@ -5939,15 +6076,17 @@ struct AAPointerInfo : public AbstractAttribute {
5939
6076
// / An access description.
5940
6077
struct Access {
5941
6078
Access (Instruction *I, int64_t Offset, int64_t Size ,
5942
- std::optional<Value *> Content, AccessKind Kind, Type *Ty)
6079
+ std::optional<Value *> Content, AccessKind Kind, Type *Ty,
6080
+ AccessPathSetTy *AccessPaths)
5943
6081
: LocalI(I), RemoteI(I), Content(Content), Ranges(Offset, Size ),
5944
- Kind (Kind), Ty(Ty) {
6082
+ Kind (Kind), Ty(Ty), AccessPaths(AccessPaths) {
5945
6083
verify ();
5946
6084
}
5947
6085
Access (Instruction *LocalI, Instruction *RemoteI, const RangeList &Ranges,
5948
- std::optional<Value *> Content, AccessKind K, Type *Ty)
6086
+ std::optional<Value *> Content, AccessKind K, Type *Ty,
6087
+ AccessPathSetTy *AccessPaths)
5949
6088
: LocalI(LocalI), RemoteI(RemoteI), Content(Content), Ranges(Ranges),
5950
- Kind(K), Ty(Ty) {
6089
+ Kind(K), Ty(Ty), AccessPaths(AccessPaths) {
5951
6090
if (Ranges.size () > 1 ) {
5952
6091
Kind = AccessKind (Kind | AK_MAY);
5953
6092
Kind = AccessKind (Kind & ~AK_MUST);
@@ -5956,17 +6095,18 @@ struct AAPointerInfo : public AbstractAttribute {
5956
6095
}
5957
6096
Access (Instruction *LocalI, Instruction *RemoteI, int64_t Offset,
5958
6097
int64_t Size , std::optional<Value *> Content, AccessKind Kind,
5959
- Type *Ty)
6098
+ Type *Ty, AccessPathSetTy *AccessPaths )
5960
6099
: LocalI(LocalI), RemoteI(RemoteI), Content(Content),
5961
- Ranges(Offset, Size ), Kind(Kind), Ty(Ty) {
6100
+ Ranges(Offset, Size ), Kind(Kind), Ty(Ty), AccessPaths(AccessPaths) {
5962
6101
verify ();
5963
6102
}
5964
6103
Access (const Access &Other) = default;
5965
6104
5966
6105
Access &operator =(const Access &Other) = default ;
5967
6106
bool operator ==(const Access &R) const {
5968
6107
return LocalI == R.LocalI && RemoteI == R.RemoteI && Ranges == R.Ranges &&
5969
- Content == R.Content && Kind == R.Kind ;
6108
+ Content == R.Content && Kind == R.Kind &&
6109
+ checkAccessPathsAreSame (R.AccessPaths );
5970
6110
}
5971
6111
bool operator !=(const Access &R) const { return !(*this == R); }
5972
6112
@@ -6078,11 +6218,53 @@ struct AAPointerInfo : public AbstractAttribute {
6078
6218
}
6079
6219
}
6080
6220
6221
+ // Merge two access paths into one.
6222
+ void mergeAccessPaths (const AccessPathSetTy *AccessPathsNew) const {
6223
+ for (auto *Path : *AccessPathsNew)
6224
+ if (!existsChain (Path))
6225
+ AccessPaths->insert (Path);
6226
+ }
6227
+
6228
+ // Check if the given access paths are same.
6229
+ bool checkAccessPathsAreSame (const AccessPathSetTy *AccessPathsR) const {
6230
+ bool IsSame = true ;
6231
+ if (AccessPaths->size () != AccessPathsR->size ())
6232
+ return false ;
6233
+
6234
+ for (auto *Path : *AccessPathsR) {
6235
+ if (!existsChain (Path))
6236
+ IsSame = false ;
6237
+ }
6238
+ return IsSame;
6239
+ }
6240
+
6241
+ // Check if the chain exists in the AccessPathsSet.
6242
+ bool existsChain (const AccessPathTy *NewPath) const {
6243
+ for (auto *OldPath : *AccessPaths)
6244
+ if (*OldPath == *NewPath)
6245
+ return true ;
6246
+
6247
+ return false ;
6248
+ }
6249
+
6250
+ void dumpAccessPaths (raw_ostream &O) const {
6251
+ O << " Print all access paths found:"
6252
+ << " \n " ;
6253
+ for (auto *It : *AccessPaths) {
6254
+ O << " Backtrack a unique access path:\n " ;
6255
+ for (Value *Ins : *It) {
6256
+ O << *Ins << " \n " ;
6257
+ }
6258
+ }
6259
+ }
6260
+
6261
+ const AccessPathSetTy *getAccessChain () const { return AccessPaths; }
6081
6262
const RangeList &getRanges () const { return Ranges; }
6082
6263
6083
6264
using const_iterator = RangeList::const_iterator;
6084
6265
const_iterator begin () const { return Ranges.begin (); }
6085
6266
const_iterator end () const { return Ranges.end (); }
6267
+ size_t size () const { return Ranges.size (); }
6086
6268
6087
6269
private:
6088
6270
// / The instruction responsible for the access with respect to the local
@@ -6105,6 +6287,10 @@ struct AAPointerInfo : public AbstractAttribute {
6105
6287
// / The type of the content, thus the type read/written, can be null if not
6106
6288
// / available.
6107
6289
Type *Ty;
6290
+
6291
+ // / The full chain of instructions that participate in the Access.
6292
+ // / There may be more than one access chain.
6293
+ AccessPathSetTy *AccessPaths;
6108
6294
};
6109
6295
6110
6296
// / Create an abstract attribute view for the position \p IRP.
0 commit comments