@@ -49,6 +49,8 @@ struct Context final {
49
49
// / introducer->getOperand()
50
50
SILValue const borrowee;
51
51
52
+ SILBasicBlock *defBlock;
53
+
52
54
SILFunction &function;
53
55
54
56
// / The copy_value instructions that the utility creates or changes.
@@ -62,7 +64,8 @@ struct Context final {
62
64
SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts,
63
65
InstructionDeleter &deleter)
64
66
: introducer(introducer), borrowedValue(BorrowedValue(&introducer)),
65
- borrowee (introducer.getOperand()), function(*introducer.getFunction()),
67
+ borrowee (introducer.getOperand()), defBlock(introducer.getParent()),
68
+ function(*introducer.getFunction()),
66
69
modifiedCopyValueInsts(modifiedCopyValueInsts), deleter(deleter) {}
67
70
Context (Context const &) = delete;
68
71
Context &operator =(Context const &) = delete ;
@@ -75,7 +78,7 @@ struct Usage final {
75
78
SmallPtrSet<SILInstruction *, 16 > users;
76
79
// The instructions from which the shrinking starts, the scope ending
77
80
// instructions.
78
- llvm::SmallSetVector <SILInstruction *, 4 > ends;
81
+ llvm::SmallVector <SILInstruction *, 4 > ends;
79
82
80
83
Usage (){};
81
84
Usage (Usage const &) = delete ;
@@ -95,7 +98,7 @@ bool findUsage(Context const &context, Usage &usage) {
95
98
// If a scope ending instruction is not an end_borrow, bail out.
96
99
if (!isa<EndBorrowInst>(instruction))
97
100
return false ;
98
- usage.ends .insert (instruction);
101
+ usage.ends .push_back (instruction);
99
102
}
100
103
101
104
SmallVector<Operand *, 16 > uses;
@@ -112,81 +115,70 @@ bool findUsage(Context const &context, Usage &usage) {
112
115
113
116
// / How end_borrow hoisting is obstructed.
114
117
struct DeinitBarriers final {
115
- // / Blocks up to "before the beginning" of which hoisting was able to proceed.
116
- BasicBlockSetVector hoistingReachesBeginBlocks;
117
-
118
- // / Blocks to "after the end" of which hoisting was able to proceed.
119
- BasicBlockSet hoistingReachesEndBlocks;
120
-
121
118
// / Copies to be rewritten as copies of %borrowee.
122
119
SmallVector<CopyValueInst *, 4 > copies;
123
120
124
121
// / Instructions above which end_borrows cannot be hoisted.
125
- SmallVector<SILInstruction *, 4 > barriers ;
122
+ SmallVector<SILInstruction *, 4 > instructions ;
126
123
127
124
// / Blocks one of whose phis is a barrier and consequently out of which
128
125
// / end_borrows cannot be hoisted.
129
- SmallVector<SILBasicBlock *, 4 > phiBarriers;
126
+ SmallVector<SILBasicBlock *, 4 > phis;
127
+
128
+ // / Blocks whose single predecessors has another successor to the top of which
129
+ // / end_borrows cannot be hoisted.
130
+ SmallVector<SILBasicBlock *, 4 > blocks;
130
131
131
- DeinitBarriers (Context &context)
132
- : hoistingReachesBeginBlocks(&context.function),
133
- hoistingReachesEndBlocks (&context.function) {}
132
+ DeinitBarriers (Context &context) {}
134
133
DeinitBarriers (DeinitBarriers const &) = delete ;
135
134
DeinitBarriers &operator =(DeinitBarriers const &) = delete ;
136
135
};
137
136
138
137
// / Works backwards from the current location of end_borrows to the earliest
139
138
// / place they can be hoisted to.
140
139
// /
141
- // / Implements BackwardReachability::BlockReachability.
140
+ // / Implements IterativeBackwardReachability::Effects.
141
+ // / Implements IterativeBackwardReachability::findBarrier::Visitor.
142
142
class Dataflow final {
143
+ public:
144
+ using Reachability = IterativeBackwardReachability<Dataflow>;
145
+ using Effect = Reachability::Effect;
146
+
147
+ private:
143
148
Context const &context;
144
149
Usage const &uses;
145
- DeinitBarriers &result;
150
+ DeinitBarriers &barriers;
151
+ Reachability::Result result;
152
+ Reachability reachability;
153
+ SmallPtrSet<BeginAccessInst *, 8 > barrierAccessScopes;
154
+ bool recordCopies = false ;
146
155
147
156
enum class Classification { Barrier, Copy, Other };
148
157
149
- BackwardReachability<Dataflow> reachability;
150
-
151
158
public:
152
- Dataflow (Context const &context, Usage const &uses, DeinitBarriers &result)
153
- : context(context), uses(uses), result(result),
154
- reachability (&context.function, *this ) {
155
- // Seed reachability with the scope ending uses from which the backwards
156
- // data flow will begin.
157
- for (auto *end : uses.ends ) {
158
- reachability.initLastUse (end);
159
- }
160
- }
159
+ Dataflow (Context const &context, Usage const &uses, DeinitBarriers &barriers)
160
+ : context(context), uses(uses), barriers(barriers),
161
+ result (&context.function),
162
+ reachability(&context.function, context.defBlock, *this , result) {}
161
163
Dataflow (Dataflow const &) = delete;
162
164
Dataflow &operator =(Dataflow const &) = delete ;
163
165
164
- void run () { reachability. solveBackward (); }
166
+ void run ();
165
167
166
168
private:
167
- friend class BackwardReachability <Dataflow>;
168
-
169
- bool hasReachableBegin (SILBasicBlock *block) {
170
- return result.hoistingReachesBeginBlocks .contains (block);
171
- }
172
-
173
- void markReachableBegin (SILBasicBlock *block) {
174
- result.hoistingReachesBeginBlocks .insert (block);
175
- }
176
-
177
- void markReachableEnd (SILBasicBlock *block) {
178
- result.hoistingReachesEndBlocks .insert (block);
179
- }
169
+ friend Reachability;
180
170
181
171
Classification classifyInstruction (SILInstruction *);
182
172
183
173
bool classificationIsBarrier (Classification);
184
174
185
- void visitedInstruction ( SILInstruction *, Classification );
186
-
187
- bool checkReachableBarrier (SILInstruction *);
175
+ ArrayRef< SILInstruction *> gens ( );
176
+ Effect effectForInstruction (SILInstruction *);
177
+ Effect effectForPhi (SILBasicBlock *);
188
178
189
- bool checkReachablePhiBarrier (SILBasicBlock *);
179
+ void visitBarrierInstruction (SILInstruction *);
180
+ void visitBarrierPhi (SILBasicBlock *);
181
+ void visitBarrierBlock (SILBasicBlock *);
190
182
};
191
183
192
184
// / Whether the specified value is %lifetime or its iterated copy_value.
@@ -207,6 +199,13 @@ bool isSimpleExtendedIntroducerDef(Context const &context, SILValue value) {
207
199
}
208
200
}
209
201
202
+ void Dataflow::run () {
203
+ reachability.initialize ();
204
+ reachability.solve ();
205
+ recordCopies = true ;
206
+ reachability.findBarriers (*this );
207
+ }
208
+
210
209
Dataflow::Classification
211
210
Dataflow::classifyInstruction (SILInstruction *instruction) {
212
211
if (instruction == &context.introducer ) {
@@ -237,29 +236,19 @@ bool Dataflow::classificationIsBarrier(Classification classification) {
237
236
llvm_unreachable (" exhaustive switch not exhaustive?!" );
238
237
}
239
238
240
- void Dataflow::visitedInstruction (SILInstruction *instruction,
241
- Classification classification) {
242
- assert (classifyInstruction (instruction) == classification);
243
- switch (classification) {
244
- case Classification::Barrier:
245
- result.barriers .push_back (instruction);
246
- return ;
247
- case Classification::Copy:
248
- result.copies .push_back (cast<CopyValueInst>(instruction));
249
- return ;
250
- case Classification::Other:
251
- return ;
252
- }
253
- llvm_unreachable (" exhaustive switch not exhaustive?!" );
254
- }
239
+ ArrayRef<SILInstruction *> Dataflow::gens () { return uses.ends ; }
255
240
256
- bool Dataflow::checkReachableBarrier (SILInstruction *instruction) {
241
+ Dataflow::Effect Dataflow::effectForInstruction (SILInstruction *instruction) {
242
+ if (llvm::find (uses.ends , instruction) != uses.ends .end ())
243
+ return Effect::Gen ();
257
244
auto classification = classifyInstruction (instruction);
258
- visitedInstruction (instruction, classification);
259
- return classificationIsBarrier (classification);
245
+ if (recordCopies && classification == Classification::Copy)
246
+ barriers.copies .push_back (cast<CopyValueInst>(instruction));
247
+ return classificationIsBarrier (classification) ? Effect::Kill ()
248
+ : Effect::NoEffect ();
260
249
}
261
250
262
- bool Dataflow::checkReachablePhiBarrier (SILBasicBlock *block) {
251
+ Dataflow::Effect Dataflow::effectForPhi (SILBasicBlock *block) {
263
252
assert (llvm::all_of (block->getArguments (),
264
253
[&](auto argument) { return PhiValue (argument); }));
265
254
@@ -268,10 +257,19 @@ bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) {
268
257
return classificationIsBarrier (
269
258
classifyInstruction (predecessor->getTerminator ()));
270
259
});
271
- if (isBarrier) {
272
- result.phiBarriers .push_back (block);
273
- }
274
- return isBarrier;
260
+ return isBarrier ? Effect::Kill () : Effect::NoEffect ();
261
+ }
262
+
263
+ void Dataflow::visitBarrierInstruction (SILInstruction *instruction) {
264
+ barriers.instructions .push_back (instruction);
265
+ }
266
+
267
+ void Dataflow::visitBarrierPhi (SILBasicBlock *block) {
268
+ barriers.phis .push_back (block);
269
+ }
270
+
271
+ void Dataflow::visitBarrierBlock (SILBasicBlock *block) {
272
+ barriers.blocks .push_back (block);
275
273
}
276
274
277
275
// / Hoist the scope ends of %lifetime, rewriting copies and borrows along the
@@ -311,7 +309,7 @@ bool Rewriter::run() {
311
309
// A block is a phi barrier iff any of its predecessors' terminators get
312
310
// classified as barriers. That happens when a copy of %lifetime is passed
313
311
// to a phi.
314
- for (auto *block : barriers.phiBarriers ) {
312
+ for (auto *block : barriers.phis ) {
315
313
madeChange |= createEndBorrow (&block->front ());
316
314
}
317
315
@@ -324,15 +322,11 @@ bool Rewriter::run() {
324
322
// of a block P's successors B had reachable beginnings. If any of them
325
323
// didn't, then BackwardReachability::meetOverSuccessors would never have
326
324
// returned true for P, so none of its instructions would ever have been
327
- // classified (except for via checkReachablePhiBarrier , which doesn't record
328
- // terminator barriers).
329
- for (auto instruction : barriers.barriers ) {
325
+ // classified (except for via effectForPhi , which doesn't record terminator
326
+ // barriers).
327
+ for (auto instruction : barriers.instructions ) {
330
328
if (auto *terminator = dyn_cast<TermInst>(instruction)) {
331
329
auto successors = terminator->getParentBlock ()->getSuccessorBlocks ();
332
- // In order for the instruction to have been classified as a barrier,
333
- // reachability would have had to reach the block containing it.
334
- assert (barriers.hoistingReachesEndBlocks .contains (
335
- terminator->getParentBlock ()));
336
330
for (auto *successor : successors) {
337
331
madeChange |= createEndBorrow (&successor->front ());
338
332
}
@@ -356,12 +350,8 @@ bool Rewriter::run() {
356
350
// P not having a reachable end--see BackwardReachability::meetOverSuccessors.
357
351
//
358
352
// control-flow-boundary(B) := beginning-reachable(B) && !end-reachable(P)
359
- for (auto *block : barriers.hoistingReachesBeginBlocks ) {
360
- if (auto *predecessor = block->getSinglePredecessorBlock ()) {
361
- if (!barriers.hoistingReachesEndBlocks .contains (predecessor)) {
362
- madeChange |= createEndBorrow (&block->front ());
363
- }
364
- }
353
+ for (auto *block : barriers.blocks ) {
354
+ madeChange |= createEndBorrow (&block->front ());
365
355
}
366
356
367
357
if (madeChange) {
@@ -379,7 +369,7 @@ bool Rewriter::run() {
379
369
380
370
bool Rewriter::createEndBorrow (SILInstruction *insertionPoint) {
381
371
if (auto *ebi = dyn_cast<EndBorrowInst>(insertionPoint)) {
382
- if (uses.ends . contains (insertionPoint )) {
372
+ if (llvm::find ( uses.ends , insertionPoint) != uses. ends . end ( )) {
383
373
reusedEndBorrowInsts.insert (insertionPoint);
384
374
return false ;
385
375
}
0 commit comments