1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #ifndef DEBUG_INFO_H
10 #define DEBUG_INFO_H
11 #include <string>
12 #include "VISADefines.h"
13 #include "FlowGraph.h"
14 #include "Common_BinaryEncoding.h"
15 #include "RegAlloc.h"
16 #include "GraphColor.h"
17 #include <unordered_map>
18 
19 namespace vISA
20 {
21 class G4_Declare;
22 }
23 class CISA_IR_Builder;
24 class VISAKernelImpl;
25 
26 struct VarnameMap;
27 namespace vISA
28 {
29 class DebugInfoState;
30 }
31 #if defined(_DEBUG) || defined(_INTERNAL)
32 #define DEBUG_RELEASE_INTERNAL_DLL_EXPORT_ONLY DLL_EXPORT
33 #else
34 #define DEBUG_RELEASE_INTERNAL_DLL_EXPORT_ONLY
35 #endif
36 
37 DEBUG_RELEASE_INTERNAL_DLL_EXPORT_ONLY int decodeAndDumpDebugInfo(char* filename);
38 void emitDebugInfo(CISA_IR_Builder* builder, std::string filename);
39 void emitDebugInfo(VISAKernelImpl* curKernel, std::string filename);
40 void emitDebugInfo(VISAKernelImpl* kernel, std::list<VISAKernelImpl*>& functions, std::string filename);
41 void emitDebugInfoToMem(VISAKernelImpl* curKernel, void*& info, unsigned& size);
42 void emitDebugInfoToMem(VISAKernelImpl* kernel, std::list<VISAKernelImpl*>& functions, void*& info, unsigned& size);
43 
44 void emitRegisterMapping(vISA::G4_Kernel& kernel, std::vector<VarnameMap*>& varsMap);
45 
46 struct IDX_VDbgCisaByte2Gen {
47     unsigned CisaByteOffset;
48     unsigned GenOffset;
49 };
50 struct IDX_VDbgCisaIndex2Gen {
51     unsigned CisaIndex;
52     unsigned GenOffset;
53 };
54 struct IDX_VDbgGen2CisaIndex {
55     unsigned GenOffset;
56     unsigned VisaIndex;
57 };
58 void generateCISAByteOffsetFromOffset(std::map<unsigned int, unsigned int>& mapCISAIndexCISAOffset,
59                                       std::vector<IDX_VDbgCisaIndex2Gen>& mapCISAIndexGenOffset,
60                                       std::vector<IDX_VDbgCisaByte2Gen>& mapCISAOffsetGenOffset);
61 void generateByteOffsetMapping(vISA::G4_Kernel& kernel, std::vector<std::pair<unsigned int, unsigned int>>& mapping, std::list<vISA::G4_BB*>& stackCallEntryBBs);
62 void updateRelocOffset(VISAKernelImpl& kernel);
63 void resetGenOffsets(vISA::G4_Kernel& kernel);
64 
65 void addCallFrameInfo(VISAKernelImpl* kernel);
66 
67 // For ranges colored during graph coloring
68 void updateDebugInfo(vISA::G4_Kernel& kernel, vISA::G4_INST* inst,
69     const vISA::LivenessAnalysis& liveAnalysis, vISA::LiveRange* lrs[], BitSet& live,
70     vISA::DebugInfoState* state, bool closeAllOpenIntervals);
71 // For ranges allocated by local RA
72 void updateDebugInfo(vISA::G4_Kernel& kernel,
73     std::vector<vISA::LocalLiveRange*>& liveIntervals);
74 // For ranges allocated by global linear scan
75 void updateDebugInfo(vISA::G4_Kernel& kernel,
76     std::vector<vISA::LSLiveRange*>& liveIntervals);
77 
78 
79 // For ranges updated by augmentation
80 void updateDebugInfo(vISA::G4_Kernel& kernel,
81     std::vector<std::tuple<vISA::G4_Declare*, vISA::G4_INST*, vISA::G4_INST*>> augmentationLiveIntervals);
82 // For ranges assigned using unique assignments in local RA
83 void updateDebugInfo(vISA::G4_Kernel& kernel, vISA::G4_Declare* dcl,
84     uint32_t start, uint32_t end);
85 void updateDebugInfo(vISA::G4_Kernel& kernel, vISA::G4_Declare* dcl, uint32_t offset);
86 
87 void updateCallStackLiveIntervals(vISA::G4_Kernel& kernel);
88 
89 #define DEBUG_MAGIC_NUMBER ((unsigned int)0xdeadd010)
90 
91 // Format of debug info
92 struct VarnameMap
93 {
94 #define VARMAP_VREG_FILE_ADDRESS 0
95 #define VARMAP_VREG_FILE_FLAG 1
96 #define VARMAP_VREG_FILE_GRF 2
97 
98     // 0 - address, 1 - flag, 2 - GRF
99     uint8_t virtualType;
100 
101 #define VARMAP_PREG_FILE_ADDRESS 0
102 #define VARMAP_PREG_FILE_FLAG 1
103 #define VARMAP_PREG_FILE_GRF 2
104 #define VARMAP_PREG_FILE_MEMORY 3
105 
106     // Physical register type allocated by RA: 0 - address, 1 - flag, 2 - GRF, 3 - memory
107     uint8_t physicalType;
108     union Mapping
109     {
110         struct Register
111         {
112             uint16_t regNum;
113             // For GRF, sub reg num is in byte granularity
114             uint16_t subRegNum;
115         }Register;
116         struct Memory
117         {
118             // For globals, spill offset is absolute whereas for frame auto vars,
119             // it is BE_FP relative.
120             uint8_t isAbs : 1;
121             int32_t memoryOffset : 31;
122         }Memory;
123     }Mapping;
124 
125     vISA::G4_Declare* dcl;
126 };
127 
128 // Instance of this class is created and stored in G4_Kernel.
129 // Any debug info related members will go here and necessary
130 // getters/setters should be added here. One level of indirection
131 // will be required from G4_Kernel instance to get to this
132 // instance, but this means no space/perf penalty is imposed
133 // on G4_Kernel.
134 namespace vISA
135 {
136 class KernelDebugInfo
137 {
138 private:
139     G4_Kernel* kernel;
140     VISAKernelImpl* visaKernel;
141     std::unordered_map<G4_Declare*, LiveIntervalInfo*> debugInfoLiveIntervalMap;
142 
143     // Instruction that saves caller BE_FP to callerbpfpdcl
144     G4_INST* saveCallerFP;
145     // Instruction that restores caller BE_FP prior to return
146     G4_INST* restoreCallerFP;
147     // Instruction that updates BE_FP for current frame
148     G4_INST* setupFP;
149     // Instruction that destroys BE_FP for current frame
150     G4_INST* restoreSP;
151 
152     // Current frame size in bytes
153     uint32_t frameSize;
154 
155     // Store declare used holding return value for stack call functions,
156     // NULL for kernel.
157     G4_Declare* fretVar;
158 
159     // Caller save/restore
160     // std::vector<std::pair<fcall inst BB, std::pair<first caller save, last caller restore>>>
161     // One entry per fcall inst in current compilation unit
162     typedef std::pair<std::vector<G4_INST*>, std::vector<G4_INST*> > SaveRestore;
163     std::unordered_map<G4_BB*, SaveRestore> callerSaveRestore;
164     SaveRestore calleeSaveRestore;
165 
166     INST_LIST oldInsts;
167 
168     // Store pair of cisa byte offset and gen byte offset in vector
169     std::vector<IDX_VDbgCisaByte2Gen> mapCISAOffsetGenOffset;
170     // Store pair of cisa index and gen byte offset in vector
171     std::vector<IDX_VDbgCisaIndex2Gen> mapCISAIndexGenOffset;
172     // Store varname map instance for each dcl
173     std::vector<VarnameMap*> varsMap;
174     // Store map between CISA bytecode index and CISA offset
175     std::map<unsigned int, unsigned int> mapCISAOffset;
176     // Store reloc_offset of gen binary. This is emitted out to debug info.
177     uint32_t reloc_offset;
178 
179     // Store set of missing VISA ids as this helps consolidate live-intervals
180     // to save compile time.
181     std::set<unsigned int> missingVISAIds;
182     bool missingVISAIdsComputed;
183 
184     std::vector<IDX_VDbgGen2CisaIndex> genISAOffsetToVISAIndex;
185 
186     // Store all dcls that are from stack call function
187     std::unordered_set<G4_Declare*> stackCallDcls;
188 
189 public:
190     LiveIntervalInfo* getLiveIntervalInfo(G4_Declare* dcl, bool createIfNULL = true);
191     void *operator new(size_t sz, Mem_Manager& m);
getKernel()192     G4_Kernel& getKernel() { return *kernel; }
getVISAKernel()193     VISAKernelImpl* getVISAKernel() const { return visaKernel; }
194     void setVISAKernel(VISAKernelImpl* k);
195 
196     KernelDebugInfo();
197     ~KernelDebugInfo();
198 
reset()199     void reset()
200     {
201         mapCISAOffsetGenOffset.clear();
202         mapCISAIndexGenOffset.clear();
203         varsMap.clear();
204         resetRelocOffset();
205         missingVISAIds.clear();
206         missingVISAIdsComputed = false;
207     }
208 
getBEFP()209     G4_Declare* getBEFP()
210     {
211         G4_Declare* ret = nullptr;
212 
213         if (!kernel->fg.getIsStackCallFunc())
214         {
215             ret = kernel->fg.builder->getBEFP();
216         }
217         else if (saveCallerFP)
218         {
219             ret = GetTopDclFromRegRegion(saveCallerFP->getSrc(0));
220         }
221 
222         return ret;
223     }
224 
getCallerBEFP()225     G4_Declare* getCallerBEFP()
226     {
227         G4_Declare* ret = nullptr;
228 
229         if (saveCallerFP)
230         {
231             ret = GetTopDclFromRegRegion(saveCallerFP->getDst());
232         }
233 
234         return ret;
235     }
236 
getCallerBEFPSaveInst()237     G4_INST* getCallerBEFPSaveInst() const { return saveCallerFP; }
setCallerBEFPSaveInst(G4_INST * i)238     void setCallerBEFPSaveInst(G4_INST* i) { saveCallerFP = i; }
239 
getCallerBEFPRestoreInst()240     G4_INST* getCallerBEFPRestoreInst() const { return restoreCallerFP; }
setCallerBEFPRestoreInst(G4_INST * i)241     void setCallerBEFPRestoreInst(G4_INST* i) { restoreCallerFP = i; }
242 
getBEFPSetupInst()243     G4_INST* getBEFPSetupInst() const { return setupFP; }
setBEFPSetupInst(G4_INST * i)244     void setBEFPSetupInst(G4_INST* i) { setupFP = i; }
245 
getCallerSPRestoreInst()246     G4_INST* getCallerSPRestoreInst() const { return restoreSP; }
setCallerSPRestoreInst(G4_INST * i)247     void setCallerSPRestoreInst(G4_INST* i) { restoreSP = i; }
248 
getFrameSize()249     uint32_t getFrameSize() const { return frameSize; }
setFrameSize(uint32_t sz)250     void setFrameSize(uint32_t sz) { frameSize = sz; }
251 
getFretVar()252     G4_Declare* getFretVar() const { return fretVar; }
setFretVar(G4_Declare * dcl)253     void setFretVar(G4_Declare* dcl) { fretVar = dcl; }
254 
255     void updateExpandedIntrinsic(G4_InstIntrinsic* spillOrFill, G4_INST* inst);
256     void addCallerSaveInst(G4_BB* fcallBB, G4_INST* inst);
257     void addCallerRestoreInst(G4_BB* fcallBB, G4_INST* inst);
258     void addCalleeSaveInst(G4_INST* inst);
259     void addCalleeRestoreInst(G4_INST* inst);
260     bool isFcallWithSaveRestore(G4_BB* bb);
261 
262     std::vector<G4_INST*>& getCallerSaveInsts(G4_BB* fcallBB);
263     std::vector<G4_INST*>& getCallerRestoreInsts(G4_BB* fcallBB);
264     std::vector<G4_INST*>& getCalleeSaveInsts();
265     std::vector<G4_INST*>& getCalleeRestoreInsts();
266 
setOldInstList(G4_BB * bb)267     void setOldInstList(G4_BB* bb)
268     {
269         oldInsts.assign(bb->begin(), bb->end());
270     }
clearOldInstList()271     void clearOldInstList() { oldInsts.clear(); }
272     INST_LIST getDeltaInstructions(G4_BB* bb);
273 
resetRelocOffset()274     void resetRelocOffset() { reloc_offset = 0; }
275     void updateMapping(std::list<G4_BB*>& stackCallEntryBBs);
276 
277     void generateByteOffsetMapping(std::list<G4_BB*>& stackCallEntryBBs);
278     void emitRegisterMapping();
279     void generateCISAByteOffsetFromOffset();
280     void updateRelocOffset();
281     void updateCallStackLiveIntervals();
282     void updateCallStackMain();
283     void generateGenISAToVISAIndex();
284 
285     void computeDebugInfo(std::list<G4_BB*>& stackCallEntryBBs);
286 
getRelocOffset()287     uint32_t getRelocOffset() const { return reloc_offset; }
288 
mapCISAOffsetInsert(unsigned int a,unsigned int b)289     void mapCISAOffsetInsert(unsigned int a, unsigned int b)
290     {
291         mapCISAOffset.insert(std::make_pair(a, b));
292     }
293 
getGenOffsetFromVISAIndex(unsigned int v)294     unsigned int getGenOffsetFromVISAIndex(unsigned int v) const
295     {
296         for (auto& item : mapCISAIndexGenOffset)
297         {
298             if (item.CisaIndex == v)
299                 return item.GenOffset;
300         }
301         return 0;
302     }
303 
getMapCISAOffsetGenOffset()304     std::vector<IDX_VDbgCisaByte2Gen>& getMapCISAOffsetGenOffset() { return mapCISAOffsetGenOffset; }
getMapCISAIndexGenOffset()305     std::vector<IDX_VDbgCisaIndex2Gen>& getMapCISAIndexGenOffset() { return mapCISAIndexGenOffset; }
getMapGenISAOffsetToCISAIndex()306     std::vector<IDX_VDbgGen2CisaIndex>& getMapGenISAOffsetToCISAIndex() { return genISAOffsetToVISAIndex; }
getVarsMap()307     std::vector<VarnameMap*>& getVarsMap() { return varsMap; }
308 
309     uint32_t getVarIndex(G4_Declare* dcl);
310 
311     void computeMissingVISAIds();
312     bool isMissingVISAId(unsigned int);
313 
314     void markStackCallFuncDcls(G4_Kernel& function);
315 };
316 
317 class SaveRestoreInfo
318 {
319     G4_INST* i;
320 
321 public:
322     // Map src GRF->GRF/Memory
323     union RegMap
324     {
325         uint32_t regNum;
326         struct
327         {
328             int32_t offset : 31;
329             uint32_t isAbs : 1;
330         };
331         int32_t memOff;
332     };
333     enum RegOrMem
334     {
335         Reg = 1,
336         MemAbs = 2,
337         MemOffBEFP = 3
338     };
339     std::map<uint32_t, std::pair<RegOrMem, RegMap>> saveRestoreMap;
340 
isEqual(SaveRestoreInfo & other)341     bool isEqual(SaveRestoreInfo& other)
342     {
343         auto otherMapIt = other.saveRestoreMap.begin();
344 
345         if (this->saveRestoreMap.size() != other.saveRestoreMap.size())
346         {
347             return false;
348         }
349 
350         for (auto& thisMap : saveRestoreMap)
351         {
352             if (thisMap.first != otherMapIt->first ||
353                 thisMap.second.first != otherMapIt->second.first ||
354                 thisMap.second.second.memOff != otherMapIt->second.second.memOff)
355             {
356                 return false;
357             }
358 
359             otherMapIt++;
360         }
361 
362         return true;
363     }
364 
365     void update(G4_INST* inst, int32_t memOffset = 0xffff, uint32_t regWithMemOffset = 0xffff, bool absOffset = false);
getInst()366     G4_INST* getInst() const { return i; }
367 };
368 
369 class SaveRestoreManager
370 {
371     VISAKernelImpl* visaKernel;
372     std::vector<SaveRestoreInfo> srInfo;
373     int32_t memOffset;
374     uint32_t regWithMemOffset;
375     bool absOffset;
376 
377 public:
378 
379     enum CallerOrCallee
380     {
381         Caller = 1,
382         Callee = 2
383     };
384 
385     void addInst(G4_INST* inst);
386 
SaveRestoreManager(VISAKernelImpl * k)387     SaveRestoreManager(VISAKernelImpl* k)
388     {
389         visaKernel = k;
390         memOffset = 0xffff;
391         regWithMemOffset = 0xffff;
392         absOffset = false;
393     }
394 
getSRInfo()395     std::vector<SaveRestoreInfo>& getSRInfo() { return srInfo; }
396 
397     void sieveInstructions(CallerOrCallee c);
398 
399     void emitAll();
400 };
401 
402 class DbgDecoder
403 {
404 private:
405     const char* const filename;
406     std::FILE* dbgFile = nullptr;
407 
408     void ddName();
409     template<class T> void ddLiveInterval();
410     void ddCalleeCallerSave(uint32_t relocOffset);
411 
412 public:
DbgDecoder(const char * f)413     DbgDecoder(const char* f) : filename(f) {}
414 
415     int ddDbg();
416 };
417 
418 class DebugInfoState
419 {
420     // Class used to store state during RA.
421 public:
setPrevBitset(const BitSet & b)422     void setPrevBitset(const BitSet& b)
423     {
424         prevBitset = b;
425     }
setPrevInst(G4_INST * i)426     void setPrevInst(G4_INST* i)
427     {
428         if (i->getCISAOff() != UNMAPPABLE_VISA_INDEX)
429         {
430             prevInst = i;
431         }
432     }
433 
getPrevBitset()434     BitSet* getPrevBitset()
435     {
436         if (prevBitset.getSize() == 0)
437             return nullptr;
438         return &prevBitset;
439     }
getPrevInst()440     G4_INST* getPrevInst() { return prevInst; }
441 
442 private:
443     BitSet prevBitset;
444     G4_INST* prevInst = nullptr;
445 };
446 }
447 /* Debug info format:
448 struct DebugFormatHeader
449 {
450     uint32_t magic;
451     uint16_t numCompiledObjects;
452     DebugInfoFormat debugInfo[numCompiledObjectsObjects];
453 }
454 
455 struct DebugInfoFormat
456 {
457     uint16_t kernelNameLen;
458     char kernelName[kernelNameLen];
459     uint32_t reloc_offset; // 0 for kernel, non-zero for stack call functions
460 
461     struct CISAOffsetMap
462     {
463         uint32_t numElements;
464         CISAMap data[numElements];
465     }
466 
467     struct CISAIndexMap
468     {
469         uint32_t numElements;
470         CISAMap data[numElements];
471     }
472 
473     struct VarInfoMap
474     {
475         uint32_t numElements;
476 
477         struct VarInfo[numElements]
478         {
479             VarName name;
480             VarLiveIntervalVISA lr;
481         }
482     }
483 
484     uint16_t numSubs
485     SubroutineInfo subInfo[numSubs];
486 
487     CallFrameInfo frameInfo;
488 }
489 
490 struct CISAMap
491 {
492     uint32_t cisaOffset/cisaIndex;
493     uint32_t genOffset;
494 }
495 
496 struct SubroutineInfo
497 {
498     VarName subName;
499     uint32_t startVISAOffset;
500     uint32_t endVISAOffset;
501     VarLiveIntervalVISA retVal;
502 }
503 
504 struct CallFrameInfo
505 {
506     uint16_t frameSizeInBytes;
507     uint8_t befpValid;
508     VarLiveIntervalGenISA befp; // Validity depends on flag befpValid
509     uint8_t callerbefpValid;
510     VarLiveIntervalGenISA callerbefp; // Validity depends on flag callerbefpValid
511     uint8_t retAddrValid;
512     VarLiveIntervalGenISA retAddr; // Validity depends on flag retAddrValid
513     uint16_t numCalleeSaveEntries;
514     PhyRegSaveInfoPerIP calleeSaveEntry[numCalleeSaveEntries];
515     // Need this because of following:
516     //
517     // V10 -> r2, r3, r4, r5, r6, r7
518     //
519     // send (16) null:w   r1 <-- Writes 4 GRFs (r1, r2, r3, r4)
520     // r4 = r0
521     // r4.2 =...
522     // send (16) null:w   r4 <-- Writes 4 GRFs (r5, r6, r7, r8)
523     //
524     uint16_t numCallerSaveEntries;
525     PhyRegSaveInfoPerIP callerSaveEntry[numCallerSaveEntries];
526 }
527 
528 struct VarName
529 {
530     uint16_t varNameLen;
531     char varName[varNameLen];
532 }
533 
534 struct VarAlloc
535 {
536     uint8_t virtualType; // Virtual register type from CISA file: 0 - address, 1 - flag, 2 - GRF
537     uint8_t physicalType; // Physical register type allocated by RA: 0 - address, 1 - flag, 2 - GRF, 3 - memory
538     Mapping mapping;
539 }
540 
541 union Mapping
542 {
543     struct Register
544     {
545         uint16_t regNum;
546         uint16_t subRegNum; // for GRF, in byte offset
547     }
548     struct Memory
549     {
550         uint32_t isBaseOffBEFP : 1; // MSB of 32-bit field denotes whether base if off BE_FP (0) or absolute (1)
551         int32_t memoryOffset : 31; // memory offset
552     }
553 }
554 
555 struct VarLiveIntervalVISA
556 {
557     uint16_t numIntervals;
558     LiveIntervalVISA interval[numIntervals];
559 }
560 
561 struct VarLiveIntervalGenISA
562 {
563     uint16_t numIntervals;
564     LiveIntervalGenISA interval[numIntervals];
565 }
566 
567 struct LiveIntervalVISA
568 {
569     uint16_t start;
570     uint16_t end;
571     VarAlloc alloc;
572 }
573 
574 struct LiveIntervalGenISA
575 {
576     uint32_t start;
577     uint32_t end;
578     VarAlloc alloc;
579 }
580 
581 struct PhyRegSaveInfoPerIP
582 {
583     uint32_t genIPOffset;
584     uint16_t numEntries;
585     RegInfoMapping data[numEntries];
586 }
587 
588 struct RegInfoMapping
589 {
590     RegInfo src;
591     uint8_t dstInReg;
592     Mapping dst;
593 }
594 
595 struct RegInfo
596 {
597     // GRF file r0.0 -> srcRegOff = 0, r1.0 -> srcRegOff = 32.
598     // Addr and flag registers can be represented beyond GRF file size of 4k. But not currently required since they are not callee save.
599     uint16_t srcRegOff;
600     uint16_t numBytes;
601 }
602 
603 */
604 #endif
605