@@ -49,6 +49,8 @@ struct Context final {
4949 // / introducer->getOperand()
5050 SILValue const borrowee;
5151
52+ SILBasicBlock *defBlock;
53+
5254 SILFunction &function;
5355
5456 // / The copy_value instructions that the utility creates or changes.
@@ -62,7 +64,8 @@ struct Context final {
6264 SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts,
6365 InstructionDeleter &deleter)
6466 : introducer(introducer), borrowedValue(BorrowedValue(&introducer)),
65- borrowee (introducer.getOperand()), function(*introducer.getFunction()),
67+ borrowee (introducer.getOperand()), defBlock(introducer.getParent()),
68+ function(*introducer.getFunction()),
6669 modifiedCopyValueInsts(modifiedCopyValueInsts), deleter(deleter) {}
6770 Context (Context const &) = delete;
6871 Context &operator =(Context const &) = delete ;
@@ -75,7 +78,7 @@ struct Usage final {
7578 SmallPtrSet<SILInstruction *, 16 > users;
7679 // The instructions from which the shrinking starts, the scope ending
7780 // instructions.
78- llvm::SmallSetVector <SILInstruction *, 4 > ends;
81+ llvm::SmallVector <SILInstruction *, 4 > ends;
7982
8083 Usage (){};
8184 Usage (Usage const &) = delete ;
@@ -95,7 +98,7 @@ bool findUsage(Context const &context, Usage &usage) {
9598 // If a scope ending instruction is not an end_borrow, bail out.
9699 if (!isa<EndBorrowInst>(instruction))
97100 return false ;
98- usage.ends .insert (instruction);
101+ usage.ends .push_back (instruction);
99102 }
100103
101104 SmallVector<Operand *, 16 > uses;
@@ -112,81 +115,82 @@ bool findUsage(Context const &context, Usage &usage) {
112115
113116// / How end_borrow hoisting is obstructed.
114117struct 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-
121118 // / Copies to be rewritten as copies of %borrowee.
122119 SmallVector<CopyValueInst *, 4 > copies;
123120
124121 // / Instructions above which end_borrows cannot be hoisted.
125- SmallVector<SILInstruction *, 4 > barriers ;
122+ SmallVector<SILInstruction *, 4 > instructions ;
126123
127124 // / Blocks one of whose phis is a barrier and consequently out of which
128125 // / 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;
130131
131- DeinitBarriers (Context &context)
132- : hoistingReachesBeginBlocks(&context.function),
133- hoistingReachesEndBlocks (&context.function) {}
132+ DeinitBarriers (Context &context) {}
134133 DeinitBarriers (DeinitBarriers const &) = delete ;
135134 DeinitBarriers &operator =(DeinitBarriers const &) = delete ;
136135};
137136
138137// / Works backwards from the current location of end_borrows to the earliest
139138// / place they can be hoisted to.
140139// /
141- // / Implements BackwardReachability::BlockReachability.
140+ // / Implements IterativeBackwardReachability::Effects.
141+ // / Implements IterativeBackwardReachability::findBarrier::Visitor.
142142class Dataflow final {
143+ public:
144+ using Reachability = IterativeBackwardReachability<Dataflow>;
145+ using Effect = Reachability::Effect;
146+
147+ private:
143148 Context const &context;
144149 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 ;
146155
147156 enum class Classification { Barrier, Copy, Other };
148157
149- BackwardReachability<Dataflow> reachability;
150-
151158public:
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) {}
161163 Dataflow (Dataflow const &) = delete;
162164 Dataflow &operator =(Dataflow const &) = delete ;
163165
164- void run () { reachability. solveBackward (); }
166+ void run ();
165167
166168private:
167- friend class BackwardReachability <Dataflow> ;
169+ friend Reachability ;
168170
169- bool hasReachableBegin (SILBasicBlock *block) {
170- return result.hoistingReachesBeginBlocks .contains (block);
171- }
171+ Classification classifyInstruction (SILInstruction *);
172172
173- void markReachableBegin (SILBasicBlock *block) {
174- result.hoistingReachesBeginBlocks .insert (block);
175- }
173+ bool classificationIsBarrier (Classification);
176174
177- void markReachableEnd (SILBasicBlock *block) {
178- result.hoistingReachesEndBlocks .insert (block);
179- }
175+ // / Implements IterativeBackwardReachability::Effects.
180176
181- Classification classifyInstruction ( SILInstruction *);
177+ ArrayRef< SILInstruction *> gens () { return uses. ends ; }
182178
183- bool classificationIsBarrier (Classification );
179+ Effect effectForInstruction (SILInstruction * );
184180
185- void visitedInstruction (SILInstruction *, Classification );
181+ Effect effectForPhi (SILBasicBlock * );
186182
187- bool checkReachableBarrier (SILInstruction *);
183+ // / IterativeBackwardReachability::findBarrier::Visitor.
188184
189- bool checkReachablePhiBarrier (SILBasicBlock *);
185+ void visitBarrierInstruction (SILInstruction *instruction) {
186+ barriers.instructions .push_back (instruction);
187+ }
188+
189+ void visitBarrierPhi (SILBasicBlock *block) { barriers.phis .push_back (block); }
190+
191+ void visitBarrierBlock (SILBasicBlock *block) {
192+ barriers.blocks .push_back (block);
193+ }
190194};
191195
192196// / Whether the specified value is %lifetime or its iterated copy_value.
@@ -237,29 +241,17 @@ bool Dataflow::classificationIsBarrier(Classification classification) {
237241 llvm_unreachable (" exhaustive switch not exhaustive?!" );
238242}
239243
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- }
255-
256- bool Dataflow::checkReachableBarrier (SILInstruction *instruction) {
244+ Dataflow::Effect Dataflow::effectForInstruction (SILInstruction *instruction) {
245+ if (llvm::find (uses.ends , instruction) != uses.ends .end ())
246+ return Effect::Gen ();
257247 auto classification = classifyInstruction (instruction);
258- visitedInstruction (instruction, classification);
259- return classificationIsBarrier (classification);
248+ if (recordCopies && classification == Classification::Copy)
249+ barriers.copies .push_back (cast<CopyValueInst>(instruction));
250+ return classificationIsBarrier (classification) ? Effect::Kill ()
251+ : Effect::NoEffect ();
260252}
261253
262- bool Dataflow::checkReachablePhiBarrier (SILBasicBlock *block) {
254+ Dataflow::Effect Dataflow::effectForPhi (SILBasicBlock *block) {
263255 assert (llvm::all_of (block->getArguments (),
264256 [&](auto argument) { return PhiValue (argument); }));
265257
@@ -268,10 +260,14 @@ bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) {
268260 return classificationIsBarrier (
269261 classifyInstruction (predecessor->getTerminator ()));
270262 });
271- if (isBarrier) {
272- result.phiBarriers .push_back (block);
273- }
274- return isBarrier;
263+ return isBarrier ? Effect::Kill () : Effect::NoEffect ();
264+ }
265+
266+ void Dataflow::run () {
267+ reachability.initialize ();
268+ reachability.solve ();
269+ recordCopies = true ;
270+ reachability.findBarriers (*this );
275271}
276272
277273// / Hoist the scope ends of %lifetime, rewriting copies and borrows along the
@@ -311,7 +307,7 @@ bool Rewriter::run() {
311307 // A block is a phi barrier iff any of its predecessors' terminators get
312308 // classified as barriers. That happens when a copy of %lifetime is passed
313309 // to a phi.
314- for (auto *block : barriers.phiBarriers ) {
310+ for (auto *block : barriers.phis ) {
315311 madeChange |= createEndBorrow (&block->front ());
316312 }
317313
@@ -324,15 +320,11 @@ bool Rewriter::run() {
324320 // of a block P's successors B had reachable beginnings. If any of them
325321 // didn't, then BackwardReachability::meetOverSuccessors would never have
326322 // 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 ) {
323+ // classified (except for via effectForPhi , which doesn't record terminator
324+ // barriers).
325+ for (auto instruction : barriers.instructions ) {
330326 if (auto *terminator = dyn_cast<TermInst>(instruction)) {
331327 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 ()));
336328 for (auto *successor : successors) {
337329 madeChange |= createEndBorrow (&successor->front ());
338330 }
@@ -356,12 +348,8 @@ bool Rewriter::run() {
356348 // P not having a reachable end--see BackwardReachability::meetOverSuccessors.
357349 //
358350 // 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- }
351+ for (auto *block : barriers.blocks ) {
352+ madeChange |= createEndBorrow (&block->front ());
365353 }
366354
367355 if (madeChange) {
@@ -379,7 +367,7 @@ bool Rewriter::run() {
379367
380368bool Rewriter::createEndBorrow (SILInstruction *insertionPoint) {
381369 if (auto *ebi = dyn_cast<EndBorrowInst>(insertionPoint)) {
382- if (uses.ends . contains (insertionPoint )) {
370+ if (llvm::find ( uses.ends , insertionPoint) != uses. ends . end ( )) {
383371 reusedEndBorrowInsts.insert (insertionPoint);
384372 return false ;
385373 }
0 commit comments