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