21
21
#include " swift/SIL/SILBasicBlock.h"
22
22
#include " swift/SIL/SILInstruction.h"
23
23
#include " swift/SILOptimizer/Analysis/Reachability.h"
24
+ #include " swift/SILOptimizer/Analysis/VisitBarrierAccessScopes.h"
24
25
#include " swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h"
25
26
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
26
27
#include " swift/SILOptimizer/Utils/InstructionDeleter.h"
@@ -134,10 +135,13 @@ struct DeinitBarriers final {
134
135
DeinitBarriers &operator =(DeinitBarriers const &) = delete ;
135
136
};
136
137
138
+ class BarrierAccessScopeFinder ;
139
+
137
140
// / Works backwards from the current location of end_borrows to the earliest
138
141
// / place they can be hoisted to.
139
142
// /
140
143
// / Implements IterativeBackwardReachability::Effects.
144
+ // / Implements BarrierAccessScopeFinder::Effects
141
145
class DataFlow final {
142
146
public:
143
147
using Reachability = IterativeBackwardReachability<DataFlow>;
@@ -166,6 +170,8 @@ class DataFlow final {
166
170
167
171
private:
168
172
friend Reachability;
173
+ friend class BarrierAccessScopeFinder ;
174
+ friend class VisitBarrierAccessScopes <DataFlow, BarrierAccessScopeFinder>;
169
175
170
176
Classification classifyInstruction (SILInstruction *);
171
177
@@ -178,6 +184,33 @@ class DataFlow final {
178
184
Optional<Effect> effectForPhi (SILBasicBlock *);
179
185
};
180
186
187
+ // / Finds end_access instructions which are barriers to hoisting because the
188
+ // / access scopes they contain barriers to hoisting. Hoisting end_borrows into
189
+ // / such access scopes could introduce exclusivity violations.
190
+ // /
191
+ // / Implements BarrierAccessScopeFinder::Visitor
192
+ class BarrierAccessScopeFinder final {
193
+ using Impl = VisitBarrierAccessScopes<DataFlow, BarrierAccessScopeFinder>;
194
+ Context const &context;
195
+ Impl impl;
196
+ DataFlow &dataflow;
197
+ Optional<SmallVector<SILBasicBlock *, 16 >> cachedRoots;
198
+
199
+ public:
200
+ BarrierAccessScopeFinder (Context const &context, DataFlow &dataflow)
201
+ : context(context), impl(&context.function, dataflow, *this ),
202
+ dataflow (dataflow) {}
203
+
204
+ void find ();
205
+
206
+ private:
207
+ friend Impl;
208
+
209
+ ArrayRef<SILBasicBlock *> roots ();
210
+ bool isInRegion (SILBasicBlock *);
211
+ void visitBarrierAccessScope (BeginAccessInst *);
212
+ };
213
+
181
214
// / Whether the specified value is %lifetime or its iterated copy_value.
182
215
// /
183
216
// / In other words, it has to be a simple extended def of %lifetime.
@@ -198,6 +231,8 @@ bool isSimpleExtendedIntroducerDef(Context const &context, SILValue value) {
198
231
199
232
void DataFlow::run () {
200
233
reachability.initialize ();
234
+ BarrierAccessScopeFinder finder (context, *this );
235
+ finder.find ();
201
236
reachability.solve ();
202
237
recordCopies = true ;
203
238
reachability.findBarriers (barriers.instructions , barriers.phis ,
@@ -217,6 +252,11 @@ DataFlow::classifyInstruction(SILInstruction *instruction) {
217
252
if (uses.users .contains (instruction)) {
218
253
return Classification::Barrier;
219
254
}
255
+ if (auto *eai = dyn_cast<EndAccessInst>(instruction)) {
256
+ return barrierAccessScopes.contains (eai->getBeginAccess ())
257
+ ? Classification::Barrier
258
+ : Classification::Other;
259
+ }
220
260
if (isDeinitBarrier (instruction)) {
221
261
return Classification::Barrier;
222
262
}
@@ -260,6 +300,33 @@ Optional<DataFlow::Effect> DataFlow::effectForPhi(SILBasicBlock *block) {
260
300
return isBarrier ? Optional<Effect>{Effect::Kill} : llvm::None;
261
301
}
262
302
303
+ void BarrierAccessScopeFinder::find () { impl.visit (); }
304
+
305
+ ArrayRef<SILBasicBlock *> BarrierAccessScopeFinder::roots () {
306
+ if (cachedRoots)
307
+ return *cachedRoots;
308
+
309
+ cachedRoots = SmallVector<SILBasicBlock *, 16 >{};
310
+ BasicBlockSet seenRoots (&context.function );
311
+ for (auto *gen : dataflow.gens ()) {
312
+ seenRoots.insert (gen->getParent ());
313
+ cachedRoots->push_back (gen->getParent ());
314
+ }
315
+
316
+ return *cachedRoots;
317
+ }
318
+
319
+ bool BarrierAccessScopeFinder::isInRegion (SILBasicBlock *block) {
320
+ return dataflow.result .discoveredBlocks .contains (block);
321
+ }
322
+
323
+ void BarrierAccessScopeFinder::visitBarrierAccessScope (BeginAccessInst *bai) {
324
+ dataflow.barrierAccessScopes .insert (bai);
325
+ for (auto *eai : bai->getEndAccesses ()) {
326
+ dataflow.reachability .addKill (eai);
327
+ }
328
+ }
329
+
263
330
// / Hoist the scope ends of %lifetime, rewriting copies and borrows along the
264
331
// / way.
265
332
class Rewriter final {
0 commit comments