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