xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/ADT/GenericUniformityImpl.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===- GenericUniformityImpl.h -----------------------*- C++ -*------------===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric // This template implementation resides in a separate file so that it
10bdd1243dSDimitry Andric // does not get injected into every .cpp file that includes the
11bdd1243dSDimitry Andric // generic header.
12bdd1243dSDimitry Andric //
13bdd1243dSDimitry Andric // DO NOT INCLUDE THIS FILE WHEN MERELY USING UNIFORMITYINFO.
14bdd1243dSDimitry Andric //
15bdd1243dSDimitry Andric // This file should only be included by files that implement a
16bdd1243dSDimitry Andric // specialization of the relvant templates. Currently these are:
17bdd1243dSDimitry Andric // - UniformityAnalysis.cpp
18bdd1243dSDimitry Andric //
19bdd1243dSDimitry Andric // Note: The DEBUG_TYPE macro should be defined before using this
20bdd1243dSDimitry Andric // file so that any use of LLVM_DEBUG is associated with the
21bdd1243dSDimitry Andric // including file rather than this file.
22bdd1243dSDimitry Andric //
23bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
24bdd1243dSDimitry Andric ///
25bdd1243dSDimitry Andric /// \file
26bdd1243dSDimitry Andric /// \brief Implementation of uniformity analysis.
27bdd1243dSDimitry Andric ///
28bdd1243dSDimitry Andric /// The algorithm is a fixed point iteration that starts with the assumption
29bdd1243dSDimitry Andric /// that all control flow and all values are uniform. Starting from sources of
30bdd1243dSDimitry Andric /// divergence (whose discovery must be implemented by a CFG- or even
31bdd1243dSDimitry Andric /// target-specific derived class), divergence of values is propagated from
32bdd1243dSDimitry Andric /// definition to uses in a straight-forward way. The main complexity lies in
33bdd1243dSDimitry Andric /// the propagation of the impact of divergent control flow on the divergence of
34bdd1243dSDimitry Andric /// values (sync dependencies).
35bdd1243dSDimitry Andric ///
36647cbc5dSDimitry Andric /// NOTE: In general, no interface exists for a transform to update
37647cbc5dSDimitry Andric /// (Machine)UniformityInfo. Additionally, (Machine)CycleAnalysis is a
38647cbc5dSDimitry Andric /// transitive dependence, but it also does not provide an interface for
39647cbc5dSDimitry Andric /// updating itself. Given that, transforms should not preserve uniformity in
40647cbc5dSDimitry Andric /// their getAnalysisUsage() callback.
41647cbc5dSDimitry Andric ///
42bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
43bdd1243dSDimitry Andric 
44bdd1243dSDimitry Andric #ifndef LLVM_ADT_GENERICUNIFORMITYIMPL_H
45bdd1243dSDimitry Andric #define LLVM_ADT_GENERICUNIFORMITYIMPL_H
46bdd1243dSDimitry Andric 
47bdd1243dSDimitry Andric #include "llvm/ADT/GenericUniformityInfo.h"
48bdd1243dSDimitry Andric 
49*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseSet.h"
50*0fca6ea1SDimitry Andric #include "llvm/ADT/STLExtras.h"
51bdd1243dSDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
52bdd1243dSDimitry Andric #include "llvm/ADT/SparseBitVector.h"
53bdd1243dSDimitry Andric #include "llvm/ADT/StringExtras.h"
54bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h"
55bdd1243dSDimitry Andric 
56bdd1243dSDimitry Andric #define DEBUG_TYPE "uniformity"
57bdd1243dSDimitry Andric 
58bdd1243dSDimitry Andric namespace llvm {
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric /// Construct a specially modified post-order traversal of cycles.
61bdd1243dSDimitry Andric ///
62bdd1243dSDimitry Andric /// The ModifiedPO is contructed using a virtually modified CFG as follows:
63bdd1243dSDimitry Andric ///
64bdd1243dSDimitry Andric /// 1. The successors of pre-entry nodes (predecessors of an cycle
65bdd1243dSDimitry Andric ///    entry that are outside the cycle) are replaced by the
66bdd1243dSDimitry Andric ///    successors of the successors of the header.
67bdd1243dSDimitry Andric /// 2. Successors of the cycle header are replaced by the exit blocks
68bdd1243dSDimitry Andric ///    of the cycle.
69bdd1243dSDimitry Andric ///
70bdd1243dSDimitry Andric /// Effectively, we produce a depth-first numbering with the following
71bdd1243dSDimitry Andric /// properties:
72bdd1243dSDimitry Andric ///
73bdd1243dSDimitry Andric /// 1. Nodes after a cycle are numbered earlier than the cycle header.
74bdd1243dSDimitry Andric /// 2. The header is numbered earlier than the nodes in the cycle.
75bdd1243dSDimitry Andric /// 3. The numbering of the nodes within the cycle forms an interval
76bdd1243dSDimitry Andric ///    starting with the header.
77bdd1243dSDimitry Andric ///
78bdd1243dSDimitry Andric /// Effectively, the virtual modification arranges the nodes in a
79bdd1243dSDimitry Andric /// cycle as a DAG with the header as the sole leaf, and successors of
80bdd1243dSDimitry Andric /// the header as the roots. A reverse traversal of this numbering has
81bdd1243dSDimitry Andric /// the following invariant on the unmodified original CFG:
82bdd1243dSDimitry Andric ///
83bdd1243dSDimitry Andric ///    Each node is visited after all its predecessors, except if that
84bdd1243dSDimitry Andric ///    predecessor is the cycle header.
85bdd1243dSDimitry Andric ///
86bdd1243dSDimitry Andric template <typename ContextT> class ModifiedPostOrder {
87bdd1243dSDimitry Andric public:
88bdd1243dSDimitry Andric   using BlockT = typename ContextT::BlockT;
89bdd1243dSDimitry Andric   using FunctionT = typename ContextT::FunctionT;
90bdd1243dSDimitry Andric   using DominatorTreeT = typename ContextT::DominatorTreeT;
91bdd1243dSDimitry Andric 
92bdd1243dSDimitry Andric   using CycleInfoT = GenericCycleInfo<ContextT>;
93bdd1243dSDimitry Andric   using CycleT = typename CycleInfoT::CycleT;
94bdd1243dSDimitry Andric   using const_iterator = typename std::vector<BlockT *>::const_iterator;
95bdd1243dSDimitry Andric 
96bdd1243dSDimitry Andric   ModifiedPostOrder(const ContextT &C) : Context(C) {}
97bdd1243dSDimitry Andric 
98bdd1243dSDimitry Andric   bool empty() const { return m_order.empty(); }
99bdd1243dSDimitry Andric   size_t size() const { return m_order.size(); }
100bdd1243dSDimitry Andric 
101bdd1243dSDimitry Andric   void clear() { m_order.clear(); }
102bdd1243dSDimitry Andric   void compute(const CycleInfoT &CI);
103bdd1243dSDimitry Andric 
104bdd1243dSDimitry Andric   unsigned count(BlockT *BB) const { return POIndex.count(BB); }
105bdd1243dSDimitry Andric   const BlockT *operator[](size_t idx) const { return m_order[idx]; }
106bdd1243dSDimitry Andric 
107bdd1243dSDimitry Andric   void appendBlock(const BlockT &BB, bool isReducibleCycleHeader = false) {
108bdd1243dSDimitry Andric     POIndex[&BB] = m_order.size();
109bdd1243dSDimitry Andric     m_order.push_back(&BB);
110bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "ModifiedPO(" << POIndex[&BB]
111bdd1243dSDimitry Andric                       << "): " << Context.print(&BB) << "\n");
112bdd1243dSDimitry Andric     if (isReducibleCycleHeader)
113bdd1243dSDimitry Andric       ReducibleCycleHeaders.insert(&BB);
114bdd1243dSDimitry Andric   }
115bdd1243dSDimitry Andric 
116bdd1243dSDimitry Andric   unsigned getIndex(const BlockT *BB) const {
117bdd1243dSDimitry Andric     assert(POIndex.count(BB));
118bdd1243dSDimitry Andric     return POIndex.lookup(BB);
119bdd1243dSDimitry Andric   }
120bdd1243dSDimitry Andric 
121bdd1243dSDimitry Andric   bool isReducibleCycleHeader(const BlockT *BB) const {
122bdd1243dSDimitry Andric     return ReducibleCycleHeaders.contains(BB);
123bdd1243dSDimitry Andric   }
124bdd1243dSDimitry Andric 
125bdd1243dSDimitry Andric private:
126bdd1243dSDimitry Andric   SmallVector<const BlockT *> m_order;
127bdd1243dSDimitry Andric   DenseMap<const BlockT *, unsigned> POIndex;
128bdd1243dSDimitry Andric   SmallPtrSet<const BlockT *, 32> ReducibleCycleHeaders;
129bdd1243dSDimitry Andric   const ContextT &Context;
130bdd1243dSDimitry Andric 
131bdd1243dSDimitry Andric   void computeCyclePO(const CycleInfoT &CI, const CycleT *Cycle,
1325f757f3fSDimitry Andric                       SmallPtrSetImpl<const BlockT *> &Finalized);
133bdd1243dSDimitry Andric 
1345f757f3fSDimitry Andric   void computeStackPO(SmallVectorImpl<const BlockT *> &Stack,
1355f757f3fSDimitry Andric                       const CycleInfoT &CI, const CycleT *Cycle,
1365f757f3fSDimitry Andric                       SmallPtrSetImpl<const BlockT *> &Finalized);
137bdd1243dSDimitry Andric };
138bdd1243dSDimitry Andric 
139bdd1243dSDimitry Andric template <typename> class DivergencePropagator;
140bdd1243dSDimitry Andric 
141bdd1243dSDimitry Andric /// \class GenericSyncDependenceAnalysis
142bdd1243dSDimitry Andric ///
143bdd1243dSDimitry Andric /// \brief Locate join blocks for disjoint paths starting at a divergent branch.
144bdd1243dSDimitry Andric ///
145bdd1243dSDimitry Andric /// An analysis per divergent branch that returns the set of basic
146bdd1243dSDimitry Andric /// blocks whose phi nodes become divergent due to divergent control.
147bdd1243dSDimitry Andric /// These are the blocks that are reachable by two disjoint paths from
148bdd1243dSDimitry Andric /// the branch, or cycle exits reachable along a path that is disjoint
149bdd1243dSDimitry Andric /// from a path to the cycle latch.
150bdd1243dSDimitry Andric 
151bdd1243dSDimitry Andric // --- Above line is not a doxygen comment; intentionally left blank ---
152bdd1243dSDimitry Andric //
153bdd1243dSDimitry Andric // Originally implemented in SyncDependenceAnalysis.cpp for DivergenceAnalysis.
154bdd1243dSDimitry Andric //
155bdd1243dSDimitry Andric // The SyncDependenceAnalysis is used in the UniformityAnalysis to model
156bdd1243dSDimitry Andric // control-induced divergence in phi nodes.
157bdd1243dSDimitry Andric //
158bdd1243dSDimitry Andric // -- Reference --
159bdd1243dSDimitry Andric // The algorithm is an extension of Section 5 of
160bdd1243dSDimitry Andric //
161bdd1243dSDimitry Andric //   An abstract interpretation for SPMD divergence
162bdd1243dSDimitry Andric //       on reducible control flow graphs.
163bdd1243dSDimitry Andric //   Julian Rosemann, Simon Moll and Sebastian Hack
164bdd1243dSDimitry Andric //   POPL '21
165bdd1243dSDimitry Andric //
166bdd1243dSDimitry Andric //
167bdd1243dSDimitry Andric // -- Sync dependence --
168bdd1243dSDimitry Andric // Sync dependence characterizes the control flow aspect of the
169bdd1243dSDimitry Andric // propagation of branch divergence. For example,
170bdd1243dSDimitry Andric //
171bdd1243dSDimitry Andric //   %cond = icmp slt i32 %tid, 10
172bdd1243dSDimitry Andric //   br i1 %cond, label %then, label %else
173bdd1243dSDimitry Andric // then:
174bdd1243dSDimitry Andric //   br label %merge
175bdd1243dSDimitry Andric // else:
176bdd1243dSDimitry Andric //   br label %merge
177bdd1243dSDimitry Andric // merge:
178bdd1243dSDimitry Andric //   %a = phi i32 [ 0, %then ], [ 1, %else ]
179bdd1243dSDimitry Andric //
180bdd1243dSDimitry Andric // Suppose %tid holds the thread ID. Although %a is not data dependent on %tid
181bdd1243dSDimitry Andric // because %tid is not on its use-def chains, %a is sync dependent on %tid
182bdd1243dSDimitry Andric // because the branch "br i1 %cond" depends on %tid and affects which value %a
183bdd1243dSDimitry Andric // is assigned to.
184bdd1243dSDimitry Andric //
185bdd1243dSDimitry Andric //
186bdd1243dSDimitry Andric // -- Reduction to SSA construction --
187bdd1243dSDimitry Andric // There are two disjoint paths from A to X, if a certain variant of SSA
188bdd1243dSDimitry Andric // construction places a phi node in X under the following set-up scheme.
189bdd1243dSDimitry Andric //
190bdd1243dSDimitry Andric // This variant of SSA construction ignores incoming undef values.
191bdd1243dSDimitry Andric // That is paths from the entry without a definition do not result in
192bdd1243dSDimitry Andric // phi nodes.
193bdd1243dSDimitry Andric //
194bdd1243dSDimitry Andric //       entry
195bdd1243dSDimitry Andric //     /      \
196bdd1243dSDimitry Andric //    A        \
197bdd1243dSDimitry Andric //  /   \       Y
198bdd1243dSDimitry Andric // B     C     /
199bdd1243dSDimitry Andric //  \   /  \  /
200bdd1243dSDimitry Andric //    D     E
201bdd1243dSDimitry Andric //     \   /
202bdd1243dSDimitry Andric //       F
203bdd1243dSDimitry Andric //
204bdd1243dSDimitry Andric // Assume that A contains a divergent branch. We are interested
205bdd1243dSDimitry Andric // in the set of all blocks where each block is reachable from A
206bdd1243dSDimitry Andric // via two disjoint paths. This would be the set {D, F} in this
207bdd1243dSDimitry Andric // case.
208bdd1243dSDimitry Andric // To generally reduce this query to SSA construction we introduce
209bdd1243dSDimitry Andric // a virtual variable x and assign to x different values in each
210bdd1243dSDimitry Andric // successor block of A.
211bdd1243dSDimitry Andric //
212bdd1243dSDimitry Andric //           entry
213bdd1243dSDimitry Andric //         /      \
214bdd1243dSDimitry Andric //        A        \
215bdd1243dSDimitry Andric //      /   \       Y
216bdd1243dSDimitry Andric // x = 0   x = 1   /
217bdd1243dSDimitry Andric //      \  /   \  /
218bdd1243dSDimitry Andric //        D     E
219bdd1243dSDimitry Andric //         \   /
220bdd1243dSDimitry Andric //           F
221bdd1243dSDimitry Andric //
222bdd1243dSDimitry Andric // Our flavor of SSA construction for x will construct the following
223bdd1243dSDimitry Andric //
224bdd1243dSDimitry Andric //            entry
225bdd1243dSDimitry Andric //          /      \
226bdd1243dSDimitry Andric //         A        \
227bdd1243dSDimitry Andric //       /   \       Y
228bdd1243dSDimitry Andric // x0 = 0   x1 = 1  /
229bdd1243dSDimitry Andric //       \   /   \ /
230bdd1243dSDimitry Andric //     x2 = phi   E
231bdd1243dSDimitry Andric //         \     /
232bdd1243dSDimitry Andric //         x3 = phi
233bdd1243dSDimitry Andric //
234bdd1243dSDimitry Andric // The blocks D and F contain phi nodes and are thus each reachable
235bdd1243dSDimitry Andric // by two disjoins paths from A.
236bdd1243dSDimitry Andric //
237bdd1243dSDimitry Andric // -- Remarks --
238bdd1243dSDimitry Andric // * In case of cycle exits we need to check for temporal divergence.
239bdd1243dSDimitry Andric //   To this end, we check whether the definition of x differs between the
240bdd1243dSDimitry Andric //   cycle exit and the cycle header (_after_ SSA construction).
241bdd1243dSDimitry Andric //
242bdd1243dSDimitry Andric // * In the presence of irreducible control flow, the fixed point is
243bdd1243dSDimitry Andric //   reached only after multiple iterations. This is because labels
244bdd1243dSDimitry Andric //   reaching the header of a cycle must be repropagated through the
245bdd1243dSDimitry Andric //   cycle. This is true even in a reducible cycle, since the labels
246bdd1243dSDimitry Andric //   may have been produced by a nested irreducible cycle.
247bdd1243dSDimitry Andric //
248bdd1243dSDimitry Andric // * Note that SyncDependenceAnalysis is not concerned with the points
249bdd1243dSDimitry Andric //   of convergence in an irreducible cycle. It's only purpose is to
250bdd1243dSDimitry Andric //   identify join blocks. The "diverged entry" criterion is
251bdd1243dSDimitry Andric //   separately applied on join blocks to determine if an entire
252bdd1243dSDimitry Andric //   irreducible cycle is assumed to be divergent.
253bdd1243dSDimitry Andric //
254bdd1243dSDimitry Andric // * Relevant related work:
255bdd1243dSDimitry Andric //     A simple algorithm for global data flow analysis problems.
256bdd1243dSDimitry Andric //     Matthew S. Hecht and Jeffrey D. Ullman.
257bdd1243dSDimitry Andric //     SIAM Journal on Computing, 4(4):519–532, December 1975.
258bdd1243dSDimitry Andric //
259bdd1243dSDimitry Andric template <typename ContextT> class GenericSyncDependenceAnalysis {
260bdd1243dSDimitry Andric public:
261bdd1243dSDimitry Andric   using BlockT = typename ContextT::BlockT;
262bdd1243dSDimitry Andric   using DominatorTreeT = typename ContextT::DominatorTreeT;
263bdd1243dSDimitry Andric   using FunctionT = typename ContextT::FunctionT;
264bdd1243dSDimitry Andric   using ValueRefT = typename ContextT::ValueRefT;
265bdd1243dSDimitry Andric   using InstructionT = typename ContextT::InstructionT;
266bdd1243dSDimitry Andric 
267bdd1243dSDimitry Andric   using CycleInfoT = GenericCycleInfo<ContextT>;
268bdd1243dSDimitry Andric   using CycleT = typename CycleInfoT::CycleT;
269bdd1243dSDimitry Andric 
270bdd1243dSDimitry Andric   using ConstBlockSet = SmallPtrSet<const BlockT *, 4>;
271bdd1243dSDimitry Andric   using ModifiedPO = ModifiedPostOrder<ContextT>;
272bdd1243dSDimitry Andric 
273bdd1243dSDimitry Andric   // * if BlockLabels[B] == C then C is the dominating definition at
274bdd1243dSDimitry Andric   //   block B
275bdd1243dSDimitry Andric   // * if BlockLabels[B] == nullptr then we haven't seen B yet
276bdd1243dSDimitry Andric   // * if BlockLabels[B] == B then:
277bdd1243dSDimitry Andric   //   - B is a join point of disjoint paths from X, or,
278bdd1243dSDimitry Andric   //   - B is an immediate successor of X (initial value), or,
279bdd1243dSDimitry Andric   //   - B is X
280bdd1243dSDimitry Andric   using BlockLabelMap = DenseMap<const BlockT *, const BlockT *>;
281bdd1243dSDimitry Andric 
282bdd1243dSDimitry Andric   /// Information discovered by the sync dependence analysis for each
283bdd1243dSDimitry Andric   /// divergent branch.
284bdd1243dSDimitry Andric   struct DivergenceDescriptor {
285bdd1243dSDimitry Andric     // Join points of diverged paths.
286bdd1243dSDimitry Andric     ConstBlockSet JoinDivBlocks;
287bdd1243dSDimitry Andric     // Divergent cycle exits
288bdd1243dSDimitry Andric     ConstBlockSet CycleDivBlocks;
289bdd1243dSDimitry Andric     // Labels assigned to blocks on diverged paths.
290bdd1243dSDimitry Andric     BlockLabelMap BlockLabels;
291bdd1243dSDimitry Andric   };
292bdd1243dSDimitry Andric 
293bdd1243dSDimitry Andric   using DivergencePropagatorT = DivergencePropagator<ContextT>;
294bdd1243dSDimitry Andric 
295bdd1243dSDimitry Andric   GenericSyncDependenceAnalysis(const ContextT &Context,
296bdd1243dSDimitry Andric                                 const DominatorTreeT &DT, const CycleInfoT &CI);
297bdd1243dSDimitry Andric 
298bdd1243dSDimitry Andric   /// \brief Computes divergent join points and cycle exits caused by branch
299bdd1243dSDimitry Andric   /// divergence in \p Term.
300bdd1243dSDimitry Andric   ///
301bdd1243dSDimitry Andric   /// This returns a pair of sets:
302bdd1243dSDimitry Andric   /// * The set of blocks which are reachable by disjoint paths from
303bdd1243dSDimitry Andric   ///   \p Term.
304bdd1243dSDimitry Andric   /// * The set also contains cycle exits if there two disjoint paths:
305bdd1243dSDimitry Andric   ///   one from \p Term to the cycle exit and another from \p Term to
306bdd1243dSDimitry Andric   ///   the cycle header.
307bdd1243dSDimitry Andric   const DivergenceDescriptor &getJoinBlocks(const BlockT *DivTermBlock);
308bdd1243dSDimitry Andric 
309bdd1243dSDimitry Andric private:
310bdd1243dSDimitry Andric   static DivergenceDescriptor EmptyDivergenceDesc;
311bdd1243dSDimitry Andric 
312bdd1243dSDimitry Andric   ModifiedPO CyclePO;
313bdd1243dSDimitry Andric 
314bdd1243dSDimitry Andric   const DominatorTreeT &DT;
315bdd1243dSDimitry Andric   const CycleInfoT &CI;
316bdd1243dSDimitry Andric 
317bdd1243dSDimitry Andric   DenseMap<const BlockT *, std::unique_ptr<DivergenceDescriptor>>
318bdd1243dSDimitry Andric       CachedControlDivDescs;
319bdd1243dSDimitry Andric };
320bdd1243dSDimitry Andric 
321bdd1243dSDimitry Andric /// \brief Analysis that identifies uniform values in a data-parallel
322bdd1243dSDimitry Andric /// execution.
323bdd1243dSDimitry Andric ///
324bdd1243dSDimitry Andric /// This analysis propagates divergence in a data-parallel context
325bdd1243dSDimitry Andric /// from sources of divergence to all users. It can be instantiated
326bdd1243dSDimitry Andric /// for an IR that provides a suitable SSAContext.
327bdd1243dSDimitry Andric template <typename ContextT> class GenericUniformityAnalysisImpl {
328bdd1243dSDimitry Andric public:
329bdd1243dSDimitry Andric   using BlockT = typename ContextT::BlockT;
330bdd1243dSDimitry Andric   using FunctionT = typename ContextT::FunctionT;
331bdd1243dSDimitry Andric   using ValueRefT = typename ContextT::ValueRefT;
332bdd1243dSDimitry Andric   using ConstValueRefT = typename ContextT::ConstValueRefT;
33306c3fb27SDimitry Andric   using UseT = typename ContextT::UseT;
334bdd1243dSDimitry Andric   using InstructionT = typename ContextT::InstructionT;
335bdd1243dSDimitry Andric   using DominatorTreeT = typename ContextT::DominatorTreeT;
336bdd1243dSDimitry Andric 
337bdd1243dSDimitry Andric   using CycleInfoT = GenericCycleInfo<ContextT>;
338bdd1243dSDimitry Andric   using CycleT = typename CycleInfoT::CycleT;
339bdd1243dSDimitry Andric 
340bdd1243dSDimitry Andric   using SyncDependenceAnalysisT = GenericSyncDependenceAnalysis<ContextT>;
341bdd1243dSDimitry Andric   using DivergenceDescriptorT =
342bdd1243dSDimitry Andric       typename SyncDependenceAnalysisT::DivergenceDescriptor;
343bdd1243dSDimitry Andric   using BlockLabelMapT = typename SyncDependenceAnalysisT::BlockLabelMap;
344bdd1243dSDimitry Andric 
3455f757f3fSDimitry Andric   GenericUniformityAnalysisImpl(const DominatorTreeT &DT, const CycleInfoT &CI,
346bdd1243dSDimitry Andric                                 const TargetTransformInfo *TTI)
3475f757f3fSDimitry Andric       : Context(CI.getSSAContext()), F(*Context.getFunction()), CI(CI),
3485f757f3fSDimitry Andric         TTI(TTI), DT(DT), SDA(Context, DT, CI) {}
349bdd1243dSDimitry Andric 
350bdd1243dSDimitry Andric   void initialize();
351bdd1243dSDimitry Andric 
352bdd1243dSDimitry Andric   const FunctionT &getFunction() const { return F; }
353bdd1243dSDimitry Andric 
354bdd1243dSDimitry Andric   /// \brief Mark \p UniVal as a value that is always uniform.
355bdd1243dSDimitry Andric   void addUniformOverride(const InstructionT &Instr);
356bdd1243dSDimitry Andric 
35706c3fb27SDimitry Andric   /// \brief Examine \p I for divergent outputs and add to the worklist.
35806c3fb27SDimitry Andric   void markDivergent(const InstructionT &I);
35906c3fb27SDimitry Andric 
36006c3fb27SDimitry Andric   /// \brief Mark \p DivVal as a divergent value.
361bdd1243dSDimitry Andric   /// \returns Whether the tracked divergence state of \p DivVal changed.
362bdd1243dSDimitry Andric   bool markDivergent(ConstValueRefT DivVal);
36306c3fb27SDimitry Andric 
36406c3fb27SDimitry Andric   /// \brief Mark outputs of \p Instr as divergent.
36506c3fb27SDimitry Andric   /// \returns Whether the tracked divergence state of any output has changed.
36606c3fb27SDimitry Andric   bool markDefsDivergent(const InstructionT &Instr);
367bdd1243dSDimitry Andric 
368bdd1243dSDimitry Andric   /// \brief Propagate divergence to all instructions in the region.
369bdd1243dSDimitry Andric   /// Divergence is seeded by calls to \p markDivergent.
370bdd1243dSDimitry Andric   void compute();
371bdd1243dSDimitry Andric 
372bdd1243dSDimitry Andric   /// \brief Whether any value was marked or analyzed to be divergent.
373bdd1243dSDimitry Andric   bool hasDivergence() const { return !DivergentValues.empty(); }
374bdd1243dSDimitry Andric 
375bdd1243dSDimitry Andric   /// \brief Whether \p Val will always return a uniform value regardless of its
376bdd1243dSDimitry Andric   /// operands
377bdd1243dSDimitry Andric   bool isAlwaysUniform(const InstructionT &Instr) const;
378bdd1243dSDimitry Andric 
379bdd1243dSDimitry Andric   bool hasDivergentDefs(const InstructionT &I) const;
380bdd1243dSDimitry Andric 
381bdd1243dSDimitry Andric   bool isDivergent(const InstructionT &I) const {
382bdd1243dSDimitry Andric     if (I.isTerminator()) {
383bdd1243dSDimitry Andric       return DivergentTermBlocks.contains(I.getParent());
384bdd1243dSDimitry Andric     }
385bdd1243dSDimitry Andric     return hasDivergentDefs(I);
386bdd1243dSDimitry Andric   };
387bdd1243dSDimitry Andric 
388bdd1243dSDimitry Andric   /// \brief Whether \p Val is divergent at its definition.
389bdd1243dSDimitry Andric   bool isDivergent(ConstValueRefT V) const { return DivergentValues.count(V); }
390bdd1243dSDimitry Andric 
39106c3fb27SDimitry Andric   bool isDivergentUse(const UseT &U) const;
39206c3fb27SDimitry Andric 
393bdd1243dSDimitry Andric   bool hasDivergentTerminator(const BlockT &B) const {
394bdd1243dSDimitry Andric     return DivergentTermBlocks.contains(&B);
395bdd1243dSDimitry Andric   }
396bdd1243dSDimitry Andric 
397bdd1243dSDimitry Andric   void print(raw_ostream &out) const;
398bdd1243dSDimitry Andric 
399bdd1243dSDimitry Andric protected:
400bdd1243dSDimitry Andric   /// \brief Value/block pair representing a single phi input.
401bdd1243dSDimitry Andric   struct PhiInput {
402bdd1243dSDimitry Andric     ConstValueRefT value;
403bdd1243dSDimitry Andric     BlockT *predBlock;
404bdd1243dSDimitry Andric 
405bdd1243dSDimitry Andric     PhiInput(ConstValueRefT value, BlockT *predBlock)
406bdd1243dSDimitry Andric         : value(value), predBlock(predBlock) {}
407bdd1243dSDimitry Andric   };
408bdd1243dSDimitry Andric 
409bdd1243dSDimitry Andric   const ContextT &Context;
410bdd1243dSDimitry Andric   const FunctionT &F;
411bdd1243dSDimitry Andric   const CycleInfoT &CI;
412bdd1243dSDimitry Andric   const TargetTransformInfo *TTI = nullptr;
413bdd1243dSDimitry Andric 
414bdd1243dSDimitry Andric   // Detected/marked divergent values.
415*0fca6ea1SDimitry Andric   DenseSet<ConstValueRefT> DivergentValues;
416bdd1243dSDimitry Andric   SmallPtrSet<const BlockT *, 32> DivergentTermBlocks;
417bdd1243dSDimitry Andric 
418bdd1243dSDimitry Andric   // Internal worklist for divergence propagation.
419bdd1243dSDimitry Andric   std::vector<const InstructionT *> Worklist;
420bdd1243dSDimitry Andric 
421bdd1243dSDimitry Andric   /// \brief Mark \p Term as divergent and push all Instructions that become
422bdd1243dSDimitry Andric   /// divergent as a result on the worklist.
423bdd1243dSDimitry Andric   void analyzeControlDivergence(const InstructionT &Term);
424bdd1243dSDimitry Andric 
425bdd1243dSDimitry Andric private:
426bdd1243dSDimitry Andric   const DominatorTreeT &DT;
427bdd1243dSDimitry Andric 
428bdd1243dSDimitry Andric   // Recognized cycles with divergent exits.
429bdd1243dSDimitry Andric   SmallPtrSet<const CycleT *, 16> DivergentExitCycles;
430bdd1243dSDimitry Andric 
431bdd1243dSDimitry Andric   // Cycles assumed to be divergent.
432bdd1243dSDimitry Andric   //
433bdd1243dSDimitry Andric   // We don't use a set here because every insertion needs an explicit
434bdd1243dSDimitry Andric   // traversal of all existing members.
435bdd1243dSDimitry Andric   SmallVector<const CycleT *> AssumedDivergent;
436bdd1243dSDimitry Andric 
437bdd1243dSDimitry Andric   // The SDA links divergent branches to divergent control-flow joins.
438bdd1243dSDimitry Andric   SyncDependenceAnalysisT SDA;
439bdd1243dSDimitry Andric 
440bdd1243dSDimitry Andric   // Set of known-uniform values.
441bdd1243dSDimitry Andric   SmallPtrSet<const InstructionT *, 32> UniformOverrides;
442bdd1243dSDimitry Andric 
443bdd1243dSDimitry Andric   /// \brief Mark all nodes in \p JoinBlock as divergent and push them on
444bdd1243dSDimitry Andric   /// the worklist.
445bdd1243dSDimitry Andric   void taintAndPushAllDefs(const BlockT &JoinBlock);
446bdd1243dSDimitry Andric 
447bdd1243dSDimitry Andric   /// \brief Mark all phi nodes in \p JoinBlock as divergent and push them on
448bdd1243dSDimitry Andric   /// the worklist.
449bdd1243dSDimitry Andric   void taintAndPushPhiNodes(const BlockT &JoinBlock);
450bdd1243dSDimitry Andric 
451bdd1243dSDimitry Andric   /// \brief Identify all Instructions that become divergent because \p DivExit
452bdd1243dSDimitry Andric   /// is a divergent cycle exit of \p DivCycle. Mark those instructions as
453bdd1243dSDimitry Andric   /// divergent and push them on the worklist.
454bdd1243dSDimitry Andric   void propagateCycleExitDivergence(const BlockT &DivExit,
455bdd1243dSDimitry Andric                                     const CycleT &DivCycle);
456bdd1243dSDimitry Andric 
45706c3fb27SDimitry Andric   /// Mark as divergent all external uses of values defined in \p DefCycle.
45806c3fb27SDimitry Andric   void analyzeCycleExitDivergence(const CycleT &DefCycle);
459bdd1243dSDimitry Andric 
46006c3fb27SDimitry Andric   /// \brief Mark as divergent all uses of \p I that are outside \p DefCycle.
46106c3fb27SDimitry Andric   void propagateTemporalDivergence(const InstructionT &I,
46206c3fb27SDimitry Andric                                    const CycleT &DefCycle);
463bdd1243dSDimitry Andric 
464bdd1243dSDimitry Andric   /// \brief Push all users of \p Val (in the region) to the worklist.
465bdd1243dSDimitry Andric   void pushUsers(const InstructionT &I);
466bdd1243dSDimitry Andric   void pushUsers(ConstValueRefT V);
467bdd1243dSDimitry Andric 
468bdd1243dSDimitry Andric   bool usesValueFromCycle(const InstructionT &I, const CycleT &DefCycle) const;
469bdd1243dSDimitry Andric 
47006c3fb27SDimitry Andric   /// \brief Whether \p Def is divergent when read in \p ObservingBlock.
471bdd1243dSDimitry Andric   bool isTemporalDivergent(const BlockT &ObservingBlock,
47206c3fb27SDimitry Andric                            const InstructionT &Def) const;
473bdd1243dSDimitry Andric };
474bdd1243dSDimitry Andric 
475bdd1243dSDimitry Andric template <typename ImplT>
476bdd1243dSDimitry Andric void GenericUniformityAnalysisImplDeleter<ImplT>::operator()(ImplT *Impl) {
477bdd1243dSDimitry Andric   delete Impl;
478bdd1243dSDimitry Andric }
479bdd1243dSDimitry Andric 
480bdd1243dSDimitry Andric /// Compute divergence starting with a divergent branch.
481bdd1243dSDimitry Andric template <typename ContextT> class DivergencePropagator {
482bdd1243dSDimitry Andric public:
483bdd1243dSDimitry Andric   using BlockT = typename ContextT::BlockT;
484bdd1243dSDimitry Andric   using DominatorTreeT = typename ContextT::DominatorTreeT;
485bdd1243dSDimitry Andric   using FunctionT = typename ContextT::FunctionT;
486bdd1243dSDimitry Andric   using ValueRefT = typename ContextT::ValueRefT;
487bdd1243dSDimitry Andric 
488bdd1243dSDimitry Andric   using CycleInfoT = GenericCycleInfo<ContextT>;
489bdd1243dSDimitry Andric   using CycleT = typename CycleInfoT::CycleT;
490bdd1243dSDimitry Andric 
491bdd1243dSDimitry Andric   using ModifiedPO = ModifiedPostOrder<ContextT>;
492bdd1243dSDimitry Andric   using SyncDependenceAnalysisT = GenericSyncDependenceAnalysis<ContextT>;
493bdd1243dSDimitry Andric   using DivergenceDescriptorT =
494bdd1243dSDimitry Andric       typename SyncDependenceAnalysisT::DivergenceDescriptor;
495bdd1243dSDimitry Andric   using BlockLabelMapT = typename SyncDependenceAnalysisT::BlockLabelMap;
496bdd1243dSDimitry Andric 
497bdd1243dSDimitry Andric   const ModifiedPO &CyclePOT;
498bdd1243dSDimitry Andric   const DominatorTreeT &DT;
499bdd1243dSDimitry Andric   const CycleInfoT &CI;
500bdd1243dSDimitry Andric   const BlockT &DivTermBlock;
501bdd1243dSDimitry Andric   const ContextT &Context;
502bdd1243dSDimitry Andric 
503bdd1243dSDimitry Andric   // Track blocks that receive a new label. Every time we relabel a
504bdd1243dSDimitry Andric   // cycle header, we another pass over the modified post-order in
505bdd1243dSDimitry Andric   // order to propagate the header label. The bit vector also allows
506bdd1243dSDimitry Andric   // us to skip labels that have not changed.
507bdd1243dSDimitry Andric   SparseBitVector<> FreshLabels;
508bdd1243dSDimitry Andric 
509bdd1243dSDimitry Andric   // divergent join and cycle exit descriptor.
510bdd1243dSDimitry Andric   std::unique_ptr<DivergenceDescriptorT> DivDesc;
511bdd1243dSDimitry Andric   BlockLabelMapT &BlockLabels;
512bdd1243dSDimitry Andric 
513bdd1243dSDimitry Andric   DivergencePropagator(const ModifiedPO &CyclePOT, const DominatorTreeT &DT,
514bdd1243dSDimitry Andric                        const CycleInfoT &CI, const BlockT &DivTermBlock)
515bdd1243dSDimitry Andric       : CyclePOT(CyclePOT), DT(DT), CI(CI), DivTermBlock(DivTermBlock),
516bdd1243dSDimitry Andric         Context(CI.getSSAContext()), DivDesc(new DivergenceDescriptorT),
517bdd1243dSDimitry Andric         BlockLabels(DivDesc->BlockLabels) {}
518bdd1243dSDimitry Andric 
519bdd1243dSDimitry Andric   void printDefs(raw_ostream &Out) {
520bdd1243dSDimitry Andric     Out << "Propagator::BlockLabels {\n";
521bdd1243dSDimitry Andric     for (int BlockIdx = (int)CyclePOT.size() - 1; BlockIdx >= 0; --BlockIdx) {
522bdd1243dSDimitry Andric       const auto *Block = CyclePOT[BlockIdx];
523bdd1243dSDimitry Andric       const auto *Label = BlockLabels[Block];
524bdd1243dSDimitry Andric       Out << Context.print(Block) << "(" << BlockIdx << ") : ";
525bdd1243dSDimitry Andric       if (!Label) {
526bdd1243dSDimitry Andric         Out << "<null>\n";
527bdd1243dSDimitry Andric       } else {
528bdd1243dSDimitry Andric         Out << Context.print(Label) << "\n";
529bdd1243dSDimitry Andric       }
530bdd1243dSDimitry Andric     }
531bdd1243dSDimitry Andric     Out << "}\n";
532bdd1243dSDimitry Andric   }
533bdd1243dSDimitry Andric 
534bdd1243dSDimitry Andric   // Push a definition (\p PushedLabel) to \p SuccBlock and return whether this
535bdd1243dSDimitry Andric   // causes a divergent join.
536bdd1243dSDimitry Andric   bool computeJoin(const BlockT &SuccBlock, const BlockT &PushedLabel) {
537bdd1243dSDimitry Andric     const auto *OldLabel = BlockLabels[&SuccBlock];
538bdd1243dSDimitry Andric 
539bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "labeling " << Context.print(&SuccBlock) << ":\n"
540bdd1243dSDimitry Andric                       << "\tpushed label: " << Context.print(&PushedLabel)
541bdd1243dSDimitry Andric                       << "\n"
542bdd1243dSDimitry Andric                       << "\told label: " << Context.print(OldLabel) << "\n");
543bdd1243dSDimitry Andric 
544bdd1243dSDimitry Andric     // Early exit if there is no change in the label.
545bdd1243dSDimitry Andric     if (OldLabel == &PushedLabel)
546bdd1243dSDimitry Andric       return false;
547bdd1243dSDimitry Andric 
548bdd1243dSDimitry Andric     if (OldLabel != &SuccBlock) {
549bdd1243dSDimitry Andric       auto SuccIdx = CyclePOT.getIndex(&SuccBlock);
550bdd1243dSDimitry Andric       // Assigning a new label, mark this in FreshLabels.
551bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "\tfresh label: " << SuccIdx << "\n");
552bdd1243dSDimitry Andric       FreshLabels.set(SuccIdx);
553bdd1243dSDimitry Andric     }
554bdd1243dSDimitry Andric 
555bdd1243dSDimitry Andric     // This is not a join if the succ was previously unlabeled.
556bdd1243dSDimitry Andric     if (!OldLabel) {
557bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "\tnew label: " << Context.print(&PushedLabel)
558bdd1243dSDimitry Andric                         << "\n");
559bdd1243dSDimitry Andric       BlockLabels[&SuccBlock] = &PushedLabel;
560bdd1243dSDimitry Andric       return false;
561bdd1243dSDimitry Andric     }
562bdd1243dSDimitry Andric 
563bdd1243dSDimitry Andric     // This is a new join. Label the join block as itself, and not as
564bdd1243dSDimitry Andric     // the pushed label.
565bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "\tnew label: " << Context.print(&SuccBlock) << "\n");
566bdd1243dSDimitry Andric     BlockLabels[&SuccBlock] = &SuccBlock;
567bdd1243dSDimitry Andric 
568bdd1243dSDimitry Andric     return true;
569bdd1243dSDimitry Andric   }
570bdd1243dSDimitry Andric 
571bdd1243dSDimitry Andric   // visiting a virtual cycle exit edge from the cycle header --> temporal
572bdd1243dSDimitry Andric   // divergence on join
573bdd1243dSDimitry Andric   bool visitCycleExitEdge(const BlockT &ExitBlock, const BlockT &Label) {
574bdd1243dSDimitry Andric     if (!computeJoin(ExitBlock, Label))
575bdd1243dSDimitry Andric       return false;
576bdd1243dSDimitry Andric 
577bdd1243dSDimitry Andric     // Identified a divergent cycle exit
578bdd1243dSDimitry Andric     DivDesc->CycleDivBlocks.insert(&ExitBlock);
579bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "\tDivergent cycle exit: " << Context.print(&ExitBlock)
580bdd1243dSDimitry Andric                       << "\n");
581bdd1243dSDimitry Andric     return true;
582bdd1243dSDimitry Andric   }
583bdd1243dSDimitry Andric 
584bdd1243dSDimitry Andric   // process \p SuccBlock with reaching definition \p Label
585bdd1243dSDimitry Andric   bool visitEdge(const BlockT &SuccBlock, const BlockT &Label) {
586bdd1243dSDimitry Andric     if (!computeJoin(SuccBlock, Label))
587bdd1243dSDimitry Andric       return false;
588bdd1243dSDimitry Andric 
589bdd1243dSDimitry Andric     // Divergent, disjoint paths join.
590bdd1243dSDimitry Andric     DivDesc->JoinDivBlocks.insert(&SuccBlock);
591bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "\tDivergent join: " << Context.print(&SuccBlock)
592bdd1243dSDimitry Andric                       << "\n");
593bdd1243dSDimitry Andric     return true;
594bdd1243dSDimitry Andric   }
595bdd1243dSDimitry Andric 
596bdd1243dSDimitry Andric   std::unique_ptr<DivergenceDescriptorT> computeJoinPoints() {
597bdd1243dSDimitry Andric     assert(DivDesc);
598bdd1243dSDimitry Andric 
599bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "SDA:computeJoinPoints: "
600bdd1243dSDimitry Andric                       << Context.print(&DivTermBlock) << "\n");
601bdd1243dSDimitry Andric 
602bdd1243dSDimitry Andric     // Early stopping criterion
603bdd1243dSDimitry Andric     int FloorIdx = CyclePOT.size() - 1;
604bdd1243dSDimitry Andric     const BlockT *FloorLabel = nullptr;
605bdd1243dSDimitry Andric     int DivTermIdx = CyclePOT.getIndex(&DivTermBlock);
606bdd1243dSDimitry Andric 
607bdd1243dSDimitry Andric     // Bootstrap with branch targets
608bdd1243dSDimitry Andric     auto const *DivTermCycle = CI.getCycle(&DivTermBlock);
609bdd1243dSDimitry Andric     for (const auto *SuccBlock : successors(&DivTermBlock)) {
610bdd1243dSDimitry Andric       if (DivTermCycle && !DivTermCycle->contains(SuccBlock)) {
611bdd1243dSDimitry Andric         // If DivTerm exits the cycle immediately, computeJoin() might
612bdd1243dSDimitry Andric         // not reach SuccBlock with a different label. We need to
613bdd1243dSDimitry Andric         // check for this exit now.
614bdd1243dSDimitry Andric         DivDesc->CycleDivBlocks.insert(SuccBlock);
615bdd1243dSDimitry Andric         LLVM_DEBUG(dbgs() << "\tImmediate divergent cycle exit: "
616bdd1243dSDimitry Andric                           << Context.print(SuccBlock) << "\n");
617bdd1243dSDimitry Andric       }
618bdd1243dSDimitry Andric       auto SuccIdx = CyclePOT.getIndex(SuccBlock);
619bdd1243dSDimitry Andric       visitEdge(*SuccBlock, *SuccBlock);
620bdd1243dSDimitry Andric       FloorIdx = std::min<int>(FloorIdx, SuccIdx);
621bdd1243dSDimitry Andric     }
622bdd1243dSDimitry Andric 
623bdd1243dSDimitry Andric     while (true) {
624bdd1243dSDimitry Andric       auto BlockIdx = FreshLabels.find_last();
625bdd1243dSDimitry Andric       if (BlockIdx == -1 || BlockIdx < FloorIdx)
626bdd1243dSDimitry Andric         break;
627bdd1243dSDimitry Andric 
628bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "Current labels:\n"; printDefs(dbgs()));
629bdd1243dSDimitry Andric 
630bdd1243dSDimitry Andric       FreshLabels.reset(BlockIdx);
631bdd1243dSDimitry Andric       if (BlockIdx == DivTermIdx) {
632bdd1243dSDimitry Andric         LLVM_DEBUG(dbgs() << "Skipping DivTermBlock\n");
633bdd1243dSDimitry Andric         continue;
634bdd1243dSDimitry Andric       }
635bdd1243dSDimitry Andric 
636bdd1243dSDimitry Andric       const auto *Block = CyclePOT[BlockIdx];
637bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "visiting " << Context.print(Block) << " at index "
638bdd1243dSDimitry Andric                         << BlockIdx << "\n");
639bdd1243dSDimitry Andric 
640bdd1243dSDimitry Andric       const auto *Label = BlockLabels[Block];
641bdd1243dSDimitry Andric       assert(Label);
642bdd1243dSDimitry Andric 
643bdd1243dSDimitry Andric       bool CausedJoin = false;
644bdd1243dSDimitry Andric       int LoweredFloorIdx = FloorIdx;
645bdd1243dSDimitry Andric 
646bdd1243dSDimitry Andric       // If the current block is the header of a reducible cycle that
647bdd1243dSDimitry Andric       // contains the divergent branch, then the label should be
648bdd1243dSDimitry Andric       // propagated to the cycle exits. Such a header is the "last
649bdd1243dSDimitry Andric       // possible join" of any disjoint paths within this cycle. This
650bdd1243dSDimitry Andric       // prevents detection of spurious joins at the entries of any
651bdd1243dSDimitry Andric       // irreducible child cycles.
652bdd1243dSDimitry Andric       //
653bdd1243dSDimitry Andric       // This conclusion about the header is true for any choice of DFS:
654bdd1243dSDimitry Andric       //
655bdd1243dSDimitry Andric       //   If some DFS has a reducible cycle C with header H, then for
656bdd1243dSDimitry Andric       //   any other DFS, H is the header of a cycle C' that is a
657bdd1243dSDimitry Andric       //   superset of C. For a divergent branch inside the subgraph
658bdd1243dSDimitry Andric       //   C, any join node inside C is either H, or some node
659bdd1243dSDimitry Andric       //   encountered without passing through H.
660bdd1243dSDimitry Andric       //
661bdd1243dSDimitry Andric       auto getReducibleParent = [&](const BlockT *Block) -> const CycleT * {
662bdd1243dSDimitry Andric         if (!CyclePOT.isReducibleCycleHeader(Block))
663bdd1243dSDimitry Andric           return nullptr;
664bdd1243dSDimitry Andric         const auto *BlockCycle = CI.getCycle(Block);
665bdd1243dSDimitry Andric         if (BlockCycle->contains(&DivTermBlock))
666bdd1243dSDimitry Andric           return BlockCycle;
667bdd1243dSDimitry Andric         return nullptr;
668bdd1243dSDimitry Andric       };
669bdd1243dSDimitry Andric 
670bdd1243dSDimitry Andric       if (const auto *BlockCycle = getReducibleParent(Block)) {
671bdd1243dSDimitry Andric         SmallVector<BlockT *, 4> BlockCycleExits;
672bdd1243dSDimitry Andric         BlockCycle->getExitBlocks(BlockCycleExits);
673bdd1243dSDimitry Andric         for (auto *BlockCycleExit : BlockCycleExits) {
674bdd1243dSDimitry Andric           CausedJoin |= visitCycleExitEdge(*BlockCycleExit, *Label);
675bdd1243dSDimitry Andric           LoweredFloorIdx =
676bdd1243dSDimitry Andric               std::min<int>(LoweredFloorIdx, CyclePOT.getIndex(BlockCycleExit));
677bdd1243dSDimitry Andric         }
678bdd1243dSDimitry Andric       } else {
679bdd1243dSDimitry Andric         for (const auto *SuccBlock : successors(Block)) {
680bdd1243dSDimitry Andric           CausedJoin |= visitEdge(*SuccBlock, *Label);
681bdd1243dSDimitry Andric           LoweredFloorIdx =
682bdd1243dSDimitry Andric               std::min<int>(LoweredFloorIdx, CyclePOT.getIndex(SuccBlock));
683bdd1243dSDimitry Andric         }
684bdd1243dSDimitry Andric       }
685bdd1243dSDimitry Andric 
686bdd1243dSDimitry Andric       // Floor update
687bdd1243dSDimitry Andric       if (CausedJoin) {
688bdd1243dSDimitry Andric         // 1. Different labels pushed to successors
689bdd1243dSDimitry Andric         FloorIdx = LoweredFloorIdx;
690bdd1243dSDimitry Andric       } else if (FloorLabel != Label) {
691bdd1243dSDimitry Andric         // 2. No join caused BUT we pushed a label that is different than the
692bdd1243dSDimitry Andric         // last pushed label
693bdd1243dSDimitry Andric         FloorIdx = LoweredFloorIdx;
694bdd1243dSDimitry Andric         FloorLabel = Label;
695bdd1243dSDimitry Andric       }
696bdd1243dSDimitry Andric     }
697bdd1243dSDimitry Andric 
698bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "Final labeling:\n"; printDefs(dbgs()));
699bdd1243dSDimitry Andric 
700bdd1243dSDimitry Andric     // Check every cycle containing DivTermBlock for exit divergence.
701bdd1243dSDimitry Andric     // A cycle has exit divergence if the label of an exit block does
702bdd1243dSDimitry Andric     // not match the label of its header.
703bdd1243dSDimitry Andric     for (const auto *Cycle = CI.getCycle(&DivTermBlock); Cycle;
704bdd1243dSDimitry Andric          Cycle = Cycle->getParentCycle()) {
705bdd1243dSDimitry Andric       if (Cycle->isReducible()) {
706bdd1243dSDimitry Andric         // The exit divergence of a reducible cycle is recorded while
707bdd1243dSDimitry Andric         // propagating labels.
708bdd1243dSDimitry Andric         continue;
709bdd1243dSDimitry Andric       }
710bdd1243dSDimitry Andric       SmallVector<BlockT *> Exits;
711bdd1243dSDimitry Andric       Cycle->getExitBlocks(Exits);
712bdd1243dSDimitry Andric       auto *Header = Cycle->getHeader();
713bdd1243dSDimitry Andric       auto *HeaderLabel = BlockLabels[Header];
714bdd1243dSDimitry Andric       for (const auto *Exit : Exits) {
715bdd1243dSDimitry Andric         if (BlockLabels[Exit] != HeaderLabel) {
716bdd1243dSDimitry Andric           // Identified a divergent cycle exit
717bdd1243dSDimitry Andric           DivDesc->CycleDivBlocks.insert(Exit);
718bdd1243dSDimitry Andric           LLVM_DEBUG(dbgs() << "\tDivergent cycle exit: " << Context.print(Exit)
719bdd1243dSDimitry Andric                             << "\n");
720bdd1243dSDimitry Andric         }
721bdd1243dSDimitry Andric       }
722bdd1243dSDimitry Andric     }
723bdd1243dSDimitry Andric 
724bdd1243dSDimitry Andric     return std::move(DivDesc);
725bdd1243dSDimitry Andric   }
726bdd1243dSDimitry Andric };
727bdd1243dSDimitry Andric 
728bdd1243dSDimitry Andric template <typename ContextT>
729bdd1243dSDimitry Andric typename llvm::GenericSyncDependenceAnalysis<ContextT>::DivergenceDescriptor
730bdd1243dSDimitry Andric     llvm::GenericSyncDependenceAnalysis<ContextT>::EmptyDivergenceDesc;
731bdd1243dSDimitry Andric 
732bdd1243dSDimitry Andric template <typename ContextT>
733bdd1243dSDimitry Andric llvm::GenericSyncDependenceAnalysis<ContextT>::GenericSyncDependenceAnalysis(
734bdd1243dSDimitry Andric     const ContextT &Context, const DominatorTreeT &DT, const CycleInfoT &CI)
735bdd1243dSDimitry Andric     : CyclePO(Context), DT(DT), CI(CI) {
736bdd1243dSDimitry Andric   CyclePO.compute(CI);
737bdd1243dSDimitry Andric }
738bdd1243dSDimitry Andric 
739bdd1243dSDimitry Andric template <typename ContextT>
740bdd1243dSDimitry Andric auto llvm::GenericSyncDependenceAnalysis<ContextT>::getJoinBlocks(
741bdd1243dSDimitry Andric     const BlockT *DivTermBlock) -> const DivergenceDescriptor & {
742bdd1243dSDimitry Andric   // trivial case
743bdd1243dSDimitry Andric   if (succ_size(DivTermBlock) <= 1) {
744bdd1243dSDimitry Andric     return EmptyDivergenceDesc;
745bdd1243dSDimitry Andric   }
746bdd1243dSDimitry Andric 
747bdd1243dSDimitry Andric   // already available in cache?
748bdd1243dSDimitry Andric   auto ItCached = CachedControlDivDescs.find(DivTermBlock);
749bdd1243dSDimitry Andric   if (ItCached != CachedControlDivDescs.end())
750bdd1243dSDimitry Andric     return *ItCached->second;
751bdd1243dSDimitry Andric 
752bdd1243dSDimitry Andric   // compute all join points
753bdd1243dSDimitry Andric   DivergencePropagatorT Propagator(CyclePO, DT, CI, *DivTermBlock);
754bdd1243dSDimitry Andric   auto DivDesc = Propagator.computeJoinPoints();
755bdd1243dSDimitry Andric 
756bdd1243dSDimitry Andric   auto printBlockSet = [&](ConstBlockSet &Blocks) {
757bdd1243dSDimitry Andric     return Printable([&](raw_ostream &Out) {
758bdd1243dSDimitry Andric       Out << "[";
759bdd1243dSDimitry Andric       ListSeparator LS;
760bdd1243dSDimitry Andric       for (const auto *BB : Blocks) {
761bdd1243dSDimitry Andric         Out << LS << CI.getSSAContext().print(BB);
762bdd1243dSDimitry Andric       }
763bdd1243dSDimitry Andric       Out << "]\n";
764bdd1243dSDimitry Andric     });
765bdd1243dSDimitry Andric   };
766bdd1243dSDimitry Andric 
767bdd1243dSDimitry Andric   LLVM_DEBUG(
768bdd1243dSDimitry Andric       dbgs() << "\nResult (" << CI.getSSAContext().print(DivTermBlock)
769bdd1243dSDimitry Andric              << "):\n  JoinDivBlocks: " << printBlockSet(DivDesc->JoinDivBlocks)
770bdd1243dSDimitry Andric              << "  CycleDivBlocks: " << printBlockSet(DivDesc->CycleDivBlocks)
771bdd1243dSDimitry Andric              << "\n");
772bdd1243dSDimitry Andric   (void)printBlockSet;
773bdd1243dSDimitry Andric 
774bdd1243dSDimitry Andric   auto ItInserted =
775bdd1243dSDimitry Andric       CachedControlDivDescs.try_emplace(DivTermBlock, std::move(DivDesc));
776bdd1243dSDimitry Andric   assert(ItInserted.second);
777bdd1243dSDimitry Andric   return *ItInserted.first->second;
778bdd1243dSDimitry Andric }
779bdd1243dSDimitry Andric 
780bdd1243dSDimitry Andric template <typename ContextT>
78106c3fb27SDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::markDivergent(
782bdd1243dSDimitry Andric     const InstructionT &I) {
78306c3fb27SDimitry Andric   if (isAlwaysUniform(I))
78406c3fb27SDimitry Andric     return;
78506c3fb27SDimitry Andric   bool Marked = false;
786bdd1243dSDimitry Andric   if (I.isTerminator()) {
78706c3fb27SDimitry Andric     Marked = DivergentTermBlocks.insert(I.getParent()).second;
78806c3fb27SDimitry Andric     if (Marked) {
789bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "marked divergent term block: "
790bdd1243dSDimitry Andric                         << Context.print(I.getParent()) << "\n");
791bdd1243dSDimitry Andric     }
79206c3fb27SDimitry Andric   } else {
79306c3fb27SDimitry Andric     Marked = markDefsDivergent(I);
794bdd1243dSDimitry Andric   }
795bdd1243dSDimitry Andric 
79606c3fb27SDimitry Andric   if (Marked)
79706c3fb27SDimitry Andric     Worklist.push_back(&I);
798bdd1243dSDimitry Andric }
799bdd1243dSDimitry Andric 
800bdd1243dSDimitry Andric template <typename ContextT>
801bdd1243dSDimitry Andric bool GenericUniformityAnalysisImpl<ContextT>::markDivergent(
802bdd1243dSDimitry Andric     ConstValueRefT Val) {
803bdd1243dSDimitry Andric   if (DivergentValues.insert(Val).second) {
804bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "marked divergent: " << Context.print(Val) << "\n");
805bdd1243dSDimitry Andric     return true;
806bdd1243dSDimitry Andric   }
807bdd1243dSDimitry Andric   return false;
808bdd1243dSDimitry Andric }
809bdd1243dSDimitry Andric 
810bdd1243dSDimitry Andric template <typename ContextT>
811bdd1243dSDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::addUniformOverride(
812bdd1243dSDimitry Andric     const InstructionT &Instr) {
813bdd1243dSDimitry Andric   UniformOverrides.insert(&Instr);
814bdd1243dSDimitry Andric }
815bdd1243dSDimitry Andric 
81606c3fb27SDimitry Andric // Mark as divergent all external uses of values defined in \p DefCycle.
817bdd1243dSDimitry Andric //
81806c3fb27SDimitry Andric // A value V defined by a block B inside \p DefCycle may be used outside the
81906c3fb27SDimitry Andric // cycle only if the use is a PHI in some exit block, or B dominates some exit
82006c3fb27SDimitry Andric // block. Thus, we check uses as follows:
82106c3fb27SDimitry Andric //
82206c3fb27SDimitry Andric // - Check all PHIs in all exit blocks for inputs defined inside \p DefCycle.
82306c3fb27SDimitry Andric // - For every block B inside \p DefCycle that dominates at least one exit
82406c3fb27SDimitry Andric //   block, check all uses outside \p DefCycle.
82506c3fb27SDimitry Andric //
82606c3fb27SDimitry Andric // FIXME: This function does not distinguish between divergent and uniform
82706c3fb27SDimitry Andric // exits. For each divergent exit, only the values that are live at that exit
82806c3fb27SDimitry Andric // need to be propagated as divergent at their use outside the cycle.
829bdd1243dSDimitry Andric template <typename ContextT>
830bdd1243dSDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::analyzeCycleExitDivergence(
83106c3fb27SDimitry Andric     const CycleT &DefCycle) {
83206c3fb27SDimitry Andric   SmallVector<BlockT *> Exits;
83306c3fb27SDimitry Andric   DefCycle.getExitBlocks(Exits);
83406c3fb27SDimitry Andric   for (auto *Exit : Exits) {
83506c3fb27SDimitry Andric     for (auto &Phi : Exit->phis()) {
83606c3fb27SDimitry Andric       if (usesValueFromCycle(Phi, DefCycle)) {
83706c3fb27SDimitry Andric         markDivergent(Phi);
83806c3fb27SDimitry Andric       }
83906c3fb27SDimitry Andric     }
84006c3fb27SDimitry Andric   }
841bdd1243dSDimitry Andric 
84206c3fb27SDimitry Andric   for (auto *BB : DefCycle.blocks()) {
84306c3fb27SDimitry Andric     if (!llvm::any_of(Exits,
84406c3fb27SDimitry Andric                      [&](BlockT *Exit) { return DT.dominates(BB, Exit); }))
845bdd1243dSDimitry Andric       continue;
84606c3fb27SDimitry Andric     for (auto &II : *BB) {
84706c3fb27SDimitry Andric       propagateTemporalDivergence(II, DefCycle);
848bdd1243dSDimitry Andric     }
849bdd1243dSDimitry Andric   }
850bdd1243dSDimitry Andric }
851bdd1243dSDimitry Andric 
852bdd1243dSDimitry Andric template <typename ContextT>
853bdd1243dSDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::propagateCycleExitDivergence(
854bdd1243dSDimitry Andric     const BlockT &DivExit, const CycleT &InnerDivCycle) {
855bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "\tpropCycleExitDiv " << Context.print(&DivExit)
856bdd1243dSDimitry Andric                     << "\n");
857bdd1243dSDimitry Andric   auto *DivCycle = &InnerDivCycle;
858bdd1243dSDimitry Andric   auto *OuterDivCycle = DivCycle;
859bdd1243dSDimitry Andric   auto *ExitLevelCycle = CI.getCycle(&DivExit);
860bdd1243dSDimitry Andric   const unsigned CycleExitDepth =
861bdd1243dSDimitry Andric       ExitLevelCycle ? ExitLevelCycle->getDepth() : 0;
862bdd1243dSDimitry Andric 
863bdd1243dSDimitry Andric   // Find outer-most cycle that does not contain \p DivExit
864bdd1243dSDimitry Andric   while (DivCycle && DivCycle->getDepth() > CycleExitDepth) {
865bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "  Found exiting cycle: "
866bdd1243dSDimitry Andric                       << Context.print(DivCycle->getHeader()) << "\n");
867bdd1243dSDimitry Andric     OuterDivCycle = DivCycle;
868bdd1243dSDimitry Andric     DivCycle = DivCycle->getParentCycle();
869bdd1243dSDimitry Andric   }
870bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "\tOuter-most exiting cycle: "
871bdd1243dSDimitry Andric                     << Context.print(OuterDivCycle->getHeader()) << "\n");
872bdd1243dSDimitry Andric 
873bdd1243dSDimitry Andric   if (!DivergentExitCycles.insert(OuterDivCycle).second)
874bdd1243dSDimitry Andric     return;
875bdd1243dSDimitry Andric 
876bdd1243dSDimitry Andric   // Exit divergence does not matter if the cycle itself is assumed to
877bdd1243dSDimitry Andric   // be divergent.
878bdd1243dSDimitry Andric   for (const auto *C : AssumedDivergent) {
879bdd1243dSDimitry Andric     if (C->contains(OuterDivCycle))
880bdd1243dSDimitry Andric       return;
881bdd1243dSDimitry Andric   }
882bdd1243dSDimitry Andric 
883bdd1243dSDimitry Andric   analyzeCycleExitDivergence(*OuterDivCycle);
884bdd1243dSDimitry Andric }
885bdd1243dSDimitry Andric 
886bdd1243dSDimitry Andric template <typename ContextT>
887bdd1243dSDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::taintAndPushAllDefs(
888bdd1243dSDimitry Andric     const BlockT &BB) {
889bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "taintAndPushAllDefs " << Context.print(&BB) << "\n");
890bdd1243dSDimitry Andric   for (const auto &I : instrs(BB)) {
891bdd1243dSDimitry Andric     // Terminators do not produce values; they are divergent only if
892bdd1243dSDimitry Andric     // the condition is divergent. That is handled when the divergent
893bdd1243dSDimitry Andric     // condition is placed in the worklist.
894bdd1243dSDimitry Andric     if (I.isTerminator())
895bdd1243dSDimitry Andric       break;
896bdd1243dSDimitry Andric 
89706c3fb27SDimitry Andric     markDivergent(I);
898bdd1243dSDimitry Andric   }
899bdd1243dSDimitry Andric }
900bdd1243dSDimitry Andric 
901bdd1243dSDimitry Andric /// Mark divergent phi nodes in a join block
902bdd1243dSDimitry Andric template <typename ContextT>
903bdd1243dSDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::taintAndPushPhiNodes(
904bdd1243dSDimitry Andric     const BlockT &JoinBlock) {
905bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "taintAndPushPhiNodes in " << Context.print(&JoinBlock)
906bdd1243dSDimitry Andric                     << "\n");
907bdd1243dSDimitry Andric   for (const auto &Phi : JoinBlock.phis()) {
90806c3fb27SDimitry Andric     // FIXME: The non-undef value is not constant per se; it just happens to be
90906c3fb27SDimitry Andric     // uniform and may not dominate this PHI. So assuming that the same value
91006c3fb27SDimitry Andric     // reaches along all incoming edges may itself be undefined behaviour. This
91106c3fb27SDimitry Andric     // particular interpretation of the undef value was added to
91206c3fb27SDimitry Andric     // DivergenceAnalysis in the following review:
91306c3fb27SDimitry Andric     //
91406c3fb27SDimitry Andric     // https://reviews.llvm.org/D19013
91506c3fb27SDimitry Andric     if (ContextT::isConstantOrUndefValuePhi(Phi))
916bdd1243dSDimitry Andric       continue;
91706c3fb27SDimitry Andric     markDivergent(Phi);
918bdd1243dSDimitry Andric   }
919bdd1243dSDimitry Andric }
920bdd1243dSDimitry Andric 
921bdd1243dSDimitry Andric /// Add \p Candidate to \p Cycles if it is not already contained in \p Cycles.
922bdd1243dSDimitry Andric ///
923bdd1243dSDimitry Andric /// \return true iff \p Candidate was added to \p Cycles.
924bdd1243dSDimitry Andric template <typename CycleT>
925bdd1243dSDimitry Andric static bool insertIfNotContained(SmallVector<CycleT *> &Cycles,
926bdd1243dSDimitry Andric                                  CycleT *Candidate) {
927bdd1243dSDimitry Andric   if (llvm::any_of(Cycles,
928bdd1243dSDimitry Andric                    [Candidate](CycleT *C) { return C->contains(Candidate); }))
929bdd1243dSDimitry Andric     return false;
930bdd1243dSDimitry Andric   Cycles.push_back(Candidate);
931bdd1243dSDimitry Andric   return true;
932bdd1243dSDimitry Andric }
933bdd1243dSDimitry Andric 
934bdd1243dSDimitry Andric /// Return the outermost cycle made divergent by branch outside it.
935bdd1243dSDimitry Andric ///
936bdd1243dSDimitry Andric /// If two paths that diverged outside an irreducible cycle join
937bdd1243dSDimitry Andric /// inside that cycle, then that whole cycle is assumed to be
938bdd1243dSDimitry Andric /// divergent. This does not apply if the cycle is reducible.
939bdd1243dSDimitry Andric template <typename CycleT, typename BlockT>
940bdd1243dSDimitry Andric static const CycleT *getExtDivCycle(const CycleT *Cycle,
941bdd1243dSDimitry Andric                                     const BlockT *DivTermBlock,
942bdd1243dSDimitry Andric                                     const BlockT *JoinBlock) {
943bdd1243dSDimitry Andric   assert(Cycle);
944bdd1243dSDimitry Andric   assert(Cycle->contains(JoinBlock));
945bdd1243dSDimitry Andric 
946bdd1243dSDimitry Andric   if (Cycle->contains(DivTermBlock))
947bdd1243dSDimitry Andric     return nullptr;
948bdd1243dSDimitry Andric 
9495f757f3fSDimitry Andric   const auto *OriginalCycle = Cycle;
9505f757f3fSDimitry Andric   const auto *Parent = Cycle->getParentCycle();
9515f757f3fSDimitry Andric   while (Parent && !Parent->contains(DivTermBlock)) {
9525f757f3fSDimitry Andric     Cycle = Parent;
9535f757f3fSDimitry Andric     Parent = Cycle->getParentCycle();
9545f757f3fSDimitry Andric   }
9555f757f3fSDimitry Andric 
9565f757f3fSDimitry Andric   // If the original cycle is not the outermost cycle, then the outermost cycle
9575f757f3fSDimitry Andric   // is irreducible. If the outermost cycle were reducible, then external
9585f757f3fSDimitry Andric   // diverged paths would not reach the original inner cycle.
9595f757f3fSDimitry Andric   (void)OriginalCycle;
9605f757f3fSDimitry Andric   assert(Cycle == OriginalCycle || !Cycle->isReducible());
9615f757f3fSDimitry Andric 
962bdd1243dSDimitry Andric   if (Cycle->isReducible()) {
963bdd1243dSDimitry Andric     assert(Cycle->getHeader() == JoinBlock);
964bdd1243dSDimitry Andric     return nullptr;
965bdd1243dSDimitry Andric   }
966bdd1243dSDimitry Andric 
967bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "cycle made divergent by external branch\n");
968bdd1243dSDimitry Andric   return Cycle;
969bdd1243dSDimitry Andric }
970bdd1243dSDimitry Andric 
971bdd1243dSDimitry Andric /// Return the outermost cycle made divergent by branch inside it.
972bdd1243dSDimitry Andric ///
973bdd1243dSDimitry Andric /// This checks the "diverged entry" criterion defined in the
974bdd1243dSDimitry Andric /// docs/ConvergenceAnalysis.html.
975bdd1243dSDimitry Andric template <typename ContextT, typename CycleT, typename BlockT,
976bdd1243dSDimitry Andric           typename DominatorTreeT>
977bdd1243dSDimitry Andric static const CycleT *
978bdd1243dSDimitry Andric getIntDivCycle(const CycleT *Cycle, const BlockT *DivTermBlock,
979bdd1243dSDimitry Andric                const BlockT *JoinBlock, const DominatorTreeT &DT,
980bdd1243dSDimitry Andric                ContextT &Context) {
981bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "examine join " << Context.print(JoinBlock)
982bdd1243dSDimitry Andric                     << " for internal branch " << Context.print(DivTermBlock)
983bdd1243dSDimitry Andric                     << "\n");
984bdd1243dSDimitry Andric   if (DT.properlyDominates(DivTermBlock, JoinBlock))
985bdd1243dSDimitry Andric     return nullptr;
986bdd1243dSDimitry Andric 
987bdd1243dSDimitry Andric   // Find the smallest common cycle, if one exists.
988bdd1243dSDimitry Andric   assert(Cycle && Cycle->contains(JoinBlock));
989bdd1243dSDimitry Andric   while (Cycle && !Cycle->contains(DivTermBlock)) {
990bdd1243dSDimitry Andric     Cycle = Cycle->getParentCycle();
991bdd1243dSDimitry Andric   }
992bdd1243dSDimitry Andric   if (!Cycle || Cycle->isReducible())
993bdd1243dSDimitry Andric     return nullptr;
994bdd1243dSDimitry Andric 
995bdd1243dSDimitry Andric   if (DT.properlyDominates(Cycle->getHeader(), JoinBlock))
996bdd1243dSDimitry Andric     return nullptr;
997bdd1243dSDimitry Andric 
998bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "  header " << Context.print(Cycle->getHeader())
999bdd1243dSDimitry Andric                     << " does not dominate join\n");
1000bdd1243dSDimitry Andric 
1001bdd1243dSDimitry Andric   const auto *Parent = Cycle->getParentCycle();
1002bdd1243dSDimitry Andric   while (Parent && !DT.properlyDominates(Parent->getHeader(), JoinBlock)) {
1003bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "  header " << Context.print(Parent->getHeader())
1004bdd1243dSDimitry Andric                       << " does not dominate join\n");
1005bdd1243dSDimitry Andric     Cycle = Parent;
1006bdd1243dSDimitry Andric     Parent = Parent->getParentCycle();
1007bdd1243dSDimitry Andric   }
1008bdd1243dSDimitry Andric 
1009bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "  cycle made divergent by internal branch\n");
1010bdd1243dSDimitry Andric   return Cycle;
1011bdd1243dSDimitry Andric }
1012bdd1243dSDimitry Andric 
1013bdd1243dSDimitry Andric template <typename ContextT, typename CycleT, typename BlockT,
1014bdd1243dSDimitry Andric           typename DominatorTreeT>
1015bdd1243dSDimitry Andric static const CycleT *
1016bdd1243dSDimitry Andric getOutermostDivergentCycle(const CycleT *Cycle, const BlockT *DivTermBlock,
1017bdd1243dSDimitry Andric                            const BlockT *JoinBlock, const DominatorTreeT &DT,
1018bdd1243dSDimitry Andric                            ContextT &Context) {
1019bdd1243dSDimitry Andric   if (!Cycle)
1020bdd1243dSDimitry Andric     return nullptr;
1021bdd1243dSDimitry Andric 
1022bdd1243dSDimitry Andric   // First try to expand Cycle to the largest that contains JoinBlock
1023bdd1243dSDimitry Andric   // but not DivTermBlock.
1024bdd1243dSDimitry Andric   const auto *Ext = getExtDivCycle(Cycle, DivTermBlock, JoinBlock);
1025bdd1243dSDimitry Andric 
1026bdd1243dSDimitry Andric   // Continue expanding to the largest cycle that contains both.
1027bdd1243dSDimitry Andric   const auto *Int = getIntDivCycle(Cycle, DivTermBlock, JoinBlock, DT, Context);
1028bdd1243dSDimitry Andric 
1029bdd1243dSDimitry Andric   if (Int)
1030bdd1243dSDimitry Andric     return Int;
1031bdd1243dSDimitry Andric   return Ext;
1032bdd1243dSDimitry Andric }
1033bdd1243dSDimitry Andric 
1034bdd1243dSDimitry Andric template <typename ContextT>
103506c3fb27SDimitry Andric bool GenericUniformityAnalysisImpl<ContextT>::isTemporalDivergent(
103606c3fb27SDimitry Andric     const BlockT &ObservingBlock, const InstructionT &Def) const {
103706c3fb27SDimitry Andric   const BlockT *DefBlock = Def.getParent();
103806c3fb27SDimitry Andric   for (const CycleT *Cycle = CI.getCycle(DefBlock);
103906c3fb27SDimitry Andric        Cycle && !Cycle->contains(&ObservingBlock);
104006c3fb27SDimitry Andric        Cycle = Cycle->getParentCycle()) {
104106c3fb27SDimitry Andric     if (DivergentExitCycles.contains(Cycle)) {
104206c3fb27SDimitry Andric       return true;
104306c3fb27SDimitry Andric     }
104406c3fb27SDimitry Andric   }
104506c3fb27SDimitry Andric   return false;
104606c3fb27SDimitry Andric }
104706c3fb27SDimitry Andric 
104806c3fb27SDimitry Andric template <typename ContextT>
1049bdd1243dSDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::analyzeControlDivergence(
1050bdd1243dSDimitry Andric     const InstructionT &Term) {
1051bdd1243dSDimitry Andric   const auto *DivTermBlock = Term.getParent();
1052bdd1243dSDimitry Andric   DivergentTermBlocks.insert(DivTermBlock);
1053bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "analyzeControlDiv " << Context.print(DivTermBlock)
1054bdd1243dSDimitry Andric                     << "\n");
1055bdd1243dSDimitry Andric 
1056bdd1243dSDimitry Andric   // Don't propagate divergence from unreachable blocks.
1057bdd1243dSDimitry Andric   if (!DT.isReachableFromEntry(DivTermBlock))
1058bdd1243dSDimitry Andric     return;
1059bdd1243dSDimitry Andric 
1060bdd1243dSDimitry Andric   const auto &DivDesc = SDA.getJoinBlocks(DivTermBlock);
1061bdd1243dSDimitry Andric   SmallVector<const CycleT *> DivCycles;
1062bdd1243dSDimitry Andric 
1063bdd1243dSDimitry Andric   // Iterate over all blocks now reachable by a disjoint path join
1064bdd1243dSDimitry Andric   for (const auto *JoinBlock : DivDesc.JoinDivBlocks) {
1065bdd1243dSDimitry Andric     const auto *Cycle = CI.getCycle(JoinBlock);
1066bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "visiting join block " << Context.print(JoinBlock)
1067bdd1243dSDimitry Andric                       << "\n");
1068bdd1243dSDimitry Andric     if (const auto *Outermost = getOutermostDivergentCycle(
1069bdd1243dSDimitry Andric             Cycle, DivTermBlock, JoinBlock, DT, Context)) {
1070bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "found divergent cycle\n");
1071bdd1243dSDimitry Andric       DivCycles.push_back(Outermost);
1072bdd1243dSDimitry Andric       continue;
1073bdd1243dSDimitry Andric     }
1074bdd1243dSDimitry Andric     taintAndPushPhiNodes(*JoinBlock);
1075bdd1243dSDimitry Andric   }
1076bdd1243dSDimitry Andric 
1077bdd1243dSDimitry Andric   // Sort by order of decreasing depth. This allows later cycles to be skipped
1078bdd1243dSDimitry Andric   // because they are already contained in earlier ones.
1079bdd1243dSDimitry Andric   llvm::sort(DivCycles, [](const CycleT *A, const CycleT *B) {
1080bdd1243dSDimitry Andric     return A->getDepth() > B->getDepth();
1081bdd1243dSDimitry Andric   });
1082bdd1243dSDimitry Andric 
1083bdd1243dSDimitry Andric   // Cycles that are assumed divergent due to the diverged entry
1084bdd1243dSDimitry Andric   // criterion potentially contain temporal divergence depending on
1085bdd1243dSDimitry Andric   // the DFS chosen. Conservatively, all values produced in such a
1086bdd1243dSDimitry Andric   // cycle are assumed divergent. "Cycle invariant" values may be
1087bdd1243dSDimitry Andric   // assumed uniform, but that requires further analysis.
1088bdd1243dSDimitry Andric   for (auto *C : DivCycles) {
1089bdd1243dSDimitry Andric     if (!insertIfNotContained(AssumedDivergent, C))
1090bdd1243dSDimitry Andric       continue;
1091bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "process divergent cycle\n");
1092bdd1243dSDimitry Andric     for (const BlockT *BB : C->blocks()) {
1093bdd1243dSDimitry Andric       taintAndPushAllDefs(*BB);
1094bdd1243dSDimitry Andric     }
1095bdd1243dSDimitry Andric   }
1096bdd1243dSDimitry Andric 
1097bdd1243dSDimitry Andric   const auto *BranchCycle = CI.getCycle(DivTermBlock);
1098bdd1243dSDimitry Andric   assert(DivDesc.CycleDivBlocks.empty() || BranchCycle);
1099bdd1243dSDimitry Andric   for (const auto *DivExitBlock : DivDesc.CycleDivBlocks) {
1100bdd1243dSDimitry Andric     propagateCycleExitDivergence(*DivExitBlock, *BranchCycle);
1101bdd1243dSDimitry Andric   }
1102bdd1243dSDimitry Andric }
1103bdd1243dSDimitry Andric 
1104bdd1243dSDimitry Andric template <typename ContextT>
1105bdd1243dSDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::compute() {
1106bdd1243dSDimitry Andric   // Initialize worklist.
1107bdd1243dSDimitry Andric   auto DivValuesCopy = DivergentValues;
1108bdd1243dSDimitry Andric   for (const auto DivVal : DivValuesCopy) {
1109bdd1243dSDimitry Andric     assert(isDivergent(DivVal) && "Worklist invariant violated!");
1110bdd1243dSDimitry Andric     pushUsers(DivVal);
1111bdd1243dSDimitry Andric   }
1112bdd1243dSDimitry Andric 
1113bdd1243dSDimitry Andric   // All values on the Worklist are divergent.
1114bdd1243dSDimitry Andric   // Their users may not have been updated yet.
1115bdd1243dSDimitry Andric   while (!Worklist.empty()) {
1116bdd1243dSDimitry Andric     const InstructionT *I = Worklist.back();
1117bdd1243dSDimitry Andric     Worklist.pop_back();
1118bdd1243dSDimitry Andric 
1119bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "worklist pop: " << Context.print(I) << "\n");
1120bdd1243dSDimitry Andric 
1121bdd1243dSDimitry Andric     if (I->isTerminator()) {
1122bdd1243dSDimitry Andric       analyzeControlDivergence(*I);
1123bdd1243dSDimitry Andric       continue;
1124bdd1243dSDimitry Andric     }
1125bdd1243dSDimitry Andric 
1126bdd1243dSDimitry Andric     // propagate value divergence to users
1127bdd1243dSDimitry Andric     assert(isDivergent(*I) && "Worklist invariant violated!");
1128bdd1243dSDimitry Andric     pushUsers(*I);
1129bdd1243dSDimitry Andric   }
1130bdd1243dSDimitry Andric }
1131bdd1243dSDimitry Andric 
1132bdd1243dSDimitry Andric template <typename ContextT>
1133bdd1243dSDimitry Andric bool GenericUniformityAnalysisImpl<ContextT>::isAlwaysUniform(
1134bdd1243dSDimitry Andric     const InstructionT &Instr) const {
1135bdd1243dSDimitry Andric   return UniformOverrides.contains(&Instr);
1136bdd1243dSDimitry Andric }
1137bdd1243dSDimitry Andric 
1138bdd1243dSDimitry Andric template <typename ContextT>
1139bdd1243dSDimitry Andric GenericUniformityInfo<ContextT>::GenericUniformityInfo(
11405f757f3fSDimitry Andric     const DominatorTreeT &DT, const CycleInfoT &CI,
11415f757f3fSDimitry Andric     const TargetTransformInfo *TTI) {
11425f757f3fSDimitry Andric   DA.reset(new ImplT{DT, CI, TTI});
1143bdd1243dSDimitry Andric }
1144bdd1243dSDimitry Andric 
1145bdd1243dSDimitry Andric template <typename ContextT>
1146bdd1243dSDimitry Andric void GenericUniformityAnalysisImpl<ContextT>::print(raw_ostream &OS) const {
1147bdd1243dSDimitry Andric   bool haveDivergentArgs = false;
1148bdd1243dSDimitry Andric 
114906c3fb27SDimitry Andric   // Control flow instructions may be divergent even if their inputs are
115006c3fb27SDimitry Andric   // uniform. Thus, although exceedingly rare, it is possible to have a program
115106c3fb27SDimitry Andric   // with no divergent values but with divergent control structures.
115206c3fb27SDimitry Andric   if (DivergentValues.empty() && DivergentTermBlocks.empty() &&
115306c3fb27SDimitry Andric       DivergentExitCycles.empty()) {
1154bdd1243dSDimitry Andric     OS << "ALL VALUES UNIFORM\n";
1155bdd1243dSDimitry Andric     return;
1156bdd1243dSDimitry Andric   }
1157bdd1243dSDimitry Andric 
1158bdd1243dSDimitry Andric   for (const auto &entry : DivergentValues) {
1159bdd1243dSDimitry Andric     const BlockT *parent = Context.getDefBlock(entry);
1160bdd1243dSDimitry Andric     if (!parent) {
1161bdd1243dSDimitry Andric       if (!haveDivergentArgs) {
1162bdd1243dSDimitry Andric         OS << "DIVERGENT ARGUMENTS:\n";
1163bdd1243dSDimitry Andric         haveDivergentArgs = true;
1164bdd1243dSDimitry Andric       }
1165bdd1243dSDimitry Andric       OS << "  DIVERGENT: " << Context.print(entry) << '\n';
1166bdd1243dSDimitry Andric     }
1167bdd1243dSDimitry Andric   }
1168bdd1243dSDimitry Andric 
1169bdd1243dSDimitry Andric   if (!AssumedDivergent.empty()) {
1170bdd1243dSDimitry Andric     OS << "CYCLES ASSSUMED DIVERGENT:\n";
1171bdd1243dSDimitry Andric     for (const CycleT *cycle : AssumedDivergent) {
1172bdd1243dSDimitry Andric       OS << "  " << cycle->print(Context) << '\n';
1173bdd1243dSDimitry Andric     }
1174bdd1243dSDimitry Andric   }
1175bdd1243dSDimitry Andric 
1176bdd1243dSDimitry Andric   if (!DivergentExitCycles.empty()) {
1177bdd1243dSDimitry Andric     OS << "CYCLES WITH DIVERGENT EXIT:\n";
1178bdd1243dSDimitry Andric     for (const CycleT *cycle : DivergentExitCycles) {
1179bdd1243dSDimitry Andric       OS << "  " << cycle->print(Context) << '\n';
1180bdd1243dSDimitry Andric     }
1181bdd1243dSDimitry Andric   }
1182bdd1243dSDimitry Andric 
1183bdd1243dSDimitry Andric   for (auto &block : F) {
1184bdd1243dSDimitry Andric     OS << "\nBLOCK " << Context.print(&block) << '\n';
1185bdd1243dSDimitry Andric 
1186bdd1243dSDimitry Andric     OS << "DEFINITIONS\n";
1187bdd1243dSDimitry Andric     SmallVector<ConstValueRefT, 16> defs;
1188bdd1243dSDimitry Andric     Context.appendBlockDefs(defs, block);
1189bdd1243dSDimitry Andric     for (auto value : defs) {
1190bdd1243dSDimitry Andric       if (isDivergent(value))
1191bdd1243dSDimitry Andric         OS << "  DIVERGENT: ";
1192bdd1243dSDimitry Andric       else
1193bdd1243dSDimitry Andric         OS << "             ";
1194bdd1243dSDimitry Andric       OS << Context.print(value) << '\n';
1195bdd1243dSDimitry Andric     }
1196bdd1243dSDimitry Andric 
1197bdd1243dSDimitry Andric     OS << "TERMINATORS\n";
1198bdd1243dSDimitry Andric     SmallVector<const InstructionT *, 8> terms;
1199bdd1243dSDimitry Andric     Context.appendBlockTerms(terms, block);
1200bdd1243dSDimitry Andric     bool divergentTerminators = hasDivergentTerminator(block);
1201bdd1243dSDimitry Andric     for (auto *T : terms) {
1202bdd1243dSDimitry Andric       if (divergentTerminators)
1203bdd1243dSDimitry Andric         OS << "  DIVERGENT: ";
1204bdd1243dSDimitry Andric       else
1205bdd1243dSDimitry Andric         OS << "             ";
1206bdd1243dSDimitry Andric       OS << Context.print(T) << '\n';
1207bdd1243dSDimitry Andric     }
1208bdd1243dSDimitry Andric 
1209bdd1243dSDimitry Andric     OS << "END BLOCK\n";
1210bdd1243dSDimitry Andric   }
1211bdd1243dSDimitry Andric }
1212bdd1243dSDimitry Andric 
1213bdd1243dSDimitry Andric template <typename ContextT>
1214bdd1243dSDimitry Andric bool GenericUniformityInfo<ContextT>::hasDivergence() const {
1215bdd1243dSDimitry Andric   return DA->hasDivergence();
1216bdd1243dSDimitry Andric }
1217bdd1243dSDimitry Andric 
12185f757f3fSDimitry Andric template <typename ContextT>
12195f757f3fSDimitry Andric const typename ContextT::FunctionT &
12205f757f3fSDimitry Andric GenericUniformityInfo<ContextT>::getFunction() const {
12215f757f3fSDimitry Andric   return DA->getFunction();
12225f757f3fSDimitry Andric }
12235f757f3fSDimitry Andric 
1224bdd1243dSDimitry Andric /// Whether \p V is divergent at its definition.
1225bdd1243dSDimitry Andric template <typename ContextT>
1226bdd1243dSDimitry Andric bool GenericUniformityInfo<ContextT>::isDivergent(ConstValueRefT V) const {
1227bdd1243dSDimitry Andric   return DA->isDivergent(V);
1228bdd1243dSDimitry Andric }
1229bdd1243dSDimitry Andric 
1230bdd1243dSDimitry Andric template <typename ContextT>
123106c3fb27SDimitry Andric bool GenericUniformityInfo<ContextT>::isDivergent(const InstructionT *I) const {
123206c3fb27SDimitry Andric   return DA->isDivergent(*I);
123306c3fb27SDimitry Andric }
123406c3fb27SDimitry Andric 
123506c3fb27SDimitry Andric template <typename ContextT>
123606c3fb27SDimitry Andric bool GenericUniformityInfo<ContextT>::isDivergentUse(const UseT &U) const {
123706c3fb27SDimitry Andric   return DA->isDivergentUse(U);
123806c3fb27SDimitry Andric }
123906c3fb27SDimitry Andric 
124006c3fb27SDimitry Andric template <typename ContextT>
1241bdd1243dSDimitry Andric bool GenericUniformityInfo<ContextT>::hasDivergentTerminator(const BlockT &B) {
1242bdd1243dSDimitry Andric   return DA->hasDivergentTerminator(B);
1243bdd1243dSDimitry Andric }
1244bdd1243dSDimitry Andric 
1245bdd1243dSDimitry Andric /// \brief T helper function for printing.
1246bdd1243dSDimitry Andric template <typename ContextT>
1247bdd1243dSDimitry Andric void GenericUniformityInfo<ContextT>::print(raw_ostream &out) const {
1248bdd1243dSDimitry Andric   DA->print(out);
1249bdd1243dSDimitry Andric }
1250bdd1243dSDimitry Andric 
1251bdd1243dSDimitry Andric template <typename ContextT>
1252bdd1243dSDimitry Andric void llvm::ModifiedPostOrder<ContextT>::computeStackPO(
12535f757f3fSDimitry Andric     SmallVectorImpl<const BlockT *> &Stack, const CycleInfoT &CI,
12545f757f3fSDimitry Andric     const CycleT *Cycle, SmallPtrSetImpl<const BlockT *> &Finalized) {
1255bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "inside computeStackPO\n");
1256bdd1243dSDimitry Andric   while (!Stack.empty()) {
1257bdd1243dSDimitry Andric     auto *NextBB = Stack.back();
1258bdd1243dSDimitry Andric     if (Finalized.count(NextBB)) {
1259bdd1243dSDimitry Andric       Stack.pop_back();
1260bdd1243dSDimitry Andric       continue;
1261bdd1243dSDimitry Andric     }
1262bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "  visiting " << CI.getSSAContext().print(NextBB)
1263bdd1243dSDimitry Andric                       << "\n");
1264bdd1243dSDimitry Andric     auto *NestedCycle = CI.getCycle(NextBB);
1265bdd1243dSDimitry Andric     if (Cycle != NestedCycle && (!Cycle || Cycle->contains(NestedCycle))) {
1266bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "  found a cycle\n");
1267bdd1243dSDimitry Andric       while (NestedCycle->getParentCycle() != Cycle)
1268bdd1243dSDimitry Andric         NestedCycle = NestedCycle->getParentCycle();
1269bdd1243dSDimitry Andric 
1270bdd1243dSDimitry Andric       SmallVector<BlockT *, 3> NestedExits;
1271bdd1243dSDimitry Andric       NestedCycle->getExitBlocks(NestedExits);
1272bdd1243dSDimitry Andric       bool PushedNodes = false;
1273bdd1243dSDimitry Andric       for (auto *NestedExitBB : NestedExits) {
1274bdd1243dSDimitry Andric         LLVM_DEBUG(dbgs() << "  examine exit: "
1275bdd1243dSDimitry Andric                           << CI.getSSAContext().print(NestedExitBB) << "\n");
1276bdd1243dSDimitry Andric         if (Cycle && !Cycle->contains(NestedExitBB))
1277bdd1243dSDimitry Andric           continue;
1278bdd1243dSDimitry Andric         if (Finalized.count(NestedExitBB))
1279bdd1243dSDimitry Andric           continue;
1280bdd1243dSDimitry Andric         PushedNodes = true;
1281bdd1243dSDimitry Andric         Stack.push_back(NestedExitBB);
1282bdd1243dSDimitry Andric         LLVM_DEBUG(dbgs() << "  pushed exit: "
1283bdd1243dSDimitry Andric                           << CI.getSSAContext().print(NestedExitBB) << "\n");
1284bdd1243dSDimitry Andric       }
1285bdd1243dSDimitry Andric       if (!PushedNodes) {
1286bdd1243dSDimitry Andric         // All loop exits finalized -> finish this node
1287bdd1243dSDimitry Andric         Stack.pop_back();
1288bdd1243dSDimitry Andric         computeCyclePO(CI, NestedCycle, Finalized);
1289bdd1243dSDimitry Andric       }
1290bdd1243dSDimitry Andric       continue;
1291bdd1243dSDimitry Andric     }
1292bdd1243dSDimitry Andric 
1293bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "  no nested cycle, going into DAG\n");
1294bdd1243dSDimitry Andric     // DAG-style
1295bdd1243dSDimitry Andric     bool PushedNodes = false;
1296bdd1243dSDimitry Andric     for (auto *SuccBB : successors(NextBB)) {
1297bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "  examine succ: "
1298bdd1243dSDimitry Andric                         << CI.getSSAContext().print(SuccBB) << "\n");
1299bdd1243dSDimitry Andric       if (Cycle && !Cycle->contains(SuccBB))
1300bdd1243dSDimitry Andric         continue;
1301bdd1243dSDimitry Andric       if (Finalized.count(SuccBB))
1302bdd1243dSDimitry Andric         continue;
1303bdd1243dSDimitry Andric       PushedNodes = true;
1304bdd1243dSDimitry Andric       Stack.push_back(SuccBB);
1305bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "  pushed succ: " << CI.getSSAContext().print(SuccBB)
1306bdd1243dSDimitry Andric                         << "\n");
1307bdd1243dSDimitry Andric     }
1308bdd1243dSDimitry Andric     if (!PushedNodes) {
1309bdd1243dSDimitry Andric       // Never push nodes twice
1310bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "  finishing node: "
1311bdd1243dSDimitry Andric                         << CI.getSSAContext().print(NextBB) << "\n");
1312bdd1243dSDimitry Andric       Stack.pop_back();
1313bdd1243dSDimitry Andric       Finalized.insert(NextBB);
1314bdd1243dSDimitry Andric       appendBlock(*NextBB);
1315bdd1243dSDimitry Andric     }
1316bdd1243dSDimitry Andric   }
1317bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "exited computeStackPO\n");
1318bdd1243dSDimitry Andric }
1319bdd1243dSDimitry Andric 
1320bdd1243dSDimitry Andric template <typename ContextT>
1321bdd1243dSDimitry Andric void ModifiedPostOrder<ContextT>::computeCyclePO(
1322bdd1243dSDimitry Andric     const CycleInfoT &CI, const CycleT *Cycle,
13235f757f3fSDimitry Andric     SmallPtrSetImpl<const BlockT *> &Finalized) {
1324bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "inside computeCyclePO\n");
13255f757f3fSDimitry Andric   SmallVector<const BlockT *> Stack;
1326bdd1243dSDimitry Andric   auto *CycleHeader = Cycle->getHeader();
1327bdd1243dSDimitry Andric 
1328bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "  noted header: "
1329bdd1243dSDimitry Andric                     << CI.getSSAContext().print(CycleHeader) << "\n");
1330bdd1243dSDimitry Andric   assert(!Finalized.count(CycleHeader));
1331bdd1243dSDimitry Andric   Finalized.insert(CycleHeader);
1332bdd1243dSDimitry Andric 
1333bdd1243dSDimitry Andric   // Visit the header last
1334bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "  finishing header: "
1335bdd1243dSDimitry Andric                     << CI.getSSAContext().print(CycleHeader) << "\n");
1336bdd1243dSDimitry Andric   appendBlock(*CycleHeader, Cycle->isReducible());
1337bdd1243dSDimitry Andric 
1338bdd1243dSDimitry Andric   // Initialize with immediate successors
1339bdd1243dSDimitry Andric   for (auto *BB : successors(CycleHeader)) {
1340bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "  examine succ: " << CI.getSSAContext().print(BB)
1341bdd1243dSDimitry Andric                       << "\n");
1342bdd1243dSDimitry Andric     if (!Cycle->contains(BB))
1343bdd1243dSDimitry Andric       continue;
1344bdd1243dSDimitry Andric     if (BB == CycleHeader)
1345bdd1243dSDimitry Andric       continue;
1346bdd1243dSDimitry Andric     if (!Finalized.count(BB)) {
1347bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "  pushed succ: " << CI.getSSAContext().print(BB)
1348bdd1243dSDimitry Andric                         << "\n");
1349bdd1243dSDimitry Andric       Stack.push_back(BB);
1350bdd1243dSDimitry Andric     }
1351bdd1243dSDimitry Andric   }
1352bdd1243dSDimitry Andric 
1353bdd1243dSDimitry Andric   // Compute PO inside region
1354bdd1243dSDimitry Andric   computeStackPO(Stack, CI, Cycle, Finalized);
1355bdd1243dSDimitry Andric 
1356bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "exited computeCyclePO\n");
1357bdd1243dSDimitry Andric }
1358bdd1243dSDimitry Andric 
1359bdd1243dSDimitry Andric /// \brief Generically compute the modified post order.
1360bdd1243dSDimitry Andric template <typename ContextT>
1361bdd1243dSDimitry Andric void llvm::ModifiedPostOrder<ContextT>::compute(const CycleInfoT &CI) {
13625f757f3fSDimitry Andric   SmallPtrSet<const BlockT *, 32> Finalized;
13635f757f3fSDimitry Andric   SmallVector<const BlockT *> Stack;
1364bdd1243dSDimitry Andric   auto *F = CI.getFunction();
1365bdd1243dSDimitry Andric   Stack.reserve(24); // FIXME made-up number
13665f757f3fSDimitry Andric   Stack.push_back(&F->front());
1367bdd1243dSDimitry Andric   computeStackPO(Stack, CI, nullptr, Finalized);
1368bdd1243dSDimitry Andric }
1369bdd1243dSDimitry Andric 
1370bdd1243dSDimitry Andric } // namespace llvm
1371bdd1243dSDimitry Andric 
1372bdd1243dSDimitry Andric #undef DEBUG_TYPE
1373bdd1243dSDimitry Andric 
1374bdd1243dSDimitry Andric #endif // LLVM_ADT_GENERICUNIFORMITYIMPL_H
1375