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 |