Skip to content

Commit c939687

Browse files
pratikasharigcbot
authored andcommitted
Debug info implementation to support subroutines
Changes to .debug_frames section to support subroutine debug info. Changes include: 1. Fixing subroutine name emitted by VISA debug info so it matches subroutine name in IGC. 2. Passing flag to indicate if a function is a subroutine. 3. Emitting CIE and FDE for subroutines.
1 parent 7803857 commit c939687

File tree

7 files changed

+161
-62
lines changed

7 files changed

+161
-62
lines changed

IGC/Compiler/CISACodeGen/EmitVISAPass.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,8 +1060,9 @@ bool EmitPass::runOnFunction(llvm::Function& F)
10601060
m_currShader->GetDebugInfoData().m_pDebugEmitter = m_pDebugEmitter;
10611061

10621062
const bool IsPrimary = isFuncGroupHead;
1063-
m_pDebugEmitter->resetModule(
1064-
IGC::ScalarVisaModule::BuildNew(m_currShader, &F, IsPrimary));
1063+
bool GroupHasStackCall = m_FGA && m_FGA->getGroup(&F)->hasStackCall();
1064+
m_pDebugEmitter->resetModule(IGC::ScalarVisaModule::BuildNew(
1065+
m_currShader, &F, IsPrimary, GroupHasStackCall));
10651066
}
10661067

10671068
// We only invoke EndEncodingMark() to update last VISA id.

IGC/Compiler/DebugInfo/ScalarVISAModule.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,18 @@ namespace IGC {
8888
return (fullDebugInfo | lineNumbersOnly);
8989
}
9090

91-
ScalarVisaModule::ScalarVisaModule(CShader* TheShader,
92-
llvm::Function *TheFunction,
93-
bool IsPrimary)
94-
: m_pShader(TheShader), VISAModule(TheFunction, IsPrimary) {
95-
UpdateVisaId();
91+
ScalarVisaModule::ScalarVisaModule(CShader *TheShader,
92+
llvm::Function *TheFunction, bool IsPrimary,
93+
bool IsStackCallContext)
94+
: m_pShader(TheShader),
95+
VISAModule(TheFunction, IsPrimary, IsStackCallContext) {
96+
UpdateVisaId();
9697
}
9798

98-
std::unique_ptr<IGC::VISAModule> ScalarVisaModule::BuildNew(CShader* S,
99-
llvm::Function *F,
100-
bool IsPrimary)
101-
{
102-
auto* n = new ScalarVisaModule(S, F, IsPrimary);
99+
std::unique_ptr<IGC::VISAModule>
100+
ScalarVisaModule::BuildNew(CShader *S, llvm::Function *F, bool IsPrimary,
101+
bool IsStackCallContext) {
102+
auto *n = new ScalarVisaModule(S, F, IsPrimary, IsStackCallContext);
103103
return std::unique_ptr<IGC::VISAModule>(n);
104104
}
105105

IGC/Compiler/DebugInfo/ScalarVISAModule.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class ScalarVisaModule final : public IGC::VISAModule {
3333
public:
3434

3535
static std::unique_ptr<IGC::VISAModule>
36-
BuildNew(CShader* S, llvm::Function *F, bool IsPrimary = false);
36+
BuildNew(CShader *S, llvm::Function *F, bool IsPrimary = false,
37+
bool IsCallerStackCall = false);
3738

3839
unsigned int getUnpaddedProgramSize() const override {
3940
return m_pShader->ProgramOutput()->m_unpaddedProgramSize;
@@ -125,8 +126,11 @@ class ScalarVisaModule final : public IGC::VISAModule {
125126
/// used to emit vISA code.
126127
/// @param IsPrimary indicates if the currently processed function
127128
/// is a "primary entry point" to the corresponding Shader object.
129+
/// @param IsStackCallContext is set to true if current instance
130+
/// is a subroutine and caller context is stack call.
128131
/// See Source/IGC/DebugInfo/VISAModule.hpp for more details
129-
ScalarVisaModule(CShader* TheShader, llvm::Function *TheFunction, bool IsPrimary);
132+
ScalarVisaModule(CShader *TheShader, llvm::Function *TheFunction,
133+
bool IsPrimary, bool IsStackCallContext);
130134
/// @brief Trace given value to its origin value, searching for LLVM Argument.
131135
/// @param pVal value to process.
132136
/// @param isAddress indecates if the value represents an address.

IGC/DebugInfo/DwarfDebug.cpp

Lines changed: 99 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,13 @@ DIE *DwarfDebug::updateSubprogramScopeDIE(CompileUnit *SPCU, DISubprogram *SP) {
496496
}
497497
}
498498

499+
if (m_pModule && m_pModule->getFunction() &&
500+
m_pModule->getFunction()->getSubprogram() == SP &&
501+
m_pModule->GetType() == VISAModule::ObjectType::SUBROUTINE) {
502+
SPCU->addUInt(SPDie, dwarf::DW_AT_calling_convention, dwarf::DW_FORM_data1,
503+
dwarf::DW_CC_nocall);
504+
}
505+
499506
if (EmitSettings.EnableRelocation) {
500507
auto Id = m_pModule->GetFuncId();
501508
SPCU->addLabelAddress(SPDie, dwarf::DW_AT_low_pc,
@@ -1131,15 +1138,11 @@ void DwarfDebug::beginModule() {
11311138
SectionMap[Asm->GetTextSection()];
11321139

11331140
Asm->SwitchSection(Asm->GetDwarfFrameSection());
1134-
if (m_pModule->getSubroutines(*VisaDbgInfo)->empty()) {
1135-
// First stack call CIE is written out,
1136-
// next subroutine CIE if required.
1137-
offsetCIEStackCall = 0;
1138-
offsetCIESubroutine = writeStackcallCIE();
1139-
} else {
1140-
// TODO: .debug_frame for subrotuines is currently unsupported.
1141-
// writeSubroutineCIE();
1142-
}
1141+
offsetCIEStackCall = 0;
1142+
offsetCIESubroutine = writeStackcallCIE();
1143+
// First stack call CIE is written out,
1144+
// next subroutine CIE.
1145+
writeSubroutineCIE();
11431146
}
11441147

11451148
// Attach DW_AT_inline attribute with inlined subprogram DIEs.
@@ -2312,13 +2315,13 @@ void DwarfDebug::endFunction(const Function *MF) {
23122315
}
23132316

23142317
Asm->SwitchSection(Asm->GetDwarfFrameSection());
2315-
if (m_pModule->getSubroutines(*VisaDbgInfo)->empty()) {
2316-
LLVM_DEBUG(dbgs() << "[DwarfDebug] writing FDEStackCall start ---\n");
2317-
writeFDEStackCall(m_pModule);
2318-
LLVM_DEBUG(dbgs() << "[DwarfDebug] writing FDEStackCall end ***\n");
2318+
2319+
if (m_pModule->GetType() == VISAModule::ObjectType::SUBROUTINE) {
2320+
LLVM_DEBUG(dbgs() << "[DwarfDebug] writing FDESubproutine ***\n");
2321+
writeFDESubroutine(m_pModule);
23192322
} else {
2320-
LLVM_DEBUG(dbgs() << "[DwarfDebug] FDESubproutine skipped ***\n");
2321-
// writeFDESubroutine(m_pModule);
2323+
LLVM_DEBUG(dbgs() << "[DwarfDebug] writing FDEStackCall ***\n");
2324+
writeFDEStackCall(m_pModule);
23222325
}
23232326

23242327
ScopeVariables.clear();
@@ -2808,6 +2811,11 @@ uint32_t DwarfDebug::writeSubroutineCIE() {
28082811
std::vector<uint8_t> data;
28092812
auto numGRFs = GetVISAModule()->getNumGRFs();
28102813

2814+
auto writeSameValue = [](std::vector<uint8_t> &data, uint32_t srcReg) {
2815+
write(data, (uint8_t)llvm::dwarf::DW_CFA_same_value);
2816+
writeULEB128(data, srcReg);
2817+
};
2818+
28112819
// Emit CIE
28122820
auto ptrSize = Asm->GetPointerSize();
28132821
// The size of the length field plus the value of length must be an integral
@@ -2818,7 +2826,7 @@ uint32_t DwarfDebug::writeSubroutineCIE() {
28182826

28192827
// Write CIE_id
28202828
write(data,
2821-
ptrSize == 4 ? (uint32_t)0xfffffffe : (uint64_t)0xfffffffffffffffe);
2829+
ptrSize == 4 ? (uint32_t)0xffffffff : (uint64_t)0xffffffffffffffff);
28222830

28232831
// version - ubyte
28242832
write(data, (uint8_t)4);
@@ -2841,13 +2849,13 @@ uint32_t DwarfDebug::writeSubroutineCIE() {
28412849
// return address register - uleb128
28422850
// set machine return register to one which is physically
28432851
// absent. later CFA instructions map this to a valid GRF.
2844-
writeULEB128(data, numGRFs);
2852+
writeULEB128(data, RegisterNumbering::IP);
28452853

28462854
// initial instructions (array of ubyte)
2847-
// DW_CFA_def_cfa -> fpreg+0
2848-
write(data, (uint8_t)llvm::dwarf::DW_CFA_def_cfa);
2849-
writeULEB128(data, 0);
2850-
writeULEB128(data, 0);
2855+
// same value rule for all GRFs
2856+
for (unsigned int grf = 0; grf != numGRFs; ++grf) {
2857+
writeSameValue(data, GetEncodedRegNum<RegisterNumbering::GRFBase>(grf));
2858+
}
28512859

28522860
while ((lenSize + data.size()) % ptrSize != 0)
28532861
// Insert DW_CFA_nop
@@ -3028,7 +3036,8 @@ uint32_t DwarfDebug::writeStackcallCIE() {
30283036
}
30293037

30303038
void DwarfDebug::writeFDESubroutine(VISAModule *m) {
3031-
std::vector<uint8_t> data;
3039+
std::vector<uint8_t> data, data1;
3040+
uint64_t LabelOffset = std::numeric_limits<uint64_t>::max();
30323041

30333042
auto firstInst = (m->GetInstInfoMap()->begin())->first;
30343043
// TODO: fixup to a proper name getter
@@ -3045,8 +3054,6 @@ void DwarfDebug::writeFDESubroutine(VISAModule *m) {
30453054
if (!sub)
30463055
return;
30473056

3048-
auto numGRFs = GetVISAModule()->getNumGRFs();
3049-
30503057
// Emit CIE
30513058
auto ptrSize = Asm->GetPointerSize();
30523059
uint8_t lenSize = 4;
@@ -3081,27 +3088,68 @@ void DwarfDebug::writeFDESubroutine(VISAModule *m) {
30813088

30823089
// assume ret var is live throughout sub-routine and it is contained
30833090
// in same GRF.
3084-
uint32_t linearAddr =
3085-
(retvarLR.front().var.mapping.r.regNum * m_pModule->getGRFSizeInBytes()) +
3086-
retvarLR.front().var.mapping.r.subRegNum;
3091+
uint16_t retRegNum = retvarLR.front().var.mapping.r.regNum;
3092+
uint16_t retSubRegNum = retvarLR.front().var.mapping.r.subRegNum;
30873093

30883094
// initial location
3089-
write(data, ptrSize == 4 ? (uint32_t)genOffStart : genOffStart);
3095+
// LabelOffset holds offset where start %ip is written to buffer.
3096+
// Code later uses this to insert label for relocation.
3097+
LabelOffset = data.size();
3098+
if (EmitSettings.EnableRelocation) {
3099+
write(data,
3100+
ptrSize == 4 ? (uint32_t)0xfefefefe : (uint64_t)0xfefefefefefefefe);
3101+
} else {
3102+
write(data, ptrSize == 4 ? (uint32_t)genOffStart : (uint64_t)genOffStart);
3103+
}
30903104

30913105
// address range
30923106
write(data, ptrSize == 4 ? (uint32_t)(genOffEnd - genOffStart)
3093-
: (genOffEnd - genOffStart));
3107+
: (uint64_t)(genOffEnd - genOffStart));
30943108

30953109
// instruction - ubyte
3096-
write(data, (uint8_t)llvm::dwarf::DW_CFA_register);
3110+
write(data, (uint8_t)llvm::dwarf::DW_CFA_val_expression);
30973111

30983112
// return reg operand
3099-
writeULEB128(data, numGRFs);
3113+
writeULEB128(data, RegisterNumbering ::IP);
31003114

31013115
// actual reg holding retval
3102-
writeULEB128(data, linearAddr);
3116+
data1.clear();
3117+
write(data1, (uint8_t)llvm::dwarf::DW_OP_const2u);
3118+
write(data1,
3119+
(uint16_t)GetEncodedRegNum<RegisterNumbering::GRFBase>(retRegNum));
3120+
write(data1, (uint8_t)llvm::dwarf::DW_OP_const2u);
3121+
write(data1, (uint16_t)(retSubRegNum * 8));
3122+
write(data1, (uint8_t)DW_OP_INTEL_regval_bits);
3123+
write(data1, (uint8_t)32);
3124+
3125+
writeULEB128(data, data1.size());
3126+
for (auto item : data1)
3127+
write(data, (uint8_t)item);
31033128

31043129
// initial instructions (array of ubyte)
3130+
// DW_CFA_def_cfa_expression = DW_OP_lit0
3131+
write(data, (uint8_t)llvm::dwarf::DW_CFA_def_cfa_expression);
3132+
data1.clear();
3133+
if (m->StackCallContext()) {
3134+
// CFA is BE_SP location
3135+
write(data1, (uint8_t)llvm::dwarf::DW_OP_const2u);
3136+
write(data1, (uint16_t)GetEncodedRegNum<RegisterNumbering::GRFBase>(
3137+
GetSpecialGRF()));
3138+
write(data1, (uint8_t)llvm::dwarf::DW_OP_const1u);
3139+
if (GetABIVersion() == 3)
3140+
write(data1, (uint8_t)(BESPSubReg_3 * 32));
3141+
else
3142+
write(data1, (uint8_t)(BESPSubReg_1_2 * 32));
3143+
write(data1, (uint8_t)DW_OP_INTEL_regval_bits);
3144+
write(data1, (uint8_t)32);
3145+
encodeScratchAddrSpace(data1);
3146+
} else {
3147+
write(data1, (uint8_t)llvm::dwarf::DW_OP_lit0);
3148+
}
3149+
writeULEB128(data, data1.size());
3150+
for (auto item : data1)
3151+
write(data, (uint8_t)item);
3152+
31053153
while ((lenSize + data.size()) % ptrSize != 0)
31063154
// Insert DW_CFA_nop
31073155
write(data, (uint8_t)llvm::dwarf::DW_CFA_nop);
@@ -3111,8 +3159,24 @@ void DwarfDebug::writeFDESubroutine(VISAModule *m) {
31113159
Asm->EmitInt32(0xffffffff);
31123160
Asm->EmitIntValue(data.size(), ptrSize);
31133161

3114-
for (auto &byte : data)
3115-
Asm->EmitInt8(byte);
3162+
if (EmitSettings.EnableRelocation) {
3163+
uint32_t ByteOffset = 0;
3164+
3165+
for (auto it = data.begin(); it != data.end(); ++it) {
3166+
auto byte = *it;
3167+
if (ByteOffset++ == (uint32_t)LabelOffset) {
3168+
auto Label = GetLabelBeforeIp(genOffStart);
3169+
Asm->EmitLabelReference(Label, ptrSize, false);
3170+
// Now skip ptrSize number of bytes from data
3171+
std::advance(it, ptrSize);
3172+
byte = *it;
3173+
}
3174+
Asm->EmitInt8(byte);
3175+
}
3176+
} else {
3177+
for (auto &byte : data)
3178+
Asm->EmitInt8(byte);
3179+
}
31163180
}
31173181

31183182
void DwarfDebug::writeFDEStackCall(VISAModule *m) {
@@ -3316,7 +3380,7 @@ void DwarfDebug::writeFDEStackCall(VISAModule *m) {
33163380
write(data1, (uint8_t)llvm::dwarf::DW_OP_const4u);
33173381
write(data1, (uint32_t)(DWRegEncoded));
33183382
write(data1, (uint8_t)llvm::dwarf::DW_OP_const2u);
3319-
write(data1, (uint16_t)(getRetIPSubReg() * 4));
3383+
write(data1, (uint16_t)(getRetIPSubReg() * 4 * 8));
33203384
write(data1, (uint8_t)DW_OP_INTEL_regval_bits);
33213385
write(data1, (uint8_t)32);
33223386
writeULEB128(cfaOps[item.end + MovGenInstSizeInBytes], data1.size());

IGC/DebugInfo/VISAModule.hpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ class VISAModule {
412412

413413
std::unique_ptr<VarInfoCache> VICache = std::make_unique<VarInfoCache>();
414414

415+
bool IsStackCallContext = false;
416+
415417
public:
416418
/// @brief Constructor.
417419
/// @param AssociatedFunc holds llvm IR function associated with
@@ -421,8 +423,14 @@ class VISAModule {
421423
/// "Primary entry point" is a function that spawns a separate
422424
/// gen object (compiled gen isa code). Currently, such functions
423425
/// correspond to kernel functions or indirectly called functions.
424-
VISAModule(llvm::Function *AssociatedFunc, bool IsPrimary)
425-
: m_Func(AssociatedFunc), IsPrimaryFunc(IsPrimary) {}
426+
/// @param StackCallContext is true for subroutines when caller is
427+
/// a stack call function. For non-subroutines this field contains
428+
/// no useful meaning.
429+
VISAModule(llvm::Function *AssociatedFunc, bool IsPrimary,
430+
bool StackCallContext = false)
431+
: m_Func(AssociatedFunc), IsPrimaryFunc(IsPrimary) {
432+
IsStackCallContext = StackCallContext;
433+
}
426434

427435
virtual ~VISAModule() {}
428436

@@ -581,6 +589,8 @@ class VISAModule {
581589
llvm::Function *getFunction() const { return m_Func; }
582590
uint64_t GetFuncId() const { return (uint64_t)m_Func; }
583591

592+
bool StackCallContext() const { return IsStackCallContext; }
593+
584594
void dump() const { print(llvm::dbgs()); }
585595
void print(llvm::raw_ostream &OS) const;
586596
};

IGC/VectorCompiler/test/DebugInfo/NoDISP/subroutine.ll

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,24 @@
1212
; RUN: -vc-dbginfo-dumps-name-override=%basename_t \
1313
; RUN: -finalizer-opts='-generateDebugInfo' -o /dev/null
1414

15-
; RUN: llvm-dwarfdump -a dbginfo_%basename_t_test_kernel_dwarf.elf | FileCheck %s
15+
; REQUIRES: oneapi-readelf
16+
; RUN: oneapi-readelf --debug-dump dbginfo_%basename_t_test_kernel_dwarf.elf | FileCheck %s
1617

17-
; CHECK: .debug_abbrev contents:
18-
; CHECK: .debug_info contents:
18+
; CHECK: Contents of the .debug_info section:
1919

2020
; CHECK: DW_TAG_compile_unit
21-
; CHECK: DW_AT_name ("kernel_genx.cpp")
21+
; CHECK: DW_AT_name : kernel_genx.cpp
2222

2323
; CHECK: DW_TAG_subprogram
24-
; CHECK: DW_AT_name ("test_kernel")
24+
; CHECK: DW_AT_name : test_kernel
2525

26-
; CHECK: .debug_line contents:
27-
; CHECK: total_length: 0x[[#]]
28-
; CHECK: version: 4
29-
; CHECK: file_names{{\[}} [[#]]{{]}}:
30-
; CHECK: Address Line Column File ISA Discriminator Flags
26+
; CHECK: Contents of the .debug_abbrev section:
27+
28+
; CHECK: Raw dump of debug contents of section .debug_line:
29+
; CHECK: Length: [[#]]
30+
; CHECK: DWARF Version: 4
31+
; CHECK: The Directory Table
32+
; CHECK: The File Name Table
3133

3234
; ModuleID = 'Deserialized SPIRV Module'
3335
target datalayout = "e-p:64:64-i64:64-n8:16:32"

visa/DebugInfo.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,25 @@ template <class T> void emitDataSubroutines(VISAKernelImpl *visaKernel, T &t) {
10461046
}
10471047
}
10481048
vISA_ASSERT(retval && subLabel, "All of the basic blocks are empty.");
1049-
emitDataName(subLabel->getLabelName(), t);
1049+
auto sanitizeSubLabel = [&](const char *lbl) {
1050+
// VISA appends L_f#_ prefix to subroutines contained
1051+
// in stack call functions. This causes a mismatch
1052+
// with function name in llvm IR. When emitting VISA
1053+
// VISA debug info, we remove this prefix.
1054+
std::string newName = lbl;
1055+
if (visaKernel->getIsFunction()) {
1056+
// Sanity check for first char of prefix
1057+
if (newName.find("L_f") != 0)
1058+
return newName;
1059+
// Eliminate L_f
1060+
newName = newName.substr(3);
1061+
auto delim = newName.find('_');
1062+
newName = newName.substr(delim + 1);
1063+
return newName;
1064+
}
1065+
return newName;
1066+
};
1067+
emitDataName(sanitizeSubLabel(subLabel->getLabelName()), t);
10501068
emitDataUInt32(start, t);
10511069
emitDataUInt32(end, t);
10521070

0 commit comments

Comments
 (0)