Skip to content

Commit 5938a67

Browse files
authored
Merge pull request #35477 from gottesmm/pr-09967e42af2f24bfb4d3114846f057222407cff4
[ownership] Add a DeadEndBlocksAnalysis that vends/saves DeadEndBlocks in between passes.
2 parents 0844b72 + 4a71042 commit 5938a67

File tree

9 files changed

+139
-26
lines changed

9 files changed

+139
-26
lines changed

include/swift/SIL/BasicBlockUtils.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,26 +62,31 @@ void mergeBasicBlockWithSingleSuccessor(SILBasicBlock *BB,
6262
/// This utility is needed to determine if the a value definition can have a
6363
/// lack of users ignored along a specific path.
6464
class DeadEndBlocks {
65-
llvm::SetVector<const SILBasicBlock *> ReachableBlocks;
66-
const SILFunction *F;
67-
bool isComputed = false;
65+
llvm::SetVector<const SILBasicBlock *> reachableBlocks;
66+
const SILFunction *f;
67+
bool didComputeValue = false;
6868

6969
void compute();
7070

7171
public:
72-
DeadEndBlocks(const SILFunction *F) : F(F) {}
72+
DeadEndBlocks(const SILFunction *f) : f(f) {}
7373

7474
/// Returns true if \p BB is a dead-end block.
7575
bool isDeadEnd(const SILBasicBlock *block) {
76-
if (!isComputed) {
76+
if (!didComputeValue) {
7777
// Lazily compute the dataflow.
7878
compute();
79-
isComputed = true;
79+
didComputeValue = true;
8080
}
81-
return ReachableBlocks.count(block) == 0;
81+
return reachableBlocks.count(block) == 0;
8282
}
8383

84-
const SILFunction *getFunction() const { return F; }
84+
/// Return true if this dead end blocks has computed its internal cache yet.
85+
///
86+
/// Used to determine if we need to verify a DeadEndBlocks.
87+
bool isComputed() const { return didComputeValue; }
88+
89+
const SILFunction *getFunction() const { return f; }
8590
};
8691

8792
/// A struct that contains the intermediate state used in computing

include/swift/SILOptimizer/Analysis/Analysis.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,6 @@ ANALYSIS(RCIdentity)
4747
ANALYSIS(SideEffect)
4848
ANALYSIS(TypeExpansion)
4949
ANALYSIS(PassManagerVerifier)
50+
ANALYSIS(DeadEndBlocks)
5051

5152
#undef ANALYSIS
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===--- DeadEndBlocksAnalysis.h ------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 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+
#ifndef SWIFT_SILOPTIMIZER_DEADENDBLOCKSANALYSIS_H
14+
#define SWIFT_SILOPTIMIZER_DEADENDBLOCKSANALYSIS_H
15+
16+
#include "swift/SIL/BasicBlockUtils.h"
17+
#include "swift/SILOptimizer/Analysis/Analysis.h"
18+
19+
namespace swift {
20+
21+
class DeadEndBlocksAnalysis final : public FunctionAnalysisBase<DeadEndBlocks> {
22+
public:
23+
DeadEndBlocksAnalysis()
24+
: FunctionAnalysisBase<DeadEndBlocks>(SILAnalysisKind::DeadEndBlocks) {}
25+
26+
DeadEndBlocksAnalysis(const DeadEndBlocksAnalysis &) = delete;
27+
DeadEndBlocksAnalysis &operator=(const DeadEndBlocksAnalysis &) = delete;
28+
29+
static bool classof(const SILAnalysis *s) {
30+
return s->getKind() == SILAnalysisKind::DeadEndBlocks;
31+
}
32+
33+
std::unique_ptr<DeadEndBlocks> newFunctionAnalysis(SILFunction *f) override {
34+
return std::make_unique<DeadEndBlocks>(f);
35+
}
36+
37+
bool shouldInvalidate(SILAnalysis::InvalidationKind k) override {
38+
return k & InvalidationKind::Branches;
39+
}
40+
41+
protected:
42+
void verify(DeadEndBlocks *deBlocks) const override;
43+
};
44+
45+
} // namespace swift
46+
47+
#endif

lib/SIL/Utils/BasicBlockUtils.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -363,22 +363,22 @@ void swift::mergeBasicBlockWithSingleSuccessor(SILBasicBlock *BB,
363363
//===----------------------------------------------------------------------===//
364364

365365
void DeadEndBlocks::compute() {
366-
assert(ReachableBlocks.empty() && "Computed twice");
366+
assert(reachableBlocks.empty() && "Computed twice");
367367

368368
// First step: find blocks which end up in a no-return block (terminated by
369369
// an unreachable instruction).
370370
// Search for function-exiting blocks, i.e. return and throw.
371-
for (const SILBasicBlock &BB : *F) {
371+
for (const SILBasicBlock &BB : *f) {
372372
const TermInst *TI = BB.getTerminator();
373373
if (TI->isFunctionExiting())
374-
ReachableBlocks.insert(&BB);
374+
reachableBlocks.insert(&BB);
375375
}
376376
// Propagate the reachability up the control flow graph.
377377
unsigned Idx = 0;
378-
while (Idx < ReachableBlocks.size()) {
379-
const SILBasicBlock *BB = ReachableBlocks[Idx++];
378+
while (Idx < reachableBlocks.size()) {
379+
const SILBasicBlock *BB = reachableBlocks[Idx++];
380380
for (SILBasicBlock *Pred : BB->getPredecessorBlocks())
381-
ReachableBlocks.insert(Pred);
381+
reachableBlocks.insert(Pred);
382382
}
383383
}
384384

lib/SILOptimizer/Analysis/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ target_sources(swiftSILOptimizer PRIVATE
1010
ClassHierarchyAnalysis.cpp
1111
ClosureScope.cpp
1212
ColdBlockInfo.cpp
13-
DifferentiableActivityAnalysis.cpp
13+
DeadEndBlocksAnalysis.cpp
1414
DestructorAnalysis.cpp
15+
DifferentiableActivityAnalysis.cpp
1516
EscapeAnalysis.cpp
1617
EpilogueARCAnalysis.cpp
1718
FunctionOrder.cpp
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===--- DeadEndBlocksAnalysis.cpp ----------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 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/DeadEndBlocksAnalysis.h"
14+
#include "swift/AST/Decl.h"
15+
#include "swift/SIL/SILFunction.h"
16+
17+
using namespace swift;
18+
19+
void DeadEndBlocksAnalysis::verify(DeadEndBlocks *deBlocks) const {
20+
// If the passed in deBlocks has not computed, there is nothing to check.
21+
if (!deBlocks->isComputed())
22+
return;
23+
24+
// Then create our new dead end blocks instance so we can check the internal
25+
// state of our input against it.
26+
auto *fn = deBlocks->getFunction();
27+
DeadEndBlocks newBlocks(fn);
28+
29+
// Make sure that all values that deBlocks thinks is unreachable are
30+
// actually unreachable.
31+
//
32+
// NOTE: We verify like this b/c DeadEndBlocks looks up state lazily so we
33+
// can only check the work we have done so far.
34+
for (auto &block : *fn) {
35+
if (deBlocks->isDeadEnd(&block)) {
36+
if (!newBlocks.isDeadEnd(&block)) {
37+
llvm::errs() << "DeadEndBlocksAnalysis Error! Found dead end block "
38+
"that is no longer a dead end block?!";
39+
llvm_unreachable("standard error assertion");
40+
}
41+
} else {
42+
if (newBlocks.isDeadEnd(&block)) {
43+
llvm::errs() << "DeadEndBlocksAnalysis Error! Found reachable block "
44+
"that is no longer reachable?!";
45+
llvm_unreachable("standard error assertion");
46+
}
47+
}
48+
}
49+
}
50+
51+
//===----------------------------------------------------------------------===//
52+
// Main Entry Point
53+
//===----------------------------------------------------------------------===//
54+
55+
SILAnalysis *swift::createDeadEndBlocksAnalysis(SILModule *) {
56+
return new DeadEndBlocksAnalysis();
57+
}

lib/SILOptimizer/SemanticARC/Context.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace semanticarc {
3232
struct LLVM_LIBRARY_VISIBILITY Context {
3333
SILFunction &fn;
3434
ARCTransformKind transformKind = ARCTransformKind::All;
35-
Optional<DeadEndBlocks> deadEndBlocks;
35+
DeadEndBlocks &deadEndBlocks;
3636
ValueLifetimeAnalysis::Frontier lifetimeFrontier;
3737
SmallMultiMapCache<SILValue, Operand *> addressToExhaustiveWriteListCache;
3838

@@ -117,14 +117,11 @@ struct LLVM_LIBRARY_VISIBILITY Context {
117117
using FrozenMultiMapRange =
118118
decltype(joinedOwnedIntroducerToConsumedOperands)::PairToSecondEltRange;
119119

120-
DeadEndBlocks &getDeadEndBlocks() {
121-
if (!deadEndBlocks)
122-
deadEndBlocks.emplace(&fn);
123-
return *deadEndBlocks;
124-
}
120+
DeadEndBlocks &getDeadEndBlocks() { return deadEndBlocks; }
125121

126-
Context(SILFunction &fn, bool onlyGuaranteedOpts, InstModCallbacks callbacks)
127-
: fn(fn), deadEndBlocks(), lifetimeFrontier(),
122+
Context(SILFunction &fn, DeadEndBlocks &deBlocks, bool onlyGuaranteedOpts,
123+
InstModCallbacks callbacks)
124+
: fn(fn), deadEndBlocks(deBlocks), lifetimeFrontier(),
128125
addressToExhaustiveWriteListCache(constructCacheValue),
129126
onlyGuaranteedOpts(onlyGuaranteedOpts), instModCallbacks(callbacks) {}
130127

lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ struct LLVM_LIBRARY_VISIBILITY SemanticARCOptVisitor
4949

5050
Context ctx;
5151

52-
explicit SemanticARCOptVisitor(SILFunction &fn, bool onlyGuaranteedOpts)
53-
: ctx(fn, onlyGuaranteedOpts,
52+
explicit SemanticARCOptVisitor(SILFunction &fn, DeadEndBlocks &deBlocks,
53+
bool onlyGuaranteedOpts)
54+
: ctx(fn, deBlocks, onlyGuaranteedOpts,
5455
InstModCallbacks(
5556
[this](SILInstruction *inst) { eraseInstruction(inst); },
5657
[this](Operand *use, SILValue newValue) {

lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include "Transforms.h"
1818

1919
#include "swift/Basic/Defer.h"
20+
#include "swift/SILOptimizer/Analysis/Analysis.h"
21+
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
2022
#include "swift/SILOptimizer/PassManager/Transforms.h"
2123

2224
#include "llvm/Support/CommandLine.h"
@@ -149,7 +151,9 @@ struct SemanticARCOpts : SILFunctionTransform {
149151
"Can not perform semantic arc optimization unless ownership "
150152
"verification is enabled");
151153

152-
SemanticARCOptVisitor visitor(f, guaranteedOptsOnly);
154+
auto *deBlocksAnalysis = getAnalysis<DeadEndBlocksAnalysis>();
155+
SemanticARCOptVisitor visitor(f, *deBlocksAnalysis->get(&f),
156+
guaranteedOptsOnly);
153157

154158
#ifndef NDEBUG
155159
// If we are being asked for testing purposes to run a series of transforms

0 commit comments

Comments
 (0)