@@ -202,9 +202,14 @@ static void promoteDebugValueAddr(DebugValueInst *dvai, SILValue value,
202
202
203
203
// / Returns true if \p I is a load which loads from \p ASI.
204
204
static bool isLoadFromStack (SILInstruction *i, AllocStackInst *asi) {
205
- if (!isa<LoadInst>(i))
205
+ if (!isa<LoadInst>(i) && !isa<LoadBorrowInst>(i) )
206
206
return false ;
207
207
208
+ if (auto *lbi = dyn_cast<LoadBorrowInst>(i)) {
209
+ if (BorrowedValue (lbi).hasReborrow ())
210
+ return false ;
211
+ }
212
+
208
213
// Skip struct and tuple address projections.
209
214
ValueBase *op = i->getOperand (0 );
210
215
while (op != asi) {
@@ -218,9 +223,9 @@ static bool isLoadFromStack(SILInstruction *i, AllocStackInst *asi) {
218
223
219
224
// / Collects all load instructions which (transitively) use \p I as address.
220
225
static void collectLoads (SILInstruction *i,
221
- SmallVectorImpl<LoadInst *> &foundLoads) {
222
- if (auto *load = dyn_cast<LoadInst >(i)) {
223
- foundLoads.push_back (load );
226
+ SmallVectorImpl<SILInstruction *> &foundLoads) {
227
+ if (isa<LoadInst>(i) || isa<LoadBorrowInst >(i)) {
228
+ foundLoads.push_back (i );
224
229
return ;
225
230
}
226
231
if (!isa<UncheckedAddrCastInst>(i) && !isa<StructElementAddrInst>(i) &&
@@ -234,22 +239,23 @@ static void collectLoads(SILInstruction *i,
234
239
}
235
240
236
241
static void
237
- replaceLoad (LoadInst *li , SILValue newValue, AllocStackInst *asi,
242
+ replaceLoad (SILInstruction *inst , SILValue newValue, AllocStackInst *asi,
238
243
SILBuilderContext &ctx, InstructionDeleter &deleter,
239
244
SmallVectorImpl<SILInstruction *> &instructionsToDelete) {
245
+ assert (isa<LoadInst>(inst) || isa<LoadBorrowInst>(inst));
240
246
ProjectionPath projections (newValue->getType ());
241
- SILValue op = li ->getOperand ();
242
- SILBuilderWithScope builder (li , ctx);
247
+ SILValue op = inst ->getOperand (0 );
248
+ SILBuilderWithScope builder (inst , ctx);
243
249
SILOptScope scope;
244
250
245
251
while (op != asi) {
246
252
assert (isa<UncheckedAddrCastInst>(op) || isa<StructElementAddrInst>(op) ||
247
253
isa<TupleElementAddrInst>(op) &&
248
254
" found instruction that should have been skipped in "
249
255
" isLoadFromStack" );
250
- auto *inst = cast<SingleValueInstruction>(op);
251
- projections.push_back (Projection (inst ));
252
- op = inst ->getOperand (0 );
256
+ auto *projInst = cast<SingleValueInstruction>(op);
257
+ projections.push_back (Projection (projInst ));
258
+ op = projInst ->getOperand (0 );
253
259
}
254
260
255
261
for (const auto &proj : llvm::reverse (projections)) {
@@ -262,33 +268,51 @@ replaceLoad(LoadInst *li, SILValue newValue, AllocStackInst *asi,
262
268
// to guaranteed!
263
269
if (proj.getKind () == ProjectionKind::Struct ||
264
270
proj.getKind () == ProjectionKind::Tuple) {
265
- if (auto opVal = scope.borrowValue (li , newValue)) {
271
+ if (auto opVal = scope.borrowValue (inst , newValue)) {
266
272
assert (*opVal != newValue &&
267
273
" Valid value should be different from input value" );
268
274
newValue = *opVal;
269
275
}
270
276
}
271
277
newValue =
272
- proj.createObjectProjection (builder, li ->getLoc (), newValue).get ();
278
+ proj.createObjectProjection (builder, inst ->getLoc (), newValue).get ();
273
279
}
274
280
275
- op = li ->getOperand ();
281
+ op = inst ->getOperand (0 );
276
282
277
- // Replace users of the loaded value with `val`
278
- // If we have a load [copy], replace the users with copy_value of `val`
279
- if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Copy) {
280
- li->replaceAllUsesWith (builder.createCopyValue (li->getLoc (), newValue));
283
+ if (auto *lbi = dyn_cast<LoadBorrowInst>(inst)) {
284
+ if (shouldAddLexicalLifetime (asi)) {
285
+ assert (isa<BeginBorrowInst>(newValue));
286
+ SmallVector<SILInstruction *, 4 > endBorrows;
287
+ for (auto *ebi : lbi->getUsersOfType <EndBorrowInst>()) {
288
+ endBorrows.push_back (ebi);
289
+ }
290
+ for (auto *ebi : endBorrows) {
291
+ ebi->eraseFromParent ();
292
+ }
293
+ lbi->replaceAllUsesWith (newValue);
294
+ }
295
+ else {
296
+ auto *borrow = SILBuilderWithScope (lbi, ctx).createBeginBorrow (
297
+ lbi->getLoc (), newValue, asi->isLexical ());
298
+ lbi->replaceAllUsesWith (borrow);
299
+ }
281
300
} else {
282
- assert (!asi->getFunction ()->hasOwnership () ||
283
- newValue.getOwnershipKind () != OwnershipKind::Guaranteed);
284
- li->replaceAllUsesWith (newValue);
301
+ auto *li = cast<LoadInst>(inst);
302
+ // Replace users of the loaded value with `newValue`
303
+ // If we have a load [copy], replace the users with copy_value of `newValue`
304
+ if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Copy) {
305
+ li->replaceAllUsesWith (builder.createCopyValue (li->getLoc (), newValue));
306
+ } else {
307
+ li->replaceAllUsesWith (newValue);
308
+ }
285
309
}
286
310
287
311
// Pop the scope so that we emit cleanups.
288
312
std::move (scope).popAtEndOfScope (&*builder.getInsertionPoint ());
289
313
290
314
// Delete the load
291
- prepareForDeletion (li , instructionsToDelete);
315
+ prepareForDeletion (inst , instructionsToDelete);
292
316
293
317
while (op != asi && op->use_empty ()) {
294
318
assert (isa<UncheckedAddrCastInst>(op) || isa<StructElementAddrInst>(op) ||
@@ -577,6 +601,20 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
577
601
578
602
if (isLoadFromStack (inst, asi)) {
579
603
assert (!runningVals || runningVals->isStorageValid );
604
+ if (auto *lbi = dyn_cast<LoadBorrowInst>(inst)) {
605
+ if (runningVals) {
606
+ if (shouldAddLexicalLifetime (asi)) {
607
+ replaceLoad (lbi, runningVals->value .borrow , asi, ctx,
608
+ deleter, instructionsToDelete);
609
+ }
610
+ else {
611
+ replaceLoad (lbi, runningVals->value .replacement (asi), asi, ctx,
612
+ deleter, instructionsToDelete);
613
+ }
614
+ ++NumInstRemoved;
615
+ }
616
+ continue ;
617
+ }
580
618
auto *li = cast<LoadInst>(inst);
581
619
if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Take) {
582
620
if (shouldAddLexicalLifetime (asi)) {
@@ -597,12 +635,13 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
597
635
if (lastStoreInst)
598
636
lastStoreInst->isStorageValid = false ;
599
637
}
638
+
600
639
if (runningVals) {
601
640
// If we are loading from the AllocStackInst and we already know the
602
641
// content of the Alloca then use it.
603
642
LLVM_DEBUG (llvm::dbgs () << " *** Promoting load: " << *li);
604
- replaceLoad (li , runningVals->value .replacement (asi), asi, ctx, deleter ,
605
- instructionsToDelete);
643
+ replaceLoad (inst , runningVals->value .replacement (asi), asi, ctx,
644
+ deleter, instructionsToDelete);
606
645
++NumInstRemoved;
607
646
} else if (li->getOperand () == asi &&
608
647
li->getOwnershipQualifier () != LoadOwnershipQualifier::Copy) {
@@ -789,10 +828,8 @@ StackAllocationPromoter::getLiveOutValues(BlockSetVector &phiBlocks,
789
828
SILValue borrow = SILValue ();
790
829
SILValue copy = SILValue ();
791
830
if (shouldAddLexicalLifetime (asi)) {
792
- auto *bbi = cast<BeginBorrowInst>(&*std::next (si->getIterator ()));
793
- borrow = bbi;
794
- auto *cvi = cast<CopyValueInst>(bbi->getNextInstruction ());
795
- copy = cvi;
831
+ borrow = cast<BeginBorrowInst>(&*std::next (si->getIterator ()));
832
+ copy = cast<CopyValueInst>(borrow->getNextInstruction ());
796
833
}
797
834
LiveValues values = {stored, borrow, copy};
798
835
return values;
@@ -953,7 +990,7 @@ void StackAllocationPromoter::propagateLiveness(
953
990
void StackAllocationPromoter::fixBranchesAndUses (BlockSetVector &phiBlocks,
954
991
BlockSetVector &phiBlocksOut) {
955
992
// First update uses of the value.
956
- SmallVector<LoadInst *, 4 > collectedLoads;
993
+ SmallVector<SILInstruction *, 4 > collectedLoads;
957
994
958
995
for (auto ui = asi->use_begin (), ue = asi->use_end (); ui != ue;) {
959
996
auto *user = ui->getUser ();
@@ -1421,6 +1458,13 @@ static bool isAddressForLoad(SILInstruction *load, SILBasicBlock *&singleBlock,
1421
1458
return true ;
1422
1459
}
1423
1460
1461
+ if (isa<LoadBorrowInst>(load)) {
1462
+ if (involvesUntakableProjection) {
1463
+ return false ;
1464
+ }
1465
+ return true ;
1466
+ }
1467
+
1424
1468
if (!isa<UncheckedAddrCastInst>(load) && !isa<StructElementAddrInst>(load) &&
1425
1469
!isa<TupleElementAddrInst>(load))
1426
1470
return false ;
@@ -1480,8 +1524,8 @@ static bool isDeadAddrProjection(SILInstruction *inst) {
1480
1524
}
1481
1525
1482
1526
// / Returns true if this AllocStacks is captured.
1483
- // / Sets \p inSingleBlock to true if all uses of \p ASI are in a single block.
1484
- static bool isCaptured (AllocStackInst *asi, bool & inSingleBlock) {
1527
+ // / Sets \p inSingleBlock to true if all uses of \p asi are in a single block.
1528
+ static bool isCaptured (AllocStackInst *asi, bool * inSingleBlock) {
1485
1529
SILBasicBlock *singleBlock = asi->getParent ();
1486
1530
1487
1531
// For all users of the AllocStack instruction.
@@ -1518,7 +1562,7 @@ static bool isCaptured(AllocStackInst *asi, bool &inSingleBlock) {
1518
1562
}
1519
1563
1520
1564
// None of the users capture the AllocStack.
1521
- inSingleBlock = (singleBlock != nullptr );
1565
+ * inSingleBlock = (singleBlock != nullptr );
1522
1566
return false ;
1523
1567
}
1524
1568
@@ -1533,6 +1577,10 @@ bool MemoryToRegisters::isWriteOnlyAllocation(AllocStackInst *asi) {
1533
1577
if (!isa<AllocStackInst>(si->getSrc ()))
1534
1578
continue ;
1535
1579
1580
+ if (auto *sbi = dyn_cast<StoreBorrowInst>(user))
1581
+ if (!isa<AllocStackInst>(sbi->getSrc ()))
1582
+ continue ;
1583
+
1536
1584
// Deallocation is also okay.
1537
1585
if (isa<DeallocStackInst>(user))
1538
1586
continue ;
@@ -1557,7 +1605,6 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
1557
1605
LLVM_DEBUG (llvm::dbgs () << " *** Promoting in-block: " << *asi);
1558
1606
1559
1607
SILBasicBlock *parentBlock = asi->getParent ();
1560
-
1561
1608
// The default value of the AllocStack is NULL because we don't have
1562
1609
// uninitialized variables in Swift.
1563
1610
Optional<StorageStateTracking<LiveValues>> runningVals;
@@ -1580,8 +1627,9 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
1580
1627
/* isStorageValid=*/ true };
1581
1628
}
1582
1629
assert (runningVals && runningVals->isStorageValid );
1583
- if (cast<LoadInst>(inst)->getOwnershipQualifier () ==
1584
- LoadOwnershipQualifier::Take) {
1630
+ auto *loadInst = dyn_cast<LoadInst>(inst);
1631
+ if (loadInst &&
1632
+ loadInst->getOwnershipQualifier () == LoadOwnershipQualifier::Take) {
1585
1633
if (shouldAddLexicalLifetime (asi)) {
1586
1634
// End the lexical lifetime at a load [take]. The storage is no
1587
1635
// longer keeping the value alive.
@@ -1590,8 +1638,8 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
1590
1638
}
1591
1639
runningVals->isStorageValid = false ;
1592
1640
}
1593
- replaceLoad (cast<LoadInst>( inst) , runningVals->value .replacement (asi),
1594
- asi, ctx, deleter, instructionsToDelete);
1641
+ replaceLoad (inst, runningVals->value .replacement (asi), asi, ctx, deleter ,
1642
+ instructionsToDelete);
1595
1643
++NumInstRemoved;
1596
1644
continue ;
1597
1645
}
@@ -1656,7 +1704,7 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
1656
1704
// Remove deallocation.
1657
1705
if (auto *dsi = dyn_cast<DeallocStackInst>(inst)) {
1658
1706
if (dsi->getOperand () == asi) {
1659
- deleter.forceDelete (inst );
1707
+ deleter.forceDelete (dsi );
1660
1708
NumInstRemoved++;
1661
1709
// No need to continue scanning after deallocation.
1662
1710
break ;
@@ -1741,7 +1789,7 @@ bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc) {
1741
1789
1742
1790
// Don't handle captured AllocStacks.
1743
1791
bool inSingleBlock = false ;
1744
- if (isCaptured (alloc, inSingleBlock)) {
1792
+ if (isCaptured (alloc, & inSingleBlock)) {
1745
1793
++NumAllocStackCaptured;
1746
1794
return false ;
1747
1795
}
0 commit comments