GCC Code Coverage Report


Directory: ../
File: src/irgenerator/DebugInfoGenerator.cpp
Date: 2025-03-05 01:50:32
Exec Total Coverage
Lines: 198 266 74.4%
Functions: 12 13 92.3%
Branches: 215 488 44.1%

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "DebugInfoGenerator.h"
4
5 #include <llvm/BinaryFormat/Dwarf.h>
6 #include <llvm/IR/Module.h>
7
8 #include <ast/ASTNodes.h>
9 #include <driver/Driver.h>
10 #include <irgenerator/IRGenerator.h>
11 #include <irgenerator/NameMangling.h>
12 #include <model/Function.h>
13 #include <model/Struct.h>
14 #include <util/CustomHashFunctions.h>
15 #include <util/FileUtil.h>
16
17 namespace spice::compiler {
18
19 15 void DebugInfoGenerator::initialize(const std::string &sourceFileName, std::filesystem::path sourceFileDir) {
20 15 llvm::Module *module = irGenerator->module;
21 15 llvm::LLVMContext &context = irGenerator->context;
22
23 // Create DIBuilder
24
1/2
✓ Branch 0 (2→3) taken 15 times.
✗ Branch 1 (2→119) not taken.
15 diBuilder = std::make_unique<llvm::DIBuilder>(*module);
25
26 // Create compilation unit
27
3/6
✓ Branch 0 (5→6) taken 15 times.
✗ Branch 1 (5→124) not taken.
✓ Branch 2 (6→7) taken 15 times.
✗ Branch 3 (6→122) not taken.
✓ Branch 4 (7→8) taken 15 times.
✗ Branch 5 (7→120) not taken.
15 std::filesystem::path absolutePath = absolute(sourceFileDir / sourceFileName);
28 15 absolutePath.make_preferred();
29 15 sourceFileDir.make_preferred();
30
3/6
✓ Branch 0 (15→16) taken 15 times.
✗ Branch 1 (15→132) not taken.
✓ Branch 2 (17→18) taken 15 times.
✗ Branch 3 (17→128) not taken.
✓ Branch 4 (19→20) taken 15 times.
✗ Branch 5 (19→126) not taken.
30 llvm::DIFile *cuDiFile = diBuilder->createFile(absolutePath.string(), sourceFileDir.string());
31
3/6
✓ Branch 0 (25→26) taken 15 times.
✗ Branch 1 (25→138) not taken.
✓ Branch 2 (26→27) taken 15 times.
✗ Branch 3 (26→137) not taken.
✓ Branch 4 (28→29) taken 15 times.
✗ Branch 5 (28→136) not taken.
30 compileUnit = diBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus_14, cuDiFile, PRODUCER_STRING,
32 15 irGenerator->cliOptions.optLevel > O0, "", 0, "", llvm::DICompileUnit::FullDebug, 0,
33 false, false, llvm::DICompileUnit::DebugNameTableKind::None);
34
35
2/4
✓ Branch 0 (29→30) taken 15 times.
✗ Branch 1 (29→141) not taken.
✓ Branch 2 (30→31) taken 15 times.
✗ Branch 3 (30→141) not taken.
15 module->addModuleFlag(llvm::Module::Max, "Dwarf Version", 5);
36
2/4
✓ Branch 0 (31→32) taken 15 times.
✗ Branch 1 (31→142) not taken.
✓ Branch 2 (32→33) taken 15 times.
✗ Branch 3 (32→142) not taken.
15 module->addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION);
37
38 // Create another DIFile as scope for subprograms
39
2/4
✓ Branch 0 (36→37) taken 15 times.
✗ Branch 1 (36→146) not taken.
✓ Branch 2 (39→40) taken 15 times.
✗ Branch 3 (39→143) not taken.
30 diFile = diBuilder->createFile(sourceFileName, sourceFileDir.string());
40
41
1/2
✓ Branch 0 (42→43) taken 15 times.
✗ Branch 1 (42→182) not taken.
15 pointerWidth = irGenerator->module->getDataLayout().getPointerSizeInBits();
42
43 // Initialize primitive debug types
44
2/4
✓ Branch 0 (44→45) taken 15 times.
✗ Branch 1 (44→150) not taken.
✓ Branch 2 (45→46) taken 15 times.
✗ Branch 3 (45→150) not taken.
15 doubleTy = diBuilder->createBasicType("double", 64, llvm::dwarf::DW_ATE_float);
45
2/4
✓ Branch 0 (47→48) taken 15 times.
✗ Branch 1 (47→151) not taken.
✓ Branch 2 (48→49) taken 15 times.
✗ Branch 3 (48→151) not taken.
15 intTy = diBuilder->createBasicType("int", 32, llvm::dwarf::DW_ATE_signed);
46
2/4
✓ Branch 0 (50→51) taken 15 times.
✗ Branch 1 (50→152) not taken.
✓ Branch 2 (51→52) taken 15 times.
✗ Branch 3 (51→152) not taken.
15 uIntTy = diBuilder->createBasicType("unsigned int", 32, llvm::dwarf::DW_ATE_unsigned);
47
2/4
✓ Branch 0 (53→54) taken 15 times.
✗ Branch 1 (53→153) not taken.
✓ Branch 2 (54→55) taken 15 times.
✗ Branch 3 (54→153) not taken.
15 shortTy = diBuilder->createBasicType("short", 16, llvm::dwarf::DW_ATE_signed);
48
2/4
✓ Branch 0 (56→57) taken 15 times.
✗ Branch 1 (56→154) not taken.
✓ Branch 2 (57→58) taken 15 times.
✗ Branch 3 (57→154) not taken.
15 uShortTy = diBuilder->createBasicType("unsigned short", 16, llvm::dwarf::DW_ATE_unsigned);
49
2/4
✓ Branch 0 (59→60) taken 15 times.
✗ Branch 1 (59→155) not taken.
✓ Branch 2 (60→61) taken 15 times.
✗ Branch 3 (60→155) not taken.
15 longTy = diBuilder->createBasicType("long", 64, llvm::dwarf::DW_ATE_signed);
50
2/4
✓ Branch 0 (62→63) taken 15 times.
✗ Branch 1 (62→156) not taken.
✓ Branch 2 (63→64) taken 15 times.
✗ Branch 3 (63→156) not taken.
15 uLongTy = diBuilder->createBasicType("unsigned long", 64, llvm::dwarf::DW_ATE_unsigned);
51
2/4
✓ Branch 0 (65→66) taken 15 times.
✗ Branch 1 (65→157) not taken.
✓ Branch 2 (66→67) taken 15 times.
✗ Branch 3 (66→157) not taken.
15 byteTy = diBuilder->createBasicType("byte", 8, llvm::dwarf::DW_ATE_unsigned);
52
2/4
✓ Branch 0 (68→69) taken 15 times.
✗ Branch 1 (68→158) not taken.
✓ Branch 2 (69→70) taken 15 times.
✗ Branch 3 (69→158) not taken.
15 charTy = diBuilder->createBasicType("char", 8, llvm::dwarf::DW_ATE_unsigned_char);
53
1/2
✓ Branch 0 (74→75) taken 15 times.
✗ Branch 1 (74→159) not taken.
30 stringTy = diBuilder->createPointerType(charTy, pointerWidth);
54
2/4
✓ Branch 0 (76→77) taken 15 times.
✗ Branch 1 (76→162) not taken.
✓ Branch 2 (77→78) taken 15 times.
✗ Branch 3 (77→162) not taken.
15 boolTy = diBuilder->createBasicType("bool", 8, llvm::dwarf::DW_ATE_boolean);
55
2/4
✓ Branch 0 (79→80) taken 15 times.
✗ Branch 1 (79→163) not taken.
✓ Branch 2 (80→81) taken 15 times.
✗ Branch 3 (80→163) not taken.
15 voidTy = diBuilder->createBasicType("void", 0, llvm::dwarf::DW_ATE_unsigned);
56
57 // Initialize fat ptr type
58
1/2
✓ Branch 0 (81→82) taken 15 times.
✗ Branch 1 (81→182) not taken.
15 llvm::PointerType *ptrTy = irGenerator->builder.getPtrTy();
59
1/2
✓ Branch 0 (82→83) taken 15 times.
✗ Branch 1 (82→86) not taken.
15 if (!irGenerator->llvmTypes.fatPtrType)
60
1/2
✓ Branch 0 (84→85) taken 15 times.
✗ Branch 1 (84→164) not taken.
15 irGenerator->llvmTypes.fatPtrType = llvm::StructType::get(context, {ptrTy, ptrTy});
61
62 15 const llvm::DataLayout &dataLayout = module->getDataLayout();
63
1/2
✓ Branch 0 (87→88) taken 15 times.
✗ Branch 1 (87→182) not taken.
15 const llvm::StructLayout *structLayout = dataLayout.getStructLayout(irGenerator->llvmTypes.fatPtrType);
64
1/2
✓ Branch 0 (88→89) taken 15 times.
✗ Branch 1 (88→166) not taken.
15 const uint32_t alignInBits = dataLayout.getABITypeAlign(irGenerator->llvmTypes.fatPtrType).value();
65
1/2
✓ Branch 0 (90→91) taken 15 times.
✗ Branch 1 (90→167) not taken.
15 const uint32_t ptrAlignInBits = dataLayout.getABITypeAlign(ptrTy).value();
66
67
6/12
✓ Branch 0 (93→94) taken 15 times.
✗ Branch 1 (93→171) not taken.
✓ Branch 2 (95→96) taken 15 times.
✗ Branch 3 (95→170) not taken.
✓ Branch 4 (96→97) taken 15 times.
✗ Branch 5 (96→169) not taken.
✓ Branch 6 (97→98) taken 15 times.
✗ Branch 7 (97→169) not taken.
✓ Branch 8 (98→99) taken 15 times.
✗ Branch 9 (98→168) not taken.
✓ Branch 10 (99→100) taken 15 times.
✗ Branch 11 (99→168) not taken.
15 fatPtrTy = diBuilder->createStructType(diFile, "_fat_ptr", diFile, 0, structLayout->getSizeInBits(), alignInBits,
68 llvm::DINode::FlagTypePassByValue | llvm::DINode::FlagNonTrivial, nullptr, {}, 0,
69 nullptr, "_fat_ptr");
70
71
1/2
✓ Branch 0 (104→105) taken 15 times.
✗ Branch 1 (104→172) not taken.
30 llvm::DIType *voidPtrDIType = diBuilder->createPointerType(voidTy, pointerWidth, ptrAlignInBits);
72
2/4
✓ Branch 0 (107→108) taken 15 times.
✗ Branch 1 (107→175) not taken.
✓ Branch 2 (108→109) taken 15 times.
✗ Branch 3 (108→175) not taken.
15 llvm::DIDerivedType *firstType = diBuilder->createMemberType(fatPtrTy, "fct", diFile, 0, pointerWidth, ptrAlignInBits, 0,
73 llvm::DINode::FlagZero, voidPtrDIType);
74
1/2
✓ Branch 0 (112→113) taken 15 times.
✗ Branch 1 (112→177) not taken.
30 llvm::DIDerivedType *secondType = diBuilder->createMemberType(fatPtrTy, "captures", diFile, 0, pointerWidth, ptrAlignInBits,
75
1/2
✓ Branch 0 (111→112) taken 15 times.
✗ Branch 1 (111→177) not taken.
15 pointerWidth, llvm::DINode::FlagZero, voidPtrDIType);
76
2/4
✓ Branch 0 (114→115) taken 15 times.
✗ Branch 1 (114→179) not taken.
✓ Branch 2 (116→117) taken 15 times.
✗ Branch 3 (116→179) not taken.
15 fatPtrTy->replaceElements(llvm::MDTuple::get(context, {firstType, secondType}));
77 15 }
78
79 8332 void DebugInfoGenerator::generateFunctionDebugInfo(llvm::Function *llvmFunction, const Function *spiceFunc, bool isLambda) {
80
2/2
✓ Branch 0 (2→3) taken 8159 times.
✓ Branch 1 (2→4) taken 173 times.
8332 if (!irGenerator->cliOptions.generateDebugInfo)
81 8159 return;
82
83 173 const ASTNode *node = spiceFunc->declNode;
84
1/2
✓ Branch 0 (4→5) taken 173 times.
✗ Branch 1 (4→117) not taken.
173 const uint32_t lineNo = spiceFunc->getDeclCodeLoc().line;
85
86 // Prepare flags
87 173 llvm::DIScope *scope = diFile;
88 173 llvm::DINode::DIFlags flags = llvm::DINode::FlagPrototyped;
89
8/10
✓ Branch 0 (5→6) taken 171 times.
✓ Branch 1 (5→10) taken 2 times.
✓ Branch 2 (6→7) taken 171 times.
✗ Branch 3 (6→117) not taken.
✓ Branch 4 (7→8) taken 171 times.
✗ Branch 5 (7→117) not taken.
✓ Branch 6 (8→9) taken 165 times.
✓ Branch 7 (8→10) taken 6 times.
✓ Branch 8 (11→12) taken 165 times.
✓ Branch 9 (11→13) taken 8 times.
173 if (spiceFunc->entry && spiceFunc->entry->getQualType().isPublic())
90
1/2
✓ Branch 0 (12→13) taken 165 times.
✗ Branch 1 (12→117) not taken.
165 flags |= llvm::DINode::FlagPublic;
91
92 // Prepare spFlags
93 173 llvm::DISubprogram::DISPFlags spFlags = llvm::DISubprogram::SPFlagDefinition;
94
1/2
✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→15) taken 173 times.
173 if (isLambda)
95 spFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
96
2/2
✓ Branch 0 (15→16) taken 5 times.
✓ Branch 1 (15→20) taken 168 times.
173 if (spiceFunc->isVirtual) {
97
2/4
✓ Branch 0 (16→17) taken 5 times.
✗ Branch 1 (16→117) not taken.
✗ Branch 2 (17→18) not taken.
✓ Branch 3 (17→19) taken 5 times.
5 if (spiceFunc->thisType.is(TY_INTERFACE))
98 spFlags |= llvm::DISubprogram::SPFlagPureVirtual;
99 else
100
1/2
✓ Branch 0 (19→20) taken 5 times.
✗ Branch 1 (19→117) not taken.
5 spFlags |= llvm::DISubprogram::SPFlagVirtual;
101 }
102
103 // Collect arguments
104
1/2
✓ Branch 0 (20→21) taken 173 times.
✗ Branch 1 (20→115) not taken.
173 std::vector<llvm::Metadata *> argTypes;
105
2/2
✓ Branch 0 (23→24) taken 52 times.
✓ Branch 1 (23→26) taken 121 times.
173 if (spiceFunc->isProcedure())
106
1/2
✓ Branch 0 (24→25) taken 52 times.
✗ Branch 1 (24→89) not taken.
52 argTypes.push_back(voidTy);
107 else
108
2/4
✓ Branch 0 (26→27) taken 121 times.
✗ Branch 1 (26→90) not taken.
✓ Branch 2 (27→28) taken 121 times.
✗ Branch 3 (27→90) not taken.
121 argTypes.push_back(getDITypeForQualType(node, spiceFunc->returnType)); // Add result type
109
2/2
✓ Branch 0 (32→33) taken 107 times.
✓ Branch 1 (32→36) taken 66 times.
173 if (spiceFunc->isMethod())
110
2/4
✓ Branch 0 (33→34) taken 107 times.
✗ Branch 1 (33→91) not taken.
✓ Branch 2 (34→35) taken 107 times.
✗ Branch 3 (34→91) not taken.
107 argTypes.push_back(getDITypeForQualType(node, spiceFunc->thisType)); // Add this type
111
1/2
✗ Branch 0 (36→37) not taken.
✓ Branch 1 (36→45) taken 173 times.
173 if (isLambda) {
112 llvm::DICompositeType *captureStructType = generateCaptureStructDebugInfo(spiceFunc);
113 scope = captureStructType;
114 llvm::DIType *captureStructPtr = diBuilder->createPointerType(captureStructType, pointerWidth);
115 argTypes.push_back(captureStructPtr); // Add this type
116 }
117
3/4
✓ Branch 0 (45→46) taken 173 times.
✗ Branch 1 (45→99) not taken.
✓ Branch 2 (53→48) taken 192 times.
✓ Branch 3 (53→54) taken 173 times.
365 for (const QualType &argType : spiceFunc->getParamTypes()) // Add arg types
118
2/4
✓ Branch 0 (49→50) taken 192 times.
✗ Branch 1 (49→96) not taken.
✓ Branch 2 (50→51) taken 192 times.
✗ Branch 3 (50→96) not taken.
365 argTypes.push_back(getDITypeForQualType(node, argType));
119
120 // Create function type
121
2/4
✓ Branch 0 (58→59) taken 173 times.
✗ Branch 1 (58→100) not taken.
✓ Branch 2 (59→60) taken 173 times.
✗ Branch 3 (59→100) not taken.
173 llvm::DISubroutineType *functionTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray(argTypes));
122
123
1/2
✓ Branch 0 (60→61) taken 173 times.
✗ Branch 1 (60→115) not taken.
173 const std::string mangledName = spiceFunc->getMangledName();
124 llvm::DISubprogram *subprogram;
125
1/2
✓ Branch 0 (61→62) taken 173 times.
✗ Branch 1 (61→113) not taken.
173 const std::string &name = spiceFunc->name;
126
2/2
✓ Branch 0 (64→65) taken 107 times.
✓ Branch 1 (64→72) taken 66 times.
173 if (spiceFunc->isMethod()) {
127
1/2
✓ Branch 0 (70→71) taken 107 times.
✗ Branch 1 (70→101) not taken.
107 subprogram = diBuilder->createMethod(scope, name, mangledName, diFile, lineNo, functionTy, 0, 0, nullptr, flags, spFlags);
128 } else {
129
1/2
✓ Branch 0 (79→80) taken 66 times.
✗ Branch 1 (79→105) not taken.
132 subprogram = diBuilder->createFunction(scope, name, mangledName, diFile, lineNo, functionTy, lineNo, flags, spFlags);
130 }
131
1/2
✓ Branch 0 (82→83) taken 173 times.
✗ Branch 1 (82→111) not taken.
173 subprogram->replaceRetainedNodes({});
132
133 // Add debug info to LLVM function
134
1/2
✓ Branch 0 (83→84) taken 173 times.
✗ Branch 1 (83→113) not taken.
173 llvmFunction->setSubprogram(subprogram);
135 // Add scope to lexicalBlocks
136
1/2
✓ Branch 0 (84→85) taken 173 times.
✗ Branch 1 (84→112) not taken.
173 lexicalBlocks.push(subprogram);
137 173 }
138
139 8556 void DebugInfoGenerator::concludeFunctionDebugInfo() {
140
2/2
✓ Branch 0 (2→3) taken 8383 times.
✓ Branch 1 (2→4) taken 173 times.
8556 if (!irGenerator->cliOptions.generateDebugInfo)
141 8383 return;
142
143
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 173 times.
173 assert(!lexicalBlocks.empty());
144 173 lexicalBlocks.pop();
145 }
146
147 7577 void DebugInfoGenerator::pushLexicalBlock(const ASTNode *node) {
148
2/2
✓ Branch 0 (2→3) taken 7401 times.
✓ Branch 1 (2→4) taken 176 times.
7577 if (!irGenerator->cliOptions.generateDebugInfo)
149 7401 return;
150
151 176 const uint32_t line = node->codeLoc.line;
152 176 const uint32_t col = node->codeLoc.col;
153 176 llvm::DILexicalBlock *lexicalBlock = diBuilder->createLexicalBlock(lexicalBlocks.top(), diFile, line, col);
154
1/2
✓ Branch 0 (7→8) taken 176 times.
✗ Branch 1 (7→10) not taken.
176 lexicalBlocks.push(lexicalBlock);
155 }
156
157 7577 void DebugInfoGenerator::popLexicalBlock() {
158
2/2
✓ Branch 0 (2→3) taken 7401 times.
✓ Branch 1 (2→4) taken 176 times.
7577 if (!irGenerator->cliOptions.generateDebugInfo)
159 7401 return;
160
161
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 176 times.
176 assert(!lexicalBlocks.empty());
162 176 lexicalBlocks.pop();
163 }
164
165 llvm::DICompositeType *DebugInfoGenerator::generateCaptureStructDebugInfo(const Function *spiceFunc) {
166 const CaptureMap &captures = spiceFunc->bodyScope->symbolTable.captures;
167 const ASTNode *node = spiceFunc->declNode;
168 const uint32_t lineNo = node->codeLoc.line;
169
170 // Get LLVM type for struct
171 std::vector<llvm::Type *> fieldTypes;
172 std::vector<SymbolTableEntry *> fieldEntries;
173 QualTypeList fieldSymbolTypes;
174 for (const auto &capture : captures | std::views::values) {
175 QualType captureType = capture.capturedSymbol->getQualType();
176
177 // Capture by reference
178 if (capture.getMode() == BY_REFERENCE)
179 captureType = captureType.toRef(node);
180
181 fieldEntries.push_back(capture.capturedSymbol);
182 fieldSymbolTypes.push_back(captureType);
183 fieldTypes.push_back(captureType.toLLVMType(irGenerator->sourceFile));
184 }
185 llvm::StructType *structType = llvm::StructType::get(irGenerator->context, fieldTypes);
186 const llvm::StructLayout *structLayout = irGenerator->module->getDataLayout().getStructLayout(structType);
187 const size_t alignInBits = irGenerator->module->getDataLayout().getABITypeAlign(structType).value();
188
189 llvm::DIScope *scope = lexicalBlocks.top();
190 llvm::DICompositeType *structDiType =
191 diBuilder->createClassType(scope, "", diFile, lineNo, structLayout->getSizeInBits(), alignInBits, 0,
192 llvm::DINode::FlagTypePassByValue | llvm::DINode::FlagNonTrivial, nullptr, {});
193
194 std::vector<llvm::Metadata *> fieldDITypes;
195 for (size_t i = 0; i < fieldEntries.size(); i++) {
196 llvm::DIType *fieldDiType = getDITypeForQualType(node, fieldSymbolTypes.at(i));
197 const std::string &fieldName = fieldEntries.at(i)->name;
198 const size_t offsetInBits = structLayout->getElementOffsetInBits(i);
199 const size_t fieldSize = fieldDiType->getSizeInBits();
200 const size_t fieldAlign = fieldDiType->getAlignInBits();
201 llvm::DIDerivedType *fieldDiDerivedType = diBuilder->createMemberType(
202 structDiType, fieldName, diFile, lineNo, fieldSize, fieldAlign, offsetInBits, llvm::DINode::FlagZero, fieldDiType);
203 fieldDITypes.push_back(fieldDiDerivedType);
204 }
205 structDiType->replaceElements(llvm::MDTuple::get(irGenerator->context, fieldDITypes));
206
207 return structDiType;
208 }
209
210 1119 void DebugInfoGenerator::generateGlobalVarDebugInfo(llvm::GlobalVariable *global, const SymbolTableEntry *globalEntry) {
211
2/2
✓ Branch 0 (2→3) taken 1113 times.
✓ Branch 1 (2→4) taken 6 times.
1119 if (!irGenerator->cliOptions.generateDebugInfo)
212 1113 return;
213
214
1/2
✓ Branch 0 (4→5) taken 6 times.
✗ Branch 1 (4→17) not taken.
6 const uint32_t lineNo = globalEntry->getDeclCodeLoc().line;
215
1/2
✓ Branch 0 (5→6) taken 6 times.
✗ Branch 1 (5→17) not taken.
6 const llvm::StringRef name = global->getName();
216
2/4
✓ Branch 0 (6→7) taken 6 times.
✗ Branch 1 (6→17) not taken.
✓ Branch 2 (7→8) taken 6 times.
✗ Branch 3 (7→17) not taken.
6 llvm::DIType *type = getDITypeForQualType(globalEntry->declNode, globalEntry->getQualType());
217
2/4
✓ Branch 0 (8→9) taken 6 times.
✗ Branch 1 (8→17) not taken.
✓ Branch 2 (9→10) taken 6 times.
✗ Branch 3 (9→17) not taken.
6 const bool isLocal = globalEntry->getQualType().isPublic();
218
219
2/4
✓ Branch 0 (12→13) taken 6 times.
✗ Branch 1 (12→16) not taken.
✓ Branch 2 (13→14) taken 6 times.
✗ Branch 3 (13→16) not taken.
6 global->addDebugInfo(diBuilder->createGlobalVariableExpression(compileUnit, name, name, diFile, lineNo, type, isLocal));
220 }
221
222 33 void DebugInfoGenerator::generateGlobalStringDebugInfo(llvm::GlobalVariable *global, const std::string &name, size_t length,
223 const CodeLoc &codeLoc) const {
224 33 const uint32_t lineNo = codeLoc.line;
225 33 const size_t sizeInBits = (length + 1) * 8; // +1 because of null-terminator
226
227
1/2
✓ Branch 0 (4→5) taken 33 times.
✗ Branch 1 (4→12) not taken.
33 llvm::DIStringType *stringType = diBuilder->createStringType(name, sizeInBits);
228
2/4
✓ Branch 0 (9→10) taken 33 times.
✗ Branch 1 (9→13) not taken.
✓ Branch 2 (10→11) taken 33 times.
✗ Branch 3 (10→13) not taken.
33 global->addDebugInfo(diBuilder->createGlobalVariableExpression(compileUnit, name, name, diFile, lineNo, stringType, true));
229 33 }
230
231 26972 void DebugInfoGenerator::generateLocalVarDebugInfo(const std::string &varName, llvm::Value *address, const size_t argNumber) {
232
2/2
✓ Branch 0 (2→3) taken 26400 times.
✓ Branch 1 (2→4) taken 572 times.
26972 if (!irGenerator->cliOptions.generateDebugInfo)
233 26400 return;
234
235 // Get symbol table entry
236 572 const SymbolTableEntry *variableEntry = irGenerator->currentScope->lookupStrict(varName);
237
1/2
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 572 times.
572 assert(variableEntry != nullptr);
238 // Build debug info
239 572 llvm::DIScope *scope = lexicalBlocks.top();
240 572 llvm::DIType *diType = getDITypeForQualType(variableEntry->declNode, variableEntry->getQualType());
241 572 const uint32_t lineNo = variableEntry->declNode->codeLoc.line;
242
243 llvm::DILocalVariable *varInfo;
244
2/2
✓ Branch 0 (12→13) taken 299 times.
✓ Branch 1 (12→18) taken 273 times.
572 if (argNumber != SIZE_MAX)
245
1/2
✓ Branch 0 (16→17) taken 299 times.
✗ Branch 1 (16→36) not taken.
299 varInfo = diBuilder->createParameterVariable(scope, varName, argNumber, diFile, lineNo, diType);
246 else
247
1/2
✓ Branch 0 (20→21) taken 273 times.
✗ Branch 1 (20→38) not taken.
273 varInfo = diBuilder->createAutoVariable(scope, varName, diFile, lineNo, diType);
248
1/2
✓ Branch 0 (24→25) taken 572 times.
✗ Branch 1 (24→39) not taken.
572 llvm::DIExpression *expr = diBuilder->createExpression();
249
2/4
✓ Branch 0 (25→26) taken 572 times.
✗ Branch 1 (25→42) not taken.
✓ Branch 2 (26→27) taken 572 times.
✗ Branch 3 (26→40) not taken.
572 const llvm::DILocation *debugLocation = irGenerator->builder.getCurrentDebugLocation();
250
1/2
✗ Branch 0 (28→29) not taken.
✓ Branch 1 (28→30) taken 572 times.
572 assert(debugLocation != nullptr);
251
1/2
✓ Branch 0 (33→34) taken 572 times.
✗ Branch 1 (33→43) not taken.
572 diBuilder->insertDeclare(address, varInfo, expr, debugLocation, irGenerator->builder.GetInsertPoint());
252 }
253
254 1105914 void DebugInfoGenerator::setSourceLocation(const CodeLoc &codeLoc) {
255
2/2
✓ Branch 0 (2→3) taken 1082075 times.
✓ Branch 1 (2→4) taken 23839 times.
1105914 if (!irGenerator->cliOptions.generateDebugInfo)
256 1082075 return;
257
258
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 23839 times.
23839 assert(!lexicalBlocks.empty());
259 23839 llvm::DIScope *scope = lexicalBlocks.top();
260 23839 const llvm::DILocation *diCodeLoc = llvm::DILocation::get(scope->getContext(), codeLoc.line, codeLoc.col, scope);
261
2/4
✓ Branch 0 (10→11) taken 23839 times.
✗ Branch 1 (10→17) not taken.
✓ Branch 2 (11→12) taken 23839 times.
✗ Branch 3 (11→15) not taken.
23839 irGenerator->builder.SetCurrentDebugLocation(diCodeLoc);
262 }
263
264 1081674 void DebugInfoGenerator::setSourceLocation(const ASTNode *node) { setSourceLocation(node->codeLoc); }
265
266 822 void DebugInfoGenerator::finalize() const {
267
2/2
✓ Branch 0 (2→3) taken 15 times.
✓ Branch 1 (2→5) taken 807 times.
822 if (irGenerator->cliOptions.generateDebugInfo)
268 15 diBuilder->finalize();
269 822 }
270
271 1337 llvm::DIType *DebugInfoGenerator::getDITypeForQualType(const ASTNode *node, const QualType &ty) { // NOLINT(*-no-recursion)
272 // Pointer type
273
2/2
✓ Branch 0 (3→4) taken 166 times.
✓ Branch 1 (3→13) taken 1171 times.
1337 if (ty.isPtr()) {
274
2/4
✓ Branch 0 (4→5) taken 166 times.
✗ Branch 1 (4→176) not taken.
✓ Branch 2 (5→6) taken 166 times.
✗ Branch 3 (5→176) not taken.
166 llvm::DIType *pointeeTy = getDITypeForQualType(node, ty.getContained());
275
1/2
✓ Branch 0 (10→11) taken 166 times.
✗ Branch 1 (10→177) not taken.
332 return diBuilder->createPointerType(pointeeTy, pointerWidth);
276 }
277
278 // Reference type
279
2/2
✓ Branch 0 (14→15) taken 117 times.
✓ Branch 1 (14→22) taken 1054 times.
1171 if (ty.isRef()) {
280
2/4
✓ Branch 0 (15→16) taken 117 times.
✗ Branch 1 (15→180) not taken.
✓ Branch 2 (16→17) taken 117 times.
✗ Branch 3 (16→180) not taken.
117 llvm::DIType *referencedType = getDITypeForQualType(node, ty.getContained());
281
1/2
✓ Branch 0 (19→20) taken 117 times.
✗ Branch 1 (19→181) not taken.
234 return diBuilder->createReferenceType(llvm::dwarf::DW_TAG_reference_type, referencedType, pointerWidth);
282 }
283
284 // Array type
285
2/2
✓ Branch 0 (23→24) taken 2 times.
✓ Branch 1 (23→38) taken 1052 times.
1054 if (ty.isArray()) {
286
2/4
✓ Branch 0 (24→25) taken 2 times.
✗ Branch 1 (24→182) not taken.
✓ Branch 2 (25→26) taken 2 times.
✗ Branch 3 (25→182) not taken.
2 llvm::DIType *itemTy = getDITypeForQualType(node, ty.getContained());
287
1/2
✓ Branch 0 (26→27) taken 2 times.
✗ Branch 1 (26→188) not taken.
2 const size_t size = ty.getArraySize();
288
1/2
✓ Branch 0 (29→30) taken 2 times.
✗ Branch 1 (29→183) not taken.
2 const llvm::DINodeArray subscripts = diBuilder->getOrCreateArray({});
289
5/10
✓ Branch 0 (31→32) taken 2 times.
✗ Branch 1 (31→187) not taken.
✓ Branch 2 (32→33) taken 2 times.
✗ Branch 3 (32→186) not taken.
✓ Branch 4 (33→34) taken 2 times.
✗ Branch 5 (33→185) not taken.
✓ Branch 6 (34→35) taken 2 times.
✗ Branch 7 (34→184) not taken.
✓ Branch 8 (35→36) taken 2 times.
✗ Branch 9 (35→184) not taken.
2 return diBuilder->createArrayType(size, 0, itemTy, subscripts);
290 }
291
292 // Primitive types
293 llvm::DIType *baseDiType;
294
7/12
✗ Branch 0 (39→40) not taken.
✓ Branch 1 (39→41) taken 62 times.
✗ Branch 2 (39→46) not taken.
✓ Branch 3 (39→51) taken 246 times.
✓ Branch 4 (39→56) taken 34 times.
✓ Branch 5 (39→57) taken 131 times.
✓ Branch 6 (39→58) taken 126 times.
✓ Branch 7 (39→59) taken 120 times.
✓ Branch 8 (39→60) taken 333 times.
✗ Branch 9 (39→125) not taken.
✗ Branch 10 (39→160) not taken.
✗ Branch 11 (39→161) not taken.
1052 switch (ty.getSuperType()) {
295 case TY_DOUBLE:
296 baseDiType = doubleTy;
297 break;
298 62 case TY_INT:
299
2/2
✓ Branch 0 (42→43) taken 45 times.
✓ Branch 1 (42→44) taken 17 times.
62 baseDiType = ty.isSigned() ? intTy : uIntTy;
300 62 break;
301 case TY_SHORT:
302 baseDiType = ty.isSigned() ? shortTy : uShortTy;
303 break;
304 246 case TY_LONG:
305
2/2
✓ Branch 0 (52→53) taken 49 times.
✓ Branch 1 (52→54) taken 197 times.
246 baseDiType = ty.isSigned() ? longTy : uLongTy;
306 246 break;
307 34 case TY_BYTE:
308 34 baseDiType = byteTy;
309 34 break;
310 131 case TY_CHAR:
311 131 baseDiType = charTy;
312 131 break;
313 126 case TY_STRING:
314 126 baseDiType = stringTy;
315 126 break;
316 120 case TY_BOOL:
317 120 baseDiType = boolTy;
318 120 break;
319 333 case TY_STRUCT: {
320 // Do cache lookup
321 333 const size_t hashKey = std::hash<QualType>{}(ty);
322
3/4
✓ Branch 0 (61→62) taken 333 times.
✗ Branch 1 (61→205) not taken.
✓ Branch 2 (62→63) taken 309 times.
✓ Branch 3 (62→65) taken 24 times.
333 if (structTypeCache.contains(hashKey))
323
1/2
✓ Branch 0 (63→64) taken 309 times.
✗ Branch 1 (63→205) not taken.
309 return structTypeCache.at(hashKey);
324
325 // Cache miss, generate struct type
326
1/2
✓ Branch 0 (65→66) taken 24 times.
✗ Branch 1 (65→205) not taken.
24 const Struct *spiceStruct = ty.getStruct(node);
327
1/2
✗ Branch 0 (66→67) not taken.
✓ Branch 1 (66→68) taken 24 times.
24 assert(spiceStruct != nullptr);
328
329 // Retrieve information about the struct
330
1/2
✓ Branch 0 (68→69) taken 24 times.
✗ Branch 1 (68→205) not taken.
24 const uint32_t lineNo = spiceStruct->getDeclCodeLoc().line;
331
2/4
✓ Branch 0 (69→70) taken 24 times.
✗ Branch 1 (69→205) not taken.
✓ Branch 2 (70→71) taken 24 times.
✗ Branch 3 (70→205) not taken.
24 llvm::Type *structType = spiceStruct->entry->getQualType().toLLVMType(irGenerator->sourceFile);
332
1/2
✗ Branch 0 (71→72) not taken.
✓ Branch 1 (71→73) taken 24 times.
24 assert(structType != nullptr);
333 24 const llvm::DataLayout &dataLayout = irGenerator->module->getDataLayout();
334
1/2
✓ Branch 0 (74→75) taken 24 times.
✗ Branch 1 (74→205) not taken.
24 const llvm::StructLayout *structLayout = dataLayout.getStructLayout(reinterpret_cast<llvm::StructType *>(structType));
335
1/2
✓ Branch 0 (75→76) taken 24 times.
✗ Branch 1 (75→189) not taken.
24 const uint32_t alignInBits = dataLayout.getABITypeAlign(structType).value();
336
337 // Create struct ty
338
1/2
✓ Branch 0 (77→78) taken 24 times.
✗ Branch 1 (77→205) not taken.
24 const std::string mangledName = NameMangling::mangleStruct(*spiceStruct);
339
2/4
✓ Branch 0 (81→82) taken 24 times.
✗ Branch 1 (81→192) not taken.
✓ Branch 2 (83→84) taken 24 times.
✗ Branch 3 (83→191) not taken.
48 llvm::DICompositeType *structDiType = diBuilder->createStructType(
340
2/4
✓ Branch 0 (82→83) taken 24 times.
✗ Branch 1 (82→191) not taken.
✓ Branch 2 (85→86) taken 24 times.
✗ Branch 3 (85→190) not taken.
48 diFile, spiceStruct->name, diFile, lineNo, structLayout->getSizeInBits(), alignInBits,
341 24 llvm::DINode::FlagTypePassByReference | llvm::DINode::FlagNonTrivial, nullptr, {}, 0, nullptr, mangledName);
342 24 baseDiType = structDiType;
343
344 // Insert into cache
345
1/2
✓ Branch 0 (87→88) taken 24 times.
✗ Branch 1 (87→194) not taken.
24 structTypeCache.insert({hashKey, structDiType});
346
347 // Collect DI types for fields
348 24 std::vector<llvm::Metadata *> fieldTypes;
349
3/4
✓ Branch 0 (114→115) taken 82 times.
✗ Branch 1 (114→201) not taken.
✓ Branch 2 (115→89) taken 58 times.
✓ Branch 3 (115→116) taken 24 times.
82 for (size_t i = 0; i < spiceStruct->scope->getFieldCount(); i++) {
350 // Get field entry
351
1/2
✗ Branch 0 (89→90) not taken.
✓ Branch 1 (89→91) taken 58 times.
58 const SymbolTableEntry *fieldEntry = spiceStruct->scope->lookupField(i);
352
3/6
✓ Branch 0 (94→95) taken 58 times.
✗ Branch 1 (94→98) not taken.
✓ Branch 2 (95→96) taken 58 times.
✗ Branch 3 (95→201) not taken.
✓ Branch 4 (96→97) taken 58 times.
✗ Branch 5 (96→98) not taken.
58 assert(fieldEntry != nullptr && fieldEntry->isField());
353
2/2
✓ Branch 0 (99→100) taken 4 times.
✓ Branch 1 (99→101) taken 54 times.
58 if (fieldEntry->isImplicitField)
354 4 continue;
355
356
1/2
✓ Branch 0 (101→102) taken 54 times.
✗ Branch 1 (101→201) not taken.
54 const QualType &fieldType = fieldEntry->getQualType();
357 54 const uint32_t fieldLineNo = fieldEntry->declNode->codeLoc.line;
358
2/4
✓ Branch 0 (102→103) taken 54 times.
✗ Branch 1 (102→195) not taken.
✓ Branch 2 (103→104) taken 54 times.
✗ Branch 3 (103→195) not taken.
54 const size_t offsetInBits = structLayout->getElementOffsetInBits(i);
359
360
1/2
✓ Branch 0 (104→105) taken 54 times.
✗ Branch 1 (104→201) not taken.
54 llvm::DIType *fieldDiType = getDITypeForQualType(node, fieldType);
361 llvm::DIDerivedType *fieldDiDerivedType =
362
2/4
✓ Branch 0 (107→108) taken 54 times.
✗ Branch 1 (107→197) not taken.
✓ Branch 2 (110→111) taken 54 times.
✗ Branch 3 (110→196) not taken.
54 diBuilder->createMemberType(structDiType, fieldEntry->name, diFile, fieldLineNo, fieldDiType->getSizeInBits(),
363 fieldDiType->getAlignInBits(), offsetInBits, llvm::DINode::FlagZero, fieldDiType);
364
365
1/2
✓ Branch 0 (111→112) taken 54 times.
✗ Branch 1 (111→198) not taken.
54 fieldTypes.push_back(fieldDiDerivedType);
366 }
367
368
2/4
✓ Branch 0 (117→118) taken 24 times.
✗ Branch 1 (117→199) not taken.
✓ Branch 2 (119→120) taken 24 times.
✗ Branch 3 (119→199) not taken.
24 structDiType->replaceElements(llvm::MDTuple::get(irGenerator->context, fieldTypes));
369 24 break;
370 24 }
371 case TY_INTERFACE: {
372 // Do cache lookup
373 const size_t hashKey = std::hash<QualType>{}(ty);
374 if (structTypeCache.contains(hashKey))
375 return structTypeCache.at(hashKey);
376
377 // Cache miss, generate interface type
378 const Interface *spiceInterface = ty.getInterface(node);
379 assert(spiceInterface != nullptr);
380
381 // Retrieve information about the interface
382 const uint32_t lineNo = spiceInterface->getDeclCodeLoc().line;
383 llvm::Type *interfaceType = spiceInterface->entry->getQualType().toLLVMType(irGenerator->sourceFile);
384 assert(interfaceType != nullptr);
385 const llvm::DataLayout dataLayout = irGenerator->module->getDataLayout();
386 const llvm::StructLayout *structLayout = dataLayout.getStructLayout(reinterpret_cast<llvm::StructType *>(interfaceType));
387 const uint32_t alignInBits = dataLayout.getABITypeAlign(interfaceType).value();
388
389 // Create interface ty
390 const std::string mangledName = NameMangling::mangleInterface(*spiceInterface);
391 llvm::DICompositeType *interfaceDiType = diBuilder->createStructType(
392 diFile, spiceInterface->name, diFile, lineNo, structLayout->getSizeInBits(), alignInBits,
393 llvm::DINode::FlagTypePassByReference | llvm::DINode::FlagNonTrivial, nullptr, {}, 0, nullptr, mangledName);
394
395 // Set vtable holder to itself for interfaces
396 interfaceDiType->replaceVTableHolder(interfaceDiType);
397 baseDiType = interfaceDiType;
398
399 // Insert into cache
400 structTypeCache.insert({hashKey, interfaceDiType});
401
402 break;
403 }
404 case TY_FUNCTION: // fall-through
405 case TY_PROCEDURE:
406 baseDiType = fatPtrTy;
407 break;
408 default:
409 throw CompilerError(UNHANDLED_BRANCH, "Debug Info Type fallthrough"); // GCOV_EXCL_LINE
410 }
411
412
2/2
✓ Branch 0 (170→171) taken 80 times.
✓ Branch 1 (170→174) taken 663 times.
743 if (ty.isConst())
413 80 baseDiType = diBuilder->createQualifiedType(llvm::dwarf::DW_TAG_const_type, baseDiType);
414
415 743 return baseDiType;
416 }
417
418 } // namespace spice::compiler
419