Skip to content

Commit 05ae04c

Browse files
author
Simon Moll
committed
[DA][SDA] SyncDependenceAnalysis re-write
This patch achieves two things: 1. It breaks up the `join_blocks` interface between the SDA to the DA to return two separate sets for divergent loops exits and divergent, disjoint path joins. 2. It updates the SDA algorithm to run in O(n) time and improves the precision on divergent loop exits. This fixes `https://bugs.llvm.org/show_bug.cgi?id=46372` (by virtue of the improved `join_blocks` interface) and revealed an imprecise expected result in the `Analysis/DivergenceAnalysis/AMDGPU/hidden_loopdiverge.ll` test. Reviewed By: sameerds Differential Revision: https://reviews.llvm.org/D84413
1 parent d6de40f commit 05ae04c

File tree

6 files changed

+455
-470
lines changed

6 files changed

+455
-470
lines changed

llvm/include/llvm/Analysis/DivergenceAnalysis.h

Lines changed: 30 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ class DivergenceAnalysis {
5959
/// \brief Mark \p UniVal as a value that is always uniform.
6060
void addUniformOverride(const Value &UniVal);
6161

62-
/// \brief Mark \p DivVal as a value that is always divergent.
63-
void markDivergent(const Value &DivVal);
62+
/// \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);
6466

6567
/// \brief Propagate divergence to all instructions in the region.
6668
/// Divergence is seeded by calls to \p markDivergent.
@@ -76,45 +78,38 @@ class DivergenceAnalysis {
7678
/// \brief Whether \p Val is divergent at its definition.
7779
bool isDivergent(const Value &Val) const;
7880

79-
/// \brief Whether \p U is divergent. Uses of a uniform value can be divergent.
81+
/// \brief Whether \p U is divergent. Uses of a uniform value can be
82+
/// divergent.
8083
bool isDivergentUse(const Use &U) const;
8184

8285
void print(raw_ostream &OS, const Module *) const;
8386

8487
private:
85-
bool updateTerminator(const Instruction &Term) const;
86-
bool updatePHINode(const PHINode &Phi) const;
87-
88-
/// \brief Computes whether \p Inst is divergent based on the
89-
/// divergence of its operands.
90-
///
91-
/// \returns Whether \p Inst is divergent.
92-
///
93-
/// This should only be called for non-phi, non-terminator instructions.
94-
bool updateNormalInstruction(const Instruction &Inst) const;
95-
96-
/// \brief Mark users of live-out users as divergent.
97-
///
98-
/// \param LoopHeader the header of the divergent loop.
99-
///
100-
/// Marks all users of live-out values of the loop headed by \p LoopHeader
101-
/// as divergent and puts them on the worklist.
102-
void taintLoopLiveOuts(const BasicBlock &LoopHeader);
103-
104-
/// \brief Push all users of \p Val (in the region) to the worklist
88+
/// \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);
94+
95+
/// \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);
100+
101+
/// \brief Internal implementation function for propagateLoopExitDivergence.
102+
void analyzeLoopExitDivergence(const BasicBlock &DivExit,
103+
const Loop &OuterDivLoop);
104+
105+
/// \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.
105111
void pushUsers(const Value &I);
106112

107-
/// \brief Push all phi nodes in @block to the worklist
108-
void pushPHINodes(const BasicBlock &Block);
109-
110-
/// \brief Mark \p Block as join divergent
111-
///
112-
/// A block is join divergent if two threads may reach it from different
113-
/// incoming blocks at the same time.
114-
void markBlockJoinDivergent(const BasicBlock &Block) {
115-
DivergentJoinBlocks.insert(&Block);
116-
}
117-
118113
/// \brief Whether \p Val is divergent when read in \p ObservingBlock.
119114
bool isTemporalDivergent(const BasicBlock &ObservingBlock,
120115
const Value &Val) const;
@@ -126,24 +121,6 @@ class DivergenceAnalysis {
126121
return DivergentJoinBlocks.find(&Block) != DivergentJoinBlocks.end();
127122
}
128123

129-
/// \brief Propagate control-induced divergence to users (phi nodes and
130-
/// instructions).
131-
//
132-
// \param JoinBlock is a divergent loop exit or join point of two disjoint
133-
// paths.
134-
// \returns Whether \p JoinBlock is a divergent loop exit of \p TermLoop.
135-
bool propagateJoinDivergence(const BasicBlock &JoinBlock,
136-
const Loop *TermLoop);
137-
138-
/// \brief Propagate induced value divergence due to control divergence in \p
139-
/// Term.
140-
void propagateBranchDivergence(const Instruction &Term);
141-
142-
/// \brief Propagate divergent caused by a divergent loop exit.
143-
///
144-
/// \param ExitingLoop is a divergent loop.
145-
void propagateLoopDivergence(const Loop &ExitingLoop);
146-
147124
private:
148125
const Function &F;
149126
// If regionLoop != nullptr, analysis is only performed within \p RegionLoop.
@@ -166,7 +143,7 @@ class DivergenceAnalysis {
166143
DenseSet<const Value *> UniformOverrides;
167144

168145
// Blocks with joining divergent control from different predecessors.
169-
DenseSet<const BasicBlock *> DivergentJoinBlocks;
146+
DenseSet<const BasicBlock *> DivergentJoinBlocks; // FIXME Deprecated
170147

171148
// Detected/marked divergent values.
172149
DenseSet<const Value *> DivergentValues;

llvm/include/llvm/Analysis/SyncDependenceAnalysis.h

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/ADT/SmallPtrSet.h"
2222
#include "llvm/Analysis/LoopInfo.h"
2323
#include <memory>
24+
#include <unordered_map>
2425

2526
namespace llvm {
2627

@@ -30,6 +31,26 @@ class Loop;
3031
class PostDominatorTree;
3132

3233
using ConstBlockSet = SmallPtrSet<const BasicBlock *, 4>;
34+
struct ControlDivergenceDesc {
35+
// Join points of divergent disjoint paths.
36+
ConstBlockSet JoinDivBlocks;
37+
// Divergent loop exits
38+
ConstBlockSet LoopDivBlocks;
39+
};
40+
41+
struct ModifiedPO {
42+
std::vector<const BasicBlock *> LoopPO;
43+
std::unordered_map<const BasicBlock *, unsigned> POIndex;
44+
void appendBlock(const BasicBlock &BB) {
45+
POIndex[&BB] = LoopPO.size();
46+
LoopPO.push_back(&BB);
47+
}
48+
unsigned getIndexOf(const BasicBlock &BB) const {
49+
return POIndex.find(&BB)->second;
50+
}
51+
unsigned size() const { return LoopPO.size(); }
52+
const BasicBlock *getBlockAt(unsigned Idx) const { return LoopPO[Idx]; }
53+
};
3354

3455
/// \brief Relates points of divergent control to join points in
3556
/// reducible CFGs.
@@ -51,28 +72,19 @@ class SyncDependenceAnalysis {
5172
/// header. Those exit blocks are added to the returned set.
5273
/// If L is the parent loop of \p Term and an exit of L is in the returned
5374
/// set then L is a divergent loop.
54-
const ConstBlockSet &join_blocks(const Instruction &Term);
55-
56-
/// \brief Computes divergent join points and loop exits (in the surrounding
57-
/// loop) caused by the divergent loop exits of\p Loop.
58-
///
59-
/// The set of blocks which are reachable by disjoint paths from the
60-
/// loop exits of \p Loop.
61-
/// This treats the loop as a single node in \p Loop's parent loop.
62-
/// The returned set has the same properties as for join_blocks(TermInst&).
63-
const ConstBlockSet &join_blocks(const Loop &Loop);
75+
const ControlDivergenceDesc &getJoinBlocks(const Instruction &Term);
6476

6577
private:
66-
static ConstBlockSet EmptyBlockSet;
78+
static ControlDivergenceDesc EmptyDivergenceDesc;
79+
80+
ModifiedPO LoopPO;
6781

68-
ReversePostOrderTraversal<const Function *> FuncRPOT;
6982
const DominatorTree &DT;
7083
const PostDominatorTree &PDT;
7184
const LoopInfo &LI;
7285

73-
std::map<const Loop *, std::unique_ptr<ConstBlockSet>> CachedLoopExitJoins;
74-
std::map<const Instruction *, std::unique_ptr<ConstBlockSet>>
75-
CachedBranchJoins;
86+
std::map<const Instruction *, std::unique_ptr<ControlDivergenceDesc>>
87+
CachedControlDivDescs;
7688
};
7789

7890
} // namespace llvm

0 commit comments

Comments
 (0)