Skip to content

Commit dc4c874

Browse files
authored
Merge pull request #72452 from jckarter/pruned-liveness-try-apply-conditional-def
FieldSensitivePrunedLiveness: Handle conditionality of `try_apply` defs.
2 parents d24843e + 1166f2e commit dc4c874

File tree

4 files changed

+78
-43
lines changed

4 files changed

+78
-43
lines changed

include/swift/SIL/FieldSensitivePrunedLiveness.h

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -493,17 +493,21 @@ class FieldSensitivePrunedLiveBlocks {
493493
/// LiveWithin blocks have at least one use and/or def within the block, but
494494
/// are not (yet) LiveOut.
495495
///
496+
/// DeadToLiveEdge blocks are not live within the block itself, but the value
497+
/// becomes live on one or more of the edges out.
498+
///
496499
/// LiveOut blocks are live on at least one successor path. LiveOut blocks may
497500
/// or may not contain defs or uses.
498-
///
499-
/// NOTE: The values below for Dead, LiveWithin, LiveOut were picked to ensure
500-
/// that given a 2 bit representation of the value, a value is Dead if the
501-
/// first bit is 0 and is LiveOut if the second bit is set.
502501
enum IsLive {
503502
Dead = 0,
504503
LiveWithin = 1,
504+
DeadToLiveEdge = 2,
505505
LiveOut = 3,
506506
};
507+
508+
static bool isDead(IsLive liveness) {
509+
return liveness == Dead || liveness == DeadToLiveEdge;
510+
}
507511

508512
/// A bit vector that stores information about liveness. This is composed
509513
/// with SmallBitVector since it contains two bits per liveness so that it
@@ -524,37 +528,27 @@ class FieldSensitivePrunedLiveBlocks {
524528
unsigned size() const { return bits.size() / 2; }
525529

526530
IsLive getLiveness(unsigned bitNo) const {
527-
if (!bits[bitNo * 2])
528-
return IsLive::Dead;
529-
return bits[bitNo * 2 + 1] ? LiveOut : LiveWithin;
531+
return IsLive((bits[bitNo * 2 + 1] << 1) | bits[bitNo * 2]);
530532
}
531533

532534
/// Returns the liveness in \p resultingFoundLiveness. We only return the
533535
/// bits for endBitNo - startBitNo.
534536
void getLiveness(unsigned startBitNo, unsigned endBitNo,
535537
SmallVectorImpl<IsLive> &resultingFoundLiveness) const {
536-
unsigned actualStartBitNo = startBitNo * 2;
537-
unsigned actualEndBitNo = endBitNo * 2;
538-
539-
for (unsigned i = actualStartBitNo, e = actualEndBitNo; i != e; i += 2) {
540-
if (!bits[i]) {
541-
resultingFoundLiveness.push_back(Dead);
542-
continue;
543-
}
544-
545-
resultingFoundLiveness.push_back(bits[i + 1] ? LiveOut : LiveWithin);
538+
for (unsigned i = startBitNo, e = endBitNo; i != e; ++i) {
539+
resultingFoundLiveness.push_back(getLiveness(i));
546540
}
547541
}
548542

549-
void setLiveness(unsigned startBitNo, unsigned endBitNo, IsLive isLive) {
550-
for (unsigned i = startBitNo * 2, e = endBitNo * 2; i != e; i += 2) {
551-
bits[i] = isLive & 1;
552-
bits[i + 1] = isLive & 2;
553-
}
543+
void setLiveness(unsigned bitNo, IsLive isLive) {
544+
bits[bitNo * 2] = isLive & 1;
545+
bits[bitNo * 2 + 1] = bool(isLive & 2);
554546
}
555547

556-
void setLiveness(unsigned bitNo, IsLive isLive) {
557-
setLiveness(bitNo, bitNo + 1, isLive);
548+
void setLiveness(unsigned startBitNo, unsigned endBitNo, IsLive isLive) {
549+
for (unsigned i = startBitNo, e = endBitNo; i != e; ++i) {
550+
setLiveness(i, isLive);
551+
}
558552
}
559553
};
560554

@@ -620,9 +614,10 @@ class FieldSensitivePrunedLiveBlocks {
620614
}
621615

622616
void initializeDefBlock(SILBasicBlock *defBB, unsigned startBitNo,
623-
unsigned endBitNo) {
617+
unsigned endBitNo,
618+
IsLive isLive = LiveWithin) {
624619
assert(isInitialized());
625-
markBlockLive(defBB, startBitNo, endBitNo, LiveWithin);
620+
markBlockLive(defBB, startBitNo, endBitNo, isLive);
626621
}
627622

628623
/// Update this liveness result for a single use.
@@ -632,7 +627,7 @@ class FieldSensitivePrunedLiveBlocks {
632627
auto *block = user->getParent();
633628
if (!isUserBeforeDef) {
634629
auto liveness = getBlockLiveness(block, bitNo);
635-
if (liveness != Dead)
630+
if (!isDead(liveness))
636631
return liveness;
637632
}
638633
computeScalarUseBlockLiveness(block, bitNo);
@@ -696,6 +691,7 @@ class FieldSensitivePrunedLiveBlocks {
696691
// If we are dead, always update to the new liveness.
697692
switch (iterAndInserted.first->getSecond().getLiveness(bitNo)) {
698693
case Dead:
694+
case DeadToLiveEdge:
699695
iterAndInserted.first->getSecond().setLiveness(bitNo, bitNo + 1,
700696
isLive);
701697
break;
@@ -935,10 +931,12 @@ class FieldSensitivePrunedLiveness {
935931
return UserBlockRange(getAllUsers(), op);
936932
}
937933

938-
void initializeDefBlock(SILBasicBlock *defBB, TypeTreeLeafTypeRange span) {
934+
void initializeDefBlock(SILBasicBlock *defBB, TypeTreeLeafTypeRange span,
935+
FieldSensitivePrunedLiveBlocks::IsLive isLive
936+
= FieldSensitivePrunedLiveBlocks::LiveWithin) {
939937
assert(isInitialized());
940938
liveBlocks.initializeDefBlock(defBB, span.startEltOffset,
941-
span.endEltOffset);
939+
span.endEltOffset, isLive);
942940
}
943941

944942
/// For flexibility, \p lifetimeEnding is provided by the
@@ -1303,6 +1301,14 @@ class FieldSensitiveSSAPrunedLiveRange
13031301
FieldSensitivePrunedLivenessBoundary &boundary) const;
13041302
};
13051303

1304+
static inline SILBasicBlock *getDefinedInBlock(SILNode *node) {
1305+
// try_apply defines the value only on the success edge.
1306+
if (auto ta = dyn_cast<TryApplyInst>(node)) {
1307+
return ta->getNormalBB();
1308+
}
1309+
return node->getParentBlock();
1310+
}
1311+
13061312
/// MultiDefPrunedLiveness is computed incrementally by calling updateForUse.
13071313
///
13081314
/// Defs should be initialized before calling updatingForUse on any def
@@ -1351,9 +1357,17 @@ class FieldSensitiveMultiDefPrunedLiveRange
13511357
void initializeDef(SILNode *node, TypeTreeLeafTypeRange span) {
13521358
assert(Super::isInitialized());
13531359
defs.insert(node, span);
1354-
auto *block = node->getParentBlock();
1355-
defBlocks.insert(block, span);
1356-
initializeDefBlock(block, span);
1360+
auto defBlock = getDefinedInBlock(node);
1361+
defBlocks.insert(defBlock, span);
1362+
initializeDefBlock(defBlock, span);
1363+
1364+
if (auto ta = dyn_cast<TryApplyInst>(node)) {
1365+
// The value becomes live on the success edge.
1366+
// Mark the basic block the try_apply terminates as a dead-to-live
1367+
// edge.
1368+
initializeDefBlock(ta->getParent(), span,
1369+
FieldSensitivePrunedLiveBlocks::DeadToLiveEdge);
1370+
}
13571371
}
13581372

13591373
void initializeDef(SILInstruction *def, TypeTreeLeafTypeRange span) {

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ void FieldSensitivePrunedLiveBlocks::computeScalarUseBlockLiveness(
579579
case LiveWithin:
580580
markBlockLive(predBlock, bitNo, LiveOut);
581581
break;
582+
case DeadToLiveEdge:
582583
case LiveOut:
583584
break;
584585
}
@@ -615,6 +616,7 @@ void FieldSensitivePrunedLiveBlocks::updateForUse(
615616
} else {
616617
LLVM_FALLTHROUGH;
617618
}
619+
case DeadToLiveEdge:
618620
case Dead: {
619621
// This use block has not yet been marked live. Mark it and its
620622
// predecessor blocks live.
@@ -634,6 +636,8 @@ FieldSensitivePrunedLiveBlocks::getStringRef(IsLive isLive) const {
634636
return "Dead";
635637
case LiveWithin:
636638
return "LiveWithin";
639+
case DeadToLiveEdge:
640+
return "DeadToLiveEdge";
637641
case LiveOut:
638642
return "LiveOut";
639643
}
@@ -853,6 +857,7 @@ bool FieldSensitivePrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
853857
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Visiting bit: " << bit << '\n');
854858
bool isLive = false;
855859
switch (pair.value()) {
860+
case FieldSensitivePrunedLiveBlocks::DeadToLiveEdge:
856861
case FieldSensitivePrunedLiveBlocks::Dead:
857862
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Dead... continuing!\n");
858863
// We are only not within the boundary if all of our bits are dead. We
@@ -942,6 +947,8 @@ static StringRef getStringRef(FieldSensitivePrunedLiveBlocks::IsLive isLive) {
942947
return "Dead";
943948
case FieldSensitivePrunedLiveBlocks::LiveWithin:
944949
return "LiveWithin";
950+
case FieldSensitivePrunedLiveBlocks::DeadToLiveEdge:
951+
return "DeadToLiveEdge";
945952
case FieldSensitivePrunedLiveBlocks::LiveOut:
946953
return "LiveOut";
947954
}
@@ -972,8 +979,8 @@ void FieldSensitivePrunedLiveRange<LivenessWithDefs>::computeBoundary(
972979
switch (pair.value()) {
973980
case FieldSensitivePrunedLiveBlocks::LiveOut:
974981
for (SILBasicBlock *succBB : block->getSuccessors()) {
975-
if (getBlockLiveness(succBB, index) ==
976-
FieldSensitivePrunedLiveBlocks::Dead) {
982+
if (FieldSensitivePrunedLiveBlocks::isDead(
983+
getBlockLiveness(succBB, index))) {
977984
PRUNED_LIVENESS_LOG(llvm::dbgs() << "Marking succBB as boundary edge: bb"
978985
<< succBB->getDebugID() << '\n');
979986
boundary.getBoundaryEdgeBits(succBB).set(index);
@@ -989,6 +996,9 @@ void FieldSensitivePrunedLiveRange<LivenessWithDefs>::computeBoundary(
989996
foundAnyNonDead = true;
990997
break;
991998
}
999+
case FieldSensitivePrunedLiveBlocks::DeadToLiveEdge:
1000+
foundAnyNonDead = true;
1001+
LLVM_FALLTHROUGH;
9921002
case FieldSensitivePrunedLiveBlocks::Dead:
9931003
// We do not assert here like in the normal pruned liveness
9941004
// implementation since we can have dead on some bits and liveness along
@@ -1178,7 +1188,7 @@ void findBoundaryInSSADefBlock(SILNode *ssaDef, unsigned bitNo,
11781188
// defInst is null for argument defs.
11791189
PRUNED_LIVENESS_LOG(llvm::dbgs() << "Searching using findBoundaryInSSADefBlock.\n");
11801190
SILInstruction *defInst = dyn_cast<SILInstruction>(ssaDef);
1181-
for (SILInstruction &inst : llvm::reverse(*ssaDef->getParentBlock())) {
1191+
for (SILInstruction &inst : llvm::reverse(*getDefinedInBlock(ssaDef))) {
11821192
PRUNED_LIVENESS_LOG(llvm::dbgs() << "Visiting: " << inst);
11831193
if (&inst == defInst) {
11841194
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found dead def: " << *defInst);
@@ -1192,9 +1202,21 @@ void findBoundaryInSSADefBlock(SILNode *ssaDef, unsigned bitNo,
11921202
}
11931203
}
11941204

1195-
auto *deadArg = cast<SILArgument>(ssaDef);
1196-
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found dead arg: " << *deadArg);
1197-
boundary.getDeadDefsBits(deadArg).set(bitNo);
1205+
if (auto *deadArg = dyn_cast<SILArgument>(ssaDef)) {
1206+
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found dead arg: " << *deadArg);
1207+
boundary.getDeadDefsBits(deadArg).set(bitNo);
1208+
return;
1209+
}
1210+
1211+
// If we searched the success branch of a try_apply and found no uses, then
1212+
// the try_apply itself is a dead def.
1213+
if (isa<TryApplyInst>(ssaDef)) {
1214+
PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found dead try_apply: " << *ssaDef);
1215+
boundary.getDeadDefsBits(ssaDef).set(bitNo);
1216+
return;
1217+
}
1218+
1219+
llvm_unreachable("def not found?!");
11981220
}
11991221

12001222
//===----------------------------------------------------------------------===//

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2816,6 +2816,7 @@ bool GlobalLivenessChecker::testInstVectorLiveness(
28162816
for (auto isLive : isLiveArray) {
28172817
switch (isLive) {
28182818
case IsLive::Dead:
2819+
case IsLive::DeadToLiveEdge:
28192820
LLVM_DEBUG(llvm::dbgs() << " Dead block!\n");
28202821
// Ignore a dead block. Our error use could not be in such a block.
28212822
//

test/Interpreter/moveonly_resilient_deinit_on_throw_same_module.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
// RUN: %target-codesign %t/a.out.fragile
44
// RUN: %target-run %t/a.out.fragile | %FileCheck %s
55

6-
// FIXME: miscompiles cause extra deinits with library evolution enabled
7-
8-
// R/UN: %target-build-swift -enable-library-evolution -o %t/a.out.resilient %s
9-
// R/UN: %target-codesign %t/a.out.resilient
10-
// R/UN: %target-run %t/a.out.resilient | %FileCheck %s
6+
// RUN: %target-build-swift -enable-library-evolution -o %t/a.out.resilient %s
7+
// RUN: %target-codesign %t/a.out.resilient
8+
// RUN: %target-run %t/a.out.resilient | %FileCheck %s
119

1210
// REQUIRES: executable_test
1311

0 commit comments

Comments
 (0)