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