GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenVTable.cpp
Date: 2025-10-09 06:28:01
Coverage Exec Excl Total
Lines: 100.0% 93 0 93
Functions: 100.0% 4 0 4
Branches: 54.1% 92 0 170

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