@@ -43,14 +43,17 @@ struct Context final {
43
43
// / value->getDefiningInstruction()
44
44
SILInstruction *const definition;
45
45
46
+ SILBasicBlock *defBlock;
47
+
46
48
SILFunction &function;
47
49
48
50
InstructionDeleter &deleter;
49
51
50
52
Context (SILValue const &value, SILFunction &function,
51
53
InstructionDeleter &deleter)
52
54
: value(value), definition(value->getDefiningInstruction ()),
53
- function(function), deleter(deleter) {
55
+ defBlock(value->getParentBlock ()), function(function),
56
+ deleter(deleter) {
54
57
assert (value->isLexical ());
55
58
assert (value->getOwnershipKind () == OwnershipKind::Owned);
56
59
}
@@ -63,7 +66,7 @@ struct Usage final {
63
66
// / Instructions which are users of the simple (i.e. not reborrowed) value.
64
67
SmallPtrSet<SILInstruction *, 16 > users;
65
68
// The instructions from which the hoisting starts, the destroy_values.
66
- llvm::SmallSetVector <SILInstruction *, 4 > ends;
69
+ llvm::SmallVector <SILInstruction *, 4 > ends;
67
70
68
71
Usage (){};
69
72
Usage (Usage const &) = delete ;
@@ -85,7 +88,7 @@ bool findUsage(Context const &context, Usage &usage) {
85
88
// flow and determine whether any were reused. They aren't uses over which
86
89
// we can't hoist though.
87
90
if (isa<DestroyValueInst>(use->getUser ())) {
88
- usage.ends .insert (use->getUser ());
91
+ usage.ends .push_back (use->getUser ());
89
92
} else {
90
93
usage.users .insert (use->getUser ());
91
94
}
@@ -95,80 +98,68 @@ bool findUsage(Context const &context, Usage &usage) {
95
98
96
99
// / How destroy_value hoisting is obstructed.
97
100
struct DeinitBarriers final {
98
- // / Blocks up to "before the beginning" of which hoisting was able to proceed.
99
- BasicBlockSetVector hoistingReachesBeginBlocks;
100
-
101
- // / Blocks to "after the end" of which hoisting was able to proceed.
102
- BasicBlockSet hoistingReachesEndBlocks;
103
-
104
101
// / Instructions above which destroy_values cannot be hoisted.
105
- SmallVector<SILInstruction *, 4 > barriers ;
102
+ SmallVector<SILInstruction *, 4 > instructions ;
106
103
107
104
// / Blocks one of whose phis is a barrier and consequently out of which
108
105
// / destroy_values cannot be hoisted.
109
- SmallVector<SILBasicBlock *, 4 > phiBarriers ;
106
+ SmallVector<SILBasicBlock *, 4 > phis ;
110
107
111
- DeinitBarriers (Context &context)
112
- : hoistingReachesBeginBlocks(&context.function),
113
- hoistingReachesEndBlocks ( &context.function ) {}
108
+ SmallVector<SILBasicBlock *, 4 > blocks;
109
+
110
+ DeinitBarriers (Context &context) {}
114
111
DeinitBarriers (DeinitBarriers const &) = delete ;
115
112
DeinitBarriers &operator =(DeinitBarriers const &) = delete ;
116
113
};
117
114
118
115
// / Works backwards from the current location of destroy_values to the earliest
119
116
// / place they can be hoisted to.
120
117
// /
121
- // / Implements BackwardReachability::BlockReachability.
118
+ // / Implements IterativeBackwardReachability::Effects
119
+ // / Implements IterativeBackwardReachability::bindBarriers::Visitor
122
120
class Dataflow final {
121
+ using Reachability = IterativeBackwardReachability<Dataflow>;
122
+ using Effect = Reachability::Effect;
123
123
Context const &context;
124
124
Usage const &uses;
125
- DeinitBarriers &result;
125
+ DeinitBarriers &barriers;
126
+ Reachability::Result result;
127
+ Reachability reachability;
126
128
127
129
enum class Classification { Barrier, Other };
128
130
129
- BackwardReachability<Dataflow> reachability;
130
-
131
131
public:
132
- Dataflow (Context const &context, Usage const &uses, DeinitBarriers &result)
133
- : context(context), uses(uses), result(result),
134
- reachability (&context.function, *this ) {
135
- // Seed reachability with the scope ending uses from which the backwards
136
- // data flow will begin.
137
- for (auto *end : uses.ends ) {
138
- reachability.initLastUse (end);
139
- }
140
- }
132
+ Dataflow (Context const &context, Usage const &uses, DeinitBarriers &barriers)
133
+ : context(context), uses(uses), barriers(barriers),
134
+ result (&context.function),
135
+ reachability(&context.function, context.defBlock, *this , result) {}
141
136
Dataflow (Dataflow const &) = delete;
142
137
Dataflow &operator =(Dataflow const &) = delete ;
143
138
144
- void run () { reachability. solveBackward (); }
139
+ void run ();
145
140
146
141
private:
147
- friend class BackwardReachability <Dataflow>;
148
-
149
- bool hasReachableBegin (SILBasicBlock *block) {
150
- return result.hoistingReachesBeginBlocks .contains (block);
151
- }
152
-
153
- void markReachableBegin (SILBasicBlock *block) {
154
- result.hoistingReachesBeginBlocks .insert (block);
155
- }
156
-
157
- void markReachableEnd (SILBasicBlock *block) {
158
- result.hoistingReachesEndBlocks .insert (block);
159
- }
142
+ friend Reachability;
160
143
161
144
Classification classifyInstruction (SILInstruction *);
162
145
163
146
bool classificationIsBarrier (Classification);
164
147
165
- void visitedInstruction ( SILInstruction *, Classification );
166
-
167
- bool checkReachableBarrier (SILInstruction *);
148
+ ArrayRef< SILInstruction *> gens ( );
149
+ Effect effectForInstruction (SILInstruction *);
150
+ Effect effectForPhi (SILBasicBlock *);
168
151
169
- bool checkReachablePhiBarrier (SILBasicBlock *);
152
+ void visitBarrierInstruction (SILInstruction *);
153
+ void visitBarrierPhi (SILBasicBlock *);
154
+ void visitBarrierBlock (SILBasicBlock *);
170
155
};
171
156
157
+ void Dataflow::run () {
158
+ reachability.initialize ();
159
+ reachability.solve ();
160
+ reachability.findBarriers (*this );
161
+ }
162
+
172
163
Dataflow::Classification
173
164
Dataflow::classifyInstruction (SILInstruction *instruction) {
174
165
if (instruction == context.definition ) {
@@ -193,26 +184,17 @@ bool Dataflow::classificationIsBarrier(Classification classification) {
193
184
llvm_unreachable (" exhaustive switch not exhaustive?!" );
194
185
}
195
186
196
- void Dataflow::visitedInstruction (SILInstruction *instruction,
197
- Classification classification) {
198
- assert (classifyInstruction (instruction) == classification);
199
- switch (classification) {
200
- case Classification::Barrier:
201
- result.barriers .push_back (instruction);
202
- return ;
203
- case Classification::Other:
204
- return ;
205
- }
206
- llvm_unreachable (" exhaustive switch not exhaustive?!" );
207
- }
187
+ ArrayRef<SILInstruction *> Dataflow::gens () { return uses.ends ; }
208
188
209
- bool Dataflow::checkReachableBarrier (SILInstruction *instruction) {
189
+ Dataflow::Effect Dataflow::effectForInstruction (SILInstruction *instruction) {
190
+ if (llvm::find (uses.ends , instruction) != uses.ends .end ())
191
+ return Effect::Gen ();
210
192
auto classification = classifyInstruction (instruction);
211
- visitedInstruction (instruction, classification);
212
- return classificationIsBarrier (classification );
193
+ return classificationIsBarrier ( classification) ? Effect::Kill ()
194
+ : Effect::NoEffect ( );
213
195
}
214
196
215
- bool Dataflow::checkReachablePhiBarrier (SILBasicBlock *block) {
197
+ Dataflow::Effect Dataflow::effectForPhi (SILBasicBlock *block) {
216
198
assert (llvm::all_of (block->getArguments (),
217
199
[&](auto argument) { return PhiValue (argument); }));
218
200
@@ -221,10 +203,19 @@ bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) {
221
203
return classificationIsBarrier (
222
204
classifyInstruction (predecessor->getTerminator ()));
223
205
});
224
- if (isBarrier) {
225
- result.phiBarriers .push_back (block);
226
- }
227
- return isBarrier;
206
+ return isBarrier ? Effect::Kill () : Effect::NoEffect ();
207
+ }
208
+
209
+ void Dataflow::visitBarrierInstruction (SILInstruction *instruction) {
210
+ barriers.instructions .push_back (instruction);
211
+ }
212
+
213
+ void Dataflow::visitBarrierPhi (SILBasicBlock *block) {
214
+ barriers.phis .push_back (block);
215
+ }
216
+
217
+ void Dataflow::visitBarrierBlock (SILBasicBlock *block) {
218
+ barriers.blocks .push_back (block);
228
219
}
229
220
230
221
// / Hoist the destroy_values of %value.
@@ -256,7 +247,7 @@ bool Rewriter::run() {
256
247
//
257
248
// A block is a phi barrier iff any of its predecessors' terminators get
258
249
// classified as barriers.
259
- for (auto *block : barriers.phiBarriers ) {
250
+ for (auto *block : barriers.phis ) {
260
251
madeChange |= createDestroyValue (&block->front ());
261
252
}
262
253
@@ -271,13 +262,9 @@ bool Rewriter::run() {
271
262
// have returned true for P, so none of its instructions would ever have been
272
263
// classified (except for via checkReachablePhiBarrier, which doesn't record
273
264
// terminator barriers).
274
- for (auto instruction : barriers.barriers ) {
265
+ for (auto instruction : barriers.instructions ) {
275
266
if (auto *terminator = dyn_cast<TermInst>(instruction)) {
276
267
auto successors = terminator->getParentBlock ()->getSuccessorBlocks ();
277
- // In order for the instruction to have been classified as a barrier,
278
- // reachability would have had to reach the block containing it.
279
- assert (barriers.hoistingReachesEndBlocks .contains (
280
- terminator->getParentBlock ()));
281
268
for (auto *successor : successors) {
282
269
madeChange |= createDestroyValue (&successor->front ());
283
270
}
@@ -301,12 +288,8 @@ bool Rewriter::run() {
301
288
// P not having a reachable end--see BackwardReachability::meetOverSuccessors.
302
289
//
303
290
// control-flow-boundary(B) := beginning-reachable(B) && !end-reachable(P)
304
- for (auto *block : barriers.hoistingReachesBeginBlocks ) {
305
- if (auto *predecessor = block->getSinglePredecessorBlock ()) {
306
- if (!barriers.hoistingReachesEndBlocks .contains (predecessor)) {
307
- madeChange |= createDestroyValue (&block->front ());
308
- }
309
- }
291
+ for (auto *block : barriers.blocks ) {
292
+ madeChange |= createDestroyValue (&block->front ());
310
293
}
311
294
312
295
if (madeChange) {
@@ -324,7 +307,7 @@ bool Rewriter::run() {
324
307
325
308
bool Rewriter::createDestroyValue (SILInstruction *insertionPoint) {
326
309
if (auto *ebi = dyn_cast<DestroyValueInst>(insertionPoint)) {
327
- if (uses.ends . contains (insertionPoint )) {
310
+ if (llvm::find ( uses.ends , insertionPoint) != uses. ends . end ( )) {
328
311
reusedDestroyValueInsts.insert (insertionPoint);
329
312
return false ;
330
313
}
0 commit comments