Skip to content

Commit c0d7a82

Browse files
Merge pull request #63606 from nate-chandler/canonicalize_ossa_lifetime/lexical_values
[CanonicalizeOSSALifetime] Run on lexical lifetimes.
2 parents c31f6fa + ec3f005 commit c0d7a82

21 files changed

+421
-107
lines changed

include/swift/SILOptimizer/Analysis/Reachability.h

Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ class IterativeBackwardReachability final {
243243
BasicBlockSet unknownEndBlocks;
244244

245245
public:
246-
/// The blocks found between the gens and the defBlock into which
246+
/// The blocks found between the gens and the initialBlocks into which
247247
/// reachability may extend.
248248
BasicBlockSetVector discoveredBlocks;
249249
/// The sublist of gens which are killed within the blocks where they occur.
@@ -296,15 +296,32 @@ class IterativeBackwardReachability final {
296296
};
297297

298298
/// Construct a dataflow for the specified function to run from the gens
299-
/// provided by \p effects to the specified def block. So that the result
300-
/// structure can be owned by the caller, it is taken by reference here.
299+
/// provided by \p effects to the specified \p initialBlocks. So that the
300+
/// result structure can be owned by the caller, it is taken by reference
301+
/// here.
301302
///
302-
/// If a nullptr defBlock is specified, the dataflow may run up to the begin
303-
/// of the function.
304-
IterativeBackwardReachability(SILFunction *function, SILBasicBlock *defBlock,
303+
/// If \p initialBlocks is empty, the dataflow may run up to the begin of the
304+
/// function.
305+
IterativeBackwardReachability(SILFunction *function,
306+
ArrayRef<SILBasicBlock *> initialBlocks,
305307
Effects &effects, Result &result)
306-
: function(function), defBlock(defBlock), effects(effects),
307-
result(result), dataflowWorklist(function) {}
308+
: function(function), initialBlocks(function), effects(effects),
309+
result(result), dataflowWorklist(function) {
310+
for (auto *block : initialBlocks) {
311+
this->initialBlocks.insert(block);
312+
}
313+
}
314+
315+
/// Convenience constructor to pass a single initial block.
316+
static IterativeBackwardReachability
317+
untilInitialBlock(SILFunction *function, SILBasicBlock *initialBlock,
318+
Effects &effects, Result &result) {
319+
using InitialBlocks = ArrayRef<SILBasicBlock *>;
320+
InitialBlocks initialBlocks =
321+
initialBlock ? InitialBlocks(initialBlock) : InitialBlocks();
322+
return IterativeBackwardReachability(function, initialBlocks, effects,
323+
result);
324+
}
308325

309326
/// Step 1: Prepare to run the global dataflow: discover and summarize the
310327
/// blocks in the relevant region.
@@ -358,9 +375,8 @@ class IterativeBackwardReachability final {
358375

359376
/// The function in which the dataflow will run.
360377
SILFunction *function;
361-
/// The block containing the def for the value--the dataflow will not
362-
/// propagate beyond this block.
363-
SILBasicBlock *defBlock;
378+
/// The blocks beyond which the dataflow will not propagate.
379+
BasicBlockSet initialBlocks;
364380

365381
/// Input to the dataflow.
366382
Effects &effects;
@@ -375,9 +391,9 @@ class IterativeBackwardReachability final {
375391
/// Current activity of the dataflow.
376392
Stage stage = Stage::Unstarted;
377393

378-
/// Whether the def effectively occurs within the specified block.
379-
bool isEffectiveDefBlock(SILBasicBlock *block) {
380-
return defBlock ? block == defBlock : block == &*function->begin();
394+
/// Whether dataflow continues beyond this block.
395+
bool stopAtBlock(SILBasicBlock *block) {
396+
return initialBlocks.contains(block) || &*function->begin() == block;
381397
}
382398

383399
/// Form the meet of the end state of the provided predecessor with the begin
@@ -424,8 +440,8 @@ class IterativeBackwardReachability final {
424440
/// effect of each block for use by the dataflow.
425441
///
426442
/// Starting from the gens, find all blocks which might be reached up to and
427-
/// including the defBlock. Summarize the effects of these blocks along the
428-
/// way.
443+
/// including the initialBlocks. Summarize the effects of these blocks along
444+
/// the way.
429445
template <typename Effects>
430446
void IterativeBackwardReachability<Effects>::initialize() {
431447
assert(stage == Stage::Unstarted);
@@ -454,9 +470,9 @@ void IterativeBackwardReachability<Effects>::initialize() {
454470
// adjacent successors.
455471
continue;
456472
}
457-
if (isEffectiveDefBlock(block)) {
458-
// If this block is the effective def block, dataflow mustn't propagate
459-
// a reachable state through this block to its predecessors.
473+
if (stopAtBlock(block)) {
474+
// If dataflow is to stop at this block, it mustn't propagate a reachable
475+
// state through this block to its predecessors.
460476
continue;
461477
}
462478
for (auto *predecessor : block->getPredecessorBlocks())
@@ -631,9 +647,9 @@ void IterativeBackwardReachability<Effects>::solve() {
631647
template <typename Effects>
632648
void IterativeBackwardReachability<Effects>::propagateIntoPredecessors(
633649
SILBasicBlock *successor) {
634-
// State isn't tracked above the def block. Don't propagate state changes
635-
// into its predecessors.
636-
if (isEffectiveDefBlock(successor))
650+
// State isn't tracked above the blocks dataflow stops at. Don't propagate
651+
// state changes into its predecessors.
652+
if (stopAtBlock(successor))
637653
return;
638654
assert(result.getBeginStateForBlock(successor) == State::Unreachable() &&
639655
"propagating unreachability into predecessors of block whose begin is "
@@ -761,7 +777,6 @@ bool IterativeBackwardReachability<Effects>::findBarrier(SILInstruction *from,
761777
if (!effect)
762778
continue;
763779
if (effect == Effect::Gen()) {
764-
assert(false && "found gen (before kill) in reachable block");
765780
continue;
766781
}
767782
// effect == Effect::Kill
@@ -777,7 +792,7 @@ bool IterativeBackwardReachability<Effects>::findBarrier(SILInstruction *from,
777792
}
778793
}
779794
assert(result.getEffectForBlock(block) != Effect::Kill());
780-
if (isEffectiveDefBlock(block)) {
795+
if (stopAtBlock(block)) {
781796
visitor.visitBarrierBlock(block);
782797
return true;
783798
}
@@ -888,6 +903,41 @@ void IterativeBackwardReachability<Effects>::Result::setEffectForBlock(
888903
}
889904
}
890905

906+
//===----------------------------------------------------------------------===//
907+
// MARK: findBarriersBackward
908+
//===----------------------------------------------------------------------===//
909+
910+
using llvm::ArrayRef;
911+
using llvm::function_ref;
912+
913+
struct ReachableBarriers final {
914+
/// Instructions which are barriers.
915+
llvm::SmallVector<SILInstruction *, 4> instructions;
916+
917+
/// Blocks one of whose phis is a barrier.
918+
llvm::SmallVector<SILBasicBlock *, 4> phis;
919+
920+
/// Boundary edges; edges such that
921+
/// (1) the target block is reachable-at-begin
922+
/// (2) at least one adjacent edge's target is not reachable-at-begin.
923+
llvm::SmallVector<SILBasicBlock *, 4> edges;
924+
925+
ReachableBarriers() {}
926+
ReachableBarriers(ReachableBarriers const &) = delete;
927+
ReachableBarriers &operator=(ReachableBarriers const &) = delete;
928+
};
929+
930+
/// Walk backwards from the specified \p roots through at the earliest \p
931+
/// initialBlocks to populate \p barriers by querying \p isBarrier along the
932+
/// way.
933+
///
934+
/// If \p initialBlocks is empty, dataflow continues to the begin of the
935+
/// function.
936+
void findBarriersBackward(ArrayRef<SILInstruction *> roots,
937+
ArrayRef<SILBasicBlock *> initialBlocks,
938+
SILFunction &function, ReachableBarriers &barriers,
939+
function_ref<bool(SILInstruction *)> isBarrier);
940+
891941
} // end namespace swift
892942

893943
#endif

include/swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@
109109

110110
namespace swift {
111111

112+
class BasicCalleeAnalysis;
113+
112114
extern llvm::Statistic NumCopiesAndMovesEliminated;
113115
extern llvm::Statistic NumCopiesGenerated;
114116

@@ -225,6 +227,8 @@ class CanonicalizeOSSALifetime final {
225227

226228
DominanceInfo *domTree = nullptr;
227229

230+
BasicCalleeAnalysis *calleeAnalysis;
231+
228232
InstructionDeleter &deleter;
229233

230234
/// The SILValue to canonicalize.
@@ -296,10 +300,12 @@ class CanonicalizeOSSALifetime final {
296300
CanonicalizeOSSALifetime(bool pruneDebugMode, bool maximizeLifetime,
297301
SILFunction *function,
298302
NonLocalAccessBlockAnalysis *accessBlockAnalysis,
299-
DominanceInfo *domTree, InstructionDeleter &deleter)
303+
DominanceInfo *domTree,
304+
BasicCalleeAnalysis *calleeAnalysis,
305+
InstructionDeleter &deleter)
300306
: pruneDebugMode(pruneDebugMode), maximizeLifetime(maximizeLifetime),
301307
accessBlockAnalysis(accessBlockAnalysis), domTree(domTree),
302-
deleter(deleter) {}
308+
calleeAnalysis(calleeAnalysis), deleter(deleter) {}
303309

304310
SILValue getCurrentDef() const { return currentDef; }
305311

@@ -405,6 +411,9 @@ class CanonicalizeOSSALifetime final {
405411
void findExtendedBoundary(PrunedLivenessBoundary const &originalBoundary,
406412
PrunedLivenessBoundary &boundary);
407413

414+
void findDestroysOutsideBoundary(SmallVectorImpl<SILInstruction *> &destroys);
415+
void extendLivenessToDeinitBarriers();
416+
408417
void extendUnconsumedLiveness(PrunedLivenessBoundary const &boundary);
409418

410419
void insertDestroysOnBoundary(PrunedLivenessBoundary const &boundary);

lib/SILOptimizer/Analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ target_sources(swiftSILOptimizer PRIVATE
2222
NonLocalAccessBlockAnalysis.cpp
2323
PassManagerVerifierAnalysis.cpp
2424
ProtocolConformanceAnalysis.cpp
25+
Reachability.cpp
2526
RCIdentityAnalysis.cpp
2627
SimplifyInstruction.cpp
2728
TypeExpansionAnalysis.cpp
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//=----------- Reachability.cpp - Walking from roots to barriers. -----------=//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/SILOptimizer/Analysis/Reachability.h"
14+
15+
using namespace swift;
16+
17+
/// Walks backwards from the specified roots to find barrier instructions, phis,
18+
/// and blocks via the isBarrier predicate.
19+
///
20+
/// Implements IterativeBackwardReachability::Effects
21+
/// Implements IterativeBackwardReachability::findBarriers::Visitor
22+
class FindBarriersBackwardDataflow final {
23+
using Reachability =
24+
IterativeBackwardReachability<FindBarriersBackwardDataflow>;
25+
using Effect = Reachability::Effect;
26+
ArrayRef<SILInstruction *> const roots;
27+
function_ref<bool(SILInstruction *)> isBarrier;
28+
ReachableBarriers &barriers;
29+
Reachability::Result result;
30+
Reachability reachability;
31+
32+
public:
33+
FindBarriersBackwardDataflow(SILFunction &function,
34+
ArrayRef<SILInstruction *> roots,
35+
ArrayRef<SILBasicBlock *> stopBlocks,
36+
ReachableBarriers &barriers,
37+
function_ref<bool(SILInstruction *)> isBarrier)
38+
: roots(roots), isBarrier(isBarrier), barriers(barriers),
39+
result(&function), reachability(&function, stopBlocks, *this, result) {}
40+
FindBarriersBackwardDataflow(FindBarriersBackwardDataflow const &) = delete;
41+
FindBarriersBackwardDataflow &
42+
operator=(FindBarriersBackwardDataflow const &) = delete;
43+
44+
void run();
45+
46+
private:
47+
friend Reachability;
48+
49+
/// IterativeBackwardReachability::Effects
50+
51+
auto gens() { return roots; }
52+
53+
Effect effectForInstruction(SILInstruction *);
54+
Effect effectForPhi(SILBasicBlock *);
55+
56+
auto localGens() { return result.localGens; }
57+
58+
bool isLocalGen(SILInstruction *instruction) {
59+
return result.localGens.contains(instruction);
60+
}
61+
62+
/// IterativeBackwardReachability::findBarriers::Visitor
63+
64+
void visitBarrierInstruction(SILInstruction *instruction) {
65+
barriers.instructions.push_back(instruction);
66+
}
67+
68+
void visitBarrierPhi(SILBasicBlock *block) { barriers.phis.push_back(block); }
69+
70+
void visitBarrierBlock(SILBasicBlock *block) {
71+
barriers.edges.push_back(block);
72+
}
73+
};
74+
75+
FindBarriersBackwardDataflow::Effect
76+
FindBarriersBackwardDataflow::effectForInstruction(
77+
SILInstruction *instruction) {
78+
if (llvm::is_contained(roots, instruction))
79+
return Effect::Gen();
80+
auto barrier = isBarrier(instruction);
81+
return barrier ? Effect::Kill() : Effect::NoEffect();
82+
}
83+
84+
FindBarriersBackwardDataflow::Effect
85+
FindBarriersBackwardDataflow::effectForPhi(SILBasicBlock *block) {
86+
assert(llvm::all_of(block->getArguments(),
87+
[&](auto argument) { return PhiValue(argument); }));
88+
89+
bool barrier =
90+
llvm::any_of(block->getPredecessorBlocks(), [&](auto *predecessor) {
91+
return isBarrier(predecessor->getTerminator());
92+
});
93+
return barrier ? Effect::Kill() : Effect::NoEffect();
94+
}
95+
96+
void FindBarriersBackwardDataflow::run() {
97+
reachability.initialize();
98+
reachability.solve();
99+
reachability.findBarriers(*this);
100+
}
101+
102+
void swift::findBarriersBackward(
103+
ArrayRef<SILInstruction *> roots, ArrayRef<SILBasicBlock *> initialBlocks,
104+
SILFunction &function, ReachableBarriers &barriers,
105+
function_ref<bool(SILInstruction *)> isBarrier) {
106+
FindBarriersBackwardDataflow flow(function, roots, initialBlocks, barriers,
107+
isBarrier);
108+
flow.run();
109+
}

lib/SILOptimizer/Mandatory/MoveOnlyObjectCheckerUtils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ struct OSSACanonicalizer {
5050
InstructionDeleter &deleter)
5151
: canonicalizer(false /*pruneDebugMode*/,
5252
!fn->shouldOptimize() /*maximizeLifetime*/, fn,
53-
nullptr /*accessBlockAnalysis*/, domTree, deleter) {}
53+
nullptr /*accessBlockAnalysis*/, domTree,
54+
nullptr /*calleeAnalysis*/, deleter) {}
5455

5556
void clear() {
5657
consumingUsesNeedingCopy.clear();

lib/SILOptimizer/SILCombiner/SILCombine.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ SILCombiner::SILCombiner(SILFunctionTransform *trans,
165165
bool removeCondFails, bool enableCopyPropagation) :
166166
parentTransform(trans),
167167
AA(trans->getPassManager()->getAnalysis<AliasAnalysis>(trans->getFunction())),
168+
CA(trans->getPassManager()->getAnalysis<BasicCalleeAnalysis>()),
168169
DA(trans->getPassManager()->getAnalysis<DominanceAnalysis>()),
169170
PCA(trans->getPassManager()->getAnalysis<ProtocolConformanceAnalysis>()),
170171
CHA(trans->getPassManager()->getAnalysis<ClassHierarchyAnalysis>()),
@@ -352,7 +353,7 @@ void SILCombiner::canonicalizeOSSALifetimes(SILInstruction *currentInst) {
352353
CanonicalizeOSSALifetime canonicalizer(
353354
false /*prune debug*/,
354355
!parentTransform->getFunction()->shouldOptimize() /*maximize lifetime*/,
355-
parentTransform->getFunction(), NLABA, domTree, deleter);
356+
parentTransform->getFunction(), NLABA, domTree, CA, deleter);
356357
CanonicalizeBorrowScope borrowCanonicalizer(parentTransform->getFunction(),
357358
deleter);
358359

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,22 @@
2323

2424
#include "swift/Basic/Defer.h"
2525
#include "swift/SIL/BasicBlockUtils.h"
26+
#include "swift/SIL/InstructionUtils.h"
2627
#include "swift/SIL/SILBuilder.h"
2728
#include "swift/SIL/SILInstruction.h"
2829
#include "swift/SIL/SILInstructionWorklist.h"
2930
#include "swift/SIL/SILValue.h"
3031
#include "swift/SIL/SILVisitor.h"
31-
#include "swift/SIL/InstructionUtils.h"
32+
#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
3233
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
3334
#include "swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h"
3435
#include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h"
3536
#include "swift/SILOptimizer/OptimizerBridging.h"
37+
#include "swift/SILOptimizer/PassManager/PassManager.h"
3638
#include "swift/SILOptimizer/Utils/CastOptimizer.h"
3739
#include "swift/SILOptimizer/Utils/Existential.h"
3840
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
3941
#include "swift/SILOptimizer/Utils/OwnershipOptUtils.h"
40-
#include "swift/SILOptimizer/PassManager/PassManager.h"
4142

4243
#include "llvm/ADT/DenseMap.h"
4344
#include "llvm/ADT/SmallVector.h"
@@ -55,6 +56,8 @@ class SILCombiner :
5556

5657
AliasAnalysis *AA;
5758

59+
BasicCalleeAnalysis *CA;
60+
5861
DominanceAnalysis *DA;
5962

6063
/// Determine the set of types a protocol conforms to in whole-module

0 commit comments

Comments
 (0)