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