@@ -156,7 +156,7 @@ class MemoryToRegisters {
156
156
SILBuilder B;
157
157
158
158
// / Check if the AllocStackInst \p ASI is only written into.
159
- bool isWriteOnlyAllocation (AllocStackInst *ASI );
159
+ bool isWriteOnlyAllocation (SingleValueInstruction *addr );
160
160
161
161
// / Promote all of the AllocStacks in a single basic block in one
162
162
// / linear scan. Note: This function deletes all of the users of the
@@ -227,7 +227,7 @@ static bool isAddressForLoad(SILInstruction *I, SILBasicBlock *&singleBlock,
227
227
// / Returns true if \p I is a dead struct_element_addr or tuple_element_addr.
228
228
static bool isDeadAddrProjection (SILInstruction *I) {
229
229
if (!isa<UncheckedAddrCastInst>(I) && !isa<StructElementAddrInst>(I) &&
230
- !isa<TupleElementAddrInst>(I))
230
+ !isa<TupleElementAddrInst>(I) && !isa<BeginAccessInst>(I) )
231
231
return false ;
232
232
233
233
// Recursively search for uses which are dead themselves.
@@ -241,8 +241,8 @@ static bool isDeadAddrProjection(SILInstruction *I) {
241
241
242
242
// / Returns true if this AllocStacks is captured.
243
243
// / Sets \p inSingleBlock to true if all uses of \p ASI are in a single block.
244
- static bool isCaptured (AllocStackInst *ASI, bool &inSingleBlock) {
245
-
244
+ static bool isCaptured (SingleValueInstruction *ASI, bool &inSingleBlock) {
245
+
246
246
SILBasicBlock *singleBlock = ASI->getParent ();
247
247
248
248
// For all users of the AllocStack instruction.
@@ -262,9 +262,10 @@ static bool isCaptured(AllocStackInst *ASI, bool &inSingleBlock) {
262
262
if (SI->getDest () == ASI)
263
263
continue ;
264
264
265
- // Deallocation is also okay, as are DebugValueAddr. We will turn
266
- // the latter into DebugValue.
267
- if (isa<DeallocStackInst>(II) || isa<DebugValueAddrInst>(II))
265
+ // Deallocation is also okay, as are EndAccess and DebugValueAddr. We will
266
+ // turn the latter into DebugValue.
267
+ if (isa<DeallocStackInst>(II) || isa<DebugValueAddrInst>(II) ||
268
+ isa<EndAccessInst>(II))
268
269
continue ;
269
270
270
271
// Destroys of loadable types can be rewritten as releases, so
@@ -273,6 +274,13 @@ static bool isCaptured(AllocStackInst *ASI, bool &inSingleBlock) {
273
274
if (DAI->getOperand ()->getType ().isLoadable (*DAI->getFunction ()))
274
275
continue ;
275
276
277
+ // Begin access is OK if it isn't captured.
278
+ if (auto *beginAccess = dyn_cast<BeginAccessInst>(II)) {
279
+ if (isCaptured (beginAccess, inSingleBlock))
280
+ return true ;
281
+ continue ;
282
+ }
283
+
276
284
// Other instructions are assumed to capture the AllocStack.
277
285
LLVM_DEBUG (llvm::dbgs () << " *** AllocStack is captured by: " << *II);
278
286
return true ;
@@ -284,9 +292,9 @@ static bool isCaptured(AllocStackInst *ASI, bool &inSingleBlock) {
284
292
}
285
293
286
294
// / Returns true if the AllocStack is only stored into.
287
- bool MemoryToRegisters::isWriteOnlyAllocation (AllocStackInst *ASI ) {
295
+ bool MemoryToRegisters::isWriteOnlyAllocation (SingleValueInstruction *addr ) {
288
296
// For all users of the AllocStack:
289
- for (auto UI = ASI ->use_begin (), E = ASI ->use_end (); UI != E; ++UI) {
297
+ for (auto UI = addr ->use_begin (), E = addr ->use_end (); UI != E; ++UI) {
290
298
SILInstruction *II = UI->getUser ();
291
299
292
300
// It is okay to store into this AllocStack.
@@ -300,11 +308,16 @@ bool MemoryToRegisters::isWriteOnlyAllocation(AllocStackInst *ASI) {
300
308
301
309
// If we haven't already promoted the AllocStack, we may see
302
310
// DebugValueAddr uses.
303
- if (isa<DebugValueAddrInst>(II))
311
+ if (isa<DebugValueAddrInst>(II) || isDeadAddrProjection (II) ||
312
+ isa<EndAccessInst>(II))
304
313
continue ;
305
314
306
- if (isDeadAddrProjection (II))
307
- continue ;
315
+ // Begin access is OK if it is write only.
316
+ if (auto *beginAccess = dyn_cast<BeginAccessInst>(II)) {
317
+ if (isWriteOnlyAllocation (beginAccess))
318
+ continue ;
319
+ return false ;
320
+ }
308
321
309
322
// Can't do anything else with it.
310
323
LLVM_DEBUG (llvm::dbgs () << " *** AllocStack has non-write use: " << *II);
@@ -343,7 +356,7 @@ static bool isLoadFromStack(SILInstruction *I, AllocStackInst *ASI) {
343
356
ValueBase *op = I->getOperand (0 );
344
357
while (op != ASI) {
345
358
if (!isa<UncheckedAddrCastInst>(op) && !isa<StructElementAddrInst>(op) &&
346
- !isa<TupleElementAddrInst>(op))
359
+ !isa<TupleElementAddrInst>(op) && !isa<BeginAccessInst>(op) )
347
360
return false ;
348
361
349
362
op = cast<SingleValueInstruction>(op)->getOperand (0 );
@@ -358,7 +371,7 @@ static void collectLoads(SILInstruction *I, SmallVectorImpl<LoadInst *> &Loads)
358
371
return ;
359
372
}
360
373
if (!isa<UncheckedAddrCastInst>(I) && !isa<StructElementAddrInst>(I) &&
361
- !isa<TupleElementAddrInst>(I))
374
+ !isa<TupleElementAddrInst>(I) && !isa<BeginAccessInst>(I) )
362
375
return ;
363
376
364
377
// Recursively search for other loads in the instruction's uses.
@@ -375,9 +388,13 @@ static void replaceLoad(LoadInst *LI, SILValue val, AllocStackInst *ASI) {
375
388
376
389
while (op != ASI) {
377
390
assert (isa<UncheckedAddrCastInst>(op) || isa<StructElementAddrInst>(op) ||
378
- isa<TupleElementAddrInst>(op));
391
+ isa<TupleElementAddrInst>(op) || isa<BeginAccessInst>(op) );
379
392
auto *Inst = cast<SingleValueInstruction>(op);
380
- projections.push_back (Projection (Inst));
393
+
394
+ // We don't want to project these instructions but we do want to follow
395
+ // their operand.
396
+ if (!isa<BeginAccessInst>(op))
397
+ projections.push_back (Projection (Inst));
381
398
op = Inst->getOperand (0 );
382
399
}
383
400
@@ -421,11 +438,17 @@ static void replaceLoad(LoadInst *LI, SILValue val, AllocStackInst *ASI) {
421
438
422
439
while (op != ASI && op->use_empty ()) {
423
440
assert (isa<UncheckedAddrCastInst>(op) || isa<StructElementAddrInst>(op) ||
424
- isa<TupleElementAddrInst>(op));
441
+ isa<TupleElementAddrInst>(op) || isa<BeginAccessInst>(op) );
425
442
auto *Inst = cast<SingleValueInstruction>(op);
426
- SILValue next = Inst->getOperand (0 );
427
- Inst->eraseFromParent ();
428
- op = next;
443
+ op = Inst->getOperand (0 );
444
+ if (Inst->use_empty ())
445
+ Inst->eraseFromParent ();
446
+ if (auto singleUse = Inst->getSingleUse ()) {
447
+ if (isa<EndAccessInst>(singleUse->getUser ())) {
448
+ singleUse->getUser ()->eraseFromParent ();
449
+ Inst->eraseFromParent ();
450
+ }
451
+ }
429
452
}
430
453
}
431
454
@@ -596,10 +619,10 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *ASI) {
596
619
SILValue RunningVal = SILValue ();
597
620
598
621
// For all instructions in the block.
599
- for ( auto BBI = BB-> begin (), E = BB-> end (); BBI != E;) {
600
- SILInstruction *Inst = &*BBI;
601
- ++BBI ;
602
-
622
+ SmallVector<SILInstruction *, 64 > allInstInBlock;
623
+ for ( auto &i : *BB)
624
+ allInstInBlock. push_back (&i) ;
625
+ for ( auto *Inst : allInstInBlock) {
603
626
// Remove instructions that we are loading from. Replace the loaded value
604
627
// with our running value.
605
628
if (isLoadFromStack (Inst, ASI)) {
@@ -665,7 +688,7 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *ASI) {
665
688
SILNode *Node = Inst;
666
689
while (isa<StructElementAddrInst>(Node) ||
667
690
isa<TupleElementAddrInst>(Node) ||
668
- isa<UncheckedAddrCastInst>(Node)) {
691
+ isa<UncheckedAddrCastInst>(Node) || isa<BeginAccessInst>(Node) ) {
669
692
auto *I = cast<SingleValueInstruction>(Node);
670
693
if (!I->use_empty ()) break ;
671
694
Node = I->getOperand (0 );
0 commit comments