
Fix code quality issues reported by static analysis tool, such as: - Rule of Three/Five. - Dereference after null check. - Unchecked return value. - Variable copied when it could be moved.
186 lines
6.3 KiB
C++
186 lines
6.3 KiB
C++
//===- SPIRVConvergenceRegionAnalysis.h ------------------------*- C++ -*--===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// The analysis determines the convergence region for each basic block of
|
|
// the module, and provides a tree-like structure describing the region
|
|
// hierarchy.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVCONVERGENCEREGIONANALYSIS_H
|
|
#define LLVM_LIB_TARGET_SPIRV_SPIRVCONVERGENCEREGIONANALYSIS_H
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/Analysis/CFG.h"
|
|
#include "llvm/Analysis/LoopInfo.h"
|
|
#include "llvm/IR/Dominators.h"
|
|
#include <optional>
|
|
#include <unordered_set>
|
|
|
|
namespace llvm {
|
|
class IntrinsicInst;
|
|
class SPIRVSubtarget;
|
|
class MachineFunction;
|
|
class MachineModuleInfo;
|
|
|
|
namespace SPIRV {
|
|
|
|
// Returns the first convergence intrinsic found in |BB|, |nullopt| otherwise.
|
|
std::optional<IntrinsicInst *> getConvergenceToken(BasicBlock *BB);
|
|
std::optional<const IntrinsicInst *> getConvergenceToken(const BasicBlock *BB);
|
|
|
|
// Describes a hierarchy of convergence regions.
|
|
// A convergence region defines a CFG for which the execution flow can diverge
|
|
// starting from the entry block, but should reconverge back before the end of
|
|
// the exit blocks.
|
|
class ConvergenceRegion {
|
|
DominatorTree &DT;
|
|
LoopInfo &LI;
|
|
|
|
public:
|
|
// The parent region of this region, if any.
|
|
ConvergenceRegion *Parent = nullptr;
|
|
// The sub-regions contained in this region, if any.
|
|
SmallVector<ConvergenceRegion *> Children = {};
|
|
// The convergence instruction linked to this region, if any.
|
|
std::optional<IntrinsicInst *> ConvergenceToken = std::nullopt;
|
|
// The only block with a predecessor outside of this region.
|
|
BasicBlock *Entry = nullptr;
|
|
// All the blocks with an edge leaving this convergence region.
|
|
SmallPtrSet<BasicBlock *, 2> Exits = {};
|
|
// All the blocks that belongs to this region, including its subregions'.
|
|
SmallPtrSet<BasicBlock *, 8> Blocks = {};
|
|
|
|
// Creates a single convergence region encapsulating the whole function |F|.
|
|
ConvergenceRegion(DominatorTree &DT, LoopInfo &LI, Function &F);
|
|
|
|
// Creates a single convergence region defined by entry and exits nodes, a
|
|
// list of blocks, and possibly a convergence token.
|
|
ConvergenceRegion(DominatorTree &DT, LoopInfo &LI,
|
|
std::optional<IntrinsicInst *> ConvergenceToken,
|
|
BasicBlock *Entry, SmallPtrSet<BasicBlock *, 8> &&Blocks,
|
|
SmallPtrSet<BasicBlock *, 2> &&Exits);
|
|
|
|
ConvergenceRegion(ConvergenceRegion &&CR)
|
|
: DT(CR.DT), LI(CR.LI), Parent(std::move(CR.Parent)),
|
|
Children(std::move(CR.Children)),
|
|
ConvergenceToken(std::move(CR.ConvergenceToken)),
|
|
Entry(std::move(CR.Entry)), Exits(std::move(CR.Exits)),
|
|
Blocks(std::move(CR.Blocks)) {}
|
|
|
|
~ConvergenceRegion() { releaseMemory(); }
|
|
|
|
ConvergenceRegion &operator=(ConvergenceRegion &&CR) = delete;
|
|
ConvergenceRegion(const ConvergenceRegion &other) = delete;
|
|
ConvergenceRegion &operator=(const ConvergenceRegion &other) = delete;
|
|
|
|
// Returns true if the given basic block belongs to this region, or to one of
|
|
// its subregion.
|
|
bool contains(const BasicBlock *BB) const { return Blocks.count(BB) != 0; }
|
|
|
|
void releaseMemory();
|
|
|
|
// Write to the debug output this region's hierarchy.
|
|
// |IndentSize| defines the number of tabs to print before any new line.
|
|
void dump(const unsigned IndentSize = 0) const;
|
|
};
|
|
|
|
// Holds a ConvergenceRegion hierarchy.
|
|
class ConvergenceRegionInfo {
|
|
// The convergence region this structure holds.
|
|
ConvergenceRegion *TopLevelRegion;
|
|
|
|
public:
|
|
ConvergenceRegionInfo() : TopLevelRegion(nullptr) {}
|
|
|
|
// Creates a new ConvergenceRegionInfo. Ownership of the TopLevelRegion is
|
|
// passed to this object.
|
|
ConvergenceRegionInfo(ConvergenceRegion *TopLevelRegion)
|
|
: TopLevelRegion(TopLevelRegion) {}
|
|
|
|
~ConvergenceRegionInfo() { releaseMemory(); }
|
|
|
|
ConvergenceRegionInfo(const ConvergenceRegionInfo &LHS) = delete;
|
|
ConvergenceRegionInfo &operator=(const ConvergenceRegionInfo &LHS) = delete;
|
|
|
|
ConvergenceRegionInfo(ConvergenceRegionInfo &&LHS)
|
|
: TopLevelRegion(LHS.TopLevelRegion) {
|
|
if (TopLevelRegion != LHS.TopLevelRegion) {
|
|
releaseMemory();
|
|
TopLevelRegion = LHS.TopLevelRegion;
|
|
}
|
|
LHS.TopLevelRegion = nullptr;
|
|
}
|
|
|
|
ConvergenceRegionInfo &operator=(ConvergenceRegionInfo &&LHS) {
|
|
if (TopLevelRegion != LHS.TopLevelRegion) {
|
|
releaseMemory();
|
|
TopLevelRegion = LHS.TopLevelRegion;
|
|
}
|
|
LHS.TopLevelRegion = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
void releaseMemory() {
|
|
if (TopLevelRegion == nullptr)
|
|
return;
|
|
|
|
TopLevelRegion->releaseMemory();
|
|
delete TopLevelRegion;
|
|
TopLevelRegion = nullptr;
|
|
}
|
|
|
|
const ConvergenceRegion *getTopLevelRegion() const { return TopLevelRegion; }
|
|
ConvergenceRegion *getWritableTopLevelRegion() const {
|
|
return TopLevelRegion;
|
|
}
|
|
};
|
|
|
|
} // namespace SPIRV
|
|
|
|
// Wrapper around the function above to use it with the legacy pass manager.
|
|
class SPIRVConvergenceRegionAnalysisWrapperPass : public FunctionPass {
|
|
SPIRV::ConvergenceRegionInfo CRI;
|
|
|
|
public:
|
|
static char ID;
|
|
|
|
SPIRVConvergenceRegionAnalysisWrapperPass();
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesAll();
|
|
AU.addRequired<LoopInfoWrapperPass>();
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
|
};
|
|
|
|
bool runOnFunction(Function &F) override;
|
|
|
|
SPIRV::ConvergenceRegionInfo &getRegionInfo() { return CRI; }
|
|
const SPIRV::ConvergenceRegionInfo &getRegionInfo() const { return CRI; }
|
|
};
|
|
|
|
// Wrapper around the function above to use it with the new pass manager.
|
|
class SPIRVConvergenceRegionAnalysis
|
|
: public AnalysisInfoMixin<SPIRVConvergenceRegionAnalysis> {
|
|
friend AnalysisInfoMixin<SPIRVConvergenceRegionAnalysis>;
|
|
static AnalysisKey Key;
|
|
|
|
public:
|
|
using Result = SPIRV::ConvergenceRegionInfo;
|
|
|
|
Result run(Function &F, FunctionAnalysisManager &AM);
|
|
};
|
|
|
|
namespace SPIRV {
|
|
ConvergenceRegionInfo getConvergenceRegions(Function &F, DominatorTree &DT,
|
|
LoopInfo &LI);
|
|
} // namespace SPIRV
|
|
|
|
} // namespace llvm
|
|
#endif // LLVM_LIB_TARGET_SPIRV_SPIRVCONVERGENCEREGIONANALYSIS_H
|