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