annotate llvm/lib/Analysis/SyncDependenceAnalysis.cpp @ 204:e348f3e5c8b2

ReadFromString worked.
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 05 Jun 2021 15:35:13 +0900
parents 0572611fdcc8
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- SyncDependenceAnalysis.cpp - Divergent Branch Dependence Calculation
anatofuz
parents:
diff changeset
2 //--===//
anatofuz
parents:
diff changeset
3 //
anatofuz
parents:
diff changeset
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
5 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
7 //
anatofuz
parents:
diff changeset
8 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
9 //
anatofuz
parents:
diff changeset
10 // This file implements an algorithm that returns for a divergent branch
anatofuz
parents:
diff changeset
11 // the set of basic blocks whose phi nodes become divergent due to divergent
anatofuz
parents:
diff changeset
12 // control. These are the blocks that are reachable by two disjoint paths from
anatofuz
parents:
diff changeset
13 // the branch or loop exits that have a reaching path that is disjoint from a
anatofuz
parents:
diff changeset
14 // path to the loop latch.
anatofuz
parents:
diff changeset
15 //
anatofuz
parents:
diff changeset
16 // The SyncDependenceAnalysis is used in the DivergenceAnalysis to model
anatofuz
parents:
diff changeset
17 // control-induced divergence in phi nodes.
anatofuz
parents:
diff changeset
18 //
anatofuz
parents:
diff changeset
19 // -- Summary --
anatofuz
parents:
diff changeset
20 // The SyncDependenceAnalysis lazily computes sync dependences [3].
anatofuz
parents:
diff changeset
21 // The analysis evaluates the disjoint path criterion [2] by a reduction
anatofuz
parents:
diff changeset
22 // to SSA construction. The SSA construction algorithm is implemented as
anatofuz
parents:
diff changeset
23 // a simple data-flow analysis [1].
anatofuz
parents:
diff changeset
24 //
anatofuz
parents:
diff changeset
25 // [1] "A Simple, Fast Dominance Algorithm", SPI '01, Cooper, Harvey and Kennedy
anatofuz
parents:
diff changeset
26 // [2] "Efficiently Computing Static Single Assignment Form
anatofuz
parents:
diff changeset
27 // and the Control Dependence Graph", TOPLAS '91,
anatofuz
parents:
diff changeset
28 // Cytron, Ferrante, Rosen, Wegman and Zadeck
anatofuz
parents:
diff changeset
29 // [3] "Improving Performance of OpenCL on CPUs", CC '12, Karrenberg and Hack
anatofuz
parents:
diff changeset
30 // [4] "Divergence Analysis", TOPLAS '13, Sampaio, Souza, Collange and Pereira
anatofuz
parents:
diff changeset
31 //
anatofuz
parents:
diff changeset
32 // -- Sync dependence --
anatofuz
parents:
diff changeset
33 // Sync dependence [4] characterizes the control flow aspect of the
anatofuz
parents:
diff changeset
34 // propagation of branch divergence. For example,
anatofuz
parents:
diff changeset
35 //
anatofuz
parents:
diff changeset
36 // %cond = icmp slt i32 %tid, 10
anatofuz
parents:
diff changeset
37 // br i1 %cond, label %then, label %else
anatofuz
parents:
diff changeset
38 // then:
anatofuz
parents:
diff changeset
39 // br label %merge
anatofuz
parents:
diff changeset
40 // else:
anatofuz
parents:
diff changeset
41 // br label %merge
anatofuz
parents:
diff changeset
42 // merge:
anatofuz
parents:
diff changeset
43 // %a = phi i32 [ 0, %then ], [ 1, %else ]
anatofuz
parents:
diff changeset
44 //
anatofuz
parents:
diff changeset
45 // Suppose %tid holds the thread ID. Although %a is not data dependent on %tid
anatofuz
parents:
diff changeset
46 // because %tid is not on its use-def chains, %a is sync dependent on %tid
anatofuz
parents:
diff changeset
47 // because the branch "br i1 %cond" depends on %tid and affects which value %a
anatofuz
parents:
diff changeset
48 // is assigned to.
anatofuz
parents:
diff changeset
49 //
anatofuz
parents:
diff changeset
50 // -- Reduction to SSA construction --
anatofuz
parents:
diff changeset
51 // There are two disjoint paths from A to X, if a certain variant of SSA
anatofuz
parents:
diff changeset
52 // construction places a phi node in X under the following set-up scheme [2].
anatofuz
parents:
diff changeset
53 //
anatofuz
parents:
diff changeset
54 // This variant of SSA construction ignores incoming undef values.
anatofuz
parents:
diff changeset
55 // That is paths from the entry without a definition do not result in
anatofuz
parents:
diff changeset
56 // phi nodes.
anatofuz
parents:
diff changeset
57 //
anatofuz
parents:
diff changeset
58 // entry
anatofuz
parents:
diff changeset
59 // / \
anatofuz
parents:
diff changeset
60 // A \
anatofuz
parents:
diff changeset
61 // / \ Y
anatofuz
parents:
diff changeset
62 // B C /
anatofuz
parents:
diff changeset
63 // \ / \ /
anatofuz
parents:
diff changeset
64 // D E
anatofuz
parents:
diff changeset
65 // \ /
anatofuz
parents:
diff changeset
66 // F
anatofuz
parents:
diff changeset
67 // Assume that A contains a divergent branch. We are interested
anatofuz
parents:
diff changeset
68 // in the set of all blocks where each block is reachable from A
anatofuz
parents:
diff changeset
69 // via two disjoint paths. This would be the set {D, F} in this
anatofuz
parents:
diff changeset
70 // case.
anatofuz
parents:
diff changeset
71 // To generally reduce this query to SSA construction we introduce
anatofuz
parents:
diff changeset
72 // a virtual variable x and assign to x different values in each
anatofuz
parents:
diff changeset
73 // successor block of A.
anatofuz
parents:
diff changeset
74 // entry
anatofuz
parents:
diff changeset
75 // / \
anatofuz
parents:
diff changeset
76 // A \
anatofuz
parents:
diff changeset
77 // / \ Y
anatofuz
parents:
diff changeset
78 // x = 0 x = 1 /
anatofuz
parents:
diff changeset
79 // \ / \ /
anatofuz
parents:
diff changeset
80 // D E
anatofuz
parents:
diff changeset
81 // \ /
anatofuz
parents:
diff changeset
82 // F
anatofuz
parents:
diff changeset
83 // Our flavor of SSA construction for x will construct the following
anatofuz
parents:
diff changeset
84 // entry
anatofuz
parents:
diff changeset
85 // / \
anatofuz
parents:
diff changeset
86 // A \
anatofuz
parents:
diff changeset
87 // / \ Y
anatofuz
parents:
diff changeset
88 // x0 = 0 x1 = 1 /
anatofuz
parents:
diff changeset
89 // \ / \ /
anatofuz
parents:
diff changeset
90 // x2=phi E
anatofuz
parents:
diff changeset
91 // \ /
anatofuz
parents:
diff changeset
92 // x3=phi
anatofuz
parents:
diff changeset
93 // The blocks D and F contain phi nodes and are thus each reachable
anatofuz
parents:
diff changeset
94 // by two disjoins paths from A.
anatofuz
parents:
diff changeset
95 //
anatofuz
parents:
diff changeset
96 // -- Remarks --
anatofuz
parents:
diff changeset
97 // In case of loop exits we need to check the disjoint path criterion for loops
anatofuz
parents:
diff changeset
98 // [2]. To this end, we check whether the definition of x differs between the
anatofuz
parents:
diff changeset
99 // loop exit and the loop header (_after_ SSA construction).
anatofuz
parents:
diff changeset
100 //
anatofuz
parents:
diff changeset
101 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
102 #include "llvm/ADT/PostOrderIterator.h"
anatofuz
parents:
diff changeset
103 #include "llvm/ADT/SmallPtrSet.h"
anatofuz
parents:
diff changeset
104 #include "llvm/Analysis/PostDominators.h"
anatofuz
parents:
diff changeset
105 #include "llvm/Analysis/SyncDependenceAnalysis.h"
anatofuz
parents:
diff changeset
106 #include "llvm/IR/BasicBlock.h"
anatofuz
parents:
diff changeset
107 #include "llvm/IR/CFG.h"
anatofuz
parents:
diff changeset
108 #include "llvm/IR/Dominators.h"
anatofuz
parents:
diff changeset
109 #include "llvm/IR/Function.h"
anatofuz
parents:
diff changeset
110
anatofuz
parents:
diff changeset
111 #include <stack>
anatofuz
parents:
diff changeset
112 #include <unordered_set>
anatofuz
parents:
diff changeset
113
anatofuz
parents:
diff changeset
114 #define DEBUG_TYPE "sync-dependence"
anatofuz
parents:
diff changeset
115
anatofuz
parents:
diff changeset
116 namespace llvm {
anatofuz
parents:
diff changeset
117
anatofuz
parents:
diff changeset
118 ConstBlockSet SyncDependenceAnalysis::EmptyBlockSet;
anatofuz
parents:
diff changeset
119
anatofuz
parents:
diff changeset
120 SyncDependenceAnalysis::SyncDependenceAnalysis(const DominatorTree &DT,
anatofuz
parents:
diff changeset
121 const PostDominatorTree &PDT,
anatofuz
parents:
diff changeset
122 const LoopInfo &LI)
anatofuz
parents:
diff changeset
123 : FuncRPOT(DT.getRoot()->getParent()), DT(DT), PDT(PDT), LI(LI) {}
anatofuz
parents:
diff changeset
124
anatofuz
parents:
diff changeset
125 SyncDependenceAnalysis::~SyncDependenceAnalysis() {}
anatofuz
parents:
diff changeset
126
anatofuz
parents:
diff changeset
127 using FunctionRPOT = ReversePostOrderTraversal<const Function *>;
anatofuz
parents:
diff changeset
128
anatofuz
parents:
diff changeset
129 // divergence propagator for reducible CFGs
anatofuz
parents:
diff changeset
130 struct DivergencePropagator {
anatofuz
parents:
diff changeset
131 const FunctionRPOT &FuncRPOT;
anatofuz
parents:
diff changeset
132 const DominatorTree &DT;
anatofuz
parents:
diff changeset
133 const PostDominatorTree &PDT;
anatofuz
parents:
diff changeset
134 const LoopInfo &LI;
anatofuz
parents:
diff changeset
135
anatofuz
parents:
diff changeset
136 // identified join points
anatofuz
parents:
diff changeset
137 std::unique_ptr<ConstBlockSet> JoinBlocks;
anatofuz
parents:
diff changeset
138
anatofuz
parents:
diff changeset
139 // reached loop exits (by a path disjoint to a path to the loop header)
anatofuz
parents:
diff changeset
140 SmallPtrSet<const BasicBlock *, 4> ReachedLoopExits;
anatofuz
parents:
diff changeset
141
anatofuz
parents:
diff changeset
142 // if DefMap[B] == C then C is the dominating definition at block B
anatofuz
parents:
diff changeset
143 // if DefMap[B] ~ undef then we haven't seen B yet
anatofuz
parents:
diff changeset
144 // if DefMap[B] == B then B is a join point of disjoint paths from X or B is
anatofuz
parents:
diff changeset
145 // an immediate successor of X (initial value).
anatofuz
parents:
diff changeset
146 using DefiningBlockMap = std::map<const BasicBlock *, const BasicBlock *>;
anatofuz
parents:
diff changeset
147 DefiningBlockMap DefMap;
anatofuz
parents:
diff changeset
148
anatofuz
parents:
diff changeset
149 // all blocks with pending visits
anatofuz
parents:
diff changeset
150 std::unordered_set<const BasicBlock *> PendingUpdates;
anatofuz
parents:
diff changeset
151
anatofuz
parents:
diff changeset
152 DivergencePropagator(const FunctionRPOT &FuncRPOT, const DominatorTree &DT,
anatofuz
parents:
diff changeset
153 const PostDominatorTree &PDT, const LoopInfo &LI)
anatofuz
parents:
diff changeset
154 : FuncRPOT(FuncRPOT), DT(DT), PDT(PDT), LI(LI),
anatofuz
parents:
diff changeset
155 JoinBlocks(new ConstBlockSet) {}
anatofuz
parents:
diff changeset
156
anatofuz
parents:
diff changeset
157 // set the definition at @block and mark @block as pending for a visit
anatofuz
parents:
diff changeset
158 void addPending(const BasicBlock &Block, const BasicBlock &DefBlock) {
anatofuz
parents:
diff changeset
159 bool WasAdded = DefMap.emplace(&Block, &DefBlock).second;
anatofuz
parents:
diff changeset
160 if (WasAdded)
anatofuz
parents:
diff changeset
161 PendingUpdates.insert(&Block);
anatofuz
parents:
diff changeset
162 }
anatofuz
parents:
diff changeset
163
anatofuz
parents:
diff changeset
164 void printDefs(raw_ostream &Out) {
anatofuz
parents:
diff changeset
165 Out << "Propagator::DefMap {\n";
anatofuz
parents:
diff changeset
166 for (const auto *Block : FuncRPOT) {
anatofuz
parents:
diff changeset
167 auto It = DefMap.find(Block);
anatofuz
parents:
diff changeset
168 Out << Block->getName() << " : ";
anatofuz
parents:
diff changeset
169 if (It == DefMap.end()) {
anatofuz
parents:
diff changeset
170 Out << "\n";
anatofuz
parents:
diff changeset
171 } else {
anatofuz
parents:
diff changeset
172 const auto *DefBlock = It->second;
anatofuz
parents:
diff changeset
173 Out << (DefBlock ? DefBlock->getName() : "<null>") << "\n";
anatofuz
parents:
diff changeset
174 }
anatofuz
parents:
diff changeset
175 }
anatofuz
parents:
diff changeset
176 Out << "}\n";
anatofuz
parents:
diff changeset
177 }
anatofuz
parents:
diff changeset
178
anatofuz
parents:
diff changeset
179 // process @succBlock with reaching definition @defBlock
anatofuz
parents:
diff changeset
180 // the original divergent branch was in @parentLoop (if any)
anatofuz
parents:
diff changeset
181 void visitSuccessor(const BasicBlock &SuccBlock, const Loop *ParentLoop,
anatofuz
parents:
diff changeset
182 const BasicBlock &DefBlock) {
anatofuz
parents:
diff changeset
183
anatofuz
parents:
diff changeset
184 // @succBlock is a loop exit
anatofuz
parents:
diff changeset
185 if (ParentLoop && !ParentLoop->contains(&SuccBlock)) {
anatofuz
parents:
diff changeset
186 DefMap.emplace(&SuccBlock, &DefBlock);
anatofuz
parents:
diff changeset
187 ReachedLoopExits.insert(&SuccBlock);
anatofuz
parents:
diff changeset
188 return;
anatofuz
parents:
diff changeset
189 }
anatofuz
parents:
diff changeset
190
anatofuz
parents:
diff changeset
191 // first reaching def?
anatofuz
parents:
diff changeset
192 auto ItLastDef = DefMap.find(&SuccBlock);
anatofuz
parents:
diff changeset
193 if (ItLastDef == DefMap.end()) {
anatofuz
parents:
diff changeset
194 addPending(SuccBlock, DefBlock);
anatofuz
parents:
diff changeset
195 return;
anatofuz
parents:
diff changeset
196 }
anatofuz
parents:
diff changeset
197
anatofuz
parents:
diff changeset
198 // a join of at least two definitions
anatofuz
parents:
diff changeset
199 if (ItLastDef->second != &DefBlock) {
anatofuz
parents:
diff changeset
200 // do we know this join already?
anatofuz
parents:
diff changeset
201 if (!JoinBlocks->insert(&SuccBlock).second)
anatofuz
parents:
diff changeset
202 return;
anatofuz
parents:
diff changeset
203
anatofuz
parents:
diff changeset
204 // update the definition
anatofuz
parents:
diff changeset
205 addPending(SuccBlock, SuccBlock);
anatofuz
parents:
diff changeset
206 }
anatofuz
parents:
diff changeset
207 }
anatofuz
parents:
diff changeset
208
anatofuz
parents:
diff changeset
209 // find all blocks reachable by two disjoint paths from @rootTerm.
anatofuz
parents:
diff changeset
210 // This method works for both divergent terminators and loops with
anatofuz
parents:
diff changeset
211 // divergent exits.
anatofuz
parents:
diff changeset
212 // @rootBlock is either the block containing the branch or the header of the
anatofuz
parents:
diff changeset
213 // divergent loop.
anatofuz
parents:
diff changeset
214 // @nodeSuccessors is the set of successors of the node (Loop or Terminator)
anatofuz
parents:
diff changeset
215 // headed by @rootBlock.
anatofuz
parents:
diff changeset
216 // @parentLoop is the parent loop of the Loop or the loop that contains the
anatofuz
parents:
diff changeset
217 // Terminator.
anatofuz
parents:
diff changeset
218 template <typename SuccessorIterable>
anatofuz
parents:
diff changeset
219 std::unique_ptr<ConstBlockSet>
anatofuz
parents:
diff changeset
220 computeJoinPoints(const BasicBlock &RootBlock,
anatofuz
parents:
diff changeset
221 SuccessorIterable NodeSuccessors, const Loop *ParentLoop) {
anatofuz
parents:
diff changeset
222 assert(JoinBlocks);
anatofuz
parents:
diff changeset
223
anatofuz
parents:
diff changeset
224 LLVM_DEBUG(dbgs() << "SDA:computeJoinPoints. Parent loop: " << (ParentLoop ? ParentLoop->getName() : "<null>") << "\n" );
anatofuz
parents:
diff changeset
225
anatofuz
parents:
diff changeset
226 // bootstrap with branch targets
anatofuz
parents:
diff changeset
227 for (const auto *SuccBlock : NodeSuccessors) {
anatofuz
parents:
diff changeset
228 DefMap.emplace(SuccBlock, SuccBlock);
anatofuz
parents:
diff changeset
229
anatofuz
parents:
diff changeset
230 if (ParentLoop && !ParentLoop->contains(SuccBlock)) {
anatofuz
parents:
diff changeset
231 // immediate loop exit from node.
anatofuz
parents:
diff changeset
232 ReachedLoopExits.insert(SuccBlock);
anatofuz
parents:
diff changeset
233 } else {
anatofuz
parents:
diff changeset
234 // regular successor
anatofuz
parents:
diff changeset
235 PendingUpdates.insert(SuccBlock);
anatofuz
parents:
diff changeset
236 }
anatofuz
parents:
diff changeset
237 }
anatofuz
parents:
diff changeset
238
anatofuz
parents:
diff changeset
239 LLVM_DEBUG(
anatofuz
parents:
diff changeset
240 dbgs() << "SDA: rpo order:\n";
anatofuz
parents:
diff changeset
241 for (const auto * RpoBlock : FuncRPOT) {
anatofuz
parents:
diff changeset
242 dbgs() << "- " << RpoBlock->getName() << "\n";
anatofuz
parents:
diff changeset
243 }
anatofuz
parents:
diff changeset
244 );
anatofuz
parents:
diff changeset
245
anatofuz
parents:
diff changeset
246 auto ItBeginRPO = FuncRPOT.begin();
anatofuz
parents:
diff changeset
247 auto ItEndRPO = FuncRPOT.end();
anatofuz
parents:
diff changeset
248
anatofuz
parents:
diff changeset
249 // skip until term (TODO RPOT won't let us start at @term directly)
anatofuz
parents:
diff changeset
250 for (; *ItBeginRPO != &RootBlock; ++ItBeginRPO) {
anatofuz
parents:
diff changeset
251 assert(ItBeginRPO != ItEndRPO && "Unable to find RootBlock");
anatofuz
parents:
diff changeset
252 }
anatofuz
parents:
diff changeset
253
anatofuz
parents:
diff changeset
254 // propagate definitions at the immediate successors of the node in RPO
anatofuz
parents:
diff changeset
255 auto ItBlockRPO = ItBeginRPO;
anatofuz
parents:
diff changeset
256 while ((++ItBlockRPO != ItEndRPO) &&
anatofuz
parents:
diff changeset
257 !PendingUpdates.empty()) {
anatofuz
parents:
diff changeset
258 const auto *Block = *ItBlockRPO;
anatofuz
parents:
diff changeset
259 LLVM_DEBUG(dbgs() << "SDA::joins. visiting " << Block->getName() << "\n");
anatofuz
parents:
diff changeset
260
anatofuz
parents:
diff changeset
261 // skip Block if not pending update
anatofuz
parents:
diff changeset
262 auto ItPending = PendingUpdates.find(Block);
anatofuz
parents:
diff changeset
263 if (ItPending == PendingUpdates.end())
anatofuz
parents:
diff changeset
264 continue;
anatofuz
parents:
diff changeset
265 PendingUpdates.erase(ItPending);
anatofuz
parents:
diff changeset
266
anatofuz
parents:
diff changeset
267 // propagate definition at Block to its successors
anatofuz
parents:
diff changeset
268 auto ItDef = DefMap.find(Block);
anatofuz
parents:
diff changeset
269 const auto *DefBlock = ItDef->second;
anatofuz
parents:
diff changeset
270 assert(DefBlock);
anatofuz
parents:
diff changeset
271
anatofuz
parents:
diff changeset
272 auto *BlockLoop = LI.getLoopFor(Block);
anatofuz
parents:
diff changeset
273 if (ParentLoop &&
anatofuz
parents:
diff changeset
274 (ParentLoop != BlockLoop && ParentLoop->contains(BlockLoop))) {
anatofuz
parents:
diff changeset
275 // if the successor is the header of a nested loop pretend its a
anatofuz
parents:
diff changeset
276 // single node with the loop's exits as successors
anatofuz
parents:
diff changeset
277 SmallVector<BasicBlock *, 4> BlockLoopExits;
anatofuz
parents:
diff changeset
278 BlockLoop->getExitBlocks(BlockLoopExits);
anatofuz
parents:
diff changeset
279 for (const auto *BlockLoopExit : BlockLoopExits) {
anatofuz
parents:
diff changeset
280 visitSuccessor(*BlockLoopExit, ParentLoop, *DefBlock);
anatofuz
parents:
diff changeset
281 }
anatofuz
parents:
diff changeset
282
anatofuz
parents:
diff changeset
283 } else {
anatofuz
parents:
diff changeset
284 // the successors are either on the same loop level or loop exits
anatofuz
parents:
diff changeset
285 for (const auto *SuccBlock : successors(Block)) {
anatofuz
parents:
diff changeset
286 visitSuccessor(*SuccBlock, ParentLoop, *DefBlock);
anatofuz
parents:
diff changeset
287 }
anatofuz
parents:
diff changeset
288 }
anatofuz
parents:
diff changeset
289 }
anatofuz
parents:
diff changeset
290
anatofuz
parents:
diff changeset
291 LLVM_DEBUG(dbgs() << "SDA::joins. After propagation:\n"; printDefs(dbgs()));
anatofuz
parents:
diff changeset
292
anatofuz
parents:
diff changeset
293 // We need to know the definition at the parent loop header to decide
anatofuz
parents:
diff changeset
294 // whether the definition at the header is different from the definition at
anatofuz
parents:
diff changeset
295 // the loop exits, which would indicate a divergent loop exits.
anatofuz
parents:
diff changeset
296 //
anatofuz
parents:
diff changeset
297 // A // loop header
anatofuz
parents:
diff changeset
298 // |
anatofuz
parents:
diff changeset
299 // B // nested loop header
anatofuz
parents:
diff changeset
300 // |
anatofuz
parents:
diff changeset
301 // C -> X (exit from B loop) -..-> (A latch)
anatofuz
parents:
diff changeset
302 // |
anatofuz
parents:
diff changeset
303 // D -> back to B (B latch)
anatofuz
parents:
diff changeset
304 // |
anatofuz
parents:
diff changeset
305 // proper exit from both loops
anatofuz
parents:
diff changeset
306 //
anatofuz
parents:
diff changeset
307 // analyze reached loop exits
anatofuz
parents:
diff changeset
308 if (!ReachedLoopExits.empty()) {
anatofuz
parents:
diff changeset
309 const BasicBlock *ParentLoopHeader =
anatofuz
parents:
diff changeset
310 ParentLoop ? ParentLoop->getHeader() : nullptr;
anatofuz
parents:
diff changeset
311
anatofuz
parents:
diff changeset
312 assert(ParentLoop);
anatofuz
parents:
diff changeset
313 auto ItHeaderDef = DefMap.find(ParentLoopHeader);
anatofuz
parents:
diff changeset
314 const auto *HeaderDefBlock = (ItHeaderDef == DefMap.end()) ? nullptr : ItHeaderDef->second;
anatofuz
parents:
diff changeset
315
anatofuz
parents:
diff changeset
316 LLVM_DEBUG(printDefs(dbgs()));
anatofuz
parents:
diff changeset
317 assert(HeaderDefBlock && "no definition at header of carrying loop");
anatofuz
parents:
diff changeset
318
anatofuz
parents:
diff changeset
319 for (const auto *ExitBlock : ReachedLoopExits) {
anatofuz
parents:
diff changeset
320 auto ItExitDef = DefMap.find(ExitBlock);
anatofuz
parents:
diff changeset
321 assert((ItExitDef != DefMap.end()) &&
anatofuz
parents:
diff changeset
322 "no reaching def at reachable loop exit");
anatofuz
parents:
diff changeset
323 if (ItExitDef->second != HeaderDefBlock) {
anatofuz
parents:
diff changeset
324 JoinBlocks->insert(ExitBlock);
anatofuz
parents:
diff changeset
325 }
anatofuz
parents:
diff changeset
326 }
anatofuz
parents:
diff changeset
327 }
anatofuz
parents:
diff changeset
328
anatofuz
parents:
diff changeset
329 return std::move(JoinBlocks);
anatofuz
parents:
diff changeset
330 }
anatofuz
parents:
diff changeset
331 };
anatofuz
parents:
diff changeset
332
anatofuz
parents:
diff changeset
333 const ConstBlockSet &SyncDependenceAnalysis::join_blocks(const Loop &Loop) {
anatofuz
parents:
diff changeset
334 using LoopExitVec = SmallVector<BasicBlock *, 4>;
anatofuz
parents:
diff changeset
335 LoopExitVec LoopExits;
anatofuz
parents:
diff changeset
336 Loop.getExitBlocks(LoopExits);
anatofuz
parents:
diff changeset
337 if (LoopExits.size() < 1) {
anatofuz
parents:
diff changeset
338 return EmptyBlockSet;
anatofuz
parents:
diff changeset
339 }
anatofuz
parents:
diff changeset
340
anatofuz
parents:
diff changeset
341 // already available in cache?
anatofuz
parents:
diff changeset
342 auto ItCached = CachedLoopExitJoins.find(&Loop);
anatofuz
parents:
diff changeset
343 if (ItCached != CachedLoopExitJoins.end()) {
anatofuz
parents:
diff changeset
344 return *ItCached->second;
anatofuz
parents:
diff changeset
345 }
anatofuz
parents:
diff changeset
346
anatofuz
parents:
diff changeset
347 // compute all join points
anatofuz
parents:
diff changeset
348 DivergencePropagator Propagator{FuncRPOT, DT, PDT, LI};
anatofuz
parents:
diff changeset
349 auto JoinBlocks = Propagator.computeJoinPoints<const LoopExitVec &>(
anatofuz
parents:
diff changeset
350 *Loop.getHeader(), LoopExits, Loop.getParentLoop());
anatofuz
parents:
diff changeset
351
anatofuz
parents:
diff changeset
352 auto ItInserted = CachedLoopExitJoins.emplace(&Loop, std::move(JoinBlocks));
anatofuz
parents:
diff changeset
353 assert(ItInserted.second);
anatofuz
parents:
diff changeset
354 return *ItInserted.first->second;
anatofuz
parents:
diff changeset
355 }
anatofuz
parents:
diff changeset
356
anatofuz
parents:
diff changeset
357 const ConstBlockSet &
anatofuz
parents:
diff changeset
358 SyncDependenceAnalysis::join_blocks(const Instruction &Term) {
anatofuz
parents:
diff changeset
359 // trivial case
anatofuz
parents:
diff changeset
360 if (Term.getNumSuccessors() < 1) {
anatofuz
parents:
diff changeset
361 return EmptyBlockSet;
anatofuz
parents:
diff changeset
362 }
anatofuz
parents:
diff changeset
363
anatofuz
parents:
diff changeset
364 // already available in cache?
anatofuz
parents:
diff changeset
365 auto ItCached = CachedBranchJoins.find(&Term);
anatofuz
parents:
diff changeset
366 if (ItCached != CachedBranchJoins.end())
anatofuz
parents:
diff changeset
367 return *ItCached->second;
anatofuz
parents:
diff changeset
368
anatofuz
parents:
diff changeset
369 // compute all join points
anatofuz
parents:
diff changeset
370 DivergencePropagator Propagator{FuncRPOT, DT, PDT, LI};
anatofuz
parents:
diff changeset
371 const auto &TermBlock = *Term.getParent();
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
372 auto JoinBlocks = Propagator.computeJoinPoints<const_succ_range>(
150
anatofuz
parents:
diff changeset
373 TermBlock, successors(Term.getParent()), LI.getLoopFor(&TermBlock));
anatofuz
parents:
diff changeset
374
anatofuz
parents:
diff changeset
375 auto ItInserted = CachedBranchJoins.emplace(&Term, std::move(JoinBlocks));
anatofuz
parents:
diff changeset
376 assert(ItInserted.second);
anatofuz
parents:
diff changeset
377 return *ItInserted.first->second;
anatofuz
parents:
diff changeset
378 }
anatofuz
parents:
diff changeset
379
anatofuz
parents:
diff changeset
380 } // namespace llvm