Files
intel-graphics-compiler/visa/G4_BB.hpp
Pratik J Ashar 4a15a02994 Refactor code so that each G4_BB in FlowGraph points to
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*.
2024-07-15 06:25:08 +02:00

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