Skip to content

Commit d2c37fc

Browse files
committed
[Attributor][FIX] Avoid dangling stack references in map
The old code did not account for new queries during an update, which caused us to leave stack RQIs in the map. We are now explicit about temporary vs non-temporary RQIs. Fixes: #64959
1 parent 3611300 commit d2c37fc

File tree

2 files changed

+74
-30
lines changed

2 files changed

+74
-30
lines changed

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3541,24 +3541,24 @@ struct CachedReachabilityAA : public BaseTy {
35413541
/// See AbstractAttribute::updateImpl(...).
35423542
ChangeStatus updateImpl(Attributor &A) override {
35433543
ChangeStatus Changed = ChangeStatus::UNCHANGED;
3544-
InUpdate = true;
35453544
for (unsigned u = 0, e = QueryVector.size(); u < e; ++u) {
35463545
RQITy *RQI = QueryVector[u];
3547-
if (RQI->Result == RQITy::Reachable::No && isReachableImpl(A, *RQI))
3546+
if (RQI->Result == RQITy::Reachable::No &&
3547+
isReachableImpl(A, *RQI, /*IsTemporaryRQI=*/false))
35483548
Changed = ChangeStatus::CHANGED;
35493549
}
3550-
InUpdate = false;
35513550
return Changed;
35523551
}
35533552

3554-
virtual bool isReachableImpl(Attributor &A, RQITy &RQI) = 0;
3553+
virtual bool isReachableImpl(Attributor &A, RQITy &RQI,
3554+
bool IsTemporaryRQI) = 0;
35553555

35563556
bool rememberResult(Attributor &A, typename RQITy::Reachable Result,
3557-
RQITy &RQI, bool UsedExclusionSet) {
3557+
RQITy &RQI, bool UsedExclusionSet, bool IsTemporaryRQI) {
35583558
RQI.Result = Result;
35593559

35603560
// Remove the temporary RQI from the cache.
3561-
if (!InUpdate)
3561+
if (IsTemporaryRQI)
35623562
QueryCache.erase(&RQI);
35633563

35643564
// Insert a plain RQI (w/o exclusion set) if that makes sense. Two options:
@@ -3576,7 +3576,7 @@ struct CachedReachabilityAA : public BaseTy {
35763576
}
35773577

35783578
// Check if we need to insert a new permanent RQI with the exclusion set.
3579-
if (!InUpdate && Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3579+
if (IsTemporaryRQI && Result != RQITy::Reachable::Yes && UsedExclusionSet) {
35803580
assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
35813581
"Did not expect empty set!");
35823582
RQITy *RQIPtr = new (A.Allocator)
@@ -3588,7 +3588,7 @@ struct CachedReachabilityAA : public BaseTy {
35883588
QueryCache.insert(RQIPtr);
35893589
}
35903590

3591-
if (Result == RQITy::Reachable::No && !InUpdate)
3591+
if (Result == RQITy::Reachable::No && IsTemporaryRQI)
35923592
A.registerForUpdate(*this);
35933593
return Result == RQITy::Reachable::Yes;
35943594
}
@@ -3629,7 +3629,6 @@ struct CachedReachabilityAA : public BaseTy {
36293629
}
36303630

36313631
private:
3632-
bool InUpdate = false;
36333632
SmallVector<RQITy *> QueryVector;
36343633
DenseSet<RQITy *> QueryCache;
36353634
};
@@ -3653,7 +3652,8 @@ struct AAIntraFnReachabilityFunction final
36533652
RQITy StackRQI(A, From, To, ExclusionSet, false);
36543653
typename RQITy::Reachable Result;
36553654
if (!NonConstThis->checkQueryCache(A, StackRQI, Result))
3656-
return NonConstThis->isReachableImpl(A, StackRQI);
3655+
return NonConstThis->isReachableImpl(A, StackRQI,
3656+
/*IsTemporaryRQI=*/true);
36573657
return Result == RQITy::Reachable::Yes;
36583658
}
36593659

@@ -3678,7 +3678,8 @@ struct AAIntraFnReachabilityFunction final
36783678
return Base::updateImpl(A);
36793679
}
36803680

3681-
bool isReachableImpl(Attributor &A, RQITy &RQI) override {
3681+
bool isReachableImpl(Attributor &A, RQITy &RQI,
3682+
bool IsTemporaryRQI) override {
36823683
const Instruction *Origin = RQI.From;
36833684
bool UsedExclusionSet = false;
36843685

@@ -3704,12 +3705,14 @@ struct AAIntraFnReachabilityFunction final
37043705
// possible.
37053706
if (FromBB == ToBB &&
37063707
WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3707-
return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet);
3708+
return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3709+
IsTemporaryRQI);
37083710

37093711
// Check if reaching the ToBB block is sufficient or if even that would not
37103712
// ensure reaching the target. In the latter case we are done.
37113713
if (!WillReachInBlock(ToBB->front(), *RQI.To, RQI.ExclusionSet))
3712-
return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet);
3714+
return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3715+
IsTemporaryRQI);
37133716

37143717
const Function *Fn = FromBB->getParent();
37153718
SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
@@ -3722,13 +3725,14 @@ struct AAIntraFnReachabilityFunction final
37223725
if (ExclusionBlocks.count(FromBB) &&
37233726
!WillReachInBlock(*RQI.From, *FromBB->getTerminator(),
37243727
RQI.ExclusionSet))
3725-
return rememberResult(A, RQITy::Reachable::No, RQI, true);
3728+
return rememberResult(A, RQITy::Reachable::No, RQI, true, IsTemporaryRQI);
37263729

37273730
auto *LivenessAA =
37283731
A.getAAFor<AAIsDead>(*this, getIRPosition(), DepClassTy::OPTIONAL);
37293732
if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
37303733
DeadBlocks.insert(ToBB);
3731-
return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet);
3734+
return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3735+
IsTemporaryRQI);
37323736
}
37333737

37343738
SmallPtrSet<const BasicBlock *, 16> Visited;
@@ -3747,11 +3751,11 @@ struct AAIntraFnReachabilityFunction final
37473751
}
37483752
// We checked before if we just need to reach the ToBB block.
37493753
if (SuccBB == ToBB)
3750-
return rememberResult(A, RQITy::Reachable::Yes, RQI,
3751-
UsedExclusionSet);
3754+
return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3755+
IsTemporaryRQI);
37523756
if (DT && ExclusionBlocks.empty() && DT->dominates(BB, ToBB))
3753-
return rememberResult(A, RQITy::Reachable::Yes, RQI,
3754-
UsedExclusionSet);
3757+
return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3758+
IsTemporaryRQI);
37553759

37563760
if (ExclusionBlocks.count(SuccBB)) {
37573761
UsedExclusionSet = true;
@@ -3762,7 +3766,8 @@ struct AAIntraFnReachabilityFunction final
37623766
}
37633767

37643768
DeadEdges.insert(LocalDeadEdges.begin(), LocalDeadEdges.end());
3765-
return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet);
3769+
return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3770+
IsTemporaryRQI);
37663771
}
37673772

37683773
/// See AbstractAttribute::trackStatistics()
@@ -10646,22 +10651,19 @@ struct AAInterFnReachabilityFunction
1064610651
RQITy StackRQI(A, From, To, ExclusionSet, false);
1064710652
typename RQITy::Reachable Result;
1064810653
if (!NonConstThis->checkQueryCache(A, StackRQI, Result))
10649-
return NonConstThis->isReachableImpl(A, StackRQI);
10654+
return NonConstThis->isReachableImpl(A, StackRQI,
10655+
/*IsTemporaryRQI=*/true);
1065010656
return Result == RQITy::Reachable::Yes;
1065110657
}
1065210658

10653-
bool isReachableImpl(Attributor &A, RQITy &RQI) override {
10654-
return isReachableImpl(A, RQI, nullptr);
10655-
}
10656-
1065710659
bool isReachableImpl(Attributor &A, RQITy &RQI,
10658-
SmallPtrSet<const Function *, 16> *Visited) {
10659-
10660+
bool IsTemporaryRQI) override {
1066010661
const Instruction *EntryI =
1066110662
&RQI.From->getFunction()->getEntryBlock().front();
1066210663
if (EntryI != RQI.From &&
1066310664
!instructionCanReach(A, *EntryI, *RQI.To, nullptr))
10664-
return rememberResult(A, RQITy::Reachable::No, RQI, false);
10665+
return rememberResult(A, RQITy::Reachable::No, RQI, false,
10666+
IsTemporaryRQI);
1066510667

1066610668
auto CheckReachableCallBase = [&](CallBase *CB) {
1066710669
auto *CBEdges = A.getAAFor<AACallEdges>(
@@ -10721,9 +10723,11 @@ struct AAInterFnReachabilityFunction
1072110723
if (!A.checkForAllCallLikeInstructions(CheckCallBase, *this,
1072210724
UsedAssumedInformation,
1072310725
/* CheckBBLivenessOnly */ true))
10724-
return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet);
10726+
return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10727+
IsTemporaryRQI);
1072510728

10726-
return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet);
10729+
return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10730+
IsTemporaryRQI);
1072710731
}
1072810732

1072910733
void trackStatistics() const override {}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %libomptarget-compile-generic
2+
// RUN: %libomptarget-compileopt-generic
3+
4+
#include <stdio.h>
5+
#define N 10
6+
7+
int main(void) {
8+
long int aa = 0;
9+
int res = 0;
10+
11+
int ng = 12;
12+
int cmom = 14;
13+
int nxyz = 5000;
14+
15+
#pragma omp target teams distribute num_teams(nxyz) \
16+
thread_limit(ng *(cmom - 1)) map(tofrom : aa)
17+
for (int gid = 0; gid < nxyz; gid++) {
18+
#pragma omp parallel for collapse(2)
19+
for (unsigned int g = 0; g < ng; g++) {
20+
for (unsigned int l = 0; l < cmom - 1; l++) {
21+
int a = 0;
22+
#pragma omp parallel for reduction(+ : a)
23+
for (int i = 0; i < N; i++) {
24+
a += i;
25+
}
26+
#pragma omp atomic
27+
aa += a;
28+
}
29+
}
30+
}
31+
long exp = (long)ng * (cmom - 1) * nxyz * (N * (N - 1) / 2);
32+
printf("The result is = %ld exp:%ld!\n", aa, exp);
33+
if (aa != exp) {
34+
printf("Failed %ld\n", aa);
35+
return 1;
36+
}
37+
// CHECK: Success
38+
printf("Success\n");
39+
return 0;
40+
}

0 commit comments

Comments
 (0)