@@ -43,14 +43,17 @@ struct Context final {
4343 // / value->getDefiningInstruction()
4444 SILInstruction *const definition;
4545
46+ SILBasicBlock *defBlock;
47+
4648 SILFunction &function;
4749
4850 InstructionDeleter &deleter;
4951
5052 Context (SILValue const &value, SILFunction &function,
5153 InstructionDeleter &deleter)
5254 : value(value), definition(value->getDefiningInstruction ()),
53- function(function), deleter(deleter) {
55+ defBlock(value->getParentBlock ()), function(function),
56+ deleter(deleter) {
5457 assert (value->isLexical ());
5558 assert (value->getOwnershipKind () == OwnershipKind::Owned);
5659 }
@@ -63,7 +66,7 @@ struct Usage final {
6366 // / Instructions which are users of the simple (i.e. not reborrowed) value.
6467 SmallPtrSet<SILInstruction *, 16 > users;
6568 // The instructions from which the hoisting starts, the destroy_values.
66- llvm::SmallSetVector <SILInstruction *, 4 > ends;
69+ llvm::SmallVector <SILInstruction *, 4 > ends;
6770
6871 Usage (){};
6972 Usage (Usage const &) = delete ;
@@ -85,7 +88,7 @@ bool findUsage(Context const &context, Usage &usage) {
8588 // flow and determine whether any were reused. They aren't uses over which
8689 // we can't hoist though.
8790 if (isa<DestroyValueInst>(use->getUser ())) {
88- usage.ends .insert (use->getUser ());
91+ usage.ends .push_back (use->getUser ());
8992 } else {
9093 usage.users .insert (use->getUser ());
9194 }
@@ -95,78 +98,71 @@ bool findUsage(Context const &context, Usage &usage) {
9598
9699// / How destroy_value hoisting is obstructed.
97100struct 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-
104101 // / Instructions above which destroy_values cannot be hoisted.
105- SmallVector<SILInstruction *, 4 > barriers ;
102+ SmallVector<SILInstruction *, 4 > instructions ;
106103
107104 // / Blocks one of whose phis is a barrier and consequently out of which
108105 // / destroy_values cannot be hoisted.
109- SmallVector<SILBasicBlock *, 4 > phiBarriers;
106+ SmallVector<SILBasicBlock *, 4 > phis;
107+
108+ SmallVector<SILBasicBlock *, 4 > blocks;
110109
111- DeinitBarriers (Context &context)
112- : hoistingReachesBeginBlocks(&context.function),
113- hoistingReachesEndBlocks (&context.function) {}
110+ DeinitBarriers (Context &context) {}
114111 DeinitBarriers (DeinitBarriers const &) = delete ;
115112 DeinitBarriers &operator =(DeinitBarriers const &) = delete ;
116113};
117114
118115// / Works backwards from the current location of destroy_values to the earliest
119116// / place they can be hoisted to.
120117// /
121- // / Implements BackwardReachability::BlockReachability.
118+ // / Implements IterativeBackwardReachability::Effects
119+ // / Implements IterativeBackwardReachability::bindBarriers::Visitor
122120class Dataflow final {
121+ using Reachability = IterativeBackwardReachability<Dataflow>;
122+ using Effect = Reachability::Effect;
123123 Context const &context;
124124 Usage const &uses;
125- DeinitBarriers &result;
125+ DeinitBarriers &barriers;
126+ Reachability::Result result;
127+ Reachability reachability;
126128
127129 enum class Classification { Barrier, Other };
128130
129- BackwardReachability<Dataflow> reachability;
130-
131131public:
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) {}
141136 Dataflow (Dataflow const &) = delete;
142137 Dataflow &operator =(Dataflow const &) = delete ;
143138
144- void run () { reachability. solveBackward (); }
139+ void run ();
145140
146141private:
147- friend class BackwardReachability <Dataflow> ;
142+ friend Reachability ;
148143
149- bool hasReachableBegin (SILBasicBlock *block) {
150- return result.hoistingReachesBeginBlocks .contains (block);
151- }
144+ Classification classifyInstruction (SILInstruction *);
152145
153- void markReachableBegin (SILBasicBlock *block) {
154- result.hoistingReachesBeginBlocks .insert (block);
155- }
146+ bool classificationIsBarrier (Classification);
156147
157- void markReachableEnd (SILBasicBlock *block) {
158- result.hoistingReachesEndBlocks .insert (block);
159- }
148+ // / IterativeBackwardReachability::Effects
160149
161- Classification classifyInstruction ( SILInstruction *);
150+ ArrayRef< SILInstruction *> gens () { return uses. ends ; }
162151
163- bool classificationIsBarrier (Classification);
152+ Effect effectForInstruction (SILInstruction *);
153+ Effect effectForPhi (SILBasicBlock *);
164154
165- void visitedInstruction (SILInstruction *, Classification);
155+ // / IterativeBackwardReachability::bindBarriers::Visitor
166156
167- bool checkReachableBarrier (SILInstruction *);
157+ void visitBarrierInstruction (SILInstruction *instruction) {
158+ barriers.instructions .push_back (instruction);
159+ }
168160
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+ }
170166};
171167
172168Dataflow::Classification
@@ -193,26 +189,15 @@ bool Dataflow::classificationIsBarrier(Classification classification) {
193189 llvm_unreachable (" exhaustive switch not exhaustive?!" );
194190}
195191
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 ();
210195 auto classification = classifyInstruction (instruction);
211- visitedInstruction (instruction, classification);
212- return classificationIsBarrier (classification );
196+ return classificationIsBarrier ( classification) ? Effect::Kill ()
197+ : Effect::NoEffect ( );
213198}
214199
215- bool Dataflow::checkReachablePhiBarrier (SILBasicBlock *block) {
200+ Dataflow::Effect Dataflow::effectForPhi (SILBasicBlock *block) {
216201 assert (llvm::all_of (block->getArguments (),
217202 [&](auto argument) { return PhiValue (argument); }));
218203
@@ -221,10 +206,13 @@ bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) {
221206 return classificationIsBarrier (
222207 classifyInstruction (predecessor->getTerminator ()));
223208 });
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 );
228216}
229217
230218// / Hoist the destroy_values of %value.
@@ -256,7 +244,7 @@ bool Rewriter::run() {
256244 //
257245 // A block is a phi barrier iff any of its predecessors' terminators get
258246 // classified as barriers.
259- for (auto *block : barriers.phiBarriers ) {
247+ for (auto *block : barriers.phis ) {
260248 madeChange |= createDestroyValue (&block->front ());
261249 }
262250
@@ -271,13 +259,9 @@ bool Rewriter::run() {
271259 // have returned true for P, so none of its instructions would ever have been
272260 // classified (except for via checkReachablePhiBarrier, which doesn't record
273261 // terminator barriers).
274- for (auto instruction : barriers.barriers ) {
262+ for (auto instruction : barriers.instructions ) {
275263 if (auto *terminator = dyn_cast<TermInst>(instruction)) {
276264 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 ()));
281265 for (auto *successor : successors) {
282266 madeChange |= createDestroyValue (&successor->front ());
283267 }
@@ -301,12 +285,8 @@ bool Rewriter::run() {
301285 // P not having a reachable end--see BackwardReachability::meetOverSuccessors.
302286 //
303287 // 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 ());
310290 }
311291
312292 if (madeChange) {
@@ -324,7 +304,7 @@ bool Rewriter::run() {
324304
325305bool Rewriter::createDestroyValue (SILInstruction *insertionPoint) {
326306 if (auto *ebi = dyn_cast<DestroyValueInst>(insertionPoint)) {
327- if (uses.ends . contains (insertionPoint )) {
307+ if (llvm::find ( uses.ends , insertionPoint) != uses. ends . end ( )) {
328308 reusedDestroyValueInsts.insert (insertionPoint);
329309 return false ;
330310 }
0 commit comments