Skip to content

Commit d0f10d6

Browse files
committed
Merge remote-tracking branch 'origin/main' into rebranch
2 parents 0d099bf + 5cb144f commit d0f10d6

File tree

8 files changed

+583
-29
lines changed

8 files changed

+583
-29
lines changed

include/swift/SIL/SILValue.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class DeadEndBlocks;
4343
class ValueBaseUseIterator;
4444
class ConsumingUseIterator;
4545
class NonConsumingUseIterator;
46+
class NonTypeDependentUseIterator;
4647
class SILValue;
4748

4849
/// An enumeration which contains values for all the concrete ValueBase
@@ -387,6 +388,9 @@ class ValueBase : public SILNode, public SILAllocated<ValueBase> {
387388
using consuming_use_range = iterator_range<consuming_use_iterator>;
388389
using non_consuming_use_iterator = NonConsumingUseIterator;
389390
using non_consuming_use_range = iterator_range<non_consuming_use_iterator>;
391+
using non_typedependent_use_iterator = NonTypeDependentUseIterator;
392+
using non_typedependent_use_range =
393+
iterator_range<non_typedependent_use_iterator>;
390394

391395
inline use_iterator use_begin() const;
392396
inline use_iterator use_end() const;
@@ -397,6 +401,9 @@ class ValueBase : public SILNode, public SILAllocated<ValueBase> {
397401
inline non_consuming_use_iterator non_consuming_use_begin() const;
398402
inline non_consuming_use_iterator non_consuming_use_end() const;
399403

404+
inline non_typedependent_use_iterator non_typedependent_use_begin() const;
405+
inline non_typedependent_use_iterator non_typedependent_use_end() const;
406+
400407
/// Returns a range of all uses, which is useful for iterating over all uses.
401408
/// To ignore debug-info instructions use swift::getNonDebugUses instead
402409
/// (see comment in DebugUtils.h).
@@ -421,6 +428,10 @@ class ValueBase : public SILNode, public SILAllocated<ValueBase> {
421428
/// Returns a range of all non consuming uses
422429
inline non_consuming_use_range getNonConsumingUses() const;
423430

431+
/// Returns a range of uses that are not classified as a type dependent
432+
/// operand of the user.
433+
inline non_typedependent_use_range getNonTypeDependentUses() const;
434+
424435
template <class T>
425436
inline T *getSingleUserOfType() const;
426437

@@ -1076,6 +1087,7 @@ class Operand {
10761087
friend class ValueBaseUseIterator;
10771088
friend class ConsumingUseIterator;
10781089
friend class NonConsumingUseIterator;
1090+
friend class NonTypeDependentUseIterator;
10791091
template <unsigned N> friend class FixedOperandList;
10801092
friend class TrailingOperandsList;
10811093
};
@@ -1202,6 +1214,41 @@ ValueBase::non_consuming_use_end() const {
12021214
return ValueBase::non_consuming_use_iterator(nullptr);
12031215
}
12041216

1217+
class NonTypeDependentUseIterator : public ValueBaseUseIterator {
1218+
public:
1219+
explicit NonTypeDependentUseIterator(Operand *cur)
1220+
: ValueBaseUseIterator(cur) {}
1221+
NonTypeDependentUseIterator &operator++() {
1222+
assert(Cur && "incrementing past end()!");
1223+
assert(!Cur->isTypeDependent());
1224+
while ((Cur = Cur->NextUse)) {
1225+
if (!Cur->isTypeDependent())
1226+
break;
1227+
}
1228+
return *this;
1229+
}
1230+
1231+
NonTypeDependentUseIterator operator++(int unused) {
1232+
NonTypeDependentUseIterator copy = *this;
1233+
++*this;
1234+
return copy;
1235+
}
1236+
};
1237+
1238+
inline ValueBase::non_typedependent_use_iterator
1239+
ValueBase::non_typedependent_use_begin() const {
1240+
auto cur = FirstUse;
1241+
while (cur && cur->isTypeDependent()) {
1242+
cur = cur->NextUse;
1243+
}
1244+
return ValueBase::non_typedependent_use_iterator(cur);
1245+
}
1246+
1247+
inline ValueBase::non_typedependent_use_iterator
1248+
ValueBase::non_typedependent_use_end() const {
1249+
return ValueBase::non_typedependent_use_iterator(nullptr);
1250+
}
1251+
12051252
inline bool ValueBase::hasOneUse() const {
12061253
auto I = use_begin(), E = use_end();
12071254
if (I == E) return false;
@@ -1247,6 +1294,11 @@ ValueBase::getNonConsumingUses() const {
12471294
return {non_consuming_use_begin(), non_consuming_use_end()};
12481295
}
12491296

1297+
inline ValueBase::non_typedependent_use_range
1298+
ValueBase::getNonTypeDependentUses() const {
1299+
return {non_typedependent_use_begin(), non_typedependent_use_end()};
1300+
}
1301+
12501302
inline bool ValueBase::hasTwoUses() const {
12511303
auto iter = use_begin(), end = use_end();
12521304
for (unsigned i = 0; i < 2; ++i) {

lib/SILOptimizer/SemanticARC/Context.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,20 @@ void Context::verify() const {
3838
bool Context::constructCacheValue(
3939
SILValue initialValue,
4040
SmallVectorImpl<Operand *> &wellBehavedWriteAccumulator) {
41-
SmallVector<Operand *, 8> worklist(initialValue->getUses());
41+
SmallVector<Operand *, 8> worklist(initialValue->getNonTypeDependentUses());
4242

4343
while (!worklist.empty()) {
4444
auto *op = worklist.pop_back_val();
45+
assert(!op->isTypeDependent() &&
46+
"Uses that are type dependent should have been filtered before "
47+
"being inserted into the worklist");
4548
SILInstruction *user = op->getUser();
4649

4750
if (Projection::isAddressProjection(user) ||
4851
isa<ProjectBlockStorageInst>(user)) {
4952
for (SILValue r : user->getResults()) {
50-
llvm::copy(r->getUses(), std::back_inserter(worklist));
53+
llvm::copy(r->getNonTypeDependentUses(),
54+
std::back_inserter(worklist));
5155
}
5256
continue;
5357
}
@@ -59,7 +63,8 @@ bool Context::constructCacheValue(
5963
}
6064

6165
// Otherwise, look through it and continue.
62-
llvm::copy(oeai->getUses(), std::back_inserter(worklist));
66+
llvm::copy(oeai->getNonTypeDependentUses(),
67+
std::back_inserter(worklist));
6368
continue;
6469
}
6570

@@ -93,7 +98,8 @@ bool Context::constructCacheValue(
9398
}
9499

95100
// And then add the users to the worklist and continue.
96-
llvm::copy(bai->getUses(), std::back_inserter(worklist));
101+
llvm::copy(bai->getNonTypeDependentUses(),
102+
std::back_inserter(worklist));
97103
continue;
98104
}
99105

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ namespace {
228228

229229
/// Promotes a single AllocStackInst into registers..
230230
class StackAllocationPromoter {
231-
using BlockSet = BasicBlockSetVector;
231+
using BlockSetVector = BasicBlockSetVector;
232232
using BlockToInstMap = llvm::DenseMap<SILBasicBlock *, SILInstruction *>;
233233

234234
// Use a priority queue keyed on dominator tree level so that inserted nodes
@@ -291,26 +291,40 @@ class StackAllocationPromoter {
291291
void promoteAllocationToPhi();
292292

293293
/// Replace the dummy nodes with new block arguments.
294-
void addBlockArguments(BlockSet &phiBlocks);
294+
void addBlockArguments(BlockSetVector &phiBlocks);
295+
296+
/// Check if \p phi is a proactively added phi by SILMem2Reg
297+
bool isProactivePhi(SILPhiArgument *phi, const BlockSetVector &phiBlocks);
298+
299+
/// Check if \p proactivePhi is live.
300+
bool isNecessaryProactivePhi(SILPhiArgument *proactivePhi,
301+
const BlockSetVector &phiBlocks);
302+
303+
/// Given a \p proactivePhi that is live, backward propagate liveness to
304+
/// other proactivePhis.
305+
void propagateLiveness(SILPhiArgument *proactivePhi,
306+
const BlockSetVector &phiBlocks,
307+
SmallPtrSetImpl<SILPhiArgument *> &livePhis);
295308

296309
/// Fix all of the branch instructions and the uses to use
297310
/// the AllocStack definitions (which include stores and Phis).
298-
void fixBranchesAndUses(BlockSet &blocks);
311+
void fixBranchesAndUses(BlockSetVector &blocks);
299312

300313
/// update the branch instructions with the new Phi argument.
301314
/// The blocks in \p PhiBlocks are blocks that define a value, \p Dest is
302315
/// the branch destination, and \p Pred is the predecessors who's branch we
303316
/// modify.
304-
void fixPhiPredBlock(BlockSet &phiBlocks, SILBasicBlock *dest,
317+
void fixPhiPredBlock(BlockSetVector &phiBlocks, SILBasicBlock *dest,
305318
SILBasicBlock *pred);
306319

307320
/// Get the value for this AllocStack variable that is
308321
/// flowing out of StartBB.
309-
SILValue getLiveOutValue(BlockSet &phiBlocks, SILBasicBlock *startBlock);
322+
SILValue getLiveOutValue(BlockSetVector &phiBlocks,
323+
SILBasicBlock *startBlock);
310324

311325
/// Get the value for this AllocStack variable that is
312326
/// flowing into BB.
313-
SILValue getLiveInValue(BlockSet &phiBlocks, SILBasicBlock *block);
327+
SILValue getLiveInValue(BlockSetVector &phiBlocks, SILBasicBlock *block);
314328

315329
/// Prune AllocStacks usage in the function. Scan the function
316330
/// and remove in-block usage of the AllocStack. Leave only the first
@@ -450,14 +464,14 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
450464
return lastStore;
451465
}
452466

453-
void StackAllocationPromoter::addBlockArguments(BlockSet &phiBlocks) {
467+
void StackAllocationPromoter::addBlockArguments(BlockSetVector &phiBlocks) {
454468
LLVM_DEBUG(llvm::dbgs() << "*** Adding new block arguments.\n");
455469

456470
for (auto *block : phiBlocks)
457471
block->createPhiArgument(asi->getElementType(), OwnershipKind::Owned);
458472
}
459473

460-
SILValue StackAllocationPromoter::getLiveOutValue(BlockSet &phiBlocks,
474+
SILValue StackAllocationPromoter::getLiveOutValue(BlockSetVector &phiBlocks,
461475
SILBasicBlock *startBlock) {
462476
LLVM_DEBUG(llvm::dbgs() << "*** Searching for a value definition.\n");
463477
// Walk the Dom tree in search of a defining value:
@@ -489,7 +503,7 @@ SILValue StackAllocationPromoter::getLiveOutValue(BlockSet &phiBlocks,
489503
return SILUndef::get(asi->getElementType(), *asi->getFunction());
490504
}
491505

492-
SILValue StackAllocationPromoter::getLiveInValue(BlockSet &phiBlocks,
506+
SILValue StackAllocationPromoter::getLiveInValue(BlockSetVector &phiBlocks,
493507
SILBasicBlock *block) {
494508
// First, check if there is a Phi value in the current block. We know that
495509
// our loads happen before stores, so we need to first check for Phi nodes
@@ -512,7 +526,7 @@ SILValue StackAllocationPromoter::getLiveInValue(BlockSet &phiBlocks,
512526
return getLiveOutValue(phiBlocks, iDom->getBlock());
513527
}
514528

515-
void StackAllocationPromoter::fixPhiPredBlock(BlockSet &phiBlocks,
529+
void StackAllocationPromoter::fixPhiPredBlock(BlockSetVector &phiBlocks,
516530
SILBasicBlock *destBlock,
517531
SILBasicBlock *predBlock) {
518532
TermInst *ti = predBlock->getTerminator();
@@ -526,7 +540,53 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSet &phiBlocks,
526540
deleter.forceDelete(ti);
527541
}
528542

529-
void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
543+
bool StackAllocationPromoter::isProactivePhi(SILPhiArgument *phi,
544+
const BlockSetVector &phiBlocks) {
545+
auto *phiBlock = phi->getParentBlock();
546+
return phiBlocks.contains(phiBlock) &&
547+
phi == phiBlock->getArgument(phiBlock->getNumArguments() - 1);
548+
}
549+
550+
bool StackAllocationPromoter::isNecessaryProactivePhi(
551+
SILPhiArgument *proactivePhi, const BlockSetVector &phiBlocks) {
552+
assert(isProactivePhi(proactivePhi, phiBlocks));
553+
for (auto *use : proactivePhi->getUses()) {
554+
auto *branch = dyn_cast<BranchInst>(use->getUser());
555+
// A non-branch use is a necessary use
556+
if (!branch)
557+
return true;
558+
auto *destBB = branch->getDestBB();
559+
auto opNum = use->getOperandNumber();
560+
// A phi has a necessary use if it is used as a branch op for a
561+
// non-proactive phi
562+
if (!phiBlocks.contains(destBB) || (opNum != branch->getNumArgs() - 1))
563+
return true;
564+
}
565+
return false;
566+
}
567+
568+
void StackAllocationPromoter::propagateLiveness(
569+
SILPhiArgument *proactivePhi, const BlockSetVector &phiBlocks,
570+
SmallPtrSetImpl<SILPhiArgument *> &livePhis) {
571+
assert(isProactivePhi(proactivePhi, phiBlocks));
572+
if (livePhis.contains(proactivePhi))
573+
return;
574+
// If liveness has not been propagated, go over the incoming operands and mark
575+
// any operand values that are proactivePhis as live
576+
livePhis.insert(proactivePhi);
577+
SmallVector<SILValue> incomingPhiVals;
578+
proactivePhi->getIncomingPhiValues(incomingPhiVals);
579+
for (auto &inVal : incomingPhiVals) {
580+
auto *inPhi = dyn_cast<SILPhiArgument>(inVal);
581+
if (!inPhi)
582+
continue;
583+
if (!isProactivePhi(inPhi, phiBlocks))
584+
continue;
585+
propagateLiveness(inPhi, phiBlocks, livePhis);
586+
}
587+
}
588+
589+
void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
530590
// First update uses of the value.
531591
SmallVector<LoadInst *, 4> collectedLoads;
532592

@@ -581,7 +641,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
581641

582642
// Now that all of the uses are fixed we can fix the branches that point
583643
// to the blocks with the added arguments.
584-
585644
// For each Block with a new Phi argument:
586645
for (auto *block : phiBlocks) {
587646
// Fix all predecessors.
@@ -595,21 +654,37 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
595654
}
596655
}
597656

598-
// If the owned phi arg we added did not have any uses, create end_lifetime to
599-
// end its lifetime. In asserts mode, make sure we have only undef incoming
600-
// values for such phi args.
601-
for (auto *block : phiBlocks) {
602-
auto *phiArg =
603-
cast<SILPhiArgument>(block->getArgument(block->getNumArguments() - 1));
604-
if (phiArg->use_empty()) {
605-
erasePhiArgument(block, block->getNumArguments() - 1);
657+
// Fix ownership of proactively created non-trivial phis
658+
if (asi->getFunction()->hasOwnership() &&
659+
!asi->getType().isTrivial(*asi->getFunction())) {
660+
SmallPtrSet<SILPhiArgument *, 4> livePhis;
661+
662+
for (auto *block : phiBlocks) {
663+
auto *proactivePhi = cast<SILPhiArgument>(
664+
block->getArgument(block->getNumArguments() - 1));
665+
// First, check if the proactively added phi is necessary by looking at
666+
// it's immediate uses.
667+
if (isNecessaryProactivePhi(proactivePhi, phiBlocks)) {
668+
// Backward propagate liveness to other dependent proactively added phis
669+
propagateLiveness(proactivePhi, phiBlocks, livePhis);
670+
}
671+
}
672+
// Go over all proactively added phis, and delete those that were not marked
673+
// live above.
674+
for (auto *block : phiBlocks) {
675+
auto *proactivePhi = cast<SILPhiArgument>(
676+
block->getArgument(block->getNumArguments() - 1));
677+
if (!livePhis.contains(proactivePhi)) {
678+
proactivePhi->replaceAllUsesWithUndef();
679+
erasePhiArgument(block, block->getNumArguments() - 1);
680+
}
606681
}
607682
}
608683
}
609684

610685
void StackAllocationPromoter::pruneAllocStackUsage() {
611686
LLVM_DEBUG(llvm::dbgs() << "*** Pruning : " << *asi);
612-
BlockSet functionBlocks(asi->getFunction());
687+
BlockSetVector functionBlocks(asi->getFunction());
613688

614689
// Insert all of the blocks that asi is live in.
615690
for (auto *use : asi->getUses())
@@ -630,7 +705,7 @@ void StackAllocationPromoter::promoteAllocationToPhi() {
630705
LLVM_DEBUG(llvm::dbgs() << "*** Placing Phis for : " << *asi);
631706

632707
// A list of blocks that will require new Phi values.
633-
BlockSet phiBlocks(asi->getFunction());
708+
BlockSetVector phiBlocks(asi->getFunction());
634709

635710
// The "piggy-bank" data-structure that we use for processing the dom-tree
636711
// bottom-up.
@@ -1048,6 +1123,12 @@ bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc) {
10481123
LLVM_DEBUG(llvm::dbgs() << "*** Memory to register looking at: " << *alloc);
10491124
++NumAllocStackFound;
10501125

1126+
// In OSSA, don't do Mem2Reg on non-trivial alloc_stack with dynamic_lifetime.
1127+
if (alloc->hasDynamicLifetime() && f.hasOwnership() &&
1128+
!alloc->getType().isTrivial(f)) {
1129+
return false;
1130+
}
1131+
10511132
// Don't handle captured AllocStacks.
10521133
bool inSingleBlock = false;
10531134
if (isCaptured(alloc, inSingleBlock)) {

test/SILOptimizer/mem2reg.sil

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,11 @@ bb0(%0 : $Optional<Klass>):
466466
return %4 : $()
467467
}
468468

469-
// check no dead args are passed to bb3
469+
// dead args okay in non-ossa
470470
// CHECK-LABEL: sil @multi_basic_block_use_on_one_path :
471471
// CHECK-NOT: alloc_stack
472-
// CHECK: bb3:
473-
// CHECK-LABEL: } // end sil function 'multi_basic_block_use_on_one_path'
472+
// CHECK: br bb3(undef : $Klass)
473+
// CHECK: bb3([[dead_arg:%.*]]):
474474
sil @multi_basic_block_use_on_one_path : $@convention(thin) (@owned Klass) -> () {
475475
bb0(%0 : $Klass):
476476
%1 = alloc_stack $Klass

0 commit comments

Comments
 (0)