| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright Contributors to the OpenVDB Project | ||
| 2 | // SPDX-License-Identifier: MPL-2.0 | ||
| 3 | |||
| 4 | /// @file codegen/ConstantFolding.h | ||
| 5 | /// | ||
| 6 | /// @authors Nick Avramoussis | ||
| 7 | /// | ||
| 8 | /// @brief Constant folding for C++ bindings. | ||
| 9 | /// | ||
| 10 | |||
| 11 | #ifndef OPENVDB_AX_CODEGEN_CONSTANT_FOLDING_HAS_BEEN_INCLUDED | ||
| 12 | #define OPENVDB_AX_CODEGEN_CONSTANT_FOLDING_HAS_BEEN_INCLUDED | ||
| 13 | |||
| 14 | #include "Types.h" | ||
| 15 | |||
| 16 | #include <openvdb/version.h> | ||
| 17 | |||
| 18 | #include <llvm/IR/Constants.h> | ||
| 19 | |||
| 20 | #include <type_traits> | ||
| 21 | #include <vector> | ||
| 22 | |||
| 23 | namespace openvdb { | ||
| 24 | OPENVDB_USE_VERSION_NAMESPACE | ||
| 25 | namespace OPENVDB_VERSION_NAME { | ||
| 26 | |||
| 27 | namespace ax { | ||
| 28 | namespace codegen { | ||
| 29 | |||
| 30 | /// @brief Constant folding support structure | ||
| 31 | /// | ||
| 32 | template <typename SignatureT, | ||
| 33 | size_t I = FunctionTraits<SignatureT>::N_ARGS> | ||
| 34 | struct ConstantFolder | ||
| 35 | { | ||
| 36 | using ArgT = typename FunctionTraits<SignatureT>::template Arg<I-1>; | ||
| 37 | using ArgumentValueType = typename ArgT::Type; | ||
| 38 | |||
| 39 | // @brief Attempts evaluate a given function with a provided set of constant llvm | ||
| 40 | // values. If successful, the function is invoked and the result is stored | ||
| 41 | // and returned in an llvm::Value. | ||
| 42 | // @details Currently only scalar constant folding is supported due to the way | ||
| 43 | // vectors and matrices are alloced. Functions which return void are also | ||
| 44 | // not supported for constant folding. | ||
| 45 | // @param args The vector of llvm constants that comprise the function arguments. | ||
| 46 | // Note that the size of this vector is expected to match the size of | ||
| 47 | // the required function arguments and the templated parameter I | ||
| 48 | // @param function The function to invoke if all arguments have a valid mapping. | ||
| 49 | // @param C The llvm Context | ||
| 50 | // @param ts The list of evaluated C types from the provided llvm constants. This | ||
| 51 | // is expected to be empty (not provided) on the first call to fold and | ||
| 52 | // is used on subsequent recursive calls. | ||
| 53 | template <typename ...Tys> | ||
| 54 | static llvm::Value* | ||
| 55 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 797 times.
|
1594 | fold(const std::vector<llvm::Constant*>& args, |
| 56 | const SignatureT& function, | ||
| 57 | llvm::LLVMContext& C, | ||
| 58 | Tys&&... ts) | ||
| 59 | { | ||
| 60 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 797 times.
|
1594 | assert(I-1 < args.size()); |
| 61 |
2/2✓ Branch 0 taken 132 times.
✓ Branch 1 taken 665 times.
|
1594 | llvm::Constant* constant = args[I-1]; |
| 62 | const llvm::Type* type = constant->getType(); | ||
| 63 |
2/2✓ Branch 0 taken 132 times.
✓ Branch 1 taken 665 times.
|
1594 | if (type->isIntegerTy()) { |
| 64 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
|
264 | assert(llvm::isa<llvm::ConstantInt>(constant)); |
| 65 | llvm::ConstantInt* cint = | ||
| 66 | 264 | llvm::cast<llvm::ConstantInt>(constant); | |
| 67 | const uint64_t val = cint->getLimitedValue(); | ||
| 68 | return call<uint64_t, ArgumentValueType>(args, function, C, val, ts...); | ||
| 69 | } | ||
| 70 |
4/4✓ Branch 0 taken 436 times.
✓ Branch 1 taken 229 times.
✓ Branch 2 taken 360 times.
✓ Branch 3 taken 76 times.
|
1330 | else if (type->isFloatTy() || type->isDoubleTy()) { |
| 71 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
|
1178 | assert(llvm::isa<llvm::ConstantFP>(constant)); |
| 72 | llvm::ConstantFP* cfp = | ||
| 73 | 1178 | llvm::cast<llvm::ConstantFP>(constant); | |
| 74 | const llvm::APFloat& apf = cfp->getValueAPF(); | ||
| 75 |
2/2✓ Branch 0 taken 229 times.
✓ Branch 1 taken 360 times.
|
1178 | if (type->isFloatTy()) { |
| 76 | 458 | const float val = apf.convertToFloat(); | |
| 77 | return call<float, ArgumentValueType>(args, function, C, val, ts...); | ||
| 78 | } | ||
| 79 |
1/2✓ Branch 0 taken 360 times.
✗ Branch 1 not taken.
|
720 | if (type->isDoubleTy()) { |
| 80 | 720 | const double val = apf.convertToDouble(); | |
| 81 | return call<double, ArgumentValueType>(args, function, C, val, ts...); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | else if (type->isArrayTy()) { | ||
| 85 | // @todo currently all arrays are alloced anyway which | ||
| 86 | // needs to be handled or changed | ||
| 87 | return nullptr; | ||
| 88 | } | ||
| 89 | // fallback | ||
| 90 | return nullptr; | ||
| 91 | } | ||
| 92 | private: | ||
| 93 | // @brief Specialization for supported implicit casting matching AX's supported | ||
| 94 | // scalar casting. Continues to traverse the constant argument list. | ||
| 95 | template <typename In, typename Out, typename ...Tys> | ||
| 96 | static typename std::enable_if<std::is_convertible<In, Out>::value, llvm::Value*>::type | ||
| 97 | call(const std::vector<llvm::Constant*>& args, | ||
| 98 | const SignatureT& function, | ||
| 99 | llvm::LLVMContext& C, | ||
| 100 | const In& arg, | ||
| 101 | Tys&&... ts) | ||
| 102 | { | ||
| 103 | using Next = ConstantFolder<SignatureT, I-1>; | ||
| 104 | 280 | return Next::fold(args, function, C, Out(arg), ts...); | |
| 105 | } | ||
| 106 | |||
| 107 | // @brief Specialization for unsupported implicit casting. Bails out with a | ||
| 108 | // nullptr return. | ||
| 109 | template <typename In, typename Out, typename ...Tys> | ||
| 110 | static typename std::enable_if<!std::is_convertible<In, Out>::value, llvm::Value*>::type | ||
| 111 | call(const std::vector<llvm::Constant*>&, | ||
| 112 | const SignatureT&, | ||
| 113 | llvm::LLVMContext&, | ||
| 114 | const In&, Tys&&...) | ||
| 115 | { | ||
| 116 | return nullptr; | ||
| 117 | } | ||
| 118 | }; | ||
| 119 | |||
| 120 | template <typename SignatureT> | ||
| 121 | struct ConstantFolder<SignatureT, 0> | ||
| 122 | { | ||
| 123 | // @brief The final call to fold when all arguments have been evaluated (or no | ||
| 124 | // arguments exist). | ||
| 125 | template <typename ...Tys> | ||
| 126 | static llvm::Value* | ||
| 127 | fold(const std::vector<llvm::Constant*>& args, | ||
| 128 | const SignatureT& function, | ||
| 129 | llvm::LLVMContext& C, | ||
| 130 | Tys&&... ts) | ||
| 131 | { | ||
| 132 | using ReturnT = typename FunctionTraits<SignatureT>::ReturnType; | ||
| 133 | return call<ReturnT>(args, function, C, ts...); | ||
| 134 | } | ||
| 135 | |||
| 136 | private: | ||
| 137 | |||
| 138 | // @brief Specialization for the invoking of the provided function if the return | ||
| 139 | // type is not void or a pointer | ||
| 140 | template <typename ReturnT, typename ...Tys> | ||
| 141 | static typename std::enable_if<!std::is_pointer<ReturnT>::value && | ||
| 142 | !std::is_same<ReturnT, void>::value, llvm::Value*>::type | ||
| 143 | call(const std::vector<llvm::Constant*>&, | ||
| 144 | const SignatureT& function, | ||
| 145 | llvm::LLVMContext& C, | ||
| 146 | Tys&&... ts) | ||
| 147 | { | ||
| 148 |
1/6✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
|
442 | const ReturnT result = function(ts...); |
| 149 |
1/6✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
|
442 | return LLVMType<ReturnT>::get(C, result); |
| 150 | } | ||
| 151 | |||
| 152 | // @brief Specialization if the return type is void or a pointer. No folding is | ||
| 153 | // supported. | ||
| 154 | template <typename ReturnT, typename ...Tys> | ||
| 155 | static typename std::enable_if<std::is_pointer<ReturnT>::value || | ||
| 156 | std::is_same<ReturnT, void>::value, llvm::Value*>::type | ||
| 157 | call(const std::vector<llvm::Constant*>&, | ||
| 158 | const SignatureT&, | ||
| 159 | llvm::LLVMContext&, | ||
| 160 | Tys&&...) | ||
| 161 | { | ||
| 162 | return nullptr; | ||
| 163 | } | ||
| 164 | }; | ||
| 165 | |||
| 166 | } // namespace codegen | ||
| 167 | } // namespace ax | ||
| 168 | } // namespace OPENVDB_VERSION_NAME | ||
| 169 | } // namespace openvdb | ||
| 170 | |||
| 171 | #endif // OPENVDB_AX_CODEGEN_CONSTANT_FOLDING_HAS_BEEN_INCLUDED | ||
| 172 | |||
| 173 |