Skip to content

Commit dd730b8

Browse files
committed
[LifetimeCompletion] Flag instructions dead_end.
1 parent d641dc6 commit dd730b8

13 files changed

+93
-57
lines changed

include/swift/SIL/OSSALifetimeCompletion.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
namespace swift {
3636

37+
class DeadEndBlocks;
38+
3739
enum class LifetimeCompletion { NoLifetime, AlreadyComplete, WasCompleted };
3840

3941
class OSSALifetimeCompletion {
@@ -42,13 +44,17 @@ class OSSALifetimeCompletion {
4244
// create a new phi would result in an immediately redundant phi.
4345
const DominanceInfo *domInfo = nullptr;
4446

47+
DeadEndBlocks &deadEndBlocks;
48+
4549
// Cache intructions already handled by the recursive algorithm to avoid
4650
// recomputing their lifetimes.
4751
ValueSet completedValues;
4852

4953
public:
50-
OSSALifetimeCompletion(SILFunction *function, const DominanceInfo *domInfo)
51-
: domInfo(domInfo), completedValues(function) {}
54+
OSSALifetimeCompletion(SILFunction *function, const DominanceInfo *domInfo,
55+
DeadEndBlocks &deadEndBlocks)
56+
: domInfo(domInfo), deadEndBlocks(deadEndBlocks),
57+
completedValues(function) {}
5258

5359
// The kind of boundary at which to complete the lifetime.
5460
//
@@ -139,16 +145,19 @@ class UnreachableLifetimeCompletion {
139145
// If domInfo is nullptr, lifetime completion may attempt to recreate
140146
// redundant phis, which should be immediately discarded.
141147
const DominanceInfo *domInfo = nullptr;
148+
DeadEndBlocks &deadEndBlocks;
142149

143150
BasicBlockSetVector unreachableBlocks;
144151
InstructionSet unreachableInsts; // not including those in unreachableBlocks
145152
ValueSetVector incompleteValues;
146153
bool updatingLifetimes = false;
147154

148155
public:
149-
UnreachableLifetimeCompletion(SILFunction *function, DominanceInfo *domInfo)
150-
: function(function), domInfo(domInfo), unreachableBlocks(function),
151-
unreachableInsts(function), incompleteValues(function) {}
156+
UnreachableLifetimeCompletion(SILFunction *function, DominanceInfo *domInfo,
157+
DeadEndBlocks &deadEndBlocks)
158+
: function(function), domInfo(domInfo), deadEndBlocks(deadEndBlocks),
159+
unreachableBlocks(function), unreachableInsts(function),
160+
incompleteValues(function) {}
152161

153162
/// Record information about this unreachable instruction and return true if
154163
/// ends any simple OSSA lifetimes.

lib/SIL/Utils/OSSALifetimeCompletion.cpp

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@
4949
///
5050
//===----------------------------------------------------------------------===//
5151

52-
#include "swift/Basic/Assertions.h"
5352
#include "swift/SIL/OSSALifetimeCompletion.h"
53+
#include "swift/Basic/Assertions.h"
54+
#include "swift/SIL/BasicBlockUtils.h"
5455
#include "swift/SIL/SILBuilder.h"
5556
#include "swift/SIL/SILFunction.h"
5657
#include "swift/SIL/SILInstruction.h"
@@ -61,23 +62,26 @@ using namespace swift;
6162

6263
static SILInstruction *endOSSALifetime(SILValue value,
6364
OSSALifetimeCompletion::LifetimeEnd end,
64-
SILBuilder &builder) {
65+
SILBuilder &builder,
66+
DeadEndBlocks &deb) {
6567
auto loc =
6668
RegularLocation::getAutoGeneratedLocation(builder.getInsertionPointLoc());
6769
if (end == OSSALifetimeCompletion::LifetimeEnd::Loop) {
6870
return builder.createExtendLifetime(loc, value);
6971
}
72+
auto isDeadEnd = IsDeadEnd_t(deb.isDeadEnd(builder.getInsertionBB()));
7073
if (value->getOwnershipKind() == OwnershipKind::Owned) {
7174
if (value->getType().is<SILBoxType>()) {
72-
return builder.createDeallocBox(loc, value);
75+
return builder.createDeallocBox(loc, value, isDeadEnd);
7376
}
74-
return builder.createDestroyValue(loc, value);
77+
return builder.createDestroyValue(loc, value, DontPoisonRefs, isDeadEnd);
7578
}
76-
return builder.createEndBorrow(loc, value);
79+
return builder.createEndBorrow(loc, value, isDeadEnd);
7780
}
7881

7982
static bool endLifetimeAtLivenessBoundary(SILValue value,
80-
const SSAPrunedLiveness &liveness) {
83+
const SSAPrunedLiveness &liveness,
84+
DeadEndBlocks &deb) {
8185
PrunedLivenessBoundary boundary;
8286
liveness.computeBoundary(boundary);
8387

@@ -86,17 +90,18 @@ static bool endLifetimeAtLivenessBoundary(SILValue value,
8690
if (liveness.isInterestingUser(lastUser)
8791
!= PrunedLiveness::LifetimeEndingUse) {
8892
changed = true;
89-
SILBuilderWithScope::insertAfter(lastUser, [value](SILBuilder &builder) {
93+
SILBuilderWithScope::insertAfter(lastUser, [value,
94+
&deb](SILBuilder &builder) {
9095
endOSSALifetime(value, OSSALifetimeCompletion::LifetimeEnd::Boundary,
91-
builder);
96+
builder, deb);
9297
});
9398
}
9499
}
95100
for (SILBasicBlock *edge : boundary.boundaryEdges) {
96101
changed = true;
97102
SILBuilderWithScope builder(edge->begin());
98103
endOSSALifetime(value, OSSALifetimeCompletion::LifetimeEnd::Boundary,
99-
builder);
104+
builder, deb);
100105
}
101106
for (SILNode *deadDef : boundary.deadDefs) {
102107
SILInstruction *next = nullptr;
@@ -108,7 +113,7 @@ static bool endLifetimeAtLivenessBoundary(SILValue value,
108113
changed = true;
109114
SILBuilderWithScope builder(next);
110115
endOSSALifetime(value, OSSALifetimeCompletion::LifetimeEnd::Boundary,
111-
builder);
116+
builder, deb);
112117
}
113118
return changed;
114119
}
@@ -395,14 +400,14 @@ void OSSALifetimeCompletion::visitAvailabilityBoundary(
395400
});
396401
}
397402

398-
static bool
399-
endLifetimeAtAvailabilityBoundary(SILValue value,
400-
const SSAPrunedLiveness &liveness) {
403+
static bool endLifetimeAtAvailabilityBoundary(SILValue value,
404+
const SSAPrunedLiveness &liveness,
405+
DeadEndBlocks &deb) {
401406
bool changed = false;
402407
OSSALifetimeCompletion::visitAvailabilityBoundary(
403408
value, liveness, [&](auto *unreachable, auto end) {
404409
SILBuilderWithScope builder(unreachable);
405-
endOSSALifetime(value, end, builder);
410+
endOSSALifetime(value, end, builder, deb);
406411
changed = true;
407412
});
408413
return changed;
@@ -424,10 +429,12 @@ bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(SILValue value,
424429
bool changed = false;
425430
switch (boundary) {
426431
case Boundary::Liveness:
427-
changed |= endLifetimeAtLivenessBoundary(value, liveness.getLiveness());
432+
changed |= endLifetimeAtLivenessBoundary(value, liveness.getLiveness(),
433+
deadEndBlocks);
428434
break;
429435
case Boundary::Availability:
430-
changed |= endLifetimeAtAvailabilityBoundary(value, liveness.getLiveness());
436+
changed |= endLifetimeAtAvailabilityBoundary(value, liveness.getLiveness(),
437+
deadEndBlocks);
431438
break;
432439
}
433440
// TODO: Rebuild outer adjacent phis on demand (SILGen does not currently
@@ -453,9 +460,10 @@ static FunctionTest OSSALifetimeCompletionTest(
453460
.Case("liveness", OSSALifetimeCompletion::Boundary::Liveness)
454461
.Case("availability",
455462
OSSALifetimeCompletion::Boundary::Availability);
463+
auto *deb = test.getDeadEndBlocks();
456464
llvm::outs() << "OSSA lifetime completion on " << kind
457465
<< " boundary: " << value;
458-
OSSALifetimeCompletion completion(&function, /*domInfo*/ nullptr);
466+
OSSALifetimeCompletion completion(&function, /*domInfo*/ nullptr, *deb);
459467
completion.completeOSSALifetime(value, kind);
460468
function.print(llvm::outs());
461469
});
@@ -532,7 +540,7 @@ bool UnreachableLifetimeCompletion::completeLifetimes() {
532540
}
533541
}
534542

535-
OSSALifetimeCompletion completion(function, domInfo);
543+
OSSALifetimeCompletion completion(function, domInfo, deadEndBlocks);
536544

537545
bool changed = false;
538546
for (auto value : incompleteValues) {

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerTester.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class MoveOnlyAddressCheckerTesterPass : public SILFunctionTransform {
9090
auto *dominanceAnalysis = getAnalysis<DominanceAnalysis>();
9191
DominanceInfo *domTree = dominanceAnalysis->get(fn);
9292
auto *poa = getAnalysis<PostOrderAnalysis>();
93+
auto *deba = getAnalysis<DeadEndBlocksAnalysis>();
9394

9495
DiagnosticEmitter diagnosticEmitter(fn);
9596
llvm::SmallSetVector<MarkUnresolvedNonCopyableValueInst *, 32>
@@ -108,8 +109,8 @@ class MoveOnlyAddressCheckerTesterPass : public SILFunctionTransform {
108109
LLVM_DEBUG(llvm::dbgs() << "No move introducers found?!\n");
109110
} else {
110111
borrowtodestructure::IntervalMapAllocator allocator;
111-
MoveOnlyAddressChecker checker{getFunction(), diagnosticEmitter,
112-
allocator, domTree, poa};
112+
MoveOnlyAddressChecker checker{
113+
getFunction(), diagnosticEmitter, allocator, domTree, poa, deba};
113114
madeChange = checker.completeLifetimes();
114115
madeChange |= checker.check(moveIntroducersToProcess);
115116
}

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4030,7 +4030,8 @@ bool MoveOnlyAddressChecker::completeLifetimes() {
40304030

40314031
// Lifetimes must be completed inside out (bottom-up in the CFG).
40324032
PostOrderFunctionInfo *postOrder = poa->get(fn);
4033-
OSSALifetimeCompletion completion(fn, domTree);
4033+
OSSALifetimeCompletion completion(fn, domTree,
4034+
*deadEndBlocksAnalysis->get(fn));
40344035
for (auto *block : postOrder->getPostOrder()) {
40354036
for (SILInstruction &inst : reverse(*block)) {
40364037
for (auto result : inst.getResults()) {

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
namespace swift {
1919

2020
class PostOrderAnalysis;
21+
class DeadEndBlocksAnalysis;
2122

2223
namespace siloptimizer {
2324

@@ -39,6 +40,7 @@ struct MoveOnlyAddressChecker {
3940
borrowtodestructure::IntervalMapAllocator &allocator;
4041
DominanceInfo *domTree;
4142
PostOrderAnalysis *poa;
43+
DeadEndBlocksAnalysis *deadEndBlocksAnalysis;
4244

4345
/// \returns true if we changed the IR. To see if we emitted a diagnostic, use
4446
/// \p diagnosticEmitter.getDiagnosticCount().

lib/SILOptimizer/Mandatory/MoveOnlyChecker.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,13 @@ struct MoveOnlyChecker {
7979
SILFunction *fn;
8080
DominanceInfo *domTree;
8181
PostOrderAnalysis *poa;
82+
DeadEndBlocksAnalysis *deba;
8283
bool madeChange = false;
8384
borrowtodestructure::IntervalMapAllocator allocator;
8485

8586
MoveOnlyChecker(SILFunction *fn, DominanceInfo *domTree,
86-
PostOrderAnalysis *poa)
87-
: diagnosticEmitter(fn), fn(fn), domTree(domTree), poa(poa) {
88-
}
87+
PostOrderAnalysis *poa, DeadEndBlocksAnalysis *deba)
88+
: diagnosticEmitter(fn), fn(fn), domTree(domTree), poa(poa), deba(deba) {}
8989

9090
void checkObjects();
9191
void completeObjectLifetimes(ArrayRef<MarkUnresolvedNonCopyableValueInst *>);
@@ -122,13 +122,13 @@ void MoveOnlyChecker::checkObjects() {
122122
void MoveOnlyChecker::completeObjectLifetimes(
123123
ArrayRef<MarkUnresolvedNonCopyableValueInst *> insts) {
124124
// TODO: Delete once OSSALifetimeCompletion is run as part of SILGenCleanup.
125-
OSSALifetimeCompletion completion(fn, domTree);
125+
OSSALifetimeCompletion completion(fn, domTree, *deba->get(fn));
126126

127-
// Collect all values derived from each mark_unresolved_non_copyable_value
128-
// instruction via ownership instructions and phis.
129-
ValueWorklist transitiveValues(fn);
130-
for (auto *inst : insts) {
131-
transitiveValues.push(inst);
127+
// Collect all values derived from each mark_unresolved_non_copyable_value
128+
// instruction via ownership instructions and phis.
129+
ValueWorklist transitiveValues(fn);
130+
for (auto *inst : insts) {
131+
transitiveValues.push(inst);
132132
}
133133
while (auto value = transitiveValues.pop()) {
134134
for (auto *use : value->getUses()) {
@@ -203,8 +203,8 @@ void MoveOnlyChecker::checkAddresses() {
203203
return;
204204
}
205205

206-
MoveOnlyAddressChecker checker{fn, diagnosticEmitter, allocator, domTree,
207-
poa};
206+
MoveOnlyAddressChecker checker{
207+
fn, diagnosticEmitter, allocator, domTree, poa, deba};
208208
madeChange |= checker.completeLifetimes();
209209
madeChange |= checker.check(moveIntroducersToProcess);
210210
}
@@ -256,9 +256,9 @@ class MoveOnlyCheckerPass : public SILFunctionTransform {
256256
LLVM_DEBUG(llvm::dbgs()
257257
<< "===> MoveOnly Checker. Visiting: " << fn->getName() << '\n');
258258

259-
MoveOnlyChecker checker(
260-
fn, getAnalysis<DominanceAnalysis>()->get(fn),
261-
getAnalysis<PostOrderAnalysis>());
259+
MoveOnlyChecker checker(fn, getAnalysis<DominanceAnalysis>()->get(fn),
260+
getAnalysis<PostOrderAnalysis>(),
261+
getAnalysis<DeadEndBlocksAnalysis>());
262262

263263
checker.checkObjects();
264264
checker.checkAddresses();

lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2664,7 +2664,8 @@ bool AllocOptimize::tryToRemoveDeadAllocation() {
26642664
// post-dominating consuming use sets. This can happen if we have an enum that
26652665
// is known dynamically none along a path. This is dynamically correct, but
26662666
// can not be represented in OSSA so we insert these destroys along said path.
2667-
OSSALifetimeCompletion completion(TheMemory->getFunction(), domInfo);
2667+
OSSALifetimeCompletion completion(TheMemory->getFunction(), domInfo,
2668+
deadEndBlocks);
26682669

26692670
while (!valuesNeedingLifetimeCompletion.empty()) {
26702671
auto optV = valuesNeedingLifetimeCompletion.pop_back_val();

lib/SILOptimizer/Mandatory/SILGenCleanup.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/SIL/PrettyStackTrace.h"
2424
#include "swift/SIL/PrunedLiveness.h"
2525
#include "swift/SIL/SILInstruction.h"
26+
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
2627
#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
2728
#include "swift/SILOptimizer/PassManager/Transforms.h"
2829
#include "swift/SILOptimizer/Utils/CanonicalizeInstruction.h"
@@ -114,7 +115,8 @@ bool SILGenCleanup::completeOSSALifetimes(SILFunction *function) {
114115
// Lifetimes must be completed inside out (bottom-up in the CFG).
115116
PostOrderFunctionInfo *postOrder =
116117
getAnalysis<PostOrderAnalysis>()->get(function);
117-
OSSALifetimeCompletion completion(function, /*DomInfo*/nullptr);
118+
DeadEndBlocks *deb = getAnalysis<DeadEndBlocksAnalysis>()->get(function);
119+
OSSALifetimeCompletion completion(function, /*DomInfo*/ nullptr, *deb);
118120
for (auto *block : postOrder->getPostOrder()) {
119121
for (SILInstruction &inst : reverse(*block)) {
120122
for (auto result : inst.getResults()) {

0 commit comments

Comments
 (0)