@@ -43,14 +43,16 @@ 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), deleter(deleter) {
54
56
assert (value->isLexical ());
55
57
assert (value->getOwnershipKind () == OwnershipKind::Owned);
56
58
}
@@ -63,7 +65,7 @@ struct Usage final {
63
65
// / Instructions which are users of the simple (i.e. not reborrowed) value.
64
66
SmallPtrSet<SILInstruction *, 16 > users;
65
67
// The instructions from which the hoisting starts, the destroy_values.
66
- llvm::SmallSetVector <SILInstruction *, 4 > ends;
68
+ llvm::SmallVector <SILInstruction *, 4 > ends;
67
69
68
70
Usage (){};
69
71
Usage (Usage const &) = delete ;
@@ -85,7 +87,7 @@ bool findUsage(Context const &context, Usage &usage) {
85
87
// flow and determine whether any were reused. They aren't uses over which
86
88
// we can't hoist though.
87
89
if (isa<DestroyValueInst>(use->getUser ())) {
88
- usage.ends .insert (use->getUser ());
90
+ usage.ends .push_back (use->getUser ());
89
91
} else {
90
92
usage.users .insert (use->getUser ());
91
93
}
@@ -95,80 +97,66 @@ bool findUsage(Context const &context, Usage &usage) {
95
97
96
98
// / How destroy_value hoisting is obstructed.
97
99
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
100
// / Instructions above which destroy_values cannot be hoisted.
105
- SmallVector <SILInstruction *, 4 > barriers ;
101
+ SmallSetVector <SILInstruction *, 4 > instructions ;
106
102
107
103
// / Blocks one of whose phis is a barrier and consequently out of which
108
104
// / destroy_values cannot be hoisted.
109
- SmallVector<SILBasicBlock *, 4 > phiBarriers;
105
+ SmallSetVector<SILBasicBlock *, 4 > phis;
106
+
107
+ SmallSetVector<SILBasicBlock *, 4 > blocks;
110
108
111
- DeinitBarriers (Context &context)
112
- : hoistingReachesBeginBlocks(&context.function),
113
- hoistingReachesEndBlocks (&context.function) {}
109
+ DeinitBarriers (Context &context) {}
114
110
DeinitBarriers (DeinitBarriers const &) = delete ;
115
111
DeinitBarriers &operator =(DeinitBarriers const &) = delete ;
116
112
};
117
113
118
114
// / Works backwards from the current location of destroy_values to the earliest
119
115
// / place they can be hoisted to.
120
116
// /
121
- // / Implements BackwardReachability::BlockReachability.
117
+ // / Implements IterativeBackwardReachability::Effects
122
118
class DataFlow final {
119
+ using Reachability = IterativeBackwardReachability<DataFlow>;
120
+ using Effect = Reachability::Effect;
123
121
Context const &context;
124
122
Usage const &uses;
125
- DeinitBarriers &result;
123
+ DeinitBarriers &barriers;
124
+ Reachability::Result result;
125
+ Reachability reachability;
126
126
127
127
enum class Classification { Barrier, Other };
128
128
129
- BackwardReachability<DataFlow> reachability;
130
-
131
129
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
- }
130
+ DataFlow (Context const &context, Usage const &uses, DeinitBarriers &barriers)
131
+ : context(context), uses(uses), barriers(barriers), result(&context.function),
132
+ reachability (&context.function, context.defBlock, *this , result) {
140
133
}
141
134
DataFlow (DataFlow const &) = delete;
142
135
DataFlow &operator =(DataFlow const &) = delete ;
143
136
144
- void run () { reachability. solveBackward (); }
137
+ void run ();
145
138
146
139
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
- }
140
+ friend Reachability;
160
141
161
142
Classification classifyInstruction (SILInstruction *);
162
143
163
144
bool classificationIsBarrier (Classification);
164
145
165
- void visitedInstruction ( SILInstruction *, Classification );
146
+ ArrayRef< SILInstruction *> gens ( );
166
147
167
- bool checkReachableBarrier (SILInstruction *);
148
+ Optional<Effect> effectForInstruction (SILInstruction *);
168
149
169
- bool checkReachablePhiBarrier (SILBasicBlock *);
150
+ Optional<Effect> effectForPhi (SILBasicBlock *);
170
151
};
171
152
153
+ void DataFlow::run () {
154
+ reachability.initialize ();
155
+ reachability.solve ();
156
+ reachability.findBarriers (barriers.instructions , barriers.phis ,
157
+ barriers.blocks );
158
+ }
159
+
172
160
DataFlow::Classification
173
161
DataFlow::classifyInstruction (SILInstruction *instruction) {
174
162
if (instruction == context.definition ) {
@@ -193,26 +181,18 @@ bool DataFlow::classificationIsBarrier(Classification classification) {
193
181
llvm_unreachable (" exhaustive switch not exhaustive?!" );
194
182
}
195
183
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
- }
184
+ ArrayRef<SILInstruction *> DataFlow::gens () { return uses.ends ; }
208
185
209
- bool DataFlow::checkReachableBarrier (SILInstruction *instruction) {
186
+ Optional<DataFlow::Effect> DataFlow::effectForInstruction (SILInstruction *instruction) {
187
+ if (llvm::find (uses.ends , instruction) != uses.ends .end ())
188
+ return {Effect::Gen};
210
189
auto classification = classifyInstruction (instruction);
211
- visitedInstruction (instruction, classification);
212
- return classificationIsBarrier (classification);
190
+ return classificationIsBarrier (classification)
191
+ ? Optional<Effect>{Effect::Kill}
192
+ : llvm::None;
213
193
}
214
194
215
- bool DataFlow::checkReachablePhiBarrier (SILBasicBlock *block) {
195
+ Optional<DataFlow::Effect> DataFlow::effectForPhi (SILBasicBlock *block) {
216
196
assert (llvm::all_of (block->getArguments (),
217
197
[&](auto argument) { return PhiValue (argument); }));
218
198
@@ -221,10 +201,7 @@ bool DataFlow::checkReachablePhiBarrier(SILBasicBlock *block) {
221
201
return classificationIsBarrier (
222
202
classifyInstruction (predecessor->getTerminator ()));
223
203
});
224
- if (isBarrier) {
225
- result.phiBarriers .push_back (block);
226
- }
227
- return isBarrier;
204
+ return isBarrier ? Optional<Effect>{Effect::Kill} : llvm::None;
228
205
}
229
206
230
207
// / Hoist the destroy_values of %value.
@@ -256,7 +233,7 @@ bool Rewriter::run() {
256
233
//
257
234
// A block is a phi barrier iff any of its predecessors' terminators get
258
235
// classified as barriers.
259
- for (auto *block : barriers.phiBarriers ) {
236
+ for (auto *block : barriers.phis ) {
260
237
madeChange |= createDestroyValue (&block->front ());
261
238
}
262
239
@@ -271,13 +248,9 @@ bool Rewriter::run() {
271
248
// have returned true for P, so none of its instructions would ever have been
272
249
// classified (except for via checkReachablePhiBarrier, which doesn't record
273
250
// terminator barriers).
274
- for (auto instruction : barriers.barriers ) {
251
+ for (auto instruction : barriers.instructions ) {
275
252
if (auto *terminator = dyn_cast<TermInst>(instruction)) {
276
253
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
254
for (auto *successor : successors) {
282
255
madeChange |= createDestroyValue (&successor->front ());
283
256
}
@@ -301,12 +274,8 @@ bool Rewriter::run() {
301
274
// P not having a reachable end--see BackwardReachability::meetOverSuccessors.
302
275
//
303
276
// 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
- }
277
+ for (auto *block : barriers.blocks ) {
278
+ madeChange |= createDestroyValue (&block->front ());
310
279
}
311
280
312
281
if (madeChange) {
@@ -324,7 +293,7 @@ bool Rewriter::run() {
324
293
325
294
bool Rewriter::createDestroyValue (SILInstruction *insertionPoint) {
326
295
if (auto *ebi = dyn_cast<DestroyValueInst>(insertionPoint)) {
327
- if (uses.ends . contains (insertionPoint )) {
296
+ if (llvm::find ( uses.ends , insertionPoint) != uses. ends . end ( )) {
328
297
reusedDestroyValueInsts.insert (insertionPoint);
329
298
return false ;
330
299
}
0 commit comments