GCC Code Coverage Report


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