@@ -74,21 +74,20 @@ class LiveValues {
74
74
public:
75
75
struct Owned {
76
76
SILValue stored = SILValue();
77
- SILValue borrow = SILValue();
78
- SILValue copy = SILValue();
77
+ SILValue move = SILValue();
79
78
80
79
// / Create an instance of the minimum values required to replace a usage of
81
80
// / an AllocStackInst. It consists of only one value.
82
81
// /
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
84
83
// / 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
87
86
// / implementation constructs an instance to match those requirements.
88
87
static Owned toReplace (AllocStackInst *asi, SILValue replacement) {
89
88
if (lexicalLifetimeEnsured (asi))
90
- return {SILValue (), SILValue (), replacement};
91
- return {replacement, SILValue (), SILValue () };
89
+ return {SILValue (), replacement};
90
+ return {replacement, SILValue ()};
92
91
}
93
92
94
93
// / The value with which usages of the provided AllocStackInst should be
@@ -97,13 +96,9 @@ class LiveValues {
97
96
if (!lexicalLifetimeEnsured (asi)) {
98
97
return stored;
99
98
}
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;
107
102
}
108
103
109
104
bool canEndLexicalLifetime () {
@@ -112,7 +107,7 @@ class LiveValues {
112
107
// to end a lexical lifetime. In that case, the lifetime end will be
113
108
// added later, when we have enough information, namely the live in
114
109
// values, to end it.
115
- return borrow ;
110
+ return move ;
116
111
}
117
112
};
118
113
struct Guaranteed {
@@ -195,8 +190,8 @@ class LiveValues {
195
190
return LiveValues::forGuaranteed ({stored, borrow});
196
191
}
197
192
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 });
200
195
}
201
196
202
197
static LiveValues toReplace (AllocStackInst *asi, SILValue replacement) {
@@ -427,8 +422,8 @@ replaceLoad(SILInstruction *inst, SILValue newValue, AllocStackInst *asi,
427
422
op = inst->getOperand (0 );
428
423
429
424
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) {
432
427
SmallVector<SILInstruction *, 4 > endBorrows;
433
428
for (auto *ebi : lbi->getUsersOfType <EndBorrowInst>()) {
434
429
endBorrows.push_back (ebi);
@@ -517,23 +512,22 @@ static bool canEndLexicalLifetime(LiveValues values) {
517
512
// /
518
513
// / The beginning of the scope looks like
519
514
// /
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.
522
519
static StorageStateTracking<LiveValues>
523
520
beginOwnedLexicalLifetimeAfterStore (AllocStackInst *asi, StoreInst *inst) {
524
521
assert (lexicalLifetimeEnsured (asi));
525
522
SILValue stored = inst->getOperand (CopyLikeInstruction::Src);
526
523
SILLocation loc = RegularLocation::getAutoGeneratedLocation (inst->getLoc ());
527
524
528
- BeginBorrowInst *bbi = nullptr ;
529
- CopyValueInst *cvi = nullptr ;
525
+ MoveValueInst *mvi = nullptr ;
530
526
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 );
533
528
});
534
- StorageStateTracking<LiveValues> vals = {
535
- LiveValues::forOwned (stored, bbi, cvi),
536
- /* isStorageValid=*/ true };
529
+ StorageStateTracking<LiveValues> vals = {LiveValues::forOwned (stored, mvi),
530
+ /* isStorageValid=*/ true };
537
531
return vals;
538
532
}
539
533
@@ -560,26 +554,22 @@ beginGuaranteedLexicalLifetimeAfterStore(AllocStackInst *asi,
560
554
// /
561
555
// / The end of the scope looks like
562
556
// /
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:
565
561
// /
566
- // / These two instructions correspond to the following instructions that begin
567
- // / a lexical borrow scope:
562
+ // / %lifetime = move_value [lexical] %original
568
563
// /
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.
571
567
static void endOwnedLexicalLifetimeBeforeInst (AllocStackInst *asi,
572
568
SILInstruction *beforeInstruction,
573
569
SILBuilderContext &ctx,
574
570
LiveValues::Owned values) {
575
571
assert (lexicalLifetimeEnsured (asi));
576
572
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 );
583
573
}
584
574
585
575
// / End the lexical borrow scope for an @guaranteed stored value described by
@@ -647,12 +637,26 @@ class StackAllocationPromoter {
647
637
// /
648
638
// / The live-out values for every block can be derived from these.
649
639
// /
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.
656
660
BlockToInstMap initializationPoints;
657
661
658
662
// / The first instruction in each block that deinitializes the storage that is
@@ -778,8 +782,9 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
778
782
// it has been destroy_addr'd, etc
779
783
// - Some + isStorageValid: a value was encountered and is currently stored
780
784
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.
783
788
SILInstruction *lastStoreInst = nullptr ;
784
789
785
790
// For all instructions in the block.
@@ -1002,15 +1007,8 @@ void StackAllocationPromoter::addBlockArguments(BlockSetVector &phiBlocks) {
1002
1007
LLVM_DEBUG (llvm::dbgs () << " *** Adding new block arguments.\n " );
1003
1008
1004
1009
for (auto *block : phiBlocks) {
1005
- // The stored value.
1010
+ // The stored value or its lexical move .
1006
1011
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
- }
1014
1012
}
1015
1013
}
1016
1014
@@ -1033,7 +1031,7 @@ StackAllocationPromoter::getLiveOutValues(BlockSetVector &phiBlocks,
1033
1031
LLVM_DEBUG (llvm::dbgs () << " *** Found Store def " << stored);
1034
1032
1035
1033
if (!lexicalLifetimeEnsured (asi)) {
1036
- auto values = LiveValues::forOwned (stored, {}, {} );
1034
+ auto values = LiveValues::forOwned (stored, {});
1037
1035
return values;
1038
1036
}
1039
1037
if (isa<StoreBorrowInst>(inst)) {
@@ -1045,30 +1043,19 @@ StackAllocationPromoter::getLiveOutValues(BlockSetVector &phiBlocks,
1045
1043
auto values = LiveValues::forGuaranteed (stored, borrow);
1046
1044
return values;
1047
1045
}
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);
1051
1048
return values;
1052
1049
}
1053
1050
1054
1051
// If there is a Phi definition in this block:
1055
1052
if (phiBlocks.contains (domBlock)) {
1056
1053
// Return the dummy instruction that represents the new value that we will
1057
1054
// 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);
1072
1059
return values;
1073
1060
}
1074
1061
@@ -1086,7 +1073,7 @@ StackAllocationPromoter::getEffectiveLiveOutValues(BlockSetVector &phiBlocks,
1086
1073
return *values;
1087
1074
}
1088
1075
auto *undef = SILUndef::get (asi->getElementType (), *asi->getFunction ());
1089
- return LiveValues::forOwned (undef, undef, undef );
1076
+ return LiveValues::forOwned (undef, undef);
1090
1077
}
1091
1078
1092
1079
Optional<LiveValues>
@@ -1098,19 +1085,8 @@ StackAllocationPromoter::getLiveInValues(BlockSetVector &phiBlocks,
1098
1085
// chain.
1099
1086
if (phiBlocks.contains (block)) {
1100
1087
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);
1114
1090
return values;
1115
1091
}
1116
1092
@@ -1134,7 +1110,7 @@ StackAllocationPromoter::getEffectiveLiveInValues(BlockSetVector &phiBlocks,
1134
1110
}
1135
1111
auto *undef = SILUndef::get (asi->getElementType (), *asi->getFunction ());
1136
1112
// TODO: Add another kind of LiveValues for undef.
1137
- return LiveValues::forOwned (undef, undef, undef );
1113
+ return LiveValues::forOwned (undef, undef);
1138
1114
}
1139
1115
1140
1116
void StackAllocationPromoter::fixPhiPredBlock (BlockSetVector &phiBlocks,
@@ -1150,11 +1126,7 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSetVector &phiBlocks,
1150
1126
<< ownedValues.stored );
1151
1127
1152
1128
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 ));
1158
1130
1159
1131
addArgumentsToBranch (vals, destBlock, ti);
1160
1132
deleter.forceDelete (ti);
@@ -1318,10 +1290,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks,
1318
1290
block->getArgument (block->getNumArguments () - 1 ));
1319
1291
if (!livePhis.contains (proactivePhi)) {
1320
1292
eraseLastPhiFromBlock (block);
1321
- if (lexicalLifetimeEnsured (asi)) {
1322
- eraseLastPhiFromBlock (block);
1323
- eraseLastPhiFromBlock (block);
1324
- }
1325
1293
} else {
1326
1294
phiBlocksOut.insert (block);
1327
1295
}
0 commit comments