GCC Code Coverage Report


Directory: ../
File: src/irgenerator/DebugInfoGenerator.cpp
Date: 2024-11-22 23:10:59
Exec Total Coverage
Lines: 207 275 75.3%
Functions: 12 13 92.3%
Branches: 238 538 44.2%

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