@@ -827,7 +827,7 @@ struct AA::PointerInfo::State : public AbstractState {
827827 AccessList = R.AccessList ;
828828 OffsetBins = R.OffsetBins ;
829829 RemoteIMap = R.RemoteIMap ;
830- ReachesReturn = R.ReachesReturn ;
830+ ReturnedOffsets = R.ReturnedOffsets ;
831831 return *this ;
832832 }
833833
@@ -838,7 +838,7 @@ struct AA::PointerInfo::State : public AbstractState {
838838 std::swap (AccessList, R.AccessList );
839839 std::swap (OffsetBins, R.OffsetBins );
840840 std::swap (RemoteIMap, R.RemoteIMap );
841- std::swap (ReachesReturn , R.ReachesReturn );
841+ std::swap (ReturnedOffsets , R.ReturnedOffsets );
842842 return *this ;
843843 }
844844
@@ -883,13 +883,13 @@ struct AA::PointerInfo::State : public AbstractState {
883883 // / Flag to determine if the underlying pointer is reaching a return statement
884884 // / in the associated function or not. Returns in other functions cause
885885 // / invalidation.
886- bool ReachesReturn = false ;
886+ AAPointerInfo::OffsetInfo ReturnedOffsets ;
887887
888888 // / See AAPointerInfo::forallInterferingAccesses.
889889 bool forallInterferingAccesses (
890890 AA::RangeTy Range,
891891 function_ref<bool (const AAPointerInfo::Access &, bool )> CB) const {
892- if (!isValidState () || ReachesReturn )
892+ if (!isValidState () || !ReturnedOffsets. isUnassigned () )
893893 return false ;
894894
895895 for (const auto &It : OffsetBins) {
@@ -911,7 +911,7 @@ struct AA::PointerInfo::State : public AbstractState {
911911 Instruction &I,
912912 function_ref<bool (const AAPointerInfo::Access &, bool )> CB,
913913 AA::RangeTy &Range) const {
914- if (!isValidState () || ReachesReturn )
914+ if (!isValidState () || !ReturnedOffsets. isUnassigned () )
915915 return false ;
916916
917917 auto LocalList = RemoteIMap.find (&I);
@@ -1010,54 +1010,9 @@ ChangeStatus AA::PointerInfo::State::addAccess(
10101010
10111011namespace {
10121012
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-
10591013#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) {
10611016 ListSeparator LS;
10621017 OS << " [" ;
10631018 for (auto Offset : OI) {
@@ -1079,7 +1034,13 @@ struct AAPointerInfoImpl
10791034 (isValidState () ? (std::string (" #" ) +
10801035 std::to_string (OffsetBins.size ()) + " bins" )
10811036 : " <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+ : " " );
10831044 }
10841045
10851046 // / See AbstractAttribute::manifest(...).
@@ -1092,13 +1053,34 @@ struct AAPointerInfoImpl
10921053 virtual int64_t numOffsetBins () const override {
10931054 return State::numOffsetBins ();
10941055 }
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+ }
10991064
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;
11021084 }
11031085
11041086 bool forallInterferingAccesses (
@@ -1390,7 +1372,7 @@ struct AAPointerInfoImpl
13901372 ChangeStatus Changed = ChangeStatus::UNCHANGED;
13911373 const auto &OtherAAImpl = static_cast <const AAPointerInfoImpl &>(OtherAA);
13921374 bool IsByval = OtherAAImpl.getAssociatedArgument ()->hasByValAttr ();
1393- Changed |= setReachesReturn (OtherAAImpl.ReachesReturn );
1375+ Changed |= setReachesReturn (OtherAAImpl.ReturnedOffsets );
13941376
13951377 // Combine the accesses bin by bin.
13961378 const auto &State = OtherAAImpl.getState ();
@@ -1485,7 +1467,7 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
14851467 // / Deal with an access and signal if it was handled successfully.
14861468 bool handleAccess (Attributor &A, Instruction &I,
14871469 std::optional<Value *> Content, AccessKind Kind,
1488- SmallVectorImpl< int64_t > &Offsets, ChangeStatus &Changed,
1470+ OffsetInfo::VecTy &Offsets, ChangeStatus &Changed,
14891471 Type &Ty) {
14901472 using namespace AA ::PointerInfo;
14911473 auto Size = AA::RangeTy::Unknown;
@@ -1495,16 +1477,16 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
14951477 Size = AccessSize.getFixedValue ();
14961478
14971479 // 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);
15011482
15021483 VectorType *VT = dyn_cast<VectorType>(&Ty);
15031484 if (!VT || VT->getElementCount ().isScalable () ||
15041485 !Content.value_or (nullptr ) || !isa<Constant>(*Content) ||
15051486 (*Content)->getType () != VT ||
15061487 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);
15081490 } else {
15091491 // Handle vector stores with constant content element-wise.
15101492 // TODO: We could look for the elements or create instructions
@@ -1689,8 +1671,12 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
16891671 // then check the call site return. Returns from other functions can't be
16901672 // tracked and are cause for invalidation.
16911673 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 ;
16941680 }
16951681
16961682 // For PHIs we need to take care of the recurrence explicitly as the value
@@ -1946,9 +1932,10 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {
19461932 *this , IRPosition::callsite_returned (*CB), DepClassTy::REQUIRED);
19471933 if (!CSRetPI)
19481934 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;
19521939 return isValidState ();
19531940 }
19541941 LLVM_DEBUG (dbgs () << " [AAPointerInfo] Call user not handled " << *CB
0 commit comments