Skip to content

Commit 755bce2

Browse files
committed
Remove complexity in findBoundariesInBlock
We can remove a ton of complexity by assuming that SSA uses never occur before a def in the same block. This will hold true as long as useless phis are only removed after all unreachable code is first removed. Then we don't have the self-loop problem. The SILVerifier already checks this invariant and I added an in-depth comment in SimplifyCFG.
1 parent 8f34d9c commit 755bce2

File tree

2 files changed

+68
-106
lines changed

2 files changed

+68
-106
lines changed

include/swift/SIL/PrunedLiveness.h

Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -530,11 +530,6 @@ struct PrunedLivenessBoundary {
530530
///
531531
/// bool isDefBlock(SILBasicBlock *block) const
532532
///
533-
/// SILArgument *getArgDef(SILBasicBlock *block) const
534-
///
535-
/// SILInstruction *findPreviousDef(SILInstruction *searchPos,
536-
/// SILInstruction *nextDef)
537-
///
538533
template <typename LivenessWithDefs>
539534
class PrunedLiveRange : public PrunedLiveness {
540535
protected:
@@ -587,10 +582,6 @@ class PrunedLiveRange : public PrunedLiveness {
587582
/// by DeadEndBlocks.
588583
void computeBoundary(PrunedLivenessBoundary &boundary,
589584
ArrayRef<SILBasicBlock *> postDomBlocks) const;
590-
591-
protected:
592-
void findBoundariesInBlock(SILBasicBlock *block, bool isLiveOut,
593-
PrunedLivenessBoundary &boundary) const;
594585
};
595586

596587
// Singly-defined liveness.
@@ -642,28 +633,9 @@ class SSAPrunedLiveness : public PrunedLiveRange<SSAPrunedLiveness> {
642633
return def->getParentBlock() == block;
643634
}
644635

645-
/// If the argument list of \p block contains a definition, return it.
646-
SILArgument *getArgDef(SILBasicBlock *block) const {
647-
if (auto *arg = dyn_cast<SILArgument>(def)) {
648-
if (arg->getParent() == block)
649-
return arg;
650-
}
651-
return nullptr;
652-
}
653-
654-
/// Return the definition if it occurs in the same block before \p searchPos.
655-
///
656-
/// Precondition: if the definition occurs in the same block on or after \p
657-
/// searchPos, then \p nextDef must point to the definition.
658-
SILInstruction *findPreviousDef(SILInstruction *searchPos,
659-
SILInstruction *nextDef) const {
660-
if (!defInst || nextDef) {
661-
assert(nextDef == defInst);
662-
return nullptr;
663-
}
664-
auto *block = searchPos->getParent();
665-
return defInst->getParent() == block ? defInst : nullptr;
666-
}
636+
/// SSA implementation of computeBoundary.
637+
void findBoundariesInBlock(SILBasicBlock *block, bool isLiveOut,
638+
PrunedLivenessBoundary &boundary) const;
667639

668640
/// Compute liveness for a single SSA definition. The lifetime-ending uses are
669641
/// also recorded--destroy_value or end_borrow.
@@ -722,26 +694,9 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
722694
return defBlocks.contains(block);
723695
}
724696

725-
/// If the argument list of \p block contains a definition, return it.
726-
SILArgument *getArgDef(SILBasicBlock *block) const {
727-
if (!isDefBlock(block))
728-
return nullptr;
729-
730-
for (SILArgument *arg : block->getArguments()) {
731-
if (defs.contains(arg))
732-
return arg;
733-
}
734-
return nullptr;
735-
}
736-
737-
/// Return the previous definition that occurs in the same block before \p
738-
/// searchPos, or nullptr if none exists.
739-
///
740-
/// Precondition: if a definition occurs in the same block on or after \p
741-
/// searchPos, then \p nextDef must point to the next definition. searchPos
742-
/// cannot point to nextDef.
743-
SILInstruction *findPreviousDef(SILInstruction *searchPos,
744-
SILInstruction *nextDef) const;
697+
/// Multi-Def implementation of computeBoundary.
698+
void findBoundariesInBlock(SILBasicBlock *block, bool isLiveOut,
699+
PrunedLivenessBoundary &boundary) const;
745700

746701
/// Compute liveness for a all currently initialized definitions. The
747702
/// lifetime-ending uses are also recorded--destroy_value or

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 62 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -367,44 +367,6 @@ bool PrunedLiveRange<LivenessWithDefs>::areUsesOutsideBoundary(
367367
return true;
368368
}
369369

370-
template <typename LivenessWithDefs>
371-
void PrunedLiveRange<LivenessWithDefs>::findBoundariesInBlock(
372-
SILBasicBlock *block, bool isLiveOut,
373-
PrunedLivenessBoundary &boundary) const {
374-
assert(asImpl().isInitialized());
375-
376-
bool isLive = isLiveOut;
377-
bool isDefBlock = asImpl().isDefBlock(block);
378-
SILInstruction *nextDef = nullptr;
379-
SILInstruction *searchPos = block->getTerminator();
380-
while (searchPos) {
381-
if (isLive) {
382-
nextDef = asImpl().findPreviousDef(searchPos, nextDef);
383-
if (!nextDef)
384-
return;
385-
386-
searchPos = nextDef;
387-
isLive = false;
388-
} else if (isDefBlock) {
389-
// Check if the previous instruction is a def before checking whether it
390-
// is a use. The same instruction can be both a dead def and boundary use.
391-
if (asImpl().isDef(searchPos)) {
392-
boundary.deadDefs.push_back(cast<SILNode>(searchPos));
393-
}
394-
}
395-
if (isInterestingUser(searchPos)) {
396-
boundary.lastUsers.push_back(searchPos);
397-
isLive = true;
398-
}
399-
searchPos = searchPos->getPreviousInstruction();
400-
}
401-
if (!isLive && isDefBlock) {
402-
if (SILArgument *deadArg = asImpl().getArgDef(block)) {
403-
boundary.deadDefs.push_back(deadArg);
404-
}
405-
}
406-
}
407-
408370
template <typename LivenessWithDefs>
409371
void PrunedLiveRange<LivenessWithDefs>::computeBoundary(
410372
PrunedLivenessBoundary &boundary) const {
@@ -419,10 +381,10 @@ void PrunedLiveRange<LivenessWithDefs>::computeBoundary(
419381
boundary.boundaryEdges.push_back(succBB);
420382
}
421383
}
422-
findBoundariesInBlock(block, /*isLiveOut*/ true, boundary);
384+
asImpl().findBoundariesInBlock(block, /*isLiveOut*/ true, boundary);
423385
break;
424386
case PrunedLiveBlocks::LiveWithin: {
425-
findBoundariesInBlock(block, /*isLiveOut*/ false, boundary);
387+
asImpl().findBoundariesInBlock(block, /*isLiveOut*/ false, boundary);
426388
break;
427389
}
428390
case PrunedLiveBlocks::Dead:
@@ -451,10 +413,10 @@ void PrunedLiveRange<LivenessWithDefs>::computeBoundary(
451413
// Process each block that has not been visited and is not LiveOut.
452414
switch (getBlockLiveness(block)) {
453415
case PrunedLiveBlocks::LiveOut:
454-
findBoundariesInBlock(block, /*isLiveOut*/ true, boundary);
416+
asImpl().findBoundariesInBlock(block, /*isLiveOut*/ true, boundary);
455417
break;
456418
case PrunedLiveBlocks::LiveWithin: {
457-
findBoundariesInBlock(block, /*isLiveOut*/ false, boundary);
419+
asImpl().findBoundariesInBlock(block, /*isLiveOut*/ false, boundary);
458420
break;
459421
}
460422
case PrunedLiveBlocks::Dead:
@@ -476,26 +438,71 @@ template class PrunedLiveRange<SSAPrunedLiveness>;
476438
template class PrunedLiveRange<MultiDefPrunedLiveness>;
477439
} // namespace swift
478440

441+
//===----------------------------------------------------------------------===//
442+
// SSAPrunedLiveness
443+
//===----------------------------------------------------------------------===//
444+
445+
void SSAPrunedLiveness::findBoundariesInBlock(
446+
SILBasicBlock *block, bool isLiveOut,
447+
PrunedLivenessBoundary &boundary) const {
448+
assert(isInitialized());
449+
450+
// For SSA, a live-out block cannot have a boundary.
451+
if (isLiveOut)
452+
return;
453+
454+
bool isDefBlockState = isDefBlock(block);
455+
for (SILInstruction &inst : llvm::reverse(*block)) {
456+
if (isDefBlockState && isDef(&inst)) {
457+
boundary.deadDefs.push_back(cast<SILNode>(&inst));
458+
return;
459+
}
460+
if (isInterestingUser(&inst)) {
461+
boundary.lastUsers.push_back(&inst);
462+
return;
463+
}
464+
}
465+
auto *deadArg = dyn_cast<SILArgument>(def);
466+
assert(deadArg && deadArg->getParent() == block
467+
&& "findBoundariesInBlock must be called on a live block");
468+
boundary.deadDefs.push_back(deadArg);
469+
}
470+
479471
//===----------------------------------------------------------------------===//
480472
// MultiDefPrunedLiveness
481473
//===----------------------------------------------------------------------===//
482474

483-
SILInstruction *
484-
MultiDefPrunedLiveness::findPreviousDef(SILInstruction *searchPos,
485-
SILInstruction *nextDef) const {
486-
auto *block = searchPos->getParent();
487-
if (!defBlocks.contains(block))
488-
return nullptr;
475+
void MultiDefPrunedLiveness::findBoundariesInBlock(
476+
SILBasicBlock *block, bool isLiveOut,
477+
PrunedLivenessBoundary &boundary) const {
478+
assert(isInitialized());
479+
unsigned prevCount = boundary.deadDefs.size() + boundary.lastUsers.size();
489480

490-
auto it = searchPos->getReverseIterator();
491-
if (searchPos == nextDef) {
492-
++it;
481+
bool isLive = isLiveOut;
482+
bool isDefBlockState = isDefBlock(block);
483+
for (auto &inst : llvm::reverse(*block)) {
484+
// Check if the instruction is a def before checking whether it is a
485+
// use. The same instruction can be both a dead def and boundary use.
486+
if (isDefBlockState && isDef(&inst)) {
487+
if (!isLive) {
488+
boundary.deadDefs.push_back(cast<SILNode>(&inst));
489+
}
490+
isLive = false;
491+
}
492+
if (!isLive && isInterestingUser(&inst)) {
493+
boundary.lastUsers.push_back(&inst);
494+
isLive = true;
495+
}
493496
}
494-
for (auto end = block->rend(); it != end; ++it) {
495-
if (isDef(&*it))
496-
return &*it;
497+
if (!isLive && isDefBlockState) {
498+
for (SILArgument *deadArg : block->getArguments()) {
499+
if (defs.contains(deadArg)) {
500+
boundary.deadDefs.push_back(deadArg);
501+
}
502+
}
497503
}
498-
return nullptr;
504+
assert(prevCount < boundary.deadDefs.size() + boundary.lastUsers.size()
505+
&& "findBoundariesInBlock must be called on a live block");
499506
}
500507

501508
SimpleLiveRangeSummary MultiDefPrunedLiveness::computeSimple() {

0 commit comments

Comments
 (0)