@@ -425,7 +425,9 @@ class AvailableValueAggregator {
425425 // / If as a result of us copying values, we may have unconsumed destroys, find
426426 // / the appropriate location and place the values there. Only used when
427427 // / ownership is enabled.
428- LoadInst *addMissingDestroysForCopiedValues (LoadInst *li, SILValue newVal);
428+ SingleValueInstruction *
429+ addMissingDestroysForCopiedValues (SingleValueInstruction *li,
430+ SILValue newVal);
429431
430432 void print (llvm::raw_ostream &os) const ;
431433 void dump () const LLVM_ATTRIBUTE_USED;
@@ -746,14 +748,14 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy,
746748 return eltVal;
747749}
748750
749- LoadInst *
750- AvailableValueAggregator::addMissingDestroysForCopiedValues (LoadInst *li,
751- SILValue newVal) {
751+ SingleValueInstruction *
752+ AvailableValueAggregator::addMissingDestroysForCopiedValues (
753+ SingleValueInstruction *svi, SILValue newVal) {
752754 // If ownership is not enabled... bail. We do not need to do this since we do
753755 // not need to insert an extra copy unless we have ownership since without
754756 // ownership stores do not consume.
755757 if (!B.hasOwnership ())
756- return li ;
758+ return svi ;
757759
758760 SmallPtrSet<SILBasicBlock *, 8 > visitedBlocks;
759761 SmallVector<SILBasicBlock *, 8 > leakingBlocks;
@@ -776,8 +778,9 @@ AvailableValueAggregator::addMissingDestroysForCopiedValues(LoadInst *li,
776778 // Then perform the linear lifetime check. If we succeed, continue. We have
777779 // no further work to do.
778780 auto errorKind = ownership::ErrorBehaviorKind::ReturnFalse;
779- auto error = valueHasLinearLifetime (
780- cvi, {li}, {}, visitedBlocks, deadEndBlocks, errorKind, &leakingBlocks);
781+ auto error =
782+ valueHasLinearLifetime (cvi, {svi}, {}, visitedBlocks, deadEndBlocks,
783+ errorKind, &leakingBlocks);
781784 if (!error.getFoundError ())
782785 continue ;
783786
@@ -795,17 +798,40 @@ AvailableValueAggregator::addMissingDestroysForCopiedValues(LoadInst *li,
795798 }
796799 }
797800
798- // If we didn't find a loop, we are done, just return li to get RAUWed.
799- if (!foundLoop)
800- return li;
801+ // If we didn't find a loop, we are done, just return svi to get RAUWed.
802+ if (!foundLoop) {
803+ // If we had a load_borrow, we have created an extra copy that we are going
804+ // to borrow at the load point. This means we need to handle the destroying
805+ // of the value along paths reachable from the load_borrow. Luckily that
806+ // will exactly be after the end_borrows of the load_borrow.
807+ if (isa<LoadBorrowInst>(svi)) {
808+ for (auto *use : svi->getUses ()) {
809+ if (auto *ebi = dyn_cast<EndBorrowInst>(use->getUser ())) {
810+ auto next = std::next (ebi->getIterator ());
811+ SILBuilderWithScope (next).emitDestroyValueOperation (ebi->getLoc (),
812+ newVal);
813+ }
814+ }
815+ }
816+ return svi;
817+ }
801818
802819 // If we found a loop, then we know that our leaking blocks are the exiting
803- // blocks of the loop. Thus we need to change the load inst to a copy_value
804- // instead of deleting it.
805- newVal = SILBuilderWithScope (li).emitCopyValueOperation (loc, newVal);
806- li->replaceAllUsesWith (newVal);
807- SILValue addr = li->getOperand ();
808- li->eraseFromParent ();
820+ // blocks of the loop and the value has been lifetime extended over the loop.
821+ if (isa<LoadInst>(svi)) {
822+ // If we have a load, we need to put in a copy so that the destroys within
823+ // the loop are properly balanced.
824+ newVal = SILBuilderWithScope (svi).emitCopyValueOperation (loc, newVal);
825+ } else {
826+ // If we have a load_borrow, we create a begin_borrow for the end_borrows in
827+ // the loop.
828+ assert (isa<LoadBorrowInst>(svi));
829+ newVal = SILBuilderWithScope (svi).createBeginBorrow (svi->getLoc (), newVal);
830+ }
831+
832+ svi->replaceAllUsesWith (newVal);
833+ SILValue addr = svi->getOperand (0 );
834+ svi->eraseFromParent ();
809835 if (auto *addrI = addr->getDefiningInstruction ())
810836 recursivelyDeleteTriviallyDeadInstructions (addrI);
811837 return nullptr ;
@@ -1308,19 +1334,23 @@ class AllocOptimize {
13081334// / If we are able to optimize \p Inst, return the source address that
13091335// / instruction is loading from. If we can not optimize \p Inst, then just
13101336// / return an empty SILValue.
1311- static SILValue tryFindSrcAddrForLoad (SILInstruction *Inst) {
1337+ static SILValue tryFindSrcAddrForLoad (SILInstruction *i) {
1338+ // We can always promote a load_borrow.
1339+ if (auto *lbi = dyn_cast<LoadBorrowInst>(i))
1340+ return lbi->getOperand ();
1341+
13121342 // We only handle load [copy], load [trivial], load and copy_addr right
13131343 // now. Notably we do not support load [take] when promoting loads.
1314- if (auto *LI = dyn_cast<LoadInst>(Inst ))
1315- if (LI ->getOwnershipQualifier () != LoadOwnershipQualifier::Take)
1316- return LI ->getOperand ();
1344+ if (auto *li = dyn_cast<LoadInst>(i ))
1345+ if (li ->getOwnershipQualifier () != LoadOwnershipQualifier::Take)
1346+ return li ->getOperand ();
13171347
13181348 // If this is a CopyAddr, verify that the element type is loadable. If not,
13191349 // we can't explode to a load.
1320- auto *CAI = dyn_cast<CopyAddrInst>(Inst );
1321- if (!CAI || !CAI ->getSrc ()->getType ().isLoadable (CAI ->getModule ()))
1350+ auto *cai = dyn_cast<CopyAddrInst>(i );
1351+ if (!cai || !cai ->getSrc ()->getType ().isLoadable (cai ->getModule ()))
13221352 return SILValue ();
1323- return CAI ->getSrc ();
1353+ return cai ->getSrc ();
13241354}
13251355
13261356// / At this point, we know that this element satisfies the definitive init
@@ -1385,25 +1415,30 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) {
13851415 // removing the instruction from Uses for us, so we return false.
13861416 return false ;
13871417 }
1388-
1418+
1419+ assert ((isa<LoadBorrowInst>(Inst) || isa<LoadInst>(Inst)) &&
1420+ " Unhandled instruction for this code path!" );
1421+
13891422 // Aggregate together all of the subelements into something that has the same
13901423 // type as the load did, and emit smaller loads for any subelements that were
1391- // not available.
1392- auto *Load = cast<LoadInst>(Inst);
1393- AvailableValueAggregator Agg (Load, AvailableValues, Uses, deadEndBlocks,
1424+ // not available. We are "propagating" a +1 available value from the store
1425+ // points.
1426+ auto *load = dyn_cast<SingleValueInstruction>(Inst);
1427+ AvailableValueAggregator agg (load, AvailableValues, Uses, deadEndBlocks,
13941428 false /* isTake*/ );
1395- SILValue newVal = Agg .aggregateValues (LoadTy, Load ->getOperand (), FirstElt);
1429+ SILValue newVal = agg .aggregateValues (LoadTy, load ->getOperand (0 ), FirstElt);
13961430
1397- LLVM_DEBUG (llvm::dbgs () << " *** Promoting load: " << *Load << " \n " );
1431+ LLVM_DEBUG (llvm::dbgs () << " *** Promoting load: " << *load << " \n " );
13981432 LLVM_DEBUG (llvm::dbgs () << " To value: " << *newVal << " \n " );
13991433
14001434 // If we inserted any copies, we created the copies at our stores. We know
14011435 // that in our load block, we will reform the aggregate as appropriate at the
1402- // load implying that the value /must/ be fully consumed. Thus any leaking
1436+ // load implying that the value /must/ be fully consumed. If we promoted a +0
1437+ // value, we created dominating destroys along those paths. Thus any leaking
14031438 // blocks that we may have can be found by performing a linear lifetime check
14041439 // over all copies that we found using the load as the "consuming uses" (just
14051440 // for the purposes of identifying the consuming block).
1406- auto *oldLoad = Agg .addMissingDestroysForCopiedValues (Load , newVal);
1441+ auto *oldLoad = agg .addMissingDestroysForCopiedValues (load , newVal);
14071442
14081443 ++NumLoadPromoted;
14091444
@@ -1412,8 +1447,14 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) {
14121447 if (!oldLoad)
14131448 return true ;
14141449
1450+ // If our load was a +0 value, borrow the value and the RAUW. We reuse the
1451+ // end_borrows of our load_borrow.
1452+ if (isa<LoadBorrowInst>(oldLoad)) {
1453+ newVal = SILBuilderWithScope (oldLoad).createBeginBorrow (oldLoad->getLoc (),
1454+ newVal);
1455+ }
14151456 oldLoad->replaceAllUsesWith (newVal);
1416- SILValue addr = oldLoad->getOperand ();
1457+ SILValue addr = oldLoad->getOperand (0 );
14171458 oldLoad->eraseFromParent ();
14181459 if (auto *addrI = addr->getDefiningInstruction ())
14191460 recursivelyDeleteTriviallyDeadInstructions (addrI);
0 commit comments