|
| 1 | +//===--- VisitBarrierAccessScopes.h - Find access scopes with barriers ----===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | +// |
| 13 | +// Given a region of a function, backwards-reachable from some set of roots, on |
| 14 | +// which gen/kill effects can be determined, determines which access scopes must |
| 15 | +// also be treated as kills in view of the rule that a kill within an access |
| 16 | +// scope makes the access scope itself a kill. |
| 17 | +// |
| 18 | +//===----------------------------------------------------------------------===// |
| 19 | + |
| 20 | +#include "swift/SIL/BasicBlockDatastructures.h" |
| 21 | +#include "swift/SIL/BasicBlockUtils.h" |
| 22 | +#include "llvm/ADT/DenseMap.h" |
| 23 | +#include "llvm/ADT/Optional.h" |
| 24 | +#include "llvm/ADT/SmallPtrSet.h" |
| 25 | + |
| 26 | +namespace swift { |
| 27 | + |
| 28 | +class BeginAccessInst; |
| 29 | +class EndAccessInst; |
| 30 | +class SILInstruction; |
| 31 | +class SILBasicBlock; |
| 32 | +class SILInstruction; |
| 33 | + |
| 34 | +/// Visits the begin_access instructions that must be regarded as barriers |
| 35 | +/// because they contain barriers. |
| 36 | +/// |
| 37 | +/// interface Effects { |
| 38 | +/// /// The effect, if any, of the specified instruction. |
| 39 | +/// Optional<Effects::Effect> effectForPhi(SILBasicBlock *) |
| 40 | +/// |
| 41 | +/// /// The effect, if any, of the phis of the specified block. |
| 42 | +/// Optional<Effects::Effect> effectForInstruction(SILInstruction *) |
| 43 | +/// } |
| 44 | +/// interface Visitor { |
| 45 | +/// /// Whether the indicated basic block is within the region of the graph |
| 46 | +/// /// that should be traversed. |
| 47 | +/// bool isInRegion(SILBasicBlock *block) |
| 48 | +/// |
| 49 | +/// /// The roots from which all blocks in the region are backwards-reachable. |
| 50 | +/// ArrayRef<SILBasicBlock *> roots(); |
| 51 | +/// |
| 52 | +/// /// Visit each discovered begin_access instruction which defines a barrier |
| 53 | +/// /// scope. |
| 54 | +/// void visitBarrierAccessScope(BeginAccessInst *) |
| 55 | +/// } |
| 56 | +template <typename Effects, typename Visitor> |
| 57 | +class VisitBarrierAccessScopes { |
| 58 | + using This = VisitBarrierAccessScopes<Effects, Visitor>; |
| 59 | + /// Describes the effect, if any, of each instruction and phi. |
| 60 | + Effects &effects; |
| 61 | + /// Describes the search region and visits the found barriers. |
| 62 | + Visitor &visitor; |
| 63 | + /// The function in which to find barrier access scopes. |
| 64 | + SILFunction *function; |
| 65 | + /// The blocks which have already been visited. Used to determine whether a |
| 66 | + /// block being visited is a barrier block. |
| 67 | + BasicBlockSet visited; |
| 68 | + |
| 69 | + /// The access scopes that are live at the begin of each block after visiting |
| 70 | + /// all the block's predecessors and its instructions. |
| 71 | + llvm::DenseMap<SILBasicBlock *, llvm::SmallPtrSet<BeginAccessInst *, 2>> |
| 72 | + liveInAccessScopes; |
| 73 | + /// While visiting a block's instructions, the access scopes that are |
| 74 | + /// currently live. |
| 75 | + llvm::SmallPtrSet<BeginAccessInst *, 2> runningLiveAccessScopes; |
| 76 | + /// The blocks in the region, in topological order. |
| 77 | + SmallVector<SILBasicBlock *, 32> order; |
| 78 | + |
| 79 | +public: |
| 80 | + VisitBarrierAccessScopes(SILFunction *function, Effects &effects, |
| 81 | + Visitor &visitor) |
| 82 | + : effects(effects), visitor(visitor), function(function), |
| 83 | + visited(function){}; |
| 84 | + |
| 85 | + /// Visit the begin_access instructions. |
| 86 | + /// |
| 87 | + /// Sort the backwards-reachable, in-region blocks topologically. Then visit |
| 88 | + /// them in the reverse of that order, so that when any block is visited, all |
| 89 | + /// of its non-backedge* successors will already have been visited. |
| 90 | + /// |
| 91 | + /// While visiting, which access scopes are live within blocks is tracked, |
| 92 | + /// storing the access scopes that are live at the begin of a block, and |
| 93 | + /// noting that every access scope live at the begin of any successor is also |
| 94 | + /// live at the end of a block. |
| 95 | + /// |
| 96 | + /// * These are backedges in the reversed graph, that are ignored in a reverse |
| 97 | + /// depth-first search. |
| 98 | + void visit() { |
| 99 | + visitSortedTopologicallyBackwards(function, visitor.roots(), *this); |
| 100 | + for (auto *block : llvm::reverse(order)) { |
| 101 | + visitBlock(block); |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + /// visitSortedTopologicallyBackwards::Visitor |
| 106 | + |
| 107 | + /// Whether the block is in the region of interest. Just a passhthrough to |
| 108 | + /// our visitor. |
| 109 | + bool isInRegion(SILBasicBlock *block) { return visitor.isInRegion(block); } |
| 110 | + |
| 111 | + /// Called for each block in the region in topological order. Record the |
| 112 | + /// order into \p order so that we can visit the blocks in the reverse of that |
| 113 | + /// order. |
| 114 | + void visit(SILBasicBlock *block) { order.push_back(block); } |
| 115 | + |
| 116 | +private: |
| 117 | + /// Block visitation |
| 118 | + |
| 119 | + void visitBlock(SILBasicBlock *block) { |
| 120 | + visitBlockEnd(block); |
| 121 | + for (auto &instruction : llvm::reverse(*block)) { |
| 122 | + visitInstruction(&instruction); |
| 123 | + } |
| 124 | + if (block->hasPhi()) |
| 125 | + visitPhi(block); |
| 126 | + visitBlockBegin(block); |
| 127 | + } |
| 128 | + |
| 129 | + void visitInstruction(SILInstruction *instruction) { |
| 130 | + if (auto *eai = dyn_cast<EndAccessInst>(instruction)) { |
| 131 | + runningLiveAccessScopes.insert(eai->getBeginAccess()); |
| 132 | + } else if (auto *bai = dyn_cast<BeginAccessInst>(instruction)) { |
| 133 | + runningLiveAccessScopes.erase(bai); |
| 134 | + } |
| 135 | + handleEffect(effects.effectForInstruction(instruction)); |
| 136 | + } |
| 137 | + |
| 138 | + void visitPhi(SILBasicBlock *block) { |
| 139 | + handleEffect(effects.effectForPhi(block)); |
| 140 | + } |
| 141 | + |
| 142 | + void visitBlockBegin(SILBasicBlock *block) { |
| 143 | + if (!runningLiveAccessScopes.empty()) { |
| 144 | + liveInAccessScopes[block] = runningLiveAccessScopes; |
| 145 | + } |
| 146 | + } |
| 147 | + |
| 148 | + void visitBlockEnd(SILBasicBlock *block) { |
| 149 | + visited.insert(block); |
| 150 | + runningLiveAccessScopes.clear(); |
| 151 | + for (auto *successor : block->getSuccessorBlocks()) { |
| 152 | + auto iterator = liveInAccessScopes.find(successor); |
| 153 | + if (iterator != liveInAccessScopes.end()) { |
| 154 | + for (auto *bai : iterator->getSecond()) { |
| 155 | + runningLiveAccessScopes.insert(bai); |
| 156 | + } |
| 157 | + } |
| 158 | + } |
| 159 | + // If any of this block's predecessors haven't already been visited, it |
| 160 | + // means that they aren't in the region and consequently this block is a |
| 161 | + // barrier block. |
| 162 | + if (llvm::any_of(block->getSuccessorBlocks(), [&](SILBasicBlock *block) { |
| 163 | + return !visited.contains(block); |
| 164 | + })) |
| 165 | + handleBarrier(); |
| 166 | + } |
| 167 | + |
| 168 | + /// Effect procecessing |
| 169 | + |
| 170 | + void handleEffect(typename Effects::Effect effect) { |
| 171 | + switch (effect.value) { |
| 172 | + case Effects::Effect::Value::NoEffect: |
| 173 | + return; |
| 174 | + case Effects::Effect::Value::Gen: |
| 175 | + runningLiveAccessScopes.clear(); |
| 176 | + return; |
| 177 | + case Effects::Effect::Value::Kill: |
| 178 | + handleBarrier(); |
| 179 | + return; |
| 180 | + } |
| 181 | + } |
| 182 | + |
| 183 | + void handleBarrier() { |
| 184 | + for (auto *scope : runningLiveAccessScopes) { |
| 185 | + visitor.visitBarrierAccessScope(scope); |
| 186 | + } |
| 187 | + } |
| 188 | +}; |
| 189 | + |
| 190 | +} // end namespace swift |
0 commit comments