Skip to content

Commit b3fd194

Browse files
Merge pull request swiftlang#76095 from nate-chandler/lifetime-completion/20240826/1
[LifetimeCompletion] Avoid instruction list walk.
2 parents ec09fa7 + 7600794 commit b3fd194

File tree

4 files changed

+164
-46
lines changed

4 files changed

+164
-46
lines changed

include/swift/AST/SILOptions.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,10 @@ class SILOptions {
188188
/// If set to true, compile with the SIL Opaque Values enabled.
189189
bool EnableSILOpaqueValues = false;
190190

191-
/// Require linear OSSA lifetimes after SILGen
192-
bool OSSACompleteLifetimes = false;
191+
/// Introduce linear OSSA lifetimes after SILGen
192+
bool OSSACompleteLifetimes = true;
193193

194-
/// Verify linear OSSA lifetimes after SILGen
194+
/// Verify linear OSSA lifetimes throughout OSSA pipeline.
195195
bool OSSAVerifyComplete = false;
196196

197197
/// Enable pack metadata stack "promotion".

include/swift/SIL/PrunedLiveness.h

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -543,10 +543,37 @@ class PrunedLiveness {
543543
RangeIterationHelpers::MapFunctor());
544544
}
545545

546+
void visitUsers(llvm::function_ref<void(SILInstruction *, LifetimeEnding)>
547+
visitor) const {
548+
for (auto &pair : users) {
549+
visitor(pair.first, pair.second);
550+
}
551+
}
552+
546553
void print(llvm::raw_ostream &OS) const;
547554
void dump() const;
548555
};
549556

557+
/// Recording liveness boundary at some level of detail; see concrete subclasses
558+
/// PrunedLivenessBoundary and PrunedLivenessBlockBoundary.
559+
struct AnyPrunedLivenessBoundary {
560+
virtual ~AnyPrunedLivenessBoundary() {}
561+
/// Targets whose single predecessor has at least one non-boundary successor.
562+
SmallVector<SILBasicBlock *, 8> boundaryEdges;
563+
564+
friend class SSAPrunedLiveness;
565+
friend class MultiDefPrunedLiveness;
566+
567+
private:
568+
virtual void findBoundaryInSSADefBlock(SILNode *ssaDef,
569+
const PrunedLiveness &liveness) = 0;
570+
virtual void
571+
findBoundaryInMultiDefBlock(SILBasicBlock *block, bool isLiveOut,
572+
const MultiDefPrunedLiveness &liveness) = 0;
573+
virtual void findBoundaryInNonDefBlock(SILBasicBlock *block,
574+
const PrunedLiveness &liveness) = 0;
575+
};
576+
550577
/// Record the last use points and CFG edges that form the boundary of
551578
/// PrunedLiveness.
552579
///
@@ -558,9 +585,8 @@ class PrunedLiveness {
558585
/// Each boundary edge is identified by its target block. The source of the edge
559586
/// is the target block's single predecessor which must have at least one other
560587
/// non-boundary successor.
561-
struct PrunedLivenessBoundary {
588+
struct PrunedLivenessBoundary : AnyPrunedLivenessBoundary {
562589
SmallVector<SILInstruction *, 8> lastUsers;
563-
SmallVector<SILBasicBlock *, 8> boundaryEdges;
564590
SmallVector<SILNode *, 1> deadDefs;
565591

566592
void clear() {
@@ -579,6 +605,39 @@ struct PrunedLivenessBoundary {
579605

580606
void print(llvm::raw_ostream &OS) const;
581607
void dump() const;
608+
609+
private:
610+
void findBoundaryInSSADefBlock(SILNode *ssaDef,
611+
const PrunedLiveness &liveness) override;
612+
void
613+
findBoundaryInMultiDefBlock(SILBasicBlock *block, bool isLiveOut,
614+
const MultiDefPrunedLiveness &liveness) override;
615+
void findBoundaryInNonDefBlock(SILBasicBlock *block,
616+
const PrunedLiveness &liveness) override;
617+
};
618+
619+
/// Record the blocks which either contain last use points or are boundary edge
620+
/// targets.
621+
///
622+
/// Enables clients only interested in block-level details to avoid expensive
623+
/// and for-them wasteful instruction list iteration.
624+
struct PrunedLivenessBlockBoundary : AnyPrunedLivenessBoundary {
625+
/// Blocks containing last users or dead defs.
626+
SmallVector<SILBasicBlock *, 8> endBlocks;
627+
628+
void clear() {
629+
endBlocks.clear();
630+
boundaryEdges.clear();
631+
}
632+
633+
private:
634+
void findBoundaryInSSADefBlock(SILNode *ssaDef,
635+
const PrunedLiveness &liveness) override;
636+
void
637+
findBoundaryInMultiDefBlock(SILBasicBlock *block, bool isLiveOut,
638+
const MultiDefPrunedLiveness &liveness) override;
639+
void findBoundaryInNonDefBlock(SILBasicBlock *block,
640+
const PrunedLiveness &liveness) override;
582641
};
583642

584643
/// PrunedLiveness with information about defs for computing the live range
@@ -689,7 +748,7 @@ class PrunedLiveRange : public PrunedLiveness {
689748
/// The computed boundary will completely post-dominate, including dead end
690749
/// paths. The client should query DeadEndBlocks to ignore those dead end
691750
/// paths.
692-
void computeBoundary(PrunedLivenessBoundary &boundary) const;
751+
void computeBoundary(AnyPrunedLivenessBoundary &boundary) const;
693752

694753
/// Compute the boundary from a backward CFG traversal from a known set of
695754
/// jointly post-dominating blocks. Avoids the need to record an ordered list
@@ -765,7 +824,7 @@ class SSAPrunedLiveness : public PrunedLiveRange<SSAPrunedLiveness> {
765824

766825
/// SSA implementation of computeBoundary.
767826
void findBoundariesInBlock(SILBasicBlock *block, bool isLiveOut,
768-
PrunedLivenessBoundary &boundary) const;
827+
AnyPrunedLivenessBoundary &boundary) const;
769828

770829
/// Compute liveness for a single SSA definition. The lifetime-ending uses are
771830
/// also recorded--destroy_value or end_borrow.
@@ -853,9 +912,9 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
853912

854913
/// Multi-Def implementation of computeBoundary.
855914
void findBoundariesInBlock(SILBasicBlock *block, bool isLiveOut,
856-
PrunedLivenessBoundary &boundary) const;
915+
AnyPrunedLivenessBoundary &boundary) const;
857916

858-
/// Compute liveness for a all currently initialized definitions. The
917+
/// Compute liveness for all currently initialized definitions. The
859918
/// lifetime-ending uses are also recorded--destroy_value or
860919
/// end_borrow. However destroy_values might not jointly-post dominate if
861920
/// dead-end blocks are present.
@@ -872,6 +931,9 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
872931
/// also lack scope-ending instructions, so the liveness of their nested uses
873932
/// may be ignored.
874933
LiveRangeSummary computeSimple();
934+
935+
friend struct PrunedLivenessBoundary;
936+
friend struct PrunedLivenessBlockBoundary;
875937
};
876938

877939
//===----------------------------------------------------------------------===//

lib/SIL/Utils/OSSALifetimeCompletion.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,18 @@ void AvailabilityBoundaryVisitor::visit(const SSAPrunedLiveness &liveness,
262262
void AvailabilityBoundaryVisitor::computeRegion(
263263
const SSAPrunedLiveness &liveness) {
264264
// (1) Compute the complete liveness boundary.
265-
PrunedLivenessBoundary boundary;
265+
PrunedLivenessBlockBoundary boundary;
266266
liveness.computeBoundary(boundary);
267267

268+
BasicBlockSet consumingBlocks(value->getFunction());
269+
270+
liveness.visitUsers(
271+
[&consumingBlocks](auto *instruction, auto lifetimeEnding) {
272+
if (lifetimeEnding.isEnding()) {
273+
consumingBlocks.insert(instruction->getParent());
274+
}
275+
});
276+
268277
// Used in the forward walk below (3).
269278
BasicBlockWorklist regionWorklist(value->getFunction());
270279

@@ -284,18 +293,14 @@ void AvailabilityBoundaryVisitor::computeRegion(
284293
regionWorklist.push(block);
285294
};
286295

287-
for (SILInstruction *lastUser : boundary.lastUsers) {
288-
if (liveness.isInterestingUser(lastUser)
289-
!= PrunedLiveness::LifetimeEndingUse) {
290-
collect(lastUser->getParent());
296+
for (auto *endBlock : boundary.endBlocks) {
297+
if (!consumingBlocks.contains(endBlock)) {
298+
collect(endBlock);
291299
}
292300
}
293301
for (SILBasicBlock *edge : boundary.boundaryEdges) {
294302
collect(edge);
295303
}
296-
for (SILNode *deadDef : boundary.deadDefs) {
297-
collect(deadDef->getParentBlock());
298-
}
299304

300305
// (3) Forward walk to find the region in which `value` might be available.
301306
while (auto *block = regionWorklist.pop()) {

0 commit comments

Comments
 (0)