1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#pragma once
#include "Compiler/MetaDataApi/MetaDataApi.h"
#include "common/LLVMWarningsPush.hpp"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/CallGraph.h"
#include "common/LLVMWarningsPop.hpp"
#include "common/Types.hpp"
#include "Probe/Assertion.h"
namespace IGC {
class GenXFunctionGroupAnalysis;
/// \brief A module pass to initialize GenXFunctionGroupAnalysis and sort function
/// list in a module properly.
///
/// The module pass's results have two parts:
///
/// (1) GenXFunctionGroupAnalysis object, which stores information needed for vISA
/// emission. E.g, each non-empty function belongs to a uniquely defined
/// function group with a kernel function as the head.
///
/// (2) The module itself. All functions reachable from different function
/// groups will be cloned if necessary; they will be ordered such that each
/// callee will be after the caller in the module function list. When clone
/// happens, this module pass returns true, otherwise it returns false.
/// Currently, we assume no kernel functions will be called. This
/// requirement could be enforced before this pass by inlining kernels.
///
class GenXCodeGenModule : public llvm::ModulePass {
public:
static char ID;
GenXCodeGenModule();
~GenXCodeGenModule();
virtual llvm::StringRef getPassName() const override { return "GenX CodeGen module"; }
void getAnalysisUsage(llvm::AnalysisUsage& AU) const override;
bool runOnModule(llvm::Module& M) override;
private:
void processFunction(llvm::Function& F);
void processSCC(std::vector<llvm::CallGraphNode*>* SCCNodes);
void setFuncProperties(llvm::CallGraph& CG);
void copyFuncProperties(llvm::Function* To, llvm::Function* From);
llvm::Function* cloneFunc(llvm::Function* F);
GenXFunctionGroupAnalysis* FGA;
IGC::IGCMD::MetaDataUtils* pMdUtils;
bool Modified;
unsigned m_FunctionCloningThreshold = 0;
};
/// \brief A collection of functions that are reachable from a kernel.
class FunctionGroup {
public:
friend class GenXFunctionGroupAnalysis;
/// \brief use 2-d vector of Functions to represent FunctionGroup.
/// Each sub-vector is a subgroup led by a kernel or a stack-call function.
/// Element [0][0] is the group head. Element[i][0] is the sub-group head.
typedef llvm::SmallVector<llvm::AssertingVH<llvm::Function>, 8> SubGroupContainer;
typedef llvm::SmallVector<SubGroupContainer*, 4> FunctionGroupContainer;
FunctionGroupContainer Functions;
class iterator
{
public:
enum POS { BEGIN, END };
iterator(FunctionGroupContainer &FC, POS pos)
{
if (pos == BEGIN)
{
major = FC.begin();
majorEnd = FC.end();
minor = (*major)->begin();
}
else if (pos == END)
{
major = FC.end();
majorEnd = FC.end();
minor = FC.back()->end();
}
}
iterator& operator++()
{
minor++;
if (minor == (*major)->end())
{
major++;
if (major != majorEnd)
minor = (*major)->begin();
}
return *this;
}
llvm::Function* operator*()
{
return *minor;
}
bool operator==(const iterator& rhs)
{
return (major == rhs.major && minor == rhs.minor);
}
bool operator!=(const iterator& rhs)
{
return !(*this == rhs);
}
private:
FunctionGroupContainer::iterator major;
FunctionGroupContainer::iterator majorEnd;
SubGroupContainer::iterator minor;
};
iterator begin() { return iterator(Functions, iterator::BEGIN); }
iterator end() { return iterator(Functions, iterator::END); }
~FunctionGroup() {
for (auto F : Functions) {
delete F;
}
}
/// \brief The entry kernel function of group.
llvm::Function* getHead() const {
return Functions.front()->front();
}
/// \brief The tail function of a group.
llvm::Function* back() const {
return Functions.back()->back();
}
/// \brief Only one function in this group
bool isSingle() const {
return (Functions.size() == 1 && Functions.front()->size() == 1);
}
/// \brief Function group has a stack call (including indirect calls)
bool hasStackCall() const {
return m_hasStackCall;
}
bool hasInlineAsm() const {
return m_hasInlineAsm;
}
/// \brief Function group has a variable length alloca
bool hasVariableLengthAlloca() const {
return m_hasVariableLengthAlloca;
}
/// \brief Function group has indirect calls
bool hasIndirectCall() const {
return m_hasIndirectCall;
}
/// \brief Function group has recursion
bool hasRecursion() const {
return m_hasRecursion;
}
void replaceGroupHead(llvm::Function* OH, llvm::Function* NH) {
IGC_UNUSED(OH);
auto headSG = Functions[0];
llvm::AssertingVH<llvm::Function>& HVH = (*headSG)[0];
IGC_ASSERT_MESSAGE(&(*HVH) == OH, "Group's head isn't set up correctly!");
HVH = NH;
}
// For a single FG, an SIMD mode is valid only if SIMD modes of all
// functions in that group are valid.
bool checkSimdModeValid(SIMDMode Mode) const;
void setSimdModeInvalid(SIMDMode Mode);
private:
bool m_hasStackCall = false;
bool m_hasInlineAsm = false;
bool m_hasVariableLengthAlloca = false;
bool m_hasIndirectCall = false;
bool m_hasRecursion = false;
bool SIMDModeValid[3] = {true, true, true};
};
class GenXFunctionGroupAnalysis : public llvm::ImmutablePass {
enum class FuncPropertyInfo : uint32_t {
FPI_LEAF = 0x1 // bit 0: 1 (leaf function)
};
/// \brief The module being analyzed.
llvm::Module* M;
/// \brief Function groups constructed in this module.
llvm::SmallVector<FunctionGroup*, 8> Groups;
/// \brief Each function belongs to a uniquely defined function group.
llvm::DenseMap<const llvm::Function*, FunctionGroup*> GroupMap;
/// \brief Each function also belongs to a uniquely defined sub-group of a stack-call entry
llvm::DenseMap<const llvm::Function*, llvm::Function*> SubGroupMap;
/// \brief Properties for each function
llvm::DenseMap<const llvm::Function*, uint32_t> FuncProperties;
/// \brief Special group that contains all indirect call functions
FunctionGroup* IndirectCallGroup = nullptr;
public:
static char ID;
explicit GenXFunctionGroupAnalysis();
~GenXFunctionGroupAnalysis() { clear(); }
virtual llvm::StringRef getPassName() const override { return "FunctionGroup analysis"; }
/// This function returns nullptr if no analysis is not available.
llvm::Module* getModule() { return M; }
void setModule(llvm::Module* Mod) { M = Mod; }
void clear();
/// \brief This function rebuilds function groups with the assumption that
/// no function will be directly or undirectly called from more than one
/// kernel, and functions in the module are well-ordered. It returns false if
/// fails to rebuild and returns true otherwise.
///
bool rebuild(llvm::Module* Mod);
// Attach all indirectly called functions to a single kernel group
void addIndirectFuncsToKernelGroup(llvm::Module* pModule);
// Replace OF with NF in Groups and GroupMap
void replaceEntryFunc(llvm::Function* OF, llvm::Function* NF);
/// \brief Verify if this analysis result is valid.
bool verify();
void getAnalysisUsage(llvm::AnalysisUsage& AU) const override;
/// \brief Get the FunctionGroup containing Function F, else nullptr.
FunctionGroup* getGroup(const llvm::Function* F);
/// \brief Get the FunctionGroup for which Function F is the head, else
/// nullptr.
FunctionGroup* getGroupForHead(const llvm::Function* F);
/// \brief Get the group head for the group to which F belongs.
llvm::Function* getGroupHead(const llvm::Function* F) {
auto FG = getGroup(F);
IGC_ASSERT(nullptr != FG);
return FG->getHead();
}
/// \brief Get the subgroup head for the subgroup to which F belongs
llvm::Function* getSubGroupMap(llvm::Function* F) {
auto I = SubGroupMap.find(F);
if (I == SubGroupMap.end())
return nullptr;
return I->second;
}
void setSubGroupMap(llvm::Function* F, llvm::Function* SubGroupHead) {
SubGroupMap[F] = SubGroupHead;
}
bool isIndirectCallGroup(const llvm::Function* F) {
FunctionGroup* FG = getGroup(F);
return FG != nullptr && FG == IndirectCallGroup;
}
FunctionGroup* getIndirectCallGroup() {
return IndirectCallGroup;
}
/// \brief Check whether this is a group header.
bool isGroupHead(const llvm::Function* F) {
return getGroupForHead(F) != nullptr;
}
/// \brief Check whether this is the last function in a function group. This
/// order is also reflected in the module function list.
bool isGroupTail(const llvm::Function* F) {
FunctionGroup* FG = getGroup(F);
IGC_ASSERT_MESSAGE(nullptr != FG, "not in function group");
return F == FG->back();
}
bool isLeafFunc(const llvm::Function* F) {
auto FI = FuncProperties.find(F);
if (FI != FuncProperties.end()) {
return (FI->second & (uint32_t)FuncPropertyInfo::FPI_LEAF);
}
return false;
}
void setLeafFunc(const llvm::Function* F) {
auto II = FuncProperties.find(F);
uint32_t P = (II != FuncProperties.end()) ? II->second : 0;
FuncProperties[F] = (P | (uint32_t)FuncPropertyInfo::FPI_LEAF);
}
void copyFuncProperties(const llvm::Function* To, const llvm::Function* From) {
auto II = FuncProperties.find(From);
if (II != FuncProperties.end()) {
FuncProperties[To] = II->second;
}
}
/// get or create the function group that holds all indirectly-called functions
FunctionGroup* getOrCreateIndirectCallGroup(llvm::Module* pModule);
/// check if function is stack-called
bool useStackCall(llvm::Function* F);
/// sets function group attribute flags
void setGroupAttributes();
typedef llvm::SmallVectorImpl<FunctionGroup*>::iterator iterator;
iterator begin() { return iterator(Groups.begin()); }
iterator end() { return iterator(Groups.end()); }
/// \brief Returns the number of groups, aka. kernels.
size_t size() { return Groups.size(); }
/// \brife add Function F to FunctionGroup FG.
void addToFunctionGroup(llvm::Function* F, FunctionGroup* FG, llvm::Function* SubGrpH);
/// \brief Create a new FunctionGroup with head F.
FunctionGroup* createFunctionGroup(llvm::Function* F);
void print(llvm::raw_ostream& os);
#if defined(_DEBUG)
void dump();
#endif
};
llvm::ModulePass* createGenXCodeGenModulePass();
llvm::ImmutablePass* createGenXFunctionGroupAnalysisPass();
llvm::Pass* createSubroutineInlinerPass();
} // namespace IGC
|