@@ -74,21 +74,20 @@ class LiveValues {
7474public:
7575 struct Owned {
7676 SILValue stored = SILValue();
77- SILValue borrow = SILValue();
78- SILValue copy = SILValue();
77+ SILValue move = SILValue();
7978
8079 // / Create an instance of the minimum values required to replace a usage of
8180 // / an AllocStackInst. It consists of only one value.
8281 // /
83- // / Whether the one value occupies the stored or the copy field depends on
82+ // / Whether the one value occupies the stored or the move field depends on
8483 // / whether the alloc_stack is lexical. If it is lexical, then usages of
85- // / the asi will be replaced with usages of the copy field; otherwise, those
86- // / usages will be replaced with usages of the stored field. The
84+ // / the asi will be replaced with usages of the move field; otherwise,
85+ // / those usages will be replaced with usages of the stored field. The
8786 // / implementation constructs an instance to match those requirements.
8887 static Owned toReplace (AllocStackInst *asi, SILValue replacement) {
8988 if (lexicalLifetimeEnsured (asi))
90- return {SILValue (), SILValue (), replacement};
91- return {replacement, SILValue (), SILValue () };
89+ return {SILValue (), replacement};
90+ return {replacement, SILValue ()};
9291 }
9392
9493 // / The value with which usages of the provided AllocStackInst should be
@@ -97,13 +96,9 @@ class LiveValues {
9796 if (!lexicalLifetimeEnsured (asi)) {
9897 return stored;
9998 }
100- // We should have created a borrow of the @owned stored value and a copy
101- // of the borrowed value.
102- assert (copy && borrow);
103- if (isa<LoadBorrowInst>(toReplace)) {
104- return borrow ? borrow : stored;
105- }
106- return copy ? copy : borrow ? borrow : stored;
99+ // We should have created a move of the @owned stored value.
100+ assert (move);
101+ return move;
107102 }
108103
109104 bool canEndLexicalLifetime () {
@@ -112,7 +107,7 @@ class LiveValues {
112107 // to end a lexical lifetime. In that case, the lifetime end will be
113108 // added later, when we have enough information, namely the live in
114109 // values, to end it.
115- return borrow ;
110+ return move ;
116111 }
117112 };
118113 struct Guaranteed {
@@ -195,8 +190,8 @@ class LiveValues {
195190 return LiveValues::forGuaranteed ({stored, borrow});
196191 }
197192
198- static LiveValues forOwned (SILValue stored, SILValue borrow, SILValue copy ) {
199- return LiveValues::forOwned ({stored, borrow, copy });
193+ static LiveValues forOwned (SILValue stored, SILValue move ) {
194+ return LiveValues::forOwned ({stored, move });
200195 }
201196
202197 static LiveValues toReplace (AllocStackInst *asi, SILValue replacement) {
@@ -427,8 +422,8 @@ replaceLoad(SILInstruction *inst, SILValue newValue, AllocStackInst *asi,
427422 op = inst->getOperand (0 );
428423
429424 if (auto *lbi = dyn_cast<LoadBorrowInst>(inst)) {
430- if (lexicalLifetimeEnsured (asi)) {
431- assert ( newValue->getOwnershipKind () == OwnershipKind::Guaranteed);
425+ if (lexicalLifetimeEnsured (asi) &&
426+ newValue->getOwnershipKind () == OwnershipKind::Guaranteed) {
432427 SmallVector<SILInstruction *, 4 > endBorrows;
433428 for (auto *ebi : lbi->getUsersOfType <EndBorrowInst>()) {
434429 endBorrows.push_back (ebi);
@@ -517,23 +512,22 @@ static bool canEndLexicalLifetime(LiveValues values) {
517512// /
518513// / The beginning of the scope looks like
519514// /
520- // / %lifetime = begin_borrow [lexical] %original
521- // / %copy = copy_value %lifetime
515+ // / %lifetime = move_value [lexical] %original
516+ // /
517+ // / Because the value was consumed by the original store instruction, it can
518+ // / be rewritten to be consumed by a lexical move_value.
522519static StorageStateTracking<LiveValues>
523520beginOwnedLexicalLifetimeAfterStore (AllocStackInst *asi, StoreInst *inst) {
524521 assert (lexicalLifetimeEnsured (asi));
525522 SILValue stored = inst->getOperand (CopyLikeInstruction::Src);
526523 SILLocation loc = RegularLocation::getAutoGeneratedLocation (inst->getLoc ());
527524
528- BeginBorrowInst *bbi = nullptr ;
529- CopyValueInst *cvi = nullptr ;
525+ MoveValueInst *mvi = nullptr ;
530526 SILBuilderWithScope::insertAfter (inst, [&](SILBuilder &builder) {
531- bbi = builder.createBeginBorrow (loc, stored, /* isLexical*/ true );
532- cvi = builder.createCopyValue (loc, bbi);
527+ mvi = builder.createMoveValue (loc, stored, /* isLexical*/ true );
533528 });
534- StorageStateTracking<LiveValues> vals = {
535- LiveValues::forOwned (stored, bbi, cvi),
536- /* isStorageValid=*/ true };
529+ StorageStateTracking<LiveValues> vals = {LiveValues::forOwned (stored, mvi),
530+ /* isStorageValid=*/ true };
537531 return vals;
538532}
539533
@@ -560,26 +554,22 @@ beginGuaranteedLexicalLifetimeAfterStore(AllocStackInst *asi,
560554// /
561555// / The end of the scope looks like
562556// /
563- // / end_borrow %lifetime
564- // / destroy_value %original
557+ // / destroy_value %lifetime
558+ // /
559+ // / This instruction corresponds to the following instructions that begin a
560+ // / lexical borrow scope:
565561// /
566- // / These two instructions correspond to the following instructions that begin
567- // / a lexical borrow scope:
562+ // / %lifetime = move_value [lexical] %original
568563// /
569- // / %lifetime = begin_borrow %original
570- // / %copy = copy_value %lifetime
564+ // / However, no intervention is required to explicitly end the lifetime because
565+ // / it will already have been ended naturally by destroy_addrs (or equivalent)
566+ // / of the alloc_stack.
571567static void endOwnedLexicalLifetimeBeforeInst (AllocStackInst *asi,
572568 SILInstruction *beforeInstruction,
573569 SILBuilderContext &ctx,
574570 LiveValues::Owned values) {
575571 assert (lexicalLifetimeEnsured (asi));
576572 assert (beforeInstruction);
577-
578- auto builder = SILBuilderWithScope (beforeInstruction, ctx);
579- SILLocation loc =
580- RegularLocation::getAutoGeneratedLocation (beforeInstruction->getLoc ());
581- builder.createEndBorrow (loc, values.borrow );
582- builder.createDestroyValue (loc, values.stored );
583573}
584574
585575// / End the lexical borrow scope for an @guaranteed stored value described by
@@ -647,12 +637,26 @@ class StackAllocationPromoter {
647637 // /
648638 // / The live-out values for every block can be derived from these.
649639 // /
650- // / For non-lexical alloc_stacks, that is just a StoreInst or a
651- // / StoreBorrowInst.
652- // / For lexical alloc_stacks, that is the StoreInst, a BeginBorrowInst of the
653- // / value stored into the StoreInst and a CopyValueInst of the result of the
654- // / BeginBorrowInst or a StoreBorrowInst, and a BeginBorrowInst of the stored
655- // / value if it did not have a guaranteed lexical scope.
640+ // / This is either a StoreInst or a StoreBorrowInst.
641+ // /
642+ // / If the alloc_stack is non-lexical, the only live-out value is the source
643+ // / operand of the instruction.
644+ // /
645+ // / If the alloc_stack is lexical but the stored value is already lexical, no
646+ // / additional lexical lifetime is necessary and as an optimization can be
647+ // / omitted. In that case, the only live-out value is the source operand of
648+ // / the instruction. This optimization has been implemented for guaranteed
649+ // / alloc_stacks.
650+ // /
651+ // / If the alloc_stack is lexical and the stored value is not already lexical,
652+ // / a lexical lifetime must be introduced that matches the duration in which
653+ // / the value remains in the alloc_stack:
654+ // / - For owned alloc_stacks, a move_value [lexical] of the stored value is
655+ // / created. That move_value is the instruction after the store, and it is
656+ // / the other running value.
657+ // / - For guaranteed alloc_stacks, a begin_borrow [lexical] of the
658+ // / store_borrow'd value is created. That begin_borrow is the instruction
659+ // / after the store_borrow, and it is the other running value.
656660 BlockToInstMap initializationPoints;
657661
658662 // / The first instruction in each block that deinitializes the storage that is
@@ -778,8 +782,9 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
778782 // it has been destroy_addr'd, etc
779783 // - Some + isStorageValid: a value was encountered and is currently stored
780784 Optional<StorageStateTracking<LiveValues>> runningVals;
781- // Keep track of the last StoreInst that we found and the BeginBorrowInst and
782- // CopyValueInst that we created in response if the alloc_stack was lexical.
785+ // The most recent StoreInst or StoreBorrowInst that encountered while
786+ // iterating over the block. The final value will be returned to the caller
787+ // which will use it to determine the live-out value of the block.
783788 SILInstruction *lastStoreInst = nullptr ;
784789
785790 // For all instructions in the block.
@@ -1002,15 +1007,8 @@ void StackAllocationPromoter::addBlockArguments(BlockSetVector &phiBlocks) {
10021007 LLVM_DEBUG (llvm::dbgs () << " *** Adding new block arguments.\n " );
10031008
10041009 for (auto *block : phiBlocks) {
1005- // The stored value.
1010+ // The stored value or its lexical move .
10061011 block->createPhiArgument (asi->getElementType (), OwnershipKind::Owned);
1007- if (lexicalLifetimeEnsured (asi)) {
1008- // The borrow scope.
1009- block->createPhiArgument (asi->getElementType (),
1010- OwnershipKind::Guaranteed);
1011- // The copy of the borrowed value.
1012- block->createPhiArgument (asi->getElementType (), OwnershipKind::Owned);
1013- }
10141012 }
10151013}
10161014
@@ -1033,7 +1031,7 @@ StackAllocationPromoter::getLiveOutValues(BlockSetVector &phiBlocks,
10331031 LLVM_DEBUG (llvm::dbgs () << " *** Found Store def " << stored);
10341032
10351033 if (!lexicalLifetimeEnsured (asi)) {
1036- auto values = LiveValues::forOwned (stored, {}, {} );
1034+ auto values = LiveValues::forOwned (stored, {});
10371035 return values;
10381036 }
10391037 if (isa<StoreBorrowInst>(inst)) {
@@ -1045,30 +1043,19 @@ StackAllocationPromoter::getLiveOutValues(BlockSetVector &phiBlocks,
10451043 auto values = LiveValues::forGuaranteed (stored, borrow);
10461044 return values;
10471045 }
1048- auto borrow = cast<BeginBorrowInst>(inst->getNextInstruction ());
1049- auto copy = cast<CopyValueInst>(borrow->getNextInstruction ());
1050- auto values = LiveValues::forOwned (stored, borrow, copy);
1046+ auto move = cast<MoveValueInst>(inst->getNextInstruction ());
1047+ auto values = LiveValues::forOwned (stored, move);
10511048 return values;
10521049 }
10531050
10541051 // If there is a Phi definition in this block:
10551052 if (phiBlocks.contains (domBlock)) {
10561053 // Return the dummy instruction that represents the new value that we will
10571054 // add to the basic block.
1058- SILValue original;
1059- SILValue borrow;
1060- SILValue copy;
1061- if (lexicalLifetimeEnsured (asi)) {
1062- original = domBlock->getArgument (domBlock->getNumArguments () - 3 );
1063- borrow = domBlock->getArgument (domBlock->getNumArguments () - 2 );
1064- copy = domBlock->getArgument (domBlock->getNumArguments () - 1 );
1065- } else {
1066- original = domBlock->getArgument (domBlock->getNumArguments () - 1 );
1067- borrow = SILValue ();
1068- copy = SILValue ();
1069- }
1070- LLVM_DEBUG (llvm::dbgs () << " *** Found a dummy Phi def " << *original);
1071- auto values = LiveValues::forOwned (original, borrow, copy);
1055+ SILValue argument =
1056+ domBlock->getArgument (domBlock->getNumArguments () - 1 );
1057+ LLVM_DEBUG (llvm::dbgs () << " *** Found a dummy Phi def " << *argument);
1058+ auto values = LiveValues::toReplace (asi, argument);
10721059 return values;
10731060 }
10741061
@@ -1086,7 +1073,7 @@ StackAllocationPromoter::getEffectiveLiveOutValues(BlockSetVector &phiBlocks,
10861073 return *values;
10871074 }
10881075 auto *undef = SILUndef::get (asi->getElementType (), *asi->getFunction ());
1089- return LiveValues::forOwned (undef, undef, undef );
1076+ return LiveValues::forOwned (undef, undef);
10901077}
10911078
10921079Optional<LiveValues>
@@ -1098,19 +1085,8 @@ StackAllocationPromoter::getLiveInValues(BlockSetVector &phiBlocks,
10981085 // chain.
10991086 if (phiBlocks.contains (block)) {
11001087 LLVM_DEBUG (llvm::dbgs () << " *** Found a local Phi definition.\n " );
1101- SILValue original;
1102- SILValue borrow;
1103- SILValue copy;
1104- if (lexicalLifetimeEnsured (asi)) {
1105- original = block->getArgument (block->getNumArguments () - 3 );
1106- borrow = block->getArgument (block->getNumArguments () - 2 );
1107- copy = block->getArgument (block->getNumArguments () - 1 );
1108- } else {
1109- original = block->getArgument (block->getNumArguments () - 1 );
1110- borrow = SILValue ();
1111- copy = SILValue ();
1112- }
1113- auto values = LiveValues::forOwned (original, borrow, copy);
1088+ SILValue argument = block->getArgument (block->getNumArguments () - 1 );
1089+ auto values = LiveValues::toReplace (asi, argument);
11141090 return values;
11151091 }
11161092
@@ -1134,7 +1110,7 @@ StackAllocationPromoter::getEffectiveLiveInValues(BlockSetVector &phiBlocks,
11341110 }
11351111 auto *undef = SILUndef::get (asi->getElementType (), *asi->getFunction ());
11361112 // TODO: Add another kind of LiveValues for undef.
1137- return LiveValues::forOwned (undef, undef, undef );
1113+ return LiveValues::forOwned (undef, undef);
11381114}
11391115
11401116void StackAllocationPromoter::fixPhiPredBlock (BlockSetVector &phiBlocks,
@@ -1150,11 +1126,7 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSetVector &phiBlocks,
11501126 << ownedValues.stored );
11511127
11521128 SmallVector<SILValue> vals;
1153- vals.push_back (ownedValues.stored );
1154- if (lexicalLifetimeEnsured (asi)) {
1155- vals.push_back (ownedValues.borrow );
1156- vals.push_back (ownedValues.copy );
1157- }
1129+ vals.push_back (ownedValues.replacement (asi, nullptr ));
11581130
11591131 addArgumentsToBranch (vals, destBlock, ti);
11601132 deleter.forceDelete (ti);
@@ -1318,10 +1290,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks,
13181290 block->getArgument (block->getNumArguments () - 1 ));
13191291 if (!livePhis.contains (proactivePhi)) {
13201292 eraseLastPhiFromBlock (block);
1321- if (lexicalLifetimeEnsured (asi)) {
1322- eraseLastPhiFromBlock (block);
1323- eraseLastPhiFromBlock (block);
1324- }
13251293 } else {
13261294 phiBlocksOut.insert (block);
13271295 }
0 commit comments