Skip to content

Commit 8fd1de0

Browse files
committed
[SILOptimizer] Added findDeinitBarriers.
1 parent ddf0936 commit 8fd1de0

File tree

2 files changed

+206
-0
lines changed

2 files changed

+206
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===- DeinitBarrierFinding.h - Find deinit barriers from roots -*- C++ -*-===//
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+
// Given a set of roots, find the deinit barriers that exist between it and the
13+
// those instructions which the client says are already barriers (think users).
14+
//===----------------------------------------------------------------------===//
15+
#include "llvm/ADT/STLFunctionalExtras.h"
16+
#include "llvm/ADT/SetVector.h"
17+
#include "llvm/ADT/SmallPtrSet.h"
18+
#include "llvm/ADT/SmallVector.h"
19+
20+
namespace swift {
21+
22+
class SILBasicBlock;
23+
class SILFunction;
24+
class SILInstruction;
25+
class BasicCalleeAnalysis;
26+
27+
using llvm::ArrayRef;
28+
using llvm::function_ref;
29+
30+
namespace DeinitBarrierFinding {
31+
/// How destroy_value hoisting is obstructed.
32+
struct Barriers final {
33+
/// Instructions which are deinit barriers.
34+
llvm::SmallVector<SILInstruction *, 4> instructions;
35+
36+
/// Blocks one of whose phis is a deinit barrier.
37+
llvm::SmallVector<SILBasicBlock *, 4> phis;
38+
39+
llvm::SmallVector<SILBasicBlock *, 4> blocks;
40+
41+
Barriers() {}
42+
Barriers(Barriers const &) = delete;
43+
Barriers &operator=(Barriers const &) = delete;
44+
};
45+
46+
} // namespace DeinitBarrierFinding
47+
48+
void findDeinitBarriersAboveInstructions(
49+
ArrayRef<SILInstruction *> roots, SILBasicBlock *defBlock,
50+
SILFunction &function, BasicCalleeAnalysis *calleeAnalysis,
51+
DeinitBarrierFinding::Barriers &barriers,
52+
function_ref<bool(SILInstruction *)> isBarrier);
53+
} // namespace swift
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
//=-- DeinitBarrierFinding.cpp - Find deinit barriers above instructions. ---=//
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+
/// Given a list of instructions, find the deinit barriers that are above them.
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "swift/SILOptimizer/Utils/DeinitBarrierFinding.h"
16+
#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
17+
#include "swift/SILOptimizer/Analysis/Reachability.h"
18+
19+
using namespace swift;
20+
using namespace DeinitBarrierFinding;
21+
22+
namespace {
23+
24+
struct Context final {
25+
SILFunction &function;
26+
BasicCalleeAnalysis *calleeAnalysis;
27+
SILBasicBlock *defBlock;
28+
ArrayRef<SILInstruction *> roots;
29+
};
30+
31+
/// Works backwards from the current location of destroy_values to the earliest
32+
/// place they can be hoisted to.
33+
///
34+
/// Implements IterativeBackwardReachability::Effects
35+
/// Implements IterativeBackwardReachability::bindBarriers::Visitor
36+
class Dataflow final {
37+
using Reachability = IterativeBackwardReachability<Dataflow>;
38+
using Effect = Reachability::Effect;
39+
Context const &context;
40+
function_ref<bool(SILInstruction *)> isBarrier;
41+
Barriers &barriers;
42+
Reachability::Result result;
43+
Reachability reachability;
44+
45+
enum class Classification { Barrier, Other };
46+
47+
public:
48+
Dataflow(Context const &context, Barriers &barriers,
49+
function_ref<bool(SILInstruction *)> isBarrier)
50+
: context(context), isBarrier(isBarrier), barriers(barriers),
51+
result(&context.function),
52+
reachability(&context.function, nullptr, *this, result) {}
53+
Dataflow(Dataflow const &) = delete;
54+
Dataflow &operator=(Dataflow const &) = delete;
55+
56+
void run();
57+
58+
private:
59+
friend Reachability;
60+
61+
Classification classifyInstruction(SILInstruction *);
62+
63+
bool classificationIsBarrier(Classification);
64+
65+
/// IterativeBackwardReachability::Effects
66+
67+
auto gens() { return context.roots; }
68+
69+
Effect effectForInstruction(SILInstruction *);
70+
Effect effectForPhi(SILBasicBlock *);
71+
72+
auto localGens() { return result.localGens; }
73+
74+
bool isLocalGen(SILInstruction *instruction) {
75+
return result.localGens.contains(instruction);
76+
}
77+
78+
/// IterativeBackwardReachability::bindBarriers::Visitor
79+
80+
void visitBarrierInstruction(SILInstruction *instruction) {
81+
barriers.instructions.push_back(instruction);
82+
}
83+
84+
void visitBarrierPhi(SILBasicBlock *block) { barriers.phis.push_back(block); }
85+
86+
void visitBarrierBlock(SILBasicBlock *block) {
87+
barriers.blocks.push_back(block);
88+
}
89+
};
90+
91+
Dataflow::Classification
92+
Dataflow::classifyInstruction(SILInstruction *instruction) {
93+
if (isBarrier(instruction)) {
94+
return Classification::Barrier;
95+
}
96+
if (isDeinitBarrier(instruction, context.calleeAnalysis)) {
97+
return Classification::Barrier;
98+
}
99+
return Classification::Other;
100+
}
101+
102+
bool Dataflow::classificationIsBarrier(Classification classification) {
103+
switch (classification) {
104+
case Classification::Barrier:
105+
return true;
106+
case Classification::Other:
107+
return false;
108+
}
109+
llvm_unreachable("exhaustive switch not exhaustive?!");
110+
}
111+
112+
Dataflow::Effect Dataflow::effectForInstruction(SILInstruction *instruction) {
113+
if (llvm::is_contained(context.roots, instruction))
114+
return Effect::Gen();
115+
auto classification = classifyInstruction(instruction);
116+
return classificationIsBarrier(classification) ? Effect::Kill()
117+
: Effect::NoEffect();
118+
}
119+
120+
Dataflow::Effect Dataflow::effectForPhi(SILBasicBlock *block) {
121+
assert(llvm::all_of(block->getArguments(),
122+
[&](auto argument) { return PhiValue(argument); }));
123+
124+
bool isBarrier =
125+
llvm::any_of(block->getPredecessorBlocks(), [&](auto *predecessor) {
126+
return classificationIsBarrier(
127+
classifyInstruction(predecessor->getTerminator()));
128+
});
129+
return isBarrier ? Effect::Kill() : Effect::NoEffect();
130+
}
131+
132+
void Dataflow::run() {
133+
reachability.initialize();
134+
reachability.solve();
135+
reachability.findBarriers(*this);
136+
}
137+
138+
void run(Context &context, Barriers &barriers,
139+
function_ref<bool(SILInstruction *)> isBarrier) {
140+
Dataflow flow(context, barriers, isBarrier);
141+
flow.run();
142+
}
143+
144+
} // namespace
145+
146+
void swift::findDeinitBarriersAboveInstructions(
147+
ArrayRef<SILInstruction *> roots, SILBasicBlock *defBlock,
148+
SILFunction &function, BasicCalleeAnalysis *calleeAnalysis,
149+
DeinitBarrierFinding::Barriers &barriers,
150+
function_ref<bool(SILInstruction *)> isBarrier) {
151+
Context context = {function, calleeAnalysis, defBlock, roots};
152+
return run(context, barriers, isBarrier);
153+
}

0 commit comments

Comments
 (0)