Skip to content

Commit 586de0a

Browse files
committed
Fix KnownSafety optimization bugs in ARCSequenceOpts
While doing bottom up dataflow, if we encounter an unmatched retain instruction, that can pair with a 'KnownSafe' already visited release instruction, we turn off KnownSafety if the two RCIdentities mayAlias. This is done in BottomUpRefCountState::checkAndResetKnownSafety. In order to determine if a retain is umatched, we look at IncToDecStateMap. If a retain was matched during bottom up dataflow, it is always found in IncToDecStateMap with value of the matched release's BottomUpRefCountState. Similarly, during top down dataflow, if we encounter an unmatched release instruction, that can pair with a 'KnownSafe' already visited retain instruction, we turn off KnownSafety if the two RCIdentities mayAlias. This is done in TopDownRefCountState::checkAndResetKnownSafety. In order to determine if a release is umatched, we look at DecToIncStateMap. If a release was matched during top down dataflow, it is always found in DecToIncStateMap with value of the matched retain's TopDownRefCountState. For ARCLoopOpts, during bottom up and top down traversal of a region with a nested loop, we find if the retain/release in the loop summary was matched or not by looking at the persistent RefCountInstToMatched map. This map is populated when processing the nested loop region from the IncToDecStateMap/DecToStateMap which gets thrown away after the loop region is processed. This fixes the bugs in both ARCSequenceOpts without loop support and with loop support.
1 parent 132d49f commit 586de0a

11 files changed

+732
-25
lines changed

lib/SILOptimizer/ARC/ARCRegionState.cpp

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ bool ARCRegionState::processBlockBottomUp(
204204
// that the instruction "visits".
205205
SILValue Op = Result.RCIdentity;
206206

207+
std::function<bool(SILInstruction *)> checkIfRefCountInstIsMatched =
208+
[&IncToDecStateMap](SILInstruction *Inst) {
209+
assert(isa<StrongRetainInst>(Inst) || isa<RetainValueInst>(Inst));
210+
return IncToDecStateMap.find(Inst) != IncToDecStateMap.end();
211+
};
212+
207213
// For all other (reference counted value, ref count state) we are
208214
// tracking...
209215
for (auto &OtherState : getBottomupStates()) {
@@ -217,6 +223,8 @@ bool ARCRegionState::processBlockBottomUp(
217223
continue;
218224

219225
OtherState->second.updateForSameLoopInst(I, AA);
226+
OtherState->second.checkAndResetKnownSafety(
227+
I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA);
220228
}
221229
}
222230

@@ -245,8 +253,9 @@ static bool hasEarlyExits(
245253

246254
bool ARCRegionState::processLoopBottomUp(
247255
const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI,
256+
RCIdentityFunctionInfo *RCIA,
248257
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &RegionStateInfo,
249-
ImmutablePointerSetFactory<SILInstruction> &SetFactory) {
258+
llvm::DenseSet<SILInstruction *> &UnmatchedRefCountInsts) {
250259
ARCRegionState *State = RegionStateInfo[R];
251260

252261
// If we find that we have non-leaking early exits, clear state
@@ -256,14 +265,23 @@ bool ARCRegionState::processLoopBottomUp(
256265
return false;
257266
}
258267

268+
std::function<bool(SILInstruction *)> checkIfRefCountInstIsMatched =
269+
[&UnmatchedRefCountInsts](SILInstruction *Inst) {
270+
assert(isa<StrongRetainInst>(Inst) || isa<RetainValueInst>(Inst));
271+
return UnmatchedRefCountInsts.find(Inst) == UnmatchedRefCountInsts.end();
272+
};
273+
259274
// For each state that we are currently tracking, apply our summarized
260275
// instructions to it.
261276
for (auto &OtherState : getBottomupStates()) {
262277
if (!OtherState.hasValue())
263278
continue;
264279

265-
for (auto *I : State->getSummarizedInterestingInsts())
280+
for (auto *I : State->getSummarizedInterestingInsts()) {
266281
OtherState->second.updateForDifferentLoopInst(I, AA);
282+
OtherState->second.checkAndResetKnownSafety(
283+
I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA);
284+
}
267285
}
268286

269287
return false;
@@ -273,6 +291,7 @@ bool ARCRegionState::processBottomUp(
273291
AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA,
274292
EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI,
275293
bool FreezeOwnedArgEpilogueReleases,
294+
llvm::DenseSet<SILInstruction *> &UnmatchedRefCountInsts,
276295
BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap,
277296
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &RegionStateInfo,
278297
ImmutablePointerSetFactory<SILInstruction> &SetFactory) {
@@ -281,7 +300,8 @@ bool ARCRegionState::processBottomUp(
281300
// We only process basic blocks for now. This ensures that we always propagate
282301
// the empty set from loops.
283302
if (!R->isBlock())
284-
return processLoopBottomUp(R, AA, LRFI, RegionStateInfo, SetFactory);
303+
return processLoopBottomUp(R, AA, LRFI, RCIA, RegionStateInfo,
304+
UnmatchedRefCountInsts);
285305

286306
return processBlockBottomUp(R, AA, RCIA, EAFI, LRFI, FreezeOwnedArgEpilogueReleases,
287307
IncToDecStateMap, SetFactory);
@@ -337,6 +357,12 @@ bool ARCRegionState::processBlockTopDown(
337357
// that the instruction "visits".
338358
SILValue Op = Result.RCIdentity;
339359

360+
std::function<bool(SILInstruction *)> checkIfRefCountInstIsMatched =
361+
[&DecToIncStateMap](SILInstruction *Inst) {
362+
assert(isa<StrongReleaseInst>(Inst) || isa<ReleaseValueInst>(Inst));
363+
return DecToIncStateMap.find(Inst) != DecToIncStateMap.end();
364+
};
365+
340366
// For all other [(SILValue, TopDownState)] we are tracking...
341367
for (auto &OtherState : getTopDownStates()) {
342368
// If the other state's value is blotted, skip it.
@@ -350,6 +376,8 @@ bool ARCRegionState::processBlockTopDown(
350376
continue;
351377

352378
OtherState->second.updateForSameLoopInst(I, AA);
379+
OtherState->second.checkAndResetKnownSafety(
380+
I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA);
353381
}
354382
}
355383

@@ -358,8 +386,8 @@ bool ARCRegionState::processBlockTopDown(
358386

359387
bool ARCRegionState::processLoopTopDown(
360388
const LoopRegion *R, ARCRegionState *State, AliasAnalysis *AA,
361-
LoopRegionFunctionInfo *LRFI,
362-
ImmutablePointerSetFactory<SILInstruction> &SetFactory) {
389+
LoopRegionFunctionInfo *LRFI, RCIdentityFunctionInfo *RCIA,
390+
llvm::DenseSet<SILInstruction *> &UnmatchedRefCountInsts) {
363391

364392
assert(R->isLoop() && "We assume we are processing a loop");
365393

@@ -375,14 +403,23 @@ bool ARCRegionState::processLoopTopDown(
375403
assert(PredRegion->isBlock() && "Expected the predecessor region to be a "
376404
"block");
377405

406+
std::function<bool(SILInstruction *)> checkIfRefCountInstIsMatched =
407+
[&UnmatchedRefCountInsts](SILInstruction *Inst) {
408+
assert(isa<StrongReleaseInst>(Inst) || isa<ReleaseValueInst>(Inst));
409+
return UnmatchedRefCountInsts.find(Inst) == UnmatchedRefCountInsts.end();
410+
};
411+
378412
// For each state that we are currently tracking, apply our summarized
379413
// instructions to it.
380414
for (auto &OtherState : getTopDownStates()) {
381415
if (!OtherState.hasValue())
382416
continue;
383417

384-
for (auto *I : State->getSummarizedInterestingInsts())
418+
for (auto *I : State->getSummarizedInterestingInsts()) {
385419
OtherState->second.updateForDifferentLoopInst(I, AA);
420+
OtherState->second.checkAndResetKnownSafety(
421+
I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA);
422+
}
386423
}
387424

388425
return false;
@@ -391,6 +428,7 @@ bool ARCRegionState::processLoopTopDown(
391428
bool ARCRegionState::processTopDown(
392429
AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA,
393430
LoopRegionFunctionInfo *LRFI,
431+
llvm::DenseSet<SILInstruction *> &UnmatchedRefCountInsts,
394432
BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
395433
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &RegionStateInfo,
396434
ImmutablePointerSetFactory<SILInstruction> &SetFactory) {
@@ -399,7 +437,8 @@ bool ARCRegionState::processTopDown(
399437
// We only process basic blocks for now. This ensures that we always propagate
400438
// the empty set from loops.
401439
if (!R->isBlock())
402-
return processLoopTopDown(R, RegionStateInfo[R], AA, LRFI, SetFactory);
440+
return processLoopTopDown(R, RegionStateInfo[R], AA, LRFI, RCIA,
441+
UnmatchedRefCountInsts);
403442

404443
return processBlockTopDown(*R->getBlock(), AA, RCIA, DecToIncStateMap,
405444
SetFactory);

lib/SILOptimizer/ARC/ARCRegionState.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class ARCRegionState {
188188
bool processTopDown(
189189
AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA,
190190
LoopRegionFunctionInfo *LRFI,
191+
llvm::DenseSet<SILInstruction *> &UnmatchedRefCountInsts,
191192
BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
192193
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &LoopRegionState,
193194
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
@@ -200,6 +201,7 @@ class ARCRegionState {
200201
AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA,
201202
EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI,
202203
bool FreezeOwnedArgEpilogueReleases,
204+
llvm::DenseSet<SILInstruction *> &UnmatchedRefCountInsts,
203205
BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap,
204206
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &RegionStateInfo,
205207
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
@@ -227,17 +229,18 @@ class ARCRegionState {
227229
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
228230
bool processLoopBottomUp(
229231
const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI,
232+
RCIdentityFunctionInfo *RCIA,
230233
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &RegionStateInfo,
231-
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
234+
llvm::DenseSet<SILInstruction *> &UnmatchedRefCountInsts);
232235

233236
bool processBlockTopDown(
234237
SILBasicBlock &BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA,
235238
BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
236239
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
237-
bool
238-
processLoopTopDown(const LoopRegion *R, ARCRegionState *State,
239-
AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI,
240-
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
240+
bool processLoopTopDown(
241+
const LoopRegion *R, ARCRegionState *State, AliasAnalysis *AA,
242+
LoopRegionFunctionInfo *LRFI, RCIdentityFunctionInfo *RCIA,
243+
llvm::DenseSet<SILInstruction *> &UnmatchedRefCountInsts);
241244

242245
void summarizeLoop(
243246
const LoopRegion *R, LoopRegionFunctionInfo *LRFI,

lib/SILOptimizer/ARC/ARCSequenceOpts.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ bool LoopARCPairingContext::processRegion(const LoopRegion *Region,
156156
}
157157

158158
MadeChange |= MatchedPair;
159+
Evaluator.saveMatchingInfo(Region);
159160
Evaluator.clearLoopState(Region);
160161
Context.DecToIncStateMap.clear();
161162
Context.IncToDecStateMap.clear();

lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) {
7676
}
7777
}
7878

79+
std::function<bool(SILInstruction *)> checkIfRefCountInstIsMatched =
80+
[&DecToIncStateMap = DecToIncStateMap](SILInstruction *Inst) {
81+
assert(isa<StrongReleaseInst>(Inst) || isa<ReleaseValueInst>(Inst));
82+
return DecToIncStateMap.find(Inst) != DecToIncStateMap.end();
83+
};
84+
7985
// For each instruction I in BB...
8086
for (auto &I : BB) {
8187

@@ -94,7 +100,7 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) {
94100

95101
// This SILValue may be null if we were unable to find a specific RCIdentity
96102
// that the instruction "visits".
97-
SILValue Op = Result.RCIdentity;
103+
SILValue CurrentRC = Result.RCIdentity;
98104

99105
// For all other [(SILValue, TopDownState)] we are tracking...
100106
for (auto &OtherState : BBState.getTopDownStates()) {
@@ -105,10 +111,12 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) {
105111
// If we visited an increment or decrement successfully (and thus Op is
106112
// set), if this is the state for this operand, skip it. We already
107113
// processed it.
108-
if (Op && OtherState->first == Op)
114+
if (CurrentRC && OtherState->first == CurrentRC)
109115
continue;
110116

111117
OtherState->second.updateForSameLoopInst(&I, AA);
118+
OtherState->second.checkAndResetKnownSafety(
119+
&I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA);
112120
}
113121
}
114122

@@ -221,6 +229,12 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp(
221229
RCIA, EAFI, BBState, FreezeOwnedArgEpilogueReleases, IncToDecStateMap,
222230
SetFactory);
223231

232+
std::function<bool(SILInstruction *)> checkIfRefCountInstIsMatched =
233+
[&IncToDecStateMap = IncToDecStateMap](SILInstruction *Inst) {
234+
assert(isa<StrongRetainInst>(Inst) || isa<RetainValueInst>(Inst));
235+
return IncToDecStateMap.find(Inst) != IncToDecStateMap.end();
236+
};
237+
224238
auto II = BB.rbegin();
225239
if (!isARCSignificantTerminator(&cast<TermInst>(*II))) {
226240
II++;
@@ -246,7 +260,7 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp(
246260

247261
// This SILValue may be null if we were unable to find a specific RCIdentity
248262
// that the instruction "visits".
249-
SILValue Op = Result.RCIdentity;
263+
SILValue CurrentRC = Result.RCIdentity;
250264

251265
// For all other (reference counted value, ref count state) we are
252266
// tracking...
@@ -257,10 +271,12 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp(
257271

258272
// If this is the state associated with the instruction that we are
259273
// currently visiting, bail.
260-
if (Op && OtherState->first == Op)
274+
if (CurrentRC && OtherState->first == CurrentRC)
261275
continue;
262276

263277
OtherState->second.updateForSameLoopInst(&I, AA);
278+
OtherState->second.checkAndResetKnownSafety(
279+
&I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA);
264280
}
265281
}
266282

lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ bool LoopARCSequenceDataflowEvaluator::processLoopTopDown(const LoopRegion *R) {
110110

111111
// Then perform the dataflow.
112112
NestingDetected |= SubregionData.processTopDown(
113-
AA, RCFI, LRFI, DecToIncStateMap, RegionStateInfo, SetFactory);
113+
AA, RCFI, LRFI, UnmatchedRefCountInsts, DecToIncStateMap,
114+
RegionStateInfo, SetFactory);
114115
}
115116

116117
return NestingDetected;
@@ -214,8 +215,9 @@ bool LoopARCSequenceDataflowEvaluator::processLoopBottomUp(
214215

215216
// Then perform the region optimization.
216217
NestingDetected |= SubregionData.processBottomUp(
217-
AA, RCFI, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, IncToDecStateMap,
218-
RegionStateInfo, SetFactory);
218+
AA, RCFI, EAFI, LRFI, FreezeOwnedArgEpilogueReleases,
219+
UnmatchedRefCountInsts, IncToDecStateMap, RegionStateInfo,
220+
SetFactory);
219221
}
220222

221223
return NestingDetected;
@@ -284,8 +286,7 @@ void LoopARCSequenceDataflowEvaluator::dumpDataflowResults() {
284286
}
285287
}
286288

287-
void LoopARCSequenceDataflowEvaluator::summarizeLoop(
288-
const LoopRegion *R) {
289+
void LoopARCSequenceDataflowEvaluator::summarizeLoop(const LoopRegion *R) {
289290
RegionStateInfo[R]->summarize(LRFI, RegionStateInfo);
290291
}
291292

@@ -314,3 +315,34 @@ void LoopARCSequenceDataflowEvaluator::removeInterestingInst(
314315
auto *Region = LRFI->getRegion(I->getParent());
315316
RegionStateInfo[Region]->removeInterestingInst(I);
316317
}
318+
319+
// Compute if a RefCountInst was unmatched and populate in the persistent
320+
// UnmatchedRefCountInsts.
321+
// This can be done by looking up the RefCountInst in IncToDecStateMap or
322+
// DecToIncStateMap. If the StrongIncrement was matched to a StrongDecrement,
323+
// it will be found in IncToDecStateMap. If the StrongDecrement was matched to
324+
// a StrongIncrement, it will be found in DecToIncStateMap.
325+
void LoopARCSequenceDataflowEvaluator::saveMatchingInfo(const LoopRegion *R) {
326+
if (R->isFunction())
327+
return;
328+
for (unsigned SubregionID : R->getSubregions()) {
329+
auto *Subregion = LRFI->getRegion(SubregionID);
330+
if (!Subregion->isBlock())
331+
continue;
332+
auto *RegionState = RegionStateInfo[Subregion];
333+
for (auto Inst : RegionState->getSummarizedInterestingInsts()) {
334+
if (isa<StrongRetainInst>(Inst) || isa<RetainValueInst>(Inst)) {
335+
// unmatched if not found in IncToDecStateMap
336+
if (IncToDecStateMap.find(Inst) == IncToDecStateMap.end())
337+
UnmatchedRefCountInsts.insert(Inst);
338+
continue;
339+
}
340+
if (isa<StrongReleaseInst>(Inst) || isa<ReleaseValueInst>(Inst)) {
341+
// unmatched if not found in DecToIncStateMap
342+
if (DecToIncStateMap.find(Inst) == DecToIncStateMap.end())
343+
UnmatchedRefCountInsts.insert(Inst);
344+
continue;
345+
}
346+
}
347+
}
348+
}

lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ class LoopARCSequenceDataflowEvaluator {
7272
/// Stashed information for each region.
7373
llvm::DenseMap<const LoopRegion *, ARCRegionState *> RegionStateInfo;
7474

75+
/// Set of unmatched RefCountInsts
76+
llvm::DenseSet<SILInstruction *> UnmatchedRefCountInsts;
77+
7578
public:
7679
LoopARCSequenceDataflowEvaluator(
7780
SILFunction &F, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI,
@@ -108,6 +111,10 @@ class LoopARCSequenceDataflowEvaluator {
108111
/// Remove \p I from the interesting instruction list of its parent block.
109112
void removeInterestingInst(SILInstruction *I);
110113

114+
/// Compute if a RefCountInst was unmatched and populate the persistent
115+
/// UnmatchedRefCountInsts set.
116+
void saveMatchingInfo(const LoopRegion *R);
117+
111118
/// Clear the folding node set of the set factory we have stored internally.
112119
void clearSetFactory() {
113120
SetFactory.clear();

0 commit comments

Comments
 (0)