Skip to content

Commit 3019be9

Browse files
committed
[Mem2Reg] Owned lexical lifetimes get moves.
1 parent 66b8b2f commit 3019be9

File tree

5 files changed

+177
-477
lines changed

5 files changed

+177
-477
lines changed

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 66 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,20 @@ class LiveValues {
7474
public:
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.
522519
static StorageStateTracking<LiveValues>
523520
beginOwnedLexicalLifetimeAfterStore(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.
571567
static 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

10921079
Optional<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

11401116
void 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

Comments
 (0)