Skip to content

Commit

Permalink
Store the full chain of instructions that make up the access.
Browse files Browse the repository at this point in the history
  • Loading branch information
vidsinghal authored and Vidush Singhal committed Jul 3, 2024
1 parent e8e05c3 commit e87d1ad
Show file tree
Hide file tree
Showing 3 changed files with 803 additions and 110 deletions.
207 changes: 200 additions & 7 deletions llvm/include/llvm/Transforms/IPO/Attributor.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Analysis/AssumeBundleQueries.h"
#include "llvm/Analysis/CFG.h"
Expand Down Expand Up @@ -141,6 +144,7 @@
#include <limits>
#include <map>
#include <optional>
#include <tuple>

namespace llvm {

Expand Down Expand Up @@ -320,6 +324,10 @@ inline bool operator==(const RangeTy &A, const RangeTy &B) {
return A.Offset == B.Offset && A.Size == B.Size;
}

inline bool operator<(const RangeTy &A, const RangeTy &B) {
return A.Offset < B.Offset;
}

inline bool operator!=(const RangeTy &A, const RangeTy &B) { return !(A == B); }

/// Return the initial value of \p Obj with type \p Ty if that is a constant.
Expand Down Expand Up @@ -5785,6 +5793,136 @@ struct AAPointerInfo : public AbstractAttribute {
AK_MUST_READ_WRITE = AK_MUST | AK_R | AK_W,
};

/// 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.
struct OffsetInfo {
using VecTy = SmallVector<AA::RangeTy>;
// A map to store depth 1 predecessors per offset.
using OriginsTy = SmallVector<SmallPtrSet<Value *, 4>>;
using const_iterator = VecTy::const_iterator;
OriginsTy Origins;
VecTy Ranges;

const_iterator begin() const { return Ranges.begin(); }
const_iterator end() const { return Ranges.end(); }

bool operator==(const OffsetInfo &RHS) const {
return Ranges == RHS.Ranges && Origins == RHS.Origins;
}

bool operator!=(const OffsetInfo &RHS) const { return !(*this == RHS); }

void insert(AA::RangeTy Range, Value &V) {

auto *It = std::find(Ranges.begin(), Ranges.end(), Range);

// Offset exists in Offsets map
if (It != Ranges.end()) {
size_t Index = It - Ranges.begin();
if (Index < Origins.size())
Origins[Index].insert(&V);
} else {
Ranges.push_back(Range);
Origins.emplace_back();
Origins.back().insert(&V);
}
}

void setSizeAll(uint64_t Size) {
for (auto &Range : Ranges)
Range.Size = Size;
}

void getOnlyOffsets(SmallVector<int64_t> &Offsets) {

for (auto &Range : Ranges)
Offsets.push_back(Range.Offset);

// ensure unique
sort(Offsets.begin(), Offsets.end());
Offsets.erase(std::unique(Offsets.begin(), Offsets.end()), Offsets.end());
}

bool isUnassigned() const { return Ranges.empty(); }

bool isUnknown() const {
if (isUnassigned())
return false;
if (Ranges.size() == 1)
return Ranges.front().Offset == AA::RangeTy::Unknown;
return false;
}

void setUnknown(Value &V) {
Ranges.clear();
Origins.clear();
insert(AA::RangeTy{AA::RangeTy::Unknown, AA::RangeTy::Unknown}, V);
}

void addToAll(int64_t Inc, Value &V) {
for (auto &Range : Ranges)
Range.Offset += Inc;

if (!Origins.empty()) {
for (auto &Origin : Origins)
Origin.insert(&V);
} else {
for (size_t Index = 0; Index < Ranges.size(); Index++) {
Origins.emplace_back();
Origins[Index].insert(&V);
}
}
}

void addToAll(int64_t Inc) {
for (auto &Range : Ranges)
Range.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) {
Ranges.append(R.Ranges);
// ensure elements are unique.
sort(Ranges.begin(), Ranges.end());
Ranges.erase(std::unique(Ranges.begin(), Ranges.end()), Ranges.end());

OriginsTy ToBeMergeOrigins = R.Origins;
for (auto &Origin : ToBeMergeOrigins)
Origins.emplace_back(Origin);
}

void mergeWithOffset(const OffsetInfo &R, Value &CurPtr) {

Ranges.append(R.Ranges);
// ensure elements are unique.
sort(Ranges.begin(), Ranges.end());
Ranges.erase(std::unique(Ranges.begin(), Ranges.end()), Ranges.end());

auto &ROffsets = R.Ranges;
for (auto Offset : ROffsets) {

auto *It = std::find(Ranges.begin(), Ranges.end(), Offset);
if (It == Ranges.end())
continue;

size_t Index = It - Ranges.begin();

if (Index >= Origins.size()) {
Origins.emplace_back();
Origins.back().insert(&CurPtr);
} else {
Origins[Index].insert(&CurPtr);
}
}
}
};

using OffsetInfoMapTy = DenseMap<Value *, OffsetInfo>;

/// A container for a list of ranges.
struct RangeList {
// The set of ranges rarely contains more than one element, and is unlikely
Expand Down Expand Up @@ -5938,16 +6076,21 @@ struct AAPointerInfo : public AbstractAttribute {

/// An access description.
struct Access {
using AccessPathTy = SmallVector<Value *, 4>;
using AccessPathSetTy = SmallPtrSet<AccessPathTy *, 4>;

Access(Instruction *I, int64_t Offset, int64_t Size,
std::optional<Value *> Content, AccessKind Kind, Type *Ty)
std::optional<Value *> Content, AccessKind Kind, Type *Ty,
AccessPathSetTy *AccessPaths)
: LocalI(I), RemoteI(I), Content(Content), Ranges(Offset, Size),
Kind(Kind), Ty(Ty) {
Kind(Kind), Ty(Ty), AccessPaths(AccessPaths) {
verify();
}
Access(Instruction *LocalI, Instruction *RemoteI, const RangeList &Ranges,
std::optional<Value *> Content, AccessKind K, Type *Ty)
std::optional<Value *> Content, AccessKind K, Type *Ty,
AccessPathSetTy *AccessPaths)
: LocalI(LocalI), RemoteI(RemoteI), Content(Content), Ranges(Ranges),
Kind(K), Ty(Ty) {
Kind(K), Ty(Ty), AccessPaths(AccessPaths) {
if (Ranges.size() > 1) {
Kind = AccessKind(Kind | AK_MAY);
Kind = AccessKind(Kind & ~AK_MUST);
Expand All @@ -5956,17 +6099,18 @@ struct AAPointerInfo : public AbstractAttribute {
}
Access(Instruction *LocalI, Instruction *RemoteI, int64_t Offset,
int64_t Size, std::optional<Value *> Content, AccessKind Kind,
Type *Ty)
Type *Ty, AccessPathSetTy *AccessPaths)
: LocalI(LocalI), RemoteI(RemoteI), Content(Content),
Ranges(Offset, Size), Kind(Kind), Ty(Ty) {
Ranges(Offset, Size), Kind(Kind), Ty(Ty), AccessPaths(AccessPaths) {
verify();
}
Access(const Access &Other) = default;

Access &operator=(const Access &Other) = default;
bool operator==(const Access &R) const {
return LocalI == R.LocalI && RemoteI == R.RemoteI && Ranges == R.Ranges &&
Content == R.Content && Kind == R.Kind;
Content == R.Content && Kind == R.Kind &&
checkAccessPathsAreSame(R.AccessPaths);
}
bool operator!=(const Access &R) const { return !(*this == R); }

Expand Down Expand Up @@ -6078,11 +6222,56 @@ struct AAPointerInfo : public AbstractAttribute {
}
}

void mergeAccessPaths(const AccessPathSetTy *AccessPathsNew) const {

for (auto *Path : *AccessPathsNew)
if (!existsChain(Path))
AccessPaths->insert(Path);
}

bool checkAccessPathsAreSame(const AccessPathSetTy *AccessPathsR) const {

bool IsSame = true;

if (AccessPaths->size() != AccessPathsR->size())
return false;

for (auto *Path : *AccessPathsR) {
if (!existsChain(Path))
IsSame = false;
}
return IsSame;
}

bool existsChain(const AccessPathTy *NewPath) const {

for (auto *OldPath : *AccessPaths)
if (*OldPath == *NewPath)
return true;

return false;
}

void dumpAccessPaths(raw_ostream &O) {

O << "Print all access paths found:"
<< "\n";
for (auto *It : *AccessPaths) {
O << "Backtrack a unique access path:\n";
for (Value *Ins : *It) {
O << *Ins << "\n";
}
}
}

const AccessPathSetTy *getAccessChain() const { return AccessPaths; }

const RangeList &getRanges() const { return Ranges; }

using const_iterator = RangeList::const_iterator;
const_iterator begin() const { return Ranges.begin(); }
const_iterator end() const { return Ranges.end(); }
size_t size() const { return Ranges.size(); }

private:
/// The instruction responsible for the access with respect to the local
Expand All @@ -6105,6 +6294,10 @@ struct AAPointerInfo : public AbstractAttribute {
/// The type of the content, thus the type read/written, can be null if not
/// available.
Type *Ty;

/// The full chain of instructions that participate in the Access.
/// There may be more than one access chain.
AccessPathSetTy *AccessPaths;
};

/// Create an abstract attribute view for the position \p IRP.
Expand Down
Loading

0 comments on commit e87d1ad

Please sign in to comment.