GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 95.9% 581 / 1 / 607
Functions: 100.0% 15 / 0 / 15
Branches: 56.6% 739 / 4 / 1310

src/irgenerator/GenValues.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "IRGenerator.h"
4
5 #include <ast/ASTNodes.h>
6 #include <irgenerator/NameMangling.h>
7 #include <symboltablebuilder/SymbolTableBuilder.h>
8 #include <typechecker/Builtins.h>
9
10 #include <llvm/IR/Module.h>
11
12 namespace spice::compiler {
13
14 20603 std::any IRGenerator::visitValue(const ValueNode *node) {
15 20603 diGenerator.setSourceLocation(node);
16
17 // Function call
18
2/2
✓ Branch 3 → 4 taken 18645 times.
✓ Branch 3 → 5 taken 1958 times.
20603 if (node->fctCall)
19 18645 return visit(node->fctCall);
20
21 // Array initialization
22
2/2
✓ Branch 5 → 6 taken 59 times.
✓ Branch 5 → 7 taken 1899 times.
1958 if (node->arrayInitialization)
23 59 return visit(node->arrayInitialization);
24
25 // Struct instantiation
26
2/2
✓ Branch 7 → 8 taken 282 times.
✓ Branch 7 → 9 taken 1617 times.
1899 if (node->structInstantiation)
27 282 return visit(node->structInstantiation);
28
29 // Lambda function
30
2/2
✓ Branch 9 → 10 taken 12 times.
✓ Branch 9 → 11 taken 1605 times.
1617 if (node->lambdaFunc)
31 12 return visit(node->lambdaFunc);
32
33 // Lambda procedure
34
2/2
✓ Branch 11 → 12 taken 19 times.
✓ Branch 11 → 13 taken 1586 times.
1605 if (node->lambdaProc)
35 19 return visit(node->lambdaProc);
36
37 // Lambda expression
38
2/2
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 15 taken 1585 times.
1586 if (node->lambdaExpr)
39 1 return visit(node->lambdaExpr);
40
41
1/2
✓ Branch 15 → 16 taken 1585 times.
✗ Branch 15 → 23 not taken.
1585 if (node->isNil) {
42 // Retrieve type of the nil constant
43
2/4
✓ Branch 16 → 17 taken 1585 times.
✗ Branch 16 → 34 not taken.
✓ Branch 17 → 18 taken 1585 times.
✗ Branch 17 → 32 not taken.
1585 const auto nilType = any_cast<llvm::Type *>(visit(node->nilType));
44 // Create constant nil value
45 1585 llvm::Constant *nilValue = llvm::Constant::getNullValue(nilType);
46 // Return it
47
1/2
✓ Branch 20 → 21 taken 1585 times.
✗ Branch 20 → 35 not taken.
3170 return LLVMExprResult{.constant = nilValue};
48 }
49
50 throw CompilerError(UNHANDLED_BRANCH, "Value fall-through"); // GCOV_EXCL_LINE
51 }
52
53 18322 std::any IRGenerator::visitConstant(const ConstantNode *node) {
54
3/6
✓ Branch 2 → 3 taken 18322 times.
✗ Branch 2 → 10 not taken.
✓ Branch 4 → 5 taken 18322 times.
✗ Branch 4 → 9 not taken.
✓ Branch 5 → 6 taken 18322 times.
✗ Branch 5 → 9 not taken.
18322 return getConst(node->getCompileTimeValue(manIdx), node->getEvaluatedSymbolType(manIdx), node);
55 }
56
57 18645 std::any IRGenerator::visitFctCall(const FctCallNode *node) {
58
1/2
✓ Branch 2 → 3 taken 18645 times.
✗ Branch 2 → 532 not taken.
18645 diGenerator.setSourceLocation(node);
59
60 // Check if this is a builtin call
61
2/2
✓ Branch 10 → 4 taken 157910 times.
✓ Branch 10 → 11 taken 16899 times.
174809 for (const auto &[builtinFctName, _] : BUILTIN_FUNCTIONS)
62
2/2
✓ Branch 6 → 7 taken 1746 times.
✓ Branch 6 → 9 taken 156164 times.
157910 if (node->fqFunctionName == builtinFctName)
63
1/2
✓ Branch 7 → 8 taken 1746 times.
✗ Branch 7 → 532 not taken.
1746 return visitBuiltinCall(node);
64
65
1/2
✓ Branch 11 → 12 taken 16899 times.
✗ Branch 11 → 532 not taken.
16899 const FctCallNode::FctCallData &data = node->data.at(manIdx);
66
67 16899 Function *spiceFunc = data.callee;
68
3/4
✓ Branch 13 → 14 taken 16855 times.
✓ Branch 13 → 16 taken 44 times.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 16855 times.
16899 assert(data.isFctPtrCall() || spiceFunc != nullptr); // If not a function pointer call, we must have a function
69 16899 std::string mangledName;
70
2/2
✓ Branch 18 → 19 taken 16855 times.
✓ Branch 18 → 23 taken 44 times.
16899 if (!data.isFctPtrCall())
71
1/2
✓ Branch 19 → 20 taken 16855 times.
✗ Branch 19 → 391 not taken.
16855 mangledName = spiceFunc->getMangledName();
72
73 // Get entry of the first fragment
74 16899 SymbolTableEntry *firstFragEntry = currentScope->lookup(node->functionNameFragments.front());
75
76 // Get this type
77 16899 std::vector<llvm::Value *> argValues;
78 16899 llvm::Value *thisPtr = nullptr;
79
2/2
✓ Branch 28 → 29 taken 6150 times.
✓ Branch 28 → 76 taken 10749 times.
16899 if (data.isMethodCall()) {
80
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 6150 times.
6150 assert(!data.isCtorCall());
81
82 // Retrieve entry of the first fragment
83
2/4
✓ Branch 32 → 33 taken 6150 times.
✗ Branch 32 → 406 not taken.
✓ Branch 33 → 34 taken 6150 times.
✗ Branch 33 → 406 not taken.
6150 const QualType baseType = firstFragEntry->getQualType().getBase();
84
3/6
✓ Branch 34 → 35 taken 6150 times.
✗ Branch 34 → 38 not taken.
✓ Branch 35 → 36 taken 6150 times.
✗ Branch 35 → 392 not taken.
✓ Branch 36 → 37 taken 6150 times.
✗ Branch 36 → 38 not taken.
6150 assert(firstFragEntry != nullptr && baseType.isOneOf({TY_STRUCT, TY_INTERFACE}));
85
1/2
✓ Branch 39 → 40 taken 6150 times.
✗ Branch 39 → 406 not taken.
6150 Scope *structScope = baseType.getBodyScope();
86
87 // Get address of the referenced variable / struct instance
88
1/2
✓ Branch 40 → 41 taken 6150 times.
✗ Branch 40 → 406 not taken.
6150 thisPtr = firstFragEntry->getAddress();
89
90 // Auto de-reference 'this' pointer
91
1/2
✓ Branch 41 → 42 taken 6150 times.
✗ Branch 41 → 406 not taken.
6150 QualType firstFragmentType = firstFragEntry->getQualType();
92
1/2
✓ Branch 42 → 43 taken 6150 times.
✗ Branch 42 → 406 not taken.
6150 autoDeReferencePtr(thisPtr, firstFragmentType);
93
1/2
✓ Branch 43 → 44 taken 6150 times.
✗ Branch 43 → 406 not taken.
6150 llvm::Type *structTy = baseType.toLLVMType(sourceFile);
94
95 // Traverse through structs - the first fragment is already looked up and the last one is the function name
96
2/2
✓ Branch 73 → 45 taken 834 times.
✓ Branch 73 → 74 taken 6150 times.
6984 for (size_t i = 1; i < node->functionNameFragments.size() - 1; i++) {
97
2/4
✓ Branch 45 → 46 taken 834 times.
✗ Branch 45 → 405 not taken.
✓ Branch 46 → 47 taken 834 times.
✗ Branch 46 → 405 not taken.
834 const std::string identifier = node->functionNameFragments.at(i);
98 // Retrieve field entry
99 834 SymbolTableEntry *fieldEntry = structScope->lookupStrict(identifier);
100
1/2
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 52 taken 834 times.
834 assert(fieldEntry != nullptr);
101
1/2
✓ Branch 52 → 53 taken 834 times.
✗ Branch 52 → 403 not taken.
834 QualType fieldEntryType = fieldEntry->getQualType();
102
3/6
✓ Branch 53 → 54 taken 834 times.
✗ Branch 53 → 394 not taken.
✓ Branch 54 → 55 taken 834 times.
✗ Branch 54 → 393 not taken.
✗ Branch 55 → 56 not taken.
✓ Branch 55 → 57 taken 834 times.
834 assert(fieldEntryType.getBase().isOneOf({TY_STRUCT, TY_INTERFACE}));
103 // Get struct type and scope
104
2/4
✓ Branch 57 → 58 taken 834 times.
✗ Branch 57 → 395 not taken.
✓ Branch 58 → 59 taken 834 times.
✗ Branch 58 → 395 not taken.
834 structScope = fieldEntryType.getBase().getBodyScope();
105
1/2
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 834 times.
834 assert(structScope != nullptr);
106 // Get address of field
107
1/2
✓ Branch 64 → 65 taken 834 times.
✗ Branch 64 → 396 not taken.
834 thisPtr = insertStructGEP(structTy, thisPtr, fieldEntry->orderIndex);
108 // Auto de-reference pointer and get new struct type
109
1/2
✓ Branch 67 → 68 taken 834 times.
✗ Branch 67 → 403 not taken.
834 autoDeReferencePtr(thisPtr, fieldEntryType);
110
2/4
✓ Branch 68 → 69 taken 834 times.
✗ Branch 68 → 402 not taken.
✓ Branch 69 → 70 taken 834 times.
✗ Branch 69 → 402 not taken.
834 structTy = fieldEntryType.getBase().toLLVMType(sourceFile);
111 834 }
112
113 // Add 'this' pointer to the front of the argument list
114
1/2
✓ Branch 74 → 75 taken 6150 times.
✗ Branch 74 → 406 not taken.
6150 argValues.push_back(thisPtr);
115 }
116
117
2/2
✓ Branch 77 → 78 taken 2344 times.
✓ Branch 77 → 89 taken 14555 times.
16899 if (data.isCtorCall()) {
118
1/2
✗ Branch 79 → 80 not taken.
✓ Branch 79 → 81 taken 2344 times.
2344 assert(!data.isMethodCall());
119
120
1/2
✓ Branch 81 → 82 taken 2344 times.
✗ Branch 81 → 528 not taken.
2344 llvm::Type *thisType = spiceFunc->thisType.toLLVMType(sourceFile);
121
1/2
✓ Branch 85 → 86 taken 2344 times.
✗ Branch 85 → 407 not taken.
2344 thisPtr = insertAlloca(thisType);
122
123 // Add 'this' pointer to the front of the argument list
124
1/2
✓ Branch 88 → 89 taken 2344 times.
✗ Branch 88 → 528 not taken.
2344 argValues.push_back(thisPtr);
125 }
126
127 // If we have a lambda call that takes captures, add them to the argument list
128 16899 llvm::Value *fctPtr = nullptr;
129
2/2
✓ Branch 90 → 91 taken 44 times.
✓ Branch 90 → 120 taken 16855 times.
16899 if (data.isFctPtrCall()) {
130
1/2
✓ Branch 91 → 92 taken 44 times.
✗ Branch 91 → 528 not taken.
44 llvm::Value *fatPtr = firstFragEntry->getAddress();
131 // Load fctPtr
132
3/6
✓ Branch 92 → 93 taken 44 times.
✗ Branch 92 → 413 not taken.
✓ Branch 93 → 94 taken 44 times.
✗ Branch 93 → 413 not taken.
✓ Branch 95 → 96 taken 44 times.
✗ Branch 95 → 413 not taken.
44 llvm::StructType *fatStructType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()});
133
1/2
✓ Branch 99 → 100 taken 44 times.
✗ Branch 99 → 415 not taken.
44 fctPtr = insertStructGEP(fatStructType, fatPtr, 0);
134
4/6
✓ Branch 102 → 103 taken 44 times.
✗ Branch 102 → 528 not taken.
✓ Branch 103 → 104 taken 44 times.
✗ Branch 103 → 528 not taken.
✓ Branch 104 → 105 taken 16 times.
✓ Branch 104 → 120 taken 28 times.
44 if (firstFragEntry->getQualType().hasLambdaCaptures()) {
135 // Load captures struct
136
1/2
✓ Branch 108 → 109 taken 16 times.
✗ Branch 108 → 421 not taken.
16 llvm::Value *capturesPtrPtr = insertStructGEP(fatStructType, fatPtr, 1);
137
3/6
✓ Branch 113 → 114 taken 16 times.
✗ Branch 113 → 429 not taken.
✓ Branch 114 → 115 taken 16 times.
✗ Branch 114 → 427 not taken.
✓ Branch 115 → 116 taken 16 times.
✗ Branch 115 → 427 not taken.
16 llvm::Value *capturesPtr = insertLoad(builder.getPtrTy(), capturesPtrPtr, false, CAPTURES_PARAM_NAME);
138 // Add captures to argument list
139
1/2
✓ Branch 118 → 119 taken 16 times.
✗ Branch 118 → 433 not taken.
16 argValues.push_back(capturesPtr);
140 }
141 }
142
143 // Get arg values
144
2/2
✓ Branch 120 → 121 taken 13311 times.
✓ Branch 120 → 209 taken 3588 times.
16899 if (node->hasArgs) {
145
1/2
✓ Branch 121 → 122 taken 13311 times.
✗ Branch 121 → 465 not taken.
13311 const std::vector<AssignExprNode *> args = node->argLst->args;
146
1/2
✓ Branch 123 → 124 taken 13311 times.
✗ Branch 123 → 463 not taken.
13311 argValues.reserve(args.size());
147 const QualTypeList paramSTypes =
148
6/10
✓ Branch 125 → 126 taken 22 times.
✓ Branch 125 → 129 taken 13289 times.
✓ Branch 126 → 127 taken 22 times.
✗ Branch 126 → 434 not taken.
✓ Branch 127 → 128 taken 22 times.
✗ Branch 127 → 434 not taken.
✓ Branch 128 → 130 taken 22 times.
✗ Branch 128 → 434 not taken.
✓ Branch 129 → 130 taken 13289 times.
✗ Branch 129 → 434 not taken.
13311 data.isFctPtrCall() ? firstFragEntry->getQualType().getBase().getFunctionParamTypes() : spiceFunc->getParamTypes();
149
1/2
✗ Branch 132 → 133 not taken.
✓ Branch 132 → 134 taken 13311 times.
13311 assert(paramSTypes.size() == args.size());
150
2/2
✓ Branch 205 → 135 taken 23408 times.
✓ Branch 205 → 206 taken 13311 times.
36719 for (size_t i = 0; i < args.size(); i++) {
151
1/2
✓ Branch 135 → 136 taken 23408 times.
✗ Branch 135 → 460 not taken.
23408 AssignExprNode *argNode = args.at(i);
152
1/2
✓ Branch 136 → 137 taken 23408 times.
✗ Branch 136 → 460 not taken.
23408 const auto &[copyCtor] = node->argLst->argInfos.at(i);
153
154
1/2
✓ Branch 137 → 138 taken 23408 times.
✗ Branch 137 → 460 not taken.
23408 const QualType &expectedSTy = paramSTypes.at(i);
155
1/2
✓ Branch 138 → 139 taken 23408 times.
✗ Branch 138 → 460 not taken.
23408 const QualType &actualSTy = argNode->getEvaluatedSymbolType(manIdx);
156
157 24516 const auto matchFct = [](QualType expectedTy, QualType actualTy) {
158
2/2
✓ Branch 3 → 4 taken 23392 times.
✓ Branch 3 → 5 taken 1124 times.
24516 if (expectedTy.matches(actualTy, false, true, true))
159 23392 return true;
160
161 // Unwrap as far as possible and remove reference wrappers if possible
162 1124 QualType::unwrapBoth(expectedTy, actualTy);
163 1124 return expectedTy.matchesInterfaceImplementedByStruct(actualTy);
164 };
165
166
3/4
✓ Branch 139 → 140 taken 23408 times.
✗ Branch 139 → 460 not taken.
✓ Branch 140 → 141 taken 22287 times.
✓ Branch 140 → 177 taken 1121 times.
23408 if (matchFct(expectedSTy, actualSTy)) {
167 // Resolve address if actual type is reference, otherwise value
168
3/4
✓ Branch 141 → 142 taken 22287 times.
✗ Branch 141 → 460 not taken.
✓ Branch 142 → 143 taken 496 times.
✓ Branch 142 → 146 taken 21791 times.
22287 if (actualSTy.isRef()) {
169
2/4
✓ Branch 143 → 144 taken 496 times.
✗ Branch 143 → 435 not taken.
✓ Branch 144 → 145 taken 496 times.
✗ Branch 144 → 435 not taken.
496 argValues.push_back(resolveAddress(argNode));
170
2/2
✓ Branch 146 → 147 taken 16 times.
✓ Branch 146 → 174 taken 21775 times.
21791 } else if (copyCtor) {
171
2/4
✓ Branch 147 → 148 taken 16 times.
✗ Branch 147 → 455 not taken.
✗ Branch 148 → 149 not taken.
✓ Branch 148 → 150 taken 16 times.
16 assert(!actualSTy.isTriviallyCopyable(node));
172
1/2
✓ Branch 150 → 151 taken 16 times.
✗ Branch 150 → 455 not taken.
16 llvm::Value *originalPtr = resolveAddress(argNode);
173
174 // Generate copy ctor call
175
1/2
✓ Branch 151 → 152 taken 16 times.
✗ Branch 151 → 455 not taken.
16 llvm::Type *valueType = actualSTy.toLLVMType(sourceFile);
176
2/4
✓ Branch 154 → 155 taken 16 times.
✗ Branch 154 → 438 not taken.
✓ Branch 155 → 156 taken 16 times.
✗ Branch 155 → 436 not taken.
16 llvm::Value *valueCopyPtr = insertAlloca(valueType, "arg.copy");
177
2/4
✓ Branch 160 → 161 taken 16 times.
✗ Branch 160 → 444 not taken.
✓ Branch 161 → 162 taken 16 times.
✗ Branch 161 → 442 not taken.
48 generateCtorOrDtorCall(valueCopyPtr, copyCtor, {originalPtr});
178
2/4
✓ Branch 166 → 167 taken 16 times.
✗ Branch 166 → 451 not taken.
✓ Branch 167 → 168 taken 16 times.
✗ Branch 167 → 449 not taken.
16 llvm::Value *newValue = insertLoad(valueType, valueCopyPtr);
179
180 // Attach address of copy to anonymous symbol
181
1/2
✓ Branch 170 → 171 taken 16 times.
✗ Branch 170 → 455 not taken.
16 SymbolTableEntry *anonymousSymbol = currentScope->symbolTable.lookupAnonymous(argNode, SIZE_MAX);
182
1/2
✓ Branch 171 → 172 taken 16 times.
✗ Branch 171 → 455 not taken.
16 anonymousSymbol->updateAddress(valueCopyPtr);
183
184
1/2
✓ Branch 172 → 173 taken 16 times.
✗ Branch 172 → 455 not taken.
16 argValues.push_back(newValue);
185 } else {
186
2/4
✓ Branch 174 → 175 taken 21775 times.
✗ Branch 174 → 456 not taken.
✓ Branch 175 → 176 taken 21775 times.
✗ Branch 175 → 456 not taken.
21775 argValues.push_back(resolveValue(argNode));
187 }
188
8/12
✓ Branch 177 → 178 taken 1121 times.
✗ Branch 177 → 460 not taken.
✓ Branch 178 → 179 taken 964 times.
✓ Branch 178 → 183 taken 157 times.
✓ Branch 179 → 180 taken 964 times.
✗ Branch 179 → 460 not taken.
✓ Branch 180 → 181 taken 964 times.
✗ Branch 180 → 460 not taken.
✓ Branch 181 → 182 taken 964 times.
✗ Branch 181 → 183 not taken.
✓ Branch 184 → 185 taken 964 times.
✓ Branch 184 → 188 taken 157 times.
1121 } else if (expectedSTy.isRef() && matchFct(expectedSTy.getContained(), actualSTy)) { // Matches with ref
189
1/2
✓ Branch 185 → 186 taken 964 times.
✗ Branch 185 → 457 not taken.
964 llvm::Value *argAddress = resolveAddress(argNode);
190
1/2
✓ Branch 186 → 187 taken 964 times.
✗ Branch 186 → 457 not taken.
964 argValues.push_back(argAddress);
191
8/12
✓ Branch 188 → 189 taken 157 times.
✗ Branch 188 → 460 not taken.
✓ Branch 189 → 190 taken 144 times.
✓ Branch 189 → 194 taken 13 times.
✓ Branch 190 → 191 taken 144 times.
✗ Branch 190 → 460 not taken.
✓ Branch 191 → 192 taken 144 times.
✗ Branch 191 → 460 not taken.
✓ Branch 192 → 193 taken 144 times.
✗ Branch 192 → 194 not taken.
✓ Branch 195 → 196 taken 144 times.
✓ Branch 195 → 199 taken 13 times.
157 } else if (actualSTy.isRef() && matchFct(expectedSTy, actualSTy.getContained())) { // Matches with ref
192
1/2
✓ Branch 196 → 197 taken 144 times.
✗ Branch 196 → 458 not taken.
144 llvm::Value *argAddress = resolveValue(argNode);
193
1/2
✓ Branch 197 → 198 taken 144 times.
✗ Branch 197 → 458 not taken.
144 argValues.push_back(argAddress);
194 } else { // Need implicit cast
195
1/2
✓ Branch 199 → 200 taken 13 times.
✗ Branch 199 → 460 not taken.
13 llvm::Value *argAddress = resolveAddress(argNode);
196
2/4
✓ Branch 200 → 201 taken 13 times.
✗ Branch 200 → 459 not taken.
✓ Branch 201 → 202 taken 13 times.
✗ Branch 201 → 459 not taken.
13 argValues.push_back(doImplicitCast(argAddress, expectedSTy, actualSTy));
197 }
198 }
199 13311 }
200
201 // Retrieve return and param types
202
1/2
✓ Branch 209 → 210 taken 16899 times.
✗ Branch 209 → 528 not taken.
16899 QualType returnSType(TY_DYN);
203 16899 QualTypeList paramSTypes;
204
2/2
✓ Branch 211 → 212 taken 44 times.
✓ Branch 211 → 225 taken 16855 times.
16899 if (data.isFctPtrCall()) {
205
4/6
✓ Branch 212 → 213 taken 44 times.
✗ Branch 212 → 526 not taken.
✓ Branch 213 → 214 taken 44 times.
✗ Branch 213 → 526 not taken.
✓ Branch 214 → 215 taken 19 times.
✓ Branch 214 → 219 taken 25 times.
44 if (firstFragEntry->getQualType().isBase(TY_FUNCTION))
206
3/6
✓ Branch 215 → 216 taken 19 times.
✗ Branch 215 → 466 not taken.
✓ Branch 216 → 217 taken 19 times.
✗ Branch 216 → 466 not taken.
✓ Branch 217 → 218 taken 19 times.
✗ Branch 217 → 466 not taken.
19 returnSType = firstFragEntry->getQualType().getBase().getFunctionReturnType();
207
3/6
✓ Branch 219 → 220 taken 44 times.
✗ Branch 219 → 467 not taken.
✓ Branch 220 → 221 taken 44 times.
✗ Branch 220 → 467 not taken.
✓ Branch 221 → 222 taken 44 times.
✗ Branch 221 → 467 not taken.
44 paramSTypes = firstFragEntry->getQualType().getBase().getFunctionParamTypes();
208 } else {
209 16855 returnSType = spiceFunc->returnType;
210
1/2
✓ Branch 225 → 226 taken 16855 times.
✗ Branch 225 → 469 not taken.
16855 paramSTypes = spiceFunc->getParamTypes();
211 }
212
213 // Function is not defined in the current module -> declare it
214 llvm::FunctionType *fctType;
215
3/4
✓ Branch 230 → 231 taken 16899 times.
✗ Branch 230 → 470 not taken.
✓ Branch 231 → 232 taken 14058 times.
✓ Branch 231 → 234 taken 2841 times.
16899 if (llvm::Function *fct = module->getFunction(mangledName)) {
216
1/2
✓ Branch 232 → 233 taken 14058 times.
✗ Branch 232 → 526 not taken.
14058 fctType = fct->getFunctionType();
217 } else {
218 // Get returnType
219
1/2
✓ Branch 234 → 235 taken 2841 times.
✗ Branch 234 → 479 not taken.
2841 llvm::Type *returnType = builder.getVoidTy();
220
3/4
✓ Branch 235 → 236 taken 2841 times.
✗ Branch 235 → 479 not taken.
✓ Branch 236 → 237 taken 1738 times.
✓ Branch 236 → 239 taken 1103 times.
2841 if (!returnSType.is(TY_DYN))
221
1/2
✓ Branch 237 → 238 taken 1738 times.
✗ Branch 237 → 479 not taken.
1738 returnType = returnSType.toLLVMType(sourceFile);
222
223 // Get arg types
224 2841 std::vector<llvm::Type *> argTypes;
225
6/6
✓ Branch 240 → 241 taken 1575 times.
✓ Branch 240 → 243 taken 1266 times.
✓ Branch 242 → 243 taken 504 times.
✓ Branch 242 → 244 taken 1071 times.
✓ Branch 245 → 246 taken 1770 times.
✓ Branch 245 → 249 taken 1071 times.
2841 if (data.isMethodCall() || data.isCtorCall())
226
2/4
✓ Branch 246 → 247 taken 1770 times.
✗ Branch 246 → 471 not taken.
✓ Branch 247 → 248 taken 1770 times.
✗ Branch 247 → 471 not taken.
1770 argTypes.push_back(builder.getPtrTy()); // This pointer
227
8/10
✓ Branch 250 → 251 taken 44 times.
✓ Branch 250 → 255 taken 2797 times.
✓ Branch 251 → 252 taken 44 times.
✗ Branch 251 → 477 not taken.
✓ Branch 252 → 253 taken 44 times.
✗ Branch 252 → 477 not taken.
✓ Branch 253 → 254 taken 16 times.
✓ Branch 253 → 255 taken 28 times.
✓ Branch 256 → 257 taken 16 times.
✓ Branch 256 → 260 taken 2825 times.
2841 if (data.isFctPtrCall() && firstFragEntry->getQualType().hasLambdaCaptures())
228
2/4
✓ Branch 257 → 258 taken 16 times.
✗ Branch 257 → 472 not taken.
✓ Branch 258 → 259 taken 16 times.
✗ Branch 258 → 472 not taken.
16 argTypes.push_back(builder.getPtrTy()); // Capture pointer
229
2/2
✓ Branch 267 → 262 taken 2723 times.
✓ Branch 267 → 268 taken 2841 times.
5564 for (const QualType &paramType : paramSTypes)
230
2/4
✓ Branch 263 → 264 taken 2723 times.
✗ Branch 263 → 473 not taken.
✓ Branch 264 → 265 taken 2723 times.
✗ Branch 264 → 473 not taken.
2723 argTypes.push_back(paramType.toLLVMType(sourceFile));
231
232
1/2
✓ Branch 269 → 270 taken 2841 times.
✗ Branch 269 → 475 not taken.
2841 fctType = llvm::FunctionType::get(returnType, argTypes, false);
233
7/8
✓ Branch 271 → 272 taken 2797 times.
✓ Branch 271 → 275 taken 44 times.
✓ Branch 272 → 273 taken 2797 times.
✗ Branch 272 → 477 not taken.
✓ Branch 273 → 274 taken 2779 times.
✓ Branch 273 → 275 taken 18 times.
✓ Branch 276 → 277 taken 2779 times.
✓ Branch 276 → 280 taken 62 times.
2841 if (!data.isFctPtrCall() && !data.isVirtualMethodCall())
234
1/2
✓ Branch 278 → 279 taken 2779 times.
✗ Branch 278 → 476 not taken.
2779 module->getOrInsertFunction(mangledName, fctType);
235 2841 }
236
1/2
✗ Branch 282 → 283 not taken.
✓ Branch 282 → 284 taken 16899 times.
16899 assert(fctType != nullptr);
237
238 llvm::CallInst *callInst;
239
3/4
✓ Branch 284 → 285 taken 16899 times.
✗ Branch 284 → 526 not taken.
✓ Branch 285 → 286 taken 18 times.
✓ Branch 285 → 318 taken 16881 times.
16899 if (data.isVirtualMethodCall()) {
240
1/2
✗ Branch 286 → 287 not taken.
✓ Branch 286 → 288 taken 18 times.
18 assert(data.callee->isVirtual);
241
1/2
✗ Branch 288 → 289 not taken.
✓ Branch 288 → 290 taken 18 times.
18 assert(thisPtr != nullptr);
242 // Load VTable
243
3/6
✓ Branch 292 → 293 taken 18 times.
✗ Branch 292 → 482 not taken.
✓ Branch 293 → 294 taken 18 times.
✗ Branch 293 → 480 not taken.
✓ Branch 294 → 295 taken 18 times.
✗ Branch 294 → 480 not taken.
18 llvm::Value *vtablePtr = insertLoad(builder.getPtrTy(), thisPtr, false, "vtable.addr");
244 18 const size_t vtableIndex = data.callee->vtableIndex;
245 // Lookup function pointer in VTable
246
4/8
✓ Branch 299 → 300 taken 18 times.
✗ Branch 299 → 490 not taken.
✓ Branch 300 → 301 taken 18 times.
✗ Branch 300 → 486 not taken.
✓ Branch 302 → 303 taken 18 times.
✗ Branch 302 → 486 not taken.
✓ Branch 303 → 304 taken 18 times.
✗ Branch 303 → 486 not taken.
36 fctPtr = insertInBoundsGEP(builder.getPtrTy(), vtablePtr, builder.getInt64(vtableIndex), "vfct.addr");
247
3/6
✓ Branch 308 → 309 taken 18 times.
✗ Branch 308 → 496 not taken.
✓ Branch 309 → 310 taken 18 times.
✗ Branch 309 → 494 not taken.
✓ Branch 310 → 311 taken 18 times.
✗ Branch 310 → 494 not taken.
18 llvm::Value *fct = insertLoad(builder.getPtrTy(), fctPtr, false, "fct");
248
249 // Generate function call
250
2/4
✓ Branch 313 → 314 taken 18 times.
✗ Branch 313 → 502 not taken.
✓ Branch 316 → 317 taken 18 times.
✗ Branch 316 → 500 not taken.
18 callInst = builder.CreateCall({fctType, fct}, argValues);
251
2/2
✓ Branch 319 → 320 taken 44 times.
✓ Branch 319 → 339 taken 16837 times.
16881 } else if (data.isFctPtrCall()) {
252
1/2
✗ Branch 320 → 321 not taken.
✓ Branch 320 → 322 taken 44 times.
44 assert(firstFragEntry != nullptr);
253
1/2
✓ Branch 322 → 323 taken 44 times.
✗ Branch 322 → 512 not taken.
44 QualType firstFragType = firstFragEntry->getQualType();
254
1/2
✗ Branch 323 → 324 not taken.
✓ Branch 323 → 326 taken 44 times.
44 if (!fctPtr)
255 fctPtr = firstFragEntry->getAddress();
256
1/2
✓ Branch 326 → 327 taken 44 times.
✗ Branch 326 → 512 not taken.
44 autoDeReferencePtr(fctPtr, firstFragType);
257
3/6
✓ Branch 329 → 330 taken 44 times.
✗ Branch 329 → 505 not taken.
✓ Branch 330 → 331 taken 44 times.
✗ Branch 330 → 503 not taken.
✓ Branch 331 → 332 taken 44 times.
✗ Branch 331 → 503 not taken.
44 llvm::Value *fct = insertLoad(builder.getPtrTy(), fctPtr, false, "fct");
258
259 // Generate function call
260
2/4
✓ Branch 334 → 335 taken 44 times.
✗ Branch 334 → 511 not taken.
✓ Branch 337 → 338 taken 44 times.
✗ Branch 337 → 509 not taken.
44 callInst = builder.CreateCall({fctType, fct}, argValues);
261 } else {
262 // Get callee function
263
1/2
✓ Branch 340 → 341 taken 16837 times.
✗ Branch 340 → 513 not taken.
16837 llvm::Function *callee = module->getFunction(mangledName);
264
1/2
✗ Branch 341 → 342 not taken.
✓ Branch 341 → 343 taken 16837 times.
16837 assert(callee != nullptr);
265
266 // Generate function call
267
3/6
✓ Branch 343 → 344 taken 16837 times.
✗ Branch 343 → 516 not taken.
✓ Branch 345 → 346 taken 16837 times.
✗ Branch 345 → 514 not taken.
✓ Branch 346 → 347 taken 16837 times.
✗ Branch 346 → 514 not taken.
16837 callInst = builder.CreateCall(callee, argValues);
268 }
269
270 // Set argument and return value attributes
271
2/2
✓ Branch 349 → 350 taken 16855 times.
✓ Branch 349 → 352 taken 44 times.
16899 if (!data.isFctPtrCall()) {
272
1/2
✓ Branch 350 → 351 taken 16855 times.
✗ Branch 350 → 526 not taken.
16855 setCallArgAttrs(callInst, spiceFunc, paramSTypes);
273
1/2
✓ Branch 351 → 352 taken 16855 times.
✗ Branch 351 → 526 not taken.
16855 setCallReturnValAttrs(callInst, returnSType);
274 }
275
276 // Attach address to anonymous symbol to keep track of de-allocation
277 16899 SymbolTableEntry *anonymousSymbol = nullptr;
278 16899 llvm::Value *resultPtr = nullptr;
279
7/8
✓ Branch 352 → 353 taken 16899 times.
✗ Branch 352 → 526 not taken.
✓ Branch 353 → 354 taken 15965 times.
✓ Branch 353 → 356 taken 934 times.
✓ Branch 355 → 356 taken 2344 times.
✓ Branch 355 → 357 taken 13621 times.
✓ Branch 358 → 359 taken 3278 times.
✓ Branch 358 → 373 taken 13621 times.
16899 if (returnSType.is(TY_STRUCT) || data.isCtorCall()) {
280
1/2
✓ Branch 359 → 360 taken 3278 times.
✗ Branch 359 → 526 not taken.
3278 anonymousSymbol = currentScope->symbolTable.lookupAnonymous(node);
281
2/2
✓ Branch 360 → 361 taken 261 times.
✓ Branch 360 → 373 taken 3017 times.
3278 if (anonymousSymbol != nullptr) {
282
2/2
✓ Branch 362 → 363 taken 181 times.
✓ Branch 362 → 364 taken 80 times.
261 if (data.isCtorCall()) {
283
1/2
✓ Branch 363 → 373 taken 181 times.
✗ Branch 363 → 526 not taken.
181 anonymousSymbol->updateAddress(thisPtr);
284 } else {
285
1/2
✓ Branch 368 → 369 taken 80 times.
✗ Branch 368 → 517 not taken.
80 resultPtr = insertAlloca(callInst->getType());
286
1/2
✓ Branch 371 → 372 taken 80 times.
✗ Branch 371 → 526 not taken.
80 insertStore(callInst, resultPtr);
287
1/2
✓ Branch 372 → 373 taken 80 times.
✗ Branch 372 → 526 not taken.
80 anonymousSymbol->updateAddress(resultPtr);
288 }
289 }
290 }
291
292 // In case this is a constructor call, return the thisPtr as pointer
293
2/2
✓ Branch 374 → 375 taken 2344 times.
✓ Branch 374 → 378 taken 14555 times.
16899 if (data.isCtorCall())
294
1/2
✓ Branch 375 → 376 taken 2344 times.
✗ Branch 375 → 523 not taken.
4688 return LLVMExprResult{.ptr = thisPtr, .refPtr = resultPtr, .entry = anonymousSymbol};
295
296 // In case this is a callee, returning a reference, return the address
297
3/4
✓ Branch 378 → 379 taken 14555 times.
✗ Branch 378 → 526 not taken.
✓ Branch 379 → 380 taken 682 times.
✓ Branch 379 → 383 taken 13873 times.
14555 if (returnSType.isRef())
298
1/2
✓ Branch 380 → 381 taken 682 times.
✗ Branch 380 → 524 not taken.
1364 return LLVMExprResult{.ptr = callInst, .refPtr = resultPtr, .entry = anonymousSymbol};
299
300 // Otherwise return the value
301
1/2
✓ Branch 383 → 384 taken 13873 times.
✗ Branch 383 → 525 not taken.
27746 return LLVMExprResult{.value = callInst, .ptr = resultPtr, .entry = anonymousSymbol};
302 16899 }
303
304 16855 void IRGenerator::setCallArgAttrs(llvm::CallInst *callInst, const Function *spiceFunc, const QualTypeList &paramSTypes) const {
305 16855 const bool isFctPtr = spiceFunc == nullptr;
306
3/4
✓ Branch 2 → 3 taken 16855 times.
✗ Branch 2 → 6 not taken.
✓ Branch 4 → 5 taken 8494 times.
✓ Branch 4 → 6 taken 8361 times.
16855 const bool isMethod = !isFctPtr && !spiceFunc->thisType.is(TY_DYN);
307
3/4
✓ Branch 7 → 8 taken 8361 times.
✓ Branch 7 → 9 taken 8494 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 11 taken 8361 times.
16855 const size_t expectedParamCount = isMethod || isFctPtr ? paramSTypes.size() + 1 : paramSTypes.size();
308
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 16855 times.
16855 assert(callInst->arg_size() == expectedParamCount);
309
2/2
✓ Branch 48 → 16 taken 31875 times.
✓ Branch 48 → 49 taken 16855 times.
48730 for (size_t i = 0; i < expectedParamCount; i++) {
310
8/10
✓ Branch 16 → 17 taken 16682 times.
✓ Branch 16 → 20 taken 15193 times.
✓ Branch 17 → 18 taken 8494 times.
✓ Branch 17 → 20 taken 8188 times.
✓ Branch 18 → 19 taken 8494 times.
✗ Branch 18 → 52 not taken.
✓ Branch 20 → 21 taken 6797 times.
✓ Branch 20 → 22 taken 16584 times.
✓ Branch 23 → 24 taken 23381 times.
✗ Branch 23 → 52 not taken.
31875 const QualType &paramType = i == 0 && isMethod ? spiceFunc->thisType.toPtr(nullptr) : paramSTypes.at(isMethod ? i - 1 : i);
311
312 // NoUndef attribute
313
1/2
✓ Branch 25 → 26 taken 31875 times.
✗ Branch 25 → 52 not taken.
31875 callInst->addParamAttr(i, llvm::Attribute::NoUndef);
314
315
3/4
✓ Branch 26 → 27 taken 31875 times.
✗ Branch 26 → 52 not taken.
✓ Branch 27 → 28 taken 11507 times.
✓ Branch 27 → 44 taken 20368 times.
31875 if (paramType.isPtr()) {
316 // NonNull attribute
317
4/4
✓ Branch 28 → 29 taken 10138 times.
✓ Branch 28 → 31 taken 1369 times.
✓ Branch 29 → 30 taken 8494 times.
✓ Branch 29 → 31 taken 1644 times.
11507 if (i == 0 && isMethod)
318
1/2
✓ Branch 30 → 31 taken 8494 times.
✗ Branch 30 → 52 not taken.
8494 callInst->addParamAttr(i, llvm::Attribute::NonNull);
319 // Dereferenceable attribute
320
2/4
✓ Branch 31 → 32 taken 11507 times.
✗ Branch 31 → 50 not taken.
✓ Branch 32 → 33 taken 11507 times.
✗ Branch 32 → 50 not taken.
11507 llvm::Type *pointeeType = paramType.getContained().toLLVMType(sourceFile);
321
1/2
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 11507 times.
11507 assert(pointeeType != nullptr);
322
4/8
✓ Branch 35 → 36 taken 11507 times.
✗ Branch 35 → 51 not taken.
✓ Branch 37 → 38 taken 11507 times.
✗ Branch 37 → 51 not taken.
✓ Branch 38 → 39 taken 11507 times.
✗ Branch 38 → 51 not taken.
✓ Branch 39 → 40 taken 11507 times.
✗ Branch 39 → 51 not taken.
11507 callInst->addDereferenceableParamAttr(i, callInst->getModule()->getDataLayout().getTypeStoreSize(pointeeType));
323 // Alignment attribute
324
3/6
✓ Branch 41 → 42 taken 11507 times.
✗ Branch 41 → 52 not taken.
✓ Branch 42 → 43 taken 11507 times.
✗ Branch 42 → 52 not taken.
✓ Branch 43 → 44 taken 11507 times.
✗ Branch 43 → 52 not taken.
11507 callInst->addParamAttr(i, llvm::Attribute::getWithAlignment(context, module->getDataLayout().getABITypeAlign(pointeeType)));
325 }
326
327 // ZExt or SExt attribute
328
3/4
✓ Branch 44 → 45 taken 31875 times.
✗ Branch 44 → 52 not taken.
✓ Branch 45 → 46 taken 6022 times.
✓ Branch 45 → 47 taken 25853 times.
31875 if (const llvm::Attribute::AttrKind extAttrKind = getExtAttrKindForType(paramType); extAttrKind != llvm::Attribute::None)
329
1/2
✓ Branch 46 → 47 taken 6022 times.
✗ Branch 46 → 52 not taken.
6022 callInst->addParamAttr(i, extAttrKind);
330 }
331 16855 }
332
333 16855 void IRGenerator::setCallReturnValAttrs(llvm::CallInst *callInst, const QualType &returnType) const {
334
2/2
✓ Branch 3 → 4 taken 6737 times.
✓ Branch 3 → 5 taken 10118 times.
16855 if (returnType.is(TY_DYN))
335 6737 return;
336
337 // NoUndef attribute
338 10118 callInst->addRetAttr(llvm::Attribute::NoUndef);
339 // ZExt or SExt attribute
340
2/2
✓ Branch 7 → 8 taken 2877 times.
✓ Branch 7 → 9 taken 7241 times.
10118 if (const llvm::Attribute::AttrKind extAttrKind = getExtAttrKindForType(returnType); extAttrKind != llvm::Attribute::None)
341 2877 callInst->addRetAttr(extAttrKind);
342 }
343
344 59 std::any IRGenerator::visitArrayInitialization(const ArrayInitializationNode *node) {
345 // Return immediately if the initialization is empty
346
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 59 times.
59 if (node->actualSize == 0)
347 return LLVMExprResult{.node = node};
348
349 // Visit array items
350 59 bool canBeConstant = true;
351 59 std::vector<LLVMExprResult> itemResults;
352
1/2
✓ Branch 6 → 7 taken 59 times.
✗ Branch 6 → 132 not taken.
59 itemResults.reserve(node->actualSize);
353
2/2
✓ Branch 16 → 9 taken 373 times.
✓ Branch 16 → 17 taken 59 times.
432 for (const AssignExprNode *itemNode : node->itemLst->args) {
354
2/4
✓ Branch 10 → 11 taken 373 times.
✗ Branch 10 → 94 not taken.
✓ Branch 11 → 12 taken 373 times.
✗ Branch 11 → 92 not taken.
373 auto item = std::any_cast<LLVMExprResult>(visit(itemNode));
355 373 canBeConstant &= item.constant != nullptr;
356 373 item.node = itemNode;
357
1/2
✓ Branch 13 → 14 taken 373 times.
✗ Branch 13 → 95 not taken.
373 itemResults.push_back(item);
358 }
359
360 // Get LLVM type of item and array
361
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 59 times.
59 assert(!itemResults.empty());
362
1/2
✓ Branch 21 → 22 taken 59 times.
✗ Branch 21 → 132 not taken.
59 const QualType &firstItemSTy = node->itemLst->args.front()->getEvaluatedSymbolType(manIdx);
363
1/2
✓ Branch 22 → 23 taken 59 times.
✗ Branch 22 → 132 not taken.
59 llvm::Type *itemType = firstItemSTy.toLLVMType(sourceFile);
364
1/2
✓ Branch 23 → 24 taken 59 times.
✗ Branch 23 → 132 not taken.
59 llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, node->actualSize);
365
366
2/2
✓ Branch 24 → 25 taken 57 times.
✓ Branch 24 → 50 taken 2 times.
59 if (canBeConstant) { // All items are constants, so we can create a global constant array
367 // Collect constants
368 57 std::vector<llvm::Constant *> constants;
369
2/2
✓ Branch 37 → 27 taken 368 times.
✓ Branch 37 → 38 taken 57 times.
425 for (const LLVMExprResult &exprResult : itemResults) {
370 // Delete potential constant globals, that were already created a layer below
371
2/2
✓ Branch 30 → 31 taken 22 times.
✓ Branch 30 → 34 taken 346 times.
368 if (exprResult.constant->getType()->isArrayTy())
372
3/6
✓ Branch 31 → 32 taken 22 times.
✗ Branch 31 → 97 not taken.
✓ Branch 32 → 33 taken 22 times.
✗ Branch 32 → 97 not taken.
✓ Branch 33 → 34 taken 22 times.
✗ Branch 33 → 97 not taken.
22 module->getNamedGlobal(exprResult.ptr->getName())->eraseFromParent();
373
1/2
✓ Branch 34 → 35 taken 368 times.
✗ Branch 34 → 97 not taken.
368 constants.push_back(exprResult.constant);
374 }
375
376 // Create global array
377
1/2
✓ Branch 39 → 40 taken 57 times.
✗ Branch 39 → 98 not taken.
57 llvm::Constant *constantArray = llvm::ConstantArray::get(arrayType, constants);
378
2/4
✓ Branch 42 → 43 taken 57 times.
✗ Branch 42 → 101 not taken.
✓ Branch 43 → 44 taken 57 times.
✗ Branch 43 → 99 not taken.
57 llvm::Value *arrayAddr = createGlobalConst(ANON_GLOBAL_ARRAY_NAME, constantArray);
379
380
1/2
✓ Branch 46 → 47 taken 57 times.
✗ Branch 46 → 105 not taken.
57 return LLVMExprResult{.constant = constantArray, .ptr = arrayAddr};
381 57 } else { // We have non-immediate values as items, so we need to take normal arrays as fallback
382
1/2
✓ Branch 53 → 54 taken 2 times.
✗ Branch 53 → 109 not taken.
2 llvm::Value *arrayAddr = insertAlloca(arrayType);
383
384 // Retrieve address of first item
385
2/4
✓ Branch 59 → 60 taken 2 times.
✗ Branch 59 → 115 not taken.
✓ Branch 61 → 62 taken 2 times.
✗ Branch 61 → 115 not taken.
2 llvm::Value *firstItemAddress = insertInBoundsGEP(arrayType, arrayAddr, builder.getInt64(0));
386
387 // Store all array items at their corresponding offsets
388 2 llvm::Value *currentItemAddress = firstItemAddress;
389
2/2
✓ Branch 84 → 65 taken 5 times.
✓ Branch 84 → 85 taken 2 times.
7 for (size_t i = 0; i < itemResults.size(); i++) {
390 5 LLVMExprResult &exprResult = itemResults[i];
391
1/2
✓ Branch 66 → 67 taken 5 times.
✗ Branch 66 → 132 not taken.
5 llvm::Value *itemValue = resolveValue(exprResult.node, exprResult);
392 // Retrieve current item address
393
2/2
✓ Branch 67 → 68 taken 3 times.
✓ Branch 67 → 77 taken 2 times.
5 if (i >= 1)
394
2/4
✓ Branch 71 → 72 taken 3 times.
✗ Branch 71 → 123 not taken.
✓ Branch 73 → 74 taken 3 times.
✗ Branch 73 → 123 not taken.
3 currentItemAddress = insertInBoundsGEP(itemType, currentItemAddress, builder.getInt64(1));
395 // Store the item value
396
3/4
✓ Branch 77 → 78 taken 3 times.
✓ Branch 77 → 80 taken 2 times.
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 3 times.
5 const bool storeVolatile = exprResult.entry != nullptr && exprResult.entry->isVolatile;
397
1/2
✓ Branch 81 → 82 taken 5 times.
✗ Branch 81 → 132 not taken.
5 insertStore(itemValue, currentItemAddress, storeVolatile);
398 }
399
400
1/2
✓ Branch 85 → 86 taken 2 times.
✗ Branch 85 → 131 not taken.
4 return LLVMExprResult{.ptr = arrayAddr};
401 }
402 59 }
403
404 282 std::any IRGenerator::visitStructInstantiation(const StructInstantiationNode *node) {
405 // Get struct object
406
1/2
✓ Branch 2 → 3 taken 282 times.
✗ Branch 2 → 138 not taken.
282 const Struct *spiceStruct = node->instantiatedStructs.at(manIdx);
407
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 282 times.
282 assert(spiceStruct != nullptr);
408 282 const QualTypeList &fieldTypes = spiceStruct->fieldTypes;
409
410 // Can only be constant if none of the fields is of type reference
411
1/2
✓ Branch 5 → 6 taken 282 times.
✗ Branch 5 → 138 not taken.
282 bool canBeConstant = !spiceStruct->hasReferenceFields();
412
413 // Get struct type
414
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 282 times.
282 assert(spiceStruct->entry != nullptr);
415
2/4
✓ Branch 8 → 9 taken 282 times.
✗ Branch 8 → 138 not taken.
✓ Branch 9 → 10 taken 282 times.
✗ Branch 9 → 138 not taken.
282 const auto structType = reinterpret_cast<llvm::StructType *>(spiceStruct->entry->getQualType().toLLVMType(sourceFile));
416
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 282 times.
282 assert(structType != nullptr);
417
418
2/2
✓ Branch 12 → 13 taken 11 times.
✓ Branch 12 → 18 taken 271 times.
282 if (!node->fieldLst) {
419
2/4
✓ Branch 13 → 14 taken 11 times.
✗ Branch 13 → 138 not taken.
✓ Branch 14 → 15 taken 11 times.
✗ Branch 14 → 138 not taken.
11 llvm::Constant *constantStruct = getDefaultValueForSymbolType(spiceStruct->entry->getQualType());
420
1/2
✓ Branch 15 → 16 taken 11 times.
✗ Branch 15 → 103 not taken.
22 return LLVMExprResult{.constant = constantStruct};
421 }
422
423 // Visit struct field values
424 271 std::vector<LLVMExprResult> fieldValueResults;
425
1/2
✓ Branch 19 → 20 taken 271 times.
✗ Branch 19 → 136 not taken.
271 fieldValueResults.reserve(spiceStruct->fieldTypes.size());
426
2/2
✓ Branch 29 → 22 taken 399 times.
✓ Branch 29 → 30 taken 271 times.
670 for (const AssignExprNode *fieldValueNode : node->fieldLst->args) {
427
2/4
✓ Branch 23 → 24 taken 399 times.
✗ Branch 23 → 106 not taken.
✓ Branch 24 → 25 taken 399 times.
✗ Branch 24 → 104 not taken.
399 auto fieldValue = std::any_cast<LLVMExprResult>(visit(fieldValueNode));
428 399 fieldValue.node = fieldValueNode;
429
1/2
✓ Branch 26 → 27 taken 399 times.
✗ Branch 26 → 107 not taken.
399 fieldValueResults.push_back(fieldValue);
430 399 canBeConstant &= fieldValue.constant != nullptr;
431 }
432
433
2/2
✓ Branch 30 → 31 taken 25 times.
✓ Branch 30 → 52 taken 246 times.
271 if (canBeConstant) { // All field values are constants, so we can create a global constant struct instantiation
434 // Collect constants
435 25 std::vector<llvm::Constant *> constants;
436 // For each interface a nullptr
437
1/2
✗ Branch 38 → 33 not taken.
✓ Branch 38 → 39 taken 25 times.
25 for (const QualType &interfaceType : spiceStruct->interfaceTypes)
438 constants.push_back(getDefaultValueForSymbolType(interfaceType));
439 // Constant value for each field
440
2/2
✓ Branch 45 → 41 taken 80 times.
✓ Branch 45 → 46 taken 25 times.
105 for (const LLVMExprResult &exprResult : fieldValueResults)
441
1/2
✓ Branch 42 → 43 taken 80 times.
✗ Branch 42 → 111 not taken.
80 constants.push_back(exprResult.constant);
442
443 // Create global constant struct
444
1/2
✓ Branch 47 → 48 taken 25 times.
✗ Branch 47 → 112 not taken.
25 llvm::Constant *constantStruct = llvm::ConstantStruct::get(structType, constants);
445
446
1/2
✓ Branch 48 → 49 taken 25 times.
✗ Branch 48 → 113 not taken.
25 return LLVMExprResult{.constant = constantStruct};
447 25 } else { // We have at least one non-immediate value, so we need to take normal struct instantiation as fallback
448
1/2
✓ Branch 55 → 56 taken 246 times.
✗ Branch 55 → 117 not taken.
246 llvm::Value *structAddr = insertAlloca(structType);
449 246 const size_t interfaceCount = spiceStruct->interfaceTypes.size();
450 246 const size_t fieldCount = spiceStruct->fieldTypes.size();
451 246 size_t i = 0;
452
453 // Store interface values at their corresponding offsets
454
1/2
✗ Branch 71 → 61 not taken.
✓ Branch 71 → 72 taken 246 times.
246 for (; i < interfaceCount; i++) {
455 const QualType &interfaceType = spiceStruct->interfaceTypes.at(i);
456 // Get field value
457 llvm::Value *itemValue = getDefaultValueForSymbolType(interfaceType);
458 // Get field address
459 llvm::Value *currentFieldAddress = insertStructGEP(structType, structAddr, i);
460 // Store the item value
461 insertStore(itemValue, currentFieldAddress);
462 }
463
464 // Store all field values at their corresponding offsets
465
2/2
✓ Branch 93 → 73 taken 319 times.
✓ Branch 93 → 94 taken 246 times.
565 for (; i < interfaceCount + fieldCount; i++) {
466
1/2
✓ Branch 73 → 74 taken 319 times.
✗ Branch 73 → 136 not taken.
319 LLVMExprResult &exprResult = fieldValueResults.at(i);
467 // Get field value
468
6/10
✓ Branch 74 → 75 taken 319 times.
✗ Branch 74 → 136 not taken.
✓ Branch 75 → 76 taken 319 times.
✗ Branch 75 → 136 not taken.
✓ Branch 76 → 77 taken 4 times.
✓ Branch 76 → 79 taken 315 times.
✓ Branch 77 → 78 taken 4 times.
✗ Branch 77 → 136 not taken.
✓ Branch 79 → 80 taken 315 times.
✗ Branch 79 → 136 not taken.
319 llvm::Value *itemValue = fieldTypes.at(i).isRef() ? resolveAddress(exprResult) : resolveValue(exprResult.node, exprResult);
469 // Get field address
470
1/2
✓ Branch 84 → 85 taken 319 times.
✗ Branch 84 → 129 not taken.
319 llvm::Value *currentFieldAddress = insertStructGEP(structType, structAddr, i);
471 // Store the item value
472
3/4
✓ Branch 87 → 88 taken 99 times.
✓ Branch 87 → 90 taken 220 times.
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 90 taken 99 times.
319 const bool storeVolatile = exprResult.entry != nullptr && exprResult.entry->isVolatile;
473
1/2
✓ Branch 91 → 92 taken 319 times.
✗ Branch 91 → 136 not taken.
319 insertStore(itemValue, currentFieldAddress, storeVolatile);
474 }
475
476 // Attach address to anonymous symbol to keep track of de-allocation
477
1/2
✓ Branch 94 → 95 taken 246 times.
✗ Branch 94 → 136 not taken.
246 SymbolTableEntry *returnSymbol = currentScope->symbolTable.lookupAnonymous(node);
478
2/2
✓ Branch 95 → 96 taken 8 times.
✓ Branch 95 → 97 taken 238 times.
246 if (returnSymbol != nullptr)
479
1/2
✓ Branch 96 → 97 taken 8 times.
✗ Branch 96 → 136 not taken.
8 returnSymbol->updateAddress(structAddr);
480
481
1/2
✓ Branch 97 → 98 taken 246 times.
✗ Branch 97 → 135 not taken.
492 return LLVMExprResult{.ptr = structAddr};
482 }
483 271 }
484
485 12 std::any IRGenerator::visitLambdaFunc(const LambdaFuncNode *node) {
486
2/4
✓ Branch 2 → 3 taken 12 times.
✗ Branch 2 → 232 not taken.
✓ Branch 3 → 4 taken 12 times.
✗ Branch 3 → 232 not taken.
12 Function spiceFunc = node->manifestations.at(manIdx);
487 12 ParamInfoList paramInfoList;
488 12 std::vector<llvm::Type *> paramTypes;
489
490 // Change scope
491
2/4
✓ Branch 4 → 5 taken 12 times.
✗ Branch 4 → 166 not taken.
✓ Branch 5 → 6 taken 12 times.
✗ Branch 5 → 164 not taken.
12 Scope *bodyScope = currentScope = currentScope->getChildScope(node->getScopeId());
492
493 // If there are captures, we pass them in a struct as the first function argument
494 12 const CaptureMap &captures = bodyScope->symbolTable.captures;
495 12 const bool hasCaptures = !captures.empty();
496 12 llvm::Type *capturesStructType = nullptr;
497
2/2
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 14 taken 8 times.
12 if (hasCaptures) {
498 // Create captures struct type
499
1/2
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 226 not taken.
4 capturesStructType = buildCapturesContainerType(captures);
500 // Add the captures struct as first parameter
501
1/2
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 167 not taken.
4 paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr);
502
2/4
✓ Branch 11 → 12 taken 4 times.
✗ Branch 11 → 168 not taken.
✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 168 not taken.
4 paramTypes.push_back(builder.getPtrTy()); // The capture struct is always passed as pointer
503 }
504
505 // Visit parameters
506 12 size_t argIdx = 0;
507
2/2
✓ Branch 14 → 15 taken 8 times.
✓ Branch 14 → 33 taken 4 times.
12 if (node->hasParams) {
508 8 const size_t numOfParams = spiceFunc.paramList.size();
509
1/2
✓ Branch 16 → 17 taken 8 times.
✗ Branch 16 → 226 not taken.
8 paramInfoList.reserve(numOfParams);
510
1/2
✓ Branch 17 → 18 taken 8 times.
✗ Branch 17 → 226 not taken.
8 paramTypes.reserve(numOfParams);
511
2/2
✓ Branch 32 → 19 taken 14 times.
✓ Branch 32 → 33 taken 8 times.
22 for (; argIdx < numOfParams; argIdx++) {
512
1/2
✓ Branch 19 → 20 taken 14 times.
✗ Branch 19 → 172 not taken.
14 const DeclStmtNode *param = node->paramLst->params.at(argIdx);
513 // Get symbol table entry of param
514
1/2
✓ Branch 20 → 21 taken 14 times.
✗ Branch 20 → 172 not taken.
14 SymbolTableEntry *paramSymbol = currentScope->lookupStrict(param->varName);
515
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 14 times.
14 assert(paramSymbol != nullptr);
516 // Retrieve type of param
517
3/6
✓ Branch 25 → 26 taken 14 times.
✗ Branch 25 → 171 not taken.
✓ Branch 26 → 27 taken 14 times.
✗ Branch 26 → 169 not taken.
✓ Branch 27 → 28 taken 14 times.
✗ Branch 27 → 169 not taken.
14 llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).toLLVMType(sourceFile);
518 // Add it to the lists
519
1/2
✓ Branch 29 → 30 taken 14 times.
✗ Branch 29 → 172 not taken.
14 paramInfoList.emplace_back(param->varName, paramSymbol);
520
1/2
✓ Branch 30 → 31 taken 14 times.
✗ Branch 30 → 172 not taken.
14 paramTypes.push_back(paramType);
521 }
522 }
523
524 // Get return type
525
1/2
✓ Branch 33 → 34 taken 12 times.
✗ Branch 33 → 226 not taken.
12 llvm::Type *returnType = spiceFunc.returnType.toLLVMType(sourceFile);
526
527 // Create function or implement declared function
528
2/4
✓ Branch 34 → 35 taken 12 times.
✗ Branch 34 → 175 not taken.
✓ Branch 35 → 36 taken 12 times.
✗ Branch 35 → 173 not taken.
12 spiceFunc.mangleSuffix = "." + std::to_string(manIdx);
529
1/2
✓ Branch 39 → 40 taken 12 times.
✗ Branch 39 → 226 not taken.
12 const std::string mangledName = spiceFunc.getMangledName();
530
1/2
✓ Branch 41 → 42 taken 12 times.
✗ Branch 41 → 177 not taken.
12 llvm::FunctionType *funcType = llvm::FunctionType::get(returnType, paramTypes, false);
531
1/2
✓ Branch 43 → 44 taken 12 times.
✗ Branch 43 → 178 not taken.
12 module->getOrInsertFunction(mangledName, funcType);
532
1/2
✓ Branch 45 → 46 taken 12 times.
✗ Branch 45 → 179 not taken.
12 llvm::Function *lambda = module->getFunction(mangledName);
533
534 // Set attributes to function
535
1/2
✓ Branch 46 → 47 taken 12 times.
✗ Branch 46 → 224 not taken.
12 lambda->setLinkage(llvm::Function::PrivateLinkage);
536 12 lambda->setDSOLocal(true);
537
1/2
✓ Branch 48 → 49 taken 12 times.
✗ Branch 48 → 224 not taken.
12 enableFunctionInstrumentation(lambda);
538
539 // In case of captures, add attribute to captures argument
540
2/2
✓ Branch 49 → 50 taken 4 times.
✓ Branch 49 → 55 taken 8 times.
12 if (hasCaptures) {
541
1/2
✓ Branch 50 → 51 taken 4 times.
✗ Branch 50 → 224 not taken.
4 lambda->addParamAttr(0, llvm::Attribute::NoUndef);
542
1/2
✓ Branch 51 → 52 taken 4 times.
✗ Branch 51 → 224 not taken.
4 lambda->addParamAttr(0, llvm::Attribute::NonNull);
543
2/4
✓ Branch 53 → 54 taken 4 times.
✗ Branch 53 → 224 not taken.
✓ Branch 54 → 55 taken 4 times.
✗ Branch 54 → 224 not taken.
4 lambda->addDereferenceableParamAttr(0, module->getDataLayout().getPointerSize());
544 }
545
546 // Add debug info
547
1/2
✓ Branch 55 → 56 taken 12 times.
✗ Branch 55 → 224 not taken.
12 diGenerator.generateFunctionDebugInfo(lambda, &spiceFunc, true);
548
1/2
✓ Branch 56 → 57 taken 12 times.
✗ Branch 56 → 224 not taken.
12 diGenerator.setSourceLocation(node);
549
550 // Save alloca insert markers
551 12 llvm::BasicBlock *allocaInsertBlockOrig = allocaInsertBlock;
552 12 llvm::AllocaInst *allocaInsertInstOrig = allocaInsertInst;
553 12 llvm::BasicBlock *bOrig = builder.GetInsertBlock();
554
555 // Create entry block
556
2/4
✓ Branch 60 → 61 taken 12 times.
✗ Branch 60 → 182 not taken.
✓ Branch 61 → 62 taken 12 times.
✗ Branch 61 → 180 not taken.
12 llvm::BasicBlock *bEntry = createBlock();
557
1/2
✓ Branch 64 → 65 taken 12 times.
✗ Branch 64 → 224 not taken.
12 switchToBlock(bEntry, lambda);
558
559 // Reset alloca insert markers to this block
560 12 allocaInsertBlock = bEntry;
561 12 allocaInsertInst = nullptr;
562
563 // Declare result variable
564
1/2
✓ Branch 67 → 68 taken 12 times.
✗ Branch 67 → 188 not taken.
36 SymbolTableEntry *resultEntry = currentScope->lookupStrict(RETURN_VARIABLE_NAME);
565
1/2
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 12 times.
12 assert(resultEntry != nullptr);
566
2/4
✓ Branch 77 → 78 taken 12 times.
✗ Branch 77 → 194 not taken.
✓ Branch 78 → 79 taken 12 times.
✗ Branch 78 → 192 not taken.
12 llvm::Value *resultAddr = insertAlloca(returnType, RETURN_VARIABLE_NAME);
567
1/2
✓ Branch 81 → 82 taken 12 times.
✗ Branch 81 → 224 not taken.
12 resultEntry->updateAddress(resultAddr);
568 // Generate debug info
569
2/4
✓ Branch 84 → 85 taken 12 times.
✗ Branch 84 → 200 not taken.
✓ Branch 85 → 86 taken 12 times.
✗ Branch 85 → 198 not taken.
24 diGenerator.generateLocalVarDebugInfo(RETURN_VARIABLE_NAME, resultAddr);
570
571 // Store function argument values
572 12 llvm::Value *captureStructPtrPtr = nullptr;
573
3/4
✓ Branch 88 → 89 taken 12 times.
✗ Branch 88 → 210 not taken.
✓ Branch 112 → 91 taken 18 times.
✓ Branch 112 → 113 taken 12 times.
30 for (auto &arg : lambda->args()) {
574 // Get parameter info
575 18 const size_t argNumber = arg.getArgNo();
576
2/4
✓ Branch 92 → 93 taken 18 times.
✗ Branch 92 → 209 not taken.
✓ Branch 93 → 94 taken 18 times.
✗ Branch 93 → 209 not taken.
18 auto [paramName, paramSymbol] = paramInfoList.at(argNumber);
577 // Allocate space for it
578
1/2
✓ Branch 96 → 97 taken 18 times.
✗ Branch 96 → 207 not taken.
18 llvm::Type *paramType = funcType->getParamType(argNumber);
579
2/4
✓ Branch 97 → 98 taken 18 times.
✗ Branch 97 → 206 not taken.
✓ Branch 98 → 99 taken 18 times.
✗ Branch 98 → 204 not taken.
18 llvm::Value *paramAddress = insertAlloca(paramType, paramName);
580 // Update the symbol table entry
581
4/4
✓ Branch 100 → 101 taken 6 times.
✓ Branch 100 → 103 taken 12 times.
✓ Branch 101 → 102 taken 4 times.
✓ Branch 101 → 103 taken 2 times.
18 const bool isCapturesStruct = hasCaptures && argNumber == 0;
582
2/2
✓ Branch 104 → 105 taken 4 times.
✓ Branch 104 → 106 taken 14 times.
18 if (isCapturesStruct)
583 4 captureStructPtrPtr = paramAddress;
584 else
585
1/2
✓ Branch 106 → 107 taken 14 times.
✗ Branch 106 → 207 not taken.
14 paramSymbol->updateAddress(paramAddress);
586 // Store the value at the new address
587
1/2
✓ Branch 107 → 108 taken 18 times.
✗ Branch 107 → 207 not taken.
18 insertStore(&arg, paramAddress);
588 // Generate debug info
589
2/2
✓ Branch 108 → 109 taken 14 times.
✓ Branch 108 → 110 taken 4 times.
18 if (!isCapturesStruct)
590
1/2
✓ Branch 109 → 110 taken 14 times.
✗ Branch 109 → 207 not taken.
14 diGenerator.generateLocalVarDebugInfo(paramName, paramAddress, argNumber + 1);
591 18 }
592
593 // Store the default values for optional function args
594
2/2
✓ Branch 113 → 114 taken 8 times.
✓ Branch 113 → 124 taken 4 times.
12 if (node->paramLst) {
595
1/2
✓ Branch 114 → 115 taken 8 times.
✗ Branch 114 → 214 not taken.
8 const std::vector<DeclStmtNode *> params = node->paramLst->params;
596
1/2
✗ Branch 121 → 116 not taken.
✓ Branch 121 → 122 taken 8 times.
8 for (; argIdx < params.size(); argIdx++)
597 visit(params.at(argIdx));
598 8 }
599
600 // Extract captures from captures struct
601
2/2
✓ Branch 124 → 125 taken 4 times.
✓ Branch 124 → 129 taken 8 times.
12 if (hasCaptures) {
602
1/2
✗ Branch 126 → 127 not taken.
✓ Branch 126 → 128 taken 4 times.
4 assert(!paramInfoList.empty());
603
1/2
✓ Branch 128 → 129 taken 4 times.
✗ Branch 128 → 224 not taken.
4 unpackCapturesToLocalVariables(captures, captureStructPtrPtr, capturesStructType);
604 }
605
606 // Visit body
607
1/2
✓ Branch 129 → 130 taken 12 times.
✗ Branch 129 → 215 not taken.
12 visit(node->body);
608
609 // Create return statement if the block is not terminated yet
610
1/2
✗ Branch 131 → 132 not taken.
✓ Branch 131 → 140 taken 12 times.
12 if (!blockAlreadyTerminated) {
611 llvm::Value *result = insertLoad(returnType, resultEntry->getAddress());
612 builder.CreateRet(result);
613 }
614
615 // Pop capture addresses
616
2/2
✓ Branch 140 → 141 taken 4 times.
✓ Branch 140 → 151 taken 8 times.
12 if (hasCaptures)
617
5/8
✓ Branch 141 → 142 taken 4 times.
✗ Branch 141 → 222 not taken.
✓ Branch 142 → 143 taken 4 times.
✗ Branch 142 → 222 not taken.
✓ Branch 143 → 144 taken 4 times.
✗ Branch 143 → 222 not taken.
✓ Branch 149 → 145 taken 6 times.
✓ Branch 149 → 150 taken 4 times.
10 for (const auto &capture : captures | std::views::values)
618
1/2
✓ Branch 146 → 147 taken 6 times.
✗ Branch 146 → 222 not taken.
6 capture.capturedSymbol->popAddress();
619
620 // Conclude debug info for function
621
1/2
✓ Branch 151 → 152 taken 12 times.
✗ Branch 151 → 224 not taken.
12 diGenerator.concludeFunctionDebugInfo();
622
1/2
✓ Branch 152 → 153 taken 12 times.
✗ Branch 152 → 224 not taken.
12 diGenerator.setSourceLocation(node);
623
624 // Restore alloca insert markers
625
1/2
✓ Branch 153 → 154 taken 12 times.
✗ Branch 153 → 224 not taken.
12 builder.SetInsertPoint(bOrig);
626 12 blockAlreadyTerminated = false;
627 12 allocaInsertBlock = allocaInsertBlockOrig;
628 12 allocaInsertInst = allocaInsertInstOrig;
629
630 // Change back to original scope
631 12 currentScope = currentScope->parent;
632
633 // Verify function
634
1/2
✓ Branch 154 → 155 taken 12 times.
✗ Branch 154 → 224 not taken.
12 verifyFunction(lambda, node->codeLoc);
635
636 // Captures, create a struct { <fct-ptr>, <capture struct ptr> }
637
1/2
✓ Branch 155 → 156 taken 12 times.
✗ Branch 155 → 224 not taken.
12 llvm::Value *result = buildFatFctPtr(bodyScope, capturesStructType, lambda);
638
639
1/2
✓ Branch 156 → 157 taken 12 times.
✗ Branch 156 → 223 not taken.
24 return LLVMExprResult{.ptr = result, .node = node};
640 12 }
641
642 19 std::any IRGenerator::visitLambdaProc(const LambdaProcNode *node) {
643
2/4
✓ Branch 2 → 3 taken 19 times.
✗ Branch 2 → 178 not taken.
✓ Branch 3 → 4 taken 19 times.
✗ Branch 3 → 178 not taken.
19 Function spiceFunc = node->manifestations.at(manIdx);
644 19 ParamInfoList paramInfoList;
645 19 std::vector<llvm::Type *> paramTypes;
646
647 // Change scope
648
2/4
✓ Branch 4 → 5 taken 19 times.
✗ Branch 4 → 136 not taken.
✓ Branch 5 → 6 taken 19 times.
✗ Branch 5 → 134 not taken.
19 Scope *bodyScope = currentScope = currentScope->getChildScope(node->getScopeId());
649
650 // If there are captures, we pass them in a struct as the first function argument
651 19 const CaptureMap &captures = bodyScope->symbolTable.captures;
652 19 const bool hasCaptures = !captures.empty();
653 19 llvm::Type *capturesStructType = nullptr;
654
2/2
✓ Branch 8 → 9 taken 10 times.
✓ Branch 8 → 14 taken 9 times.
19 if (hasCaptures) {
655 // Create captures struct type
656
1/2
✓ Branch 9 → 10 taken 10 times.
✗ Branch 9 → 172 not taken.
10 capturesStructType = buildCapturesContainerType(captures);
657 // Add the captures struct as first parameter
658
1/2
✓ Branch 10 → 11 taken 10 times.
✗ Branch 10 → 137 not taken.
10 paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr);
659
2/4
✓ Branch 11 → 12 taken 10 times.
✗ Branch 11 → 138 not taken.
✓ Branch 12 → 13 taken 10 times.
✗ Branch 12 → 138 not taken.
10 paramTypes.push_back(builder.getPtrTy()); // The captures struct is always passed as pointer
660 }
661
662 // Visit parameters
663 19 size_t argIdx = 0;
664
2/2
✓ Branch 14 → 15 taken 9 times.
✓ Branch 14 → 33 taken 10 times.
19 if (node->hasParams) {
665 9 const size_t numOfParams = spiceFunc.paramList.size();
666
1/2
✓ Branch 16 → 17 taken 9 times.
✗ Branch 16 → 172 not taken.
9 paramInfoList.reserve(numOfParams);
667
1/2
✓ Branch 17 → 18 taken 9 times.
✗ Branch 17 → 172 not taken.
9 paramTypes.reserve(numOfParams);
668
2/2
✓ Branch 32 → 19 taken 15 times.
✓ Branch 32 → 33 taken 9 times.
24 for (; argIdx < numOfParams; argIdx++) {
669
1/2
✓ Branch 19 → 20 taken 15 times.
✗ Branch 19 → 142 not taken.
15 const DeclStmtNode *param = node->paramLst->params.at(argIdx);
670 // Get symbol table entry of param
671
1/2
✓ Branch 20 → 21 taken 15 times.
✗ Branch 20 → 142 not taken.
15 SymbolTableEntry *paramSymbol = currentScope->lookupStrict(param->varName);
672
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 15 times.
15 assert(paramSymbol != nullptr);
673 // Retrieve type of param
674
3/6
✓ Branch 25 → 26 taken 15 times.
✗ Branch 25 → 141 not taken.
✓ Branch 26 → 27 taken 15 times.
✗ Branch 26 → 139 not taken.
✓ Branch 27 → 28 taken 15 times.
✗ Branch 27 → 139 not taken.
15 llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).toLLVMType(sourceFile);
675 // Add it to the lists
676
1/2
✓ Branch 29 → 30 taken 15 times.
✗ Branch 29 → 142 not taken.
15 paramInfoList.emplace_back(param->varName, paramSymbol);
677
1/2
✓ Branch 30 → 31 taken 15 times.
✗ Branch 30 → 142 not taken.
15 paramTypes.push_back(paramType);
678 }
679 }
680
681 // Create function or implement declared function
682
2/4
✓ Branch 33 → 34 taken 19 times.
✗ Branch 33 → 145 not taken.
✓ Branch 34 → 35 taken 19 times.
✗ Branch 34 → 143 not taken.
19 spiceFunc.mangleSuffix = "." + std::to_string(manIdx);
683
1/2
✓ Branch 38 → 39 taken 19 times.
✗ Branch 38 → 172 not taken.
19 const std::string mangledName = spiceFunc.getMangledName();
684
2/4
✓ Branch 40 → 41 taken 19 times.
✗ Branch 40 → 147 not taken.
✓ Branch 41 → 42 taken 19 times.
✗ Branch 41 → 147 not taken.
19 llvm::FunctionType *funcType = llvm::FunctionType::get(builder.getVoidTy(), paramTypes, false);
685
1/2
✓ Branch 43 → 44 taken 19 times.
✗ Branch 43 → 148 not taken.
19 module->getOrInsertFunction(mangledName, funcType);
686
1/2
✓ Branch 45 → 46 taken 19 times.
✗ Branch 45 → 149 not taken.
19 llvm::Function *lambda = module->getFunction(mangledName);
687
688 // Set attributes to function
689
1/2
✓ Branch 46 → 47 taken 19 times.
✗ Branch 46 → 170 not taken.
19 lambda->setLinkage(llvm::Function::PrivateLinkage);
690 19 lambda->setDSOLocal(true);
691
1/2
✓ Branch 48 → 49 taken 19 times.
✗ Branch 48 → 170 not taken.
19 enableFunctionInstrumentation(lambda);
692
693 // In case of captures, add attribute to captures argument
694
2/2
✓ Branch 49 → 50 taken 10 times.
✓ Branch 49 → 55 taken 9 times.
19 if (hasCaptures) {
695
1/2
✓ Branch 50 → 51 taken 10 times.
✗ Branch 50 → 170 not taken.
10 lambda->addParamAttr(0, llvm::Attribute::NoUndef);
696
1/2
✓ Branch 51 → 52 taken 10 times.
✗ Branch 51 → 170 not taken.
10 lambda->addParamAttr(0, llvm::Attribute::NonNull);
697
2/4
✓ Branch 53 → 54 taken 10 times.
✗ Branch 53 → 170 not taken.
✓ Branch 54 → 55 taken 10 times.
✗ Branch 54 → 170 not taken.
10 lambda->addDereferenceableParamAttr(0, module->getDataLayout().getPointerSize());
698 }
699
700 // Add debug info
701
1/2
✓ Branch 55 → 56 taken 19 times.
✗ Branch 55 → 170 not taken.
19 diGenerator.generateFunctionDebugInfo(lambda, &spiceFunc, true);
702
1/2
✓ Branch 56 → 57 taken 19 times.
✗ Branch 56 → 170 not taken.
19 diGenerator.setSourceLocation(node);
703
704 // Save alloca insert markers
705 19 llvm::BasicBlock *allocaInsertBlockOrig = allocaInsertBlock;
706 19 llvm::AllocaInst *allocaInsertInstOrig = allocaInsertInst;
707 19 llvm::BasicBlock *bOrig = builder.GetInsertBlock();
708
709 // Create entry block
710
2/4
✓ Branch 60 → 61 taken 19 times.
✗ Branch 60 → 152 not taken.
✓ Branch 61 → 62 taken 19 times.
✗ Branch 61 → 150 not taken.
19 llvm::BasicBlock *bEntry = createBlock();
711
1/2
✓ Branch 64 → 65 taken 19 times.
✗ Branch 64 → 170 not taken.
19 switchToBlock(bEntry, lambda);
712
713 // Reset alloca insert markers to this block
714 19 allocaInsertBlock = bEntry;
715 19 allocaInsertInst = nullptr;
716
717 // Save values of parameters to locals
718 19 llvm::Value *captureStructPtrPtr = nullptr;
719
3/4
✓ Branch 65 → 66 taken 19 times.
✗ Branch 65 → 162 not taken.
✓ Branch 89 → 68 taken 25 times.
✓ Branch 89 → 90 taken 19 times.
44 for (auto &arg : lambda->args()) {
720 // Get information about the parameter
721 25 const size_t argNumber = arg.getArgNo();
722
2/4
✓ Branch 69 → 70 taken 25 times.
✗ Branch 69 → 161 not taken.
✓ Branch 70 → 71 taken 25 times.
✗ Branch 70 → 161 not taken.
25 auto [paramName, paramSymbol] = paramInfoList.at(argNumber);
723 // Allocate space for it
724
1/2
✓ Branch 73 → 74 taken 25 times.
✗ Branch 73 → 159 not taken.
25 llvm::Type *paramType = funcType->getParamType(argNumber);
725
2/4
✓ Branch 74 → 75 taken 25 times.
✗ Branch 74 → 158 not taken.
✓ Branch 75 → 76 taken 25 times.
✗ Branch 75 → 156 not taken.
25 llvm::Value *paramAddress = insertAlloca(paramType, paramName);
726 // Update the symbol table entry
727
4/4
✓ Branch 77 → 78 taken 12 times.
✓ Branch 77 → 80 taken 13 times.
✓ Branch 78 → 79 taken 10 times.
✓ Branch 78 → 80 taken 2 times.
25 const bool isCapturesStruct = hasCaptures && argNumber == 0;
728
2/2
✓ Branch 81 → 82 taken 10 times.
✓ Branch 81 → 83 taken 15 times.
25 if (isCapturesStruct)
729 10 captureStructPtrPtr = paramAddress;
730 else
731
1/2
✓ Branch 83 → 84 taken 15 times.
✗ Branch 83 → 159 not taken.
15 paramSymbol->updateAddress(paramAddress);
732 // Store the value at the new address
733
1/2
✓ Branch 84 → 85 taken 25 times.
✗ Branch 84 → 159 not taken.
25 insertStore(&arg, paramAddress);
734 // Generate debug info
735
2/2
✓ Branch 85 → 86 taken 15 times.
✓ Branch 85 → 87 taken 10 times.
25 if (!isCapturesStruct)
736
1/2
✓ Branch 86 → 87 taken 15 times.
✗ Branch 86 → 159 not taken.
15 diGenerator.generateLocalVarDebugInfo(paramName, paramAddress, argNumber + 1);
737 25 }
738
739 // Store the default values for optional function args
740
2/2
✓ Branch 90 → 91 taken 9 times.
✓ Branch 90 → 101 taken 10 times.
19 if (node->paramLst) {
741
1/2
✓ Branch 91 → 92 taken 9 times.
✗ Branch 91 → 166 not taken.
9 const std::vector<DeclStmtNode *> params = node->paramLst->params;
742
1/2
✗ Branch 98 → 93 not taken.
✓ Branch 98 → 99 taken 9 times.
9 for (; argIdx < params.size(); argIdx++)
743 visit(params.at(argIdx));
744 9 }
745
746 // Extract captures from captures struct
747
2/2
✓ Branch 101 → 102 taken 10 times.
✓ Branch 101 → 106 taken 9 times.
19 if (hasCaptures) {
748
1/2
✗ Branch 103 → 104 not taken.
✓ Branch 103 → 105 taken 10 times.
10 assert(!paramInfoList.empty());
749
1/2
✓ Branch 105 → 106 taken 10 times.
✗ Branch 105 → 170 not taken.
10 unpackCapturesToLocalVariables(captures, captureStructPtrPtr, capturesStructType);
750 }
751
752 // Visit body
753
1/2
✓ Branch 106 → 107 taken 19 times.
✗ Branch 106 → 167 not taken.
19 visit(node->body);
754
755 // Create return statement if the block is not terminated yet
756
1/2
✓ Branch 108 → 109 taken 19 times.
✗ Branch 108 → 110 not taken.
19 if (!blockAlreadyTerminated)
757
1/2
✓ Branch 109 → 110 taken 19 times.
✗ Branch 109 → 170 not taken.
19 builder.CreateRetVoid();
758
759 // Pop capture addresses
760
2/2
✓ Branch 110 → 111 taken 10 times.
✓ Branch 110 → 121 taken 9 times.
19 if (hasCaptures)
761
5/8
✓ Branch 111 → 112 taken 10 times.
✗ Branch 111 → 168 not taken.
✓ Branch 112 → 113 taken 10 times.
✗ Branch 112 → 168 not taken.
✓ Branch 113 → 114 taken 10 times.
✗ Branch 113 → 168 not taken.
✓ Branch 119 → 115 taken 17 times.
✓ Branch 119 → 120 taken 10 times.
27 for (const auto &capture : captures | std::views::values)
762
1/2
✓ Branch 116 → 117 taken 17 times.
✗ Branch 116 → 168 not taken.
17 capture.capturedSymbol->popAddress();
763
764 // Conclude debug info for function
765
1/2
✓ Branch 121 → 122 taken 19 times.
✗ Branch 121 → 170 not taken.
19 diGenerator.concludeFunctionDebugInfo();
766
1/2
✓ Branch 122 → 123 taken 19 times.
✗ Branch 122 → 170 not taken.
19 diGenerator.setSourceLocation(node);
767
768 // Restore alloca insert markers
769
1/2
✓ Branch 123 → 124 taken 19 times.
✗ Branch 123 → 170 not taken.
19 builder.SetInsertPoint(bOrig);
770 19 blockAlreadyTerminated = false;
771 19 allocaInsertBlock = allocaInsertBlockOrig;
772 19 allocaInsertInst = allocaInsertInstOrig;
773
774 // Change back to original scope
775 19 currentScope = currentScope->parent;
776
777 // Verify function
778
1/2
✓ Branch 124 → 125 taken 19 times.
✗ Branch 124 → 170 not taken.
19 verifyFunction(lambda, node->codeLoc);
779
780 // Create a struct { <fct-ptr>, <capture struct ptr> }
781
1/2
✓ Branch 125 → 126 taken 19 times.
✗ Branch 125 → 170 not taken.
19 llvm::Value *result = buildFatFctPtr(bodyScope, capturesStructType, lambda);
782
783
1/2
✓ Branch 126 → 127 taken 19 times.
✗ Branch 126 → 169 not taken.
38 return LLVMExprResult{.ptr = result, .node = node};
784 19 }
785
786 1 std::any IRGenerator::visitLambdaExpr(const LambdaExprNode *node) {
787
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 168 not taken.
1 const Function &spiceFunc = node->manifestations.at(manIdx);
788 1 ParamInfoList paramInfoList;
789 1 std::vector<llvm::Type *> paramTypes;
790
791 // Change scope
792
2/4
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 133 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 131 not taken.
1 Scope *bodyScope = currentScope = currentScope->getChildScope(node->getScopeId());
793
794 // If there are captures, we pass them in a struct as the first function argument
795 1 const CaptureMap &captures = bodyScope->symbolTable.captures;
796 1 const bool hasCaptures = !captures.empty();
797 1 llvm::Type *capturesStructType = nullptr;
798
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 13 taken 1 time.
1 if (hasCaptures) {
799 // Create captures struct type
800 capturesStructType = buildCapturesContainerType(captures);
801 // Add the captures struct as first parameter
802 paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr);
803 paramTypes.push_back(builder.getPtrTy()); // The capture struct is always passed as pointer
804 }
805
806 // Visit parameters
807 1 size_t argIdx = 0;
808
1/2
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 32 not taken.
1 if (node->hasParams) {
809 1 const size_t numOfParams = spiceFunc.paramList.size();
810
1/2
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 164 not taken.
1 paramInfoList.reserve(numOfParams);
811
1/2
✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 164 not taken.
1 paramTypes.reserve(numOfParams);
812
2/2
✓ Branch 31 → 18 taken 2 times.
✓ Branch 31 → 32 taken 1 time.
3 for (; argIdx < numOfParams; argIdx++) {
813
1/2
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 139 not taken.
2 const DeclStmtNode *param = node->paramLst->params.at(argIdx);
814 // Get symbol table entry of param
815
1/2
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 139 not taken.
2 SymbolTableEntry *paramSymbol = currentScope->lookupStrict(param->varName);
816
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 2 times.
2 assert(paramSymbol != nullptr);
817 // Retrieve type of param
818
3/6
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 138 not taken.
✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 136 not taken.
✓ Branch 26 → 27 taken 2 times.
✗ Branch 26 → 136 not taken.
2 llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).toLLVMType(sourceFile);
819 // Add it to the lists
820
1/2
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 139 not taken.
2 paramInfoList.emplace_back(param->varName, paramSymbol);
821
1/2
✓ Branch 29 → 30 taken 2 times.
✗ Branch 29 → 139 not taken.
2 paramTypes.push_back(paramType);
822 }
823 }
824
825 // Get return type
826
2/4
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 164 not taken.
✓ Branch 33 → 34 taken 1 time.
✗ Branch 33 → 164 not taken.
1 llvm::Type *returnType = builder.getVoidTy();
827
1/2
✓ Branch 36 → 37 taken 1 time.
✗ Branch 36 → 39 not taken.
1 if (spiceFunc.isFunction())
828
1/2
✓ Branch 37 → 38 taken 1 time.
✗ Branch 37 → 164 not taken.
1 returnType = spiceFunc.returnType.toLLVMType(sourceFile);
829
830 // Create function or implement declared function
831
1/2
✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 164 not taken.
1 const std::string mangledName = spiceFunc.getMangledName();
832
1/2
✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 140 not taken.
1 llvm::FunctionType *funcType = llvm::FunctionType::get(returnType, paramTypes, false);
833
1/2
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 141 not taken.
1 module->getOrInsertFunction(mangledName, funcType);
834
1/2
✓ Branch 45 → 46 taken 1 time.
✗ Branch 45 → 142 not taken.
1 llvm::Function *lambda = module->getFunction(mangledName);
835
836 // Set attributes to function
837
1/2
✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 162 not taken.
1 lambda->setLinkage(llvm::Function::PrivateLinkage);
838 1 lambda->setDSOLocal(true);
839
1/2
✓ Branch 48 → 49 taken 1 time.
✗ Branch 48 → 162 not taken.
1 enableFunctionInstrumentation(lambda);
840
841 // In case of captures, add attribute to captures argument
842
1/2
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 55 taken 1 time.
1 if (hasCaptures) {
843 lambda->addParamAttr(0, llvm::Attribute::NoUndef);
844 lambda->addParamAttr(0, llvm::Attribute::NonNull);
845 lambda->addDereferenceableParamAttr(0, module->getDataLayout().getPointerSize());
846 }
847
848 // Add debug info
849
1/2
✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 162 not taken.
1 diGenerator.generateFunctionDebugInfo(lambda, &spiceFunc, true);
850
1/2
✓ Branch 56 → 57 taken 1 time.
✗ Branch 56 → 162 not taken.
1 diGenerator.setSourceLocation(node);
851
852 // Save alloca insert markers
853 1 llvm::BasicBlock *allocaInsertBlockOrig = allocaInsertBlock;
854 1 llvm::AllocaInst *allocaInsertInstOrig = allocaInsertInst;
855 1 llvm::BasicBlock *bOrig = builder.GetInsertBlock();
856
857 // Create entry block
858
2/4
✓ Branch 60 → 61 taken 1 time.
✗ Branch 60 → 145 not taken.
✓ Branch 61 → 62 taken 1 time.
✗ Branch 61 → 143 not taken.
1 llvm::BasicBlock *bEntry = createBlock();
859
1/2
✓ Branch 64 → 65 taken 1 time.
✗ Branch 64 → 162 not taken.
1 switchToBlock(bEntry, lambda);
860
861 // Reset alloca insert markers to this block
862 1 allocaInsertBlock = bEntry;
863 1 allocaInsertInst = nullptr;
864
865 // Save values of parameters to locals
866 1 llvm::Value *captureStructPtrPtr = nullptr;
867
3/4
✓ Branch 65 → 66 taken 1 time.
✗ Branch 65 → 155 not taken.
✓ Branch 89 → 68 taken 2 times.
✓ Branch 89 → 90 taken 1 time.
3 for (auto &arg : lambda->args()) {
868 // Get information about the parameter
869 2 const size_t argNumber = arg.getArgNo();
870
2/4
✓ Branch 69 → 70 taken 2 times.
✗ Branch 69 → 154 not taken.
✓ Branch 70 → 71 taken 2 times.
✗ Branch 70 → 154 not taken.
2 auto [paramName, paramSymbol] = paramInfoList.at(argNumber);
871 // Allocate space for it
872
1/2
✓ Branch 73 → 74 taken 2 times.
✗ Branch 73 → 152 not taken.
2 llvm::Type *paramType = funcType->getParamType(argNumber);
873
2/4
✓ Branch 74 → 75 taken 2 times.
✗ Branch 74 → 151 not taken.
✓ Branch 75 → 76 taken 2 times.
✗ Branch 75 → 149 not taken.
2 llvm::Value *paramAddress = insertAlloca(paramType, paramName);
874 // Update the symbol table entry
875
1/4
✗ Branch 77 → 78 not taken.
✓ Branch 77 → 80 taken 2 times.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
2 const bool isCapturesStruct = hasCaptures && argNumber == 0;
876
1/2
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 83 taken 2 times.
2 if (isCapturesStruct)
877 captureStructPtrPtr = paramAddress;
878 else
879
1/2
✓ Branch 83 → 84 taken 2 times.
✗ Branch 83 → 152 not taken.
2 paramSymbol->updateAddress(paramAddress);
880 // Store the value at the new address
881
1/2
✓ Branch 84 → 85 taken 2 times.
✗ Branch 84 → 152 not taken.
2 insertStore(&arg, paramAddress);
882 // Generate debug info
883
1/2
✓ Branch 85 → 86 taken 2 times.
✗ Branch 85 → 87 not taken.
2 if (!isCapturesStruct)
884
1/2
✓ Branch 86 → 87 taken 2 times.
✗ Branch 86 → 152 not taken.
2 diGenerator.generateLocalVarDebugInfo(paramName, paramAddress, argNumber + 1);
885 2 }
886
887 // Store the default values for optional function args
888
1/2
✓ Branch 90 → 91 taken 1 time.
✗ Branch 90 → 101 not taken.
1 if (node->paramLst) {
889
1/2
✓ Branch 91 → 92 taken 1 time.
✗ Branch 91 → 159 not taken.
1 const std::vector<DeclStmtNode *> params = node->paramLst->params;
890
1/2
✗ Branch 98 → 93 not taken.
✓ Branch 98 → 99 taken 1 time.
1 for (; argIdx < params.size(); argIdx++)
891 visit(params.at(argIdx));
892 1 }
893
894 // Extract captures from captures struct
895
1/2
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 106 taken 1 time.
1 if (hasCaptures) {
896 assert(!paramInfoList.empty());
897 unpackCapturesToLocalVariables(captures, captureStructPtrPtr, capturesStructType);
898 }
899
900 // Visit lambda expression
901
1/2
✓ Branch 106 → 107 taken 1 time.
✗ Branch 106 → 162 not taken.
1 llvm::Value *exprResult = resolveValue(node->lambdaExpr);
902
1/2
✓ Branch 107 → 108 taken 1 time.
✗ Branch 107 → 162 not taken.
1 builder.CreateRet(exprResult);
903
904 // Pop capture addresses
905
1/2
✗ Branch 108 → 109 not taken.
✓ Branch 108 → 119 taken 1 time.
1 if (hasCaptures)
906 for (const auto &val : captures | std::views::values)
907 val.capturedSymbol->popAddress();
908
909 // Conclude debug info for function
910
1/2
✓ Branch 119 → 120 taken 1 time.
✗ Branch 119 → 162 not taken.
1 diGenerator.concludeFunctionDebugInfo();
911
1/2
✓ Branch 120 → 121 taken 1 time.
✗ Branch 120 → 162 not taken.
1 diGenerator.setSourceLocation(node);
912
913 // Restore alloca insert markers
914
1/2
✓ Branch 121 → 122 taken 1 time.
✗ Branch 121 → 162 not taken.
1 builder.SetInsertPoint(bOrig);
915 1 blockAlreadyTerminated = false;
916 1 allocaInsertBlock = allocaInsertBlockOrig;
917 1 allocaInsertInst = allocaInsertInstOrig;
918
919 // Change back to original scope
920 1 currentScope = currentScope->parent;
921
922 // Verify function
923
1/2
✓ Branch 122 → 123 taken 1 time.
✗ Branch 122 → 162 not taken.
1 verifyFunction(lambda, node->codeLoc);
924 // Create a struct { <fct-ptr>, <capture struct ptr> }
925
1/2
✓ Branch 123 → 124 taken 1 time.
✗ Branch 123 → 162 not taken.
1 llvm::Value *result = buildFatFctPtr(bodyScope, capturesStructType, lambda);
926
927
1/2
✓ Branch 124 → 125 taken 1 time.
✗ Branch 124 → 161 not taken.
2 return LLVMExprResult{.ptr = result, .node = node};
928 1 }
929
930 2760 std::any IRGenerator::visitDataType(const DataTypeNode *node) {
931 // Only set the source location if this is not the root scope
932
6/8
✓ Branch 2 → 3 taken 1593 times.
✓ Branch 2 → 7 taken 1167 times.
✓ Branch 3 → 4 taken 1585 times.
✓ Branch 3 → 7 taken 8 times.
✓ Branch 4 → 5 taken 1585 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 1585 times.
✗ Branch 5 → 7 not taken.
2760 if (currentScope != rootScope && !node->isParamType && !node->isReturnType && !node->isFieldType)
933
1/2
✓ Branch 6 → 7 taken 1585 times.
✗ Branch 6 → 17 not taken.
1585 diGenerator.setSourceLocation(node);
934 // Retrieve symbol type
935
1/2
✓ Branch 7 → 8 taken 2760 times.
✗ Branch 7 → 17 not taken.
2760 const QualType symbolType = node->getEvaluatedSymbolType(manIdx);
936
2/4
✓ Branch 8 → 9 taken 2760 times.
✗ Branch 8 → 17 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2760 times.
2760 assert(!symbolType.is(TY_DYN)); // Symbol type should not be dyn anymore at this point
937
2/4
✓ Branch 11 → 12 taken 2760 times.
✗ Branch 11 → 16 not taken.
✓ Branch 12 → 13 taken 2760 times.
✗ Branch 12 → 16 not taken.
2760 return symbolType.toLLVMType(sourceFile);
938 }
939
940 40 llvm::Value *IRGenerator::buildFatFctPtr(Scope *bodyScope, llvm::Type *capturesStructType, llvm::Value *lambda) {
941 // Create capture struct if required
942 40 llvm::Value *capturesPtr = nullptr;
943
2/2
✓ Branch 2 → 3 taken 14 times.
✓ Branch 2 → 62 taken 26 times.
40 if (capturesStructType != nullptr) {
944
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 14 times.
14 assert(bodyScope != nullptr);
945 // If we have a single capture of ptr type, we can directly store it into the fat ptr. Otherwise, we need a stack allocated
946 // struct to store the captures in a memory-efficient manner and store a pointer to that struct to the fat ptr.
947
2/2
✓ Branch 6 → 7 taken 5 times.
✓ Branch 6 → 26 taken 9 times.
14 if (capturesStructType->isPointerTy()) {
948 5 const CaptureMap &captures = bodyScope->symbolTable.captures;
949
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 5 times.
5 assert(captures.size() == 1);
950 5 const Capture &capture = captures.begin()->second;
951
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 24 taken 5 times.
5 if (capture.getMode() == BY_VALUE) {
952 llvm::Type *varType = capture.capturedSymbol->getQualType().toLLVMType(sourceFile);
953 capturesPtr = insertLoad(varType, capture.capturedSymbol->getAddress());
954 } else {
955 5 capturesPtr = capture.capturedSymbol->getAddress();
956 }
957 } else {
958
2/4
✓ Branch 28 → 29 taken 9 times.
✗ Branch 28 → 103 not taken.
✓ Branch 29 → 30 taken 9 times.
✗ Branch 29 → 101 not taken.
9 capturesPtr = insertAlloca(capturesStructType, CAPTURES_PARAM_NAME);
959 9 size_t captureIdx = 0;
960
5/8
✓ Branch 32 → 33 taken 9 times.
✗ Branch 32 → 119 not taken.
✓ Branch 33 → 34 taken 9 times.
✗ Branch 33 → 119 not taken.
✓ Branch 34 → 35 taken 9 times.
✗ Branch 34 → 119 not taken.
✓ Branch 60 → 36 taken 18 times.
✓ Branch 60 → 61 taken 9 times.
27 for (const auto &capture : bodyScope->symbolTable.captures | std::views::values) {
961 18 const SymbolTableEntry *capturedEntry = capture.capturedSymbol;
962 // Get address or value of captured variable, depending on the capturing mode
963
1/2
✓ Branch 37 → 38 taken 18 times.
✗ Branch 37 → 119 not taken.
18 llvm::Value *capturedValue = capturedEntry->getAddress();
964
1/2
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 40 taken 18 times.
18 assert(capturedValue != nullptr);
965
3/4
✓ Branch 40 → 41 taken 18 times.
✗ Branch 40 → 119 not taken.
✓ Branch 41 → 42 taken 15 times.
✓ Branch 41 → 51 taken 3 times.
18 if (capture.getMode() == BY_VALUE) {
966
2/4
✓ Branch 42 → 43 taken 15 times.
✗ Branch 42 → 119 not taken.
✓ Branch 43 → 44 taken 15 times.
✗ Branch 43 → 119 not taken.
15 llvm::Type *captureType = capturedEntry->getQualType().toLLVMType(sourceFile);
967
2/4
✓ Branch 46 → 47 taken 15 times.
✗ Branch 46 → 109 not taken.
✓ Branch 47 → 48 taken 15 times.
✗ Branch 47 → 107 not taken.
30 capturedValue = insertLoad(captureType, capturedValue);
968 }
969 // Store it in the capture struct
970
1/2
✓ Branch 54 → 55 taken 18 times.
✗ Branch 54 → 113 not taken.
18 llvm::Value *captureAddress = insertStructGEP(capturesStructType, capturesPtr, captureIdx);
971
1/2
✓ Branch 57 → 58 taken 18 times.
✗ Branch 57 → 119 not taken.
18 insertStore(capturedValue, captureAddress);
972 18 captureIdx++;
973 }
974 }
975 }
976
977 // Create fat ptr struct type if not exists yet
978
2/2
✓ Branch 62 → 63 taken 18 times.
✓ Branch 62 → 68 taken 22 times.
40 if (!llvmTypes.fatPtrType)
979
3/6
✓ Branch 63 → 64 taken 18 times.
✗ Branch 63 → 120 not taken.
✓ Branch 64 → 65 taken 18 times.
✗ Branch 64 → 120 not taken.
✓ Branch 66 → 67 taken 18 times.
✗ Branch 66 → 120 not taken.
18 llvmTypes.fatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()});
980
981 // Create fat pointer
982
2/4
✓ Branch 70 → 71 taken 40 times.
✗ Branch 70 → 124 not taken.
✓ Branch 71 → 72 taken 40 times.
✗ Branch 71 → 122 not taken.
80 llvm::Value *fatFctPtr = insertAlloca(llvmTypes.fatPtrType, "fat.ptr");
983
1/2
✓ Branch 77 → 78 taken 40 times.
✗ Branch 77 → 128 not taken.
40 llvm::Value *fctPtr = insertStructGEP(llvmTypes.fatPtrType, fatFctPtr, 0);
984 40 insertStore(lambda, fctPtr);
985
1/2
✓ Branch 84 → 85 taken 40 times.
✗ Branch 84 → 134 not taken.
40 llvm::Value *capturePtr = insertStructGEP(llvmTypes.fatPtrType, fatFctPtr, 1);
986
2/2
✓ Branch 87 → 88 taken 26 times.
✓ Branch 87 → 91 taken 14 times.
40 insertStore(capturesPtr != nullptr ? capturesPtr : llvm::PoisonValue::get(builder.getPtrTy()), capturePtr);
987
988 40 return fatFctPtr;
989 }
990
991 14 llvm::Type *IRGenerator::buildCapturesContainerType(const CaptureMap &captures) const {
992
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 14 times.
14 assert(!captures.empty());
993
994 // If we have only one capture that is a ptr, we can just use that ptr type
995 14 const Capture &capture = captures.begin()->second;
996
10/14
✓ Branch 8 → 9 taken 5 times.
✓ Branch 8 → 15 taken 9 times.
✓ Branch 9 → 10 taken 5 times.
✗ Branch 9 → 48 not taken.
✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 48 not taken.
✓ Branch 11 → 12 taken 4 times.
✓ Branch 11 → 14 taken 1 time.
✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 48 not taken.
✓ Branch 13 → 14 taken 4 times.
✗ Branch 13 → 15 not taken.
✓ Branch 16 → 17 taken 5 times.
✓ Branch 16 → 19 taken 9 times.
14 if (captures.size() == 1 && (capture.capturedSymbol->getQualType().isPtr() || capture.getMode() == BY_REFERENCE))
997
1/2
✓ Branch 17 → 18 taken 5 times.
✗ Branch 17 → 48 not taken.
5 return builder.getPtrTy();
998
999 // Create captures struct type
1000 9 std::vector<llvm::Type *> captureTypes;
1001
5/8
✓ Branch 19 → 20 taken 9 times.
✗ Branch 19 → 44 not taken.
✓ Branch 20 → 21 taken 9 times.
✗ Branch 20 → 44 not taken.
✓ Branch 21 → 22 taken 9 times.
✗ Branch 21 → 44 not taken.
✓ Branch 35 → 23 taken 18 times.
✓ Branch 35 → 36 taken 9 times.
27 for (const auto &c : captures | std::views::values) {
1002
3/4
✓ Branch 24 → 25 taken 18 times.
✗ Branch 24 → 44 not taken.
✓ Branch 25 → 26 taken 15 times.
✓ Branch 25 → 30 taken 3 times.
18 if (c.getMode() == BY_VALUE)
1003
3/6
✓ Branch 26 → 27 taken 15 times.
✗ Branch 26 → 42 not taken.
✓ Branch 27 → 28 taken 15 times.
✗ Branch 27 → 42 not taken.
✓ Branch 28 → 29 taken 15 times.
✗ Branch 28 → 42 not taken.
15 captureTypes.push_back(c.capturedSymbol->getQualType().toLLVMType(sourceFile));
1004 else
1005
2/4
✓ Branch 30 → 31 taken 3 times.
✗ Branch 30 → 43 not taken.
✓ Branch 31 → 32 taken 3 times.
✗ Branch 31 → 43 not taken.
3 captureTypes.push_back(builder.getPtrTy());
1006 }
1007
1/2
✓ Branch 37 → 38 taken 9 times.
✗ Branch 37 → 45 not taken.
9 return llvm::StructType::get(context, captureTypes);
1008 9 }
1009
1010 14 void IRGenerator::unpackCapturesToLocalVariables(const CaptureMap &captures, llvm::Value *val, llvm::Type *structType) {
1011
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 14 times.
14 assert(!captures.empty());
1012 // If we have only one capture that is a ptr, we can just load the ptr
1013 14 const Capture &firstCapture = captures.begin()->second;
1014
7/8
✓ Branch 8 → 9 taken 5 times.
✓ Branch 8 → 15 taken 9 times.
✓ Branch 11 → 12 taken 4 times.
✓ Branch 11 → 14 taken 1 time.
✓ Branch 13 → 14 taken 4 times.
✗ Branch 13 → 15 not taken.
✓ Branch 16 → 17 taken 5 times.
✓ Branch 16 → 22 taken 9 times.
14 if (captures.size() == 1 && (firstCapture.capturedSymbol->getQualType().isPtr() || firstCapture.getMode() == BY_REFERENCE)) {
1015 // Interpret capturesPtr as ptr to the first and only capture
1016 5 llvm::Value *captureAddress = val;
1017 5 firstCapture.capturedSymbol->pushAddress(captureAddress);
1018 // Generate debug info
1019
2/4
✓ Branch 18 → 19 taken 5 times.
✗ Branch 18 → 53 not taken.
✓ Branch 19 → 20 taken 5 times.
✗ Branch 19 → 51 not taken.
5 diGenerator.generateLocalVarDebugInfo(firstCapture.getName(), captureAddress);
1020 } else {
1021 // Interpret capturesPtr as ptr to the captures struct
1022
3/6
✓ Branch 24 → 25 taken 9 times.
✗ Branch 24 → 56 not taken.
✓ Branch 25 → 26 taken 9 times.
✗ Branch 25 → 54 not taken.
✓ Branch 26 → 27 taken 9 times.
✗ Branch 26 → 54 not taken.
9 llvm::Value *capturesPtr = insertLoad(builder.getPtrTy(), val);
1023
1024 9 size_t captureIdx = 0;
1025
2/2
✓ Branch 48 → 31 taken 18 times.
✓ Branch 48 → 49 taken 9 times.
27 for (const auto &[name, capture] : captures) {
1026
5/8
✓ Branch 34 → 35 taken 18 times.
✗ Branch 34 → 68 not taken.
✓ Branch 35 → 36 taken 3 times.
✓ Branch 35 → 37 taken 15 times.
✓ Branch 36 → 38 taken 3 times.
✗ Branch 36 → 68 not taken.
✓ Branch 37 → 38 taken 15 times.
✗ Branch 37 → 68 not taken.
18 const std::string valueName = capture.getMode() == BY_REFERENCE ? name + ".addr" : name;
1027
2/4
✓ Branch 38 → 39 taken 18 times.
✗ Branch 38 → 62 not taken.
✓ Branch 39 → 40 taken 18 times.
✗ Branch 39 → 60 not taken.
18 llvm::Value *captureAddress = insertStructGEP(structType, capturesPtr, captureIdx, valueName);
1028
1/2
✓ Branch 41 → 42 taken 18 times.
✗ Branch 41 → 66 not taken.
18 capture.capturedSymbol->pushAddress(captureAddress);
1029 // Generate debug info
1030
2/4
✓ Branch 42 → 43 taken 18 times.
✗ Branch 42 → 65 not taken.
✓ Branch 43 → 44 taken 18 times.
✗ Branch 43 → 63 not taken.
18 diGenerator.generateLocalVarDebugInfo(capture.getName(), captureAddress);
1031 18 captureIdx++;
1032 18 }
1033 }
1034 14 }
1035
1036 } // namespace spice::compiler
1037