Skip to content

Commit 4d561ee

Browse files
authored
Merge pull request #61475 from atrick/liveness-cleanup
Liveness cleanup - preparation for OSSA liveness
2 parents 6fb7bcc + 715d3f7 commit 4d561ee

File tree

4 files changed

+83
-25
lines changed

4 files changed

+83
-25
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,11 @@ class DeadEndBlocks;
6363
class MultiDefPrunedLiveness;
6464
struct BorrowedValue;
6565

66-
/// Returns true if v is an address or trivial.
67-
bool isValueAddressOrTrivial(SILValue v);
66+
//===----------------------------------------------------------------------===//
67+
// Forwarding Utilities
68+
//
69+
// TODO: encapsulate in a ForwardingInstruction abstraction
70+
//===----------------------------------------------------------------------===//
6871

6972
/// Is the opcode that produces \p value capable of forwarding guaranteed
7073
/// values?
@@ -108,6 +111,10 @@ inline bool isForwardingConsume(SILValue value) {
108111
return canOpcodeForwardOwnedValues(value);
109112
}
110113

114+
//===----------------------------------------------------------------------===//
115+
// Ownership Def-Use Utilities
116+
//===----------------------------------------------------------------------===//
117+
111118
bool hasPointerEscape(BorrowedValue value);
112119

113120
/// Find leaf "use points" of \p guaranteedValue that determine its lifetime

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,6 @@ bool swift::hasPointerEscape(BorrowedValue value) {
8383
return false;
8484
}
8585

86-
bool swift::isValueAddressOrTrivial(SILValue v) {
87-
return v->getType().isAddress() ||
88-
v->getOwnershipKind() == OwnershipKind::None;
89-
}
90-
9186
bool swift::canOpcodeForwardGuaranteedValues(SILValue value) {
9287
// If we have an argument from a transforming terminator, we can forward
9388
// guaranteed.

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -442,32 +442,68 @@ template class PrunedLiveRange<MultiDefPrunedLiveness>;
442442
// SSAPrunedLiveness
443443
//===----------------------------------------------------------------------===//
444444

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;
445+
/// Given live-within (non-live-out) \p block, find the last user.
446+
void findBoundaryInNonDefBlock(SILBasicBlock *block,
447+
PrunedLivenessBoundary &boundary,
448+
const PrunedLiveness &liveness) {
449+
assert(liveness.getBlockLiveness(block) == PrunedLiveBlocks::LiveWithin);
453450

454-
bool isDefBlockState = isDefBlock(block);
455451
for (SILInstruction &inst : llvm::reverse(*block)) {
456-
if (isDefBlockState && isDef(&inst)) {
452+
if (liveness.isInterestingUser(&inst)) {
453+
boundary.lastUsers.push_back(&inst);
454+
return;
455+
}
456+
}
457+
llvm_unreachable("live-within block must contain an interesting use");
458+
}
459+
460+
/// Given a live-within \p block that contains an SSA definition, and knowledge
461+
/// that all live uses are dominated by that single definition, find either the
462+
/// last user or a dead def.
463+
///
464+
/// A live range with a single definition cannot have any uses above that
465+
/// definition in the same block. This even holds for unreachable self-loops.
466+
void findBoundaryInSSADefBlock(SILNode *ssaDef,
467+
PrunedLivenessBoundary &boundary,
468+
const PrunedLiveness &liveness) {
469+
// defInst is null for argument defs.
470+
SILInstruction *defInst = dyn_cast<SILInstruction>(ssaDef);
471+
for (SILInstruction &inst : llvm::reverse(*ssaDef->getParentBlock())) {
472+
if (&inst == defInst) {
457473
boundary.deadDefs.push_back(cast<SILNode>(&inst));
458474
return;
459475
}
460-
if (isInterestingUser(&inst)) {
476+
if (liveness.isInterestingUser(&inst)) {
461477
boundary.lastUsers.push_back(&inst);
462478
return;
463479
}
464480
}
465-
auto *deadArg = dyn_cast<SILArgument>(def);
466-
assert(deadArg && deadArg->getParent() == block
481+
auto *deadArg = dyn_cast<SILArgument>(ssaDef);
482+
assert(deadArg
467483
&& "findBoundariesInBlock must be called on a live block");
468484
boundary.deadDefs.push_back(deadArg);
469485
}
470486

487+
void SSAPrunedLiveness::findBoundariesInBlock(
488+
SILBasicBlock *block, bool isLiveOut,
489+
PrunedLivenessBoundary &boundary) const {
490+
assert(isInitialized());
491+
492+
// For SSA, a live-out block cannot have a boundary.
493+
if (isLiveOut)
494+
return;
495+
496+
// Handle live-within block
497+
if (!isDefBlock(block)) {
498+
findBoundaryInNonDefBlock(block, boundary, *this);
499+
return;
500+
}
501+
// Find either the last user or a dead def
502+
auto *defInst = def->getDefiningInstruction();
503+
SILNode *defNode = defInst ? cast<SILNode>(defInst) : cast<SILArgument>(def);
504+
findBoundaryInSSADefBlock(defNode, boundary, *this);
505+
}
506+
471507
//===----------------------------------------------------------------------===//
472508
// MultiDefPrunedLiveness
473509
//===----------------------------------------------------------------------===//
@@ -476,25 +512,45 @@ void MultiDefPrunedLiveness::findBoundariesInBlock(
476512
SILBasicBlock *block, bool isLiveOut,
477513
PrunedLivenessBoundary &boundary) const {
478514
assert(isInitialized());
479-
unsigned prevCount = boundary.deadDefs.size() + boundary.lastUsers.size();
480515

516+
if (!isDefBlock(block)) {
517+
// A live-out block with no defs cannot have a boundary.
518+
if (!isLiveOut) {
519+
findBoundaryInNonDefBlock(block, boundary, *this);
520+
}
521+
return;
522+
}
523+
// Handle def blocks...
524+
//
525+
// First, check for an SSA live range
526+
if (++defs.begin() == defs.end()) {
527+
// For SSA, a live-out block cannot have a boundary.
528+
if (!isLiveOut) {
529+
findBoundaryInSSADefBlock(*defs.begin(), boundary, *this);
530+
}
531+
return;
532+
}
533+
// Handle a live-out or live-within block with potentially multiple defs
534+
unsigned prevCount = boundary.deadDefs.size() + boundary.lastUsers.size();
481535
bool isLive = isLiveOut;
482-
bool isDefBlockState = isDefBlock(block);
483536
for (auto &inst : llvm::reverse(*block)) {
484537
// Check if the instruction is a def before checking whether it is a
485538
// use. The same instruction can be both a dead def and boundary use.
486-
if (isDefBlockState && isDef(&inst)) {
539+
if (isDef(&inst)) {
487540
if (!isLive) {
488541
boundary.deadDefs.push_back(cast<SILNode>(&inst));
489542
}
490543
isLive = false;
491544
}
545+
// Note: the same instruction could potentially be both a dead def and last
546+
// user. The liveness boundary supports this, although it won't happen in
547+
// any context where we care about inserting code on the boundary.
492548
if (!isLive && isInterestingUser(&inst)) {
493549
boundary.lastUsers.push_back(&inst);
494550
isLive = true;
495551
}
496552
}
497-
if (!isLive && isDefBlockState) {
553+
if (!isLive) {
498554
for (SILArgument *deadArg : block->getArguments()) {
499555
if (defs.contains(deadArg)) {
500556
boundary.deadDefs.push_back(deadArg);

lib/SIL/Verifier/SILOwnershipVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses(
579579
}
580580
}
581581

582-
if (!isValueAddressOrTrivial(value)) {
582+
if (value->getOwnershipKind() != OwnershipKind::None) {
583583
return !errorBuilder.handleMalformedSIL([&] {
584584
if (value->getOwnershipKind() == OwnershipKind::Owned) {
585585
llvm::errs() << "Error! Found a leaked owned value that was never "

0 commit comments

Comments
 (0)