blob: 2e4ae65d09817a05d56e2547c3b48bd3834388c5 [file] [log] [blame]
Andrew Walbran16937d02019-10-22 13:54:20 +01001//===- 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_DIVERGENCE_ANALYSIS_H
16#define LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H
17
18#include "llvm/ADT/DenseSet.h"
19#include "llvm/Analysis/SyncDependenceAnalysis.h"
20#include "llvm/IR/Function.h"
21#include "llvm/Pass.h"
22#include <vector>
23
24namespace llvm {
25class Module;
26class Value;
27class Instruction;
28class Loop;
29class raw_ostream;
30class TargetTransformInfo;
31
32/// \brief Generic divergence analysis for reducible CFGs.
33///
34/// This analysis propagates divergence in a data-parallel context from sources
35/// of divergence to all users. It requires reducible CFGs. All assignments
36/// should be in SSA form.
37class DivergenceAnalysis {
38public:
39 /// \brief This instance will analyze the whole function \p F or the loop \p
40 /// RegionLoop.
41 ///
42 /// \param RegionLoop if non-null the analysis is restricted to \p RegionLoop.
43 /// Otherwise the whole function is analyzed.
44 /// \param IsLCSSAForm whether the analysis may assume that the IR in the
45 /// region in in LCSSA form.
46 DivergenceAnalysis(const Function &F, const Loop *RegionLoop,
47 const DominatorTree &DT, const LoopInfo &LI,
48 SyncDependenceAnalysis &SDA, bool IsLCSSAForm);
49
50 /// \brief The loop that defines the analyzed region (if any).
51 const Loop *getRegionLoop() const { return RegionLoop; }
52 const Function &getFunction() const { return F; }
53
54 /// \brief Whether \p BB is part of the region.
55 bool inRegion(const BasicBlock &BB) const;
56 /// \brief Whether \p I is part of the region.
57 bool inRegion(const Instruction &I) const;
58
59 /// \brief Mark \p UniVal as a value that is always uniform.
60 void addUniformOverride(const Value &UniVal);
61
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020062 /// \brief Mark \p DivVal as a value that is always divergent. Will not do so
63 /// if `isAlwaysUniform(DivVal)`.
64 /// \returns Whether the tracked divergence state of \p DivVal changed.
65 bool markDivergent(const Value &DivVal);
Andrew Walbran16937d02019-10-22 13:54:20 +010066
67 /// \brief Propagate divergence to all instructions in the region.
68 /// Divergence is seeded by calls to \p markDivergent.
69 void compute();
70
71 /// \brief Whether any value was marked or analyzed to be divergent.
72 bool hasDetectedDivergence() const { return !DivergentValues.empty(); }
73
74 /// \brief Whether \p Val will always return a uniform value regardless of its
75 /// operands
76 bool isAlwaysUniform(const Value &Val) const;
77
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020078 /// \brief Whether \p Val is divergent at its definition.
Andrew Walbran16937d02019-10-22 13:54:20 +010079 bool isDivergent(const Value &Val) const;
80
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020081 /// \brief Whether \p U is divergent. Uses of a uniform value can be
82 /// divergent.
83 bool isDivergentUse(const Use &U) const;
84
Andrew Walbran16937d02019-10-22 13:54:20 +010085 void print(raw_ostream &OS, const Module *) const;
86
87private:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020088 /// \brief Mark \p Term as divergent and push all Instructions that become
89 /// divergent as a result on the worklist.
90 void analyzeControlDivergence(const Instruction &Term);
91 /// \brief Mark all phi nodes in \p JoinBlock as divergent and push them on
92 /// the worklist.
93 void taintAndPushPhiNodes(const BasicBlock &JoinBlock);
Andrew Walbran16937d02019-10-22 13:54:20 +010094
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020095 /// \brief Identify all Instructions that become divergent because \p DivExit
96 /// is a divergent loop exit of \p DivLoop. Mark those instructions as
97 /// divergent and push them on the worklist.
98 void propagateLoopExitDivergence(const BasicBlock &DivExit,
99 const Loop &DivLoop);
Andrew Walbran16937d02019-10-22 13:54:20 +0100100
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200101 /// \brief Internal implementation function for propagateLoopExitDivergence.
102 void analyzeLoopExitDivergence(const BasicBlock &DivExit,
103 const Loop &OuterDivLoop);
Andrew Walbran16937d02019-10-22 13:54:20 +0100104
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200105 /// \brief Mark all instruction as divergent that use a value defined in \p
106 /// OuterDivLoop. Push their users on the worklist.
107 void analyzeTemporalDivergence(const Instruction &I,
108 const Loop &OuterDivLoop);
109
110 /// \brief Push all users of \p Val (in the region) to the worklist.
Andrew Walbran16937d02019-10-22 13:54:20 +0100111 void pushUsers(const Value &I);
112
Andrew Walbran16937d02019-10-22 13:54:20 +0100113 /// \brief Whether \p Val is divergent when read in \p ObservingBlock.
114 bool isTemporalDivergent(const BasicBlock &ObservingBlock,
115 const Value &Val) const;
116
117 /// \brief Whether \p Block is join divergent
118 ///
119 /// (see markBlockJoinDivergent).
120 bool isJoinDivergent(const BasicBlock &Block) const {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200121 return DivergentJoinBlocks.contains(&Block);
Andrew Walbran16937d02019-10-22 13:54:20 +0100122 }
123
Andrew Walbran16937d02019-10-22 13:54:20 +0100124private:
125 const Function &F;
126 // If regionLoop != nullptr, analysis is only performed within \p RegionLoop.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200127 // Otherwise, analyze the whole function
Andrew Walbran16937d02019-10-22 13:54:20 +0100128 const Loop *RegionLoop;
129
130 const DominatorTree &DT;
131 const LoopInfo &LI;
132
133 // Recognized divergent loops
134 DenseSet<const Loop *> DivergentLoops;
135
136 // The SDA links divergent branches to divergent control-flow joins.
137 SyncDependenceAnalysis &SDA;
138
139 // Use simplified code path for LCSSA form.
140 bool IsLCSSAForm;
141
142 // Set of known-uniform values.
143 DenseSet<const Value *> UniformOverrides;
144
145 // Blocks with joining divergent control from different predecessors.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200146 DenseSet<const BasicBlock *> DivergentJoinBlocks; // FIXME Deprecated
Andrew Walbran16937d02019-10-22 13:54:20 +0100147
148 // Detected/marked divergent values.
149 DenseSet<const Value *> DivergentValues;
150
151 // Internal worklist for divergence propagation.
152 std::vector<const Instruction *> Worklist;
153};
154
155/// \brief Divergence analysis frontend for GPU kernels.
156class GPUDivergenceAnalysis {
157 SyncDependenceAnalysis SDA;
158 DivergenceAnalysis DA;
159
160public:
161 /// Runs the divergence analysis on @F, a GPU kernel
162 GPUDivergenceAnalysis(Function &F, const DominatorTree &DT,
163 const PostDominatorTree &PDT, const LoopInfo &LI,
164 const TargetTransformInfo &TTI);
165
166 /// Whether any divergence was detected.
167 bool hasDivergence() const { return DA.hasDetectedDivergence(); }
168
169 /// The GPU kernel this analysis result is for
170 const Function &getFunction() const { return DA.getFunction(); }
171
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200172 /// Whether \p V is divergent at its definition.
Andrew Walbran16937d02019-10-22 13:54:20 +0100173 bool isDivergent(const Value &V) const;
174
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200175 /// Whether \p U is divergent. Uses of a uniform value can be divergent.
176 bool isDivergentUse(const Use &U) const;
177
178 /// Whether \p V is uniform/non-divergent.
Andrew Walbran16937d02019-10-22 13:54:20 +0100179 bool isUniform(const Value &V) const { return !isDivergent(V); }
180
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200181 /// Whether \p U is uniform/non-divergent. Uses of a uniform value can be
182 /// divergent.
183 bool isUniformUse(const Use &U) const { return !isDivergentUse(U); }
184
Andrew Walbran16937d02019-10-22 13:54:20 +0100185 /// Print all divergent values in the kernel.
186 void print(raw_ostream &OS, const Module *) const;
187};
188
189} // namespace llvm
190
191#endif // LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H