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