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