mirror of
https://github.com/intel/intel-graphics-compiler.git
synced 2025-11-04 08:21:06 +08:00
FuncInfo* Each kernel, stack call function, subroutine contains unique FuncInfo instance. These are stored in FlowGraph. A FuncInfo instance contains list of G4_BB that are part of that kernel, stack call, function. Given a G4_BB, there was no direct way to get corresponding FuncInfo. This refactor adds a member to G4_BB so that each G4_BB points to own FuncInfo. G4_BB's funcInfo member is initialized at the end of CFG construction. After this phase, any new G4_BB inserted in CFG will be linked to adjoining G4_BB's FuncInfo*.
323 lines
11 KiB
C++
323 lines
11 KiB
C++
/*========================== begin_copyright_notice ============================
|
|
|
|
Copyright (C) 2021 Intel Corporation
|
|
|
|
SPDX-License-Identifier: MIT
|
|
|
|
============================= end_copyright_notice ===========================*/
|
|
|
|
#ifndef G4_BB_H
|
|
#define G4_BB_H
|
|
|
|
#include "G4_IR.hpp"
|
|
|
|
#include <list>
|
|
#include <unordered_map>
|
|
|
|
namespace vISA {
|
|
class G4_BB;
|
|
|
|
typedef std::list<G4_BB *> BB_LIST;
|
|
typedef BB_LIST::iterator BB_LIST_ITER;
|
|
typedef BB_LIST::const_iterator BB_LIST_CITER;
|
|
typedef BB_LIST::reverse_iterator BB_LIST_RITER;
|
|
|
|
//
|
|
// Block types
|
|
//
|
|
enum G4_BB_TYPE {
|
|
G4_BB_NONE_TYPE = 0x00,
|
|
G4_BB_CALL_TYPE = 0x01,
|
|
G4_BB_RETURN_TYPE = 0x02,
|
|
G4_BB_INIT_TYPE = 0x04,
|
|
G4_BB_EXIT_TYPE = 0x08,
|
|
G4_BB_NM_WA_TYPE = 0x10, // For NoMaskWA
|
|
G4_BB_FCALL_TYPE = 0x20, // For NoMaskWA
|
|
|
|
// Keep BB without deleting. Its instructions stay and are not moved out.
|
|
// Moving instructions into BB are okay.
|
|
G4_BB_KEEP_TYPE = 0x40
|
|
};
|
|
|
|
class FuncInfo;
|
|
class FlowGraph;
|
|
|
|
class G4_BB {
|
|
//
|
|
// basic block id
|
|
//
|
|
unsigned id = 0;
|
|
//
|
|
// traversal is for traversing control flow graph (to indicate the
|
|
// block is visited)
|
|
//
|
|
unsigned traversal = 0;
|
|
|
|
// If the current BB ends with a CALL subroutine, then calleeInfo points
|
|
// to the FuncInfo instance corresponding to the called function. Otherwise,
|
|
// this member contains no useful information.
|
|
FuncInfo *calleeInfo = nullptr;
|
|
|
|
// Points to FuncInfo instance this G4_BB belongs to. After CFG construction,
|
|
// all G4_BB instances must have valid pointer in funcInfo.
|
|
FuncInfo *funcInfo = nullptr;
|
|
|
|
//
|
|
// the block classification
|
|
//
|
|
unsigned BBType = G4_BB_NONE_TYPE;
|
|
|
|
// indicate the nest level of the loop
|
|
unsigned char loopNestLevel = 0;
|
|
|
|
// indicates the scoping info in call graph
|
|
unsigned scopeID = 0;
|
|
|
|
// If a BB is divergent, this field is set to true. By divergent, it means
|
|
// that among all active lanes on entry to shader/kernel, not all lanes are
|
|
// active in this BB.
|
|
bool divergent = false;
|
|
|
|
bool specialEmptyBB = false;
|
|
|
|
// the physical pred/succ for this block (i.e., the pred/succ for this
|
|
// block in the BB list). Note that some transformations may rearrange
|
|
// BB layout, so for safety it's best to recompute this
|
|
G4_BB *physicalPred = nullptr;
|
|
G4_BB *physicalSucc = nullptr;
|
|
|
|
FlowGraph *parent = nullptr;
|
|
|
|
INST_LIST instList;
|
|
|
|
INST_LIST_ITER insert(INST_LIST::iterator iter, G4_INST *inst) {
|
|
return instList.insert(iter, inst);
|
|
}
|
|
|
|
public:
|
|
// forwarding functions to this BB's instList
|
|
INST_LIST_ITER begin() { return instList.begin(); }
|
|
INST_LIST_ITER end() { return instList.end(); }
|
|
INST_LIST::reverse_iterator rbegin() { return instList.rbegin(); }
|
|
INST_LIST::reverse_iterator rend() { return instList.rend(); }
|
|
INST_LIST &getInstList() { return instList; }
|
|
|
|
template <class InputIt>
|
|
INST_LIST_ITER insert(INST_LIST::iterator iter, InputIt first, InputIt last) {
|
|
return instList.insert(iter, first, last);
|
|
}
|
|
|
|
INST_LIST_ITER insertBefore(INST_LIST::iterator iter, G4_INST *inst,
|
|
bool inheritDI = true) {
|
|
if (inheritDI && iter != instList.end() && !inst->isVISAIdValid())
|
|
inst->inheritDIFrom(*iter);
|
|
return instList.insert(iter, inst);
|
|
}
|
|
|
|
INST_LIST_ITER insertAfter(INST_LIST::iterator iter, G4_INST *inst,
|
|
bool inheritDI = true) {
|
|
auto next = iter;
|
|
++next;
|
|
if (inheritDI && !inst->isVISAIdValid()) {
|
|
// Inheriting from iter seems more reasonable
|
|
// since invoking invokeAfter on iter means
|
|
// we're processing iter and not ++iter
|
|
inst->inheritDIFrom(*iter);
|
|
}
|
|
return instList.insert(next, inst);
|
|
}
|
|
|
|
INST_LIST_ITER erase(INST_LIST::iterator iter) {
|
|
return instList.erase(iter);
|
|
}
|
|
INST_LIST_ITER erase(INST_LIST::iterator first, INST_LIST::iterator last) {
|
|
return instList.erase(first, last);
|
|
}
|
|
void remove(G4_INST *inst) { instList.remove(inst); }
|
|
void clear() { instList.clear(); }
|
|
void pop_back() { instList.pop_back(); }
|
|
void pop_front() { instList.pop_front(); }
|
|
void push_back(G4_INST *inst, bool inheritDI = true) {
|
|
insertBefore(instList.end(), inst, inheritDI);
|
|
}
|
|
void push_front(G4_INST *inst, bool inheritDI = true) {
|
|
insertBefore(instList.begin(), inst, inheritDI);
|
|
}
|
|
|
|
size_t size() const { return instList.size(); }
|
|
bool empty() const { return instList.empty(); }
|
|
G4_INST *front() { return instList.front(); }
|
|
const G4_INST *front() const { return instList.front(); }
|
|
G4_INST *back() { return instList.back(); }
|
|
const G4_INST *back() const { return instList.back(); }
|
|
|
|
// splice functions below expect caller to have correctly set CISA offset
|
|
// in instructions to be spliced. CISA offsets must be maintained to
|
|
// preserve debug info links.
|
|
void splice(INST_LIST::iterator pos, INST_LIST &other) {
|
|
instList.splice(pos, other);
|
|
}
|
|
void splice(INST_LIST::iterator pos, G4_BB *otherBB) {
|
|
instList.splice(pos, otherBB->getInstList());
|
|
}
|
|
void splice(INST_LIST::iterator pos, INST_LIST &other,
|
|
INST_LIST::iterator it) {
|
|
instList.splice(pos, other, it);
|
|
}
|
|
void splice(INST_LIST::iterator pos, G4_BB *otherBB, INST_LIST::iterator it) {
|
|
instList.splice(pos, otherBB->getInstList(), it);
|
|
}
|
|
void splice(INST_LIST::iterator pos, INST_LIST &other,
|
|
INST_LIST::iterator first, INST_LIST::iterator last) {
|
|
instList.splice(pos, other, first, last);
|
|
}
|
|
void splice(INST_LIST::iterator pos, G4_BB *otherBB,
|
|
INST_LIST::iterator first, INST_LIST::iterator last) {
|
|
instList.splice(pos, otherBB->getInstList(), first, last);
|
|
}
|
|
|
|
//
|
|
// Important invariant: fall-through BB must be at the front of Succs.
|
|
// If we don't maintain this property, extra checking (e.g., label
|
|
// comparison) is needed to retrieve fallThroughBB
|
|
//
|
|
BB_LIST Preds;
|
|
BB_LIST Succs;
|
|
|
|
G4_BB(INST_LIST_NODE_ALLOCATOR &alloc, unsigned i, FlowGraph *fg)
|
|
: id(i), parent(fg), instList(alloc) {}
|
|
|
|
~G4_BB() { instList.clear(); }
|
|
G4_BB(const G4_BB&) = delete;
|
|
G4_BB& operator=(const G4_BB&) = delete;
|
|
|
|
void *operator new(size_t sz, Mem_Manager &m) { return m.alloc(sz); }
|
|
|
|
FlowGraph &getParent() const { return *parent; }
|
|
G4_Kernel &getKernel() const;
|
|
|
|
bool isLastInstEOT() const; // to check if the last instruction in list is EOT
|
|
G4_opcode getLastOpcode() const;
|
|
|
|
// If the last inst is CFInst, return it; otherwise, return nullptr
|
|
G4_InstCF *getLastCFInst() const {
|
|
if (empty())
|
|
return nullptr;
|
|
const G4_INST* I = back();
|
|
return I->isFlowControl() ? I->asCFInst() : nullptr;
|
|
}
|
|
|
|
unsigned getId() const { return id; }
|
|
void setId(unsigned i);
|
|
|
|
void markTraversed(unsigned num) { traversal = num; }
|
|
bool isAlreadyTraversed(unsigned num) const { return traversal >= num; }
|
|
|
|
void removePredEdge(G4_BB *pred);
|
|
void removeSuccEdge(G4_BB *succ);
|
|
|
|
void writeBBId(std::ostream &os) const { os << "BB" << id; }
|
|
G4_BB *fallThroughBB();
|
|
G4_BB *BBBeforeCall() const;
|
|
G4_BB *BBAfterCall() const;
|
|
|
|
FuncInfo *getCalleeInfo() const { return calleeInfo; }
|
|
void setCalleeInfo(FuncInfo *callee) { calleeInfo = callee; }
|
|
FuncInfo *getFuncInfo() const { return funcInfo; }
|
|
void setFuncInfo(FuncInfo *func) { funcInfo = func; }
|
|
|
|
int getBBType() const { return BBType; }
|
|
void setBBType(int type) { BBType |= type; }
|
|
void unsetBBType(G4_BB_TYPE type) { BBType &= ~unsigned(type); }
|
|
|
|
bool isSuccBB(G4_BB *succ) const; // return true if succ is in bb's Succss
|
|
|
|
void setNestLevel() { loopNestLevel++; }
|
|
unsigned getNestLevel() const { return loopNestLevel; }
|
|
void resetNestLevel() { loopNestLevel = 0; }
|
|
|
|
void setDivergent(bool val) { divergent = val; }
|
|
bool isDivergent() const { return divergent; }
|
|
bool isAllLaneActive() const;
|
|
|
|
unsigned getScopeID() const { return scopeID; }
|
|
void setScopeID(unsigned id) { scopeID = id; }
|
|
|
|
G4_BB *getPhysicalPred() const { return physicalPred; }
|
|
void setPhysicalPred(G4_BB *pred) { physicalPred = pred; }
|
|
|
|
G4_BB *getPhysicalSucc() const { return physicalSucc; }
|
|
void setPhysicalSucc(G4_BB *succ) { physicalSucc = succ; }
|
|
|
|
void emit(std::ostream &output);
|
|
void emitInstruction(std::ostream &output, INST_LIST_ITER &it);
|
|
void emitBasicInstruction(std::ostream &output, INST_LIST_ITER &it);
|
|
void emitBasicInstructionComment(std::ostream &output, INST_LIST_ITER &it,
|
|
int *suppressRegs, int *lastRegs, int32_t pc);
|
|
void emitInstructionSourceLineMapping(std::ostream &output,
|
|
INST_LIST_ITER &it);
|
|
void emitBankConflict(std::ostream &output, const G4_INST *inst);
|
|
|
|
int getConflictTimesForTGL(std::ostream &output, int *firstRegCandidate,
|
|
int &sameBankConflicts, bool zeroOne, bool isTGLLP,
|
|
bool reducedBundles);
|
|
|
|
uint32_t emitBankConflictXe(std::ostream &os, const G4_INST *inst,
|
|
int *suppressRegs, int &sameConflictTimes,
|
|
int &twoSrcConflicts, int &simd16RS, bool zeroOne,
|
|
bool isTGLLP, bool hasReducedBundles);
|
|
uint32_t emitBankConflictXeLP(std::ostream &os, const G4_INST *inst,
|
|
int *suppressRegs, int *lastRegs,
|
|
int &sameConflictTimes, int &twoSrcConflicts,
|
|
int &simd16RS);
|
|
uint32_t countReadModifyWrite(std::ostream &os, const G4_INST *inst);
|
|
|
|
// SWSB_G4IR.cpp
|
|
void emitRegInfo(std::ostream &os, G4_INST *inst, int offset);
|
|
|
|
bool isEndWithCall() const { return getLastOpcode() == G4_call; }
|
|
bool isEndWithFCall() const { return getLastOpcode() == G4_pseudo_fcall; }
|
|
bool isEndWithFCCall() const { return getLastOpcode() == G4_pseudo_fc_call; }
|
|
bool isEndWithFRet() const { return getLastOpcode() == G4_pseudo_fret; }
|
|
bool isEndWithGoto() const { return getLastOpcode() == G4_goto; }
|
|
|
|
G4_Label *getLabel();
|
|
|
|
// Return the first non-label instruction if any.
|
|
G4_INST *getFirstInst();
|
|
|
|
// Return the first insert position if any; otherwise return end().
|
|
INST_LIST_ITER getFirstInsertPos();
|
|
|
|
void addEOTSend(G4_INST *lastInst = NULL);
|
|
|
|
std::string getBBTypeStr() const;
|
|
|
|
void print(std::ostream &os = std::cerr) const;
|
|
/// Dump instructions into the standard error.
|
|
void dump() const; // used in debugger
|
|
void dumpDefUse(std::ostream &os = std::cerr) const;
|
|
|
|
void emitBbInfo(std::ostream &os) const;
|
|
|
|
// reset this BB's instruction's local id so they are [0,..#BBInst-1]
|
|
void resetLocalIds();
|
|
|
|
void removeIntrinsics(Intrinsic intrinId);
|
|
void removeIntrinsics(std::vector<Intrinsic>& intrinIdVec);
|
|
|
|
void addSamplerFlushBeforeEOT();
|
|
|
|
bool dominates(G4_BB *other);
|
|
|
|
/// Mark this BB as a special empty BB with single label
|
|
/// instruction. It will not be deleted by optimizations such as
|
|
/// removeRedundnantLabels and removeEmptyBlocks.
|
|
void markEmpty(IR_Builder *IRB, const std::string str = "");
|
|
bool isSpecialEmptyBB() const { return specialEmptyBB; }
|
|
|
|
}; // class G4_BB
|
|
} // namespace vISA
|
|
|
|
#endif // G4_BB_H
|