GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenValues.cpp
Date: 2025-03-05 01:50:32
Exec Total Coverage
Lines: 552 575 96.0%
Functions: 13 13 100.0%
Branches: 703 1250 56.2%

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