GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 78.1% 261 / 1 / 335
Functions: 92.3% 12 / 0 / 13
Branches: 45.8% 288 / 4 / 633

src/irgenerator/DebugInfoGenerator.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "DebugInfoGenerator.h"
4
5 #include <driver/Driver.h>
6 #include <irgenerator/IRGenerator.h>
7 #include <irgenerator/NameMangling.h>
8 #include <model/Function.h>
9 #include <model/Struct.h>
10 #include <model/Union.h>
11 #include <util/CustomHashFunctions.h>
12 #include <util/FileUtil.h>
13
14 #include <llvm/BinaryFormat/Dwarf.h>
15 #include <llvm/IR/Module.h>
16
17 namespace spice::compiler {
18
19
1/2
✓ Branch 3 → 4 taken 5791 times.
✗ Branch 3 → 6 not taken.
5791 DebugInfoGenerator::DebugInfoGenerator(IRGenerator *irGenerator) : irGenerator(irGenerator) {}
20
21 2923 void DebugInfoGenerator::initialize(const std::string &sourceFileName, std::filesystem::path sourceFileDir) {
22 2923 llvm::Module *module = irGenerator->module;
23 2923 llvm::LLVMContext &context = irGenerator->context;
24
25 // Create DIBuilder
26
1/2
✓ Branch 2 → 3 taken 2923 times.
✗ Branch 2 → 144 not taken.
2923 diBuilder = std::make_unique<llvm::DIBuilder>(*module);
27
28 // Create compilation unit
29
3/6
✓ Branch 5 → 6 taken 2923 times.
✗ Branch 5 → 149 not taken.
✓ Branch 6 → 7 taken 2923 times.
✗ Branch 6 → 147 not taken.
✓ Branch 7 → 8 taken 2923 times.
✗ Branch 7 → 145 not taken.
2923 std::filesystem::path absolutePath = absolute(sourceFileDir / sourceFileName);
30 2923 absolutePath.make_preferred();
31 2923 sourceFileDir.make_preferred();
32
3/6
✓ Branch 15 → 16 taken 2923 times.
✗ Branch 15 → 157 not taken.
✓ Branch 17 → 18 taken 2923 times.
✗ Branch 17 → 153 not taken.
✓ Branch 19 → 20 taken 2923 times.
✗ Branch 19 → 151 not taken.
5846 llvm::DIFile *cuDiFile = diBuilder->createFile(absolutePath.string(), sourceFileDir.string());
33 2923 const bool fullDebugInfo = irGenerator->cliOptions.instrumentation.emitsFullDebugInfo();
34
2/2
✓ Branch 24 → 25 taken 116 times.
✓ Branch 24 → 26 taken 2807 times.
2923 const auto emissionKind = fullDebugInfo ? llvm::DICompileUnit::FullDebug : llvm::DICompileUnit::LineTablesOnly;
35 2923 const bool isOptimized = irGenerator->cliOptions.optLevel > OptLevel::O0;
36
2/4
✓ Branch 31 → 32 taken 2923 times.
✗ Branch 31 → 163 not taken.
✓ Branch 34 → 35 taken 2923 times.
✗ Branch 34 → 161 not taken.
5846 compileUnit = diBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus_14, cuDiFile, PRODUCER_STRING, isOptimized, "", 0,
37
1/2
✓ Branch 30 → 31 taken 2923 times.
✗ Branch 30 → 164 not taken.
2923 "", emissionKind, 0, false, false, llvm::DICompileUnit::DebugNameTableKind::None);
38
39
2/4
✓ Branch 35 → 36 taken 2923 times.
✗ Branch 35 → 167 not taken.
✓ Branch 36 → 37 taken 2923 times.
✗ Branch 36 → 167 not taken.
2923 module->addModuleFlag(llvm::Module::Max, "Dwarf Version", 5);
40
2/4
✓ Branch 37 → 38 taken 2923 times.
✗ Branch 37 → 168 not taken.
✓ Branch 38 → 39 taken 2923 times.
✗ Branch 38 → 168 not taken.
2923 module->addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION);
41
42 // Create another DIFile as scope for subprograms
43
2/4
✓ Branch 42 → 43 taken 2923 times.
✗ Branch 42 → 172 not taken.
✓ Branch 45 → 46 taken 2923 times.
✗ Branch 45 → 169 not taken.
5846 diFile = diBuilder->createFile(sourceFileName, sourceFileDir.string());
44
45
1/2
✓ Branch 48 → 49 taken 2923 times.
✗ Branch 48 → 214 not taken.
2923 pointerWidth = irGenerator->module->getDataLayout().getPointerSizeInBits();
46
47 // Line tables do not carry any type information, so there is no need to build the debug types at all
48
2/2
✓ Branch 49 → 50 taken 2807 times.
✓ Branch 49 → 51 taken 116 times.
2923 if (!fullDebugInfo)
49 2807 return;
50
51 // Initialize primitive debug types
52
2/4
✓ Branch 52 → 53 taken 116 times.
✗ Branch 52 → 176 not taken.
✓ Branch 53 → 54 taken 116 times.
✗ Branch 53 → 176 not taken.
116 doubleTy = diBuilder->createBasicType("double", 64, llvm::dwarf::DW_ATE_float);
53
2/4
✓ Branch 55 → 56 taken 116 times.
✗ Branch 55 → 177 not taken.
✓ Branch 56 → 57 taken 116 times.
✗ Branch 56 → 177 not taken.
116 intTy = diBuilder->createBasicType("int", 32, llvm::dwarf::DW_ATE_signed);
54
2/4
✓ Branch 58 → 59 taken 116 times.
✗ Branch 58 → 178 not taken.
✓ Branch 59 → 60 taken 116 times.
✗ Branch 59 → 178 not taken.
116 uIntTy = diBuilder->createBasicType("unsigned int", 32, llvm::dwarf::DW_ATE_unsigned);
55
2/4
✓ Branch 61 → 62 taken 116 times.
✗ Branch 61 → 179 not taken.
✓ Branch 62 → 63 taken 116 times.
✗ Branch 62 → 179 not taken.
116 shortTy = diBuilder->createBasicType("short", 16, llvm::dwarf::DW_ATE_signed);
56
2/4
✓ Branch 64 → 65 taken 116 times.
✗ Branch 64 → 180 not taken.
✓ Branch 65 → 66 taken 116 times.
✗ Branch 65 → 180 not taken.
116 uShortTy = diBuilder->createBasicType("unsigned short", 16, llvm::dwarf::DW_ATE_unsigned);
57
2/4
✓ Branch 67 → 68 taken 116 times.
✗ Branch 67 → 181 not taken.
✓ Branch 68 → 69 taken 116 times.
✗ Branch 68 → 181 not taken.
116 longTy = diBuilder->createBasicType("long", 64, llvm::dwarf::DW_ATE_signed);
58
2/4
✓ Branch 70 → 71 taken 116 times.
✗ Branch 70 → 182 not taken.
✓ Branch 71 → 72 taken 116 times.
✗ Branch 71 → 182 not taken.
116 uLongTy = diBuilder->createBasicType("unsigned long", 64, llvm::dwarf::DW_ATE_unsigned);
59
2/4
✓ Branch 73 → 74 taken 116 times.
✗ Branch 73 → 183 not taken.
✓ Branch 74 → 75 taken 116 times.
✗ Branch 74 → 183 not taken.
116 byteTy = diBuilder->createBasicType("byte", 8, llvm::dwarf::DW_ATE_unsigned);
60
2/4
✓ Branch 76 → 77 taken 116 times.
✗ Branch 76 → 184 not taken.
✓ Branch 77 → 78 taken 116 times.
✗ Branch 77 → 184 not taken.
116 charTy = diBuilder->createBasicType("char", 8, llvm::dwarf::DW_ATE_unsigned_char);
61
1/2
✓ Branch 82 → 83 taken 116 times.
✗ Branch 82 → 185 not taken.
232 stringTy = diBuilder->createPointerType(charTy, pointerWidth);
62
2/4
✓ Branch 84 → 85 taken 116 times.
✗ Branch 84 → 188 not taken.
✓ Branch 85 → 86 taken 116 times.
✗ Branch 85 → 188 not taken.
116 boolTy = diBuilder->createBasicType("bool", 8, llvm::dwarf::DW_ATE_boolean);
63
2/4
✓ Branch 87 → 88 taken 116 times.
✗ Branch 87 → 189 not taken.
✓ Branch 88 → 89 taken 116 times.
✗ Branch 88 → 189 not taken.
116 voidTy = diBuilder->createBasicType("void", 0, llvm::dwarf::DW_ATE_unsigned);
64
65 // Initialize lambda fat ptr type
66
1/2
✓ Branch 89 → 90 taken 116 times.
✗ Branch 89 → 214 not taken.
116 llvm::PointerType *ptrTy = irGenerator->builder.getPtrTy();
67
1/2
✓ Branch 90 → 91 taken 116 times.
✗ Branch 90 → 214 not taken.
116 llvm::IntegerType *int64Ty = irGenerator->builder.getInt64Ty();
68 116 const llvm::DataLayout &dataLayout = module->getDataLayout();
69
1/2
✓ Branch 92 → 93 taken 116 times.
✗ Branch 92 → 214 not taken.
116 const llvm::StructLayout *structLayout = dataLayout.getStructLayout(irGenerator->llvmTypes.lambdaFatPtrType);
70
1/2
✓ Branch 93 → 94 taken 116 times.
✗ Branch 93 → 190 not taken.
116 const uint32_t alignInBits = dataLayout.getABITypeAlign(irGenerator->llvmTypes.lambdaFatPtrType).value();
71
1/2
✓ Branch 95 → 96 taken 116 times.
✗ Branch 95 → 191 not taken.
116 const uint32_t ptrAlignInBits = dataLayout.getABITypeAlign(ptrTy).value();
72
2/4
✓ Branch 97 → 98 taken 116 times.
✗ Branch 97 → 192 not taken.
✓ Branch 98 → 99 taken 116 times.
✗ Branch 98 → 192 not taken.
116 const uint32_t int64Width = dataLayout.getTypeSizeInBits(int64Ty);
73
1/2
✓ Branch 99 → 100 taken 116 times.
✗ Branch 99 → 193 not taken.
116 const uint32_t int64AlignInBits = dataLayout.getABITypeAlign(int64Ty).value();
74
2/4
✓ Branch 101 → 102 taken 116 times.
✗ Branch 101 → 194 not taken.
✓ Branch 102 → 103 taken 116 times.
✗ Branch 102 → 194 not taken.
116 const uint64_t fctPtrOffset = structLayout->getElementOffsetInBits(0);
75
2/4
✓ Branch 103 → 104 taken 116 times.
✗ Branch 103 → 195 not taken.
✓ Branch 104 → 105 taken 116 times.
✗ Branch 104 → 195 not taken.
116 const uint64_t capturesOffset = structLayout->getElementOffsetInBits(1);
76
2/4
✓ Branch 105 → 106 taken 116 times.
✗ Branch 105 → 196 not taken.
✓ Branch 106 → 107 taken 116 times.
✗ Branch 106 → 196 not taken.
116 const uint64_t captureSizeOffset = structLayout->getElementOffsetInBits(2);
77
78
1/2
✓ Branch 111 → 112 taken 116 times.
✗ Branch 111 → 197 not taken.
232 llvm::DIType *voidPtrDIType = diBuilder->createPointerType(voidTy, pointerWidth, ptrAlignInBits);
79
5/10
✓ Branch 116 → 117 taken 116 times.
✗ Branch 116 → 202 not taken.
✓ Branch 117 → 118 taken 116 times.
✗ Branch 117 → 201 not taken.
✓ Branch 118 → 119 taken 116 times.
✗ Branch 118 → 201 not taken.
✓ Branch 119 → 120 taken 116 times.
✗ Branch 119 → 200 not taken.
✓ Branch 120 → 121 taken 116 times.
✗ Branch 120 → 200 not taken.
232 fatPtrTy = diBuilder->createStructType(diFile, "_lambda", diFile, 0, structLayout->getSizeInBits(), alignInBits,
80 llvm::DINode::FlagTypePassByValue | llvm::DINode::FlagNonTrivial, nullptr, {}, 0,
81
1/2
✓ Branch 114 → 115 taken 116 times.
✗ Branch 114 → 203 not taken.
116 nullptr, "_lambda");
82
2/4
✓ Branch 123 → 124 taken 116 times.
✗ Branch 123 → 205 not taken.
✓ Branch 124 → 125 taken 116 times.
✗ Branch 124 → 205 not taken.
116 const auto firstType = diBuilder->createMemberType(fatPtrTy, "fct", diFile, 0, pointerWidth, ptrAlignInBits, fctPtrOffset,
83 llvm::DINode::FlagZero, voidPtrDIType);
84
2/4
✓ Branch 127 → 128 taken 116 times.
✗ Branch 127 → 207 not taken.
✓ Branch 128 → 129 taken 116 times.
✗ Branch 128 → 207 not taken.
116 const auto secondType = diBuilder->createMemberType(fatPtrTy, "captures", diFile, 0, pointerWidth, ptrAlignInBits,
85 capturesOffset, llvm::DINode::FlagZero, voidPtrDIType);
86
2/4
✓ Branch 131 → 132 taken 116 times.
✗ Branch 131 → 209 not taken.
✓ Branch 132 → 133 taken 116 times.
✗ Branch 132 → 209 not taken.
116 const auto thirdType = diBuilder->createMemberType(fatPtrTy, "captureSize", diFile, 0, int64Width, int64AlignInBits,
87 captureSizeOffset, llvm::DINode::FlagZero, uLongTy);
88
2/4
✓ Branch 134 → 135 taken 116 times.
✗ Branch 134 → 211 not taken.
✓ Branch 136 → 137 taken 116 times.
✗ Branch 136 → 211 not taken.
116 fatPtrTy->replaceElements(llvm::MDTuple::get(context, {firstType, secondType, thirdType}));
89
2/2
✓ Branch 139 → 140 taken 116 times.
✓ Branch 139 → 142 taken 2807 times.
2923 }
90
91 88131 void DebugInfoGenerator::generateFunctionDebugInfo(llvm::Function *llvmFunction, const Function *spiceFunc, bool isLambda) {
92
2/2
✓ Branch 4 → 5 taken 43173 times.
✓ Branch 4 → 6 taken 44958 times.
176262 if (!irGenerator->cliOptions.instrumentation.emitsDebugInfo())
93 43179 return;
94
95 44958 const ASTNode *node = spiceFunc->declNode;
96 // Compiler-synthesized functions without a source declaration (e.g. the generated test-suite main) have no code
97 // location to attach debug info to, so skip them
98
2/2
✓ Branch 6 → 7 taken 6 times.
✓ Branch 6 → 8 taken 44952 times.
44958 if (!node)
99 6 return;
100
1/2
✓ Branch 8 → 9 taken 44952 times.
✗ Branch 8 → 134 not taken.
44952 const uint32_t lineNo = spiceFunc->getDeclCodeLoc().line;
101
102 // Prepare flags
103 44952 llvm::DIScope *scope = diFile;
104 44952 llvm::DINode::DIFlags flags = llvm::DINode::FlagPrototyped;
105
8/10
✓ Branch 9 → 10 taken 44389 times.
✓ Branch 9 → 14 taken 563 times.
✓ Branch 10 → 11 taken 44389 times.
✗ Branch 10 → 134 not taken.
✓ Branch 11 → 12 taken 44389 times.
✗ Branch 11 → 134 not taken.
✓ Branch 12 → 13 taken 39639 times.
✓ Branch 12 → 14 taken 4750 times.
✓ Branch 15 → 16 taken 39639 times.
✓ Branch 15 → 17 taken 5313 times.
44952 if (spiceFunc->entry && spiceFunc->entry->getQualType().isPublic())
106
1/2
✓ Branch 16 → 17 taken 39639 times.
✗ Branch 16 → 134 not taken.
39639 flags |= llvm::DINode::FlagPublic;
107
108 // Prepare spFlags
109 44952 llvm::DISubprogram::DISPFlags spFlags = llvm::DISubprogram::SPFlagDefinition;
110
2/2
✓ Branch 17 → 18 taken 93 times.
✓ Branch 17 → 19 taken 44859 times.
44952 if (isLambda)
111
1/2
✓ Branch 18 → 19 taken 93 times.
✗ Branch 18 → 134 not taken.
93 spFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
112
2/2
✓ Branch 19 → 20 taken 3085 times.
✓ Branch 19 → 24 taken 41867 times.
44952 if (spiceFunc->isVirtual) {
113
2/4
✓ Branch 20 → 21 taken 3085 times.
✗ Branch 20 → 134 not taken.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 3085 times.
3085 if (spiceFunc->thisType.is(TY_INTERFACE))
114 spFlags |= llvm::DISubprogram::SPFlagPureVirtual;
115 else
116
1/2
✓ Branch 23 → 24 taken 3085 times.
✗ Branch 23 → 134 not taken.
3085 spFlags |= llvm::DISubprogram::SPFlagVirtual;
117 }
118
119 // Collect arguments. In line info only mode, the subroutine type stays empty, since no type info is emitted at all
120 44952 std::vector<llvm::Metadata *> argTypes;
121
2/2
✓ Branch 26 → 27 taken 1770 times.
✓ Branch 26 → 71 taken 43182 times.
89904 if (irGenerator->cliOptions.instrumentation.emitsFullDebugInfo()) {
122
2/2
✓ Branch 30 → 31 taken 823 times.
✓ Branch 30 → 33 taken 947 times.
1770 if (spiceFunc->isProcedure())
123
1/2
✓ Branch 31 → 32 taken 823 times.
✗ Branch 31 → 106 not taken.
823 argTypes.push_back(voidTy);
124 else
125
2/4
✓ Branch 33 → 34 taken 947 times.
✗ Branch 33 → 107 not taken.
✓ Branch 34 → 35 taken 947 times.
✗ Branch 34 → 107 not taken.
947 argTypes.push_back(getDITypeForQualType(node, spiceFunc->returnType)); // Add result type
126
2/2
✓ Branch 39 → 40 taken 1259 times.
✓ Branch 39 → 43 taken 511 times.
1770 if (spiceFunc->isMethod())
127
2/4
✓ Branch 40 → 41 taken 1259 times.
✗ Branch 40 → 108 not taken.
✓ Branch 41 → 42 taken 1259 times.
✗ Branch 41 → 108 not taken.
1259 argTypes.push_back(getDITypeForQualType(node, spiceFunc->thisType)); // Add this type
128
1/2
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 52 taken 1770 times.
1770 if (isLambda) {
129 llvm::DICompositeType *captureStructType = generateCaptureStructDebugInfo(spiceFunc);
130 scope = captureStructType;
131 llvm::DIType *captureStructPtr = diBuilder->createPointerType(captureStructType, pointerWidth);
132 argTypes.push_back(captureStructPtr); // Add this type
133 }
134
3/4
✓ Branch 52 → 53 taken 1770 times.
✗ Branch 52 → 116 not taken.
✓ Branch 68 → 55 taken 1566 times.
✓ Branch 68 → 69 taken 1770 times.
5106 for (const QualType &argType : spiceFunc->getParamTypes()) // Add arg types
135
2/4
✓ Branch 57 → 58 taken 1566 times.
✗ Branch 57 → 113 not taken.
✓ Branch 58 → 59 taken 1566 times.
✗ Branch 58 → 113 not taken.
3336 argTypes.push_back(getDITypeForQualType(node, argType));
136 }
137
138 // Create function type
139
2/4
✓ Branch 74 → 75 taken 44952 times.
✗ Branch 74 → 117 not taken.
✓ Branch 75 → 76 taken 44952 times.
✗ Branch 75 → 117 not taken.
44952 llvm::DISubroutineType *functionTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray(argTypes));
140
141
1/2
✓ Branch 76 → 77 taken 44952 times.
✗ Branch 76 → 132 not taken.
44952 const std::string mangledName = spiceFunc->getMangledName();
142 llvm::DISubprogram *subprogram;
143
1/2
✓ Branch 77 → 78 taken 44952 times.
✗ Branch 77 → 130 not taken.
44952 const std::string &name = spiceFunc->name;
144
2/2
✓ Branch 80 → 81 taken 29993 times.
✓ Branch 80 → 88 taken 14959 times.
44952 if (spiceFunc->isMethod()) {
145
1/2
✓ Branch 86 → 87 taken 29993 times.
✗ Branch 86 → 118 not taken.
29993 subprogram = diBuilder->createMethod(scope, name, mangledName, diFile, lineNo, functionTy, 0, 0, nullptr, flags, spFlags);
146 } else {
147
1/2
✓ Branch 95 → 96 taken 14959 times.
✗ Branch 95 → 122 not taken.
29918 subprogram = diBuilder->createFunction(scope, name, mangledName, diFile, lineNo, functionTy, lineNo, flags, spFlags);
148 }
149
1/2
✓ Branch 98 → 99 taken 44952 times.
✗ Branch 98 → 128 not taken.
44952 subprogram->replaceRetainedNodes({});
150
151 // Add debug info to LLVM function
152
1/2
✓ Branch 99 → 100 taken 44952 times.
✗ Branch 99 → 130 not taken.
44952 llvmFunction->setSubprogram(subprogram);
153 // Add scope to lexicalBlocks
154
1/2
✓ Branch 100 → 101 taken 44952 times.
✗ Branch 100 → 129 not taken.
44952 lexicalBlocks.push(subprogram);
155 44952 }
156
157 88608 void DebugInfoGenerator::concludeFunctionDebugInfo() {
158
2/2
✓ Branch 4 → 5 taken 43650 times.
✓ Branch 4 → 6 taken 44958 times.
177216 if (!irGenerator->cliOptions.instrumentation.emitsDebugInfo())
159 43650 return;
160 // Functions generateFunctionDebugInfo skipped (no declNode, see there) never pushed a scope to conclude here.
161
2/2
✓ Branch 7 → 8 taken 6 times.
✓ Branch 7 → 9 taken 44952 times.
44958 if (lexicalBlocks.empty())
162 6 return;
163
164 44952 lexicalBlocks.pop();
165 }
166
167 80175 void DebugInfoGenerator::pushLexicalBlock(const ASTNode *node) {
168 // Line tables do not carry scope info, so we attach all locations to the enclosing subprogram instead
169
2/2
✓ Branch 4 → 5 taken 78373 times.
✓ Branch 4 → 6 taken 1802 times.
160350 if (!irGenerator->cliOptions.instrumentation.emitsFullDebugInfo())
170 78373 return;
171
172 1802 const uint32_t line = node->codeLoc.line;
173 1802 const uint32_t col = node->codeLoc.col;
174 1802 llvm::DILexicalBlock *lexicalBlock = diBuilder->createLexicalBlock(lexicalBlocks.top(), diFile, line, col);
175
1/2
✓ Branch 9 → 10 taken 1802 times.
✗ Branch 9 → 12 not taken.
1802 lexicalBlocks.push(lexicalBlock);
176 }
177
178 80175 void DebugInfoGenerator::popLexicalBlock() {
179
2/2
✓ Branch 4 → 5 taken 78373 times.
✓ Branch 4 → 6 taken 1802 times.
160350 if (!irGenerator->cliOptions.instrumentation.emitsFullDebugInfo())
180 78373 return;
181
182
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1802 times.
1802 assert(!lexicalBlocks.empty());
183 1802 lexicalBlocks.pop();
184 }
185
186 llvm::DICompositeType *DebugInfoGenerator::generateCaptureStructDebugInfo(const Function *spiceFunc) {
187 const CaptureMap &captures = spiceFunc->bodyScope->symbolTable.captures;
188 const ASTNode *node = spiceFunc->declNode;
189 const uint32_t lineNo = node->codeLoc.line;
190
191 // Get LLVM type for struct
192 std::vector<llvm::Type *> fieldTypes;
193 std::vector<const SymbolTableEntry *> fieldEntries;
194 QualTypeList fieldSymbolTypes;
195 for (const auto &capture : captures | std::views::values) {
196 QualType captureType = capture.capturedSymbol->getQualType();
197
198 // Capture by reference
199 if (capture.getMode() == BY_REFERENCE)
200 captureType = captureType.toRef(node);
201
202 fieldEntries.push_back(capture.capturedSymbol);
203 fieldSymbolTypes.push_back(captureType);
204 fieldTypes.push_back(captureType.toLLVMType(irGenerator->sourceFile));
205 }
206 llvm::StructType *structType = llvm::StructType::get(irGenerator->context, fieldTypes);
207 const llvm::StructLayout *structLayout = irGenerator->module->getDataLayout().getStructLayout(structType);
208 const size_t alignInBits = irGenerator->module->getDataLayout().getABITypeAlign(structType).value();
209
210 llvm::DIScope *scope = lexicalBlocks.top();
211 llvm::DICompositeType *structDiType =
212 diBuilder->createClassType(scope, "", diFile, lineNo, structLayout->getSizeInBits(), alignInBits, 0,
213 llvm::DINode::FlagTypePassByValue | llvm::DINode::FlagNonTrivial, nullptr, {});
214
215 std::vector<llvm::Metadata *> fieldDITypes;
216 for (size_t i = 0; i < fieldEntries.size(); i++) {
217 llvm::DIType *fieldDiType = getDITypeForQualType(node, fieldSymbolTypes.at(i));
218 const std::string &fieldName = fieldEntries.at(i)->name;
219 const size_t offsetInBits = structLayout->getElementOffsetInBits(i);
220 const size_t fieldSize = fieldDiType->getSizeInBits();
221 const size_t fieldAlign = fieldDiType->getAlignInBits();
222 llvm::DIDerivedType *fieldDiDerivedType = diBuilder->createMemberType(
223 structDiType, fieldName, diFile, lineNo, fieldSize, fieldAlign, offsetInBits, llvm::DINode::FlagZero, fieldDiType);
224 fieldDITypes.push_back(fieldDiDerivedType);
225 }
226 structDiType->replaceElements(llvm::MDTuple::get(irGenerator->context, fieldDITypes));
227
228 return structDiType;
229 }
230
231 6223 void DebugInfoGenerator::generateGlobalVarDebugInfo(llvm::GlobalVariable *global, const SymbolTableEntry *globalEntry) {
232
2/2
✓ Branch 4 → 5 taken 6162 times.
✓ Branch 4 → 6 taken 61 times.
12446 if (!irGenerator->cliOptions.instrumentation.emitsFullDebugInfo())
233 6162 return;
234
235
1/2
✓ Branch 6 → 7 taken 61 times.
✗ Branch 6 → 19 not taken.
61 const uint32_t lineNo = globalEntry->getDeclCodeLoc().line;
236
1/2
✓ Branch 7 → 8 taken 61 times.
✗ Branch 7 → 19 not taken.
61 const llvm::StringRef name = global->getName();
237
2/4
✓ Branch 8 → 9 taken 61 times.
✗ Branch 8 → 19 not taken.
✓ Branch 9 → 10 taken 61 times.
✗ Branch 9 → 19 not taken.
61 llvm::DIType *type = getDITypeForQualType(globalEntry->declNode, globalEntry->getQualType());
238
2/4
✓ Branch 10 → 11 taken 61 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 61 times.
✗ Branch 11 → 19 not taken.
61 const bool isLocal = globalEntry->getQualType().isPublic();
239
240
2/4
✓ Branch 14 → 15 taken 61 times.
✗ Branch 14 → 18 not taken.
✓ Branch 15 → 16 taken 61 times.
✗ Branch 15 → 18 not taken.
61 global->addDebugInfo(diBuilder->createGlobalVariableExpression(compileUnit, name, name, diFile, lineNo, type, isLocal));
241 }
242
243 283 void DebugInfoGenerator::generateGlobalStringDebugInfo(llvm::GlobalVariable *global, const std::string &name, size_t length,
244 const CodeLoc &codeLoc) const {
245 283 const uint32_t lineNo = codeLoc.line;
246 283 const size_t sizeInBits = (length + 1) * 8; // +1 because of null-terminator
247
248
1/2
✓ Branch 4 → 5 taken 283 times.
✗ Branch 4 → 12 not taken.
283 llvm::DIStringType *stringType = diBuilder->createStringType(name, sizeInBits);
249
2/4
✓ Branch 9 → 10 taken 283 times.
✗ Branch 9 → 13 not taken.
✓ Branch 10 → 11 taken 283 times.
✗ Branch 10 → 13 not taken.
283 global->addDebugInfo(diBuilder->createGlobalVariableExpression(compileUnit, name, name, diFile, lineNo, stringType, true));
250 283 }
251
252 220448 void DebugInfoGenerator::generateLocalVarDebugInfo(const std::string &varName, llvm::Value *address, size_t argNumber) {
253
2/2
✓ Branch 4 → 5 taken 216267 times.
✓ Branch 4 → 6 taken 4181 times.
440896 if (!irGenerator->cliOptions.instrumentation.emitsFullDebugInfo())
254 216267 return;
255
256 // Get symbol table entry
257 4181 const SymbolTableEntry *variableEntry = irGenerator->currentScope->lookupStrict(varName);
258
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 4181 times.
4181 assert(variableEntry != nullptr);
259 // Build debug info
260 4181 llvm::DIScope *scope = lexicalBlocks.top();
261 4181 llvm::DIType *diType = getDITypeForQualType(variableEntry->declNode, variableEntry->getQualType());
262 4181 const uint32_t lineNo = variableEntry->declNode->codeLoc.line;
263
264 llvm::DILocalVariable *varInfo;
265
2/2
✓ Branch 14 → 15 taken 2823 times.
✓ Branch 14 → 20 taken 1358 times.
4181 if (argNumber != SIZE_MAX)
266
1/2
✓ Branch 18 → 19 taken 2823 times.
✗ Branch 18 → 37 not taken.
2823 varInfo = diBuilder->createParameterVariable(scope, varName, argNumber, diFile, lineNo, diType);
267 else
268
1/2
✓ Branch 22 → 23 taken 1358 times.
✗ Branch 22 → 39 not taken.
1358 varInfo = diBuilder->createAutoVariable(scope, varName, diFile, lineNo, diType);
269
1/2
✓ Branch 26 → 27 taken 4181 times.
✗ Branch 26 → 40 not taken.
4181 llvm::DIExpression *expr = diBuilder->createExpression();
270
1/2
✓ Branch 27 → 28 taken 4181 times.
✗ Branch 27 → 41 not taken.
4181 const llvm::DILocation *debugLocation = irGenerator->builder.getCurrentDebugLocation();
271
1/2
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 4181 times.
4181 assert(debugLocation != nullptr);
272
1/2
✓ Branch 34 → 35 taken 4181 times.
✗ Branch 34 → 42 not taken.
4181 diBuilder->insertDeclare(address, varInfo, expr, debugLocation, irGenerator->builder.GetInsertPoint());
273 }
274
275 1992570 void DebugInfoGenerator::setSourceLocation(const CodeLoc &codeLoc) {
276
2/2
✓ Branch 4 → 5 taken 981170 times.
✓ Branch 4 → 6 taken 1011400 times.
3985140 if (!irGenerator->cliOptions.instrumentation.emitsDebugInfo())
277 981170 return;
278
279
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1011400 times.
1011400 assert(!lexicalBlocks.empty());
280 1011400 llvm::DIScope *scope = lexicalBlocks.top();
281 1011400 const llvm::DILocation *diCodeLoc = llvm::DILocation::get(scope->getContext(), codeLoc.line, codeLoc.col, scope);
282 1011400 irGenerator->builder.SetCurrentDebugLocation(diCodeLoc);
283 }
284
285 5791 void DebugInfoGenerator::finalize() const {
286
2/2
✓ Branch 4 → 5 taken 2923 times.
✓ Branch 4 → 7 taken 2868 times.
11582 if (irGenerator->cliOptions.instrumentation.emitsDebugInfo())
287 2923 diBuilder->finalize();
288 5791 }
289
290 15329 llvm::DIType *DebugInfoGenerator::getDITypeForQualType(const ASTNode *node, const QualType &ty) { // NOLINT(*-no-recursion)
291 // Pointer type
292
2/2
✓ Branch 3 → 4 taken 2617 times.
✓ Branch 3 → 13 taken 12712 times.
15329 if (ty.isPtr()) {
293
2/4
✓ Branch 4 → 5 taken 2617 times.
✗ Branch 4 → 297 not taken.
✓ Branch 5 → 6 taken 2617 times.
✗ Branch 5 → 297 not taken.
2617 llvm::DIType *pointeeTy = getDITypeForQualType(node, ty.getContained());
294
1/2
✓ Branch 10 → 11 taken 2617 times.
✗ Branch 10 → 298 not taken.
5234 return diBuilder->createPointerType(pointeeTy, pointerWidth);
295 }
296
297 // Reference type
298
2/2
✓ Branch 14 → 15 taken 1710 times.
✓ Branch 14 → 22 taken 11002 times.
12712 if (ty.isRef()) {
299
2/4
✓ Branch 15 → 16 taken 1710 times.
✗ Branch 15 → 301 not taken.
✓ Branch 16 → 17 taken 1710 times.
✗ Branch 16 → 301 not taken.
1710 llvm::DIType *referencedType = getDITypeForQualType(node, ty.getContained());
300
1/2
✓ Branch 19 → 20 taken 1710 times.
✗ Branch 19 → 302 not taken.
3420 return diBuilder->createReferenceType(llvm::dwarf::DW_TAG_reference_type, referencedType, pointerWidth);
301 }
302
303 // Array type
304
2/2
✓ Branch 23 → 24 taken 12 times.
✓ Branch 23 → 38 taken 10990 times.
11002 if (ty.isArray()) {
305
2/4
✓ Branch 24 → 25 taken 12 times.
✗ Branch 24 → 303 not taken.
✓ Branch 25 → 26 taken 12 times.
✗ Branch 25 → 303 not taken.
12 llvm::DIType *itemTy = getDITypeForQualType(node, ty.getContained());
306
1/2
✓ Branch 26 → 27 taken 12 times.
✗ Branch 26 → 309 not taken.
12 const size_t size = ty.getArraySize();
307
1/2
✓ Branch 29 → 30 taken 12 times.
✗ Branch 29 → 304 not taken.
12 const llvm::DINodeArray subscripts = diBuilder->getOrCreateArray({});
308
5/10
✓ Branch 31 → 32 taken 12 times.
✗ Branch 31 → 308 not taken.
✓ Branch 32 → 33 taken 12 times.
✗ Branch 32 → 307 not taken.
✓ Branch 33 → 34 taken 12 times.
✗ Branch 33 → 306 not taken.
✓ Branch 34 → 35 taken 12 times.
✗ Branch 34 → 305 not taken.
✓ Branch 35 → 36 taken 12 times.
✗ Branch 35 → 305 not taken.
12 return diBuilder->createArrayType(size, 0, itemTy, subscripts);
309 }
310
311 // Primitive types
312 llvm::DIType *baseDiType;
313
11/13
✓ Branch 39 → 40 taken 39 times.
✓ Branch 39 → 41 taken 1390 times.
✓ Branch 39 → 46 taken 44 times.
✓ Branch 39 → 51 taken 2137 times.
✓ Branch 39 → 56 taken 417 times.
✓ Branch 39 → 57 taken 532 times.
✓ Branch 39 → 58 taken 702 times.
✓ Branch 39 → 59 taken 604 times.
✓ Branch 39 → 60 taken 5106 times.
✓ Branch 39 → 175 taken 4 times.
✗ Branch 39 → 212 not taken.
✓ Branch 39 → 281 taken 15 times.
✗ Branch 39 → 282 not taken.
10990 switch (ty.getSuperType()) {
314 39 case TY_DOUBLE:
315 39 baseDiType = doubleTy;
316 39 break;
317 1390 case TY_INT:
318
2/2
✓ Branch 42 → 43 taken 1168 times.
✓ Branch 42 → 44 taken 222 times.
1390 baseDiType = ty.isSigned() ? intTy : uIntTy;
319 1390 break;
320 44 case TY_SHORT:
321
1/2
✓ Branch 47 → 48 taken 44 times.
✗ Branch 47 → 49 not taken.
44 baseDiType = ty.isSigned() ? shortTy : uShortTy;
322 44 break;
323 2137 case TY_LONG:
324
2/2
✓ Branch 52 → 53 taken 175 times.
✓ Branch 52 → 54 taken 1962 times.
2137 baseDiType = ty.isSigned() ? longTy : uLongTy;
325 2137 break;
326 417 case TY_BYTE:
327 417 baseDiType = byteTy;
328 417 break;
329 532 case TY_CHAR:
330 532 baseDiType = charTy;
331 532 break;
332 702 case TY_STRING:
333 702 baseDiType = stringTy;
334 702 break;
335 604 case TY_BOOL:
336 604 baseDiType = boolTy;
337 604 break;
338 5106 case TY_STRUCT: {
339 // Do cache lookup
340 5106 const size_t hashKey = std::hash<QualType>{}(ty);
341
1/2
✓ Branch 61 → 62 taken 5106 times.
✗ Branch 61 → 335 not taken.
5106 const auto it = structTypeCache.find(hashKey);
342
2/2
✓ Branch 64 → 65 taken 4331 times.
✓ Branch 64 → 67 taken 775 times.
5106 if (it != structTypeCache.end())
343 4331 return it->second;
344
345 // Cache miss, generate struct type
346
1/2
✓ Branch 67 → 68 taken 775 times.
✗ Branch 67 → 335 not taken.
775 const Struct *spiceStruct = ty.getStruct(node);
347
1/2
✗ Branch 68 → 69 not taken.
✓ Branch 68 → 70 taken 775 times.
775 assert(spiceStruct != nullptr);
348
349 // Retrieve information about the struct
350
1/2
✓ Branch 70 → 71 taken 775 times.
✗ Branch 70 → 335 not taken.
775 const uint32_t lineNo = spiceStruct->getDeclCodeLoc().line;
351
2/4
✓ Branch 71 → 72 taken 775 times.
✗ Branch 71 → 335 not taken.
✓ Branch 72 → 73 taken 775 times.
✗ Branch 72 → 335 not taken.
775 llvm::Type *structType = spiceStruct->entry->getQualType().toLLVMType(irGenerator->sourceFile);
352
1/2
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 775 times.
775 assert(structType != nullptr);
353 775 const llvm::DataLayout &dataLayout = irGenerator->module->getDataLayout();
354
2/4
✓ Branch 76 → 77 taken 775 times.
✗ Branch 76 → 335 not taken.
✓ Branch 77 → 78 taken 775 times.
✗ Branch 77 → 335 not taken.
775 const llvm::StructLayout *structLayout = dataLayout.getStructLayout(llvm::cast<llvm::StructType>(structType));
355
1/2
✓ Branch 78 → 79 taken 775 times.
✗ Branch 78 → 310 not taken.
775 const uint32_t alignInBits = dataLayout.getABITypeAlign(structType).value();
356
357 // Create struct ty. Generic substantiations are named by their signature (e.g. Vector<int>), so that debuggers can
358 // tell the manifestations of a generic struct apart
359
1/2
✓ Branch 80 → 81 taken 775 times.
✗ Branch 80 → 335 not taken.
775 const std::string structName = spiceStruct->getSignature();
360
1/2
✓ Branch 81 → 82 taken 775 times.
✗ Branch 81 → 333 not taken.
775 const std::string mangledName = NameMangling::mangleStruct(*spiceStruct);
361
2/4
✓ Branch 86 → 87 taken 775 times.
✗ Branch 86 → 313 not taken.
✓ Branch 88 → 89 taken 775 times.
✗ Branch 88 → 312 not taken.
2325 llvm::DICompositeType *structDiType = diBuilder->createStructType(
362
2/4
✓ Branch 87 → 88 taken 775 times.
✗ Branch 87 → 312 not taken.
✓ Branch 90 → 91 taken 775 times.
✗ Branch 90 → 311 not taken.
1550 diFile, structName, diFile, lineNo, structLayout->getSizeInBits(), alignInBits,
363 775 llvm::DINode::FlagTypePassByReference | llvm::DINode::FlagNonTrivial, nullptr, {}, 0, nullptr, mangledName);
364
365 // Insert into cache
366
1/2
✓ Branch 91 → 92 taken 775 times.
✗ Branch 91 → 331 not taken.
775 structTypeCache.emplace(hashKey, structDiType);
367
368 // A synthesized vtable pointer takes up the first element of the LLVM struct type, which shifts all fields
369 // by one element
370
3/4
✓ Branch 92 → 93 taken 775 times.
✗ Branch 92 → 331 not taken.
✓ Branch 93 → 94 taken 8 times.
✓ Branch 93 → 95 taken 767 times.
775 const size_t fieldElementOffset = spiceStruct->hasSynthesizedVTablePtr() ? 1 : 0;
371
372 // Collect DI types for fields
373 775 std::vector<llvm::Metadata *> fieldTypes;
374
3/4
✓ Branch 123 → 124 taken 3048 times.
✗ Branch 123 → 329 not taken.
✓ Branch 124 → 97 taken 2273 times.
✓ Branch 124 → 125 taken 775 times.
3048 for (size_t i = 0; i < spiceStruct->scope->getFieldCount(); i++) {
375 // Get field entry
376
1/2
✗ Branch 97 → 98 not taken.
✓ Branch 97 → 100 taken 2273 times.
2273 const SymbolTableEntry *fieldEntry = spiceStruct->scope->lookupField(i);
377
3/6
✓ Branch 103 → 104 taken 2273 times.
✗ Branch 103 → 107 not taken.
✓ Branch 104 → 105 taken 2273 times.
✗ Branch 104 → 329 not taken.
✓ Branch 105 → 106 taken 2273 times.
✗ Branch 105 → 107 not taken.
2273 assert(fieldEntry != nullptr && fieldEntry->isField());
378
2/2
✓ Branch 108 → 109 taken 234 times.
✓ Branch 108 → 110 taken 2039 times.
2273 if (fieldEntry->isImplicitField)
379 234 continue;
380
381
1/2
✓ Branch 110 → 111 taken 2039 times.
✗ Branch 110 → 329 not taken.
2039 const QualType &fieldType = fieldEntry->getQualType();
382 2039 const uint32_t fieldLineNo = fieldEntry->declNode->codeLoc.line;
383
2/4
✓ Branch 111 → 112 taken 2039 times.
✗ Branch 111 → 316 not taken.
✓ Branch 112 → 113 taken 2039 times.
✗ Branch 112 → 316 not taken.
2039 const size_t offsetInBits = structLayout->getElementOffsetInBits(i + fieldElementOffset);
384
385
1/2
✓ Branch 113 → 114 taken 2039 times.
✗ Branch 113 → 329 not taken.
2039 llvm::DIType *fieldDiType = getDITypeForQualType(node, fieldType);
386 llvm::DIDerivedType *fieldDiDerivedType =
387
3/6
✓ Branch 116 → 117 taken 2039 times.
✗ Branch 116 → 318 not taken.
✓ Branch 117 → 118 taken 2039 times.
✗ Branch 117 → 318 not taken.
✓ Branch 119 → 120 taken 2039 times.
✗ Branch 119 → 317 not taken.
2039 diBuilder->createMemberType(structDiType, fieldEntry->name, diFile, fieldLineNo, fieldDiType->getSizeInBits(),
388 fieldDiType->getAlignInBits(), offsetInBits, llvm::DINode::FlagZero, fieldDiType);
389
390
1/2
✓ Branch 120 → 121 taken 2039 times.
✗ Branch 120 → 319 not taken.
2039 fieldTypes.push_back(fieldDiDerivedType);
391 }
392
393 // Collect DI nodes for the template parameters of generic substantiations
394 775 std::vector<llvm::Metadata *> templateParams;
395
6/8
✓ Branch 126 → 127 taken 607 times.
✓ Branch 126 → 130 taken 168 times.
✓ Branch 127 → 128 taken 607 times.
✗ Branch 127 → 327 not taken.
✓ Branch 128 → 129 taken 607 times.
✗ Branch 128 → 130 not taken.
✓ Branch 131 → 132 taken 607 times.
✓ Branch 131 → 157 taken 168 times.
775 if (!spiceStruct->templateTypes.empty() && spiceStruct->isFullySubstantiated()) {
396 // The template parameters of a substantiation carry the concrete types, so the declared parameter names
397 // (e.g. 'T') have to be taken from the generic preset
398
2/4
✓ Branch 132 → 133 taken 607 times.
✗ Branch 132 → 324 not taken.
✓ Branch 133 → 134 taken 607 times.
✗ Branch 133 → 135 not taken.
607 const StructBase *nameSource = spiceStruct->isGenericSubstantiation() ? spiceStruct->genericPreset : spiceStruct;
399
1/2
✓ Branch 136 → 137 taken 607 times.
✗ Branch 136 → 324 not taken.
607 const QualTypeList concreteTemplateTypes = spiceStruct->getConcreteTemplateTypes();
400
1/2
✗ Branch 139 → 140 not taken.
✓ Branch 139 → 141 taken 607 times.
607 assert(nameSource->templateTypes.size() == concreteTemplateTypes.size());
401
1/2
✓ Branch 142 → 143 taken 607 times.
✗ Branch 142 → 322 not taken.
607 templateParams.reserve(concreteTemplateTypes.size());
402
2/2
✓ Branch 154 → 144 taken 937 times.
✓ Branch 154 → 155 taken 607 times.
1544 for (size_t i = 0; i < concreteTemplateTypes.size(); i++) {
403
2/4
✓ Branch 144 → 145 taken 937 times.
✗ Branch 144 → 322 not taken.
✓ Branch 145 → 146 taken 937 times.
✗ Branch 145 → 322 not taken.
937 const std::string &paramName = nameSource->templateTypes.at(i).getSubType();
404
2/4
✓ Branch 146 → 147 taken 937 times.
✗ Branch 146 → 322 not taken.
✓ Branch 147 → 148 taken 937 times.
✗ Branch 147 → 322 not taken.
937 llvm::DIType *paramDiType = getDITypeForQualType(node, concreteTemplateTypes.at(i));
405
2/4
✓ Branch 150 → 151 taken 937 times.
✗ Branch 150 → 320 not taken.
✓ Branch 151 → 152 taken 937 times.
✗ Branch 151 → 320 not taken.
937 templateParams.push_back(diBuilder->createTemplateTypeParameter(compileUnit, paramName, paramDiType, false));
406 }
407 607 }
408
409 // Attach fields and template parameters. This may re-unique the struct type, so refresh all references to it
410 775 const llvm::DINodeArray templateParamArray =
411
3/4
✓ Branch 158 → 159 taken 168 times.
✓ Branch 158 → 160 taken 607 times.
✓ Branch 162 → 163 taken 607 times.
✗ Branch 162 → 325 not taken.
775 templateParams.empty() ? llvm::DINodeArray() : diBuilder->getOrCreateArray(templateParams);
412
2/4
✓ Branch 166 → 167 taken 775 times.
✗ Branch 166 → 326 not taken.
✓ Branch 167 → 168 taken 775 times.
✗ Branch 167 → 326 not taken.
775 diBuilder->replaceArrays(structDiType, diBuilder->getOrCreateArray(fieldTypes), templateParamArray);
413
1/2
✓ Branch 168 → 169 taken 775 times.
✗ Branch 168 → 327 not taken.
775 structTypeCache.at(hashKey) = structDiType;
414 775 baseDiType = structDiType;
415 775 break;
416 775 }
417 4 case TY_INTERFACE: {
418 // Do cache lookup
419 4 const size_t hashKey = std::hash<QualType>{}(ty);
420
1/2
✓ Branch 176 → 177 taken 4 times.
✗ Branch 176 → 346 not taken.
4 const auto it = structTypeCache.find(hashKey);
421
2/2
✓ Branch 179 → 180 taken 2 times.
✓ Branch 179 → 182 taken 2 times.
4 if (it != structTypeCache.end())
422 2 return it->second;
423
424 // Cache miss, generate interface type
425
1/2
✓ Branch 182 → 183 taken 2 times.
✗ Branch 182 → 346 not taken.
2 const Interface *spiceInterface = ty.getInterface(node);
426
1/2
✗ Branch 183 → 184 not taken.
✓ Branch 183 → 185 taken 2 times.
2 assert(spiceInterface != nullptr);
427
428 // Retrieve information about the interface
429
1/2
✓ Branch 185 → 186 taken 2 times.
✗ Branch 185 → 346 not taken.
2 const uint32_t lineNo = spiceInterface->getDeclCodeLoc().line;
430
2/4
✓ Branch 186 → 187 taken 2 times.
✗ Branch 186 → 346 not taken.
✓ Branch 187 → 188 taken 2 times.
✗ Branch 187 → 346 not taken.
2 llvm::Type *interfaceType = spiceInterface->entry->getQualType().toLLVMType(irGenerator->sourceFile);
431
1/2
✗ Branch 188 → 189 not taken.
✓ Branch 188 → 190 taken 2 times.
2 assert(interfaceType != nullptr);
432
1/2
✓ Branch 191 → 192 taken 2 times.
✗ Branch 191 → 346 not taken.
2 const llvm::DataLayout dataLayout = irGenerator->module->getDataLayout();
433
2/4
✓ Branch 192 → 193 taken 2 times.
✗ Branch 192 → 344 not taken.
✓ Branch 193 → 194 taken 2 times.
✗ Branch 193 → 344 not taken.
2 const llvm::StructLayout *structLayout = dataLayout.getStructLayout(llvm::cast<llvm::StructType>(interfaceType));
434
1/2
✓ Branch 194 → 195 taken 2 times.
✗ Branch 194 → 336 not taken.
2 const uint32_t alignInBits = dataLayout.getABITypeAlign(interfaceType).value();
435
436 // Create interface ty
437
1/2
✓ Branch 196 → 197 taken 2 times.
✗ Branch 196 → 344 not taken.
2 const std::string mangledName = NameMangling::mangleInterface(*spiceInterface);
438
2/4
✓ Branch 201 → 202 taken 2 times.
✗ Branch 201 → 339 not taken.
✓ Branch 203 → 204 taken 2 times.
✗ Branch 203 → 338 not taken.
6 llvm::DICompositeType *interfaceDiType = diBuilder->createStructType(
439
2/4
✓ Branch 202 → 203 taken 2 times.
✗ Branch 202 → 338 not taken.
✓ Branch 205 → 206 taken 2 times.
✗ Branch 205 → 337 not taken.
4 diFile, spiceInterface->name, diFile, lineNo, structLayout->getSizeInBits(), alignInBits,
440 2 llvm::DINode::FlagTypePassByReference | llvm::DINode::FlagNonTrivial, nullptr, {}, 0, nullptr, mangledName);
441
442 // Set vtable holder to itself for interfaces
443
1/2
✓ Branch 206 → 207 taken 2 times.
✗ Branch 206 → 342 not taken.
2 interfaceDiType->replaceVTableHolder(interfaceDiType);
444 2 baseDiType = interfaceDiType;
445
446 // Insert into cache
447
1/2
✓ Branch 207 → 208 taken 2 times.
✗ Branch 207 → 342 not taken.
2 structTypeCache.emplace(hashKey, interfaceDiType);
448
449 2 break;
450 2 }
451 case TY_UNION: {
452 // Do cache lookup
453 const size_t hashKey = std::hash<QualType>{}(ty);
454 const auto it = structTypeCache.find(hashKey);
455 if (it != structTypeCache.end())
456 return it->second;
457
458 // Cache miss, generate union type
459 const Union *spiceUnion = ty.getUnion(node);
460 assert(spiceUnion != nullptr);
461
462 // Retrieve information about the union
463 const uint32_t lineNo = spiceUnion->getDeclCodeLoc().line;
464 llvm::Type *unionType = spiceUnion->entry->getQualType().toLLVMType(irGenerator->sourceFile);
465 assert(unionType != nullptr);
466 const auto unionStructType = llvm::cast<llvm::StructType>(unionType);
467 const llvm::DataLayout &dataLayout = irGenerator->module->getDataLayout();
468 const llvm::StructLayout *structLayout = dataLayout.getStructLayout(unionStructType);
469 const uint32_t alignInBits = dataLayout.getABITypeAlign(unionType).value() * 8;
470 // Element 2 is the raw byte-buffer payload that every field aliases at runtime (see Type::toLLVMType's TY_UNION
471 // branch); element 0 is the hidden discriminant tag, which is not surfaced in the debug view.
472 const uint64_t payloadOffsetInBits = structLayout->getElementOffsetInBits(2);
473
474 const std::string unionName = spiceUnion->getSignature();
475 const std::string mangledName = NameMangling::mangleUnion(*spiceUnion);
476 llvm::DICompositeType *unionDiType =
477 diBuilder->createUnionType(diFile, unionName, diFile, lineNo, structLayout->getSizeInBits(), alignInBits,
478 llvm::DINode::FlagZero, {}, 0, mangledName);
479
480 // Insert into cache before computing field types, so that a self-referential field (e.g. a pointer to this same
481 // union) can find this (still-empty) type instead of recursing infinitely
482 structTypeCache.emplace(hashKey, unionDiType);
483
484 // Collect DI types for fields. Every field overlaps the same payload bytes, so they all share the same offset
485 std::vector<llvm::Metadata *> fieldTypes;
486 for (size_t i = 0; i < spiceUnion->scope->getFieldCount(); i++) {
487 const SymbolTableEntry *fieldEntry = spiceUnion->scope->lookupField(i);
488 assert(fieldEntry != nullptr && fieldEntry->isField());
489
490 const QualType &fieldType = fieldEntry->getQualType();
491 const uint32_t fieldLineNo = fieldEntry->declNode->codeLoc.line;
492 llvm::DIType *fieldDiType = getDITypeForQualType(node, fieldType);
493 llvm::DIDerivedType *fieldDiDerivedType = diBuilder->createMemberType(
494 unionDiType, fieldEntry->name, diFile, fieldLineNo, fieldDiType->getSizeInBits(), fieldDiType->getAlignInBits(),
495 payloadOffsetInBits, llvm::DINode::FlagZero, fieldDiType);
496
497 fieldTypes.push_back(fieldDiDerivedType);
498 }
499
500 // Attach fields. This may re-unique the union type, so refresh all references to it
501 diBuilder->replaceArrays(unionDiType, diBuilder->getOrCreateArray(fieldTypes));
502 structTypeCache.at(hashKey) = unionDiType;
503 baseDiType = unionDiType;
504 break;
505 }
506 15 case TY_FUNCTION: // fall-through
507 case TY_PROCEDURE:
508 15 baseDiType = fatPtrTy;
509 15 break;
510 default:
511 throw CompilerError(UNHANDLED_BRANCH, "Debug Info Type fallthrough"); // GCOV_EXCL_LINE
512 }
513
514
2/2
✓ Branch 291 → 292 taken 854 times.
✓ Branch 291 → 295 taken 5803 times.
6657 if (ty.isConst())
515 854 baseDiType = diBuilder->createQualifiedType(llvm::dwarf::DW_TAG_const_type, baseDiType);
516
517 6657 return baseDiType;
518 }
519
520 } // namespace spice::compiler
521