@@ -215,6 +215,8 @@ class DeinitBarriers {
215215 DeinitBarriers &result;
216216 SILInstruction *storageDefInst = nullptr ; // null for function args
217217
218+ enum class Classification { DeadUser, Barrier, Other };
219+
218220 BackwardReachability<DestroyReachability> reachability;
219221
220222 public:
@@ -245,37 +247,87 @@ class DeinitBarriers {
245247 result.destroyReachesEndBlocks .insert (block);
246248 }
247249
248- bool checkReachableBarrier (SILInstruction *inst);
250+ Classification classifyInstruction (SILInstruction *inst);
251+
252+ bool classificationIsBarrier (Classification classification);
253+
254+ void visitedInstruction (SILInstruction *instruction,
255+ Classification classification);
256+
257+ bool checkReachableBarrier (SILInstruction *);
258+
259+ bool checkReachablePhiBarrier (SILBasicBlock *);
249260
250261 void solveBackward () { reachability.solveBackward (); }
251262 };
252263};
253264
254- // / Return true if \p inst is a barrier.
255- // /
256- // / Called exactly once for each reachable instruction. This is guaranteed to
257- // / hold as a barrier occurs between any original destroys that are reachable
258- // / from each. Any path reaching multiple destroys requires initialization,
259- // / which is a storageUser and therefore a barrier.
260- bool DeinitBarriers::DestroyReachability::checkReachableBarrier (
261- SILInstruction *inst) {
265+ DeinitBarriers::DestroyReachability::Classification
266+ DeinitBarriers::DestroyReachability::classifyInstruction (SILInstruction *inst) {
262267 if (knownUses.debugInsts .contains (inst)) {
263- result.deadUsers .push_back (inst);
264- return false ;
268+ return Classification::DeadUser;
265269 }
266270 if (inst == storageDefInst) {
267271 result.barriers .push_back (inst);
268- return true ;
272+ return Classification::Barrier ;
269273 }
270274 if (knownUses.storageUsers .contains (inst)) {
271- result.barriers .push_back (inst);
272- return true ;
275+ return Classification::Barrier;
273276 }
274277 if (isDeinitBarrier (inst)) {
275- result.barriers .push_back (inst);
278+ return Classification::Barrier;
279+ }
280+ return Classification::Other;
281+ }
282+
283+ bool DeinitBarriers::DestroyReachability::classificationIsBarrier (
284+ Classification classification) {
285+ switch (classification) {
286+ case Classification::DeadUser:
287+ case Classification::Other:
288+ return false ;
289+ case Classification::Barrier:
276290 return true ;
277291 }
278- return false ;
292+ llvm_unreachable (" exhaustive switch is not exhaustive?!" );
293+ }
294+
295+ void DeinitBarriers::DestroyReachability::visitedInstruction (
296+ SILInstruction *instruction, Classification classification) {
297+ assert (classifyInstruction (instruction) == classification);
298+ switch (classification) {
299+ case Classification::DeadUser:
300+ result.deadUsers .push_back (instruction);
301+ break ;
302+ case Classification::Barrier:
303+ result.barriers .push_back (instruction);
304+ break ;
305+ case Classification::Other:
306+ break ;
307+ }
308+ }
309+
310+ // / Return true if \p inst is a barrier.
311+ // /
312+ // / Called exactly once for each reachable instruction. This is guaranteed to
313+ // / hold as a barrier occurs between any original destroys that are reachable
314+ // / from each. Any path reaching multiple destroys requires initialization,
315+ // / which is a storageUser and therefore a barrier.
316+ bool DeinitBarriers::DestroyReachability::checkReachableBarrier (
317+ SILInstruction *instruction) {
318+ auto classification = classifyInstruction (instruction);
319+ visitedInstruction (instruction, classification);
320+ return classificationIsBarrier (classification);
321+ }
322+
323+ bool DeinitBarriers::DestroyReachability::checkReachablePhiBarrier (
324+ SILBasicBlock *block) {
325+ assert (llvm::all_of (block->getArguments (),
326+ [&](auto argument) { return PhiValue (argument); }));
327+ return llvm::any_of (block->getPredecessorBlocks (), [&](auto *predecessor) {
328+ return classificationIsBarrier (
329+ classifyInstruction (predecessor->getTerminator ()));
330+ });
279331}
280332
281333// / Algorithm for hoisting the destroys of a single uniquely identified storage
0 commit comments