GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenImplicit.cpp
Date: 2025-03-05 01:50:32
Exec Total Coverage
Lines: 354 406 87.2%
Functions: 20 21 95.2%
Branches: 464 982 47.3%

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