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