@@ -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,78 +98,71 @@ 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;
107
+
108
+ SmallVector<SILBasicBlock *, 4 > blocks;
110
109
111
- DeinitBarriers (Context &context)
112
- : hoistingReachesBeginBlocks(&context.function),
113
- hoistingReachesEndBlocks (&context.function) {}
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> ;
142
+ friend Reachability ;
148
143
149
- bool hasReachableBegin (SILBasicBlock *block) {
150
- return result.hoistingReachesBeginBlocks .contains (block);
151
- }
144
+ Classification classifyInstruction (SILInstruction *);
152
145
153
- void markReachableBegin (SILBasicBlock *block) {
154
- result.hoistingReachesBeginBlocks .insert (block);
155
- }
146
+ bool classificationIsBarrier (Classification);
156
147
157
- void markReachableEnd (SILBasicBlock *block) {
158
- result.hoistingReachesEndBlocks .insert (block);
159
- }
148
+ // / IterativeBackwardReachability::Effects
160
149
161
- Classification classifyInstruction ( SILInstruction *);
150
+ ArrayRef< SILInstruction *> gens () { return uses. ends ; }
162
151
163
- bool classificationIsBarrier (Classification);
152
+ Effect effectForInstruction (SILInstruction *);
153
+ Effect effectForPhi (SILBasicBlock *);
164
154
165
- void visitedInstruction (SILInstruction *, Classification);
155
+ // / IterativeBackwardReachability::bindBarriers::Visitor
166
156
167
- bool checkReachableBarrier (SILInstruction *);
157
+ void visitBarrierInstruction (SILInstruction *instruction) {
158
+ barriers.instructions .push_back (instruction);
159
+ }
168
160
169
- bool checkReachablePhiBarrier (SILBasicBlock *);
161
+ void visitBarrierPhi (SILBasicBlock *block) { barriers.phis .push_back (block); }
162
+
163
+ void visitBarrierBlock (SILBasicBlock *block) {
164
+ barriers.blocks .push_back (block);
165
+ }
170
166
};
171
167
172
168
Dataflow::Classification
@@ -193,26 +189,15 @@ bool Dataflow::classificationIsBarrier(Classification classification) {
193
189
llvm_unreachable (" exhaustive switch not exhaustive?!" );
194
190
}
195
191
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
- }
208
-
209
- bool Dataflow::checkReachableBarrier (SILInstruction *instruction) {
192
+ Dataflow::Effect Dataflow::effectForInstruction (SILInstruction *instruction) {
193
+ if (llvm::find (uses.ends , instruction) != uses.ends .end ())
194
+ return Effect::Gen ();
210
195
auto classification = classifyInstruction (instruction);
211
- visitedInstruction (instruction, classification);
212
- return classificationIsBarrier (classification );
196
+ return classificationIsBarrier ( classification) ? Effect::Kill ()
197
+ : Effect::NoEffect ( );
213
198
}
214
199
215
- bool Dataflow::checkReachablePhiBarrier (SILBasicBlock *block) {
200
+ Dataflow::Effect Dataflow::effectForPhi (SILBasicBlock *block) {
216
201
assert (llvm::all_of (block->getArguments (),
217
202
[&](auto argument) { return PhiValue (argument); }));
218
203
@@ -221,10 +206,13 @@ bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) {
221
206
return classificationIsBarrier (
222
207
classifyInstruction (predecessor->getTerminator ()));
223
208
});
224
- if (isBarrier) {
225
- result.phiBarriers .push_back (block);
226
- }
227
- return isBarrier;
209
+ return isBarrier ? Effect::Kill () : Effect::NoEffect ();
210
+ }
211
+
212
+ void Dataflow::run () {
213
+ reachability.initialize ();
214
+ reachability.solve ();
215
+ reachability.findBarriers (*this );
228
216
}
229
217
230
218
// / Hoist the destroy_values of %value.
@@ -256,7 +244,7 @@ bool Rewriter::run() {
256
244
//
257
245
// A block is a phi barrier iff any of its predecessors' terminators get
258
246
// classified as barriers.
259
- for (auto *block : barriers.phiBarriers ) {
247
+ for (auto *block : barriers.phis ) {
260
248
madeChange |= createDestroyValue (&block->front ());
261
249
}
262
250
@@ -271,13 +259,9 @@ bool Rewriter::run() {
271
259
// have returned true for P, so none of its instructions would ever have been
272
260
// classified (except for via checkReachablePhiBarrier, which doesn't record
273
261
// terminator barriers).
274
- for (auto instruction : barriers.barriers ) {
262
+ for (auto instruction : barriers.instructions ) {
275
263
if (auto *terminator = dyn_cast<TermInst>(instruction)) {
276
264
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
265
for (auto *successor : successors) {
282
266
madeChange |= createDestroyValue (&successor->front ());
283
267
}
@@ -301,12 +285,8 @@ bool Rewriter::run() {
301
285
// P not having a reachable end--see BackwardReachability::meetOverSuccessors.
302
286
//
303
287
// 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
- }
288
+ for (auto *block : barriers.blocks ) {
289
+ madeChange |= createDestroyValue (&block->front ());
310
290
}
311
291
312
292
if (madeChange) {
@@ -324,7 +304,7 @@ bool Rewriter::run() {
324
304
325
305
bool Rewriter::createDestroyValue (SILInstruction *insertionPoint) {
326
306
if (auto *ebi = dyn_cast<DestroyValueInst>(insertionPoint)) {
327
- if (uses.ends . contains (insertionPoint )) {
307
+ if (llvm::find ( uses.ends , insertionPoint) != uses. ends . end ( )) {
328
308
reusedDestroyValueInsts.insert (insertionPoint);
329
309
return false ;
330
310
}
0 commit comments