[llvm] [Attributor][FIX] Track returned pointer offsets (PR #110534)
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 30 14:49:29 PDT 2024
https://github.com/jdoerfert updated https://github.com/llvm/llvm-project/pull/110534
>From e30d4dedbe51b17c4e11e27018dccac861676176 Mon Sep 17 00:00:00 2001
From: Johannes Doerfert <jdoerfert at llnl.gov>
Date: Fri, 20 Sep 2024 00:26:50 -0700
Subject: [PATCH 1/3] [Attributor][NFC] Precommit test
---
.../Attributor/value-simplify-pointer-info.ll | 182 ++++++++++++++++++
1 file changed, 182 insertions(+)
diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
index 378560cc89cd12..b16a0609f9b4e6 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
@@ -3389,6 +3389,188 @@ entry:
ret ptr %R
}
+define ptr @move2(ptr %p) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@move2
+; CHECK-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i32 2
+; CHECK-NEXT: ret ptr [[G]]
+;
+ %g = getelementptr i8, ptr %p, i32 2
+ ret ptr %g
+}
+define internal ptr @move4(ptr %p) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@move4
+; CHECK-SAME: (ptr noalias nofree readnone "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i32 4
+; CHECK-NEXT: ret ptr [[G]]
+;
+ %g = getelementptr i8, ptr %p, i32 4
+ ret ptr %g
+}
+
+define ptr @move246(i32 %i, ptr %p) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@move246
+; CHECK-SAME: (i32 [[I:%.*]], ptr nofree readnone "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[C0:%.*]] = icmp eq i32 [[I]], 0
+; CHECK-NEXT: br i1 [[C0]], label [[BG2:%.*]], label [[BG46:%.*]]
+; CHECK: bg2:
+; CHECK-NEXT: [[G2:%.*]] = getelementptr i8, ptr [[P]], i32 2
+; CHECK-NEXT: ret ptr [[G2]]
+; CHECK: bg46:
+; CHECK-NEXT: [[C1:%.*]] = icmp eq i32 [[I]], 1
+; CHECK-NEXT: br i1 [[C1]], label [[BG4:%.*]], label [[BG6:%.*]]
+; CHECK: bg4:
+; CHECK-NEXT: [[G4:%.*]] = getelementptr i8, ptr [[P]], i32 4
+; CHECK-NEXT: ret ptr [[G4]]
+; CHECK: bg6:
+; CHECK-NEXT: [[G6:%.*]] = getelementptr i8, ptr [[P]], i32 6
+; CHECK-NEXT: ret ptr [[G6]]
+;
+ %c0 = icmp eq i32 %i, 0
+ br i1 %c0, label %bg2, label %bg46
+bg2:
+ %g2 = getelementptr i8, ptr %p, i32 2
+ ret ptr %g2
+bg46:
+ %c1 = icmp eq i32 %i, 1
+ br i1 %c1, label %bg4, label %bg6
+bg4:
+ %g4 = getelementptr i8, ptr %p, i32 4
+ ret ptr %g4
+bg6:
+ %g6 = getelementptr i8, ptr %p, i32 6
+ ret ptr %g6
+}
+
+declare void @use3i8(i8, i8, i8)
+
+define void @returnedPtrAccesses() {
+; TUNIT-LABEL: define {{[^@]+}}@returnedPtrAccesses() {
+; TUNIT-NEXT: [[A:%.*]] = alloca i64, align 8
+; TUNIT-NEXT: [[A2:%.*]] = call ptr @move2(ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR23]]
+; TUNIT-NEXT: [[A4:%.*]] = call ptr @move4(ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR23]]
+; TUNIT-NEXT: [[A6:%.*]] = call ptr @move4(ptr noalias nofree readnone "no-capture-maybe-returned" [[A2]]) #[[ATTR23]]
+; TUNIT-NEXT: store i8 2, ptr [[A2]], align 1
+; TUNIT-NEXT: store i8 4, ptr [[A4]], align 1
+; TUNIT-NEXT: store i8 6, ptr [[A6]], align 1
+; TUNIT-NEXT: call void @use3i8(i8 undef, i8 undef, i8 undef)
+; TUNIT-NEXT: ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@returnedPtrAccesses() {
+; CGSCC-NEXT: [[A:%.*]] = alloca i64, align 8
+; CGSCC-NEXT: [[A2:%.*]] = call nonnull dereferenceable(1) ptr @move2(ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) [[A]]) #[[ATTR20]]
+; CGSCC-NEXT: [[A4:%.*]] = call ptr @move4(ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) [[A]]) #[[ATTR20]]
+; CGSCC-NEXT: [[A6:%.*]] = call ptr @move4(ptr noalias nofree noundef nonnull readnone dereferenceable(1) [[A2]]) #[[ATTR20]]
+; CGSCC-NEXT: [[G2:%.*]] = getelementptr i8, ptr [[A]], i32 2
+; CGSCC-NEXT: [[G4:%.*]] = getelementptr i8, ptr [[A]], i32 4
+; CGSCC-NEXT: [[G6:%.*]] = getelementptr i8, ptr [[A]], i32 6
+; CGSCC-NEXT: store i8 2, ptr [[A2]], align 1
+; CGSCC-NEXT: store i8 4, ptr [[A4]], align 1
+; CGSCC-NEXT: store i8 6, ptr [[A6]], align 1
+; CGSCC-NEXT: [[L2:%.*]] = load i8, ptr [[G2]], align 2
+; CGSCC-NEXT: [[L4:%.*]] = load i8, ptr [[G4]], align 4
+; CGSCC-NEXT: [[L6:%.*]] = load i8, ptr [[G6]], align 2
+; CGSCC-NEXT: call void @use3i8(i8 [[L2]], i8 [[L4]], i8 [[L6]])
+; CGSCC-NEXT: ret void
+;
+ %a = alloca i64
+ %a2 = call ptr @move2(ptr %a)
+ %a4 = call ptr @move4(ptr %a)
+ %a6 = call ptr @move4(ptr %a2)
+ %g2 = getelementptr i8, ptr %a, i32 2
+ %g4 = getelementptr i8, ptr %a, i32 4
+ %g6 = getelementptr i8, ptr %a, i32 6
+ store i8 2, ptr %a2
+ store i8 4, ptr %a4
+ store i8 6, ptr %a6
+ %l2 = load i8, ptr %g2
+ %l4 = load i8, ptr %g4
+ %l6 = load i8, ptr %g6
+ call void @use3i8(i8 %l2, i8 %l4, i8 %l6)
+ ret void
+}
+
+define void @returnedPtrAccessesMultiple(i32 %i) {
+; TUNIT-LABEL: define {{[^@]+}}@returnedPtrAccessesMultiple
+; TUNIT-SAME: (i32 [[I:%.*]]) {
+; TUNIT-NEXT: [[A:%.*]] = alloca i64, align 8
+; TUNIT-NEXT: [[AP:%.*]] = call ptr @move246(i32 [[I]], ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR23]]
+; TUNIT-NEXT: store i8 2, ptr [[AP]], align 1
+; TUNIT-NEXT: call void @use3i8(i8 undef, i8 undef, i8 undef)
+; TUNIT-NEXT: ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@returnedPtrAccessesMultiple
+; CGSCC-SAME: (i32 [[I:%.*]]) {
+; CGSCC-NEXT: [[A:%.*]] = alloca i64, align 8
+; CGSCC-NEXT: [[AP:%.*]] = call ptr @move246(i32 [[I]], ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) [[A]]) #[[ATTR20]]
+; CGSCC-NEXT: [[G2:%.*]] = getelementptr i8, ptr [[A]], i32 2
+; CGSCC-NEXT: [[G4:%.*]] = getelementptr i8, ptr [[A]], i32 4
+; CGSCC-NEXT: [[G6:%.*]] = getelementptr i8, ptr [[A]], i32 6
+; CGSCC-NEXT: store i8 2, ptr [[AP]], align 1
+; CGSCC-NEXT: [[L2:%.*]] = load i8, ptr [[G2]], align 2
+; CGSCC-NEXT: [[L4:%.*]] = load i8, ptr [[G4]], align 4
+; CGSCC-NEXT: [[L6:%.*]] = load i8, ptr [[G6]], align 2
+; CGSCC-NEXT: call void @use3i8(i8 [[L2]], i8 [[L4]], i8 [[L6]])
+; CGSCC-NEXT: ret void
+;
+ %a = alloca i64
+ %ap = call ptr @move246(i32 %i, ptr %a)
+ %g2 = getelementptr i8, ptr %a, i32 2
+ %g4 = getelementptr i8, ptr %a, i32 4
+ %g6 = getelementptr i8, ptr %a, i32 6
+ store i8 2, ptr %ap
+ %l2 = load i8, ptr %g2
+ %l4 = load i8, ptr %g4
+ %l6 = load i8, ptr %g6
+ call void @use3i8(i8 %l2, i8 %l4, i8 %l6)
+ ret void
+}
+
+define void @returnedPtrAccessesMultiple2(i32 %i) {
+; TUNIT-LABEL: define {{[^@]+}}@returnedPtrAccessesMultiple2
+; TUNIT-SAME: (i32 [[I:%.*]]) {
+; TUNIT-NEXT: [[A:%.*]] = alloca i64, align 8
+; TUNIT-NEXT: [[AP:%.*]] = call ptr @move246(i32 [[I]], ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR23]]
+; TUNIT-NEXT: store i8 2, ptr [[AP]], align 1
+; TUNIT-NEXT: call void @use3i8(i8 noundef 0, i8 noundef 0, i8 noundef 0)
+; TUNIT-NEXT: ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@returnedPtrAccessesMultiple2
+; CGSCC-SAME: (i32 [[I:%.*]]) {
+; CGSCC-NEXT: [[A:%.*]] = alloca i64, align 8
+; CGSCC-NEXT: [[G2:%.*]] = getelementptr i8, ptr [[A]], i32 2
+; CGSCC-NEXT: [[G4:%.*]] = getelementptr i8, ptr [[A]], i32 4
+; CGSCC-NEXT: [[G6:%.*]] = getelementptr i8, ptr [[A]], i32 6
+; CGSCC-NEXT: store i8 0, ptr [[G2]], align 2
+; CGSCC-NEXT: store i8 0, ptr [[G4]], align 4
+; CGSCC-NEXT: store i8 0, ptr [[G6]], align 2
+; CGSCC-NEXT: [[AP:%.*]] = call ptr @move246(i32 [[I]], ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) [[A]]) #[[ATTR20]]
+; CGSCC-NEXT: store i8 2, ptr [[AP]], align 1
+; CGSCC-NEXT: [[L2:%.*]] = load i8, ptr [[G2]], align 2
+; CGSCC-NEXT: [[L4:%.*]] = load i8, ptr [[G4]], align 4
+; CGSCC-NEXT: [[L6:%.*]] = load i8, ptr [[G6]], align 2
+; CGSCC-NEXT: call void @use3i8(i8 [[L2]], i8 [[L4]], i8 [[L6]])
+; CGSCC-NEXT: ret void
+;
+ %a = alloca i64
+ %g2 = getelementptr i8, ptr %a, i32 2
+ %g4 = getelementptr i8, ptr %a, i32 4
+ %g6 = getelementptr i8, ptr %a, i32 6
+ store i8 0, ptr %g2
+ store i8 0, ptr %g4
+ store i8 0, ptr %g6
+ %ap = call ptr @move246(i32 %i, ptr %a)
+ store i8 2, ptr %ap
+ %l2 = load i8, ptr %g2
+ %l4 = load i8, ptr %g4
+ %l6 = load i8, ptr %g6
+ call void @use3i8(i8 %l2, i8 %l4, i8 %l6)
+ ret void
+}
+
declare void @llvm.assume(i1 noundef)
>From 05c128028db82beca16e1b23cb940f4a50c14cca Mon Sep 17 00:00:00 2001
From: Johannes Doerfert <jdoerfert at llnl.gov>
Date: Thu, 19 Sep 2024 23:48:17 -0700
Subject: [PATCH 2/3] [Attributor][FIX] Track the offsets of returned pointers
---
llvm/include/llvm/Transforms/IPO/Attributor.h | 48 +++++++
.../Transforms/IPO/AttributorAttributes.cpp | 127 ++++++++----------
.../Attributor/value-simplify-pointer-info.ll | 15 ++-
3 files changed, 117 insertions(+), 73 deletions(-)
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 921fe945539510..0c2b4d5dbea6f8 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -5783,6 +5783,53 @@ 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 = SmallSet<int64_t, 4>;
+ using const_iterator = VecTy::const_iterator;
+ VecTy Offsets;
+
+ const_iterator begin() const { return Offsets.begin(); }
+ const_iterator end() const { return Offsets.end(); }
+
+ bool operator==(const OffsetInfo &RHS) const {
+ return Offsets == RHS.Offsets;
+ }
+
+ bool operator!=(const OffsetInfo &RHS) const { return !(*this == RHS); }
+
+ bool insert(int64_t Offset) { return Offsets.insert(Offset).second; }
+ bool isUnassigned() const { return Offsets.size() == 0; }
+
+ bool isUnknown() const {
+ if (isUnassigned())
+ return false;
+ if (Offsets.size() == 1)
+ return *Offsets.begin() == AA::RangeTy::Unknown;
+ return false;
+ }
+
+ void setUnknown() {
+ Offsets.clear();
+ Offsets.insert(AA::RangeTy::Unknown);
+ }
+
+ void addToAll(int64_t Inc) {
+ VecTy NewOffsets;
+ for (auto &Offset : Offsets)
+ NewOffsets.insert(Offset + Inc);
+ Offsets = std::move(NewOffsets);
+ }
+
+ /// 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.
+ bool merge(const OffsetInfo &R) { return set_union(Offsets, R.Offsets); }
+ };
+
/// A container for a list of ranges.
struct RangeList {
// The set of ranges rarely contains more than one element, and is unlikely
@@ -6120,6 +6167,7 @@ struct AAPointerInfo : public AbstractAttribute {
virtual const_bin_iterator end() const = 0;
virtual int64_t numOffsetBins() const = 0;
virtual bool reachesReturn() const = 0;
+ virtual void addReturnedOffsets(OffsetInfo &) const = 0;
/// Call \p CB on all accesses that might interfere with \p Range and return
/// true if all such accesses were known and the callback returned true for
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 038a374e19f793..242ffbfb4fca7d 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -827,7 +827,7 @@ struct AA::PointerInfo::State : public AbstractState {
AccessList = R.AccessList;
OffsetBins = R.OffsetBins;
RemoteIMap = R.RemoteIMap;
- ReachesReturn = R.ReachesReturn;
+ ReturnedOffsets = R.ReturnedOffsets;
return *this;
}
@@ -838,7 +838,7 @@ struct AA::PointerInfo::State : public AbstractState {
std::swap(AccessList, R.AccessList);
std::swap(OffsetBins, R.OffsetBins);
std::swap(RemoteIMap, R.RemoteIMap);
- std::swap(ReachesReturn, R.ReachesReturn);
+ std::swap(ReturnedOffsets, R.ReturnedOffsets);
return *this;
}
@@ -883,13 +883,13 @@ struct AA::PointerInfo::State : public AbstractState {
/// Flag to determine if the underlying pointer is reaching a return statement
/// in the associated function or not. Returns in other functions cause
/// invalidation.
- bool ReachesReturn = false;
+ AAPointerInfo::OffsetInfo ReturnedOffsets;
/// See AAPointerInfo::forallInterferingAccesses.
bool forallInterferingAccesses(
AA::RangeTy Range,
function_ref<bool(const AAPointerInfo::Access &, bool)> CB) const {
- if (!isValidState() || ReachesReturn)
+ if (!isValidState() || !ReturnedOffsets.isUnassigned())
return false;
for (const auto &It : OffsetBins) {
@@ -911,7 +911,7 @@ struct AA::PointerInfo::State : public AbstractState {
Instruction &I,
function_ref<bool(const AAPointerInfo::Access &, bool)> CB,
AA::RangeTy &Range) const {
- if (!isValidState() || ReachesReturn)
+ if (!isValidState() || !ReturnedOffsets.isUnassigned())
return false;
auto LocalList = RemoteIMap.find(&I);
@@ -1010,54 +1010,9 @@ ChangeStatus AA::PointerInfo::State::addAccess(
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.
-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(); }
-
- bool operator==(const OffsetInfo &RHS) const {
- return Offsets == RHS.Offsets;
- }
-
- bool operator!=(const OffsetInfo &RHS) const { return !(*this == RHS); }
-
- 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); }
-};
-
#ifndef NDEBUG
-static raw_ostream &operator<<(raw_ostream &OS, const OffsetInfo &OI) {
+static raw_ostream &operator<<(raw_ostream &OS,
+ const AAPointerInfo::OffsetInfo &OI) {
ListSeparator LS;
OS << "[";
for (auto Offset : OI) {
@@ -1079,7 +1034,13 @@ struct AAPointerInfoImpl
(isValidState() ? (std::string("#") +
std::to_string(OffsetBins.size()) + " bins")
: "<invalid>") +
- (ReachesReturn ? " (returned)" : "");
+ (reachesReturn()
+ ? (" (returned:" +
+ join(map_range(ReturnedOffsets,
+ [](int64_t O) { return std::to_string(O); }),
+ ", ") +
+ ")")
+ : "");
}
/// See AbstractAttribute::manifest(...).
@@ -1092,13 +1053,34 @@ struct AAPointerInfoImpl
virtual int64_t numOffsetBins() const override {
return State::numOffsetBins();
}
- virtual bool reachesReturn() const override { return ReachesReturn; }
- ChangeStatus setReachesReturn(bool Val) {
- if (ReachesReturn == Val)
- return ChangeStatus::UNCHANGED;
+ virtual bool reachesReturn() const override {
+ return !ReturnedOffsets.isUnassigned();
+ }
+ virtual void addReturnedOffsets(OffsetInfo &OI) const override {
+ if (ReturnedOffsets.isUnknown()) {
+ OI.setUnknown();
+ return;
+ }
- ReachesReturn = Val;
- return ChangeStatus::CHANGED;
+ OffsetInfo MergedOI;
+ for (auto Offset : ReturnedOffsets) {
+ OffsetInfo TmpOI = OI;
+ TmpOI.addToAll(Offset);
+ MergedOI.merge(TmpOI);
+ }
+ OI = std::move(MergedOI);
+ }
+
+ ChangeStatus setReachesReturn(const OffsetInfo &ReachedReturnedOffsets) {
+ if (ReturnedOffsets.isUnknown())
+ return ChangeStatus::UNCHANGED;
+ if (ReachedReturnedOffsets.isUnknown()) {
+ ReturnedOffsets.setUnknown();
+ return ChangeStatus::CHANGED;
+ }
+ if (ReturnedOffsets.merge(ReachedReturnedOffsets))
+ return ChangeStatus::CHANGED;
+ return ChangeStatus::UNCHANGED;
}
bool forallInterferingAccesses(
@@ -1390,7 +1372,7 @@ struct AAPointerInfoImpl
ChangeStatus Changed = ChangeStatus::UNCHANGED;
const auto &OtherAAImpl = static_cast<const AAPointerInfoImpl &>(OtherAA);
bool IsByval = OtherAAImpl.getAssociatedArgument()->hasByValAttr();
- Changed |= setReachesReturn(OtherAAImpl.ReachesReturn);
+ Changed |= setReachesReturn(OtherAAImpl.ReturnedOffsets);
// Combine the accesses bin by bin.
const auto &State = OtherAAImpl.getState();
@@ -1485,7 +1467,7 @@ 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,
+ OffsetInfo::VecTy &Offsets, ChangeStatus &Changed,
Type &Ty) {
using namespace AA::PointerInfo;
auto Size = AA::RangeTy::Unknown;
@@ -1495,16 +1477,16 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
Size = AccessSize.getFixedValue();
// Make a strictly ascending list of offsets as required by addAccess()
- llvm::sort(Offsets);
- auto *Last = llvm::unique(Offsets);
- Offsets.erase(Last, Offsets.end());
+ SmallVector<int64_t> OffsetsSorted(Offsets.begin(), Offsets.end());
+ llvm::sort(OffsetsSorted);
VectorType *VT = dyn_cast<VectorType>(&Ty);
if (!VT || VT->getElementCount().isScalable() ||
!Content.value_or(nullptr) || !isa<Constant>(*Content) ||
(*Content)->getType() != VT ||
DL.getTypeStoreSize(VT->getElementType()).isScalable()) {
- Changed = Changed | addAccess(A, {Offsets, Size}, I, Content, Kind, &Ty);
+ Changed =
+ Changed | addAccess(A, {OffsetsSorted, Size}, I, Content, Kind, &Ty);
} else {
// Handle vector stores with constant content element-wise.
// TODO: We could look for the elements or create instructions
@@ -1689,8 +1671,12 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
// then check the call site return. Returns from other functions can't be
// tracked and are cause for invalidation.
if (auto *RI = dyn_cast<ReturnInst>(Usr)) {
- Changed |= setReachesReturn(RI->getFunction() == getAssociatedFunction());
- return ReachesReturn;
+ if (RI->getFunction() == getAssociatedFunction()) {
+ auto &PtrOI = OffsetInfoMap[CurPtr];
+ Changed |= setReachesReturn(PtrOI);
+ return true;
+ }
+ return false;
}
// For PHIs we need to take care of the recurrence explicitly as the value
@@ -1946,9 +1932,10 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
*this, IRPosition::callsite_returned(*CB), DepClassTy::REQUIRED);
if (!CSRetPI)
return false;
- Changed = translateAndAddState(A, *CSRetPI, OffsetInfoMap[CurPtr], *CB,
- IsRetMustAcc) |
- Changed;
+ OffsetInfo OI = OffsetInfoMap[CurPtr];
+ CSArgPI->addReturnedOffsets(OI);
+ Changed =
+ translateAndAddState(A, *CSRetPI, OI, *CB, IsRetMustAcc) | Changed;
return isValidState();
}
LLVM_DEBUG(dbgs() << "[AAPointerInfo] Call user not handled " << *CB
diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
index b16a0609f9b4e6..adcee750cae6e5 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
@@ -3456,7 +3456,7 @@ define void @returnedPtrAccesses() {
; TUNIT-NEXT: store i8 2, ptr [[A2]], align 1
; TUNIT-NEXT: store i8 4, ptr [[A4]], align 1
; TUNIT-NEXT: store i8 6, ptr [[A6]], align 1
-; TUNIT-NEXT: call void @use3i8(i8 undef, i8 undef, i8 undef)
+; TUNIT-NEXT: call void @use3i8(i8 2, i8 4, i8 6)
; TUNIT-NEXT: ret void
;
; CGSCC-LABEL: define {{[^@]+}}@returnedPtrAccesses() {
@@ -3499,7 +3499,7 @@ define void @returnedPtrAccessesMultiple(i32 %i) {
; TUNIT-NEXT: [[A:%.*]] = alloca i64, align 8
; TUNIT-NEXT: [[AP:%.*]] = call ptr @move246(i32 [[I]], ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR23]]
; TUNIT-NEXT: store i8 2, ptr [[AP]], align 1
-; TUNIT-NEXT: call void @use3i8(i8 undef, i8 undef, i8 undef)
+; TUNIT-NEXT: call void @use3i8(i8 2, i8 2, i8 2)
; TUNIT-NEXT: ret void
;
; CGSCC-LABEL: define {{[^@]+}}@returnedPtrAccessesMultiple
@@ -3533,9 +3533,18 @@ define void @returnedPtrAccessesMultiple2(i32 %i) {
; TUNIT-LABEL: define {{[^@]+}}@returnedPtrAccessesMultiple2
; TUNIT-SAME: (i32 [[I:%.*]]) {
; TUNIT-NEXT: [[A:%.*]] = alloca i64, align 8
+; TUNIT-NEXT: [[G2:%.*]] = getelementptr i8, ptr [[A]], i32 2
+; TUNIT-NEXT: [[G4:%.*]] = getelementptr i8, ptr [[A]], i32 4
+; TUNIT-NEXT: [[G6:%.*]] = getelementptr i8, ptr [[A]], i32 6
+; TUNIT-NEXT: store i8 0, ptr [[G2]], align 2
+; TUNIT-NEXT: store i8 0, ptr [[G4]], align 4
+; TUNIT-NEXT: store i8 0, ptr [[G6]], align 2
; TUNIT-NEXT: [[AP:%.*]] = call ptr @move246(i32 [[I]], ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR23]]
; TUNIT-NEXT: store i8 2, ptr [[AP]], align 1
-; TUNIT-NEXT: call void @use3i8(i8 noundef 0, i8 noundef 0, i8 noundef 0)
+; TUNIT-NEXT: [[L2:%.*]] = load i8, ptr [[G2]], align 2
+; TUNIT-NEXT: [[L4:%.*]] = load i8, ptr [[G4]], align 4
+; TUNIT-NEXT: [[L6:%.*]] = load i8, ptr [[G6]], align 2
+; TUNIT-NEXT: call void @use3i8(i8 noundef [[L2]], i8 noundef [[L4]], i8 noundef [[L6]])
; TUNIT-NEXT: ret void
;
; CGSCC-LABEL: define {{[^@]+}}@returnedPtrAccessesMultiple2
>From 0db0dea4c5f8c84c928edf95d48079d668d5e51b Mon Sep 17 00:00:00 2001
From: Johannes Doerfert <johannesdoerfert at gmail.com>
Date: Mon, 30 Sep 2024 14:49:20 -0700
Subject: [PATCH 3/3] Rename function.
---
llvm/include/llvm/Transforms/IPO/Attributor.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 0c2b4d5dbea6f8..09c1ac9c974db0 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -6167,7 +6167,7 @@ struct AAPointerInfo : public AbstractAttribute {
virtual const_bin_iterator end() const = 0;
virtual int64_t numOffsetBins() const = 0;
virtual bool reachesReturn() const = 0;
- virtual void addReturnedOffsets(OffsetInfo &) const = 0;
+ virtual void addReturnedOffsetsTo(OffsetInfo &) const = 0;
/// Call \p CB on all accesses that might interfere with \p Range and return
/// true if all such accesses were known and the callback returned true for
More information about the llvm-commits
mailing list