| 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 |