GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 96 / 0 / 96
Functions: 100.0% 4 / 0 / 4
Branches: 53.7% 101 / 0 / 188

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