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 ¶mType : 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 |