Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 1 | //===- llvm/Analysis/DivergenceAnalysis.h - Divergence Analysis -*- C++ -*-===// | 
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // \file | ||
| 10 | // The divergence analysis determines which instructions and branches are | ||
| 11 | // divergent given a set of divergent source instructions. | ||
| 12 | // | ||
| 13 | //===----------------------------------------------------------------------===// | ||
| 14 | |||
| 15 | #ifndef LLVM_ANALYSIS_DIVERGENCEANALYSIS_H | ||
| 16 | #define LLVM_ANALYSIS_DIVERGENCEANALYSIS_H | ||
| 17 | |||
| 18 | #include "llvm/ADT/DenseSet.h" | ||
| 19 | #include "llvm/Analysis/SyncDependenceAnalysis.h" | ||
| 20 | #include "llvm/IR/PassManager.h" | ||
| 21 | #include <vector> | ||
| 22 | |||
| 23 | namespace llvm { | ||
| 24 | class Function; | ||
| 25 | class Instruction; | ||
| 26 | class Loop; | ||
| 27 | class raw_ostream; | ||
| 28 | class TargetTransformInfo; | ||
| 29 | class Value; | ||
| 30 | |||
| 31 | /// \brief Generic divergence analysis for reducible CFGs. | ||
| 32 | /// | ||
| 33 | /// This analysis propagates divergence in a data-parallel context from sources | ||
| 34 | /// of divergence to all users. It requires reducible CFGs. All assignments | ||
| 35 | /// should be in SSA form. | ||
| 36 | class DivergenceAnalysisImpl { | ||
| 37 | public: | ||
| 38 |   /// \brief This instance will analyze the whole function \p F or the loop \p | ||
| 39 |   /// RegionLoop. | ||
| 40 |   /// | ||
| 41 |   /// \param RegionLoop if non-null the analysis is restricted to \p RegionLoop. | ||
| 42 |   /// Otherwise the whole function is analyzed. | ||
| 43 |   /// \param IsLCSSAForm whether the analysis may assume that the IR in the | ||
| 44 |   /// region in LCSSA form. | ||
| 45 | DivergenceAnalysisImpl(const Function &F, const Loop *RegionLoop, | ||
| 46 | const DominatorTree &DT, const LoopInfo &LI, | ||
| 47 | SyncDependenceAnalysis &SDA, bool IsLCSSAForm); | ||
| 48 | |||
| 49 |   /// \brief The loop that defines the analyzed region (if any). | ||
| 50 | const Loop *getRegionLoop() const { return RegionLoop; } | ||
| 51 | const Function &getFunction() const { return F; } | ||
| 52 | |||
| 53 |   /// \brief Whether \p BB is part of the region. | ||
| 54 | bool inRegion(const BasicBlock &BB) const; | ||
| 55 |   /// \brief Whether \p I is part of the region. | ||
| 56 | bool inRegion(const Instruction &I) const; | ||
| 57 | |||
| 58 |   /// \brief Mark \p UniVal as a value that is always uniform. | ||
| 59 | void addUniformOverride(const Value &UniVal); | ||
| 60 | |||
| 61 |   /// \brief Mark \p DivVal as a value that is always divergent. Will not do so | ||
| 62 |   /// if `isAlwaysUniform(DivVal)`. | ||
| 63 |   /// \returns Whether the tracked divergence state of \p DivVal changed. | ||
| 64 | bool markDivergent(const Value &DivVal); | ||
| 65 | |||
| 66 |   /// \brief Propagate divergence to all instructions in the region. | ||
| 67 |   /// Divergence is seeded by calls to \p markDivergent. | ||
| 68 | void compute(); | ||
| 69 | |||
| 70 |   /// \brief Whether any value was marked or analyzed to be divergent. | ||
| 71 | bool hasDetectedDivergence() const { return !DivergentValues.empty(); } | ||
| 72 | |||
| 73 |   /// \brief Whether \p Val will always return a uniform value regardless of its | ||
| 74 |   /// operands | ||
| 75 | bool isAlwaysUniform(const Value &Val) const; | ||
| 76 | |||
| 77 |   /// \brief Whether \p Val is divergent at its definition. | ||
| 78 | bool isDivergent(const Value &Val) const; | ||
| 79 | |||
| 80 |   /// \brief Whether \p U is divergent. Uses of a uniform value can be | ||
| 81 |   /// divergent. | ||
| 82 | bool isDivergentUse(const Use &U) const; | ||
| 83 | |||
| 84 | private: | ||
| 85 |   /// \brief Mark \p Term as divergent and push all Instructions that become | ||
| 86 |   /// divergent as a result on the worklist. | ||
| 87 | void analyzeControlDivergence(const Instruction &Term); | ||
| 88 |   /// \brief Mark all phi nodes in \p JoinBlock as divergent and push them on | ||
| 89 |   /// the worklist. | ||
| 90 | void taintAndPushPhiNodes(const BasicBlock &JoinBlock); | ||
| 91 | |||
| 92 |   /// \brief Identify all Instructions that become divergent because \p DivExit | ||
| 93 |   /// is a divergent loop exit of \p DivLoop. Mark those instructions as | ||
| 94 |   /// divergent and push them on the worklist. | ||
| 95 | void propagateLoopExitDivergence(const BasicBlock &DivExit, | ||
| 96 | const Loop &DivLoop); | ||
| 97 | |||
| 98 |   /// \brief Internal implementation function for propagateLoopExitDivergence. | ||
| 99 | void analyzeLoopExitDivergence(const BasicBlock &DivExit, | ||
| 100 | const Loop &OuterDivLoop); | ||
| 101 | |||
| 102 |   /// \brief Mark all instruction as divergent that use a value defined in \p | ||
| 103 |   /// OuterDivLoop. Push their users on the worklist. | ||
| 104 | void analyzeTemporalDivergence(const Instruction &I, | ||
| 105 | const Loop &OuterDivLoop); | ||
| 106 | |||
| 107 |   /// \brief Push all users of \p Val (in the region) to the worklist. | ||
| 108 | void pushUsers(const Value &I); | ||
| 109 | |||
| 110 |   /// \brief Whether \p Val is divergent when read in \p ObservingBlock. | ||
| 111 | bool isTemporalDivergent(const BasicBlock &ObservingBlock, | ||
| 112 | const Value &Val) const; | ||
| 113 | |||
| 114 | private: | ||
| 115 | const Function &F; | ||
| 116 |   // If regionLoop != nullptr, analysis is only performed within \p RegionLoop. | ||
| 117 |   // Otherwise, analyze the whole function | ||
| 118 | const Loop *RegionLoop; | ||
| 119 | |||
| 120 | const DominatorTree &DT; | ||
| 121 | const LoopInfo &LI; | ||
| 122 | |||
| 123 |   // Recognized divergent loops | ||
| 124 | DenseSet<const Loop *> DivergentLoops; | ||
| 125 | |||
| 126 |   // The SDA links divergent branches to divergent control-flow joins. | ||
| 127 | SyncDependenceAnalysis &SDA; | ||
| 128 | |||
| 129 |   // Use simplified code path for LCSSA form. | ||
| 130 | bool IsLCSSAForm; | ||
| 131 | |||
| 132 |   // Set of known-uniform values. | ||
| 133 | DenseSet<const Value *> UniformOverrides; | ||
| 134 | |||
| 135 |   // Detected/marked divergent values. | ||
| 136 | DenseSet<const Value *> DivergentValues; | ||
| 137 | |||
| 138 |   // Internal worklist for divergence propagation. | ||
| 139 | std::vector<const Instruction *> Worklist; | ||
| 140 | }; | ||
| 141 | |||
| 142 | class DivergenceInfo { | ||
| 143 | Function &F; | ||
| 144 | |||
| 145 |   // If the function contains an irreducible region the divergence | ||
| 146 |   // analysis can run indefinitely. We set ContainsIrreducible and no | ||
| 147 |   // analysis is actually performed on the function. All values in | ||
| 148 |   // this function are conservatively reported as divergent instead. | ||
| 149 | bool ContainsIrreducible = false; | ||
| 150 | std::unique_ptr<SyncDependenceAnalysis> SDA; | ||
| 151 | std::unique_ptr<DivergenceAnalysisImpl> DA; | ||
| 152 | |||
| 153 | public: | ||
| 154 | DivergenceInfo(Function &F, const DominatorTree &DT, | ||
| 155 | const PostDominatorTree &PDT, const LoopInfo &LI, | ||
| 156 | const TargetTransformInfo &TTI, bool KnownReducible); | ||
| 157 | |||
| 158 |   /// Whether any divergence was detected. | ||
| 159 | bool hasDivergence() const { | ||
| 160 | return ContainsIrreducible || DA->hasDetectedDivergence(); | ||
| 161 |   } | ||
| 162 | |||
| 163 |   /// The GPU kernel this analysis result is for | ||
| 164 | const Function &getFunction() const { return F; } | ||
| 165 | |||
| 166 |   /// Whether \p V is divergent at its definition. | ||
| 167 | bool isDivergent(const Value &V) const { | ||
| 168 | return ContainsIrreducible || DA->isDivergent(V); | ||
| 169 |   } | ||
| 170 | |||
| 171 |   /// Whether \p U is divergent. Uses of a uniform value can be divergent. | ||
| 172 | bool isDivergentUse(const Use &U) const { | ||
| 173 | return ContainsIrreducible || DA->isDivergentUse(U); | ||
| 174 |   } | ||
| 175 | |||
| 176 |   /// Whether \p V is uniform/non-divergent. | ||
| 177 | bool isUniform(const Value &V) const { return !isDivergent(V); } | ||
| 178 | |||
| 179 |   /// Whether \p U is uniform/non-divergent. Uses of a uniform value can be | ||
| 180 |   /// divergent. | ||
| 181 | bool isUniformUse(const Use &U) const { return !isDivergentUse(U); } | ||
| 182 | }; | ||
| 183 | |||
| 184 | /// \brief Divergence analysis frontend for GPU kernels. | ||
| 185 | class DivergenceAnalysis : public AnalysisInfoMixin<DivergenceAnalysis> { | ||
| 186 | friend AnalysisInfoMixin<DivergenceAnalysis>; | ||
| 187 | |||
| 188 | static AnalysisKey Key; | ||
| 189 | |||
| 190 | public: | ||
| 191 | using Result = DivergenceInfo; | ||
| 192 | |||
| 193 |   /// Runs the divergence analysis on @F, a GPU kernel | ||
| 194 | Result run(Function &F, FunctionAnalysisManager &AM); | ||
| 195 | }; | ||
| 196 | |||
| 197 | /// Printer pass to dump divergence analysis results. | ||
| 198 | struct DivergenceAnalysisPrinterPass | ||
| 199 | : public PassInfoMixin<DivergenceAnalysisPrinterPass> { | ||
| 200 | DivergenceAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {} | ||
| 201 | |||
| 202 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); | ||
| 203 | |||
| 204 | private: | ||
| 205 | raw_ostream &OS; | ||
| 206 | }; // class DivergenceAnalysisPrinterPass | ||
| 207 | |||
| 208 | } // namespace llvm | ||
| 209 | |||
| 210 | #endif // LLVM_ANALYSIS_DIVERGENCEANALYSIS_H |