GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenVTable.cpp
Date: 2025-11-11 23:26:16
Coverage Exec Excl Total
Lines: 100.0% 97 0 97
Functions: 100.0% 5 0 5
Branches: 55.7% 98 0 176

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "IRGenerator.h"
4
5 #include <llvm/IR/Module.h>
6
7 #include <SourceFile.h>
8 #include <driver/Driver.h>
9 #include <irgenerator/NameMangling.h>
10
11 namespace spice::compiler {
12
13 383 llvm::Constant *IRGenerator::generateTypeInfoName(StructBase *spiceStruct) const {
14 // Resolve mangled type info name and mangled global name
15
1/2
✓ Branch 2 → 3 taken 383 times.
✗ Branch 2 → 34 not taken.
383 const std::string globalName = NameMangling::mangleTypeInfoName(spiceStruct);
16
17 // Generate global string constant
18 llvm::GlobalVariable *global =
19
3/6
✓ Branch 3 → 4 taken 383 times.
✗ Branch 3 → 29 not taken.
✓ Branch 4 → 5 taken 383 times.
✗ Branch 4 → 27 not taken.
✓ Branch 6 → 7 taken 383 times.
✗ Branch 6 → 25 not taken.
383 builder.CreateGlobalString(NameMangling::mangleTypeInfoValue(spiceStruct->name), globalName, 0, module);
20
21 // If the output should be comparable, fix alignment to 4 bytes
22
1/2
✓ Branch 8 → 9 taken 383 times.
✗ Branch 8 → 12 not taken.
383 if (cliOptions.comparableOutput)
23
2/4
✓ Branch 9 → 10 taken 383 times.
✗ Branch 9 → 30 not taken.
✓ Branch 10 → 11 taken 383 times.
✗ Branch 10 → 30 not taken.
383 global->setAlignment(llvm::Align(4));
24
25 // Set global attributes
26 383 global->setConstant(true);
27 383 global->setDSOLocal(true);
28 383 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
29
1/2
✓ Branch 15 → 16 taken 383 times.
✗ Branch 15 → 32 not taken.
383 global->setLinkage(llvm::GlobalValue::ExternalLinkage);
30 // MachO does not support comdat annotations
31
2/2
✓ Branch 17 → 18 taken 378 times.
✓ Branch 17 → 22 taken 5 times.
383 if (doesTargetSupportComDat())
32
2/4
✓ Branch 19 → 20 taken 378 times.
✗ Branch 19 → 31 not taken.
✓ Branch 20 → 21 taken 378 times.
✗ Branch 20 → 31 not taken.
378 global->setComdat(module->getOrInsertComdat(globalName));
33
34 383 return spiceStruct->vTableData.typeInfoName = global;
35 383 }
36
37 383 llvm::Constant *IRGenerator::generateTypeInfo(StructBase *spiceStruct) const {
38 // Generate type info name
39
1/2
✓ Branch 2 → 3 taken 383 times.
✗ Branch 2 → 119 not taken.
383 llvm::Constant *typeInfoName = generateTypeInfoName(spiceStruct);
40
41 // Generate LLVM type for type info
42
1/2
✓ Branch 3 → 4 taken 383 times.
✗ Branch 3 → 119 not taken.
383 const std::string mangledName = NameMangling::mangleTypeInfo(spiceStruct);
43
1/2
✓ Branch 4 → 5 taken 383 times.
✗ Branch 4 → 117 not taken.
383 llvm::PointerType *ptrTy = builder.getPtrTy();
44
45 383 QualTypeList interfaceTypes;
46
4/6
✓ Branch 5 → 6 taken 383 times.
✗ Branch 5 → 115 not taken.
✓ Branch 6 → 7 taken 383 times.
✗ Branch 6 → 115 not taken.
✓ Branch 7 → 8 taken 209 times.
✓ Branch 7 → 9 taken 174 times.
383 if (spiceStruct->entry->getQualType().is(TY_STRUCT)) {
47 209 const auto spiceStructEnsured = reinterpret_cast<Struct *>(spiceStruct);
48
1/2
✓ Branch 8 → 9 taken 209 times.
✗ Branch 8 → 115 not taken.
209 interfaceTypes = spiceStructEnsured->interfaceTypes;
49 }
50
51 // Build type info LLVM type
52
1/2
✓ Branch 11 → 12 taken 383 times.
✗ Branch 11 → 85 not taken.
766 std::vector<llvm::Type *> typeInfoFieldTypes = {ptrTy, ptrTy};
53
2/2
✓ Branch 17 → 14 taken 162 times.
✓ Branch 17 → 18 taken 383 times.
545 for (size_t i = 0; i < interfaceTypes.size(); i++)
54
1/2
✓ Branch 14 → 15 taken 162 times.
✗ Branch 14 → 89 not taken.
162 typeInfoFieldTypes.push_back(ptrTy);
55
1/2
✓ Branch 19 → 20 taken 383 times.
✗ Branch 19 → 90 not taken.
383 spiceStruct->vTableData.typeInfoType = llvm::StructType::get(context, typeInfoFieldTypes);
56
57 // Generate type info values
58
1/2
✓ Branch 20 → 21 taken 383 times.
✗ Branch 20 → 113 not taken.
383 llvm::Constant *typeInfoVTable = llvm::Constant::getNullValue(ptrTy);
59
3/4
✓ Branch 21 → 22 taken 383 times.
✗ Branch 21 → 113 not taken.
✓ Branch 24 → 25 taken 336 times.
✓ Branch 24 → 41 taken 47 times.
766 if (!sourceFile->isRttiRT()) {
60 // Add external global pointer for TypeInfo vtable
61
2/4
✓ Branch 25 → 26 taken 336 times.
✗ Branch 25 → 100 not taken.
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 336 times.
336 assert(sourceFile->isRuntimeModuleAvailable(RuntimeModule::RTTI_RT));
62
2/4
✓ Branch 30 → 31 taken 336 times.
✗ Branch 30 → 93 not taken.
✓ Branch 31 → 32 taken 336 times.
✗ Branch 31 → 91 not taken.
336 const std::string typeInfoMangledName = NameMangling::mangleVTable("TypeInfo");
63
2/4
✓ Branch 34 → 35 taken 336 times.
✗ Branch 34 → 98 not taken.
✓ Branch 36 → 37 taken 336 times.
✗ Branch 36 → 97 not taken.
336 llvm::Constant *typeInfoExtPtr = module->getOrInsertGlobal(typeInfoMangledName, builder.getPtrTy());
64
2/4
✓ Branch 37 → 38 taken 336 times.
✗ Branch 37 → 98 not taken.
✓ Branch 38 → 39 taken 336 times.
✗ Branch 38 → 98 not taken.
336 typeInfoVTable = llvm::ConstantExpr::getInBoundsGetElementPtr(ptrTy, typeInfoExtPtr, builder.getInt64(2));
65 336 }
66 383 std::vector<llvm::Constant *> fieldValues;
67
1/2
✓ Branch 41 → 42 taken 383 times.
✗ Branch 41 → 111 not taken.
383 fieldValues.push_back(typeInfoVTable);
68
1/2
✓ Branch 42 → 43 taken 383 times.
✗ Branch 42 → 111 not taken.
383 fieldValues.push_back(typeInfoName);
69
2/2
✓ Branch 59 → 45 taken 162 times.
✓ Branch 59 → 60 taken 383 times.
545 for (const QualType &interfaceType : interfaceTypes) {
70
1/2
✓ Branch 46 → 47 taken 162 times.
✗ Branch 46 → 104 not taken.
162 const Interface *interface = interfaceType.getInterface(nullptr);
71
2/4
✓ Branch 47 → 48 taken 162 times.
✗ Branch 47 → 50 not taken.
✓ Branch 48 → 49 taken 162 times.
✗ Branch 48 → 50 not taken.
162 assert(interface != nullptr && interface->vTableData.typeInfo != nullptr);
72
1/2
✓ Branch 51 → 52 taken 162 times.
✗ Branch 51 → 104 not taken.
162 const std::string interfaceMangledName = NameMangling::mangleTypeInfo(interface);
73
2/4
✓ Branch 52 → 53 taken 162 times.
✗ Branch 52 → 102 not taken.
✓ Branch 54 → 55 taken 162 times.
✗ Branch 54 → 101 not taken.
162 llvm::Constant *global = module->getOrInsertGlobal(interfaceMangledName, builder.getPtrTy());
74
1/2
✓ Branch 55 → 56 taken 162 times.
✗ Branch 55 → 102 not taken.
162 fieldValues.push_back(global);
75 162 }
76
1/2
✓ Branch 61 → 62 taken 383 times.
✗ Branch 61 → 106 not taken.
383 llvm::Constant *typeInfo = llvm::ConstantStruct::get(spiceStruct->vTableData.typeInfoType, fieldValues);
77
78 // Generate global variable
79
1/2
✓ Branch 63 → 64 taken 383 times.
✗ Branch 63 → 107 not taken.
383 module->getOrInsertGlobal(mangledName, spiceStruct->vTableData.typeInfoType);
80
1/2
✓ Branch 65 → 66 taken 383 times.
✗ Branch 65 → 108 not taken.
383 llvm::GlobalVariable *global = module->getNamedGlobal(mangledName);
81
1/2
✓ Branch 66 → 67 taken 383 times.
✗ Branch 66 → 111 not taken.
383 global->setInitializer(typeInfo);
82
83 // Set global attributes
84 383 global->setConstant(true);
85 383 global->setDSOLocal(true);
86 383 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
87
1/2
✓ Branch 70 → 71 taken 383 times.
✗ Branch 70 → 111 not taken.
383 global->setLinkage(llvm::GlobalValue::ExternalLinkage);
88
2/2
✓ Branch 72 → 73 taken 378 times.
✓ Branch 72 → 77 taken 5 times.
383 if (doesTargetSupportComDat())
89
2/4
✓ Branch 74 → 75 taken 378 times.
✗ Branch 74 → 109 not taken.
✓ Branch 75 → 76 taken 378 times.
✗ Branch 75 → 109 not taken.
378 global->setComdat(module->getOrInsertComdat(mangledName));
90
2/4
✓ Branch 77 → 78 taken 383 times.
✗ Branch 77 → 110 not taken.
✓ Branch 78 → 79 taken 383 times.
✗ Branch 78 → 110 not taken.
383 global->setAlignment(llvm::MaybeAlign(8));
91
92 383 return spiceStruct->vTableData.typeInfo = global;
93 383 }
94
95 383 llvm::Constant *IRGenerator::generateVTable(StructBase *spiceStruct) const {
96 // Retrieve virtual method count
97
1/2
✓ Branch 2 → 3 taken 383 times.
✗ Branch 2 → 40 not taken.
383 const std::vector<Function *> virtualMethods = spiceStruct->scope->getVirtualMethods();
98 383 const size_t virtualMethodCount = virtualMethods.size();
99 383 const size_t arrayElementCount = virtualMethodCount + 2; // +2 for nullptr and TypeInfo
100
101 // Generate type info data structures
102
1/2
✓ Branch 4 → 5 taken 383 times.
✗ Branch 4 → 38 not taken.
383 generateTypeInfo(spiceStruct);
103
104 // Generate VTable type
105
2/4
✓ Branch 5 → 6 taken 383 times.
✗ Branch 5 → 38 not taken.
✓ Branch 6 → 7 taken 383 times.
✗ Branch 6 → 38 not taken.
383 llvm::ArrayType *vtableArrayTy = llvm::ArrayType::get(builder.getPtrTy(), arrayElementCount);
106
1/2
✓ Branch 8 → 9 taken 383 times.
✗ Branch 8 → 30 not taken.
383 spiceStruct->vTableData.vtableType = llvm::StructType::get(context, vtableArrayTy, false);
107
108
1/2
✓ Branch 9 → 10 taken 383 times.
✗ Branch 9 → 38 not taken.
383 const std::string mangledName = NameMangling::mangleVTable(spiceStruct);
109
1/2
✓ Branch 11 → 12 taken 383 times.
✗ Branch 11 → 32 not taken.
383 module->getOrInsertGlobal(mangledName, spiceStruct->vTableData.vtableType);
110
1/2
✓ Branch 13 → 14 taken 383 times.
✗ Branch 13 → 33 not taken.
383 llvm::GlobalVariable *global = module->getNamedGlobal(mangledName);
111
112 // Set global attributes
113 383 global->setConstant(true);
114 383 global->setDSOLocal(true);
115 383 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
116
1/2
✓ Branch 17 → 18 taken 383 times.
✗ Branch 17 → 36 not taken.
383 global->setLinkage(llvm::GlobalValue::ExternalLinkage);
117
2/2
✓ Branch 19 → 20 taken 378 times.
✓ Branch 19 → 24 taken 5 times.
383 if (doesTargetSupportComDat())
118
2/4
✓ Branch 21 → 22 taken 378 times.
✗ Branch 21 → 34 not taken.
✓ Branch 22 → 23 taken 378 times.
✗ Branch 22 → 34 not taken.
378 global->setComdat(module->getOrInsertComdat(mangledName));
119
2/4
✓ Branch 24 → 25 taken 383 times.
✗ Branch 24 → 35 not taken.
✓ Branch 25 → 26 taken 383 times.
✗ Branch 25 → 35 not taken.
383 global->setAlignment(llvm::MaybeAlign(8));
120
121 383 return spiceStruct->vTableData.vtable = global;
122 383 }
123
124 383 void IRGenerator::generateVTableInitializer(const StructBase *spiceStruct) const {
125 // Retrieve virtual method count
126
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 383 times.
383 assert(spiceStruct->scope);
127
1/2
✓ Branch 4 → 5 taken 383 times.
✗ Branch 4 → 58 not taken.
383 const std::vector<Function *> virtualMethods = spiceStruct->scope->getVirtualMethods();
128 383 const size_t virtualMethodCount = virtualMethods.size();
129 383 const size_t arrayElementCount = virtualMethodCount + 2; // +2 for nullptr and TypeInfo
130
131 // Generate VTable type
132
1/2
✓ Branch 6 → 7 taken 383 times.
✗ Branch 6 → 56 not taken.
383 llvm::PointerType *ptrTy = builder.getPtrTy();
133
1/2
✓ Branch 7 → 8 taken 383 times.
✗ Branch 7 → 56 not taken.
383 llvm::ArrayType *vtableArrayTy = llvm::ArrayType::get(ptrTy, arrayElementCount);
134
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 383 times.
383 assert(spiceStruct->vTableData.vtableType);
135
136 // Generate VTable values
137 383 std::vector<llvm::Constant *> arrayValues;
138
2/4
✓ Branch 10 → 11 taken 383 times.
✗ Branch 10 → 43 not taken.
✓ Branch 11 → 12 taken 383 times.
✗ Branch 11 → 43 not taken.
383 arrayValues.push_back(llvm::Constant::getNullValue(ptrTy)); // nullptr as safety guard
139
1/2
✓ Branch 12 → 13 taken 383 times.
✗ Branch 12 → 54 not taken.
383 arrayValues.push_back(spiceStruct->vTableData.typeInfo); // TypeInfo to identify the type for the VTable
140
2/2
✓ Branch 26 → 15 taken 865 times.
✓ Branch 26 → 27 taken 383 times.
1248 for (Function *virtualMethod : virtualMethods) {
141
3/4
✓ Branch 16 → 17 taken 412 times.
✓ Branch 16 → 19 taken 453 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 412 times.
865 assert(spiceStruct->scope->type == ScopeType::INTERFACE || virtualMethod->llvmFunction != nullptr);
142
4/6
✓ Branch 19 → 20 taken 412 times.
✓ Branch 19 → 21 taken 453 times.
✓ Branch 21 → 22 taken 453 times.
✗ Branch 21 → 44 not taken.
✓ Branch 23 → 24 taken 865 times.
✗ Branch 23 → 44 not taken.
865 arrayValues.push_back(virtualMethod->llvmFunction ? virtualMethod->llvmFunction : llvm::Constant::getNullValue(ptrTy));
143 }
144
145 // Generate VTable struct
146 383 std::vector<llvm::Constant *> fieldValues;
147
2/4
✓ Branch 28 → 29 taken 383 times.
✗ Branch 28 → 46 not taken.
✓ Branch 29 → 30 taken 383 times.
✗ Branch 29 → 46 not taken.
383 fieldValues.push_back(llvm::ConstantArray::get(vtableArrayTy, arrayValues));
148
1/2
✓ Branch 31 → 32 taken 383 times.
✗ Branch 31 → 48 not taken.
383 llvm::Constant *initializer = llvm::ConstantStruct::get(spiceStruct->vTableData.vtableType, fieldValues);
149
150
1/2
✓ Branch 32 → 33 taken 383 times.
✗ Branch 32 → 52 not taken.
383 const std::string mangledName = NameMangling::mangleVTable(spiceStruct);
151
1/2
✓ Branch 34 → 35 taken 383 times.
✗ Branch 34 → 49 not taken.
383 llvm::GlobalVariable *global = module->getNamedGlobal(mangledName);
152
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 383 times.
383 assert(global != nullptr);
153
1/2
✓ Branch 37 → 38 taken 383 times.
✗ Branch 37 → 50 not taken.
383 global->setInitializer(initializer);
154 383 }
155
156 1149 bool IRGenerator::doesTargetSupportComDat() const { return cliOptions.targetTriple.getObjectFormat() != llvm::Triple::MachO; }
157
158 } // namespace spice::compiler
159