| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright Contributors to the OpenVDB Project | ||
| 2 | // SPDX-License-Identifier: MPL-2.0 | ||
| 3 | |||
| 4 | /// @file codegen/Utils.h | ||
| 5 | /// | ||
| 6 | /// @authors Nick Avramoussis | ||
| 7 | /// | ||
| 8 | /// @brief Utility code generation methods for performing various llvm | ||
| 9 | /// operations | ||
| 10 | /// | ||
| 11 | |||
| 12 | #ifndef OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED | ||
| 13 | #define OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED | ||
| 14 | |||
| 15 | #include "Types.h" | ||
| 16 | |||
| 17 | #include "../ast/Tokens.h" | ||
| 18 | #include "../Exceptions.h" | ||
| 19 | |||
| 20 | #include <openvdb/version.h> | ||
| 21 | |||
| 22 | #include <llvm/IR/IRBuilder.h> | ||
| 23 | #include <llvm/IR/LLVMContext.h> | ||
| 24 | |||
| 25 | // Note: As of LLVM 5.0, the llvm::Type::dump() method isn't being | ||
| 26 | // picked up correctly by the linker. dump() is internally implemented | ||
| 27 | // using Type::print(llvm::errs()) which is being used in place. See: | ||
| 28 | // | ||
| 29 | // https://stackoverflow.com/questions/43723127/llvm-5-0-makefile-undefined-reference-fail | ||
| 30 | // | ||
| 31 | #include <llvm/Support/raw_ostream.h> // llvm::errs() | ||
| 32 | |||
| 33 | namespace openvdb { | ||
| 34 | OPENVDB_USE_VERSION_NAMESPACE | ||
| 35 | namespace OPENVDB_VERSION_NAME { | ||
| 36 | |||
| 37 | namespace ax { | ||
| 38 | namespace codegen { | ||
| 39 | |||
| 40 | /// @note Function definitions for some types returned from automatic token to | ||
| 41 | /// llvm IR operations. See llvmArithmeticConversion and llvmBianryConversion | ||
| 42 | |||
| 43 | using CastFunction = std::function<llvm::Value* | ||
| 44 | (llvm::IRBuilder<>&, llvm::Value*, llvm::Type*)>; | ||
| 45 | |||
| 46 | using BinaryFunction = std::function<llvm::Value* | ||
| 47 | (llvm::IRBuilder<>&, llvm::Value*, llvm::Value*)>; | ||
| 48 | |||
| 49 | /// @brief Populate a vector of llvm Types from a vector of llvm values | ||
| 50 | /// | ||
| 51 | /// @param values A vector of llvm values to retrieve types from | ||
| 52 | /// @param types A vector of llvm types to populate | ||
| 53 | /// | ||
| 54 | inline void | ||
| 55 | 43751 | valuesToTypes(const std::vector<llvm::Value*>& values, | |
| 56 | std::vector<llvm::Type*>& types) | ||
| 57 | { | ||
| 58 | 43751 | types.reserve(values.size()); | |
| 59 |
2/2✓ Branch 0 taken 136905 times.
✓ Branch 1 taken 43751 times.
|
180656 | for (const auto& v : values) { |
| 60 | 136905 | types.emplace_back(v->getType()); | |
| 61 | } | ||
| 62 | 43751 | } | |
| 63 | |||
| 64 | /// @brief Prints an llvm type to a std string | ||
| 65 | /// | ||
| 66 | /// @param type The llvm type to convert | ||
| 67 | /// @param str The string to store the type info to | ||
| 68 | /// | ||
| 69 | inline void | ||
| 70 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | llvmTypeToString(const llvm::Type* const type, std::string& str) |
| 71 | { | ||
| 72 | 2 | llvm::raw_string_ostream os(str); | |
| 73 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | type->print(os); |
| 74 | os.flush(); | ||
| 75 | 2 | } | |
| 76 | |||
| 77 | /// @brief Return the base llvm value which is being pointed to through | ||
| 78 | /// any number of layered pointers. | ||
| 79 | /// @note This function does not check for cyclical pointer dependencies | ||
| 80 | /// | ||
| 81 | /// @param type A llvm pointer type to traverse | ||
| 82 | /// | ||
| 83 | inline llvm::Type* | ||
| 84 | 7571 | getBaseContainedType(llvm::Type* const type) | |
| 85 | { | ||
| 86 | llvm::Type* elementType = type; | ||
| 87 |
2/2✓ Branch 0 taken 7571 times.
✓ Branch 1 taken 7571 times.
|
15142 | while (elementType->isPointerTy()) { |
| 88 | elementType = elementType->getContainedType(0); | ||
| 89 | } | ||
| 90 | 7571 | return elementType; | |
| 91 | } | ||
| 92 | |||
| 93 | /// @brief Return an llvm value representing a pointer to the provided ptr builtin | ||
| 94 | /// ValueT. | ||
| 95 | /// @note This is probably not a suitable solution for anything other than POD | ||
| 96 | /// types and should be used with caution. | ||
| 97 | /// | ||
| 98 | /// @param ptr A pointer to a type of ValueT whose address will be computed and | ||
| 99 | /// returned | ||
| 100 | /// @param builder The current llvm IRBuilder | ||
| 101 | /// | ||
| 102 | template <typename ValueT> | ||
| 103 | inline llvm::Value* | ||
| 104 | llvmPointerFromAddress(const ValueT* const& ptr, | ||
| 105 | llvm::IRBuilder<>& builder) | ||
| 106 | { | ||
| 107 | llvm::Value* address = | ||
| 108 | llvm::ConstantInt::get(llvm::Type::getIntNTy(builder.getContext(), sizeof(uintptr_t)*8), | ||
| 109 | reinterpret_cast<uintptr_t>(ptr)); | ||
| 110 | return builder.CreateIntToPtr(address, LLVMType<ValueT*>::get(builder.getContext())); | ||
| 111 | } | ||
| 112 | |||
| 113 | /// @brief Insert a stack allocation at the beginning of the current function | ||
| 114 | /// of the provided type and size. The IRBuilder's insertion point must | ||
| 115 | /// be set to a BasicBlock with a valid Function parent. | ||
| 116 | /// @note If a size is provided, the size must not depend on any other | ||
| 117 | /// instructions. If it does, invalid LLVM IR will bb generated. | ||
| 118 | /// | ||
| 119 | /// @param B The IRBuilder | ||
| 120 | /// @param type The type to allocate | ||
| 121 | /// @param size Optional count of allocations. If nullptr, runs a single allocation | ||
| 122 | inline llvm::Value* | ||
| 123 | 35450 | insertStaticAlloca(llvm::IRBuilder<>& B, | |
| 124 | llvm::Type* type, | ||
| 125 | llvm::Value* size = nullptr) | ||
| 126 | { | ||
| 127 | 35450 | llvm::Type* strtype = LLVMType<codegen::String>::get(B.getContext()); | |
| 128 | // Create the allocation at the start of the function block | ||
| 129 | llvm::Function* parent = B.GetInsertBlock()->getParent(); | ||
| 130 |
2/4✓ Branch 0 taken 35450 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35450 times.
|
35450 | assert(parent && !parent->empty()); |
| 131 |
1/2✓ Branch 0 taken 35450 times.
✗ Branch 1 not taken.
|
35450 | auto IP = B.saveIP(); |
| 132 | llvm::BasicBlock& block = parent->front(); | ||
| 133 |
2/2✓ Branch 0 taken 3570 times.
✓ Branch 1 taken 31880 times.
|
35450 | if (block.empty()) B.SetInsertPoint(&block); |
| 134 |
1/2✓ Branch 0 taken 31880 times.
✗ Branch 1 not taken.
|
63760 | else B.SetInsertPoint(&(block.front())); |
| 135 | 35450 | llvm::Value* result = B.CreateAlloca(type, size); | |
| 136 | |||
| 137 | /// @note Strings need to be initialised correctly when they are | ||
| 138 | /// created. We alloc them at the start of the function but | ||
| 139 | /// strings in branches may not ever be set to anything. If | ||
| 140 | /// we don't init these correctly, the clearup frees will | ||
| 141 | /// try and free uninitialised memory | ||
| 142 |
2/2✓ Branch 0 taken 1114 times.
✓ Branch 1 taken 34336 times.
|
35450 | if (type == strtype) { |
| 143 | 1114 | llvm::Value* cptr = B.CreateStructGEP(strtype, result, 0); // char** | |
| 144 | 1114 | llvm::Value* sso = B.CreateStructGEP(strtype, result, 1); // char[]* | |
| 145 | 1114 | llvm::Value* sso_load = B.CreateConstGEP2_64(sso, 0 ,0); // char* | |
| 146 | 1114 | llvm::Value* len = B.CreateStructGEP(strtype, result, 2); | |
| 147 | 1114 | B.CreateStore(sso_load, cptr); // this->ptr = this->SSO; | |
| 148 | 1114 | B.CreateStore(B.getInt64(0), len); | |
| 149 | } | ||
| 150 | 35450 | B.restoreIP(IP); | |
| 151 | 35450 | return result; | |
| 152 | } | ||
| 153 | |||
| 154 | inline llvm::Argument* | ||
| 155 | 28 | extractArgument(llvm::Function* F, const size_t idx) | |
| 156 | { | ||
| 157 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | if (!F) return nullptr; |
| 158 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | if (idx >= F->arg_size()) return nullptr; |
| 159 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | return llvm::cast<llvm::Argument>(F->arg_begin() + idx); |
| 160 | } | ||
| 161 | |||
| 162 | inline llvm::Argument* | ||
| 163 | 54919 | extractArgument(llvm::Function* F, const std::string& name) | |
| 164 | { | ||
| 165 |
1/2✓ Branch 0 taken 54919 times.
✗ Branch 1 not taken.
|
54919 | if (!F) return nullptr; |
| 166 |
1/2✓ Branch 0 taken 317218 times.
✗ Branch 1 not taken.
|
579517 | for (auto iter = F->arg_begin(); iter != F->arg_end(); ++iter) { |
| 167 | llvm::Argument* arg = llvm::cast<llvm::Argument>(iter); | ||
| 168 |
2/2✓ Branch 1 taken 262299 times.
✓ Branch 2 taken 54919 times.
|
317218 | if (arg->getName() == name) return arg; |
| 169 | } | ||
| 170 | return nullptr; | ||
| 171 | } | ||
| 172 | |||
| 173 | /// @brief Returns the highest order type from two LLVM Scalar types | ||
| 174 | /// | ||
| 175 | /// @param typeA The first scalar llvm type | ||
| 176 | /// @param typeB The second scalar llvm type | ||
| 177 | /// | ||
| 178 | inline llvm::Type* | ||
| 179 | 28037 | typePrecedence(llvm::Type* const typeA, | |
| 180 | llvm::Type* const typeB) | ||
| 181 | { | ||
| 182 |
3/4✓ Branch 0 taken 28037 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18361 times.
✓ Branch 3 taken 9676 times.
|
28037 | assert(typeA && (typeA->isIntegerTy() || typeA->isFloatingPointTy()) && |
| 183 | "First Type in typePrecedence is not a scalar type"); | ||
| 184 |
3/4✓ Branch 0 taken 28037 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21134 times.
✓ Branch 3 taken 6903 times.
|
28037 | assert(typeB && (typeB->isIntegerTy() || typeB->isFloatingPointTy()) && |
| 185 | "Second Type in typePrecedence is not a scalar type"); | ||
| 186 | |||
| 187 | // handle implicit arithmetic conversion | ||
| 188 | // (http://osr507doc.sco.com/en/tools/clang_conv_implicit.html) | ||
| 189 | |||
| 190 |
2/2✓ Branch 0 taken 19089 times.
✓ Branch 1 taken 8948 times.
|
28037 | if (typeA->isDoubleTy()) return typeA; |
| 191 |
2/2✓ Branch 0 taken 17236 times.
✓ Branch 1 taken 1853 times.
|
19089 | if (typeB->isDoubleTy()) return typeB; |
| 192 | |||
| 193 |
2/2✓ Branch 0 taken 8020 times.
✓ Branch 1 taken 9216 times.
|
17236 | if (typeA->isFloatTy()) return typeA; |
| 194 |
2/2✓ Branch 0 taken 6462 times.
✓ Branch 1 taken 1558 times.
|
8020 | if (typeB->isFloatTy()) return typeB; |
| 195 | |||
| 196 |
2/2✓ Branch 1 taken 6230 times.
✓ Branch 2 taken 232 times.
|
6462 | if (typeA->isIntegerTy(64)) return typeA; |
| 197 |
2/2✓ Branch 1 taken 6206 times.
✓ Branch 2 taken 24 times.
|
6230 | if (typeB->isIntegerTy(64)) return typeB; |
| 198 | |||
| 199 |
2/2✓ Branch 1 taken 1355 times.
✓ Branch 2 taken 4851 times.
|
6206 | if (typeA->isIntegerTy(32)) return typeA; |
| 200 |
2/2✓ Branch 1 taken 224 times.
✓ Branch 2 taken 1131 times.
|
1355 | if (typeB->isIntegerTy(32)) return typeB; |
| 201 | |||
| 202 |
2/2✓ Branch 1 taken 216 times.
✓ Branch 2 taken 8 times.
|
224 | if (typeA->isIntegerTy(16)) return typeA; |
| 203 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | if (typeB->isIntegerTy(16)) return typeB; |
| 204 | |||
| 205 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | if (typeA->isIntegerTy(8)) return typeA; |
| 206 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | if (typeB->isIntegerTy(8)) return typeB; |
| 207 | |||
| 208 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 216 times.
|
216 | if (typeA->isIntegerTy(1)) return typeA; |
| 209 | ✗ | if (typeB->isIntegerTy(1)) return typeB; | |
| 210 | |||
| 211 | ✗ | assert(false && "invalid LLVM type precedence"); | |
| 212 | return nullptr; | ||
| 213 | } | ||
| 214 | |||
| 215 | /// @brief Returns a CastFunction which represents the corresponding instruction | ||
| 216 | /// to convert a source llvm Type to a target llvm Type. If the conversion | ||
| 217 | /// is unsupported, throws an error. | ||
| 218 | /// @warning This assumes any integer types are signed. | ||
| 219 | /// @param sourceType The source type to cast | ||
| 220 | /// @param targetType The target type to cast to | ||
| 221 | /// @param twine An optional string description of the cast function. This can | ||
| 222 | /// be used for for more verbose llvm information on IR compilation | ||
| 223 | /// failure | ||
| 224 | inline CastFunction | ||
| 225 |
2/2✓ Branch 0 taken 3413 times.
✓ Branch 1 taken 10673 times.
|
14086 | llvmArithmeticConversion(const llvm::Type* const sourceType, |
| 226 | const llvm::Type* const targetType, | ||
| 227 | const std::string& twine = "") | ||
| 228 | { | ||
| 229 | |||
| 230 | #define BIND_ARITHMETIC_CAST_OP(Function, Twine) \ | ||
| 231 | std::bind(&Function, \ | ||
| 232 | std::placeholders::_1, \ | ||
| 233 | std::placeholders::_2, \ | ||
| 234 | std::placeholders::_3, \ | ||
| 235 | Twine) | ||
| 236 | |||
| 237 |
2/2✓ Branch 0 taken 3413 times.
✓ Branch 1 taken 10673 times.
|
14086 | if (targetType->isDoubleTy()) { |
| 238 |
3/4✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 821 times.
✓ Branch 4 taken 2592 times.
✗ Branch 5 not taken.
|
6005 | if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine); |
| 239 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 821 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
821 | else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine); |
| 240 |
3/4✓ Branch 1 taken 52 times.
✓ Branch 2 taken 769 times.
✓ Branch 5 taken 52 times.
✗ Branch 6 not taken.
|
873 | else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); |
| 241 |
3/4✓ Branch 1 taken 709 times.
✓ Branch 2 taken 60 times.
✓ Branch 5 taken 709 times.
✗ Branch 6 not taken.
|
1478 | else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); |
| 242 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
60 | else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); |
| 243 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
60 | else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); |
| 244 |
2/4✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 60 times.
✗ Branch 6 not taken.
|
120 | else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine); |
| 245 | } | ||
| 246 |
2/2✓ Branch 0 taken 1699 times.
✓ Branch 1 taken 8974 times.
|
10673 | else if (targetType->isFloatTy()) { |
| 247 |
3/4✓ Branch 0 taken 609 times.
✓ Branch 1 taken 1090 times.
✓ Branch 4 taken 609 times.
✗ Branch 5 not taken.
|
2308 | if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine); |
| 248 |
3/4✓ Branch 0 taken 349 times.
✓ Branch 1 taken 741 times.
✓ Branch 4 taken 349 times.
✗ Branch 5 not taken.
|
1439 | else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine); |
| 249 |
3/4✓ Branch 1 taken 53 times.
✓ Branch 2 taken 688 times.
✓ Branch 5 taken 53 times.
✗ Branch 6 not taken.
|
794 | else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); |
| 250 |
3/4✓ Branch 1 taken 627 times.
✓ Branch 2 taken 61 times.
✓ Branch 5 taken 627 times.
✗ Branch 6 not taken.
|
1315 | else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); |
| 251 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
61 | else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); |
| 252 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
61 | else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); |
| 253 |
2/4✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
|
122 | else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine); |
| 254 | } | ||
| 255 |
2/2✓ Branch 0 taken 340 times.
✓ Branch 1 taken 8634 times.
|
8974 | else if (targetType->isHalfTy()) { |
| 256 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 340 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
340 | if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine); |
| 257 |
2/4✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
|
680 | else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine); |
| 258 | ✗ | else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); | |
| 259 | ✗ | else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); | |
| 260 | ✗ | else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); | |
| 261 | ✗ | else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine); | |
| 262 | ✗ | else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine); | |
| 263 | } | ||
| 264 |
2/2✓ Branch 1 taken 886 times.
✓ Branch 2 taken 7748 times.
|
8634 | else if (targetType->isIntegerTy(64)) { |
| 265 |
3/4✓ Branch 0 taken 20 times.
✓ Branch 1 taken 866 times.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
|
906 | if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 266 |
3/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 857 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
875 | else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 267 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 857 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
857 | else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 268 |
3/4✓ Branch 1 taken 840 times.
✓ Branch 2 taken 17 times.
✓ Branch 5 taken 840 times.
✗ Branch 6 not taken.
|
1697 | else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine); |
| 269 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
17 | else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine); |
| 270 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
17 | else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine); |
| 271 |
2/4✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 17 times.
✗ Branch 6 not taken.
|
34 | else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine); |
| 272 | } | ||
| 273 |
2/2✓ Branch 1 taken 7608 times.
✓ Branch 2 taken 140 times.
|
7748 | else if (targetType->isIntegerTy(32)) { |
| 274 |
3/4✓ Branch 0 taken 97 times.
✓ Branch 1 taken 7511 times.
✓ Branch 4 taken 97 times.
✗ Branch 5 not taken.
|
7705 | if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 275 |
3/4✓ Branch 0 taken 139 times.
✓ Branch 1 taken 7372 times.
✓ Branch 4 taken 139 times.
✗ Branch 5 not taken.
|
7650 | else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 276 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7372 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
7372 | else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 277 |
3/4✓ Branch 1 taken 5121 times.
✓ Branch 2 taken 2251 times.
✓ Branch 5 taken 5121 times.
✗ Branch 6 not taken.
|
12493 | else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); |
| 278 |
3/4✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2247 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
2255 | else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine); |
| 279 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 2247 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
2247 | else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine); |
| 280 |
2/4✓ Branch 1 taken 2247 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2247 times.
✗ Branch 6 not taken.
|
4494 | else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine); |
| 281 | } | ||
| 282 |
1/2✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
|
140 | else if (targetType->isIntegerTy(16)) { |
| 283 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
140 | if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 284 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
140 | else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 285 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
140 | else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); |
| 286 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 140 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
140 | else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); |
| 287 |
3/4✓ Branch 1 taken 132 times.
✓ Branch 2 taken 8 times.
✓ Branch 5 taken 132 times.
✗ Branch 6 not taken.
|
272 | else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); |
| 288 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
8 | else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine); |
| 289 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
|
16 | else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine); |
| 290 | } | ||
| 291 | ✗ | else if (targetType->isIntegerTy(8)) { | |
| 292 | ✗ | if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); | |
| 293 | ✗ | else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); | |
| 294 | ✗ | else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine); | |
| 295 | ✗ | else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); | |
| 296 | ✗ | else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); | |
| 297 | ✗ | else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); | |
| 298 | ✗ | else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine); | |
| 299 | } | ||
| 300 | ✗ | else if (targetType->isIntegerTy(1)) { | |
| 301 | ✗ | if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine); | |
| 302 | ✗ | else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine); | |
| 303 | ✗ | else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine); | |
| 304 | ✗ | else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); | |
| 305 | ✗ | else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); | |
| 306 | ✗ | else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); | |
| 307 | ✗ | else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine); | |
| 308 | } | ||
| 309 | |||
| 310 | #undef BIND_ARITHMETIC_CAST_OP | ||
| 311 | ✗ | assert(false && "invalid LLVM type conversion"); | |
| 312 | return CastFunction(); | ||
| 313 | } | ||
| 314 | |||
| 315 | /// @brief Returns a BinaryFunction representing the corresponding instruction to | ||
| 316 | /// perform on two scalar values, relative to a provided operator token. Note that | ||
| 317 | /// not all operations are supported on floating point types! If the token is not | ||
| 318 | /// supported, or the llvm type is not a scalar type, throws an error. | ||
| 319 | /// @note Various default arguments are bound to provide a simple function call | ||
| 320 | /// signature. For floating point operations, this includes a null pointer to | ||
| 321 | /// the optional metadata node. For integer operations, this includes disabling | ||
| 322 | /// all overflow/rounding optimisations | ||
| 323 | /// | ||
| 324 | /// @param type The type defining the precision of the binary operation | ||
| 325 | /// @param token The token used to create the relative binary operation | ||
| 326 | /// @param twine An optional string description of the binary function. This can | ||
| 327 | /// be used for for more verbose llvm information on IR compilation | ||
| 328 | /// failure | ||
| 329 | inline BinaryFunction | ||
| 330 |
1/2✓ Branch 0 taken 32850 times.
✗ Branch 1 not taken.
|
32850 | llvmBinaryConversion(const llvm::Type* const type, |
| 331 | const ast::tokens::OperatorToken& token, | ||
| 332 | const std::string& twine = "") | ||
| 333 | { | ||
| 334 | |||
| 335 | #define BIND_BINARY_OP(Function) \ | ||
| 336 | [twine](llvm::IRBuilder<>& B, llvm::Value* L, llvm::Value* R) \ | ||
| 337 | -> llvm::Value* { return B.Function(L, R, twine); } | ||
| 338 | |||
| 339 | // NOTE: Binary % and / ops always take sign into account (CreateSDiv vs CreateUDiv, CreateSRem vs CreateURem). | ||
| 340 | // See http://stackoverflow.com/questions/5346160/llvm-irbuildercreateudiv-createsdiv-createexactudiv | ||
| 341 | // a%b in AX is implemented as a floored modulo op and is handled explicitly in binaryExpression | ||
| 342 | |||
| 343 | if (type->isFloatingPointTy()) { | ||
| 344 |
2/2✓ Branch 0 taken 4158 times.
✓ Branch 1 taken 11953 times.
|
16111 | assert(!(ast::tokens::operatorType(token) == ast::tokens::LOGICAL || |
| 345 | ast::tokens::operatorType(token) == ast::tokens::BITWISE) | ||
| 346 | && "unable to perform logical or bitwise operation on floating point values"); | ||
| 347 | |||
| 348 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 4786 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 4786 times.
✓ Branch 10 taken 11325 times.
✓ Branch 13 taken 4786 times.
✗ Branch 14 not taken.
|
35255 | if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateFAdd); |
| 349 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1349 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 1349 times.
✓ Branch 10 taken 9976 times.
✓ Branch 13 taken 1349 times.
✗ Branch 14 not taken.
|
16721 | else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateFSub); |
| 350 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 5114 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 5114 times.
✓ Branch 10 taken 4862 times.
✓ Branch 13 taken 5114 times.
✗ Branch 14 not taken.
|
30432 | else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateFMul); |
| 351 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 588 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 588 times.
✓ Branch 10 taken 4274 times.
✓ Branch 13 taken 588 times.
✗ Branch 14 not taken.
|
7214 | else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateFDiv); |
| 352 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 116 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 116 times.
✓ Branch 10 taken 4158 times.
✓ Branch 13 taken 116 times.
✗ Branch 14 not taken.
|
4738 | else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateFRem); // Note this is NOT a%b in AX. |
| 353 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 884 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 884 times.
✓ Branch 8 taken 3274 times.
✓ Branch 11 taken 884 times.
✗ Branch 12 not taken.
|
7694 | else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateFCmpOEQ); |
| 354 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 904 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 904 times.
✓ Branch 8 taken 2370 times.
✓ Branch 11 taken 904 times.
✗ Branch 12 not taken.
|
6890 | else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateFCmpONE); |
| 355 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1136 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1136 times.
✓ Branch 8 taken 1234 times.
✓ Branch 11 taken 1136 times.
✗ Branch 12 not taken.
|
6914 | else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateFCmpOGT); |
| 356 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 300 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 300 times.
✓ Branch 8 taken 934 times.
✓ Branch 11 taken 300 times.
✗ Branch 12 not taken.
|
2434 | else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateFCmpOLT); |
| 357 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 40 times.
✓ Branch 8 taken 894 times.
✓ Branch 11 taken 40 times.
✗ Branch 12 not taken.
|
1094 | else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOGE); |
| 358 |
3/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 894 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 894 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 894 times.
✗ Branch 12 not taken.
|
4470 | else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOLE); |
| 359 | ✗ | assert(false && "unrecognised binary operator"); | |
| 360 | } | ||
| 361 |
1/2✓ Branch 0 taken 16739 times.
✗ Branch 1 not taken.
|
16739 | else if (type->isIntegerTy()) { |
| 362 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1158 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1158 times.
✓ Branch 8 taken 15581 times.
✓ Branch 11 taken 1158 times.
✗ Branch 12 not taken.
|
21371 | if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateAdd); // No Unsigned/Signed Wrap |
| 363 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 960 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 960 times.
✓ Branch 8 taken 14621 times.
✓ Branch 11 taken 960 times.
✗ Branch 12 not taken.
|
19421 | else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateSub); // No Unsigned/Signed Wrap |
| 364 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 684 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 684 times.
✓ Branch 8 taken 13937 times.
✓ Branch 11 taken 684 times.
✗ Branch 12 not taken.
|
17357 | else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateMul); // No Unsigned/Signed Wrap |
| 365 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 148 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 148 times.
✓ Branch 10 taken 13789 times.
✓ Branch 13 taken 148 times.
✗ Branch 14 not taken.
|
14529 | else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateSDiv); // IsExact = false - when true, poison value if the reuslt is rounded |
| 366 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 76 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 76 times.
✓ Branch 10 taken 13713 times.
✓ Branch 13 taken 76 times.
✗ Branch 14 not taken.
|
14093 | else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateSRem); // Note this is NOT a%b in AX. |
| 367 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1023 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1023 times.
✓ Branch 9 taken 12690 times.
✓ Branch 12 taken 1023 times.
✗ Branch 13 not taken.
|
17805 | else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateICmpEQ); |
| 368 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1959 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1959 times.
✓ Branch 9 taken 10731 times.
✓ Branch 12 taken 1959 times.
✗ Branch 13 not taken.
|
20526 | else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateICmpNE); |
| 369 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 192 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 192 times.
✓ Branch 9 taken 10539 times.
✓ Branch 12 taken 192 times.
✗ Branch 13 not taken.
|
11499 | else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateICmpSGT); |
| 370 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 324 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 324 times.
✓ Branch 9 taken 10215 times.
✓ Branch 12 taken 324 times.
✗ Branch 13 not taken.
|
11835 | else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateICmpSLT); |
| 371 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 48 times.
✓ Branch 9 taken 10167 times.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
|
10407 | else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateICmpSGE); |
| 372 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 48 times.
✓ Branch 9 taken 10119 times.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
|
10359 | else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateICmpSLE); |
| 373 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1088 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 1088 times.
✓ Branch 10 taken 9031 times.
✓ Branch 13 taken 1088 times.
✗ Branch 14 not taken.
|
14471 | else if (token == ast::tokens::AND) return BIND_BINARY_OP(CreateAnd); |
| 374 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 2715 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 2715 times.
✓ Branch 10 taken 6316 times.
✓ Branch 13 taken 2715 times.
✗ Branch 14 not taken.
|
19891 | else if (token == ast::tokens::OR) return BIND_BINARY_OP(CreateOr); |
| 375 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1563 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1563 times.
✓ Branch 8 taken 4753 times.
✓ Branch 11 taken 1563 times.
✗ Branch 12 not taken.
|
12568 | else if (token == ast::tokens::SHIFTLEFT) return BIND_BINARY_OP(CreateShl); // No Unsigned/Signed Wrap |
| 376 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1587 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 1587 times.
✓ Branch 10 taken 3166 times.
✓ Branch 13 taken 1587 times.
✗ Branch 14 not taken.
|
11101 | else if (token == ast::tokens::SHIFTRIGHT) return BIND_BINARY_OP(CreateAShr); // IsExact = false - poison value if any of the bits shifted out are non-zero. |
| 377 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 3078 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 3078 times.
✓ Branch 10 taken 88 times.
✓ Branch 13 taken 3078 times.
✗ Branch 14 not taken.
|
15478 | else if (token == ast::tokens::BITAND) return BIND_BINARY_OP(CreateAnd); |
| 378 |
4/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 40 times.
✓ Branch 10 taken 48 times.
✓ Branch 13 taken 40 times.
✗ Branch 14 not taken.
|
248 | else if (token == ast::tokens::BITOR) return BIND_BINARY_OP(CreateOr); |
| 379 |
3/8✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 48 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 48 times.
✗ Branch 14 not taken.
|
240 | else if (token == ast::tokens::BITXOR) return BIND_BINARY_OP(CreateXor); |
| 380 | ✗ | assert(false && "unrecognised binary operator"); | |
| 381 | } | ||
| 382 | |||
| 383 | #undef BIND_BINARY_OP | ||
| 384 | ✗ | assert(false && "invalid LLVM type for binary operation"); | |
| 385 | return BinaryFunction(); | ||
| 386 | } | ||
| 387 | |||
| 388 | /// @brief Returns true if the llvm Type 'from' can be safely cast to the llvm | ||
| 389 | /// Type 'to'. | ||
| 390 | 179852 | inline bool isValidCast(llvm::Type* from, llvm::Type* to) | |
| 391 | { | ||
| 392 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 179852 times.
|
179852 | assert(from && "llvm Type 'from' is null in isValidCast"); |
| 393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 179852 times.
|
179852 | assert(to && "llvm Type 'to' is null in isValidCast"); |
| 394 | |||
| 395 |
4/4✓ Branch 0 taken 59708 times.
✓ Branch 1 taken 120144 times.
✓ Branch 2 taken 18072 times.
✓ Branch 3 taken 109525 times.
|
187305 | if ((from->isIntegerTy() || from->isFloatingPointTy()) && |
| 396 | (to->isIntegerTy() || to->isFloatingPointTy())) { | ||
| 397 | return true; | ||
| 398 | } | ||
| 399 |
4/4✓ Branch 0 taken 28871 times.
✓ Branch 1 taken 24828 times.
✓ Branch 2 taken 28864 times.
✓ Branch 3 taken 7 times.
|
53699 | if (from->isArrayTy() && to->isArrayTy()) { |
| 400 | 28864 | llvm::ArrayType* af = llvm::cast<llvm::ArrayType>(from); | |
| 401 | 28864 | llvm::ArrayType* at = llvm::cast<llvm::ArrayType>(to); | |
| 402 |
2/2✓ Branch 2 taken 4684 times.
✓ Branch 3 taken 24180 times.
|
28864 | if (af->getArrayNumElements() == at->getArrayNumElements()) { |
| 403 | 4684 | return isValidCast(af->getArrayElementType(), | |
| 404 | 4684 | at->getArrayElementType()); | |
| 405 | } | ||
| 406 | } | ||
| 407 | return false; | ||
| 408 | } | ||
| 409 | |||
| 410 | /// @brief Casts a scalar llvm Value to a target scalar llvm Type. Returns | ||
| 411 | /// the cast scalar value of type targetType. | ||
| 412 | /// @warning This assumes any integer types are signed. | ||
| 413 | /// @param value A llvm scalar value to convert | ||
| 414 | /// @param targetType The target llvm scalar type to convert to | ||
| 415 | /// @param builder The current llvm IRBuilder | ||
| 416 | inline llvm::Value* | ||
| 417 | 92306 | arithmeticConversion(llvm::Value* value, | |
| 418 | llvm::Type* targetType, | ||
| 419 | llvm::IRBuilder<>& builder) | ||
| 420 | { | ||
| 421 |
3/4✓ Branch 0 taken 92306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66848 times.
✓ Branch 3 taken 25458 times.
|
92306 | assert(value && (value->getType()->isIntegerTy() || value->getType()->isFloatingPointTy()) && |
| 422 | "First Value in arithmeticConversion is not a scalar type"); | ||
| 423 |
3/4✓ Branch 0 taken 92306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67951 times.
✓ Branch 3 taken 24355 times.
|
92306 | assert(targetType && (targetType->isIntegerTy() || targetType->isFloatingPointTy()) && |
| 424 | "Target Type in arithmeticConversion is not a scalar type"); | ||
| 425 | |||
| 426 | const llvm::Type* const valueType = value->getType(); | ||
| 427 |
2/2✓ Branch 0 taken 13551 times.
✓ Branch 1 taken 78755 times.
|
92306 | if (valueType == targetType) return value; |
| 428 | |||
| 429 |
2/4✓ Branch 1 taken 13551 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13551 times.
✗ Branch 5 not taken.
|
13551 | CastFunction llvmCastFunction = llvmArithmeticConversion(valueType, targetType); |
| 430 |
1/2✓ Branch 1 taken 13551 times.
✗ Branch 2 not taken.
|
13551 | return llvmCastFunction(builder, value, targetType); |
| 431 | } | ||
| 432 | |||
| 433 | /// @brief Casts an array to another array of equal size but of a different element | ||
| 434 | /// type. Both source and target array element types must be scalar types. | ||
| 435 | /// The source array llvm Value should be a pointer to the array to cast. | ||
| 436 | /// | ||
| 437 | /// @param ptrToArray A llvm value which is a pointer to a llvm array | ||
| 438 | /// @param targetElementType The target llvm scalar type to convert each element | ||
| 439 | /// of the input array | ||
| 440 | /// @param builder The current llvm IRBuilder | ||
| 441 | /// | ||
| 442 | inline llvm::Value* | ||
| 443 | 7615 | arrayCast(llvm::Value* ptrToArray, | |
| 444 | llvm::Type* targetElementType, | ||
| 445 | llvm::IRBuilder<>& builder) | ||
| 446 | { | ||
| 447 |
3/4✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2142 times.
✓ Branch 3 taken 5473 times.
|
7615 | assert(targetElementType && (targetElementType->isIntegerTy() || |
| 448 | targetElementType->isFloatingPointTy()) && | ||
| 449 | "Target element type is not a scalar type"); | ||
| 450 |
2/4✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7615 times.
|
7615 | assert(ptrToArray && ptrToArray->getType()->isPointerTy() && |
| 451 | "Input to arrayCast is not a pointer type."); | ||
| 452 | |||
| 453 | llvm::Type* arrayType = ptrToArray->getType()->getContainedType(0); | ||
| 454 |
2/4✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7615 times.
|
7615 | assert(arrayType && llvm::isa<llvm::ArrayType>(arrayType)); |
| 455 | |||
| 456 | // getArrayElementType() calls getContainedType(0) | ||
| 457 | llvm::Type* sourceElementType = arrayType->getArrayElementType(); | ||
| 458 |
3/4✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1956 times.
✓ Branch 3 taken 5659 times.
|
7615 | assert(sourceElementType && (sourceElementType->isIntegerTy() || |
| 459 | sourceElementType->isFloatingPointTy()) && | ||
| 460 | "Source element type is not a scalar type"); | ||
| 461 | |||
| 462 |
2/2✓ Branch 0 taken 290 times.
✓ Branch 1 taken 7325 times.
|
7615 | if (sourceElementType == targetElementType) return ptrToArray; |
| 463 | |||
| 464 |
2/4✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 290 times.
✗ Branch 5 not taken.
|
580 | CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType); |
| 465 | |||
| 466 | const size_t elementSize = arrayType->getArrayNumElements(); | ||
| 467 | llvm::Value* targetArray = | ||
| 468 |
1/2✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
|
290 | insertStaticAlloca(builder, |
| 469 |
1/2✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
|
290 | llvm::ArrayType::get(targetElementType, elementSize)); |
| 470 | |||
| 471 |
2/2✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 290 times.
|
1340 | for (size_t i = 0; i < elementSize; ++i) { |
| 472 | 1050 | llvm::Value* target = builder.CreateConstGEP2_64(targetArray, 0, i); | |
| 473 | 1050 | llvm::Value* source = builder.CreateConstGEP2_64(ptrToArray, 0, i); | |
| 474 |
1/4✓ Branch 2 taken 1050 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1050 | source = builder.CreateLoad(source); |
| 475 |
1/2✓ Branch 1 taken 1050 times.
✗ Branch 2 not taken.
|
1050 | source = llvmCastFunction(builder, source, targetElementType); |
| 476 |
1/2✓ Branch 1 taken 1050 times.
✗ Branch 2 not taken.
|
1050 | builder.CreateStore(source, target); |
| 477 | } | ||
| 478 | |||
| 479 | return targetArray; | ||
| 480 | } | ||
| 481 | |||
| 482 | /// @brief Converts a vector of loaded llvm scalar values of the same type to a | ||
| 483 | /// target scalar type. Each value is converted individually and the loaded | ||
| 484 | /// result stored in the same location within values. | ||
| 485 | /// @warning This assumes any integer types are signed. | ||
| 486 | /// @param values A vector of llvm scalar values to convert | ||
| 487 | /// @param targetElementType The target llvm scalar type to convert each value | ||
| 488 | /// of the input vector | ||
| 489 | /// @param builder The current llvm IRBuilder | ||
| 490 | inline void | ||
| 491 | 245 | arithmeticConversion(std::vector<llvm::Value*>& values, | |
| 492 | llvm::Type* targetElementType, | ||
| 493 | llvm::IRBuilder<>& builder) | ||
| 494 | { | ||
| 495 |
3/4✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 239 times.
✓ Branch 3 taken 6 times.
|
245 | assert(targetElementType && (targetElementType->isIntegerTy() || |
| 496 | targetElementType->isFloatingPointTy()) && | ||
| 497 | "Target element type is not a scalar type"); | ||
| 498 | |||
| 499 |
1/2✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
|
245 | llvm::Type* sourceElementType = values.front()->getType(); |
| 500 |
3/4✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 231 times.
✓ Branch 3 taken 14 times.
|
245 | assert(sourceElementType && (sourceElementType->isIntegerTy() || |
| 501 | sourceElementType->isFloatingPointTy()) && | ||
| 502 | "Source element type is not a scalar type"); | ||
| 503 | |||
| 504 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
|
245 | if (sourceElementType == targetElementType) return; |
| 505 | |||
| 506 |
2/4✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 245 times.
✗ Branch 5 not taken.
|
490 | CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType); |
| 507 | |||
| 508 |
2/2✓ Branch 0 taken 739 times.
✓ Branch 1 taken 245 times.
|
984 | for (llvm::Value*& value : values) { |
| 509 |
1/2✓ Branch 1 taken 739 times.
✗ Branch 2 not taken.
|
739 | value = llvmCastFunction(builder, value, targetElementType); |
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 513 | /// @brief Converts a vector of loaded llvm scalar values to the highest precision | ||
| 514 | /// type stored amongst them. Any values which are not scalar types are ignored | ||
| 515 | /// @warning This assumes any integer types are signed. | ||
| 516 | /// @param values A vector of llvm scalar values to convert | ||
| 517 | /// @param builder The current llvm IRBuilder | ||
| 518 | inline void | ||
| 519 | arithmeticConversion(std::vector<llvm::Value*>& values, | ||
| 520 | llvm::IRBuilder<>& builder) | ||
| 521 | { | ||
| 522 | llvm::Type* typeCast = LLVMType<bool>::get(builder.getContext()); | ||
| 523 | for (llvm::Value*& value : values) { | ||
| 524 | llvm::Type* type = value->getType(); | ||
| 525 | if (type->isIntegerTy() || type->isFloatingPointTy()) { | ||
| 526 | typeCast = typePrecedence(typeCast, type); | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | arithmeticConversion(values, typeCast, builder); | ||
| 531 | } | ||
| 532 | |||
| 533 | /// @brief Chooses the highest order llvm Type as defined by typePrecedence | ||
| 534 | /// from either of the two incoming values and casts the other value to | ||
| 535 | /// the choosen type if it is not already. The types of valueA and valueB | ||
| 536 | /// are guaranteed to match. Both values must be scalar LLVM types | ||
| 537 | /// @warning This assumes any integer types are signed. | ||
| 538 | /// @param valueA The first llvm value | ||
| 539 | /// @param valueB The second llvm value | ||
| 540 | /// @param builder The current llvm IRBuilder | ||
| 541 | inline void | ||
| 542 | arithmeticConversion(llvm::Value*& valueA, | ||
| 543 | llvm::Value*& valueB, | ||
| 544 | llvm::IRBuilder<>& builder) | ||
| 545 | { | ||
| 546 | llvm::Type* type = typePrecedence(valueA->getType(), valueB->getType()); | ||
| 547 | valueA = arithmeticConversion(valueA, type, builder); | ||
| 548 | valueB = arithmeticConversion(valueB, type, builder); | ||
| 549 | } | ||
| 550 | |||
| 551 | /// @brief Performs a C style boolean comparison from a given scalar LLVM value | ||
| 552 | /// | ||
| 553 | /// @param value The scalar llvm value to convert to a boolean | ||
| 554 | /// @param builder The current llvm IRBuilder | ||
| 555 | /// | ||
| 556 | inline llvm::Value* | ||
| 557 |
1/2✓ Branch 0 taken 27164 times.
✗ Branch 1 not taken.
|
27164 | boolComparison(llvm::Value* value, |
| 558 | llvm::IRBuilder<>& builder) | ||
| 559 | { | ||
| 560 | llvm::Type* type = value->getType(); | ||
| 561 | |||
| 562 | 80 | if (type->isFloatingPointTy()) return builder.CreateFCmpONE(value, llvm::ConstantFP::get(type, 0.0)); | |
| 563 |
2/2✓ Branch 1 taken 13128 times.
✓ Branch 2 taken 13996 times.
|
40252 | else if (type->isIntegerTy(1)) return builder.CreateICmpNE(value, llvm::ConstantInt::get(type, 0)); |
| 564 |
1/2✓ Branch 0 taken 13996 times.
✗ Branch 1 not taken.
|
27992 | else if (type->isIntegerTy()) return builder.CreateICmpNE(value, llvm::ConstantInt::getSigned(type, 0)); |
| 565 | ✗ | assert(false && "Invalid type for bool conversion"); | |
| 566 | return nullptr; | ||
| 567 | } | ||
| 568 | |||
| 569 | /// @ brief Performs a binary operation on two loaded llvm scalar values of the same type. | ||
| 570 | /// The type of operation performed is defined by the token (see the list of supported | ||
| 571 | /// tokens in ast/Tokens.h. Returns a loaded llvm scalar result | ||
| 572 | /// | ||
| 573 | /// @param lhs The left hand side value of the binary operation | ||
| 574 | /// @param rhs The right hand side value of the binary operation | ||
| 575 | /// @param token The token representing the binary operation to perform | ||
| 576 | /// @param builder The current llvm IRBuilder | ||
| 577 | inline llvm::Value* | ||
| 578 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32850 times.
|
32850 | binaryOperator(llvm::Value* lhs, llvm::Value* rhs, |
| 579 | const ast::tokens::OperatorToken& token, | ||
| 580 | llvm::IRBuilder<>& builder) | ||
| 581 | { | ||
| 582 | llvm::Type* lhsType = lhs->getType(); | ||
| 583 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 32850 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
32850 | assert(lhsType == rhs->getType() || |
| 584 | (token == ast::tokens::SHIFTLEFT || | ||
| 585 | token == ast::tokens::SHIFTRIGHT)); | ||
| 586 | |||
| 587 |
2/2✓ Branch 0 taken 17871 times.
✓ Branch 1 taken 14979 times.
|
32850 | const ast::tokens::OperatorType opType = ast::tokens::operatorType(token); |
| 588 | |||
| 589 | if (opType == ast::tokens::LOGICAL) { | ||
| 590 | 3803 | lhs = boolComparison(lhs, builder); | |
| 591 | 3803 | rhs = boolComparison(rhs, builder); | |
| 592 | lhsType = lhs->getType(); // now bool type | ||
| 593 | } | ||
| 594 | |||
| 595 |
2/4✓ Branch 1 taken 32850 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32850 times.
✗ Branch 5 not taken.
|
32850 | const BinaryFunction llvmBinaryFunction = llvmBinaryConversion(lhsType, token); |
| 596 |
1/2✓ Branch 1 taken 32850 times.
✗ Branch 2 not taken.
|
65700 | return llvmBinaryFunction(builder, lhs, rhs); |
| 597 | } | ||
| 598 | |||
| 599 | /// @brief Unpack a particular element of an array and return a pointer to that element | ||
| 600 | /// The provided llvm Value is expected to be a pointer to an array | ||
| 601 | /// | ||
| 602 | /// @param ptrToArray A llvm value which is a pointer to a llvm array | ||
| 603 | /// @param index The index at which to access the array | ||
| 604 | /// @param builder The current llvm IRBuilder | ||
| 605 | /// | ||
| 606 | inline llvm::Value* | ||
| 607 | arrayIndexUnpack(llvm::Value* ptrToArray, | ||
| 608 | const int16_t index, | ||
| 609 | llvm::IRBuilder<>& builder) | ||
| 610 | { | ||
| 611 | return builder.CreateConstGEP2_64(ptrToArray, 0, index); | ||
| 612 | } | ||
| 613 | |||
| 614 | /// @brief Unpack an array type into llvm Values which represent all its elements | ||
| 615 | /// The provided llvm Value is expected to be a pointer to an array | ||
| 616 | /// If loadElements is true, values will store loaded llvm values instead | ||
| 617 | /// of pointers to the array elements | ||
| 618 | /// | ||
| 619 | /// @param ptrToArray A llvm value which is a pointer to a llvm array | ||
| 620 | /// @param values A vector of llvm values where to store the array elements | ||
| 621 | /// @param builder The current llvm IRBuilder | ||
| 622 | /// @param loadElements Whether or not to load each array element into a register | ||
| 623 | /// | ||
| 624 | inline void | ||
| 625 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3344 times.
|
3344 | arrayUnpack(llvm::Value* ptrToArray, |
| 626 | std::vector<llvm::Value*>& values, | ||
| 627 | llvm::IRBuilder<>& builder, | ||
| 628 | const bool loadElements = false) | ||
| 629 | { | ||
| 630 | const size_t elements = | ||
| 631 | ptrToArray->getType()->getContainedType(0)->getArrayNumElements(); | ||
| 632 | |||
| 633 | 3344 | values.reserve(elements); | |
| 634 |
2/2✓ Branch 0 taken 15324 times.
✓ Branch 1 taken 3344 times.
|
18668 | for (size_t i = 0; i < elements; ++i) { |
| 635 | 15324 | llvm::Value* value = builder.CreateConstGEP2_64(ptrToArray, 0, i); | |
| 636 |
2/2✓ Branch 0 taken 7380 times.
✓ Branch 1 taken 7944 times.
|
15324 | if (loadElements) value = builder.CreateLoad(value); |
| 637 | 15324 | values.push_back(value); | |
| 638 | } | ||
| 639 | 3344 | } | |
| 640 | |||
| 641 | /// @brief Unpack the first three elements of an array. | ||
| 642 | /// The provided llvm Value is expected to be a pointer to an array | ||
| 643 | /// @note The elements are note loaded | ||
| 644 | /// | ||
| 645 | /// @param ptrToArray A llvm value which is a pointer to a llvm array | ||
| 646 | /// @param value1 The first array value | ||
| 647 | /// @param value2 The second array value | ||
| 648 | /// @param value3 The third array value | ||
| 649 | /// @param builder The current llvm IRBuilder | ||
| 650 | /// | ||
| 651 | inline void | ||
| 652 | array3Unpack(llvm::Value* ptrToArray, | ||
| 653 | llvm::Value*& value1, | ||
| 654 | llvm::Value*& value2, | ||
| 655 | llvm::Value*& value3, | ||
| 656 | llvm::IRBuilder<>& builder) | ||
| 657 | { | ||
| 658 | assert(ptrToArray && ptrToArray->getType()->isPointerTy() && | ||
| 659 | "Input to array3Unpack is not a pointer type."); | ||
| 660 | |||
| 661 | value1 = builder.CreateConstGEP2_64(ptrToArray, 0, 0); | ||
| 662 | value2 = builder.CreateConstGEP2_64(ptrToArray, 0, 1); | ||
| 663 | value3 = builder.CreateConstGEP2_64(ptrToArray, 0, 2); | ||
| 664 | } | ||
| 665 | |||
| 666 | /// @brief Pack three values into a new array and return a pointer to the | ||
| 667 | /// newly allocated array. If the values are of a mismatching type, | ||
| 668 | /// the highets order type is uses, as defined by typePrecedence. All | ||
| 669 | /// llvm values are expected to a be a loaded scalar type | ||
| 670 | /// | ||
| 671 | /// @param value1 The first array value | ||
| 672 | /// @param value2 The second array value | ||
| 673 | /// @param value3 The third array value | ||
| 674 | /// @param builder The current llvm IRBuilder | ||
| 675 | /// | ||
| 676 | inline llvm::Value* | ||
| 677 | array3Pack(llvm::Value* value1, | ||
| 678 | llvm::Value* value2, | ||
| 679 | llvm::Value* value3, | ||
| 680 | llvm::IRBuilder<>& builder) | ||
| 681 | { | ||
| 682 | llvm::Type* type = typePrecedence(value1->getType(), value2->getType()); | ||
| 683 | type = typePrecedence(type, value3->getType()); | ||
| 684 | |||
| 685 | value1 = arithmeticConversion(value1, type, builder); | ||
| 686 | value2 = arithmeticConversion(value2, type, builder); | ||
| 687 | value3 = arithmeticConversion(value3, type, builder); | ||
| 688 | |||
| 689 | llvm::Type* vectorType = llvm::ArrayType::get(type, 3); | ||
| 690 | llvm::Value* vector = insertStaticAlloca(builder, vectorType); | ||
| 691 | |||
| 692 | llvm::Value* e1 = builder.CreateConstGEP2_64(vector, 0, 0); | ||
| 693 | llvm::Value* e2 = builder.CreateConstGEP2_64(vector, 0, 1); | ||
| 694 | llvm::Value* e3 = builder.CreateConstGEP2_64(vector, 0, 2); | ||
| 695 | |||
| 696 | builder.CreateStore(value1, e1); | ||
| 697 | builder.CreateStore(value2, e2); | ||
| 698 | builder.CreateStore(value3, e3); | ||
| 699 | |||
| 700 | return vector; | ||
| 701 | } | ||
| 702 | |||
| 703 | /// @brief Pack a loaded llvm scalar value into a new array of a specified | ||
| 704 | /// size and return a pointer to the newly allocated array. Each element | ||
| 705 | /// of the new array will have the value of the given scalar | ||
| 706 | /// | ||
| 707 | /// @param value The uniform scalar llvm value to pack into the array | ||
| 708 | /// @param builder The current llvm IRBuilder | ||
| 709 | /// @param size The size of the newly allocated array | ||
| 710 | /// | ||
| 711 | inline llvm::Value* | ||
| 712 | 32 | arrayPack(llvm::Value* value, | |
| 713 | llvm::IRBuilder<>& builder, | ||
| 714 | const size_t size = 3) | ||
| 715 | { | ||
| 716 |
2/4✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
32 | assert(value && (value->getType()->isIntegerTy() || |
| 717 | value->getType()->isFloatingPointTy()) && | ||
| 718 | "value type is not a scalar type"); | ||
| 719 | |||
| 720 | llvm::Type* type = value->getType(); | ||
| 721 | llvm::Value* array = | ||
| 722 | 32 | insertStaticAlloca(builder, | |
| 723 | 32 | llvm::ArrayType::get(type, size)); | |
| 724 | |||
| 725 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 32 times.
|
128 | for (size_t i = 0; i < size; ++i) { |
| 726 | 96 | llvm::Value* element = builder.CreateConstGEP2_64(array, 0, i); | |
| 727 | 96 | builder.CreateStore(value, element); | |
| 728 | } | ||
| 729 | |||
| 730 | 32 | return array; | |
| 731 | } | ||
| 732 | |||
| 733 | /// @brief Pack a vector of loaded llvm scalar values into a new array of | ||
| 734 | /// equal size and return a pointer to the newly allocated array. | ||
| 735 | /// | ||
| 736 | /// @param values A vector of loaded llvm scalar values to pack | ||
| 737 | /// @param builder The current llvm IRBuilder | ||
| 738 | /// | ||
| 739 | inline llvm::Value* | ||
| 740 | 4028 | arrayPack(const std::vector<llvm::Value*>& values, | |
| 741 | llvm::IRBuilder<>& builder) | ||
| 742 | { | ||
| 743 | 4028 | llvm::Type* type = values.front()->getType(); | |
| 744 | 4028 | llvm::Value* array = insertStaticAlloca(builder, | |
| 745 | 4028 | llvm::ArrayType::get(type, values.size())); | |
| 746 | |||
| 747 | size_t idx = 0; | ||
| 748 |
2/2✓ Branch 0 taken 22719 times.
✓ Branch 1 taken 4028 times.
|
26747 | for (llvm::Value* const& value : values) { |
| 749 | 22719 | llvm::Value* element = builder.CreateConstGEP2_64(array, 0, idx++); | |
| 750 | 22719 | builder.CreateStore(value, element); | |
| 751 | } | ||
| 752 | |||
| 753 | 4028 | return array; | |
| 754 | } | ||
| 755 | |||
| 756 | /// @brief Pack a vector of loaded llvm scalar values into a new array of | ||
| 757 | /// equal size and return a pointer to the newly allocated array. | ||
| 758 | /// arrayPackCast first checks all the contained types in values | ||
| 759 | /// and casts all types to the highest order type present. All llvm | ||
| 760 | /// values in values are expected to be loaded scalar types | ||
| 761 | /// | ||
| 762 | /// @param values A vector of loaded llvm scalar values to pack | ||
| 763 | /// @param builder The current llvm IRBuilder | ||
| 764 | /// | ||
| 765 | inline llvm::Value* | ||
| 766 | 3931 | arrayPackCast(std::vector<llvm::Value*>& values, | |
| 767 | llvm::IRBuilder<>& builder) | ||
| 768 | { | ||
| 769 | // get the highest order type present | ||
| 770 | |||
| 771 | llvm::Type* type = LLVMType<bool>::get(builder.getContext()); | ||
| 772 |
2/2✓ Branch 0 taken 21943 times.
✓ Branch 1 taken 3931 times.
|
25874 | for (llvm::Value* const& value : values) { |
| 773 | 21943 | type = typePrecedence(type, value->getType()); | |
| 774 | } | ||
| 775 | |||
| 776 | // convert all to this type | ||
| 777 | |||
| 778 |
2/2✓ Branch 0 taken 21943 times.
✓ Branch 1 taken 3931 times.
|
25874 | for (llvm::Value*& value : values) { |
| 779 | 21943 | value = arithmeticConversion(value, type, builder); | |
| 780 | } | ||
| 781 | |||
| 782 | 3931 | return arrayPack(values, builder); | |
| 783 | } | ||
| 784 | |||
| 785 | inline llvm::Value* | ||
| 786 | 118 | scalarToMatrix(llvm::Value* scalar, | |
| 787 | llvm::IRBuilder<>& builder, | ||
| 788 | const size_t dim = 3) | ||
| 789 | { | ||
| 790 |
3/4✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 2 times.
|
118 | assert(scalar && (scalar->getType()->isIntegerTy() || |
| 791 | scalar->getType()->isFloatingPointTy()) && | ||
| 792 | "value type is not a scalar type"); | ||
| 793 | |||
| 794 | llvm::Type* type = scalar->getType(); | ||
| 795 | llvm::Value* array = | ||
| 796 | 118 | insertStaticAlloca(builder, | |
| 797 | 118 | llvm::ArrayType::get(type, dim*dim)); | |
| 798 | |||
| 799 | 118 | llvm::Value* zero = llvmConstant(0, type); | |
| 800 |
2/2✓ Branch 0 taken 1426 times.
✓ Branch 1 taken 118 times.
|
1544 | for (size_t i = 0; i < dim*dim; ++i) { |
| 801 |
2/2✓ Branch 0 taken 1020 times.
✓ Branch 1 taken 406 times.
|
1426 | llvm::Value* m = ((i % (dim+1) == 0) ? scalar : zero); |
| 802 | 1426 | llvm::Value* element = builder.CreateConstGEP2_64(array, 0, i); | |
| 803 | 1426 | builder.CreateStore(m, element); | |
| 804 | } | ||
| 805 | |||
| 806 | 118 | return array; | |
| 807 | } | ||
| 808 | |||
| 809 | } // namespace codegen | ||
| 810 | } // namespace ax | ||
| 811 | } // namespace OPENVDB_VERSION_NAME | ||
| 812 | } // namespace openvdb | ||
| 813 | |||
| 814 | #endif // OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED | ||
| 815 | |||
| 816 |