GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenValues.cpp
Date: 2025-12-19 06:54:40
Coverage Exec Excl Total
Lines: 96.2% 580 1 604
Functions: 100.0% 15 0 15
Branches: 56.8% 738 4 1304

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