Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | /// @file codegen/ComputeGenerator.cc | ||
5 | |||
6 | #include "ComputeGenerator.h" | ||
7 | #include "FunctionRegistry.h" | ||
8 | #include "FunctionTypes.h" | ||
9 | #include "Types.h" | ||
10 | #include "Utils.h" | ||
11 | |||
12 | #include "../ast/AST.h" | ||
13 | #include "../ast/Tokens.h" | ||
14 | #include "../compiler/CustomData.h" | ||
15 | #include "../Exceptions.h" | ||
16 | |||
17 | #include <llvm/ADT/SmallVector.h> | ||
18 | #include <llvm/IR/CallingConv.h> | ||
19 | #include <llvm/IR/Constants.h> | ||
20 | #include <llvm/IR/DerivedTypes.h> | ||
21 | #include <llvm/IR/GlobalVariable.h> | ||
22 | #include <llvm/IR/InlineAsm.h> | ||
23 | #include <llvm/IR/Instructions.h> | ||
24 | #include <llvm/IR/Intrinsics.h> | ||
25 | #include <llvm/Pass.h> | ||
26 | #include <llvm/Support/MathExtras.h> | ||
27 | #include <llvm/Support/raw_os_ostream.h> | ||
28 | #include <llvm/Transforms/Utils/BuildLibCalls.h> | ||
29 | |||
30 | namespace openvdb { | ||
31 | OPENVDB_USE_VERSION_NAMESPACE | ||
32 | namespace OPENVDB_VERSION_NAME { | ||
33 | |||
34 | namespace ax { | ||
35 | namespace codegen { | ||
36 | |||
37 | namespace { | ||
38 | |||
39 | inline void | ||
40 | ✗ | printType(const llvm::Type* type, llvm::raw_os_ostream& stream, const bool axTypes) | |
41 | { | ||
42 | const ast::tokens::CoreType token = | ||
43 | ✗ | axTypes ? tokenFromLLVMType(type) : ast::tokens::UNKNOWN; | |
44 | ✗ | if (token == ast::tokens::UNKNOWN) type->print(stream); | |
45 | ✗ | else stream << ast::tokens::typeStringFromToken(token); | |
46 | } | ||
47 | |||
48 | inline void | ||
49 | ✗ | printTypes(llvm::raw_os_ostream& stream, | |
50 | const std::vector<llvm::Type*>& types, | ||
51 | const std::vector<const char*>& names = {}, | ||
52 | const std::string sep = "; ", | ||
53 | const bool axTypes = true) | ||
54 | { | ||
55 | ✗ | if (types.empty()) return; | |
56 | ✗ | auto typeIter = types.cbegin(); | |
57 | ✗ | std::vector<const char*>::const_iterator nameIter; | |
58 | ✗ | if (!names.empty()) nameIter = names.cbegin(); | |
59 | |||
60 | ✗ | for (; typeIter != types.cend() - 1; ++typeIter) { | |
61 | ✗ | printType(*typeIter, stream, axTypes); | |
62 | ✗ | if (!names.empty() && nameIter != names.cend()) { | |
63 | ✗ | if (*nameIter && (*nameIter)[0] != '\0') { | |
64 | ✗ | stream << ' ' << *nameIter; | |
65 | } | ||
66 | ++nameIter; | ||
67 | } | ||
68 | ✗ | stream << sep; | |
69 | } | ||
70 | |||
71 | ✗ | printType(*typeIter, stream, axTypes); | |
72 | ✗ | if (!names.empty() && nameIter != names.cend()) { | |
73 | ✗ | if (*nameIter && (*nameIter)[0] != '\0') { | |
74 | ✗ | stream << ' ' << *nameIter; | |
75 | } | ||
76 | } | ||
77 | } | ||
78 | |||
79 | } | ||
80 | |||
81 | const std::array<std::string, ComputeKernel::N_ARGS>& | ||
82 | 281 | ComputeKernel::getArgumentKeys() | |
83 | { | ||
84 | static const std::array<std::string, ComputeKernel::N_ARGS> arguments = { | ||
85 | { "custom_data" } | ||
86 |
4/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 280 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
281 | }; |
87 | |||
88 | 281 | return arguments; | |
89 | } | ||
90 | |||
91 | 562 | std::string ComputeKernel::getDefaultName() { return "ax.compute"; } | |
92 | |||
93 | |||
94 | /////////////////////////////////////////////////////////////////////////// | ||
95 | /////////////////////////////////////////////////////////////////////////// | ||
96 | |||
97 | namespace codegen_internal { | ||
98 | |||
99 | 1816 | ComputeGenerator::ComputeGenerator(llvm::Module& module, | |
100 | const FunctionOptions& options, | ||
101 | FunctionRegistry& functionRegistry, | ||
102 | 1816 | Logger& logger) | |
103 | : mModule(module) | ||
104 | , mContext(module.getContext()) | ||
105 | , mBuilder(module.getContext()) | ||
106 | , mValues() | ||
107 | , mBreakContinueStack() | ||
108 | , mScopeIndex(1) | ||
109 | , mSymbolTables() | ||
110 | , mFunction(nullptr) | ||
111 | , mOptions(options) | ||
112 | , mLog(logger) | ||
113 |
2/4✓ Branch 1 taken 1816 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1816 times.
✗ Branch 5 not taken.
|
3632 | , mFunctionRegistry(functionRegistry) {} |
114 | |||
115 | 281 | bool ComputeGenerator::generate(const ast::Tree& tree) | |
116 | { | ||
117 | llvm::FunctionType* type = | ||
118 | 281 | llvmFunctionTypeFromSignature<ComputeKernel::Signature>(mContext); | |
119 | |||
120 |
1/2✓ Branch 2 taken 281 times.
✗ Branch 3 not taken.
|
281 | mFunction = llvm::Function::Create(type, |
121 | llvm::Function::ExternalLinkage, | ||
122 | 562 | ComputeKernel::getDefaultName(), | |
123 | 281 | &mModule); | |
124 | |||
125 | // Set up arguments for initial entry | ||
126 | |||
127 |
1/2✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
|
281 | llvm::Function::arg_iterator argIter = mFunction->arg_begin(); |
128 | 281 | const auto arguments = ComputeKernel::getArgumentKeys(); | |
129 | auto keyIter = arguments.cbegin(); | ||
130 | |||
131 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 562 times.
✓ Branch 2 taken 281 times.
✓ Branch 3 taken 281 times.
|
562 | for (; argIter != mFunction->arg_end(); ++argIter, ++keyIter) { |
132 |
1/2✓ Branch 2 taken 281 times.
✗ Branch 3 not taken.
|
281 | argIter->setName(*keyIter); |
133 | } | ||
134 | |||
135 |
1/2✓ Branch 2 taken 281 times.
✗ Branch 3 not taken.
|
281 | llvm::BasicBlock* entry = llvm::BasicBlock::Create(mContext, |
136 |
3/8✓ Branch 1 taken 281 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 281 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 281 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
562 | "entry_" + ComputeKernel::getDefaultName(), mFunction); |
137 | mBuilder.SetInsertPoint(entry); | ||
138 | |||
139 | // if traverse is false, log should have error, but can error | ||
140 | // without stopping traversal, so check both | ||
141 |
1/2✓ Branch 1 taken 281 times.
✗ Branch 2 not taken.
|
281 | const size_t err = mLog.errors(); |
142 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 281 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
281 | if (!this->traverse(&tree) || (mLog.errors() > err)) return false; |
143 | |||
144 | // free strings at terminating blocks | ||
145 | |||
146 | ✗ | this->createFreeSymbolStrings(mBuilder); | |
147 | |||
148 | return true; | ||
149 | } | ||
150 | |||
151 | 2395 | bool ComputeGenerator::visit(const ast::Block* block) | |
152 | { | ||
153 | 2395 | mScopeIndex++; | |
154 | |||
155 | // traverse the contents of the block | ||
156 | const size_t children = block->children(); | ||
157 | |||
158 |
2/2✓ Branch 0 taken 15552 times.
✓ Branch 1 taken 2103 times.
|
17655 | for (size_t i = 0; i < children; ++i) { |
159 |
4/4✓ Branch 1 taken 299 times.
✓ Branch 2 taken 15244 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 283 times.
|
15552 | if (!this->traverse(block->child(i)) && mLog.atErrorLimit()) { |
160 | return false; | ||
161 | } | ||
162 | // reset the value stack for each statement | ||
163 | 15260 | mValues = std::stack<llvm::Value*>(); | |
164 | } | ||
165 | |||
166 | 2103 | mSymbolTables.erase(mScopeIndex); | |
167 | 2103 | mScopeIndex--; | |
168 | 2103 | return true; | |
169 | } | ||
170 | |||
171 | 178 | bool ComputeGenerator::visit(const ast::CommaOperator* comma) | |
172 | { | ||
173 | // traverse the contents of the comma expression | ||
174 | const size_t children = comma->children(); | ||
175 | 178 | llvm::Value* value = nullptr; | |
176 | bool hasErrored = false; | ||
177 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 176 times.
|
627 | for (size_t i = 0; i < children; ++i) { |
178 |
2/2✓ Branch 1 taken 449 times.
✓ Branch 2 taken 2 times.
|
451 | if (this->traverse(comma->child(i))) { |
179 |
1/2✓ Branch 0 taken 449 times.
✗ Branch 1 not taken.
|
449 | value = mValues.top(); mValues.pop(); |
180 | } | ||
181 | else { | ||
182 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (mLog.atErrorLimit()) return false; |
183 | hasErrored = true; | ||
184 | } | ||
185 | } | ||
186 | // only keep the last value | ||
187 |
2/4✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 176 times.
✗ Branch 3 not taken.
|
176 | if (!value || hasErrored) return false; |
188 | mValues.push(value); | ||
189 | return true; | ||
190 | } | ||
191 | |||
192 | 173 | bool ComputeGenerator::visit(const ast::ConditionalStatement* cond) | |
193 | { | ||
194 | 173 | llvm::BasicBlock* postIfBlock = llvm::BasicBlock::Create(mContext, "block", mFunction); | |
195 |
2/2✓ Branch 2 taken 50 times.
✓ Branch 3 taken 123 times.
|
173 | llvm::BasicBlock* thenBlock = llvm::BasicBlock::Create(mContext, "then", mFunction); |
196 | const bool hasElse = cond->hasFalse(); | ||
197 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 123 times.
|
173 | llvm::BasicBlock* elseBlock = hasElse ? llvm::BasicBlock::Create(mContext, "else", mFunction) : postIfBlock; |
198 | |||
199 | // generate conditional | ||
200 |
2/2✓ Branch 1 taken 171 times.
✓ Branch 2 taken 2 times.
|
173 | if (this->traverse(cond->condition())) { |
201 |
1/2✓ Branch 0 taken 171 times.
✗ Branch 1 not taken.
|
171 | llvm::Value* condition = mValues.top(); mValues.pop(); |
202 | |||
203 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 149 times.
|
171 | if (condition->getType()->isPointerTy()) { |
204 | 22 | condition = mBuilder.CreateLoad(condition); | |
205 | } | ||
206 | llvm::Type* conditionType = condition->getType(); | ||
207 | // check the type of the condition branch is bool-convertable | ||
208 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 153 times.
|
171 | if (conditionType->isFloatingPointTy() || conditionType->isIntegerTy()) { |
209 | 153 | condition = boolComparison(condition, mBuilder); | |
210 | 153 | mBuilder.CreateCondBr(condition, thenBlock, elseBlock); | |
211 | } else { | ||
212 |
4/6✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 12 times.
|
36 | if (!mLog.error("cannot convert non-scalar type to bool in condition", cond->condition())) return false; |
213 | } | ||
214 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | } else if (mLog.atErrorLimit()) return false; |
215 | |||
216 | // generate if-then branch | ||
217 | mBuilder.SetInsertPoint(thenBlock); | ||
218 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!this->traverse(cond->trueBranch()) && mLog.atErrorLimit()) return false; |
219 | 159 | mBuilder.CreateBr(postIfBlock); | |
220 | |||
221 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 109 times.
|
159 | if (hasElse) { |
222 | // generate else-then branch | ||
223 | mBuilder.SetInsertPoint(elseBlock); | ||
224 | ✗ | if (!this->traverse(cond->falseBranch()) && mLog.atErrorLimit()) return false; | |
225 | 50 | mBuilder.CreateBr(postIfBlock); | |
226 | } | ||
227 | |||
228 | // reset to continue block | ||
229 | mBuilder.SetInsertPoint(postIfBlock); | ||
230 | |||
231 | // reset the value stack | ||
232 | 159 | mValues = std::stack<llvm::Value*>(); | |
233 | |||
234 | 159 | return true; | |
235 | } | ||
236 | |||
237 | 184 | bool ComputeGenerator::visit(const ast::TernaryOperator* tern) | |
238 | { | ||
239 | 184 | llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(mContext, "ternary_true", mFunction); | |
240 | 184 | llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(mContext, "ternary_false", mFunction); | |
241 | 184 | llvm::BasicBlock* returnBlock = llvm::BasicBlock::Create(mContext, "ternary_return", mFunction); | |
242 | |||
243 | llvm::Value* trueValue = nullptr; | ||
244 | llvm::Type* trueType = nullptr; | ||
245 | bool truePtr = false; | ||
246 | // generate conditional | ||
247 | 184 | bool conditionSuccess = this->traverse(tern->condition()); | |
248 |
2/2✓ Branch 0 taken 179 times.
✓ Branch 1 taken 5 times.
|
184 | if (conditionSuccess) { |
249 | // get the condition | ||
250 |
1/2✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
|
179 | trueValue = mValues.top(); mValues.pop(); |
251 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 179 times.
|
179 | assert(trueValue); |
252 | |||
253 | trueType = trueValue->getType(); | ||
254 | truePtr = trueType->isPointerTy(); | ||
255 | |||
256 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 140 times.
|
179 | llvm::Type* conditionType = truePtr ? trueType->getPointerElementType() : trueType; |
257 | llvm::Value* boolCondition = nullptr; | ||
258 | // check the type of the condition branch is bool-convertable | ||
259 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 162 times.
|
179 | if (conditionType->isFloatingPointTy() || conditionType->isIntegerTy()) { |
260 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 140 times.
|
162 | boolCondition = truePtr ? |
261 | 162 | boolComparison(mBuilder.CreateLoad(trueValue), mBuilder) : boolComparison(trueValue, mBuilder); | |
262 | 162 | mBuilder.CreateCondBr(boolCondition, trueBlock, falseBlock); | |
263 | } | ||
264 | else { | ||
265 |
4/6✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 14 times.
|
34 | if (!mLog.error("cannot convert non-scalar type to bool in condition", tern->condition())) return false; |
266 | conditionSuccess = false; | ||
267 | } | ||
268 | } | ||
269 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
|
5 | else if (mLog.atErrorLimit()) return false; |
270 | |||
271 | // generate true branch, if it exists otherwise take condition as true value | ||
272 | |||
273 |
2/2✓ Branch 0 taken 152 times.
✓ Branch 1 taken 14 times.
|
166 | mBuilder.SetInsertPoint(trueBlock); |
274 | bool trueSuccess = conditionSuccess; | ||
275 |
2/2✓ Branch 0 taken 152 times.
✓ Branch 1 taken 14 times.
|
166 | if (tern->hasTrue()) { |
276 | 152 | trueSuccess = this->traverse(tern->trueBranch()); | |
277 |
2/2✓ Branch 0 taken 149 times.
✓ Branch 1 taken 3 times.
|
152 | if (trueSuccess) { |
278 |
1/2✓ Branch 0 taken 149 times.
✗ Branch 1 not taken.
|
149 | trueValue = mValues.top(); mValues.pop();// get true value from true expression |
279 | // update true type details | ||
280 | trueType = trueValue->getType(); | ||
281 | } | ||
282 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | else if (mLog.atErrorLimit()) return false; |
283 | } | ||
284 | |||
285 | 163 | llvm::BranchInst* trueBranch = mBuilder.CreateBr(returnBlock); | |
286 | |||
287 | // generate false branch | ||
288 | |||
289 | mBuilder.SetInsertPoint(falseBlock); | ||
290 | 163 | bool falseSuccess = this->traverse(tern->falseBranch()); | |
291 | // even if the condition isnt successful but the others are, we continue to code gen to find type errors in branches | ||
292 |
2/2✓ Branch 0 taken 159 times.
✓ Branch 1 taken 4 times.
|
163 | if (!(trueSuccess && falseSuccess)) return false; |
293 | |||
294 | 159 | llvm::BranchInst* falseBranch = mBuilder.CreateBr(returnBlock); | |
295 | |||
296 |
1/2✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
|
159 | llvm::Value* falseValue = mValues.top(); mValues.pop(); |
297 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 159 times.
|
159 | llvm::Type* falseType = falseValue->getType(); |
298 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 159 times.
|
159 | assert(trueType); |
299 | // if both variables of same type do no casting or loading | ||
300 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 69 times.
|
159 | if (trueType != falseType) { |
301 | // get the (contained) types of the expressions | ||
302 | truePtr = trueType->isPointerTy(); | ||
303 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 43 times.
|
90 | if (truePtr) trueType = trueType->getPointerElementType(); |
304 | |||
305 | const bool falsePtr = falseType->isPointerTy(); | ||
306 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 47 times.
|
90 | if (falsePtr) falseType = falseType->getPointerElementType(); |
307 | |||
308 | // if same contained type but one needs loading | ||
309 | // can only have one pointer, one not, for scalars right now, i.e. no loaded arrays or strings | ||
310 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 78 times.
|
90 | if (trueType == falseType) { |
311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | assert(!(truePtr && falsePtr)); |
312 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
|
12 | if (truePtr) { |
313 | 8 | mBuilder.SetInsertPoint(trueBranch); | |
314 | 8 | trueValue = mBuilder.CreateLoad(trueValue); | |
315 | } | ||
316 | else { | ||
317 | 4 | mBuilder.SetInsertPoint(falseBranch); | |
318 | 4 | falseValue = mBuilder.CreateLoad(falseValue); | |
319 | } | ||
320 | } | ||
321 | else { // needs casting | ||
322 | |||
323 | // get type for return | ||
324 | llvm::Type* returnType = nullptr; | ||
325 | |||
326 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 16 times.
|
78 | const bool trueScalar = (trueType->isIntegerTy() || trueType->isFloatingPointTy()); |
327 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 16 times.
|
46 | if (trueScalar && |
328 | (falseType->isIntegerTy() || falseType->isFloatingPointTy())) { | ||
329 | assert(trueType != falseType); | ||
330 | // SCALAR_SCALAR | ||
331 | 20 | returnType = typePrecedence(trueType, falseType); | |
332 | // always load scalars here, even if they are the correct type | ||
333 | 20 | mBuilder.SetInsertPoint(trueBranch); | |
334 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
|
20 | if (truePtr) trueValue = mBuilder.CreateLoad(trueValue); |
335 | 20 | trueValue = arithmeticConversion(trueValue, returnType, mBuilder); | |
336 | 20 | mBuilder.SetInsertPoint(falseBranch); | |
337 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
|
20 | if (falsePtr) falseValue = mBuilder.CreateLoad(falseValue); |
338 | 20 | falseValue = arithmeticConversion(falseValue, returnType, mBuilder); | |
339 | } | ||
340 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 24 times.
|
29 | else if (trueType->isArrayTy() && falseType->isArrayTy() |
341 |
4/4✓ Branch 0 taken 29 times.
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
63 | && (trueType->getArrayNumElements() == falseType->getArrayNumElements())) { |
342 | // ARRAY_ARRAY | ||
343 | trueType = trueType->getArrayElementType(); | ||
344 | falseType = falseType->getArrayElementType(); | ||
345 | 4 | returnType = typePrecedence(trueType, falseType); | |
346 | |||
347 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (trueType != returnType) { |
348 | 4 | mBuilder.SetInsertPoint(trueBranch); | |
349 | 4 | trueValue = arrayCast(trueValue, returnType, mBuilder); | |
350 | } | ||
351 | ✗ | else if (falseType != returnType) { | |
352 | ✗ | mBuilder.SetInsertPoint(falseBranch); | |
353 | ✗ | falseValue = arrayCast(falseValue, returnType, mBuilder); | |
354 | } | ||
355 | } | ||
356 |
4/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24 times.
|
54 | else if (trueScalar && falseType->isArrayTy()) { |
357 | // SCALAR_ARRAY | ||
358 | 24 | returnType = typePrecedence(trueType, falseType->getArrayElementType()); | |
359 | 24 | mBuilder.SetInsertPoint(trueBranch); | |
360 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
|
24 | if (truePtr) trueValue = mBuilder.CreateLoad(trueValue); |
361 | 24 | trueValue = arithmeticConversion(trueValue, returnType, mBuilder); | |
362 | const size_t arraySize = falseType->getArrayNumElements(); | ||
363 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
|
24 | if (arraySize == 9 || arraySize == 16) { |
364 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
12 | trueValue = scalarToMatrix(trueValue, mBuilder, arraySize == 9 ? 3 : 4); |
365 | } | ||
366 | else { | ||
367 | 16 | trueValue = arrayPack(trueValue, mBuilder, arraySize); | |
368 | } | ||
369 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
|
24 | if (falseType->getArrayElementType() != returnType) { |
370 | 20 | mBuilder.SetInsertPoint(falseBranch); | |
371 | 20 | falseValue = arrayCast(falseValue, returnType, mBuilder); | |
372 | } | ||
373 | } | ||
374 |
4/4✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 4 times.
|
30 | else if (trueType->isArrayTy() && |
375 | (falseType->isIntegerTy() || falseType->isFloatingPointTy())) { | ||
376 | // ARRAY_SCALAR | ||
377 | 24 | returnType = typePrecedence(trueType->getArrayElementType(), falseType); | |
378 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
|
24 | if (trueType->getArrayElementType() != returnType) { |
379 | 20 | mBuilder.SetInsertPoint(trueBranch); | |
380 | 20 | trueValue = arrayCast(trueValue, returnType, mBuilder); | |
381 | } | ||
382 | 24 | mBuilder.SetInsertPoint(falseBranch); | |
383 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
|
24 | if (falsePtr) falseValue = mBuilder.CreateLoad(falseValue); |
384 | 24 | falseValue = arithmeticConversion(falseValue, returnType, mBuilder); | |
385 | const size_t arraySize = trueType->getArrayNumElements(); | ||
386 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
|
24 | if (arraySize == 9 || arraySize == 16) { |
387 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
12 | falseValue = scalarToMatrix(falseValue, mBuilder, arraySize == 9 ? 3 : 4); |
388 | } | ||
389 | else { | ||
390 | 16 | falseValue = arrayPack(falseValue, mBuilder, arraySize); | |
391 | } | ||
392 | } | ||
393 | else { | ||
394 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
|
6 | mLog.error("unsupported implicit cast in ternary operation", |
395 | tern->hasTrue() ? tern->trueBranch() : tern->falseBranch()); | ||
396 | 6 | return false; | |
397 | } | ||
398 | } | ||
399 | } | ||
400 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
69 | else if (trueType->isVoidTy() && falseType->isVoidTy()) { |
401 | // void type ternary acts like if-else statement | ||
402 | // push void value to stop use of return from this expression | ||
403 | mBuilder.SetInsertPoint(returnBlock); | ||
404 | mValues.push(falseValue); | ||
405 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | return conditionSuccess && trueSuccess && falseSuccess; |
406 | } | ||
407 | |||
408 | // reset to continue block | ||
409 | mBuilder.SetInsertPoint(returnBlock); | ||
410 | 150 | llvm::PHINode* ternary = mBuilder.CreatePHI(trueValue->getType(), 2, "ternary"); | |
411 | |||
412 | // if nesting branches the blocks for true and false branches may have been updated | ||
413 | // so get these again rather than reusing trueBlock/falseBlock | ||
414 | 150 | ternary->addIncoming(trueValue, trueBranch->getParent()); | |
415 | 150 | ternary->addIncoming(falseValue, falseBranch->getParent()); | |
416 | |||
417 | 150 | mValues.push(ternary); | |
418 |
3/4✓ Branch 0 taken 148 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 148 times.
|
150 | return conditionSuccess && trueSuccess && falseSuccess; |
419 | } | ||
420 | |||
421 | 200 | bool ComputeGenerator::visit(const ast::Loop* loop) | |
422 | { | ||
423 | 200 | mScopeIndex++; | |
424 | |||
425 | 200 | llvm::BasicBlock* postLoopBlock = llvm::BasicBlock::Create(mContext, "block", mFunction); | |
426 | 200 | llvm::BasicBlock* conditionBlock = llvm::BasicBlock::Create(mContext, "loop_condition", mFunction); | |
427 |
2/2✓ Branch 2 taken 41 times.
✓ Branch 3 taken 159 times.
|
200 | llvm::BasicBlock* bodyBlock = llvm::BasicBlock::Create(mContext, "loop_body", mFunction); |
428 | |||
429 | llvm::BasicBlock* postBodyBlock = conditionBlock; | ||
430 | |||
431 | const ast::tokens::LoopToken loopType = loop->loopType(); | ||
432 |
3/4✓ Branch 0 taken 41 times.
✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 41 times.
|
200 | assert((loopType == ast::tokens::LoopToken::FOR || |
433 | loopType == ast::tokens::LoopToken::WHILE || | ||
434 | loopType == ast::tokens::LoopToken::DO) && | ||
435 | "Unsupported loop type"); | ||
436 | |||
437 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 82 times.
|
200 | if (loopType == ast::tokens::LoopToken::FOR) { |
438 | // init -> condition -> body -> iter -> condition ... continue | ||
439 | |||
440 | // generate initial statement | ||
441 |
2/2✓ Branch 0 taken 94 times.
✓ Branch 1 taken 24 times.
|
118 | if (loop->hasInit()) { |
442 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 94 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
94 | if (!this->traverse(loop->initial()) && mLog.atErrorLimit()) return false; |
443 | // reset the value stack | ||
444 | 94 | mValues = std::stack<llvm::Value*>(); | |
445 | } | ||
446 | 118 | mBuilder.CreateBr(conditionBlock); | |
447 | |||
448 | // generate iteration | ||
449 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 20 times.
|
118 | if (loop->hasIter()) { |
450 | 98 | llvm::BasicBlock* iterBlock = llvm::BasicBlock::Create(mContext, "loop_iteration", mFunction); | |
451 | postBodyBlock = iterBlock; | ||
452 | |||
453 | mBuilder.SetInsertPoint(iterBlock); | ||
454 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
98 | if (!this->traverse(loop->iteration()) && mLog.atErrorLimit()) return false; |
455 | 98 | mBuilder.CreateBr(conditionBlock); | |
456 | } | ||
457 | } | ||
458 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 41 times.
|
82 | else if (loopType == ast::tokens::LoopToken::DO) { |
459 | // body -> condition -> body -> condition ... continue | ||
460 | 41 | mBuilder.CreateBr(bodyBlock); | |
461 | } | ||
462 |
1/2✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
|
41 | else if (loopType == ast::tokens::LoopToken::WHILE) { |
463 | // condition -> body -> condition ... continue | ||
464 | 41 | mBuilder.CreateBr(conditionBlock); | |
465 | } | ||
466 | |||
467 | // store the destinations for break and continue | ||
468 |
1/2✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
|
200 | mBreakContinueStack.push({postLoopBlock, postBodyBlock}); |
469 | |||
470 | // generate loop body | ||
471 | mBuilder.SetInsertPoint(bodyBlock); | ||
472 | ✗ | if (!this->traverse(loop->body()) && mLog.atErrorLimit()) return false; | |
473 | 200 | mBuilder.CreateBr(postBodyBlock); | |
474 | |||
475 | // generate condition | ||
476 | mBuilder.SetInsertPoint(conditionBlock); | ||
477 |
2/2✓ Branch 1 taken 199 times.
✓ Branch 2 taken 1 times.
|
200 | if (this->traverse(loop->condition())) { |
478 |
1/2✓ Branch 0 taken 199 times.
✗ Branch 1 not taken.
|
199 | llvm::Value* condition = mValues.top(); mValues.pop(); |
479 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 148 times.
|
199 | if (condition->getType()->isPointerTy()) { |
480 | 51 | condition = mBuilder.CreateLoad(condition); | |
481 | } | ||
482 | llvm::Type* conditionType = condition->getType(); | ||
483 | // check the type of the condition branch is bool-convertable | ||
484 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 160 times.
|
199 | if (conditionType->isFloatingPointTy() || conditionType->isIntegerTy()) { |
485 | 160 | condition = boolComparison(condition, mBuilder); | |
486 | 160 | mBuilder.CreateCondBr(condition, bodyBlock, postLoopBlock); | |
487 | } | ||
488 | else { | ||
489 |
4/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 36 times.
|
78 | if (!mLog.error("cannot convert non-scalar type to bool in condition", loop->condition())) return false; |
490 | } | ||
491 | // reset the value stack | ||
492 | 163 | mValues = std::stack<llvm::Value*>(); | |
493 | } | ||
494 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | else if (mLog.atErrorLimit()) return false; |
495 | |||
496 | // reset to post loop block | ||
497 | mBuilder.SetInsertPoint(postLoopBlock); | ||
498 | |||
499 | // discard break and continue | ||
500 | mBreakContinueStack.pop(); | ||
501 | |||
502 | // remove the symbol table created in this scope | ||
503 | 164 | mSymbolTables.erase(mScopeIndex); | |
504 | 164 | mScopeIndex--; | |
505 | |||
506 | // reset the value stack | ||
507 | 164 | mValues = std::stack<llvm::Value*>(); | |
508 | |||
509 | 164 | return true; | |
510 | } | ||
511 | |||
512 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
|
89 | bool ComputeGenerator::visit(const ast::Keyword* node) |
513 | { | ||
514 | const ast::tokens::KeywordToken keyw = node->keyword(); | ||
515 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
|
89 | assert((keyw == ast::tokens::KeywordToken::RETURN || |
516 | keyw == ast::tokens::KeywordToken::BREAK || | ||
517 | keyw == ast::tokens::KeywordToken::CONTINUE) && | ||
518 | "Unsupported keyword"); | ||
519 | |||
520 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 57 times.
|
89 | if (keyw == ast::tokens::KeywordToken::RETURN) { |
521 | 32 | mBuilder.CreateRetVoid(); | |
522 | } | ||
523 |
1/2✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
|
57 | else if (keyw == ast::tokens::KeywordToken::BREAK || |
524 | keyw == ast::tokens::KeywordToken::CONTINUE) { | ||
525 | // find the parent loop, if it exists | ||
526 | const ast::Node* child = node; | ||
527 | const ast::Node* parentLoop = node->parent(); | ||
528 |
2/2✓ Branch 0 taken 226 times.
✓ Branch 1 taken 1 times.
|
227 | while (parentLoop) { |
529 |
2/2✓ Branch 1 taken 170 times.
✓ Branch 2 taken 56 times.
|
226 | if (parentLoop->nodetype() == ast::Node::NodeType::LoopNode) { |
530 | break; | ||
531 | } | ||
532 | child = parentLoop; | ||
533 | parentLoop = child->parent(); | ||
534 | } | ||
535 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
|
57 | if (!parentLoop) { |
536 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
|
3 | if (!mLog.error("keyword \"" + ast::tokens::keywordNameFromToken(keyw) |
537 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | + "\" used outside of loop.", node)) return false; |
538 | } | ||
539 | else { | ||
540 | const std::pair<llvm::BasicBlock*, llvm::BasicBlock*> | ||
541 | 56 | breakContinue = mBreakContinueStack.top(); | |
542 | |||
543 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 16 times.
|
56 | if (keyw == ast::tokens::KeywordToken::BREAK) { |
544 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
|
40 | assert(breakContinue.first); |
545 | 40 | mBuilder.CreateBr(breakContinue.first); | |
546 | } | ||
547 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | else if (keyw == ast::tokens::KeywordToken::CONTINUE) { |
548 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | assert(breakContinue.second); |
549 | 16 | mBuilder.CreateBr(breakContinue.second); | |
550 | } | ||
551 | } | ||
552 | } | ||
553 | |||
554 | 88 | llvm::BasicBlock* nullBlock = llvm::BasicBlock::Create(mContext, "null", mFunction); | |
555 | // insert all remaining instructions in scope into a null block | ||
556 | // this will incorporate all instructions that follow until new insert point is set | ||
557 | mBuilder.SetInsertPoint(nullBlock); | ||
558 | 88 | return true; | |
559 | } | ||
560 | |||
561 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 1729 times.
|
1844 | bool ComputeGenerator::visit(const ast::BinaryOperator* node) |
562 | { | ||
563 | openvdb::ax::ast::tokens::OperatorToken opToken = node->operation(); | ||
564 | // if AND or OR, need to handle short-circuiting | ||
565 | 1844 | if (opToken == openvdb::ax::ast::tokens::OperatorToken::AND | |
566 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 1729 times.
|
1844 | || opToken == openvdb::ax::ast::tokens::OperatorToken::OR) { |
567 | llvm::BranchInst* lhsBranch = nullptr; | ||
568 | 115 | llvm::BasicBlock* rhsBlock = llvm::BasicBlock::Create(mContext, "binary_rhs", mFunction); | |
569 | 115 | llvm::BasicBlock* returnBlock = llvm::BasicBlock::Create(mContext, "binary_return", mFunction); | |
570 | llvm::Value* lhs = nullptr; | ||
571 | 115 | bool lhsSuccess = this->traverse(node->lhs()); | |
572 |
2/2✓ Branch 0 taken 113 times.
✓ Branch 1 taken 2 times.
|
115 | if (lhsSuccess) { |
573 |
1/2✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
|
113 | lhs = mValues.top(); mValues.pop(); |
574 | llvm::Type* lhsType = lhs->getType(); | ||
575 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 73 times.
|
113 | if (lhsType->isPointerTy()) { |
576 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
|
40 | lhs = mBuilder.CreateLoad(lhs); |
577 | lhsType = lhsType->getPointerElementType(); | ||
578 | } | ||
579 | |||
580 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 65 times.
|
97 | if (lhsType->isFloatingPointTy() || lhsType->isIntegerTy()) { |
581 | 81 | lhs = boolComparison(lhs, mBuilder); | |
582 | |||
583 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 40 times.
|
81 | if (opToken == openvdb::ax::ast::tokens::OperatorToken::AND) { |
584 | 41 | lhsBranch = mBuilder.CreateCondBr(lhs, rhsBlock, returnBlock); | |
585 | } | ||
586 | else { | ||
587 | 40 | lhsBranch = mBuilder.CreateCondBr(lhs, returnBlock, rhsBlock); | |
588 | } | ||
589 | } | ||
590 | else { | ||
591 |
2/4✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
|
64 | mLog.error("cannot convert non-scalar lhs to bool", node->lhs()); |
592 | lhsSuccess = false; | ||
593 | } | ||
594 | } | ||
595 | |||
596 |
2/2✓ Branch 1 taken 81 times.
✓ Branch 2 taken 34 times.
|
115 | if (mLog.atErrorLimit()) return false; |
597 | |||
598 | mBuilder.SetInsertPoint(rhsBlock); | ||
599 | 81 | bool rhsSuccess = this->traverse(node->rhs()); | |
600 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 1 times.
|
81 | if (rhsSuccess) { |
601 |
1/2✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
|
80 | llvm::Value* rhs = mValues.top(); mValues.pop(); |
602 | llvm::Type* rhsType = rhs->getType(); | ||
603 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 48 times.
|
80 | if (rhsType->isPointerTy()) { |
604 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
|
32 | rhs = mBuilder.CreateLoad(rhs); |
605 | rhsType = rhsType->getPointerElementType(); | ||
606 | } | ||
607 | |||
608 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | if (rhsType->isFloatingPointTy() || rhsType->isIntegerTy()) { |
609 | 80 | rhs = boolComparison(rhs, mBuilder); | |
610 | 80 | llvm::BranchInst* rhsBranch = mBuilder.CreateBr(returnBlock); | |
611 | |||
612 | mBuilder.SetInsertPoint(returnBlock); | ||
613 |
1/2✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
|
80 | if (lhsBranch) {// i.e. lhs was successful |
614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
|
80 | assert(rhs && lhs); |
615 | 80 | llvm::PHINode* result = mBuilder.CreatePHI(LLVMType<bool>::get(mContext), 2, "binary_op"); | |
616 | 80 | result->addIncoming(lhs, lhsBranch->getParent()); | |
617 | 80 | result->addIncoming(rhs, rhsBranch->getParent()); | |
618 | 80 | mValues.push(result); | |
619 | } | ||
620 | } | ||
621 | else { | ||
622 | ✗ | mLog.error("cannot convert non-scalar rhs to bool", node->rhs()); | |
623 | rhsSuccess = false; | ||
624 | } | ||
625 | } | ||
626 | 81 | return lhsSuccess && rhsSuccess; | |
627 | } | ||
628 | else { | ||
629 | llvm::Value* lhs = nullptr; | ||
630 |
1/2✓ Branch 1 taken 1729 times.
✗ Branch 2 not taken.
|
1729 | if (this->traverse(node->lhs())) { |
631 |
1/2✓ Branch 0 taken 1729 times.
✗ Branch 1 not taken.
|
1729 | lhs = mValues.top(); mValues.pop(); |
632 | } | ||
633 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
90 | else if (mLog.atErrorLimit()) return false; |
634 | llvm::Value* rhs = nullptr; | ||
635 |
1/2✓ Branch 1 taken 1729 times.
✗ Branch 2 not taken.
|
1729 | if (this->traverse(node->rhs())) { |
636 |
1/2✓ Branch 0 taken 1729 times.
✗ Branch 1 not taken.
|
1729 | rhs = mValues.top(); mValues.pop(); |
637 | } | ||
638 | ✗ | else if (mLog.atErrorLimit()) return false; | |
639 | 1729 | llvm::Value* result = nullptr; | |
640 |
3/4✓ Branch 0 taken 1729 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1639 times.
✓ Branch 4 taken 90 times.
|
1729 | if (!(lhs && rhs) || !this->binaryExpression(result, lhs, rhs, node->operation(), node)) return false; |
641 | |||
642 |
1/2✓ Branch 0 taken 1639 times.
✗ Branch 1 not taken.
|
1639 | if (result) { |
643 | mValues.push(result); | ||
644 | } | ||
645 | } | ||
646 | 1639 | return true; | |
647 | } | ||
648 | |||
649 |
2/2✓ Branch 0 taken 3602 times.
✓ Branch 1 taken 80 times.
|
3682 | bool ComputeGenerator::visit(const ast::UnaryOperator* node) |
650 | { | ||
651 | // If the unary operation is a +, keep the value ptr on the stack and | ||
652 | // continue (avoid any new allocations or unecessary loads) | ||
653 | |||
654 | const ast::tokens::OperatorToken token = node->operation(); | ||
655 |
2/2✓ Branch 0 taken 3602 times.
✓ Branch 1 taken 80 times.
|
3682 | if (token == ast::tokens::PLUS) return true; |
656 | |||
657 | 3602 | if (token != ast::tokens::MINUS && | |
658 |
3/4✓ Branch 0 taken 34 times.
✓ Branch 1 taken 3568 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 34 times.
|
3602 | token != ast::tokens::BITNOT && |
659 | token != ast::tokens::NOT) { | ||
660 | ✗ | mLog.error("unrecognised unary operator \"" + | |
661 | ✗ | ast::tokens::operatorNameFromToken(token) + "\"", node); | |
662 | ✗ | return false; | |
663 | } | ||
664 | // unary operator uses default traversal so value should be on the stack | ||
665 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 3445 times.
|
3602 | llvm::Value* value = mValues.top(); |
666 | llvm::Type* type = value->getType(); | ||
667 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 3445 times.
|
3602 | if (type->isPointerTy()) { |
668 | type = type->getPointerElementType(); | ||
669 |
2/2✓ Branch 0 taken 121 times.
✓ Branch 1 taken 36 times.
|
157 | if (type->isIntegerTy() || type->isFloatingPointTy()) { |
670 | 48 | value = mBuilder.CreateLoad(value); | |
671 | } | ||
672 | } | ||
673 | |||
674 |
2/2✓ Branch 0 taken 476 times.
✓ Branch 1 taken 3126 times.
|
3602 | llvm::Value* result = nullptr; |
675 |
2/2✓ Branch 0 taken 476 times.
✓ Branch 1 taken 3126 times.
|
3602 | if (type->isIntegerTy()) { |
676 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 460 times.
|
476 | if (token == ast::tokens::NOT) { |
677 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
32 | if (type->isIntegerTy(1)) result = mBuilder.CreateICmpEQ(value, llvm::ConstantInt::get(type, 0)); |
678 | ✗ | else result = mBuilder.CreateICmpEQ(value, llvm::ConstantInt::getSigned(type, 0)); | |
679 | } | ||
680 | else { | ||
681 | // if bool, cast to int32 for unary minus and bitnot | ||
682 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 460 times.
|
460 | if (type->isIntegerTy(1)) { |
683 | ✗ | type = LLVMType<int32_t>::get(mContext); | |
684 | ✗ | value = arithmeticConversion(value, type, mBuilder); | |
685 | } | ||
686 |
2/2✓ Branch 0 taken 452 times.
✓ Branch 1 taken 8 times.
|
460 | if (token == ast::tokens::MINUS) result = mBuilder.CreateNeg(value); |
687 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | else if (token == ast::tokens::BITNOT) result = mBuilder.CreateNot(value); |
688 | } | ||
689 | } | ||
690 | else if (type->isFloatingPointTy()) { | ||
691 |
1/2✓ Branch 0 taken 3017 times.
✗ Branch 1 not taken.
|
3017 | if (token == ast::tokens::MINUS) result = mBuilder.CreateFNeg(value); |
692 | ✗ | else if (token == ast::tokens::NOT) result = mBuilder.CreateFCmpOEQ(value, llvm::ConstantFP::get(type, 0)); | |
693 | ✗ | else if (token == ast::tokens::BITNOT) { | |
694 | ✗ | mLog.error("unable to perform operation \"" | |
695 | ✗ | + ast::tokens::operatorNameFromToken(token) + "\" on floating point values", node); | |
696 | ✗ | return false; | |
697 | } | ||
698 | } | ||
699 |
1/2✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
|
109 | else if (type->isArrayTy()) { |
700 | type = type->getArrayElementType(); | ||
701 | std::vector<llvm::Value*> elements; | ||
702 |
1/2✓ Branch 1 taken 109 times.
✗ Branch 2 not taken.
|
109 | arrayUnpack(value, elements, mBuilder, /*load*/true); |
703 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | assert(elements.size() > 0); |
704 | |||
705 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 85 times.
|
109 | if (type->isIntegerTy()) { |
706 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
|
24 | if (token == ast::tokens::MINUS) { |
707 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 8 times.
|
36 | for (llvm::Value*& element : elements) { |
708 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | element = mBuilder.CreateNeg(element); |
709 | } | ||
710 | } | ||
711 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | else if (token == ast::tokens::NOT) { |
712 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 8 times.
|
36 | for (llvm::Value*& element : elements) { |
713 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
56 | element = mBuilder.CreateICmpEQ(element, |
714 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | llvm::ConstantInt::getSigned(type, 0)); |
715 | } | ||
716 | } | ||
717 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | else if (token == ast::tokens::BITNOT) { |
718 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 8 times.
|
36 | for (llvm::Value*& element : elements) { |
719 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | element = mBuilder.CreateNot(element); |
720 | } | ||
721 | } | ||
722 | } | ||
723 | else if (type->isFloatingPointTy()) { | ||
724 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 21 times.
|
85 | if (token == ast::tokens::MINUS) { |
725 |
2/2✓ Branch 0 taken 656 times.
✓ Branch 1 taken 64 times.
|
720 | for (llvm::Value*& element : elements) { |
726 |
1/2✓ Branch 2 taken 656 times.
✗ Branch 3 not taken.
|
656 | element = mBuilder.CreateFNeg(element); |
727 | } | ||
728 | } | ||
729 | else { | ||
730 | //@todo support NOT? | ||
731 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | mLog.error("unable to perform operation \"" |
732 |
3/8✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
42 | + ast::tokens::operatorNameFromToken(token) + "\" on arrays/vectors", node); |
733 | 21 | return false; | |
734 | } | ||
735 | } | ||
736 | else { | ||
737 | ✗ | mLog.error("unrecognised array element type", node); | |
738 | ✗ | return false; | |
739 | } | ||
740 | |||
741 |
2/4✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
✗ Branch 4 not taken.
|
88 | result = arrayPack(elements, mBuilder); |
742 | } | ||
743 | else { | ||
744 | ✗ | mLog.error("value is not a scalar or vector", node); | |
745 | ✗ | return false; | |
746 | } | ||
747 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3581 times.
|
3581 | assert(result); |
748 | mValues.pop(); | ||
749 | mValues.push(result); | ||
750 | return true; | ||
751 | } | ||
752 | |||
753 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11448 times.
|
11448 | bool ComputeGenerator::visit(const ast::AssignExpression* assign) |
754 | { | ||
755 | // default traversal, should have rhs and lhs on stack | ||
756 | // leave LHS on stack | ||
757 |
1/2✓ Branch 0 taken 11448 times.
✗ Branch 1 not taken.
|
11448 | llvm::Value* rhs = mValues.top(); mValues.pop(); |
758 | 11448 | llvm::Value* lhs = mValues.top(); | |
759 | |||
760 |
2/2✓ Branch 0 taken 1575 times.
✓ Branch 1 taken 9873 times.
|
11448 | llvm::Type* rhsType = rhs->getType(); |
761 |
2/2✓ Branch 0 taken 1575 times.
✓ Branch 1 taken 9873 times.
|
11448 | if (assign->isCompound()) { |
762 | 1575 | llvm::Value* rhsValue = nullptr; | |
763 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1575 times.
|
1575 | if (!this->binaryExpression(rhsValue, lhs, rhs, assign->operation(), assign)) return false; |
764 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1575 times.
|
1575 | assert(rhsValue); |
765 | 1575 | rhs = rhsValue; | |
766 | rhsType = rhs->getType(); | ||
767 | } | ||
768 | // rhs must be loaded for assignExpression() if it's a scalar | ||
769 |
2/2✓ Branch 0 taken 5055 times.
✓ Branch 1 taken 6393 times.
|
11448 | if (rhsType->isPointerTy()) { |
770 | rhsType = rhsType->getPointerElementType(); | ||
771 |
2/2✓ Branch 0 taken 4522 times.
✓ Branch 1 taken 533 times.
|
5055 | if (rhsType->isIntegerTy() || rhsType->isFloatingPointTy()) { |
772 | 1517 | rhs = mBuilder.CreateLoad(rhs); | |
773 | } | ||
774 | } | ||
775 | |||
776 |
2/2✓ Branch 1 taken 29 times.
✓ Branch 2 taken 11419 times.
|
11448 | if (!this->assignExpression(lhs, rhs, assign)) return false; |
777 | return true; | ||
778 | } | ||
779 | |||
780 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 774 times.
|
774 | bool ComputeGenerator::visit(const ast::Crement* node) |
781 | { | ||
782 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 774 times.
|
774 | llvm::Value* value = mValues.top(); |
783 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 774 times.
|
774 | if (!value->getType()->isPointerTy()) { |
784 | ✗ | mLog.error("unable to assign to an rvalue", node); | |
785 | ✗ | return false; | |
786 | } | ||
787 | 774 | llvm::Value* rvalue = mBuilder.CreateLoad(value); | |
788 | llvm::Type* type = rvalue->getType(); | ||
789 | |||
790 |
3/4✓ Branch 1 taken 774 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 320 times.
✓ Branch 4 taken 454 times.
|
774 | if (type->isIntegerTy(1) || (!type->isIntegerTy() && !type->isFloatingPointTy())) { |
791 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | mLog.error("variable is an unsupported type for " |
792 | "crement. Must be a non-boolean scalar", node); | ||
793 | 8 | return false; | |
794 | } | ||
795 | else { | ||
796 | llvm::Value* crement = nullptr; | ||
797 |
3/4✓ Branch 0 taken 304 times.
✓ Branch 1 taken 462 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 304 times.
|
766 | assert((node->increment() || node->decrement()) && "unrecognised crement operation"); |
798 |
2/2✓ Branch 0 taken 462 times.
✓ Branch 1 taken 304 times.
|
766 | if (node->increment()) crement = LLVMType<int32_t>::get(mContext, 1); |
799 |
1/2✓ Branch 0 taken 304 times.
✗ Branch 1 not taken.
|
304 | else if (node->decrement()) crement = LLVMType<int32_t>::get(mContext, -1); |
800 | |||
801 | 766 | crement = arithmeticConversion(crement, type, mBuilder); | |
802 |
2/2✓ Branch 0 taken 454 times.
✓ Branch 1 taken 312 times.
|
766 | if (type->isIntegerTy()) crement = mBuilder.CreateAdd(rvalue, crement); |
803 | 312 | if (type->isFloatingPointTy()) crement = mBuilder.CreateFAdd(rvalue, crement); | |
804 | |||
805 | 766 | mBuilder.CreateStore(crement, value); | |
806 | |||
807 | // decide what to put on the expression stack | ||
808 | } | ||
809 | mValues.pop(); | ||
810 | |||
811 |
2/2✓ Branch 0 taken 340 times.
✓ Branch 1 taken 426 times.
|
766 | if (node->post()) mValues.push(rvalue); |
812 | else mValues.push(value); | ||
813 | return true; | ||
814 | } | ||
815 | |||
816 | 4943 | bool ComputeGenerator::visit(const ast::FunctionCall* node) | |
817 | { | ||
818 | const FunctionGroup* const function = | ||
819 | 4943 | mFunctionRegistry.getOrInsert(node->name(), mOptions, false); | |
820 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4942 times.
|
4943 | if (!function) { |
821 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
2 | mLog.error("unable to locate function \"" + node->name() + "\"", node); |
822 | 1 | return false; | |
823 | } | ||
824 | else { | ||
825 | const size_t args = node->children(); | ||
826 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4942 times.
|
4942 | assert(mValues.size() >= args); |
827 | |||
828 | // initialize arguments. scalars are always passed by value, arrays | ||
829 | // and strings always by pointer | ||
830 | |||
831 | std::vector<llvm::Value*> arguments; | ||
832 |
1/2✓ Branch 1 taken 4942 times.
✗ Branch 2 not taken.
|
4942 | arguments.resize(args); |
833 | |||
834 |
2/2✓ Branch 0 taken 6944 times.
✓ Branch 1 taken 4942 times.
|
11886 | for (auto r = arguments.rbegin(); r != arguments.rend(); ++r) { |
835 |
1/2✓ Branch 0 taken 6944 times.
✗ Branch 1 not taken.
|
6944 | llvm::Value* arg = mValues.top(); mValues.pop(); |
836 | llvm::Type* type = arg->getType(); | ||
837 |
2/2✓ Branch 0 taken 3335 times.
✓ Branch 1 taken 3609 times.
|
6944 | if (type->isPointerTy()) { |
838 | type = type->getPointerElementType(); | ||
839 |
2/2✓ Branch 0 taken 3311 times.
✓ Branch 1 taken 24 times.
|
3335 | if (type->isIntegerTy() || type->isFloatingPointTy()) { |
840 | // pass by value | ||
841 |
3/4✓ Branch 2 taken 404 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 6 times.
|
413 | arg = mBuilder.CreateLoad(arg); |
842 | } | ||
843 | } | ||
844 | else { | ||
845 | // arrays should never be loaded | ||
846 |
3/6✓ Branch 0 taken 3609 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3609 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3609 times.
|
3609 | assert(!type->isArrayTy() && type != LLVMType<codegen::String>::get(mContext)); |
847 | if (type->isIntegerTy() || type->isFloatingPointTy()) { | ||
848 | /*pass by value*/ | ||
849 | } | ||
850 | } | ||
851 | 6944 | *r = arg; | |
852 | } | ||
853 | |||
854 | std::vector<llvm::Type*> inputTypes; | ||
855 |
1/2✓ Branch 1 taken 4942 times.
✗ Branch 2 not taken.
|
4942 | valuesToTypes(arguments, inputTypes); |
856 | |||
857 | Function::SignatureMatch match; | ||
858 |
1/2✓ Branch 1 taken 4942 times.
✗ Branch 2 not taken.
|
4942 | const Function* target = function->match(inputTypes, mContext, &match); |
859 | |||
860 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4942 times.
|
4942 | if (!target) { |
861 | ✗ | assert(!function->list().empty() | |
862 | && "FunctionGroup has no function declarations"); | ||
863 | |||
864 | ✗ | std::ostringstream os; | |
865 | ✗ | if (match == Function::SignatureMatch::None) { | |
866 | os << "wrong number of arguments. \"" << node->name() << "\"" | ||
867 | ✗ | << " was called with: ("; | |
868 | ✗ | llvm::raw_os_ostream stream(os); | |
869 | ✗ | printTypes(stream, inputTypes); | |
870 | ✗ | stream << ")"; | |
871 | } | ||
872 | else { | ||
873 | // match == Function::SignatureMatch::Size | ||
874 | ✗ | os << "no matching function for "; | |
875 | ✗ | printSignature(os, inputTypes, | |
876 | ✗ | LLVMType<void>::get(mContext), | |
877 | node->name().c_str(), {}, true); | ||
878 | } | ||
879 | |||
880 | ✗ | os << " \ncandidates are: "; | |
881 | ✗ | for (const auto& sig : function->list()) { | |
882 | os << std::endl; | ||
883 | ✗ | sig->print(mContext, os, node->name().c_str()); | |
884 | } | ||
885 | ✗ | mLog.error(os.str(), node); | |
886 | return false; | ||
887 | } | ||
888 | else { | ||
889 | 4942 | llvm::Value* result = nullptr; | |
890 |
2/2✓ Branch 0 taken 684 times.
✓ Branch 1 taken 4258 times.
|
4942 | if (match == Function::SignatureMatch::Implicit) { |
891 |
3/6✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 684 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 684 times.
|
1368 | if (!mLog.warning("implicit conversion in function call", node)) return false; |
892 |
1/2✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
|
684 | result = target->call(arguments, mBuilder, /*cast=*/true); |
893 | } | ||
894 | else { | ||
895 | // match == Function::SignatureMatch::Explicit | ||
896 |
2/2✓ Branch 1 taken 4249 times.
✓ Branch 2 taken 9 times.
|
4258 | result = target->call(arguments, mBuilder, /*cast=*/false); |
897 | } | ||
898 | |||
899 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4933 times.
|
4933 | assert(result && "Function has been invoked with no valid llvm Value return"); |
900 | mValues.push(result); | ||
901 | } | ||
902 | } | ||
903 | 4933 | return true; | |
904 | } | ||
905 | |||
906 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
|
82 | bool ComputeGenerator::visit(const ast::Cast* node) |
907 | { | ||
908 |
1/2✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
|
82 | llvm::Value* value = mValues.top(); mValues.pop(); |
909 | |||
910 | llvm::Type* type = | ||
911 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 2 times.
|
82 | value->getType()->isPointerTy() ? |
912 | value->getType()->getPointerElementType() : | ||
913 | value->getType(); | ||
914 | |||
915 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 50 times.
|
82 | if (!type->isIntegerTy() && !type->isFloatingPointTy()) { |
916 | ✗ | mLog.error("unable to cast non scalar values", node); | |
917 | ✗ | return false; | |
918 | } | ||
919 | else { | ||
920 | // If the value to cast is already the correct type, return | ||
921 | 82 | llvm::Type* targetType = llvmTypeFromToken(node->type(), mContext); | |
922 |
1/2✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
|
82 | if (type == targetType) return true; |
923 | |||
924 | |||
925 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 2 times.
|
82 | if (value->getType()->isPointerTy()) { |
926 | 80 | value = mBuilder.CreateLoad(value); | |
927 | } | ||
928 | |||
929 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 66 times.
|
82 | if (targetType->isIntegerTy(1)) { |
930 | // if target is bool, perform standard boolean conversion (*not* truncation). | ||
931 | 16 | value = boolComparison(value, mBuilder); | |
932 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | assert(value->getType()->isIntegerTy(1)); |
933 | } | ||
934 | else { | ||
935 | 66 | value = arithmeticConversion(value, targetType, mBuilder); | |
936 | } | ||
937 | mValues.push(value); | ||
938 | } | ||
939 | |||
940 | return true; | ||
941 | } | ||
942 | |||
943 | 3587 | bool ComputeGenerator::visit(const ast::DeclareLocal* node) | |
944 | { | ||
945 | // create storage for the local value. | ||
946 |
2/2✓ Branch 1 taken 135 times.
✓ Branch 2 taken 3452 times.
|
3587 | llvm::Type* type = llvmTypeFromToken(node->type(), mContext); |
947 | llvm::Value* value; | ||
948 | |||
949 | // @note For strings, we call the string::string function rather than | ||
950 | // rely on the behaviour of insertStaticAlloca. The key difference here is | ||
951 | // that the string::string method performs the complete list of functions | ||
952 | // that are comprised by the ax::codegen::String constructor. In other | ||
953 | // words, it ensures all observable behaviour matches between the IR for | ||
954 | // strings and the C++ string implementation. Importantly, | ||
955 | // insertStaticAlloca does not initialise the first character of the SSO | ||
956 | // array to '\0' and does not call alloc (which, although does not change | ||
957 | // the string state compared to insertStaticAlloca, may change the order | ||
958 | // of assignments and other observable behaviour). Ideally, | ||
959 | // insertStaticAlloca should call string::string. | ||
960 |
2/2✓ Branch 0 taken 135 times.
✓ Branch 1 taken 3452 times.
|
3587 | if (node->type() == ast::tokens::STRING) { |
961 |
2/4✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 135 times.
✗ Branch 5 not taken.
|
135 | const FunctionGroup* axstring = this->getFunction("string::string", /*internal*/true); |
962 |
2/4✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 135 times.
|
135 | value = axstring->execute({}, mBuilder); |
963 | } | ||
964 | else { | ||
965 | 3452 | value = insertStaticAlloca(mBuilder, type); | |
966 | } | ||
967 | |||
968 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3587 times.
|
3587 | assert(value); |
969 | 3587 | SymbolTable* current = mSymbolTables.getOrInsert(mScopeIndex); | |
970 | |||
971 | const std::string& name = node->local()->name(); | ||
972 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3584 times.
|
3587 | if (!current->insert(name, value)) { |
973 |
2/4✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
6 | mLog.error("local variable \"" + name + |
974 | "\" has already been declared", node); | ||
975 | 3 | return false; | |
976 | } | ||
977 | |||
978 |
2/2✓ Branch 1 taken 32 times.
✓ Branch 2 taken 3552 times.
|
3584 | if (mSymbolTables.find(name, mScopeIndex - 1)) { |
979 |
2/4✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
|
96 | if (!mLog.warning("declaration of variable \"" + name |
980 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
64 | + "\" shadows a previous declaration", node)) return false; |
981 | } | ||
982 | |||
983 | |||
984 | // do this to ensure all AST nodes are visited | ||
985 | // shouldn't ever fail | ||
986 |
1/2✓ Branch 0 taken 3584 times.
✗ Branch 1 not taken.
|
3584 | if (this->traverse(node->local())) { |
987 |
1/2✓ Branch 0 taken 3584 times.
✗ Branch 1 not taken.
|
3584 | value = mValues.top(); mValues.pop(); |
988 | } | ||
989 | ✗ | else if (mLog.atErrorLimit()) return false; | |
990 | |||
991 |
2/2✓ Branch 0 taken 2858 times.
✓ Branch 1 taken 726 times.
|
3584 | if (node->hasInit()) { |
992 |
1/2✓ Branch 1 taken 2858 times.
✗ Branch 2 not taken.
|
2858 | if (this->traverse(node->init())) { |
993 |
1/2✓ Branch 0 taken 2858 times.
✗ Branch 1 not taken.
|
2858 | llvm::Value* init = mValues.top(); mValues.pop(); |
994 |
2/2✓ Branch 0 taken 2163 times.
✓ Branch 1 taken 695 times.
|
2858 | llvm::Type* initType = init->getType(); |
995 | |||
996 |
2/2✓ Branch 0 taken 2163 times.
✓ Branch 1 taken 695 times.
|
2858 | if (initType->isPointerTy()) { |
997 | initType = initType->getPointerElementType(); | ||
998 |
1/2✓ Branch 0 taken 2163 times.
✗ Branch 1 not taken.
|
2163 | if (initType->isIntegerTy() || initType->isFloatingPointTy()) { |
999 | ✗ | init = mBuilder.CreateLoad(init); | |
1000 | } | ||
1001 | } | ||
1002 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 2851 times.
|
2858 | if (!this->assignExpression(value, init, node)) return false; |
1003 | |||
1004 | // note that loop conditions allow uses of initialized declarations | ||
1005 | // and so require the value | ||
1006 |
1/2✓ Branch 0 taken 2851 times.
✗ Branch 1 not taken.
|
2851 | if (value) mValues.push(value); |
1007 | } | ||
1008 | ✗ | else if (mLog.atErrorLimit()) return false; | |
1009 | } | ||
1010 | return true; | ||
1011 | } | ||
1012 | |||
1013 | 10147 | bool ComputeGenerator::visit(const ast::Local* node) | |
1014 | { | ||
1015 | // Reverse iterate through the current blocks and use the first declaration found | ||
1016 | // The current block number looks something like as follows | ||
1017 | // | ||
1018 | // ENTRY: Block 1 | ||
1019 | // | ||
1020 | // if(...) // Block 3 | ||
1021 | // { | ||
1022 | // if(...) {} // Block 5 | ||
1023 | // } | ||
1024 | // else {} // Block 2 | ||
1025 | // | ||
1026 | // Note that in block 5, block 2 variables will be queried. However block variables | ||
1027 | // are constructed from the top down, so although the block number is used for | ||
1028 | // reverse iterating, block 2 will not contain any information | ||
1029 | // | ||
1030 | |||
1031 | 10147 | llvm::Value* value = mSymbolTables.find(node->name()); | |
1032 |
2/2✓ Branch 0 taken 10126 times.
✓ Branch 1 taken 21 times.
|
10147 | if (value) { |
1033 | mValues.push(value); | ||
1034 | } | ||
1035 | else { | ||
1036 |
2/4✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
|
42 | mLog.error("variable \"" + node->name() + "\" hasn't been declared", node); |
1037 | 21 | return false; | |
1038 | } | ||
1039 | return true; | ||
1040 | } | ||
1041 | |||
1042 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2510 times.
|
2510 | bool ComputeGenerator::visit(const ast::ArrayUnpack* node) |
1043 | { | ||
1044 |
1/2✓ Branch 0 taken 2510 times.
✗ Branch 1 not taken.
|
2510 | llvm::Value* value = mValues.top(); mValues.pop(); |
1045 |
1/2✓ Branch 0 taken 2510 times.
✗ Branch 1 not taken.
|
2510 | llvm::Value* component0 = mValues.top(); mValues.pop(); |
1046 | llvm::Value* component1 = nullptr; | ||
1047 | |||
1048 |
2/2✓ Branch 0 taken 419 times.
✓ Branch 1 taken 2091 times.
|
2510 | if (node->isMatrixIndex()) { |
1049 |
1/2✓ Branch 0 taken 419 times.
✗ Branch 1 not taken.
|
419 | component1 = mValues.top(); mValues.pop(); |
1050 | // if double indexing, the two component values will be | ||
1051 | // pushed onto the stack with the first index last. i.e. | ||
1052 | // top: expression | ||
1053 | // 2nd index (if matrix access) | ||
1054 | // bottom: 1st index | ||
1055 | // so swap the components | ||
1056 | std::swap(component0, component1); | ||
1057 | } | ||
1058 | |||
1059 |
1/2✓ Branch 0 taken 2510 times.
✗ Branch 1 not taken.
|
2510 | llvm::Type* type = value->getType(); |
1060 |
3/4✓ Branch 0 taken 2510 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2509 times.
|
5020 | if (!type->isPointerTy() || |
1061 | !type->getPointerElementType()->isArrayTy()) { | ||
1062 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | mLog.error("variable is not a valid type for component access", node); |
1063 | 1 | return false; | |
1064 | } | ||
1065 | |||
1066 | // type now guaranteed to be an array type | ||
1067 | type = type->getPointerElementType(); | ||
1068 | const size_t size = type->getArrayNumElements(); | ||
1069 |
4/4✓ Branch 0 taken 419 times.
✓ Branch 1 taken 2090 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 418 times.
|
2509 | if (component1 && size <= 4) { |
1070 | { | ||
1071 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | mLog.error("attribute or local variable is not a compatible matrix type " |
1072 | "for [,] indexing", node); | ||
1073 | 1 | return false; | |
1074 | } | ||
1075 | } | ||
1076 | |||
1077 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 2400 times.
|
2508 | if (component0->getType()->isPointerTy()) { |
1078 | 108 | component0 = mBuilder.CreateLoad(component0); | |
1079 | } | ||
1080 |
4/4✓ Branch 0 taken 418 times.
✓ Branch 1 taken 2090 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 401 times.
|
2508 | if (component1 && component1->getType()->isPointerTy()) { |
1081 | 17 | component1 = mBuilder.CreateLoad(component1); | |
1082 | } | ||
1083 | |||
1084 |
4/4✓ Branch 0 taken 2504 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 417 times.
✓ Branch 3 taken 2087 times.
|
2508 | if (!component0->getType()->isIntegerTy() || |
1085 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 416 times.
|
417 | (component1 && !component1->getType()->isIntegerTy())) { |
1086 | 10 | std::ostringstream os; | |
1087 | 5 | llvm::raw_os_ostream stream(os); | |
1088 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | component0->getType()->print(stream); |
1089 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5 | if (component1) { |
1090 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | stream << ", "; |
1091 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | component1->getType()->print(stream); |
1092 | } | ||
1093 | stream.flush(); | ||
1094 | { | ||
1095 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
10 | mLog.error("unable to index into array with a non integer value. Types are [" |
1096 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
10 | + os.str() + "]", node); |
1097 | return false; | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | 2503 | llvm::Value* zero = LLVMType<int32_t>::get(mContext, 0); | |
1102 |
2/2✓ Branch 0 taken 2087 times.
✓ Branch 1 taken 416 times.
|
2503 | if (!component1) { |
1103 | 2087 | value = mBuilder.CreateGEP(value, {zero, component0}); | |
1104 | } | ||
1105 | else { | ||
1106 | // component0 = row, component1 = column. Index into the matrix array | ||
1107 | // which is layed out in row major = (component0*dim + component1) | ||
1108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 416 times.
|
416 | assert(size == 9 || size == 16); |
1109 |
2/2✓ Branch 0 taken 256 times.
✓ Branch 1 taken 160 times.
|
416 | const int32_t dim = size == 9 ? 3 : 4; |
1110 | llvm::Value* offset = | ||
1111 | 416 | LLVMType<int32_t>::get(mContext, static_cast<int32_t>(dim)); | |
1112 | 416 | component0 = binaryOperator(component0, offset, ast::tokens::MULTIPLY, mBuilder); | |
1113 | 416 | component0 = binaryOperator(component0, component1, ast::tokens::PLUS, mBuilder); | |
1114 | 416 | value = mBuilder.CreateGEP(value, {zero, component0}); | |
1115 | } | ||
1116 | |||
1117 | mValues.push(value); | ||
1118 | return true; | ||
1119 | } | ||
1120 | |||
1121 |
1/2✓ Branch 0 taken 3939 times.
✗ Branch 1 not taken.
|
3939 | bool ComputeGenerator::visit(const ast::ArrayPack* node) |
1122 | { | ||
1123 | const size_t num = node->children(); | ||
1124 | |||
1125 | // if there is only one element on the stack, leave it as a pointer to a scalar | ||
1126 | // or another array | ||
1127 |
1/2✓ Branch 0 taken 3939 times.
✗ Branch 1 not taken.
|
3939 | if (num == 1) return true; |
1128 | |||
1129 | 3939 | llvm::Type* strtype = LLVMType<codegen::String>::get(mContext); | |
1130 | |||
1131 | std::vector<llvm::Value*> values; | ||
1132 |
1/2✓ Branch 1 taken 3939 times.
✗ Branch 2 not taken.
|
3939 | values.reserve(num); |
1133 |
2/2✓ Branch 0 taken 21952 times.
✓ Branch 1 taken 3931 times.
|
25883 | for (size_t i = 0; i < num; ++i) { |
1134 |
1/2✓ Branch 0 taken 21952 times.
✗ Branch 1 not taken.
|
21952 | llvm::Value* value = mValues.top(); mValues.pop(); |
1135 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 21944 times.
|
21952 | if (value->getType()->isPointerTy()) { |
1136 |
1/4✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
8 | value = mBuilder.CreateLoad(value); |
1137 | } | ||
1138 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 21946 times.
|
21952 | if (value->getType()->isArrayTy()) { |
1139 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
|
12 | mLog.error("cannot build nested arrays", node->child(num-(i+1))); |
1140 | 8 | return false; | |
1141 | } | ||
1142 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21944 times.
|
21946 | if (value->getType() == strtype) { |
1143 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
4 | mLog.error("cannot build arrays of strings", node->child(num-(i+1))); |
1144 | 2 | return false; | |
1145 | } | ||
1146 | |||
1147 |
1/2✓ Branch 1 taken 21944 times.
✗ Branch 2 not taken.
|
21944 | values.emplace_back(value); |
1148 | } | ||
1149 | |||
1150 | // reserve the values | ||
1151 | // @todo this should probably be handled by the AST | ||
1152 | 3931 | std::reverse(values.begin(), values.end()); | |
1153 | |||
1154 |
2/4✓ Branch 1 taken 3931 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3931 times.
✗ Branch 5 not taken.
|
3931 | llvm::Value* array = arrayPackCast(values, mBuilder); |
1155 | mValues.push(array); | ||
1156 | return true; | ||
1157 | } | ||
1158 | |||
1159 | 667 | bool ComputeGenerator::visit(const ast::Value<bool>* node) | |
1160 | { | ||
1161 | 667 | llvm::Constant* value = LLVMType<bool>::get(mContext, node->value()); | |
1162 | 667 | mValues.push(value); | |
1163 | 667 | return true; | |
1164 | } | ||
1165 | |||
1166 | ✗ | bool ComputeGenerator::visit(const ast::Value<int16_t>* node) | |
1167 | { | ||
1168 | ✗ | return visit<int16_t>(node); | |
1169 | } | ||
1170 | |||
1171 | 8181 | bool ComputeGenerator::visit(const ast::Value<int32_t>* node) | |
1172 | { | ||
1173 | 8181 | return visit<int32_t>(node); | |
1174 | } | ||
1175 | |||
1176 | 396 | bool ComputeGenerator::visit(const ast::Value<int64_t>* node) | |
1177 | { | ||
1178 | 396 | return visit<int64_t>(node); | |
1179 | } | ||
1180 | |||
1181 | 11472 | bool ComputeGenerator::visit(const ast::Value<float>* node) | |
1182 | { | ||
1183 | 11472 | return visit<float>(node); | |
1184 | } | ||
1185 | |||
1186 | 11835 | bool ComputeGenerator::visit(const ast::Value<double>* node) | |
1187 | { | ||
1188 | 11835 | return visit<double>(node); | |
1189 | } | ||
1190 | |||
1191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 605 times.
|
605 | bool ComputeGenerator::visit(const ast::Value<std::string>* node) |
1192 | { | ||
1193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 605 times.
|
605 | assert(node->value().size() < static_cast<size_t>(std::numeric_limits<size_t>::max())); |
1194 |
2/4✓ Branch 1 taken 605 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 605 times.
✗ Branch 5 not taken.
|
605 | const FunctionGroup* axstring = this->getFunction("string::string", /*internal*/true); |
1195 | 605 | llvm::Value* loc = mBuilder.CreateGlobalStringPtr(node->value()); // char* | |
1196 |
3/6✓ Branch 1 taken 605 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 605 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 605 times.
✗ Branch 7 not taken.
|
1210 | llvm::Value* result = axstring->execute({loc}, mBuilder); |
1197 | mValues.push(result); | ||
1198 | 605 | return true; | |
1199 | } | ||
1200 | |||
1201 | 26599 | const FunctionGroup* ComputeGenerator::getFunction(const std::string &identifier, | |
1202 | const bool allowInternal) | ||
1203 | { | ||
1204 | const FunctionGroup* F = | ||
1205 | 26599 | mFunctionRegistry.getOrInsert(identifier, mOptions, allowInternal); | |
1206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26599 times.
|
26599 | assert(F); |
1207 | 26599 | return F; | |
1208 | } | ||
1209 | |||
1210 | template <typename ValueType> | ||
1211 | typename std::enable_if<std::is_integral<ValueType>::value, bool>::type | ||
1212 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8569 times.
|
17154 | ComputeGenerator::visit(const ast::Value<ValueType>* node) |
1213 | { | ||
1214 | using ContainerT = typename ast::Value<ValueType>::ContainerType; | ||
1215 | |||
1216 | static const ContainerT max = | ||
1217 | static_cast<ContainerT>(std::numeric_limits<ValueType>::max()); | ||
1218 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8569 times.
|
17154 | if (node->asContainerType() > max) { |
1219 |
3/6✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
|
32 | if (!mLog.warning("signed integer overflow in integer literal " |
1220 | + std::to_string(node->asContainerType()), node)) return false; | ||
1221 | } | ||
1222 | |||
1223 | 17154 | llvm::Constant* value = LLVMType<ValueType>::get(mContext, node->value()); | |
1224 | 17154 | mValues.push(value); | |
1225 | 17154 | return true; | |
1226 | } | ||
1227 | |||
1228 | template <typename ValueType> | ||
1229 | typename std::enable_if<std::is_floating_point<ValueType>::value, bool>::type | ||
1230 |
1/2✓ Branch 0 taken 23307 times.
✗ Branch 1 not taken.
|
46614 | ComputeGenerator::visit(const ast::Value<ValueType>* node) |
1231 | { | ||
1232 |
2/4✓ Branch 0 taken 23307 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23307 times.
|
46614 | assert(std::isinf(node->value()) || node->value() >= 0.0); |
1233 | 46614 | llvm::Constant* value = LLVMType<ValueType>::get(mContext, node->value()); | |
1234 | 46614 | mValues.push(value); | |
1235 | 46614 | return true; | |
1236 | } | ||
1237 | |||
1238 | 77 | bool ComputeGenerator::visit(const ast::ExternalVariable* node) | |
1239 | { | ||
1240 | const std::string globalName = node->tokenname(); | ||
1241 | 77 | llvm::Value* ptrToAddress = this->globals().get(globalName); | |
1242 | |||
1243 |
1/2✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
|
77 | if (!ptrToAddress) { |
1244 | ptrToAddress = llvm::cast<llvm::GlobalVariable> | ||
1245 |
3/6✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 77 times.
✗ Branch 9 not taken.
|
77 | (mModule.getOrInsertGlobal(globalName, LLVMType<uintptr_t>::get(mContext))); |
1246 |
1/2✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
|
77 | this->globals().insert(globalName, ptrToAddress); |
1247 | } | ||
1248 | |||
1249 |
1/2✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
|
77 | llvm::Type* type = llvmTypeFromToken(node->type(), mContext); |
1250 |
1/2✓ Branch 2 taken 77 times.
✗ Branch 3 not taken.
|
77 | llvm::Value* address = mBuilder.CreateLoad(ptrToAddress); |
1251 |
3/4✓ Branch 2 taken 77 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 65 times.
✓ Branch 5 taken 12 times.
|
154 | llvm::Value* value = mBuilder.CreateIntToPtr(address, type->getPointerTo(0)); |
1252 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 12 times.
|
77 | if (type->isIntegerTy() || type->isFloatingPointTy()) { |
1253 |
1/2✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
21 | value = mBuilder.CreateLoad(value); |
1254 | } | ||
1255 | mValues.push(value); | ||
1256 | 77 | return true; | |
1257 | } | ||
1258 | |||
1259 | 1526 | bool ComputeGenerator::visit(const ast::Tree*) | |
1260 | { | ||
1261 | // In case we haven't returned already (i.e. we are NOT in a null block) | ||
1262 | // we insert a ret void. If we are, this will just get cleaned up anyway below. | ||
1263 | 1526 | mBuilder.CreateRetVoid(); | |
1264 |
1/2✓ Branch 0 taken 1526 times.
✗ Branch 1 not taken.
|
1526 | mBuilder.SetInsertPoint(&mFunction->back()); |
1265 | 1526 | return true; | |
1266 | } | ||
1267 | |||
1268 | ✗ | bool ComputeGenerator::visit(const ast::Attribute*) | |
1269 | { | ||
1270 | ✗ | assert(false && "Base ComputeGenerator attempted to generate code for an Attribute. " | |
1271 | "PointComputeGenerator or VolumeComputeGenerator should be used for " | ||
1272 | "attribute accesses."); | ||
1273 | return false; | ||
1274 | } | ||
1275 | |||
1276 | 14306 | bool ComputeGenerator::assignExpression(llvm::Value* lhs, llvm::Value*& rhs, const ast::Node* node) | |
1277 | { | ||
1278 | 14306 | llvm::Type* strtype = LLVMType<codegen::String>::get(mContext); | |
1279 | |||
1280 | llvm::Type* ltype = lhs->getType(); | ||
1281 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14306 times.
|
14306 | llvm::Type* rtype = rhs->getType(); |
1282 | |||
1283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14306 times.
|
14306 | if (!ltype->isPointerTy()) { |
1284 | ✗ | mLog.error("unable to assign to an rvalue", node); | |
1285 | ✗ | return false; | |
1286 | } | ||
1287 | |||
1288 | ltype = ltype->getPointerElementType(); | ||
1289 |
2/2✓ Branch 0 taken 5701 times.
✓ Branch 1 taken 8605 times.
|
14306 | if (rtype->isPointerTy()) rtype = rtype->getPointerElementType(); |
1290 | |||
1291 |
4/4✓ Branch 0 taken 5772 times.
✓ Branch 1 taken 8534 times.
✓ Branch 2 taken 5400 times.
✓ Branch 3 taken 8906 times.
|
20078 | size_t lsize = ltype->isArrayTy() ? ltype->getArrayNumElements() : 1; |
1292 |
2/2✓ Branch 0 taken 5400 times.
✓ Branch 1 taken 8906 times.
|
14306 | size_t rsize = rtype->isArrayTy() ? rtype->getArrayNumElements() : 1; |
1293 | |||
1294 | // Handle scalar->matrix promotion if necessary | ||
1295 | // @todo promote all values (i.e. scalar to vectors) to make below branching | ||
1296 | // easier. Need to verifier IR is able to optimise to the same logic | ||
1297 | |||
1298 |
2/2✓ Branch 0 taken 1833 times.
✓ Branch 1 taken 12473 times.
|
14306 | if (lsize == 9 || lsize == 16) { |
1299 |
2/2✓ Branch 0 taken 1781 times.
✓ Branch 1 taken 52 times.
|
1833 | if (rtype->isIntegerTy() || rtype->isFloatingPointTy()) { |
1300 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
|
100 | if (rhs->getType()->isPointerTy()) { |
1301 | ✗ | rhs = mBuilder.CreateLoad(rhs); | |
1302 | } | ||
1303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
|
100 | rhs = arithmeticConversion(rhs, ltype->getArrayElementType(), mBuilder); |
1304 |
3/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 56 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 100 times.
|
144 | rhs = scalarToMatrix(rhs, mBuilder, lsize == 9 ? 3 : 4); |
1305 | rtype = rhs->getType()->getPointerElementType(); | ||
1306 | 100 | rsize = lsize; | |
1307 | } | ||
1308 | } | ||
1309 | |||
1310 |
2/2✓ Branch 0 taken 318 times.
✓ Branch 1 taken 13988 times.
|
14306 | if (lsize != rsize) { |
1311 |
4/4✓ Branch 0 taken 303 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 287 times.
|
318 | if (lsize > 1 && rsize > 1) { |
1312 |
2/4✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 | mLog.error("unable to assign vector/array " |
1313 | "attributes with mismatching sizes", node); | ||
1314 | 16 | return false; | |
1315 | } | ||
1316 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 287 times.
|
302 | else if (lsize == 1) { |
1317 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | assert(rsize > 1); |
1318 |
2/4✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | mLog.error("cannot assign a scalar value " |
1319 | "from a vector or matrix. Consider using the [] operator to " | ||
1320 | "get a particular element", node); | ||
1321 | 15 | return false; | |
1322 | } | ||
1323 | } | ||
1324 | |||
1325 | // All remaining operators are either componentwise, string or invalid implicit casts | ||
1326 | |||
1327 | 14275 | const bool string = | |
1328 | 14275 | (ltype == strtype && rtype == strtype); | |
1329 | |||
1330 | const bool componentwise = !string && | ||
1331 |
6/6✓ Branch 0 taken 13974 times.
✓ Branch 1 taken 301 times.
✓ Branch 2 taken 5470 times.
✓ Branch 3 taken 4174 times.
✓ Branch 4 taken 5469 times.
✓ Branch 5 taken 1 times.
|
23919 | (rtype->isFloatingPointTy() || rtype->isIntegerTy() || rtype->isArrayTy()) && |
1332 |
4/4✓ Branch 0 taken 5760 times.
✓ Branch 1 taken 3956 times.
✓ Branch 2 taken 5756 times.
✓ Branch 3 taken 4 times.
|
9716 | (ltype->isFloatingPointTy() || ltype->isIntegerTy() || ltype->isArrayTy()); |
1333 | |||
1334 | if (componentwise) { | ||
1335 |
3/6✓ Branch 0 taken 287 times.
✓ Branch 1 taken 13682 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 287 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
13969 | assert(rsize == lsize || (rsize == 1 || lsize == 1)); |
1336 | 13969 | const size_t resultsize = std::max(lsize, rsize); | |
1337 | |||
1338 |
2/2✓ Branch 0 taken 1247 times.
✓ Branch 1 taken 12722 times.
|
13969 | if (ltype != rtype) { |
1339 |
2/2✓ Branch 0 taken 709 times.
✓ Branch 1 taken 538 times.
|
1247 | llvm::Type* letype = ltype->isArrayTy() ? ltype->getArrayElementType() : ltype; |
1340 |
2/2✓ Branch 0 taken 422 times.
✓ Branch 1 taken 825 times.
|
1247 | llvm::Type* retype = rtype->isArrayTy() ? rtype->getArrayElementType() : rtype; |
1341 |
2/2✓ Branch 0 taken 1121 times.
✓ Branch 1 taken 126 times.
|
1247 | if (letype != retype) { |
1342 | 1121 | llvm::Type* highest = typePrecedence(letype, retype); | |
1343 |
2/2✓ Branch 0 taken 535 times.
✓ Branch 1 taken 586 times.
|
1121 | if (highest != letype) { |
1344 |
3/6✓ Branch 1 taken 535 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 535 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 535 times.
✗ Branch 7 not taken.
|
1070 | if (!mLog.warning("implicit conversion in assignment (possible truncation)", node)) return false; |
1345 | } | ||
1346 | } | ||
1347 | } | ||
1348 | |||
1349 | // compute the componentwise precision | ||
1350 | |||
1351 |
2/2✓ Branch 0 taken 5756 times.
✓ Branch 1 taken 8213 times.
|
13969 | llvm::Type* opprec = ltype->isArrayTy() ? ltype->getArrayElementType() : ltype; |
1352 | // if target is bool, perform standard boolean conversion (*not* truncation). | ||
1353 | // i.e. if rhs is anything but zero, lhs is true | ||
1354 | // @todo zeroval should be at rhstype | ||
1355 |
2/2✓ Branch 1 taken 1843 times.
✓ Branch 2 taken 12126 times.
|
13969 | if (opprec->isIntegerTy(1)) { |
1356 | 1843 | llvm::Value* newRhs = nullptr; | |
1357 |
1/2✓ Branch 2 taken 1843 times.
✗ Branch 3 not taken.
|
1843 | if (!this->binaryExpression(newRhs, LLVMType<int32_t>::get(mContext, 0), rhs, ast::tokens::NOTEQUALS, node)) return false; |
1358 |
1/2✓ Branch 0 taken 1843 times.
✗ Branch 1 not taken.
|
1843 | if (!newRhs) return true; |
1359 | 1843 | rhs = newRhs; | |
1360 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1843 times.
|
1843 | assert(newRhs->getType()->isIntegerTy(1)); |
1361 | } | ||
1362 | |||
1363 |
2/2✓ Branch 0 taken 43071 times.
✓ Branch 1 taken 13969 times.
|
57040 | for (size_t i = 0; i < resultsize; ++i) { |
1364 |
2/2✓ Branch 0 taken 34858 times.
✓ Branch 1 taken 8213 times.
|
43071 | llvm::Value* lelement = lsize == 1 ? lhs : mBuilder.CreateConstGEP2_64(lhs, 0, i); |
1365 |
4/6✓ Branch 0 taken 9074 times.
✓ Branch 1 taken 33997 times.
✓ Branch 5 taken 33997 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 33997 times.
✗ Branch 9 not taken.
|
43071 | llvm::Value* relement = rsize == 1 ? rhs : mBuilder.CreateLoad(mBuilder.CreateConstGEP2_64(rhs, 0, i)); |
1366 | 43071 | relement = arithmeticConversion(relement, opprec, mBuilder); | |
1367 | 43071 | mBuilder.CreateStore(relement, lelement); | |
1368 | } | ||
1369 | } | ||
1370 |
2/2✓ Branch 0 taken 301 times.
✓ Branch 1 taken 5 times.
|
306 | else if (string) { |
1371 |
2/4✓ Branch 1 taken 301 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 301 times.
✗ Branch 5 not taken.
|
301 | const FunctionGroup* axstringassign = this->getFunction("string::op=", /*internal*/true); |
1372 |
2/4✓ Branch 1 taken 301 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 301 times.
✗ Branch 5 not taken.
|
602 | axstringassign->execute({lhs, rhs}, mBuilder); |
1373 | } | ||
1374 | else { | ||
1375 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | mLog.error("unsupported implicit cast in assignment", node); |
1376 | 5 | return false; | |
1377 | } | ||
1378 | return true; | ||
1379 | } | ||
1380 | |||
1381 | /////////////////////////////////////////////////////////////////////////// | ||
1382 | /////////////////////////////////////////////////////////////////////////// | ||
1383 | |||
1384 | |||
1385 | 3014 | void ComputeGenerator::createFreeSymbolStrings(llvm::IRBuilder<>& B) | |
1386 | { | ||
1387 | 3014 | llvm::Type* strtype = LLVMType<codegen::String>::get(mContext); | |
1388 | |||
1389 | // Loop through the initial function allocations and create string clears | ||
1390 | // to any strings that were created. Allocs should only be made at the | ||
1391 | // start of the function, so we only have to scan the function entry block. | ||
1392 | // | ||
1393 | // @note technically, AX guarantees that the first set of instructions are | ||
1394 | // allocs, so we could stop on the first instr that isn't an alloc. This | ||
1395 | // would be hard to test though should this change in the future. | ||
1396 | |||
1397 | llvm::Function* F = B.GetInsertBlock()->getParent(); | ||
1398 | llvm::BasicBlock& entry = F->getEntryBlock(); | ||
1399 | |||
1400 | std::vector<llvm::Value*> ptrs; | ||
1401 | |||
1402 | // collect string allocas | ||
1403 |
2/2✓ Branch 0 taken 260804 times.
✓ Branch 1 taken 3014 times.
|
263818 | for (auto& inst : entry) { |
1404 |
2/2✓ Branch 0 taken 224620 times.
✓ Branch 1 taken 36184 times.
|
295926 | if (!llvm::isa<llvm::AllocaInst>(inst)) continue; |
1405 |
2/2✓ Branch 1 taken 35122 times.
✓ Branch 2 taken 1062 times.
|
36184 | llvm::AllocaInst* alloc = llvm::cast<llvm::AllocaInst>(&inst); |
1406 |
2/2✓ Branch 0 taken 35122 times.
✓ Branch 1 taken 1062 times.
|
36184 | if (alloc->getAllocatedType() != strtype) continue; |
1407 |
1/2✓ Branch 1 taken 1062 times.
✗ Branch 2 not taken.
|
1062 | ptrs.emplace_back(alloc); |
1408 | } | ||
1409 | |||
1410 |
2/2✓ Branch 0 taken 2855 times.
✓ Branch 1 taken 159 times.
|
3014 | if (ptrs.empty()) return; |
1411 | |||
1412 | // clear the strings to make sure malloc has been freed | ||
1413 | const FunctionGroup* axstringclear = | ||
1414 |
2/4✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 159 times.
✗ Branch 5 not taken.
|
318 | this->getFunction("string::clear", /*internal*/true); |
1415 | |||
1416 | 159 | const auto IP = B.saveIP(); | |
1417 | |||
1418 |
2/2✓ Branch 0 taken 2170 times.
✓ Branch 1 taken 159 times.
|
2329 | for (llvm::BasicBlock& BB : *F) { |
1419 | llvm::Instruction* TI = BB.getTerminator(); | ||
1420 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2170 times.
|
2170 | assert(TI); |
1421 |
2/2✓ Branch 0 taken 159 times.
✓ Branch 1 taken 2011 times.
|
2170 | if (llvm::isa<llvm::ReturnInst>(TI)) { |
1422 |
1/2✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
|
159 | B.SetInsertPoint(TI); |
1423 |
2/2✓ Branch 0 taken 1062 times.
✓ Branch 1 taken 159 times.
|
1221 | for (auto ptr : ptrs) { |
1424 |
2/6✓ Branch 1 taken 1062 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1062 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2124 | axstringclear->execute({ptr}, B); |
1425 | } | ||
1426 | } | ||
1427 | } | ||
1428 | |||
1429 |
1/2✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
|
159 | B.restoreIP(IP); |
1430 | } | ||
1431 | |||
1432 | 5147 | bool ComputeGenerator::binaryExpression(llvm::Value*& result, llvm::Value* lhs, llvm::Value* rhs, | |
1433 | const ast::tokens::OperatorToken op, const ast::Node* node) | ||
1434 | { | ||
1435 | 5147 | llvm::Type* strtype = LLVMType<codegen::String>::get(mContext); | |
1436 | |||
1437 | llvm::Type* ltype = lhs->getType(); | ||
1438 | llvm::Type* rtype = rhs->getType(); | ||
1439 | |||
1440 |
2/2✓ Branch 0 taken 2494 times.
✓ Branch 1 taken 2653 times.
|
5147 | if (ltype->isPointerTy()) ltype = ltype->getPointerElementType(); |
1441 |
2/2✓ Branch 0 taken 1536 times.
✓ Branch 1 taken 3611 times.
|
5147 | if (rtype->isPointerTy()) rtype = rtype->getPointerElementType(); |
1442 | |||
1443 |
4/4✓ Branch 0 taken 1273 times.
✓ Branch 1 taken 3874 times.
✓ Branch 2 taken 1270 times.
✓ Branch 3 taken 3877 times.
|
6420 | size_t lsize = ltype->isArrayTy() ? ltype->getArrayNumElements() : 1; |
1444 |
2/2✓ Branch 0 taken 1270 times.
✓ Branch 1 taken 3877 times.
|
5147 | size_t rsize = rtype->isArrayTy() ? rtype->getArrayNumElements() : 1; |
1445 | |||
1446 | // Handle scalar->matrix promotion if necessary | ||
1447 | // @todo promote all values (i.e. scalar to vectors) to make below branching | ||
1448 | // easier. Need to verifier IR is able to optimise to the same logic | ||
1449 | |||
1450 |
2/2✓ Branch 0 taken 322 times.
✓ Branch 1 taken 4825 times.
|
5147 | if (lsize == 9 || lsize == 16) { |
1451 |
2/2✓ Branch 0 taken 320 times.
✓ Branch 1 taken 2 times.
|
322 | if (rtype->isIntegerTy() || rtype->isFloatingPointTy()) { |
1452 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (rhs->getType()->isPointerTy()) { |
1453 | ✗ | rhs = mBuilder.CreateLoad(rhs); | |
1454 | } | ||
1455 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | rhs = arithmeticConversion(rhs, ltype->getArrayElementType(), mBuilder); |
1456 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | rhs = scalarToMatrix(rhs, mBuilder, lsize == 9 ? 3 : 4); |
1457 | rtype = rhs->getType()->getPointerElementType(); | ||
1458 | 2 | rsize = lsize; | |
1459 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (auto* child = node->child(0)) { |
1460 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (child->isType<ast::ArrayPack>()) { |
1461 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | mLog.error("unable to deduce implicit {...} type for binary op as value " |
1462 | "may be a matrix or array. assign to a local mat variable", child); | ||
1463 | 2 | return false; | |
1464 | } | ||
1465 | } | ||
1466 | ✗ | if (!mLog.warning("implicit cast to matrix from scalar. resulting " | |
1467 | ✗ | "cast will be equal to scalar * identity.", node->child(1))) return false; | |
1468 | } | ||
1469 | } | ||
1470 | |||
1471 |
2/2✓ Branch 0 taken 321 times.
✓ Branch 1 taken 4824 times.
|
5145 | if (rsize == 9 || rsize == 16) { |
1472 |
1/2✓ Branch 0 taken 321 times.
✗ Branch 1 not taken.
|
321 | if (ltype->isIntegerTy() || ltype->isFloatingPointTy()) { |
1473 | ✗ | if (lhs->getType()->isPointerTy()) { | |
1474 | ✗ | lhs = mBuilder.CreateLoad(lhs); | |
1475 | } | ||
1476 | ✗ | lhs = arithmeticConversion(lhs, rtype->getArrayElementType(), mBuilder); | |
1477 | ✗ | lhs = scalarToMatrix(lhs, mBuilder, rsize == 9 ? 3 : 4); | |
1478 | ltype = lhs->getType()->getPointerElementType(); | ||
1479 | ✗ | lsize = rsize; | |
1480 | ✗ | if (auto* child = node->child(1)) { | |
1481 | ✗ | if (child->isType<ast::ArrayPack>()) { | |
1482 | ✗ | mLog.error("unable to deduce implicit {...} type for binary op as value " | |
1483 | "may be a matrix or array. assign to a local mat variable", child); | ||
1484 | ✗ | return false; | |
1485 | } | ||
1486 | } | ||
1487 | ✗ | if (!mLog.warning("implicit cast to matrix from scalar. resulting " | |
1488 | ✗ | "cast will be equal to scalar * identity.", node->child(0))) return false; | |
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | // | ||
1493 | |||
1494 | const ast::tokens::OperatorType opType = ast::tokens::operatorType(op); | ||
1495 | 5145 | result = nullptr; | |
1496 | // Handle custom matrix operators | ||
1497 | |||
1498 |
4/4✓ Branch 0 taken 4825 times.
✓ Branch 1 taken 320 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4824 times.
|
5145 | if (lsize >= 9 || rsize >= 9) |
1499 | { | ||
1500 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 271 times.
|
321 | if (op == ast::tokens::MULTIPLY) { |
1501 |
6/6✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 2 times.
|
50 | if ((lsize == 9 && rsize == 9) || |
1502 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | (lsize == 16 && rsize == 16)) { |
1503 | // matrix matrix multiplication all handled through mmmult | ||
1504 |
5/10✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
|
96 | result = this->getFunction("mmmult", /*internal*/true)->execute({lhs, rhs}, mBuilder); |
1505 | } | ||
1506 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | else if ((lsize == 9 && rsize == 3) || |
1507 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | (lsize == 16 && rsize == 3) || |
1508 | ✗ | (lsize == 16 && rsize == 4)) { | |
1509 | // matrix vector multiplication all handled through pretransform | ||
1510 | ✗ | result = this->getFunction("pretransform")->execute({lhs, rhs}, mBuilder); | |
1511 | } | ||
1512 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | else if ((lsize == 3 && rsize == 9) || |
1513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | (lsize == 3 && rsize == 16) || |
1514 | ✗ | (lsize == 4 && rsize == 16)) { | |
1515 | // vector matrix multiplication all handled through transform | ||
1516 | ✗ | result = this->getFunction("transform")->execute({lhs, rhs}, mBuilder); | |
1517 | } | ||
1518 | else { | ||
1519 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | mLog.error("unsupported * operator on " |
1520 | "vector/matrix sizes", node); | ||
1521 | 2 | return false; | |
1522 | } | ||
1523 | } | ||
1524 | 271 | else if (op == ast::tokens::MORETHAN || | |
1525 | op == ast::tokens::LESSTHAN || | ||
1526 | 271 | op == ast::tokens::MORETHANOREQUAL || | |
1527 | 271 | op == ast::tokens::LESSTHANOREQUAL || | |
1528 |
1/2✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
|
271 | op == ast::tokens::DIVIDE || // no / support for mats |
1529 | 271 | op == ast::tokens::MODULO || // no % support for mats | |
1530 |
4/4✓ Branch 0 taken 268 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 256 times.
|
271 | opType == ast::tokens::LOGICAL || |
1531 | opType == ast::tokens::BITWISE) { | ||
1532 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | mLog.error("call to unsupported operator \"" |
1533 |
2/4✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
|
30 | + ast::tokens::operatorNameFromToken(op) + |
1534 | "\" with a vector/matrix argument", node); | ||
1535 | 15 | return false; | |
1536 | } | ||
1537 | } | ||
1538 | |||
1539 |
2/2✓ Branch 0 taken 5080 times.
✓ Branch 1 taken 48 times.
|
5128 | if (!result) { |
1540 | // Handle matrix/vector ops of mismatching sizes | ||
1541 |
3/4✓ Branch 0 taken 3873 times.
✓ Branch 1 taken 1207 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3873 times.
|
5080 | if (lsize > 1 || rsize > 1) { |
1542 |
5/6✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1201 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
|
1207 | if (lsize != rsize && (lsize > 1 && rsize > 1)) { |
1543 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | mLog.error("unsupported binary operator on vector/matrix " |
1544 | "arguments of mismatching sizes", node); | ||
1545 | 4 | return false; | |
1546 | } | ||
1547 | 1203 | if (op == ast::tokens::MORETHAN || | |
1548 | op == ast::tokens::LESSTHAN || | ||
1549 |
2/2✓ Branch 0 taken 1201 times.
✓ Branch 1 taken 2 times.
|
1203 | op == ast::tokens::MORETHANOREQUAL || |
1550 | op == ast::tokens::LESSTHANOREQUAL || | ||
1551 | 1201 | opType == ast::tokens::LOGICAL || | |
1552 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 1156 times.
|
1201 | opType == ast::tokens::BITWISE) { |
1553 |
1/2✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
|
47 | mLog.error("call to unsupported operator \"" |
1554 |
2/4✓ Branch 2 taken 47 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 47 times.
✗ Branch 6 not taken.
|
94 | + ast::tokens::operatorNameFromToken(op) + |
1555 | "\" with a vector/matrix argument", node); | ||
1556 | 47 | return false; | |
1557 | } | ||
1558 | } | ||
1559 | |||
1560 | // Handle invalid floating point ops | ||
1561 | if (rtype->isFloatingPointTy() || ltype->isFloatingPointTy()) { | ||
1562 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 725 times.
|
735 | if (opType == ast::tokens::BITWISE) { |
1563 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | mLog.error("call to unsupported operator \"" |
1564 |
2/4✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
|
20 | + ast::tokens::operatorNameFromToken(op) + |
1565 | "\" with a floating point argument", node); | ||
1566 | 10 | return false; | |
1567 | } | ||
1568 | } | ||
1569 | } | ||
1570 | |||
1571 | // All remaining operators are either componentwise, string or invalid implicit casts | ||
1572 | |||
1573 | const bool componentwise = !result && | ||
1574 |
6/6✓ Branch 0 taken 5019 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 1274 times.
✓ Branch 3 taken 3020 times.
✓ Branch 4 taken 1156 times.
✓ Branch 5 taken 118 times.
|
9361 | (rtype->isFloatingPointTy() || rtype->isIntegerTy() || rtype->isArrayTy()) && |
1575 |
3/4✓ Branch 0 taken 1156 times.
✓ Branch 1 taken 3028 times.
✓ Branch 2 taken 1156 times.
✗ Branch 3 not taken.
|
4184 | (ltype->isFloatingPointTy() || ltype->isIntegerTy() || ltype->isArrayTy()); |
1576 | |||
1577 | if (componentwise) | ||
1578 | { | ||
1579 |
3/4✓ Branch 0 taken 3745 times.
✓ Branch 1 taken 1156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3028 times.
|
7929 | assert(ltype->isArrayTy() || ltype->isFloatingPointTy() || ltype->isIntegerTy()); |
1580 |
3/4✓ Branch 0 taken 3745 times.
✓ Branch 1 taken 1156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3020 times.
|
7921 | assert(rtype->isArrayTy() || rtype->isFloatingPointTy() || rtype->isIntegerTy()); |
1581 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 4901 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
4901 | assert(rsize == lsize || (rsize == 1 || lsize == 1)); |
1582 | |||
1583 |
2/2✓ Branch 0 taken 776 times.
✓ Branch 1 taken 4125 times.
|
4901 | if (op == ast::tokens::DIVIDE || op == ast::tokens::MODULO) { |
1584 |
2/2✓ Branch 1 taken 560 times.
✓ Branch 2 taken 216 times.
|
776 | if (llvm::Constant* c = llvm::dyn_cast<llvm::Constant>(rhs)) { |
1585 |
2/2✓ Branch 1 taken 288 times.
✓ Branch 2 taken 272 times.
|
560 | if (c->isZeroValue()) { |
1586 |
1/2✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
|
288 | if (op == ast::tokens::DIVIDE) { |
1587 |
3/6✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 288 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 288 times.
✗ Branch 7 not taken.
|
576 | if (!mLog.warning("division by zero is undefined", node)) return false; |
1588 | } | ||
1589 | else { | ||
1590 | ✗ | if (!mLog.warning("modulo by zero is undefined", node)) return false; | |
1591 | } | ||
1592 | } | ||
1593 | } | ||
1594 | } | ||
1595 | |||
1596 | // compute the componentwise precision | ||
1597 | |||
1598 |
2/2✓ Branch 0 taken 1156 times.
✓ Branch 1 taken 3745 times.
|
4901 | llvm::Type* opprec = ltype->isArrayTy() ? ltype->getArrayElementType() : ltype; |
1599 |
2/2✓ Branch 0 taken 1156 times.
✓ Branch 1 taken 3745 times.
|
4901 | opprec = rtype->isArrayTy() ? |
1600 | 1156 | typePrecedence(opprec, rtype->getArrayElementType()) : | |
1601 | 3745 | typePrecedence(opprec, rtype); | |
1602 | |||
1603 | // if bool, the lowest precision and subsequent result should be int32 | ||
1604 | // for arithmetic, bitwise and certain other ops | ||
1605 | // @note - no bool containers, so if the type is a container, it can't | ||
1606 | // contain booleans | ||
1607 |
2/2✓ Branch 1 taken 216 times.
✓ Branch 2 taken 4685 times.
|
4901 | if (opprec->isIntegerTy(1)) { |
1608 | 216 | if (opType == ast::tokens::ARITHMETIC || | |
1609 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 152 times.
|
216 | opType == ast::tokens::BITWISE || |
1610 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 24 times.
|
64 | op == ast::tokens::MORETHAN || |
1611 | op == ast::tokens::LESSTHAN || | ||
1612 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 16 times.
|
40 | op == ast::tokens::MORETHANOREQUAL || |
1613 | op == ast::tokens::LESSTHANOREQUAL) { | ||
1614 | 200 | opprec = LLVMType<int32_t>::get(mContext); | |
1615 | } | ||
1616 | } | ||
1617 | |||
1618 | // load scalars once | ||
1619 | |||
1620 |
2/2✓ Branch 0 taken 3745 times.
✓ Branch 1 taken 1156 times.
|
4901 | if (!ltype->isArrayTy()) { |
1621 |
2/2✓ Branch 0 taken 1092 times.
✓ Branch 1 taken 2653 times.
|
3745 | if (lhs->getType()->isPointerTy()) { |
1622 | 1092 | lhs = mBuilder.CreateLoad(lhs); | |
1623 | } | ||
1624 | } | ||
1625 |
2/2✓ Branch 0 taken 3745 times.
✓ Branch 1 taken 1156 times.
|
4901 | if (!rtype->isArrayTy()) { |
1626 |
2/2✓ Branch 0 taken 148 times.
✓ Branch 1 taken 3597 times.
|
3745 | if (rhs->getType()->isPointerTy()) { |
1627 | 148 | rhs = mBuilder.CreateLoad(rhs); | |
1628 | } | ||
1629 | } | ||
1630 | |||
1631 |
1/2✓ Branch 1 taken 4901 times.
✗ Branch 2 not taken.
|
4901 | const size_t resultsize = std::max(lsize, rsize); |
1632 | std::vector<llvm::Value*> elements; | ||
1633 |
1/2✓ Branch 1 taken 4901 times.
✗ Branch 2 not taken.
|
4901 | elements.reserve(resultsize); |
1634 | |||
1635 | // handle floored modulo | ||
1636 | 4901 | const Function* target = nullptr; | |
1637 | 19290 | auto runop = [&target, op, this](llvm::Value* a, llvm::Value* b) { | |
1638 |
4/6✓ Branch 0 taken 532 times.
✓ Branch 1 taken 9113 times.
✓ Branch 3 taken 532 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 532 times.
✗ Branch 7 not taken.
|
10177 | if (target) return target->call({a,b}, this->mBuilder, /*cast=*/false); |
1639 | 9113 | else return binaryOperator(a, b, op, this->mBuilder); | |
1640 | 4901 | }; | |
1641 | |||
1642 |
2/2✓ Branch 0 taken 316 times.
✓ Branch 1 taken 4585 times.
|
4901 | if (op == ast::tokens::MODULO) { |
1643 |
2/4✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 316 times.
✗ Branch 5 not taken.
|
316 | const FunctionGroup* mod = this->getFunction("floormod"); |
1644 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 316 times.
|
316 | assert(mod); |
1645 |
3/6✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 316 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 316 times.
✗ Branch 7 not taken.
|
316 | target = mod->match({opprec,opprec}, mContext); |
1646 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 316 times.
|
316 | assert(target); |
1647 | } | ||
1648 | |||
1649 | // perform op | ||
1650 |
2/2✓ Branch 0 taken 9645 times.
✓ Branch 1 taken 4901 times.
|
14546 | for (size_t i = 0; i < resultsize; ++i) { |
1651 |
3/4✓ Branch 0 taken 5900 times.
✓ Branch 1 taken 3745 times.
✓ Branch 5 taken 5900 times.
✗ Branch 6 not taken.
|
15545 | llvm::Value* lelement = lsize == 1 ? lhs : mBuilder.CreateLoad(mBuilder.CreateConstGEP2_64(lhs, 0, i)); |
1652 |
3/4✓ Branch 0 taken 5900 times.
✓ Branch 1 taken 3745 times.
✓ Branch 5 taken 5900 times.
✗ Branch 6 not taken.
|
15545 | llvm::Value* relement = rsize == 1 ? rhs : mBuilder.CreateLoad(mBuilder.CreateConstGEP2_64(rhs, 0, i)); |
1653 |
1/2✓ Branch 1 taken 9645 times.
✗ Branch 2 not taken.
|
9645 | lelement = arithmeticConversion(lelement, opprec, mBuilder); |
1654 |
1/2✓ Branch 1 taken 9645 times.
✗ Branch 2 not taken.
|
9645 | relement = arithmeticConversion(relement, opprec, mBuilder); |
1655 |
2/4✓ Branch 1 taken 9645 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9645 times.
✗ Branch 5 not taken.
|
9645 | elements.emplace_back(runop(lelement, relement)); |
1656 | } | ||
1657 | |||
1658 | // handle vec/mat results | ||
1659 |
2/2✓ Branch 0 taken 1156 times.
✓ Branch 1 taken 3745 times.
|
4901 | if (resultsize > 1) { |
1660 |
2/2✓ Branch 0 taken 208 times.
✓ Branch 1 taken 948 times.
|
1156 | if (op == ast::tokens::EQUALSEQUALS || op == ast::tokens::NOTEQUALS) { |
1661 |
1/2✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
|
208 | const ast::tokens::OperatorToken reductionOp = |
1662 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 104 times.
|
208 | op == ast::tokens::EQUALSEQUALS ? ast::tokens::AND : ast::tokens::OR; |
1663 |
1/2✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
|
208 | result = elements.front(); |
1664 |
2/4✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 208 times.
|
208 | assert(result->getType() == LLVMType<bool>::get(mContext)); |
1665 |
2/2✓ Branch 0 taken 1024 times.
✓ Branch 1 taken 208 times.
|
1232 | for (size_t i = 1; i < resultsize; ++i) { |
1666 |
1/2✓ Branch 1 taken 1024 times.
✗ Branch 2 not taken.
|
1024 | result = binaryOperator(result, elements[i], reductionOp, mBuilder); |
1667 | } | ||
1668 | } | ||
1669 | else { | ||
1670 | // Create the allocation at the start of the function block | ||
1671 |
1/2✓ Branch 1 taken 948 times.
✗ Branch 2 not taken.
|
948 | result = insertStaticAlloca(mBuilder, |
1672 |
1/2✓ Branch 1 taken 948 times.
✗ Branch 2 not taken.
|
948 | llvm::ArrayType::get(opprec, resultsize)); |
1673 |
2/2✓ Branch 0 taken 4668 times.
✓ Branch 1 taken 948 times.
|
5616 | for (size_t i = 0; i < resultsize; ++i) { |
1674 |
2/6✓ Branch 2 taken 4668 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4668 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
4668 | mBuilder.CreateStore(elements[i], mBuilder.CreateConstGEP2_64(result, 0, i)); |
1675 | } | ||
1676 | } | ||
1677 | } | ||
1678 | else { | ||
1679 | 3745 | result = elements.front(); | |
1680 | } | ||
1681 | } | ||
1682 | |||
1683 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 4949 times.
|
5067 | const bool string = !result && |
1684 |
2/2✓ Branch 0 taken 117 times.
✓ Branch 1 taken 1 times.
|
118 | (ltype == strtype && rtype == strtype); |
1685 | |||
1686 | if (string) | ||
1687 | { | ||
1688 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 108 times.
|
117 | if (op != ast::tokens::PLUS) { |
1689 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | mLog.error("unsupported string operation \"" |
1690 |
2/4✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
|
18 | + ast::tokens::operatorNameFromToken(op) + "\"", node); |
1691 | 9 | return false; | |
1692 | } | ||
1693 | |||
1694 |
2/4✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 108 times.
✗ Branch 5 not taken.
|
108 | const FunctionGroup* axstringplus = this->getFunction("string::op+", /*internal*/true); |
1695 |
3/6✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 108 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 108 times.
✗ Branch 7 not taken.
|
216 | result = axstringplus->execute({lhs, rhs}, mBuilder); |
1696 | } | ||
1697 | |||
1698 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5057 times.
|
5058 | if (!result) { |
1699 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | mLog.error("unsupported implicit cast in binary op", node); |
1700 | 1 | return false; | |
1701 | } | ||
1702 | |||
1703 | return true; | ||
1704 | } | ||
1705 | |||
1706 | } // namespace codegen_internal | ||
1707 | |||
1708 | } // namespace codegen | ||
1709 | } // namespace ax | ||
1710 | } // namespace OPENVDB_VERSION_NAME | ||
1711 | } // namespace openvdb | ||
1712 | |||
1713 |