GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenImplicit.cpp
Date: 2025-02-05 01:09:36
Exec Total Coverage
Lines: 355 407 87.2%
Functions: 20 21 95.2%
Branches: 483 1020 47.4%

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "IRGenerator.h"
4
5 #include <SourceFile.h>
6 #include <ast/ASTNodes.h>
7 #include <ast/Attributes.h>
8 #include <driver/Driver.h>
9 #include <global/GlobalResourceManager.h>
10 #include <model/Function.h>
11 #include <symboltablebuilder/SymbolTableBuilder.h>
12
13 #include <llvm/IR/Module.h>
14
15 namespace spice::compiler {
16
17 // String placeholders for builtin testing output
18 static const char *const TEST_ALL_START_MSG = "[==========] Running %d test(s) from %d source file(s)\n";
19 static const char *const TEST_ALL_END_MSG = "[==========] Ran %d test(s) from %d source file(s)\n";
20 static const char *const TEST_FILE_START_MSG = "[----------] Running %d test(s) from %s\n";
21 static const char *const TEST_FILE_END_MSG = "[----------] Ran %d test(s) from %s\n\n";
22 static const char *const TEST_CASE_RUN_MSG = "[ RUN ] %s\n";
23 static const char *const TEST_CASE_SUCCESS_MSG = "\033[1m\033[32m[ PASSED ]\033[0m\033[22m %s\n";
24 static const char *const TEST_CASE_FAILED_MSG = "\033[1m\033[31m[ FAILED ]\033[0m\033[22m %s\n";
25 static const char *const TEST_CASE_SKIPPED_MSG = "\033[1m\033[33m[ SKIPPED ]\033[0m\033[22m %s\n";
26
27 12 llvm::Value *IRGenerator::doImplicitCast(llvm::Value *src, QualType dstSTy, QualType srcSTy) {
28
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 12 times.
12 assert(srcSTy != dstSTy); // We only need to cast implicitly, if the types do not match exactly
29
30 // Unpack the pointers until a pointer of another type is met
31 12 size_t loadCounter = 0;
32
1/2
✗ Branch 0 (17→6) not taken.
✓ Branch 1 (17→18) taken 12 times.
12 while (srcSTy.isPtr()) {
33 src = insertLoad(srcSTy.toLLVMType(sourceFile), src);
34 srcSTy = srcSTy.getContained();
35 dstSTy = dstSTy.getContained();
36 loadCounter++;
37 }
38 // GEP or bit-cast
39
3/6
✓ Branch 0 (19→20) taken 12 times.
✗ Branch 1 (19→23) not taken.
✓ Branch 2 (21→22) taken 12 times.
✗ Branch 3 (21→23) not taken.
✓ Branch 4 (24→25) taken 12 times.
✗ Branch 5 (24→36) not taken.
12 if (dstSTy.isArray() && srcSTy.isArray()) { // Special case that is used for passing arrays as pointer to functions
40
2/4
✓ Branch 0 (25→26) taken 12 times.
✗ Branch 1 (25→75) not taken.
✓ Branch 2 (26→27) taken 12 times.
✗ Branch 3 (26→75) not taken.
12 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)};
41
2/4
✓ Branch 0 (31→32) taken 12 times.
✗ Branch 1 (31→68) not taken.
✓ Branch 2 (32→33) taken 12 times.
✗ Branch 3 (32→68) not taken.
12 src = insertInBoundsGEP(srcSTy.toLLVMType(sourceFile), src, indices);
42 } else {
43 src = insertLoad(srcSTy.toLLVMType(sourceFile), src);
44 src = builder.CreateBitCast(src, dstSTy.toLLVMType(sourceFile));
45 }
46 // Pack the pointers together again
47
1/2
✗ Branch 0 (57→48) not taken.
✓ Branch 1 (57→58) taken 12 times.
12 for (; loadCounter > 0; loadCounter--) {
48 llvm::Value *newActualArg = insertAlloca(src->getType());
49 insertStore(src, newActualArg);
50 src = newActualArg;
51 }
52 12 return src;
53 }
54
55 23460 void IRGenerator::generateScopeCleanup(const StmtLstNode *node) const {
56 // Do not clean up if the block is already terminated
57
2/2
✓ Branch 0 (2→3) taken 8567 times.
✓ Branch 1 (2→4) taken 14893 times.
23460 if (blockAlreadyTerminated)
58 8567 return;
59
60 // Call all dtor functions
61 14893 const auto &[dtorFunctionsToCall, heapVarsToFree] = node->resourcesToCleanup.at(manIdx);
62
2/2
✓ Branch 0 (15→7) taken 894 times.
✓ Branch 1 (15→16) taken 14893 times.
15787 for (auto [entry, dtor] : dtorFunctionsToCall)
63
1/2
✓ Branch 0 (11→12) taken 894 times.
✗ Branch 1 (11→45) not taken.
894 generateCtorOrDtorCall(entry, dtor, {});
64
65 // Deallocate all heap variables that go out of scope and are currently owned
66
2/2
✓ Branch 0 (23→18) taken 3 times.
✓ Branch 1 (23→24) taken 14893 times.
14896 for (const SymbolTableEntry *entry : heapVarsToFree)
67
2/4
✓ Branch 0 (19→20) taken 3 times.
✗ Branch 1 (19→49) not taken.
✓ Branch 2 (20→21) taken 3 times.
✗ Branch 3 (20→49) not taken.
3 generateDeallocCall(entry->getAddress());
68
69 // Generate lifetime end markers
70
1/2
✗ Branch 0 (24→25) not taken.
✓ Branch 1 (24→44) taken 14893 times.
14893 if (cliOptions.useLifetimeMarkers) {
71 for (const SymbolTableEntry *var : currentScope->getVarsGoingOutOfScope()) {
72 llvm::Value *address = var->getAddress();
73 if (address == nullptr)
74 continue;
75 const uint64_t sizeInBytes = module->getDataLayout().getTypeAllocSize(var->getQualType().toLLVMType(sourceFile));
76 builder.CreateLifetimeEnd(address, builder.getInt64(sizeInBytes));
77 }
78 }
79 }
80
81 llvm::Value *IRGenerator::generateFctCall(const Function *fct, const std::vector<llvm::Value *> &args) const {
82 // Retrieve metadata for the function
83 const std::string mangledName = fct->getMangledName();
84
85 // Function is not defined in the current module -> declare it
86 if (!module->getFunction(mangledName)) {
87 std::vector<llvm::Type *> paramTypes;
88 for (const llvm::Value *argValue : args)
89 paramTypes.push_back(argValue->getType());
90 llvm::Type *returnType = fct->returnType.toLLVMType(sourceFile);
91 llvm::FunctionType *fctType = llvm::FunctionType::get(returnType, paramTypes, false);
92 module->getOrInsertFunction(mangledName, fctType);
93 }
94
95 // Get callee function
96 llvm::Function *callee = module->getFunction(mangledName);
97 assert(callee != nullptr);
98
99 // Generate function call
100 return builder.CreateCall(callee, args);
101 }
102
103 1606 void IRGenerator::generateProcCall(const Function *proc, std::vector<llvm::Value *> &args) const {
104 // Retrieve metadata for the function
105
1/2
✓ Branch 0 (2→3) taken 1606 times.
✗ Branch 1 (2→45) not taken.
1606 const std::string mangledName = proc->getMangledName();
106
107 // Function is not defined in the current module -> declare it
108
3/4
✓ Branch 0 (4→5) taken 1606 times.
✗ Branch 1 (4→31) not taken.
✓ Branch 2 (5→6) taken 339 times.
✓ Branch 3 (5→21) taken 1267 times.
1606 if (!module->getFunction(mangledName)) {
109 339 std::vector<llvm::Type *> paramTypes;
110
2/2
✓ Branch 0 (13→8) taken 414 times.
✓ Branch 1 (13→14) taken 339 times.
753 for (const llvm::Value *argValue : args)
111
1/2
✓ Branch 0 (10→11) taken 414 times.
✗ Branch 1 (10→32) not taken.
414 paramTypes.push_back(argValue->getType());
112
2/4
✓ Branch 0 (15→16) taken 339 times.
✗ Branch 1 (15→34) not taken.
✓ Branch 2 (16→17) taken 339 times.
✗ Branch 3 (16→34) not taken.
339 llvm::FunctionType *fctType = llvm::FunctionType::get(builder.getVoidTy(), paramTypes, false);
113
1/2
✓ Branch 0 (18→19) taken 339 times.
✗ Branch 1 (18→35) not taken.
339 module->getOrInsertFunction(mangledName, fctType);
114 339 }
115
116 // Get callee function
117
1/2
✓ Branch 0 (22→23) taken 1606 times.
✗ Branch 1 (22→39) not taken.
1606 llvm::Function *callee = module->getFunction(mangledName);
118
1/2
✗ Branch 0 (23→24) not taken.
✓ Branch 1 (23→25) taken 1606 times.
1606 assert(callee != nullptr);
119
120 // Generate function call
121
3/6
✓ Branch 0 (25→26) taken 1606 times.
✗ Branch 1 (25→42) not taken.
✓ Branch 2 (27→28) taken 1606 times.
✗ Branch 3 (27→40) not taken.
✓ Branch 4 (28→29) taken 1606 times.
✗ Branch 5 (28→40) not taken.
1606 builder.CreateCall(callee, args);
122 1606 }
123
124 1472 void IRGenerator::generateCtorOrDtorCall(const SymbolTableEntry *entry, const Function *ctorOrDtor,
125 const std::vector<llvm::Value *> &args) const {
126 // Retrieve address of the struct variable. For fields this is the 'this' variable, otherwise use the normal address
127 llvm::Value *structAddr;
128
2/2
✓ Branch 0 (3→4) taken 446 times.
✓ Branch 1 (3→44) taken 1026 times.
1472 if (entry->isField()) {
129 // Take 'this' var as base pointer
130
1/2
✓ Branch 0 (6→7) taken 446 times.
✗ Branch 1 (6→53) not taken.
1338 const SymbolTableEntry *thisVar = currentScope->lookupStrict(THIS_VARIABLE_NAME);
131
1/2
✗ Branch 0 (12→13) not taken.
✓ Branch 1 (12→14) taken 446 times.
446 assert(thisVar != nullptr);
132
7/14
✓ Branch 0 (14→15) taken 446 times.
✗ Branch 1 (14→57) not taken.
✓ Branch 2 (15→16) taken 446 times.
✗ Branch 3 (15→57) not taken.
✓ Branch 4 (16→17) taken 446 times.
✗ Branch 5 (16→22) not taken.
✓ Branch 6 (17→18) taken 446 times.
✗ Branch 7 (17→57) not taken.
✓ Branch 8 (18→19) taken 446 times.
✗ Branch 9 (18→57) not taken.
✓ Branch 10 (19→20) taken 446 times.
✗ Branch 11 (19→57) not taken.
✓ Branch 12 (20→21) taken 446 times.
✗ Branch 13 (20→22) not taken.
446 assert(thisVar->getQualType().isPtr() && thisVar->getQualType().getContained().is(TY_STRUCT));
133
3/6
✓ Branch 0 (23→24) taken 446 times.
✗ Branch 1 (23→58) not taken.
✓ Branch 2 (24→25) taken 446 times.
✗ Branch 3 (24→58) not taken.
✓ Branch 4 (25→26) taken 446 times.
✗ Branch 5 (25→58) not taken.
446 llvm::Type *thisType = thisVar->getQualType().getContained().toLLVMType(sourceFile);
134
4/8
✓ Branch 0 (28→29) taken 446 times.
✗ Branch 1 (28→61) not taken.
✓ Branch 2 (29→30) taken 446 times.
✗ Branch 3 (29→59) not taken.
✓ Branch 4 (30→31) taken 446 times.
✗ Branch 5 (30→59) not taken.
✓ Branch 6 (31→32) taken 446 times.
✗ Branch 7 (31→59) not taken.
446 llvm::Value *thisPtr = insertLoad(builder.getPtrTy(), thisVar->getAddress());
135 // Add field offset
136
2/4
✓ Branch 0 (34→35) taken 446 times.
✗ Branch 1 (34→72) not taken.
✓ Branch 2 (35→36) taken 446 times.
✗ Branch 3 (35→72) not taken.
446 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(entry->orderIndex)};
137
1/2
✓ Branch 0 (40→41) taken 446 times.
✗ Branch 1 (40→65) not taken.
446 structAddr = insertInBoundsGEP(thisType, thisPtr, indices);
138 } else {
139 1026 structAddr = entry->getAddress();
140 // For optional parameter initializers we need this exception
141
2/2
✓ Branch 0 (45→46) taken 5 times.
✓ Branch 1 (45→47) taken 1021 times.
1026 if (!structAddr)
142 5 return;
143 }
144
1/2
✗ Branch 0 (47→48) not taken.
✓ Branch 1 (47→49) taken 1467 times.
1467 assert(structAddr != nullptr);
145 1467 generateCtorOrDtorCall(structAddr, ctorOrDtor, args);
146 }
147
148 1606 void IRGenerator::generateCtorOrDtorCall(llvm::Value *structAddr, const Function *ctorOrDtor,
149 const std::vector<llvm::Value *> &args) const {
150 // Build parameter list
151
1/2
✓ Branch 0 (4→5) taken 1606 times.
✗ Branch 1 (4→14) not taken.
3212 std::vector argValues = {structAddr};
152
1/2
✓ Branch 0 (10→11) taken 1606 times.
✗ Branch 1 (10→18) not taken.
1606 argValues.insert(argValues.end(), args.begin(), args.end());
153
154 // Generate function call
155
1/2
✓ Branch 0 (11→12) taken 1606 times.
✗ Branch 1 (11→20) not taken.
1606 generateProcCall(ctorOrDtor, argValues);
156 1606 }
157
158 57 void IRGenerator::generateDeallocCall(llvm::Value *variableAddress) const {
159 // Abort if the address is not set. This can happen when leaving the scope of a dtor, which already freed the heap memory
160
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 56 times.
57 if (!variableAddress)
161 1 return;
162
163 // In case of string runtime, call free manually. Otherwise, use the memory_rt implementation of sDealloc()
164
1/2
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→14) taken 56 times.
112 if (sourceFile->isStringRT()) {
165 llvm::Function *freeFct = stdFunctionManager.getFreeFct();
166 builder.CreateCall(freeFct, variableAddress);
167 } else {
168 56 llvm::Function *deallocFct = stdFunctionManager.getDeallocBytePtrRefFct();
169
3/6
✓ Branch 0 (15→16) taken 56 times.
✗ Branch 1 (15→26) not taken.
✓ Branch 2 (17→18) taken 56 times.
✗ Branch 3 (17→24) not taken.
✓ Branch 4 (18→19) taken 56 times.
✗ Branch 5 (18→24) not taken.
56 builder.CreateCall(deallocFct, variableAddress);
170 }
171 }
172
173 2 llvm::Function *IRGenerator::generateImplicitFunction(const std::function<void()> &generateBody, const Function *spiceFunc) {
174 // Only focus on method procedures
175
1/2
✓ Branch 0 (2→3) taken 2 times.
✗ Branch 1 (2→155) not taken.
2 const ASTNode *node = spiceFunc->entry->declNode;
176
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 2 times.
2 assert(spiceFunc->isFunction());
177
178 // Only generate if used
179
1/2
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 2 times.
2 if (!spiceFunc->used)
180 return nullptr;
181
182 // Retrieve return type
183
1/2
✓ Branch 0 (9→10) taken 2 times.
✗ Branch 1 (9→155) not taken.
2 llvm::Type *returnType = spiceFunc->returnType.toLLVMType(sourceFile);
184
185 // Get 'this' entry
186 2 std::vector<llvm::Type *> paramTypes;
187
1/2
✓ Branch 0 (10→11) taken 2 times.
✗ Branch 1 (10→153) not taken.
2 SymbolTableEntry *thisEntry = nullptr;
188
1/2
✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→27) taken 2 times.
2 if (spiceFunc->isMethod()) {
189 thisEntry = spiceFunc->bodyScope->lookupStrict(THIS_VARIABLE_NAME);
190 assert(thisEntry != nullptr);
191 paramTypes.push_back(builder.getPtrTy());
192 }
193
194 // Get parameter types
195
1/2
✗ Branch 0 (36→29) not taken.
✓ Branch 1 (36→37) taken 2 times.
2 for (const auto &[qualType, isOptional] : spiceFunc->paramList) {
196 assert(!isOptional);
197 paramTypes.push_back(qualType.toLLVMType(sourceFile));
198 }
199
200 // Get function linkage
201
2/4
✓ Branch 0 (37→38) taken 2 times.
✗ Branch 1 (37→153) not taken.
✓ Branch 2 (38→39) taken 2 times.
✗ Branch 3 (38→153) not taken.
2 const bool isPublic = spiceFunc->entry->getQualType().isPublic();
202
1/2
✓ Branch 0 (39→40) taken 2 times.
✗ Branch 1 (39→41) not taken.
2 const llvm::GlobalValue::LinkageTypes linkage = isPublic ? llvm::Function::ExternalLinkage : llvm::Function::PrivateLinkage;
203
204 // Create function
205
1/2
✓ Branch 0 (42→43) taken 2 times.
✗ Branch 1 (42→153) not taken.
2 const std::string mangledName = spiceFunc->getMangledName();
206
1/2
✓ Branch 0 (44→45) taken 2 times.
✗ Branch 1 (44→126) not taken.
2 llvm::FunctionType *fctType = llvm::FunctionType::get(returnType, paramTypes, false);
207
2/4
✓ Branch 0 (45→46) taken 2 times.
✗ Branch 1 (45→127) not taken.
✓ Branch 2 (46→47) taken 2 times.
✗ Branch 3 (46→127) not taken.
2 llvm::Function *fct = llvm::Function::Create(fctType, llvm::Function::ExternalLinkage, mangledName, module);
208
1/2
✓ Branch 0 (47→48) taken 2 times.
✗ Branch 1 (47→151) not taken.
2 fct->setLinkage(linkage);
209
1/2
✓ Branch 0 (48→49) taken 2 times.
✗ Branch 1 (48→151) not taken.
2 fct->setDoesNotRecurse();
210
211 // Set attributes to 'this' param
212
1/2
✗ Branch 0 (52→53) not taken.
✓ Branch 1 (52→70) taken 2 times.
2 if (spiceFunc->isMethod()) {
213 fct->addParamAttr(0, llvm::Attribute::NoUndef);
214 fct->addParamAttr(0, llvm::Attribute::NonNull);
215 assert(thisEntry != nullptr);
216 llvm::Type *structType = thisEntry->getQualType().getContained().toLLVMType(sourceFile);
217 assert(structType != nullptr);
218 fct->addDereferenceableParamAttr(0, module->getDataLayout().getTypeStoreSize(structType));
219 fct->addParamAttr(0, llvm::Attribute::getWithAlignment(context, module->getDataLayout().getABITypeAlign(structType)));
220 }
221
222 // Add debug info
223
1/2
✓ Branch 0 (70→71) taken 2 times.
✗ Branch 1 (70→151) not taken.
2 diGenerator.generateFunctionDebugInfo(fct, spiceFunc);
224
1/2
✗ Branch 0 (71→72) not taken.
✓ Branch 1 (71→73) taken 2 times.
2 if (node != nullptr)
225 diGenerator.setSourceLocation(node);
226
227 // Change to body scope
228
2/4
✓ Branch 0 (73→74) taken 2 times.
✗ Branch 1 (73→132) not taken.
✓ Branch 2 (74→75) taken 2 times.
✗ Branch 3 (74→130) not taken.
2 changeToScope(spiceFunc->getSignature(false), ScopeType::FUNC_PROC_BODY);
229
230 // Create entry block
231
2/4
✓ Branch 0 (78→79) taken 2 times.
✗ Branch 1 (78→135) not taken.
✓ Branch 2 (79→80) taken 2 times.
✗ Branch 3 (79→133) not taken.
2 llvm::BasicBlock *bEntry = createBlock();
232
1/2
✓ Branch 0 (82→83) taken 2 times.
✗ Branch 1 (82→151) not taken.
2 switchToBlock(bEntry, fct);
233
234 // Reset alloca insert markers to this block
235 2 allocaInsertBlock = bEntry;
236
1/2
✓ Branch 0 (83→84) taken 2 times.
✗ Branch 1 (83→151) not taken.
2 allocaInsertInst = nullptr;
237
238 // Store first argument to 'this' symbol
239
1/2
✗ Branch 0 (86→87) not taken.
✓ Branch 1 (86→106) taken 2 times.
2 if (spiceFunc->isMethod()) {
240 assert(thisEntry != nullptr);
241 // Allocate space for the parameter
242 llvm::Value *thisAddress = insertAlloca(paramTypes.front(), THIS_VARIABLE_NAME);
243 // Update the symbol table entry
244 thisEntry->updateAddress(thisAddress);
245 // Store the value at the new address
246 insertStore(fct->arg_begin(), thisAddress);
247 // Generate debug info
248 diGenerator.generateLocalVarDebugInfo(THIS_VARIABLE_NAME, thisAddress, 1);
249 }
250
251 // Generate body
252
1/2
✓ Branch 0 (106→107) taken 2 times.
✗ Branch 1 (106→151) not taken.
2 generateBody();
253
254 // Conclude debug info for function
255
1/2
✓ Branch 0 (107→108) taken 2 times.
✗ Branch 1 (107→151) not taken.
2 diGenerator.concludeFunctionDebugInfo();
256
257 // Verify function
258 // Use the code location of the declaration node if available. Otherwise, (e.g. in case of test main) use an artificial code loc
259
2/4
✗ Branch 0 (108→109) not taken.
✓ Branch 1 (108→110) taken 2 times.
✓ Branch 2 (110→111) taken 2 times.
✗ Branch 3 (110→151) not taken.
2 const CodeLoc codeLoc = node != nullptr ? node->codeLoc : CodeLoc(1, 1, sourceFile);
260
1/2
✓ Branch 0 (111→112) taken 2 times.
✗ Branch 1 (111→151) not taken.
2 verifyFunction(fct, codeLoc);
261
262 // Change to parent scope
263
1/2
✓ Branch 0 (112→113) taken 2 times.
✗ Branch 1 (112→151) not taken.
2 changeToParentScope(ScopeType::FUNC_PROC_BODY);
264
265 2 return fct;
266 2 }
267
268 207 llvm::Function *IRGenerator::generateImplicitProcedure(const std::function<void()> &generateBody, const Function *spiceProc) {
269 // Only focus on method procedures
270 207 const ASTNode *node = spiceProc->entry->declNode;
271
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 207 times.
207 assert(node != nullptr);
272
1/2
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 207 times.
207 assert(spiceProc->isProcedure());
273
274 // Only generate if used
275
2/2
✓ Branch 0 (9→10) taken 66 times.
✓ Branch 1 (9→11) taken 141 times.
207 if (!spiceProc->used)
276 66 return nullptr;
277
278 // Get 'this' entry
279 141 std::vector<llvm::Type *> paramTypes;
280
1/2
✓ Branch 0 (11→12) taken 141 times.
✗ Branch 1 (11→152) not taken.
141 SymbolTableEntry *thisEntry = nullptr;
281
1/2
✓ Branch 0 (14→15) taken 141 times.
✗ Branch 1 (14→28) not taken.
141 if (spiceProc->isMethod()) {
282
1/2
✓ Branch 0 (17→18) taken 141 times.
✗ Branch 1 (17→118) not taken.
423 thisEntry = spiceProc->bodyScope->lookupStrict(THIS_VARIABLE_NAME);
283
1/2
✗ Branch 0 (23→24) not taken.
✓ Branch 1 (23→25) taken 141 times.
141 assert(thisEntry != nullptr);
284
2/4
✓ Branch 0 (25→26) taken 141 times.
✗ Branch 1 (25→122) not taken.
✓ Branch 2 (26→27) taken 141 times.
✗ Branch 3 (26→122) not taken.
141 paramTypes.push_back(builder.getPtrTy());
285 }
286
287 // Get parameter types
288
2/2
✓ Branch 0 (37→30) taken 27 times.
✓ Branch 1 (37→38) taken 141 times.
168 for (const auto &[qualType, isOptional] : spiceProc->paramList) {
289
1/2
✗ Branch 0 (31→32) not taken.
✓ Branch 1 (31→33) taken 27 times.
27 assert(!isOptional);
290
2/4
✓ Branch 0 (33→34) taken 27 times.
✗ Branch 1 (33→123) not taken.
✓ Branch 2 (34→35) taken 27 times.
✗ Branch 3 (34→123) not taken.
27 paramTypes.push_back(qualType.toLLVMType(sourceFile));
291 }
292
293 // Get function linkage
294
2/4
✓ Branch 0 (38→39) taken 141 times.
✗ Branch 1 (38→152) not taken.
✓ Branch 2 (39→40) taken 141 times.
✗ Branch 3 (39→152) not taken.
141 const bool isPublic = spiceProc->entry->getQualType().isPublic();
295
1/2
✓ Branch 0 (40→41) taken 141 times.
✗ Branch 1 (40→42) not taken.
141 const llvm::GlobalValue::LinkageTypes linkage = isPublic ? llvm::Function::ExternalLinkage : llvm::Function::PrivateLinkage;
296
297 // Create function
298
1/2
✓ Branch 0 (43→44) taken 141 times.
✗ Branch 1 (43→152) not taken.
141 const std::string mangledName = spiceProc->getMangledName();
299
2/4
✓ Branch 0 (45→46) taken 141 times.
✗ Branch 1 (45→125) not taken.
✓ Branch 2 (46→47) taken 141 times.
✗ Branch 3 (46→125) not taken.
141 llvm::FunctionType *fctType = llvm::FunctionType::get(builder.getVoidTy(), paramTypes, false);
300
2/4
✓ Branch 0 (47→48) taken 141 times.
✗ Branch 1 (47→126) not taken.
✓ Branch 2 (48→49) taken 141 times.
✗ Branch 3 (48→126) not taken.
141 llvm::Function *fct = llvm::Function::Create(fctType, llvm::Function::ExternalLinkage, mangledName, module);
301
1/2
✓ Branch 0 (49→50) taken 141 times.
✗ Branch 1 (49→150) not taken.
141 fct->setLinkage(linkage);
302
1/2
✓ Branch 0 (50→51) taken 141 times.
✗ Branch 1 (50→150) not taken.
141 fct->setDoesNotRecurse();
303
304 // Set attributes to 'this' param
305
1/2
✓ Branch 0 (54→55) taken 141 times.
✗ Branch 1 (54→72) not taken.
141 if (spiceProc->isMethod()) {
306
1/2
✓ Branch 0 (55→56) taken 141 times.
✗ Branch 1 (55→150) not taken.
141 fct->addParamAttr(0, llvm::Attribute::NoUndef);
307
1/2
✓ Branch 0 (56→57) taken 141 times.
✗ Branch 1 (56→150) not taken.
141 fct->addParamAttr(0, llvm::Attribute::NonNull);
308
1/2
✗ Branch 0 (57→58) not taken.
✓ Branch 1 (57→59) taken 141 times.
141 assert(thisEntry != nullptr);
309
3/6
✓ Branch 0 (59→60) taken 141 times.
✗ Branch 1 (59→127) not taken.
✓ Branch 2 (60→61) taken 141 times.
✗ Branch 3 (60→127) not taken.
✓ Branch 4 (61→62) taken 141 times.
✗ Branch 5 (61→127) not taken.
141 llvm::Type *structType = thisEntry->getQualType().getContained().toLLVMType(sourceFile);
310
1/2
✗ Branch 0 (62→63) not taken.
✓ Branch 1 (62→64) taken 141 times.
141 assert(structType != nullptr);
311
3/6
✓ Branch 0 (65→66) taken 141 times.
✗ Branch 1 (65→128) not taken.
✓ Branch 2 (66→67) taken 141 times.
✗ Branch 3 (66→128) not taken.
✓ Branch 4 (67→68) taken 141 times.
✗ Branch 5 (67→128) not taken.
141 fct->addDereferenceableParamAttr(0, module->getDataLayout().getTypeStoreSize(structType));
312
3/6
✓ Branch 0 (69→70) taken 141 times.
✗ Branch 1 (69→150) not taken.
✓ Branch 2 (70→71) taken 141 times.
✗ Branch 3 (70→150) not taken.
✓ Branch 4 (71→72) taken 141 times.
✗ Branch 5 (71→150) not taken.
141 fct->addParamAttr(0, llvm::Attribute::getWithAlignment(context, module->getDataLayout().getABITypeAlign(structType)));
313 }
314
315 // Add debug info
316
1/2
✓ Branch 0 (72→73) taken 141 times.
✗ Branch 1 (72→150) not taken.
141 diGenerator.generateFunctionDebugInfo(fct, spiceProc);
317
1/2
✓ Branch 0 (73→74) taken 141 times.
✗ Branch 1 (73→150) not taken.
141 diGenerator.setSourceLocation(node);
318
319 // Change to body scope
320
2/4
✓ Branch 0 (74→75) taken 141 times.
✗ Branch 1 (74→131) not taken.
✓ Branch 2 (75→76) taken 141 times.
✗ Branch 3 (75→129) not taken.
141 changeToScope(spiceProc->getSignature(false), ScopeType::FUNC_PROC_BODY);
321
322 // Create entry block
323
2/4
✓ Branch 0 (79→80) taken 141 times.
✗ Branch 1 (79→134) not taken.
✓ Branch 2 (80→81) taken 141 times.
✗ Branch 3 (80→132) not taken.
141 llvm::BasicBlock *bEntry = createBlock();
324
1/2
✓ Branch 0 (83→84) taken 141 times.
✗ Branch 1 (83→150) not taken.
141 switchToBlock(bEntry, fct);
325
326 // Reset alloca insert markers to this block
327 141 allocaInsertBlock = bEntry;
328
1/2
✓ Branch 0 (84→85) taken 141 times.
✗ Branch 1 (84→150) not taken.
141 allocaInsertInst = nullptr;
329
330 // Store first argument to 'this' symbol
331
1/2
✓ Branch 0 (87→88) taken 141 times.
✗ Branch 1 (87→107) not taken.
141 if (spiceProc->isMethod()) {
332
1/2
✗ Branch 0 (88→89) not taken.
✓ Branch 1 (88→90) taken 141 times.
141 assert(thisEntry != nullptr);
333 // Allocate space for the parameter
334
2/4
✓ Branch 0 (92→93) taken 141 times.
✗ Branch 1 (92→140) not taken.
✓ Branch 2 (94→95) taken 141 times.
✗ Branch 3 (94→138) not taken.
141 llvm::Value *thisAddress = insertAlloca(paramTypes.front(), THIS_VARIABLE_NAME);
335 // Update the symbol table entry
336
1/2
✓ Branch 0 (97→98) taken 141 times.
✗ Branch 1 (97→150) not taken.
141 thisEntry->updateAddress(thisAddress);
337 // Store the value at the new address
338
2/4
✓ Branch 0 (98→99) taken 141 times.
✗ Branch 1 (98→150) not taken.
✓ Branch 2 (99→100) taken 141 times.
✗ Branch 3 (99→150) not taken.
141 insertStore(fct->arg_begin(), thisAddress);
339 // Generate debug info
340
2/4
✓ Branch 0 (102→103) taken 141 times.
✗ Branch 1 (102→146) not taken.
✓ Branch 2 (103→104) taken 141 times.
✗ Branch 3 (103→144) not taken.
423 diGenerator.generateLocalVarDebugInfo(THIS_VARIABLE_NAME, thisAddress, 1);
341 }
342
343 // Generate body
344
1/2
✓ Branch 0 (107→108) taken 141 times.
✗ Branch 1 (107→150) not taken.
141 generateBody();
345
346 // Create return instruction
347
1/2
✓ Branch 0 (108→109) taken 141 times.
✗ Branch 1 (108→150) not taken.
141 builder.CreateRetVoid();
348
349 // Conclude debug info for function
350
1/2
✓ Branch 0 (109→110) taken 141 times.
✗ Branch 1 (109→150) not taken.
141 diGenerator.concludeFunctionDebugInfo();
351
352 // Verify function
353
1/2
✓ Branch 0 (110→111) taken 141 times.
✗ Branch 1 (110→150) not taken.
141 verifyFunction(fct, node->codeLoc);
354
355 // Change to parent scope
356
1/2
✓ Branch 0 (111→112) taken 141 times.
✗ Branch 1 (111→150) not taken.
141 changeToParentScope(ScopeType::FUNC_PROC_BODY);
357
358 141 return fct;
359 141 }
360
361 1082 void IRGenerator::generateCtorBodyPreamble(Scope *bodyScope) {
362 // Retrieve struct scope
363 1082 Scope *structScope = bodyScope->parent;
364
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 1082 times.
1082 assert(structScope != nullptr);
365
366 // Get struct address
367
1/2
✓ Branch 0 (6→7) taken 1082 times.
✗ Branch 1 (6→118) not taken.
3246 const SymbolTableEntry *thisEntry = bodyScope->lookupStrict(THIS_VARIABLE_NAME);
368
1/2
✗ Branch 0 (12→13) not taken.
✓ Branch 1 (12→14) taken 1082 times.
1082 assert(thisEntry != nullptr);
369
1/2
✓ Branch 0 (14→15) taken 1082 times.
✗ Branch 1 (14→162) not taken.
1082 llvm::Value *thisPtrPtr = thisEntry->getAddress();
370
1/2
✗ Branch 0 (15→16) not taken.
✓ Branch 1 (15→17) taken 1082 times.
1082 assert(thisPtrPtr != nullptr);
371 1082 llvm::Value *thisPtr = nullptr;
372
2/4
✓ Branch 0 (17→18) taken 1082 times.
✗ Branch 1 (17→162) not taken.
✓ Branch 2 (18→19) taken 1082 times.
✗ Branch 3 (18→162) not taken.
1082 const QualType structSymbolType = thisEntry->getQualType().getBase();
373
1/2
✓ Branch 0 (19→20) taken 1082 times.
✗ Branch 1 (19→162) not taken.
1082 llvm::Type *structType = structSymbolType.toLLVMType(sourceFile);
374
375 // Store VTable to first struct field if required
376
1/2
✓ Branch 0 (20→21) taken 1082 times.
✗ Branch 1 (20→162) not taken.
1082 const Struct *spiceStruct = structSymbolType.getStruct(nullptr);
377
1/2
✗ Branch 0 (21→22) not taken.
✓ Branch 1 (21→23) taken 1082 times.
1082 assert(spiceStruct != nullptr);
378
2/2
✓ Branch 0 (23→24) taken 192 times.
✓ Branch 1 (23→45) taken 890 times.
1082 if (spiceStruct->vTableData.vtable != nullptr) {
379
1/2
✗ Branch 0 (24→25) not taken.
✓ Branch 1 (24→26) taken 192 times.
192 assert(spiceStruct->vTableData.vtableType != nullptr);
380 // Store VTable to field address at index 0
381
3/6
✓ Branch 0 (28→29) taken 192 times.
✗ Branch 1 (28→124) not taken.
✓ Branch 2 (29→30) taken 192 times.
✗ Branch 3 (29→122) not taken.
✓ Branch 4 (30→31) taken 192 times.
✗ Branch 5 (30→122) not taken.
192 thisPtr = insertLoad(builder.getPtrTy(), thisPtrPtr);
382
3/6
✓ Branch 0 (33→34) taken 192 times.
✗ Branch 1 (33→135) not taken.
✓ Branch 2 (34→35) taken 192 times.
✗ Branch 3 (34→135) not taken.
✓ Branch 4 (35→36) taken 192 times.
✗ Branch 5 (35→135) not taken.
192 llvm::Value *indices[3] = {builder.getInt64(0), builder.getInt32(0), builder.getInt32(2)};
383
1/2
✓ Branch 0 (40→41) taken 192 times.
✗ Branch 1 (40→128) not taken.
192 llvm::Value *gepResult = insertInBoundsGEP(spiceStruct->vTableData.vtableType, spiceStruct->vTableData.vtable, indices);
384
1/2
✓ Branch 0 (43→44) taken 192 times.
✗ Branch 1 (43→135) not taken.
192 insertStore(gepResult, thisPtr);
385 }
386
387
1/2
✓ Branch 0 (45→46) taken 1082 times.
✗ Branch 1 (45→162) not taken.
1082 const size_t fieldCount = structScope->getFieldCount();
388
2/2
✓ Branch 0 (114→47) taken 2800 times.
✓ Branch 1 (114→115) taken 1082 times.
3882 for (size_t i = 0; i < fieldCount; i++) {
389
1/2
✗ Branch 0 (47→48) not taken.
✓ Branch 1 (47→49) taken 2800 times.
2800 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
390
3/6
✓ Branch 0 (52→53) taken 2800 times.
✗ Branch 1 (52→56) not taken.
✓ Branch 2 (53→54) taken 2800 times.
✗ Branch 3 (53→162) not taken.
✓ Branch 4 (54→55) taken 2800 times.
✗ Branch 5 (54→56) not taken.
2800 assert(fieldSymbol != nullptr && fieldSymbol->isField());
391
2/2
✓ Branch 0 (57→58) taken 154 times.
✓ Branch 1 (57→59) taken 2646 times.
2800 if (fieldSymbol->isImplicitField)
392 154 continue;
393
394 // Call ctor for struct fields
395
1/2
✓ Branch 0 (59→60) taken 2646 times.
✗ Branch 1 (59→162) not taken.
2646 const QualType &fieldType = fieldSymbol->getQualType();
396
1/2
✓ Branch 0 (60→61) taken 2646 times.
✗ Branch 1 (60→62) not taken.
2646 const auto fieldNode = spice_pointer_cast<FieldNode *>(fieldSymbol->declNode);
397
3/4
✓ Branch 0 (67→68) taken 2646 times.
✗ Branch 1 (67→162) not taken.
✓ Branch 2 (68→69) taken 349 times.
✓ Branch 3 (68→84) taken 2297 times.
2646 if (fieldType.is(TY_STRUCT)) {
398 // Lookup ctor function and call if available
399
1/2
✓ Branch 0 (69→70) taken 349 times.
✗ Branch 1 (69→162) not taken.
349 Scope *matchScope = fieldType.getBodyScope();
400
4/6
✓ Branch 0 (73→74) taken 349 times.
✗ Branch 1 (73→138) not taken.
✓ Branch 2 (74→75) taken 349 times.
✗ Branch 3 (74→136) not taken.
✓ Branch 4 (78→79) taken 301 times.
✓ Branch 5 (78→83) taken 48 times.
1047 if (const Function *ctorFunction = FunctionManager::lookup(matchScope, CTOR_FUNCTION_NAME, fieldType, {}, false))
401
1/2
✓ Branch 0 (80→81) taken 301 times.
✗ Branch 1 (80→145) not taken.
301 generateCtorOrDtorCall(fieldSymbol, ctorFunction, {});
402
403 349 continue;
404 349 }
405
406 // Store default field values
407
3/4
✓ Branch 0 (84→85) taken 2057 times.
✓ Branch 1 (84→86) taken 240 times.
✓ Branch 2 (85→86) taken 2057 times.
✗ Branch 3 (85→113) not taken.
2297 if (fieldNode->defaultValue != nullptr || cliOptions.buildMode == DEBUG) {
408 // Retrieve field address
409
2/2
✓ Branch 0 (86→87) taken 820 times.
✓ Branch 1 (86→95) taken 1477 times.
2297 if (!thisPtr)
410
3/6
✓ Branch 0 (89→90) taken 820 times.
✗ Branch 1 (89→150) not taken.
✓ Branch 2 (90→91) taken 820 times.
✗ Branch 3 (90→148) not taken.
✓ Branch 4 (91→92) taken 820 times.
✗ Branch 5 (91→148) not taken.
1640 thisPtr = insertLoad(builder.getPtrTy(), thisPtrPtr);
411
2/4
✓ Branch 0 (95→96) taken 2297 times.
✗ Branch 1 (95→161) not taken.
✓ Branch 2 (96→97) taken 2297 times.
✗ Branch 3 (96→161) not taken.
2297 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(i)};
412
1/2
✓ Branch 0 (101→102) taken 2297 times.
✗ Branch 1 (101→154) not taken.
2297 llvm::Value *fieldAddress = insertInBoundsGEP(structType, thisPtr, indices);
413 // Retrieve default value
414 llvm::Value *value;
415
2/2
✓ Branch 0 (104→105) taken 240 times.
✓ Branch 1 (104→107) taken 2057 times.
2297 if (fieldNode->defaultValue != nullptr) {
416 // To resolve the default value, we need to temporarily change to the manifestation of the current struct instantiation
417 240 const size_t oldManIdx = manIdx; // Save manifestation index
418 240 manIdx = spiceStruct->manifestationIndex;
419
1/2
✓ Branch 0 (105→106) taken 240 times.
✗ Branch 1 (105→161) not taken.
240 value = resolveValue(fieldNode->defaultValue);
420 240 manIdx = oldManIdx; // Restore manifestation index
421 } else {
422
1/2
✗ Branch 0 (107→108) not taken.
✓ Branch 1 (107→109) taken 2057 times.
2057 assert(cliOptions.buildMode == DEBUG);
423
1/2
✓ Branch 0 (109→110) taken 2057 times.
✗ Branch 1 (109→161) not taken.
2057 value = getDefaultValueForSymbolType(fieldType);
424 }
425 // Store default value
426
1/2
✓ Branch 0 (111→112) taken 2297 times.
✗ Branch 1 (111→161) not taken.
2297 insertStore(value, fieldAddress);
427 }
428 }
429 1082 }
430
431 29 void IRGenerator::generateDefaultCtor(const Function *ctorFunction) {
432
3/6
✓ Branch 0 (2→3) taken 29 times.
✗ Branch 1 (2→6) not taken.
✓ Branch 2 (3→4) taken 29 times.
✗ Branch 3 (3→13) not taken.
✓ Branch 4 (4→5) taken 29 times.
✗ Branch 5 (4→6) not taken.
29 assert(ctorFunction->implicitDefault && ctorFunction->name == CTOR_FUNCTION_NAME);
433 54 const std::function<void()> generateBody = [&] { generateCtorBodyPreamble(ctorFunction->bodyScope); };
434
1/2
✓ Branch 0 (8→9) taken 29 times.
✗ Branch 1 (8→11) not taken.
29 generateImplicitProcedure(generateBody, ctorFunction);
435 29 }
436
437 27 void IRGenerator::generateCopyCtorBodyPreamble(const Function *copyCtorFunction) {
438 // Retrieve struct scope
439 27 Scope *structScope = copyCtorFunction->bodyScope->parent;
440
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 27 times.
27 assert(structScope != nullptr);
441
442 // Get struct address
443
1/2
✓ Branch 0 (6→7) taken 27 times.
✗ Branch 1 (6→149) not taken.
81 const SymbolTableEntry *thisEntry = copyCtorFunction->bodyScope->lookupStrict(THIS_VARIABLE_NAME);
444
1/2
✗ Branch 0 (12→13) not taken.
✓ Branch 1 (12→14) taken 27 times.
27 assert(thisEntry != nullptr);
445 27 llvm::Value *thisPtrPtr = thisEntry->getAddress();
446
1/2
✗ Branch 0 (15→16) not taken.
✓ Branch 1 (15→17) taken 27 times.
27 assert(thisPtrPtr != nullptr);
447 27 llvm::Value *thisPtr = nullptr;
448
3/6
✓ Branch 0 (17→18) taken 27 times.
✗ Branch 1 (17→153) not taken.
✓ Branch 2 (18→19) taken 27 times.
✗ Branch 3 (18→153) not taken.
✓ Branch 4 (19→20) taken 27 times.
✗ Branch 5 (19→153) not taken.
27 llvm::Type *structType = thisEntry->getQualType().getBase().toLLVMType(sourceFile);
449
450 // Retrieve the value of the original struct, which is the only function parameter
451 27 llvm::Value *originalThisPtr = builder.GetInsertBlock()->getParent()->getArg(1);
452
453 27 const size_t fieldCount = structScope->getFieldCount();
454
2/2
✓ Branch 0 (145→25) taken 118 times.
✓ Branch 1 (145→146) taken 27 times.
145 for (size_t i = 0; i < fieldCount; i++) {
455
1/2
✗ Branch 0 (25→26) not taken.
✓ Branch 1 (25→27) taken 118 times.
118 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
456
3/6
✓ Branch 0 (30→31) taken 118 times.
✗ Branch 1 (30→34) not taken.
✓ Branch 2 (31→32) taken 118 times.
✗ Branch 3 (31→221) not taken.
✓ Branch 4 (32→33) taken 118 times.
✗ Branch 5 (32→34) not taken.
118 assert(fieldSymbol != nullptr && fieldSymbol->isField());
457
2/2
✓ Branch 0 (35→36) taken 3 times.
✓ Branch 1 (35→37) taken 115 times.
118 if (fieldSymbol->isImplicitField)
458 70 continue;
459
460 // Retrieve the address of the original field (copy source)
461
2/4
✓ Branch 0 (37→38) taken 115 times.
✗ Branch 1 (37→221) not taken.
✓ Branch 2 (38→39) taken 115 times.
✗ Branch 3 (38→221) not taken.
115 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(i)};
462
1/2
✓ Branch 0 (43→44) taken 115 times.
✗ Branch 1 (43→154) not taken.
115 llvm::Value *originalFieldAddress = insertInBoundsGEP(structType, originalThisPtr, indices);
463
464
1/2
✓ Branch 0 (46→47) taken 115 times.
✗ Branch 1 (46→221) not taken.
115 const QualType &fieldType = fieldSymbol->getQualType();
465
466 // Call copy ctor for struct fields
467
8/10
✓ Branch 0 (47→48) taken 115 times.
✗ Branch 1 (47→221) not taken.
✓ Branch 2 (48→49) taken 66 times.
✓ Branch 3 (48→52) taken 49 times.
✓ Branch 4 (49→50) taken 66 times.
✗ Branch 5 (49→221) not taken.
✓ Branch 6 (50→51) taken 63 times.
✓ Branch 7 (50→52) taken 3 times.
✓ Branch 8 (53→54) taken 63 times.
✓ Branch 9 (53→78) taken 52 times.
115 if (fieldType.is(TY_STRUCT) && !fieldType.isTriviallyCopyable(nullptr)) {
468 // Lookup copy ctor function and call if available
469
1/2
✓ Branch 0 (54→55) taken 63 times.
✗ Branch 1 (54→182) not taken.
63 Scope *matchScope = fieldType.getBodyScope();
470
2/4
✓ Branch 0 (55→56) taken 63 times.
✗ Branch 1 (55→165) not taken.
✓ Branch 2 (59→60) taken 63 times.
✗ Branch 3 (59→161) not taken.
189 const ArgList args = {{fieldType.toConstRef(nullptr), false /* we have the field as storage */}};
471
2/4
✓ Branch 0 (63→64) taken 63 times.
✗ Branch 1 (63→169) not taken.
✓ Branch 2 (64→65) taken 63 times.
✗ Branch 3 (64→167) not taken.
63 const Function *copyCtor = FunctionManager::lookup(matchScope, CTOR_FUNCTION_NAME, fieldType, args, false);
472
1/2
✗ Branch 0 (67→68) not taken.
✓ Branch 1 (67→69) taken 63 times.
63 assert(copyCtor != nullptr);
473
2/4
✓ Branch 0 (71→72) taken 63 times.
✗ Branch 1 (71→175) not taken.
✓ Branch 2 (72→73) taken 63 times.
✗ Branch 3 (72→173) not taken.
126 generateCtorOrDtorCall(fieldSymbol, copyCtor, {originalFieldAddress});
474 63 continue;
475 63 }
476
477 // Retrieve the address of the new field (copy dest)
478
2/2
✓ Branch 0 (78→79) taken 18 times.
✓ Branch 1 (78→87) taken 34 times.
52 if (!thisPtr)
479
3/6
✓ Branch 0 (81→82) taken 18 times.
✗ Branch 1 (81→185) not taken.
✓ Branch 2 (82→83) taken 18 times.
✗ Branch 3 (82→183) not taken.
✓ Branch 4 (83→84) taken 18 times.
✗ Branch 5 (83→183) not taken.
36 thisPtr = insertLoad(builder.getPtrTy(), thisPtrPtr);
480
1/2
✓ Branch 0 (91→92) taken 52 times.
✗ Branch 1 (91→189) not taken.
52 llvm::Value *fieldAddress = insertInBoundsGEP(structType, thisPtr, indices);
481
482 // For owning heap fields, copy the underlying heap storage
483
3/4
✓ Branch 0 (94→95) taken 52 times.
✗ Branch 1 (94→221) not taken.
✓ Branch 2 (95→96) taken 4 times.
✓ Branch 3 (95→140) taken 48 times.
52 if (fieldType.isHeap()) {
484
2/4
✓ Branch 0 (96→97) taken 4 times.
✗ Branch 1 (96→221) not taken.
✗ Branch 2 (97→98) not taken.
✓ Branch 3 (97→99) taken 4 times.
4 assert(fieldType.isPtr());
485
2/4
✓ Branch 0 (99→100) taken 4 times.
✗ Branch 1 (99→196) not taken.
✓ Branch 2 (100→101) taken 4 times.
✗ Branch 3 (100→196) not taken.
4 llvm::Type *pointeeType = fieldType.getContained().toLLVMType(sourceFile);
486
487 // Retrieve original heap address
488
3/6
✓ Branch 0 (103→104) taken 4 times.
✗ Branch 1 (103→199) not taken.
✓ Branch 2 (104→105) taken 4 times.
✗ Branch 3 (104→197) not taken.
✓ Branch 4 (105→106) taken 4 times.
✗ Branch 5 (105→197) not taken.
8 llvm::Value *originalHeapAddress = insertLoad(builder.getPtrTy(), originalFieldAddress);
489
490 // Insert check for nullptr
491
2/4
✓ Branch 0 (110→111) taken 4 times.
✗ Branch 1 (110→205) not taken.
✓ Branch 2 (111→112) taken 4 times.
✗ Branch 3 (111→203) not taken.
8 llvm::BasicBlock *bThen = createBlock("nullptrcheck.then");
492
2/4
✓ Branch 0 (116→117) taken 4 times.
✗ Branch 1 (116→211) not taken.
✓ Branch 2 (117→118) taken 4 times.
✗ Branch 3 (117→209) not taken.
4 llvm::BasicBlock *bExit = createBlock("nullptrcheck.exit");
493
4/8
✓ Branch 0 (120→121) taken 4 times.
✗ Branch 1 (120→215) not taken.
✓ Branch 2 (121→122) taken 4 times.
✗ Branch 3 (121→215) not taken.
✓ Branch 4 (122→123) taken 4 times.
✗ Branch 5 (122→215) not taken.
✓ Branch 6 (123→124) taken 4 times.
✗ Branch 7 (123→215) not taken.
4 llvm::Value *condValue = builder.CreateICmpNE(originalHeapAddress, llvm::Constant::getNullValue(builder.getPtrTy()));
494
1/2
✓ Branch 0 (124→125) taken 4 times.
✗ Branch 1 (124→221) not taken.
4 insertCondJump(condValue, bThen, bExit);
495
496 // Fill then block
497
1/2
✓ Branch 0 (125→126) taken 4 times.
✗ Branch 1 (125→221) not taken.
4 switchToBlock(bThen);
498
499 // Allocate new space on the heap
500
1/2
✓ Branch 0 (126→127) taken 4 times.
✗ Branch 1 (126→221) not taken.
4 llvm::Function *unsafeAllocFct = stdFunctionManager.getAllocUnsafeLongFct();
501
2/4
✓ Branch 0 (128→129) taken 4 times.
✗ Branch 1 (128→216) not taken.
✓ Branch 2 (129→130) taken 4 times.
✗ Branch 3 (129→216) not taken.
4 const size_t typeSizeInBytes = module->getDataLayout().getTypeSizeInBits(pointeeType) / 8;
502
1/2
✓ Branch 0 (130→131) taken 4 times.
✗ Branch 1 (130→221) not taken.
4 llvm::ConstantInt *typeSize = builder.getInt64(typeSizeInBytes);
503
3/6
✓ Branch 0 (131→132) taken 4 times.
✗ Branch 1 (131→220) not taken.
✓ Branch 2 (133→134) taken 4 times.
✗ Branch 3 (133→217) not taken.
✓ Branch 4 (134→135) taken 4 times.
✗ Branch 5 (134→217) not taken.
4 llvm::Value *newHeapAddress = builder.CreateCall(unsafeAllocFct, {typeSize});
504
1/2
✓ Branch 0 (135→136) taken 4 times.
✗ Branch 1 (135→221) not taken.
4 insertStore(newHeapAddress, fieldAddress);
505
506 // Copy data from the old heap storage to the new one
507
1/2
✓ Branch 0 (136→137) taken 4 times.
✗ Branch 1 (136→221) not taken.
4 generateShallowCopy(originalHeapAddress, pointeeType, newHeapAddress, false);
508
1/2
✓ Branch 0 (137→138) taken 4 times.
✗ Branch 1 (137→221) not taken.
4 insertJump(bExit);
509
510 // Switch to exit block
511
1/2
✓ Branch 0 (138→139) taken 4 times.
✗ Branch 1 (138→221) not taken.
4 switchToBlock(bExit);
512
513 4 continue;
514 4 }
515
516 // Shallow copy
517
1/2
✓ Branch 0 (140→141) taken 48 times.
✗ Branch 1 (140→221) not taken.
48 llvm::Type *type = fieldType.toLLVMType(sourceFile);
518
1/2
✓ Branch 0 (141→142) taken 48 times.
✗ Branch 1 (141→221) not taken.
48 generateShallowCopy(originalFieldAddress, type, fieldAddress, false);
519 }
520 27 }
521
522 87 void IRGenerator::generateDefaultCopyCtor(const Function *copyCtorFunction) {
523
3/6
✓ Branch 0 (2→3) taken 87 times.
✗ Branch 1 (2→6) not taken.
✓ Branch 2 (3→4) taken 87 times.
✗ Branch 3 (3→13) not taken.
✓ Branch 4 (4→5) taken 87 times.
✗ Branch 5 (4→6) not taken.
87 assert(copyCtorFunction->implicitDefault && copyCtorFunction->name == CTOR_FUNCTION_NAME);
524 114 const std::function<void()> generateBody = [&] { generateCopyCtorBodyPreamble(copyCtorFunction); };
525
1/2
✓ Branch 0 (8→9) taken 87 times.
✗ Branch 1 (8→11) not taken.
87 generateImplicitProcedure(generateBody, copyCtorFunction);
526 87 }
527
528 89 void IRGenerator::generateDtorBodyPreamble(const Function *dtorFunction) const {
529 // Retrieve struct scope
530 89 Scope *structScope = dtorFunction->bodyScope->parent;
531
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 89 times.
89 assert(structScope != nullptr);
532
533 // Get struct address
534
1/2
✓ Branch 0 (6→7) taken 89 times.
✗ Branch 1 (6→79) not taken.
267 const SymbolTableEntry *thisEntry = dtorFunction->bodyScope->lookupStrict(THIS_VARIABLE_NAME);
535
1/2
✗ Branch 0 (12→13) not taken.
✓ Branch 1 (12→14) taken 89 times.
89 assert(thisEntry != nullptr);
536 89 llvm::Value *thisPtrPtr = thisEntry->getAddress();
537
1/2
✗ Branch 0 (15→16) not taken.
✓ Branch 1 (15→17) taken 89 times.
89 assert(thisPtrPtr != nullptr);
538 89 llvm::Value *thisPtr = nullptr;
539
3/6
✓ Branch 0 (17→18) taken 89 times.
✗ Branch 1 (17→83) not taken.
✓ Branch 2 (18→19) taken 89 times.
✗ Branch 3 (18→83) not taken.
✓ Branch 4 (19→20) taken 89 times.
✗ Branch 5 (19→83) not taken.
89 llvm::Type *structType = thisEntry->getQualType().getBase().toLLVMType(sourceFile);
540
541 89 const size_t fieldCount = structScope->getFieldCount();
542
2/2
✓ Branch 0 (75→22) taken 339 times.
✓ Branch 1 (75→76) taken 89 times.
428 for (size_t i = 0; i < fieldCount; i++) {
543
1/2
✗ Branch 0 (22→23) not taken.
✓ Branch 1 (22→24) taken 339 times.
339 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
544
2/4
✓ Branch 0 (27→28) taken 339 times.
✗ Branch 1 (27→31) not taken.
✓ Branch 2 (29→30) taken 339 times.
✗ Branch 3 (29→31) not taken.
339 assert(fieldSymbol != nullptr && fieldSymbol->isField());
545
2/2
✓ Branch 0 (32→33) taken 45 times.
✓ Branch 1 (32→34) taken 294 times.
339 if (fieldSymbol->isImplicitField)
546 45 continue;
547
548 // Call dtor for struct fields
549 294 const QualType &fieldType = fieldSymbol->getQualType();
550
2/2
✓ Branch 0 (36→37) taken 88 times.
✓ Branch 1 (36→52) taken 206 times.
294 if (fieldType.is(TY_STRUCT)) {
551 // Lookup dtor function and generate call if found
552
5/8
✓ Branch 0 (40→41) taken 88 times.
✗ Branch 1 (40→86) not taken.
✓ Branch 2 (41→42) taken 88 times.
✗ Branch 3 (41→84) not taken.
✓ Branch 4 (42→43) taken 88 times.
✗ Branch 5 (42→84) not taken.
✓ Branch 6 (46→47) taken 82 times.
✓ Branch 7 (46→51) taken 6 times.
264 if (const Function *dtorFct = FunctionManager::lookup(fieldType.getBodyScope(), DTOR_FUNCTION_NAME, fieldType, {}, false))
553
1/2
✓ Branch 0 (48→49) taken 82 times.
✗ Branch 1 (48→93) not taken.
82 generateCtorOrDtorCall(fieldSymbol, dtorFct, {});
554 88 continue;
555 88 }
556
557 // Deallocate fields, that are stored on the heap
558
2/2
✓ Branch 0 (53→54) taken 54 times.
✓ Branch 1 (53→74) taken 152 times.
206 if (fieldType.isHeap()) {
559 // Retrieve field address
560
2/2
✓ Branch 0 (54→55) taken 50 times.
✓ Branch 1 (54→63) taken 4 times.
54 if (!thisPtr)
561
3/6
✓ Branch 0 (57→58) taken 50 times.
✗ Branch 1 (57→98) not taken.
✓ Branch 2 (58→59) taken 50 times.
✗ Branch 3 (58→96) not taken.
✓ Branch 4 (59→60) taken 50 times.
✗ Branch 5 (59→96) not taken.
100 thisPtr = insertLoad(builder.getPtrTy(), thisPtrPtr);
562
2/4
✓ Branch 0 (63→64) taken 54 times.
✗ Branch 1 (63→109) not taken.
✓ Branch 2 (64→65) taken 54 times.
✗ Branch 3 (64→109) not taken.
54 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(i)};
563
1/2
✓ Branch 0 (69→70) taken 54 times.
✗ Branch 1 (69→102) not taken.
54 llvm::Value *fieldAddress = insertInBoundsGEP(structType, thisPtr, indices);
564 // Call dealloc function
565
1/2
✓ Branch 0 (72→73) taken 54 times.
✗ Branch 1 (72→109) not taken.
54 generateDeallocCall(fieldAddress);
566 }
567 }
568 89 }
569
570 91 void IRGenerator::generateDefaultDtor(const Function *dtorFunction) {
571
3/6
✓ Branch 0 (2→3) taken 91 times.
✗ Branch 1 (2→6) not taken.
✓ Branch 2 (3→4) taken 91 times.
✗ Branch 3 (3→13) not taken.
✓ Branch 4 (4→5) taken 91 times.
✗ Branch 5 (4→6) not taken.
91 assert(dtorFunction->implicitDefault && dtorFunction->name == DTOR_FUNCTION_NAME);
572 180 const std::function<void()> generateBody = [&] { generateDtorBodyPreamble(dtorFunction); };
573
1/2
✓ Branch 0 (8→9) taken 91 times.
✗ Branch 1 (8→11) not taken.
91 generateImplicitProcedure(generateBody, dtorFunction);
574 91 }
575
576 2 void IRGenerator::generateTestMain() {
577 // Collect all test functions
578 2 std::vector<const std::vector<const Function *> *> tests;
579
5/8
✓ Branch 0 (2→3) taken 2 times.
✗ Branch 1 (2→138) not taken.
✓ Branch 2 (3→4) taken 2 times.
✗ Branch 3 (3→138) not taken.
✓ Branch 4 (4→5) taken 2 times.
✗ Branch 5 (4→138) not taken.
✓ Branch 6 (15→6) taken 3 times.
✓ Branch 7 (15→16) taken 2 times.
5 for (const auto &sourceFile : resourceManager.sourceFiles | std::views::values)
580
1/2
✓ Branch 0 (9→10) taken 3 times.
✗ Branch 1 (9→13) not taken.
3 if (!sourceFile->testFunctions.empty())
581
1/2
✓ Branch 0 (11→12) taken 3 times.
✗ Branch 1 (11→137) not taken.
3 tests.push_back(&sourceFile->testFunctions);
582
583 // Prepare printf function
584
1/2
✓ Branch 0 (16→17) taken 2 times.
✗ Branch 1 (16→263) not taken.
2 llvm::Function *printfFct = stdFunctionManager.getPrintfFct();
585
586 // Prepare success and error messages
587
3/6
✓ Branch 0 (19→20) taken 2 times.
✗ Branch 1 (19→147) not taken.
✓ Branch 2 (22→23) taken 2 times.
✗ Branch 3 (22→141) not taken.
✓ Branch 4 (23→24) taken 2 times.
✗ Branch 5 (23→139) not taken.
8 llvm::Constant *allStartMsg = createGlobalStringConst("allStartMsg", TEST_ALL_START_MSG, *rootScope->codeLoc);
588
3/6
✓ Branch 0 (30→31) taken 2 times.
✗ Branch 1 (30→159) not taken.
✓ Branch 2 (33→34) taken 2 times.
✗ Branch 3 (33→153) not taken.
✓ Branch 4 (34→35) taken 2 times.
✗ Branch 5 (34→151) not taken.
8 llvm::Constant *allEndMsg = createGlobalStringConst("allEndMsg", TEST_ALL_END_MSG, *rootScope->codeLoc);
589
3/6
✓ Branch 0 (41→42) taken 2 times.
✗ Branch 1 (41→171) not taken.
✓ Branch 2 (44→45) taken 2 times.
✗ Branch 3 (44→165) not taken.
✓ Branch 4 (45→46) taken 2 times.
✗ Branch 5 (45→163) not taken.
8 llvm::Constant *fileStartMsg = createGlobalStringConst("fileStartMsg", TEST_FILE_START_MSG, *rootScope->codeLoc);
590
3/6
✓ Branch 0 (52→53) taken 2 times.
✗ Branch 1 (52→183) not taken.
✓ Branch 2 (55→56) taken 2 times.
✗ Branch 3 (55→177) not taken.
✓ Branch 4 (56→57) taken 2 times.
✗ Branch 5 (56→175) not taken.
8 llvm::Constant *fileEndMsg = createGlobalStringConst("fileEndMsg", TEST_FILE_END_MSG, *rootScope->codeLoc);
591
3/6
✓ Branch 0 (63→64) taken 2 times.
✗ Branch 1 (63→195) not taken.
✓ Branch 2 (66→67) taken 2 times.
✗ Branch 3 (66→189) not taken.
✓ Branch 4 (67→68) taken 2 times.
✗ Branch 5 (67→187) not taken.
8 llvm::Constant *runMsg = createGlobalStringConst("runMsg", TEST_CASE_RUN_MSG, *rootScope->codeLoc);
592
3/6
✓ Branch 0 (74→75) taken 2 times.
✗ Branch 1 (74→207) not taken.
✓ Branch 2 (77→78) taken 2 times.
✗ Branch 3 (77→201) not taken.
✓ Branch 4 (78→79) taken 2 times.
✗ Branch 5 (78→199) not taken.
8 llvm::Constant *successMsg = createGlobalStringConst("successMsg", TEST_CASE_SUCCESS_MSG, *rootScope->codeLoc);
593
3/6
✓ Branch 0 (85→86) taken 2 times.
✗ Branch 1 (85→219) not taken.
✓ Branch 2 (88→89) taken 2 times.
✗ Branch 3 (88→213) not taken.
✓ Branch 4 (89→90) taken 2 times.
✗ Branch 5 (89→211) not taken.
8 llvm::Constant *errorMsg = createGlobalStringConst("errorMsg", TEST_CASE_FAILED_MSG, *rootScope->codeLoc);
594
3/6
✓ Branch 0 (96→97) taken 2 times.
✗ Branch 1 (96→231) not taken.
✓ Branch 2 (99→100) taken 2 times.
✗ Branch 3 (99→225) not taken.
✓ Branch 4 (100→101) taken 2 times.
✗ Branch 5 (100→223) not taken.
8 llvm::Constant *skippedMsg = createGlobalStringConst("skippedMsg", TEST_CASE_SKIPPED_MSG, *rootScope->codeLoc);
595
596 // Prepare entry for test main
597
1/2
✓ Branch 0 (105→106) taken 2 times.
✗ Branch 1 (105→263) not taken.
2 QualType functionType(TY_FUNCTION);
598
1/2
✓ Branch 0 (106→107) taken 2 times.
✗ Branch 1 (106→263) not taken.
2 functionType.setQualifiers(TypeQualifiers::of(TY_FUNCTION));
599
1/2
✓ Branch 0 (108→109) taken 2 times.
✗ Branch 1 (108→263) not taken.
2 functionType.makePublic();
600
2/4
✓ Branch 0 (111→112) taken 2 times.
✗ Branch 1 (111→237) not taken.
✓ Branch 2 (112→113) taken 2 times.
✗ Branch 3 (112→235) not taken.
4 SymbolTableEntry entry(MAIN_FUNCTION_NAME, functionType, rootScope, nullptr, 0, false);
601
602 // Prepare test main function
603
3/6
✓ Branch 0 (117→118) taken 2 times.
✗ Branch 1 (117→246) not taken.
✓ Branch 2 (118→119) taken 2 times.
✗ Branch 3 (118→245) not taken.
✓ Branch 4 (121→122) taken 2 times.
✗ Branch 5 (121→241) not taken.
6 Function testMain(MAIN_FUNCTION_NAME, &entry, QualType(TY_DYN), QualType(TY_INT), {}, {}, nullptr);
604 2 testMain.used = true; // Mark as used to prevent removal
605 2 testMain.implicitDefault = true;
606 2 testMain.mangleFunctionName = false;
607
608 // Prepare scope
609
2/4
✓ Branch 0 (127→128) taken 2 times.
✗ Branch 1 (127→255) not taken.
✓ Branch 2 (128→129) taken 2 times.
✗ Branch 3 (128→253) not taken.
2 rootScope->createChildScope(testMain.getSignature(false), ScopeType::FUNC_PROC_BODY, nullptr);
610
611 // Generate
612 const std::function<void()> generateBody = [&] {
613 // Prepare result variable
614
1/2
✓ Branch 0 (2→3) taken 2 times.
✗ Branch 1 (2→297) not taken.
2 llvm::Type *i32Ty = builder.getInt32Ty();
615
2/4
✓ Branch 0 (5→6) taken 2 times.
✗ Branch 1 (5→200) not taken.
✓ Branch 2 (6→7) taken 2 times.
✗ Branch 3 (6→198) not taken.
4 llvm::Value *overallResult = insertAlloca(i32Ty, RETURN_VARIABLE_NAME);
616
2/4
✓ Branch 0 (9→10) taken 2 times.
✗ Branch 1 (9→297) not taken.
✓ Branch 2 (10→11) taken 2 times.
✗ Branch 3 (10→297) not taken.
2 insertStore(builder.getTrue(), overallResult);
617
618 // Print start message
619 3 const auto accFct = [&](size_t sum, const std::vector<const Function *> *innerVector) { return sum + innerVector->size(); };
620 2 const size_t totalTestCount = std::accumulate(tests.begin(), tests.end(), 0, accFct);
621
5/10
✓ Branch 0 (14→15) taken 2 times.
✗ Branch 1 (14→207) not taken.
✓ Branch 2 (15→16) taken 2 times.
✗ Branch 3 (15→205) not taken.
✓ Branch 4 (17→18) taken 2 times.
✗ Branch 5 (17→205) not taken.
✓ Branch 6 (19→20) taken 2 times.
✗ Branch 7 (19→204) not taken.
✓ Branch 8 (20→21) taken 2 times.
✗ Branch 9 (20→204) not taken.
2 builder.CreateCall(printfFct, {allStartMsg, builder.getInt32(totalTestCount), builder.getInt32(tests.size())});
622
623 // Generate a call to each test function
624
2/2
✓ Branch 0 (182→23) taken 3 times.
✓ Branch 1 (182→183) taken 2 times.
5 for (const std::vector<const Function *> *testSuite : tests) {
625 // Print test suite prologue
626
1/2
✓ Branch 0 (25→26) taken 3 times.
✗ Branch 1 (25→285) not taken.
3 const std::string fileName = testSuite->front()->bodyScope->sourceFile->fileName;
627
3/6
✓ Branch 0 (27→28) taken 3 times.
✗ Branch 1 (27→283) not taken.
✓ Branch 2 (30→31) taken 3 times.
✗ Branch 3 (30→210) not taken.
✓ Branch 4 (31→32) taken 3 times.
✗ Branch 5 (31→208) not taken.
6 llvm::Constant *fileNameValue = createGlobalStringConst("fileName", fileName, testSuite->front()->getDeclCodeLoc());
628
4/8
✓ Branch 0 (34→35) taken 3 times.
✗ Branch 1 (34→217) not taken.
✓ Branch 2 (36→37) taken 3 times.
✗ Branch 3 (36→215) not taken.
✓ Branch 4 (38→39) taken 3 times.
✗ Branch 5 (38→214) not taken.
✓ Branch 6 (39→40) taken 3 times.
✗ Branch 7 (39→214) not taken.
3 builder.CreateCall(printfFct, {fileStartMsg, builder.getInt32(testSuite->size()), fileNameValue});
629
630
3/4
✓ Branch 0 (43→44) taken 8 times.
✗ Branch 1 (43→277) not taken.
✓ Branch 2 (172→42) taken 8 times.
✓ Branch 3 (172→173) taken 3 times.
11 for (const Function *testFunction : *testSuite) {
631
1/2
✗ Branch 0 (55→56) not taken.
✓ Branch 1 (55→57) taken 8 times.
8 assert(testFunction->isNormalFunction());
632
1/2
✗ Branch 0 (58→59) not taken.
✓ Branch 1 (58→60) taken 8 times.
8 assert(testFunction->paramList.empty());
633
634 // Retrieve attribute list for the test function
635
2/4
✓ Branch 0 (60→61) taken 8 times.
✗ Branch 1 (60→277) not taken.
✗ Branch 2 (61→62) not taken.
✓ Branch 3 (61→63) taken 8 times.
8 assert(testFunction->declNode->isFctOrProcDef());
636
1/2
✓ Branch 0 (63→64) taken 8 times.
✗ Branch 1 (63→65) not taken.
8 const auto fctDefNode = spice_pointer_cast<FctDefBaseNode *>(testFunction->declNode);
637
1/2
✗ Branch 0 (70→71) not taken.
✓ Branch 1 (70→72) taken 8 times.
8 assert(fctDefNode->attrs != nullptr);
638 8 const AttrLstNode *attrs = fctDefNode->attrs->attrLst;
639
3/6
✓ Branch 0 (74→75) taken 8 times.
✗ Branch 1 (74→220) not taken.
✓ Branch 2 (75→76) taken 8 times.
✗ Branch 3 (75→218) not taken.
✗ Branch 4 (76→77) not taken.
✓ Branch 5 (76→78) taken 8 times.
16 assert(attrs->getAttrValueByName(ATTR_TEST)->boolValue); // The test attribute must be present
640
2/4
✓ Branch 0 (82→83) taken 8 times.
✗ Branch 1 (82→226) not taken.
✓ Branch 2 (83→84) taken 8 times.
✗ Branch 3 (83→224) not taken.
16 const CompileTimeValue *testSkipAttr = attrs->getAttrValueByName(ATTR_TEST_SKIP);
641
4/4
✓ Branch 0 (86→87) taken 3 times.
✓ Branch 1 (86→89) taken 5 times.
✓ Branch 2 (87→88) taken 1 times.
✓ Branch 3 (87→89) taken 2 times.
8 const bool skipTest = testSkipAttr && testSkipAttr->boolValue;
642
2/4
✓ Branch 0 (92→93) taken 8 times.
✗ Branch 1 (92→232) not taken.
✓ Branch 2 (93→94) taken 8 times.
✗ Branch 3 (93→230) not taken.
16 const CompileTimeValue *testNameAttr = attrs->getAttrValueByName(ATTR_TEST_NAME);
643
644 // Prepare test name
645
1/2
✓ Branch 0 (96→97) taken 8 times.
✗ Branch 1 (96→277) not taken.
8 std::stringstream testName;
646
1/2
✓ Branch 0 (97→98) taken 8 times.
✗ Branch 1 (97→275) not taken.
8 testName << testFunction->name;
647
2/2
✓ Branch 0 (98→99) taken 1 times.
✓ Branch 1 (98→103) taken 7 times.
8 if (testNameAttr)
648
4/8
✓ Branch 0 (99→100) taken 1 times.
✗ Branch 1 (99→275) not taken.
✓ Branch 2 (100→101) taken 1 times.
✗ Branch 3 (100→275) not taken.
✓ Branch 4 (101→102) taken 1 times.
✗ Branch 5 (101→275) not taken.
✓ Branch 6 (102→103) taken 1 times.
✗ Branch 7 (102→275) not taken.
1 testName << " (" << resourceManager.compileTimeStringValues.at(testNameAttr->stringValueOffset) << ")";
649
650 // Print test case run message
651
4/8
✓ Branch 0 (103→104) taken 8 times.
✗ Branch 1 (103→275) not taken.
✓ Branch 2 (104→105) taken 8 times.
✗ Branch 3 (104→244) not taken.
✓ Branch 4 (107→108) taken 8 times.
✗ Branch 5 (107→238) not taken.
✓ Branch 6 (108→109) taken 8 times.
✗ Branch 7 (108→236) not taken.
24 llvm::Constant *testNameValue = createGlobalStringConst("testName", testName.str(), testFunction->getDeclCodeLoc());
652
3/6
✓ Branch 0 (112→113) taken 8 times.
✗ Branch 1 (112→248) not taken.
✓ Branch 2 (114→115) taken 8 times.
✗ Branch 3 (114→245) not taken.
✓ Branch 4 (115→116) taken 8 times.
✗ Branch 5 (115→245) not taken.
8 builder.CreateCall(printfFct, {runMsg, testNameValue});
653
654
2/2
✓ Branch 0 (116→117) taken 1 times.
✓ Branch 1 (116→122) taken 7 times.
8 if (skipTest) {
655 // Print test case skip message
656
3/6
✓ Branch 0 (117→118) taken 1 times.
✗ Branch 1 (117→252) not taken.
✓ Branch 2 (119→120) taken 1 times.
✗ Branch 3 (119→249) not taken.
✓ Branch 4 (120→121) taken 1 times.
✗ Branch 5 (120→249) not taken.
1 builder.CreateCall(printfFct, {skippedMsg, testNameValue});
657 1 continue;
658 }
659
660 // Test function is not defined in the current module -> declare it
661
1/2
✓ Branch 0 (122→123) taken 7 times.
✗ Branch 1 (122→275) not taken.
7 const std::string mangledName = testFunction->getMangledName();
662
3/4
✓ Branch 0 (124→125) taken 7 times.
✗ Branch 1 (124→253) not taken.
✓ Branch 2 (125→126) taken 2 times.
✓ Branch 3 (125→138) taken 5 times.
7 if (!module->getFunction(mangledName)) {
663
2/4
✓ Branch 0 (126→127) taken 2 times.
✗ Branch 1 (126→273) not taken.
✗ Branch 2 (127→128) not taken.
✓ Branch 3 (127→129) taken 2 times.
2 assert(testFunction->returnType.is(TY_BOOL));
664
1/2
✗ Branch 0 (130→131) not taken.
✓ Branch 1 (130→132) taken 2 times.
2 assert(testFunction->paramList.empty());
665
2/4
✓ Branch 0 (133→134) taken 2 times.
✗ Branch 1 (133→254) not taken.
✓ Branch 2 (134→135) taken 2 times.
✗ Branch 3 (134→254) not taken.
2 llvm::FunctionType *fctType = llvm::FunctionType::get(builder.getInt1Ty(), {}, false);
666
1/2
✓ Branch 0 (136→137) taken 2 times.
✗ Branch 1 (136→255) not taken.
2 module->getOrInsertFunction(mangledName, fctType);
667 }
668
669 // Call test function
670
1/2
✓ Branch 0 (139→140) taken 7 times.
✗ Branch 1 (139→256) not taken.
7 llvm::Function *callee = module->getFunction(mangledName);
671
1/2
✗ Branch 0 (140→141) not taken.
✓ Branch 1 (140→142) taken 7 times.
7 assert(callee != nullptr);
672
3/6
✓ Branch 0 (142→143) taken 7 times.
✗ Branch 1 (142→259) not taken.
✓ Branch 2 (144→145) taken 7 times.
✗ Branch 3 (144→257) not taken.
✓ Branch 4 (145→146) taken 7 times.
✗ Branch 5 (145→257) not taken.
7 llvm::Value *testCaseResult = builder.CreateCall(callee);
673
674 // Update result variable
675
2/4
✓ Branch 0 (148→149) taken 7 times.
✗ Branch 1 (148→262) not taken.
✓ Branch 2 (149→150) taken 7 times.
✗ Branch 3 (149→260) not taken.
14 llvm::Value *oldResult = insertLoad(i32Ty, overallResult);
676
4/8
✓ Branch 0 (152→153) taken 7 times.
✗ Branch 1 (152→267) not taken.
✓ Branch 2 (153→154) taken 7 times.
✗ Branch 3 (153→266) not taken.
✓ Branch 4 (154→155) taken 7 times.
✗ Branch 5 (154→266) not taken.
✓ Branch 6 (155→156) taken 7 times.
✗ Branch 7 (155→266) not taken.
7 llvm::Value *newResult = builder.CreateAnd(oldResult, builder.CreateZExt(testCaseResult, i32Ty));
677
1/2
✓ Branch 0 (156→157) taken 7 times.
✗ Branch 1 (156→273) not taken.
7 insertStore(newResult, overallResult);
678
679 // Print test case result message
680
2/4
✓ Branch 0 (157→158) taken 7 times.
✗ Branch 1 (157→268) not taken.
✓ Branch 2 (158→159) taken 7 times.
✗ Branch 3 (158→268) not taken.
7 llvm::Value *message = builder.CreateSelect(testCaseResult, successMsg, errorMsg);
681
3/6
✓ Branch 0 (159→160) taken 7 times.
✗ Branch 1 (159→272) not taken.
✓ Branch 2 (161→162) taken 7 times.
✗ Branch 3 (161→269) not taken.
✓ Branch 4 (162→163) taken 7 times.
✗ Branch 5 (162→269) not taken.
7 builder.CreateCall(printfFct, {message, testNameValue});
682
2/2
✓ Branch 0 (166→167) taken 7 times.
✓ Branch 1 (166→169) taken 1 times.
8 }
683
684 // Print test suite epilogue
685
4/8
✓ Branch 0 (173→174) taken 3 times.
✗ Branch 1 (173→282) not taken.
✓ Branch 2 (175→176) taken 3 times.
✗ Branch 3 (175→280) not taken.
✓ Branch 4 (177→178) taken 3 times.
✗ Branch 5 (177→279) not taken.
✓ Branch 6 (178→179) taken 3 times.
✗ Branch 7 (178→279) not taken.
3 builder.CreateCall(printfFct, {fileEndMsg, builder.getInt32(testSuite->size()), fileNameValue});
686 3 }
687
688 // Print end message
689
5/10
✓ Branch 0 (183→184) taken 2 times.
✗ Branch 1 (183→290) not taken.
✓ Branch 2 (184→185) taken 2 times.
✗ Branch 3 (184→288) not taken.
✓ Branch 4 (186→187) taken 2 times.
✗ Branch 5 (186→288) not taken.
✓ Branch 6 (188→189) taken 2 times.
✗ Branch 7 (188→287) not taken.
✓ Branch 8 (189→190) taken 2 times.
✗ Branch 9 (189→287) not taken.
2 builder.CreateCall(printfFct, {allEndMsg, builder.getInt32(totalTestCount), builder.getInt32(tests.size())});
690
691 // Return result
692
2/4
✓ Branch 0 (192→193) taken 2 times.
✗ Branch 1 (192→293) not taken.
✓ Branch 2 (193→194) taken 2 times.
✗ Branch 3 (193→291) not taken.
4 llvm::Value *finalResult = insertLoad(i32Ty, overallResult);
693
1/2
✓ Branch 0 (196→197) taken 2 times.
✗ Branch 1 (196→297) not taken.
2 builder.CreateRet(finalResult);
694
1/2
✓ Branch 0 (130→131) taken 2 times.
✗ Branch 1 (130→256) not taken.
4 };
695
1/2
✓ Branch 0 (131→132) taken 2 times.
✗ Branch 1 (131→257) not taken.
2 generateImplicitFunction(generateBody, &testMain);
696 2 }
697
698 } // namespace spice::compiler
699