@@ -87,7 +87,12 @@ class SelectEnforcement {
87
87
void propagateEscapesFrom (SILBasicBlock *bb);
88
88
89
89
bool hasPotentiallyEscapedAt (SILInstruction *inst);
90
- bool hasPotentiallyEscapedAtAnyReachableBlock (BeginAccessInst *access);
90
+
91
+ typedef llvm::SmallSetVector<SILBasicBlock*, 8 > BlockSetVector;
92
+ void findBlocksAccessedAcross (EndAccessInst *endAccess,
93
+ BlockSetVector &blocksAccessedAcross);
94
+ bool hasPotentiallyEscapedAtAnyReachableBlock (
95
+ BeginAccessInst *access, BlockSetVector &blocksAccessedAcross);
91
96
92
97
void updateAccesses ();
93
98
void updateAccess (BeginAccessInst *access);
@@ -216,22 +221,53 @@ bool SelectEnforcement::hasPotentiallyEscapedAt(SILInstruction *point) {
216
221
return false ;
217
222
}
218
223
219
- bool SelectEnforcement::hasPotentiallyEscapedAtAnyReachableBlock (
220
- BeginAccessInst *access) {
224
+ // / Add all blocks to `Worklist` between the given `endAccess` and its
225
+ // / `begin_access` in which the access is active at the end of the block.
226
+ void SelectEnforcement::findBlocksAccessedAcross (
227
+ EndAccessInst *endAccess, BlockSetVector &blocksAccessedAcross) {
228
+
221
229
// Fast path: we're not tracking any escapes. (But the box should
222
230
// probably have been promoted to the stack in this case.)
223
231
if (StateMap.empty ())
224
- return false ;
232
+ return ;
233
+
234
+ SILBasicBlock *beginBB = endAccess->getBeginAccess ()->getParent ();
235
+ if (endAccess->getParent () == beginBB)
236
+ return ;
237
+
238
+ assert (Worklist.empty ());
239
+ Worklist.push_back (endAccess->getParent ());
240
+ while (!Worklist.empty ()) {
241
+ SILBasicBlock *bb = Worklist.pop_back_val ();
242
+ for (auto *predBB : bb->getPredecessorBlocks ()) {
243
+ if (!blocksAccessedAcross.insert (predBB)) continue ;
244
+ if (predBB == beginBB) continue ;
245
+ Worklist.push_back (predBB);
246
+ }
247
+ }
248
+ }
225
249
226
- auto bb = access->getParent ();
250
+ bool SelectEnforcement::hasPotentiallyEscapedAtAnyReachableBlock (
251
+ BeginAccessInst *access, BlockSetVector &blocksAccessedAcross) {
227
252
228
253
assert (Worklist.empty ());
229
254
SmallPtrSet<SILBasicBlock*, 8 > visited;
230
- visited.insert (bb);
231
- Worklist.push_back (bb);
255
+
256
+ // Don't follow any paths that lead to an end_access.
257
+ for (auto endAccess : access->getEndAccesses ())
258
+ visited.insert (endAccess->getParent ());
259
+
260
+ // / Initialize the worklist with all blocks that exit the access path.
261
+ for (SILBasicBlock *bb : blocksAccessedAcross) {
262
+ for (SILBasicBlock *succBB : bb->getSuccessorBlocks ()) {
263
+ if (blocksAccessedAcross.count (succBB)) continue ;
264
+ if (visited.insert (succBB).second )
265
+ Worklist.push_back (succBB);
266
+ }
267
+ }
232
268
233
269
while (!Worklist.empty ()) {
234
- bb = Worklist.pop_back_val ();
270
+ SILBasicBlock * bb = Worklist.pop_back_val ();
235
271
assert (visited.count (bb));
236
272
237
273
// If we're tracking information for this block, there's an escape.
@@ -259,27 +295,23 @@ void SelectEnforcement::updateAccess(BeginAccessInst *access) {
259
295
assert (access->getEnforcement () == SILAccessEnforcement::Unknown);
260
296
261
297
// Check whether the variable escaped before any of the end_accesses.
262
- bool anyDynamic = false ;
263
- bool hasEndAccess = false ;
298
+ BlockSetVector blocksAccessedAcross;
264
299
for (auto endAccess : access->getEndAccesses ()) {
265
- hasEndAccess = true ;
266
- if (hasPotentiallyEscapedAt (endAccess)) {
267
- anyDynamic = true ;
268
- break ;
269
- }
300
+ if (hasPotentiallyEscapedAt (endAccess))
301
+ return setDynamicEnforcement (access);
302
+
303
+ // Add all blocks to blocksAccessedAcross between begin_access and this
304
+ // end_access.
305
+ findBlocksAccessedAcross (endAccess, blocksAccessedAcross);
270
306
}
307
+ assert (blocksAccessedAcross.empty ()
308
+ || blocksAccessedAcross.count (access->getParent ()));
271
309
272
- // If so, make the access dynamic.
273
- if (anyDynamic)
310
+ // For every path through this access that doesn't reach an end_access, check
311
+ // if any block reachable from that path can see an escaped value.
312
+ if (hasPotentiallyEscapedAtAnyReachableBlock (access, blocksAccessedAcross)) {
274
313
return setDynamicEnforcement (access);
275
-
276
- // Otherwise, if there are no end_access instructions,
277
- // check the terminators of every reachable block.
278
- if (!hasEndAccess) {
279
- if (hasPotentiallyEscapedAtAnyReachableBlock (access))
280
- return setDynamicEnforcement (access);
281
314
}
282
-
283
315
// Otherwise, use static enforcement.
284
316
setStaticEnforcement (access);
285
317
}
0 commit comments