@@ -827,7 +827,7 @@ struct AA::PointerInfo::State : public AbstractState {
827
827
AccessList = R.AccessList ;
828
828
OffsetBins = R.OffsetBins ;
829
829
RemoteIMap = R.RemoteIMap ;
830
- ReachesReturn = R.ReachesReturn ;
830
+ ReturnedOffsets = R.ReturnedOffsets ;
831
831
return *this ;
832
832
}
833
833
@@ -838,7 +838,7 @@ struct AA::PointerInfo::State : public AbstractState {
838
838
std::swap (AccessList, R.AccessList );
839
839
std::swap (OffsetBins, R.OffsetBins );
840
840
std::swap (RemoteIMap, R.RemoteIMap );
841
- std::swap (ReachesReturn , R.ReachesReturn );
841
+ std::swap (ReturnedOffsets , R.ReturnedOffsets );
842
842
return *this ;
843
843
}
844
844
@@ -883,13 +883,13 @@ struct AA::PointerInfo::State : public AbstractState {
883
883
// / Flag to determine if the underlying pointer is reaching a return statement
884
884
// / in the associated function or not. Returns in other functions cause
885
885
// / invalidation.
886
- bool ReachesReturn = false ;
886
+ AAPointerInfo::OffsetInfo ReturnedOffsets ;
887
887
888
888
// / See AAPointerInfo::forallInterferingAccesses.
889
889
bool forallInterferingAccesses (
890
890
AA::RangeTy Range,
891
891
function_ref<bool (const AAPointerInfo::Access &, bool )> CB) const {
892
- if (!isValidState () || ReachesReturn )
892
+ if (!isValidState () || !ReturnedOffsets. isUnassigned () )
893
893
return false ;
894
894
895
895
for (const auto &It : OffsetBins) {
@@ -911,7 +911,7 @@ struct AA::PointerInfo::State : public AbstractState {
911
911
Instruction &I,
912
912
function_ref<bool (const AAPointerInfo::Access &, bool )> CB,
913
913
AA::RangeTy &Range) const {
914
- if (!isValidState () || ReachesReturn )
914
+ if (!isValidState () || !ReturnedOffsets. isUnassigned () )
915
915
return false ;
916
916
917
917
auto LocalList = RemoteIMap.find (&I);
@@ -1010,54 +1010,9 @@ ChangeStatus AA::PointerInfo::State::addAccess(
1010
1010
1011
1011
namespace {
1012
1012
1013
- // / A helper containing a list of offsets computed for a Use. Ideally this
1014
- // / list should be strictly ascending, but we ensure that only when we
1015
- // / actually translate the list of offsets to a RangeList.
1016
- struct OffsetInfo {
1017
- using VecTy = SmallVector<int64_t >;
1018
- using const_iterator = VecTy::const_iterator;
1019
- VecTy Offsets;
1020
-
1021
- const_iterator begin () const { return Offsets.begin (); }
1022
- const_iterator end () const { return Offsets.end (); }
1023
-
1024
- bool operator ==(const OffsetInfo &RHS) const {
1025
- return Offsets == RHS.Offsets ;
1026
- }
1027
-
1028
- bool operator !=(const OffsetInfo &RHS) const { return !(*this == RHS); }
1029
-
1030
- void insert (int64_t Offset) { Offsets.push_back (Offset); }
1031
- bool isUnassigned () const { return Offsets.size () == 0 ; }
1032
-
1033
- bool isUnknown () const {
1034
- if (isUnassigned ())
1035
- return false ;
1036
- if (Offsets.size () == 1 )
1037
- return Offsets.front () == AA::RangeTy::Unknown;
1038
- return false ;
1039
- }
1040
-
1041
- void setUnknown () {
1042
- Offsets.clear ();
1043
- Offsets.push_back (AA::RangeTy::Unknown);
1044
- }
1045
-
1046
- void addToAll (int64_t Inc) {
1047
- for (auto &Offset : Offsets) {
1048
- Offset += Inc;
1049
- }
1050
- }
1051
-
1052
- // / Copy offsets from \p R into the current list.
1053
- // /
1054
- // / Ideally all lists should be strictly ascending, but we defer that to the
1055
- // / actual use of the list. So we just blindly append here.
1056
- void merge (const OffsetInfo &R) { Offsets.append (R.Offsets ); }
1057
- };
1058
-
1059
1013
#ifndef NDEBUG
1060
- static raw_ostream &operator <<(raw_ostream &OS, const OffsetInfo &OI) {
1014
+ static raw_ostream &operator <<(raw_ostream &OS,
1015
+ const AAPointerInfo::OffsetInfo &OI) {
1061
1016
ListSeparator LS;
1062
1017
OS << " [" ;
1063
1018
for (auto Offset : OI) {
@@ -1079,7 +1034,13 @@ struct AAPointerInfoImpl
1079
1034
(isValidState () ? (std::string (" #" ) +
1080
1035
std::to_string (OffsetBins.size ()) + " bins" )
1081
1036
: " <invalid>" ) +
1082
- (ReachesReturn ? " (returned)" : " " );
1037
+ (reachesReturn ()
1038
+ ? (" (returned:" +
1039
+ join (map_range (ReturnedOffsets,
1040
+ [](int64_t O) { return std::to_string (O); }),
1041
+ " , " ) +
1042
+ " )" )
1043
+ : " " );
1083
1044
}
1084
1045
1085
1046
// / See AbstractAttribute::manifest(...).
@@ -1092,13 +1053,34 @@ struct AAPointerInfoImpl
1092
1053
virtual int64_t numOffsetBins () const override {
1093
1054
return State::numOffsetBins ();
1094
1055
}
1095
- virtual bool reachesReturn () const override { return ReachesReturn; }
1096
- ChangeStatus setReachesReturn (bool Val) {
1097
- if (ReachesReturn == Val)
1098
- return ChangeStatus::UNCHANGED;
1056
+ virtual bool reachesReturn () const override {
1057
+ return !ReturnedOffsets.isUnassigned ();
1058
+ }
1059
+ virtual void addReturnedOffsetsTo (OffsetInfo &OI) const override {
1060
+ if (ReturnedOffsets.isUnknown ()) {
1061
+ OI.setUnknown ();
1062
+ return ;
1063
+ }
1099
1064
1100
- ReachesReturn = Val;
1101
- return ChangeStatus::CHANGED;
1065
+ OffsetInfo MergedOI;
1066
+ for (auto Offset : ReturnedOffsets) {
1067
+ OffsetInfo TmpOI = OI;
1068
+ TmpOI.addToAll (Offset);
1069
+ MergedOI.merge (TmpOI);
1070
+ }
1071
+ OI = std::move (MergedOI);
1072
+ }
1073
+
1074
+ ChangeStatus setReachesReturn (const OffsetInfo &ReachedReturnedOffsets) {
1075
+ if (ReturnedOffsets.isUnknown ())
1076
+ return ChangeStatus::UNCHANGED;
1077
+ if (ReachedReturnedOffsets.isUnknown ()) {
1078
+ ReturnedOffsets.setUnknown ();
1079
+ return ChangeStatus::CHANGED;
1080
+ }
1081
+ if (ReturnedOffsets.merge (ReachedReturnedOffsets))
1082
+ return ChangeStatus::CHANGED;
1083
+ return ChangeStatus::UNCHANGED;
1102
1084
}
1103
1085
1104
1086
bool forallInterferingAccesses (
@@ -1390,7 +1372,7 @@ struct AAPointerInfoImpl
1390
1372
ChangeStatus Changed = ChangeStatus::UNCHANGED;
1391
1373
const auto &OtherAAImpl = static_cast <const AAPointerInfoImpl &>(OtherAA);
1392
1374
bool IsByval = OtherAAImpl.getAssociatedArgument ()->hasByValAttr ();
1393
- Changed |= setReachesReturn (OtherAAImpl.ReachesReturn );
1375
+ Changed |= setReachesReturn (OtherAAImpl.ReturnedOffsets );
1394
1376
1395
1377
// Combine the accesses bin by bin.
1396
1378
const auto &State = OtherAAImpl.getState ();
@@ -1485,7 +1467,7 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
1485
1467
// / Deal with an access and signal if it was handled successfully.
1486
1468
bool handleAccess (Attributor &A, Instruction &I,
1487
1469
std::optional<Value *> Content, AccessKind Kind,
1488
- SmallVectorImpl< int64_t > &Offsets, ChangeStatus &Changed,
1470
+ OffsetInfo::VecTy &Offsets, ChangeStatus &Changed,
1489
1471
Type &Ty) {
1490
1472
using namespace AA ::PointerInfo;
1491
1473
auto Size = AA::RangeTy::Unknown;
@@ -1495,16 +1477,16 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
1495
1477
Size = AccessSize.getFixedValue ();
1496
1478
1497
1479
// Make a strictly ascending list of offsets as required by addAccess()
1498
- llvm::sort (Offsets);
1499
- auto *Last = llvm::unique (Offsets);
1500
- Offsets.erase (Last, Offsets.end ());
1480
+ SmallVector<int64_t > OffsetsSorted (Offsets.begin (), Offsets.end ());
1481
+ llvm::sort (OffsetsSorted);
1501
1482
1502
1483
VectorType *VT = dyn_cast<VectorType>(&Ty);
1503
1484
if (!VT || VT->getElementCount ().isScalable () ||
1504
1485
!Content.value_or (nullptr ) || !isa<Constant>(*Content) ||
1505
1486
(*Content)->getType () != VT ||
1506
1487
DL.getTypeStoreSize (VT->getElementType ()).isScalable ()) {
1507
- Changed = Changed | addAccess (A, {Offsets, Size}, I, Content, Kind, &Ty);
1488
+ Changed =
1489
+ Changed | addAccess (A, {OffsetsSorted, Size}, I, Content, Kind, &Ty);
1508
1490
} else {
1509
1491
// Handle vector stores with constant content element-wise.
1510
1492
// TODO: We could look for the elements or create instructions
@@ -1689,8 +1671,12 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
1689
1671
// then check the call site return. Returns from other functions can't be
1690
1672
// tracked and are cause for invalidation.
1691
1673
if (auto *RI = dyn_cast<ReturnInst>(Usr)) {
1692
- Changed |= setReachesReturn (RI->getFunction () == getAssociatedFunction ());
1693
- return ReachesReturn;
1674
+ if (RI->getFunction () == getAssociatedFunction ()) {
1675
+ auto &PtrOI = OffsetInfoMap[CurPtr];
1676
+ Changed |= setReachesReturn (PtrOI);
1677
+ return true ;
1678
+ }
1679
+ return false ;
1694
1680
}
1695
1681
1696
1682
// For PHIs we need to take care of the recurrence explicitly as the value
@@ -1946,9 +1932,10 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
1946
1932
*this , IRPosition::callsite_returned (*CB), DepClassTy::REQUIRED);
1947
1933
if (!CSRetPI)
1948
1934
return false ;
1949
- Changed = translateAndAddState (A, *CSRetPI, OffsetInfoMap[CurPtr], *CB,
1950
- IsRetMustAcc) |
1951
- Changed;
1935
+ OffsetInfo OI = OffsetInfoMap[CurPtr];
1936
+ CSArgPI->addReturnedOffsetsTo (OI);
1937
+ Changed =
1938
+ translateAndAddState (A, *CSRetPI, OI, *CB, IsRetMustAcc) | Changed;
1952
1939
return isValidState ();
1953
1940
}
1954
1941
LLVM_DEBUG (dbgs () << " [AAPointerInfo] Call user not handled " << *CB
0 commit comments