Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DA] DivergenceAnalysis for unstructured, reducible CFGs
Summary: This is patch 2 of the new DivergenceAnalysis (https://reviews.llvm.org/D50433). This patch contains a generic divergence analysis implementation for unstructured, reducible Control-Flow Graphs. It contains two new classes. The `SyncDependenceAnalysis` class lazily computes sync dependences, which relate divergent branches to points of joining divergent control. The `DivergenceAnalysis` class contains the generic divergence analysis implementation. Reviewers: nhaehnle Reviewed By: nhaehnle Subscribers: sameerds, kristina, nhaehnle, xbolva00, tschuett, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D51491 llvm-svn: 344734
- Loading branch information
Showing
8 changed files
with
1,508 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
//===- llvm/Analysis/DivergenceAnalysis.h - Divergence Analysis -*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// \file | ||
// The divergence analysis determines which instructions and branches are | ||
// divergent given a set of divergent source instructions. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H | ||
#define LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H | ||
|
||
#include "llvm/ADT/DenseSet.h" | ||
#include "llvm/Analysis/SyncDependenceAnalysis.h" | ||
#include "llvm/IR/Function.h" | ||
#include "llvm/Pass.h" | ||
#include <vector> | ||
|
||
namespace llvm { | ||
class Module; | ||
class Value; | ||
class Instruction; | ||
class Loop; | ||
class raw_ostream; | ||
class TargetTransformInfo; | ||
|
||
/// \brief Generic divergence analysis for reducible CFGs. | ||
/// | ||
/// This analysis propagates divergence in a data-parallel context from sources | ||
/// of divergence to all users. It requires reducible CFGs. All assignments | ||
/// should be in SSA form. | ||
class DivergenceAnalysis { | ||
public: | ||
/// \brief This instance will analyze the whole function \p F or the loop \p | ||
/// RegionLoop. | ||
/// | ||
/// \param RegionLoop if non-null the analysis is restricted to \p RegionLoop. | ||
/// Otherwise the whole function is analyzed. | ||
/// \param IsLCSSAForm whether the analysis may assume that the IR in the | ||
/// region in in LCSSA form. | ||
DivergenceAnalysis(const Function &F, const Loop *RegionLoop, | ||
const DominatorTree &DT, const LoopInfo &LI, | ||
SyncDependenceAnalysis &SDA, bool IsLCSSAForm); | ||
|
||
/// \brief The loop that defines the analyzed region (if any). | ||
const Loop *getRegionLoop() const { return RegionLoop; } | ||
const Function &getFunction() const { return F; } | ||
|
||
/// \brief Whether \p BB is part of the region. | ||
bool inRegion(const BasicBlock &BB) const; | ||
/// \brief Whether \p I is part of the region. | ||
bool inRegion(const Instruction &I) const; | ||
|
||
/// \brief Mark \p UniVal as a value that is always uniform. | ||
void addUniformOverride(const Value &UniVal); | ||
|
||
/// \brief Mark \p DivVal as a value that is always divergent. | ||
void markDivergent(const Value &DivVal); | ||
|
||
/// \brief Propagate divergence to all instructions in the region. | ||
/// Divergence is seeded by calls to \p markDivergent. | ||
void compute(); | ||
|
||
/// \brief Whether any value was marked or analyzed to be divergent. | ||
bool hasDetectedDivergence() const { return !DivergentValues.empty(); } | ||
|
||
/// \brief Whether \p Val will always return a uniform value regardless of its | ||
/// operands | ||
bool isAlwaysUniform(const Value &Val) const; | ||
|
||
/// \brief Whether \p Val is a divergent value | ||
bool isDivergent(const Value &Val) const; | ||
|
||
void print(raw_ostream &OS, const Module *) const; | ||
|
||
private: | ||
bool updateTerminator(const TerminatorInst &Term) const; | ||
bool updatePHINode(const PHINode &Phi) const; | ||
|
||
/// \brief Computes whether \p Inst is divergent based on the | ||
/// divergence of its operands. | ||
/// | ||
/// \returns Whether \p Inst is divergent. | ||
/// | ||
/// This should only be called for non-phi, non-terminator instructions. | ||
bool updateNormalInstruction(const Instruction &Inst) const; | ||
|
||
/// \brief Mark users of live-out users as divergent. | ||
/// | ||
/// \param LoopHeader the header of the divergent loop. | ||
/// | ||
/// Marks all users of live-out values of the loop headed by \p LoopHeader | ||
/// as divergent and puts them on the worklist. | ||
void taintLoopLiveOuts(const BasicBlock &LoopHeader); | ||
|
||
/// \brief Push all users of \p Val (in the region) to the worklist | ||
void pushUsers(const Value &I); | ||
|
||
/// \brief Push all phi nodes in @block to the worklist | ||
void pushPHINodes(const BasicBlock &Block); | ||
|
||
/// \brief Mark \p Block as join divergent | ||
/// | ||
/// A block is join divergent if two threads may reach it from different | ||
/// incoming blocks at the same time. | ||
void markBlockJoinDivergent(const BasicBlock &Block) { | ||
DivergentJoinBlocks.insert(&Block); | ||
} | ||
|
||
/// \brief Whether \p Val is divergent when read in \p ObservingBlock. | ||
bool isTemporalDivergent(const BasicBlock &ObservingBlock, | ||
const Value &Val) const; | ||
|
||
/// \brief Whether \p Block is join divergent | ||
/// | ||
/// (see markBlockJoinDivergent). | ||
bool isJoinDivergent(const BasicBlock &Block) const { | ||
return DivergentJoinBlocks.find(&Block) != DivergentJoinBlocks.end(); | ||
} | ||
|
||
/// \brief Propagate control-induced divergence to users (phi nodes and | ||
/// instructions). | ||
// | ||
// \param JoinBlock is a divergent loop exit or join point of two disjoint | ||
// paths. | ||
// \returns Whether \p JoinBlock is a divergent loop exit of \p TermLoop. | ||
bool propagateJoinDivergence(const BasicBlock &JoinBlock, | ||
const Loop *TermLoop); | ||
|
||
/// \brief Propagate induced value divergence due to control divergence in \p | ||
/// Term. | ||
void propagateBranchDivergence(const TerminatorInst &Term); | ||
|
||
/// \brief Propagate divergent caused by a divergent loop exit. | ||
/// | ||
/// \param ExitingLoop is a divergent loop. | ||
void propagateLoopDivergence(const Loop &ExitingLoop); | ||
|
||
private: | ||
const Function &F; | ||
// If regionLoop != nullptr, analysis is only performed within \p RegionLoop. | ||
// Otw, analyze the whole function | ||
const Loop *RegionLoop; | ||
|
||
const DominatorTree &DT; | ||
const LoopInfo &LI; | ||
|
||
// Recognized divergent loops | ||
DenseSet<const Loop *> DivergentLoops; | ||
|
||
// The SDA links divergent branches to divergent control-flow joins. | ||
SyncDependenceAnalysis &SDA; | ||
|
||
// Use simplified code path for LCSSA form. | ||
bool IsLCSSAForm; | ||
|
||
// Set of known-uniform values. | ||
DenseSet<const Value *> UniformOverrides; | ||
|
||
// Blocks with joining divergent control from different predecessors. | ||
DenseSet<const BasicBlock *> DivergentJoinBlocks; | ||
|
||
// Detected/marked divergent values. | ||
DenseSet<const Value *> DivergentValues; | ||
|
||
// Internal worklist for divergence propagation. | ||
std::vector<const Instruction *> Worklist; | ||
}; | ||
|
||
} // namespace llvm | ||
|
||
#endif // LLVM_ANALYSIS_DIVERGENCE_ANALYSIS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
//===- SyncDependenceAnalysis.h - Divergent Branch Dependence -*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// \file | ||
// This file defines the SyncDependenceAnalysis class, which computes for | ||
// every divergent branch the set of phi nodes that the branch will make | ||
// divergent. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_ANALYSIS_SYNC_DEPENDENCE_ANALYSIS_H | ||
#define LLVM_ANALYSIS_SYNC_DEPENDENCE_ANALYSIS_H | ||
|
||
#include "llvm/ADT/DenseMap.h" | ||
#include "llvm/ADT/PostOrderIterator.h" | ||
#include "llvm/ADT/SmallPtrSet.h" | ||
#include "llvm/Analysis/LoopInfo.h" | ||
#include <memory> | ||
|
||
namespace llvm { | ||
|
||
class BasicBlock; | ||
class DominatorTree; | ||
class Loop; | ||
class PostDominatorTree; | ||
class TerminatorInst; | ||
class TerminatorInst; | ||
|
||
using ConstBlockSet = SmallPtrSet<const BasicBlock *, 4>; | ||
|
||
/// \brief Relates points of divergent control to join points in | ||
/// reducible CFGs. | ||
/// | ||
/// This analysis relates points of divergent control to points of converging | ||
/// divergent control. The analysis requires all loops to be reducible. | ||
class SyncDependenceAnalysis { | ||
void visitSuccessor(const BasicBlock &succBlock, const Loop *termLoop, | ||
const BasicBlock *defBlock); | ||
|
||
public: | ||
bool inRegion(const BasicBlock &BB) const; | ||
|
||
~SyncDependenceAnalysis(); | ||
SyncDependenceAnalysis(const DominatorTree &DT, const PostDominatorTree &PDT, | ||
const LoopInfo &LI); | ||
|
||
/// \brief Computes divergent join points and loop exits caused by branch | ||
/// divergence in \p Term. | ||
/// | ||
/// The set of blocks which are reachable by disjoint paths from \p Term. | ||
/// The set also contains loop exits if there two disjoint paths: | ||
/// one from \p Term to the loop exit and another from \p Term to the loop | ||
/// header. Those exit blocks are added to the returned set. | ||
/// If L is the parent loop of \p Term and an exit of L is in the returned | ||
/// set then L is a divergent loop. | ||
const ConstBlockSet &join_blocks(const TerminatorInst &Term); | ||
|
||
/// \brief Computes divergent join points and loop exits (in the surrounding | ||
/// loop) caused by the divergent loop exits of\p Loop. | ||
/// | ||
/// The set of blocks which are reachable by disjoint paths from the | ||
/// loop exits of \p Loop. | ||
/// This treats the loop as a single node in \p Loop's parent loop. | ||
/// The returned set has the same properties as for join_blocks(TermInst&). | ||
const ConstBlockSet &join_blocks(const Loop &Loop); | ||
|
||
private: | ||
static ConstBlockSet EmptyBlockSet; | ||
|
||
ReversePostOrderTraversal<const Function *> FuncRPOT; | ||
const DominatorTree &DT; | ||
const PostDominatorTree &PDT; | ||
const LoopInfo &LI; | ||
|
||
std::map<const Loop *, std::unique_ptr<ConstBlockSet>> CachedLoopExitJoins; | ||
std::map<const TerminatorInst *, std::unique_ptr<ConstBlockSet>> | ||
CachedBranchJoins; | ||
}; | ||
|
||
} // namespace llvm | ||
|
||
#endif // LLVM_ANALYSIS_SYNC_DEPENDENCE_ANALYSIS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.