GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenValues.cpp
Date: 2025-11-04 23:06:20
Coverage Exec Excl Total
Lines: 96.0% 555 1 579
Functions: 100.0% 13 0 13
Branches: 56.2% 706 4 1260

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