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