1 /*========================== begin_copyright_notice ============================ 2 3 Copyright (C) 2021 Intel Corporation 4 5 SPDX-License-Identifier: MIT 6 7 ============================= end_copyright_notice ===========================*/ 8 9 #ifndef G4_BB_H 10 #define G4_BB_H 11 12 #include "G4_IR.hpp" 13 14 #include <list> 15 #include <unordered_map> 16 17 namespace vISA 18 { 19 class G4_BB; 20 21 typedef std::list<G4_BB*> BB_LIST; 22 typedef BB_LIST::iterator BB_LIST_ITER; 23 typedef BB_LIST::const_iterator BB_LIST_CITER; 24 typedef BB_LIST::reverse_iterator BB_LIST_RITER; 25 26 // 27 // Block types 28 // 29 enum G4_BB_TYPE 30 { 31 G4_BB_NONE_TYPE = 0x00, 32 G4_BB_CALL_TYPE = 0x01, 33 G4_BB_RETURN_TYPE = 0x02, 34 G4_BB_INIT_TYPE = 0x04, 35 G4_BB_EXIT_TYPE = 0x08, 36 G4_BB_NM_WA_TYPE = 0x10, // For NoMaskWA 37 G4_BB_FCALL_TYPE = 0x20 // For NoMaskWA 38 }; 39 40 class FuncInfo; 41 class FlowGraph; 42 43 class G4_BB 44 { 45 // 46 // basic block id 47 // 48 unsigned id; 49 // 50 // preorder block id 51 // 52 unsigned preId; 53 // 54 // reverse postorder block id 55 // 56 unsigned rpostId; 57 // 58 // traversal is for traversing control flow graph (to indicate the 59 // block is visited) 60 // 61 unsigned traversal; 62 63 // 64 // if the current BB ends with a CALL subroutine, then the calleeInfo points 65 // to the FuncInfo node corresponding to the called function. 66 // else if the block is an INIT/EXIT block of a function, then the funcInfo 67 // points to the FuncInfo node of its function. 68 // 69 union { 70 FuncInfo * calleeInfo; 71 FuncInfo * funcInfo; 72 }; 73 74 // 75 // the block classification 76 // 77 unsigned BBType; 78 79 // indicates if the block is part of a natural loop or not 80 bool inNaturalLoop; 81 bool hasSendInBB; 82 83 // indicate the nest level of the loop 84 unsigned char loopNestLevel; 85 86 // indicates the scoping info in call graph 87 unsigned scopeID; 88 89 // If a BB is divergent, this field is set to true. By divergent, it means 90 // that among all active lanes on entry to shader/kernel, not all lanes are 91 // active in this BB. 92 bool divergent; 93 94 // the physical pred/succ for this block (i.e., the pred/succ for this 95 // block in the BB list). Note that some transformations may rearrange 96 // BB layout, so for safety it's best to recompute this 97 G4_BB * physicalPred; 98 G4_BB * physicalSucc; 99 100 FlowGraph * parent; 101 102 INST_LIST instList; 103 insert(INST_LIST::iterator iter,G4_INST * inst)104 INST_LIST_ITER insert(INST_LIST::iterator iter, G4_INST* inst) 105 { 106 return instList.insert(iter, inst); 107 } 108 public: 109 // forwarding functions to this BB's instList begin()110 INST_LIST_ITER begin() { return instList.begin(); } end()111 INST_LIST_ITER end() { return instList.end(); } rbegin()112 INST_LIST::reverse_iterator rbegin() { return instList.rbegin(); } rend()113 INST_LIST::reverse_iterator rend() { return instList.rend(); } getInstList()114 INST_LIST& getInstList() { return instList; } 115 116 template <class InputIt> insert(INST_LIST::iterator iter,InputIt first,InputIt last)117 INST_LIST_ITER insert(INST_LIST::iterator iter, InputIt first, InputIt last) 118 { 119 return instList.insert(iter, first, last); 120 } 121 insertBefore(INST_LIST::iterator iter,G4_INST * inst)122 INST_LIST_ITER insertBefore(INST_LIST::iterator iter, G4_INST* inst) 123 { 124 if (iter != instList.end() && !inst->isCISAOffValid()) 125 inst->inheritDIFrom(*iter); 126 return instList.insert(iter, inst); 127 } 128 insertAfter(INST_LIST::iterator iter,G4_INST * inst)129 INST_LIST_ITER insertAfter(INST_LIST::iterator iter, G4_INST* inst) 130 { 131 auto next = iter; 132 ++next; 133 if (!inst->isCISAOffValid()) 134 { 135 // Inheriting from iter seems more reasonable 136 // since invoking invokeAfter on iter means 137 // we're processing iter and not ++iter 138 inst->inheritDIFrom(*iter); 139 } 140 return instList.insert(next, inst); 141 } 142 erase(INST_LIST::iterator iter)143 INST_LIST_ITER erase(INST_LIST::iterator iter) { 144 return instList.erase(iter); 145 } erase(INST_LIST::iterator first,INST_LIST::iterator last)146 INST_LIST_ITER erase(INST_LIST::iterator first, INST_LIST::iterator last) { 147 return instList.erase(first, last); 148 } remove(G4_INST * inst)149 void remove(G4_INST* inst) { instList.remove(inst); } clear()150 void clear() { instList.clear(); } pop_back()151 void pop_back() { instList.pop_back(); } pop_front()152 void pop_front() { instList.pop_front(); } push_back(G4_INST * inst)153 void push_back(G4_INST* inst) {insertBefore(instList.end(), inst);} push_front(G4_INST * inst)154 void push_front(G4_INST* inst) {insertBefore(instList.begin(), inst);} 155 size() const156 size_t size() const { return instList.size(); } empty() const157 bool empty() const { return instList.empty(); } front()158 G4_INST* front() { return instList.front(); } front() const159 const G4_INST* front() const { return instList.front(); } back()160 G4_INST* back() { return instList.back(); } back() const161 const G4_INST* back() const { return instList.back(); } 162 163 // splice functions below expect caller to have correctly set CISA offset 164 // in instructions to be spliced. CISA offsets must be maintained to 165 // preserve debug info links. splice(INST_LIST::iterator pos,INST_LIST & other)166 void splice(INST_LIST::iterator pos, INST_LIST& other) 167 { 168 instList.splice(pos, other); 169 } splice(INST_LIST::iterator pos,G4_BB * otherBB)170 void splice(INST_LIST::iterator pos, G4_BB* otherBB) 171 { 172 instList.splice(pos, otherBB->getInstList()); 173 } splice(INST_LIST::iterator pos,INST_LIST & other,INST_LIST::iterator it)174 void splice(INST_LIST::iterator pos, INST_LIST& other, INST_LIST::iterator it) 175 { 176 instList.splice(pos, other, it); 177 } splice(INST_LIST::iterator pos,G4_BB * otherBB,INST_LIST::iterator it)178 void splice(INST_LIST::iterator pos, G4_BB* otherBB, INST_LIST::iterator it) 179 { 180 instList.splice(pos, otherBB->getInstList(), it); 181 } splice(INST_LIST::iterator pos,INST_LIST & other,INST_LIST::iterator first,INST_LIST::iterator last)182 void splice(INST_LIST::iterator pos, INST_LIST& other, 183 INST_LIST::iterator first, INST_LIST::iterator last) 184 { 185 instList.splice(pos, other, first, last); 186 } splice(INST_LIST::iterator pos,G4_BB * otherBB,INST_LIST::iterator first,INST_LIST::iterator last)187 void splice(INST_LIST::iterator pos, G4_BB* otherBB, 188 INST_LIST::iterator first, INST_LIST::iterator last) 189 { 190 instList.splice(pos, otherBB->getInstList(), first, last); 191 } 192 193 // 194 // Important invariant: fall-through BB must be at the front of Succs. 195 // If we don't maintain this property, extra checking (e.g., label 196 // comparison) is needed to retrieve fallThroughBB 197 // 198 BB_LIST Preds; 199 BB_LIST Succs; 200 G4_BB(INST_LIST_NODE_ALLOCATOR & alloc,unsigned i,FlowGraph * fg)201 G4_BB(INST_LIST_NODE_ALLOCATOR& alloc, unsigned i, FlowGraph* fg) : 202 id(i), preId(0), rpostId(0), 203 traversal(0), calleeInfo(NULL), BBType(G4_BB_NONE_TYPE), 204 inNaturalLoop(false), hasSendInBB(false), loopNestLevel(0), scopeID(0), 205 divergent(false), physicalPred(NULL), physicalSucc(NULL), 206 parent(fg), instList(alloc) 207 { 208 } 209 ~G4_BB()210 ~G4_BB() {instList.clear();} 211 operator new(size_t sz,Mem_Manager & m)212 void *operator new(size_t sz, Mem_Manager& m) {return m.alloc(sz);} 213 getParent() const214 FlowGraph& getParent() const { return *parent; } 215 G4_Kernel& getKernel() const; 216 217 bool isLastInstEOT() const; // to check if the last instruction in list is EOT 218 G4_opcode getLastOpcode() const; 219 getId() const220 unsigned getId() const {return id;} 221 void setId(unsigned i); 222 getPreId() const223 unsigned getPreId() const {return preId;} setPreId(unsigned i)224 void setPreId(unsigned i) {preId = i;} 225 getRPostId() const226 unsigned getRPostId() const {return rpostId;} setRPostId(unsigned i)227 void setRPostId(unsigned i) {rpostId = i;} 228 markTraversed(unsigned num)229 void markTraversed(unsigned num) {traversal = num;} isAlreadyTraversed(unsigned num) const230 bool isAlreadyTraversed(unsigned num) const {return traversal >= num;} 231 232 void removePredEdge(G4_BB* pred); 233 void removeSuccEdge(G4_BB* succ); 234 writeBBId(std::ostream & os) const235 void writeBBId(std::ostream& os) const {os << "BB" << id;} 236 G4_BB* fallThroughBB(); 237 G4_BB* BBBeforeCall() const; 238 G4_BB* BBAfterCall() const; 239 getCalleeInfo() const240 FuncInfo* getCalleeInfo() const {return calleeInfo;} setCalleeInfo(FuncInfo * callee)241 void setCalleeInfo(FuncInfo* callee) {calleeInfo = callee;} getFuncInfo() const242 FuncInfo* getFuncInfo() const {return funcInfo;} setFuncInfo(FuncInfo * func)243 void setFuncInfo(FuncInfo* func) {funcInfo = func;} 244 getBBType() const245 int getBBType() const {return BBType;} setBBType(int type)246 void setBBType(int type) {BBType |= type;} unsetBBType(G4_BB_TYPE type)247 void unsetBBType(G4_BB_TYPE type) {BBType &= ~unsigned(type);} 248 setInNaturalLoop(bool val)249 void setInNaturalLoop(bool val) {inNaturalLoop = val;} isInNaturalLoop() const250 bool isInNaturalLoop() const {return inNaturalLoop;} 251 252 bool isSuccBB(G4_BB* succ) const; // return true if succ is in bb's Succss setSendInBB(bool val)253 void setSendInBB(bool val) { hasSendInBB = val; } isSendInBB() const254 bool isSendInBB() const { return hasSendInBB; } 255 setNestLevel()256 void setNestLevel() { loopNestLevel++;} getNestLevel() const257 unsigned getNestLevel() const { return loopNestLevel; } resetNestLevel()258 void resetNestLevel() { loopNestLevel = 0; } 259 setDivergent(bool val)260 void setDivergent(bool val) { divergent = val; } isDivergent() const261 bool isDivergent() const { return divergent; } 262 bool isAllLaneActive() const; 263 getScopeID() const264 unsigned getScopeID() const { return scopeID; } setScopeID(unsigned id)265 void setScopeID(unsigned id) { scopeID = id; } 266 getPhysicalPred() const267 G4_BB * getPhysicalPred() const { return physicalPred; } setPhysicalPred(G4_BB * pred)268 void setPhysicalPred(G4_BB* pred) { physicalPred = pred; } 269 getPhysicalSucc() const270 G4_BB * getPhysicalSucc() const { return physicalSucc; } setPhysicalSucc(G4_BB * succ)271 void setPhysicalSucc(G4_BB* succ) { physicalSucc = succ; } 272 273 void emit(std::ostream& output); 274 void emitInstruction(std::ostream& output, INST_LIST_ITER &it); 275 void emitBasicInstruction(std::ostream& output, INST_LIST_ITER &it); 276 void emitBasicInstructionComment(std::ostream& output, INST_LIST_ITER &it, int *suppressRegs, int *lastRegs); 277 void emitInstructionSourceLineMapping(std::ostream& output, INST_LIST_ITER &it); 278 void emitBankConflict(std::ostream& output, const G4_INST *inst); 279 280 int getConflictTimesForTGL(std::ostream& output, int* firstRegCandidate, int& sameBankConflicts, bool zeroOne, bool isTGLLP, bool reducedBundles); 281 282 uint32_t emitBankConflictXe( 283 std::ostream& os, const G4_INST *inst, 284 int* suppressRegs, 285 int& sameConflictTimes, int& twoSrcConflicts, int& simd16RS, 286 bool zeroOne, bool isTGLLP, bool hasReducedBundles); 287 uint32_t emitBankConflictXeLP( 288 std::ostream& os, const G4_INST *inst, 289 int * suppressRegs, int * lastRegs, 290 int & sameConflictTimes, int & twoSrcConflicts, int & simd16RS); 291 uint32_t countReadModifyWrite(std::ostream& os, const G4_INST *inst); 292 293 // SWSB_G4IR.cpp 294 void emitRegInfo(std::ostream& os, G4_INST * inst, int offset); 295 isEndWithCall() const296 bool isEndWithCall() const { return getLastOpcode() == G4_call; } isEndWithFCall() const297 bool isEndWithFCall() const { return getLastOpcode() == G4_pseudo_fcall; } isEndWithFCCall() const298 bool isEndWithFCCall() const { return getLastOpcode() == G4_pseudo_fc_call; } isEndWithFRet() const299 bool isEndWithFRet() const { return getLastOpcode() == G4_pseudo_fret; } isEndWithGoto() const300 bool isEndWithGoto() const { return getLastOpcode() == G4_goto; } 301 302 G4_Label* getLabel(); 303 304 // Return the first non-label instruction if any. 305 G4_INST* getFirstInst(); 306 307 // Return the first insert position if any; otherwise return end(). 308 INST_LIST_ITER getFirstInsertPos(); 309 310 void addEOTSend(G4_INST* lastInst = NULL); 311 312 /// Dump instructions into the standard error. 313 const char* getBBTypeStr() const; 314 315 void print(std::ostream& os = std::cerr) const; 316 void dump() const; // used in debugger 317 void dumpDefUse(std::ostream& os = std::cerr) const; 318 319 void emitBbInfo(std::ostream& os) const; 320 321 // reset this BB's instruction's local id so they are [0,..#BBInst-1] 322 void resetLocalIds(); 323 324 void removeIntrinsics(Intrinsic intrinId); 325 326 void addSamplerFlushBeforeEOT(); 327 328 bool dominates(G4_BB* other); 329 }; // class G4_BB 330 } // vISA:: 331 332 #endif // G4_BB_H 333