OpenVDB  8.2.0
Types.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file codegen/Types.h
5 ///
6 /// @authors Nick Avramoussis
7 ///
8 /// @brief Consolidated llvm types for most supported types
9 ///
10 
11 #ifndef OPENVDB_AX_CODEGEN_TYPES_HAS_BEEN_INCLUDED
12 #define OPENVDB_AX_CODEGEN_TYPES_HAS_BEEN_INCLUDED
13 
14 #include "openvdb_ax/ast/Tokens.h"
15 #include "openvdb_ax/Exceptions.h"
16 #include "String.h"
17 
18 #include <openvdb/version.h>
19 #include <openvdb/Types.h>
20 #include <openvdb/math/Mat3.h>
21 #include <openvdb/math/Mat4.h>
22 #include <openvdb/math/Vec3.h>
23 
24 #include <llvm/IR/Constants.h>
25 #include <llvm/IR/IRBuilder.h>
26 #include <llvm/IR/LLVMContext.h>
27 
28 #include <type_traits>
29 
30 namespace openvdb {
32 namespace OPENVDB_VERSION_NAME {
33 
34 namespace ax {
35 namespace codegen {
36 
37 template <size_t Bits> struct int_t;
38 template <> struct int_t<8> { using type = int8_t; };
39 template <> struct int_t<16> { using type = int16_t; };
40 template <> struct int_t<32> { using type = int32_t; };
41 template <> struct int_t<64> { using type = int64_t; };
42 
43 /// @brief LLVM type mapping from pod types
44 /// @note LLVM Types do not store information about the value sign, only meta
45 /// information about the primitive type (i.e. float, int, pointer) and
46 /// the precision width. LLVMType<uint64_t>::get(C) will provide the same
47 /// type as LLVMType<int64_t>::get(C), however sign is taken into account
48 /// during construction of LLVM constants.
49 /// @note LLVMType classes are importantly used to provided automatic external
50 /// function mapping. Note that references are not supported, pointers
51 /// should be used instead.
52 /// @note Provide your own custom class mapping by specializing the below.
53 template <typename T>
54 struct LLVMType
55 {
56  static_assert(!std::is_reference<T>::value,
57  "Reference types/arguments are not supported for automatic "
58  "LLVM Type conversion. Use pointers instead.");
59  static_assert(!std::is_class<T>::value,
60  "Object types/arguments are not supported for automatic "
61  "LLVM Type conversion.");
62 
63  /// @brief Return an LLVM type which represents T
64  /// @param C The LLVMContext to request the Type from.
65  static inline llvm::Type*
66  get(llvm::LLVMContext& C)
67  {
68  // @note bools always treated as i1 values as the constants
69  // true and false from the IRBuilder are i1
70  if (std::is_same<T, bool>::value) {
71  return llvm::Type::getInt1Ty(C);
72  }
73 
74 #if LLVM_VERSION_MAJOR > 6
75  return llvm::Type::getScalarTy<T>(C);
76 #else
77  int bits = sizeof(T) * CHAR_BIT;
78  if (std::is_integral<T>::value) {
79  return llvm::Type::getIntNTy(C, bits);
80  }
81  else if (std::is_floating_point<T>::value) {
82  switch (bits) {
83  case 32: return llvm::Type::getFloatTy(C);
84  case 64: return llvm::Type::getDoubleTy(C);
85  }
86  }
87  OPENVDB_THROW(AXCodeGenError, "LLVMType called with an unsupported type \"" +
88  std::string(typeNameAsString<T>()) + "\".");
89 #endif
90  }
91 
92  /// @brief Return an LLVM constant Value which represents T value
93  /// @param C The LLVMContext
94  /// @param V The value to convert to an LLVM constant
95  /// @return If successful, returns a pointer to an LLVM constant which
96  /// holds the value T.
97  static inline llvm::Constant*
98  get(llvm::LLVMContext& C, const T V)
99  {
100  llvm::Type* type = LLVMType<T>::get(C);
101  llvm::Constant* constant = nullptr;
102 
103  if (std::is_floating_point<T>::value) {
104  assert(llvm::ConstantFP::isValueValidForType(type,
105  llvm::APFloat(static_cast<typename std::conditional
106  <std::is_floating_point<T>::value, T, double>::type>(V))));
107  constant = llvm::ConstantFP::get(type, static_cast<double>(V));
108  }
109  else if (std::is_integral<T>::value) {
110  const constexpr bool isSigned = std::is_signed<T>::value;
111  assert((isSigned && llvm::ConstantInt::isValueValidForType(type, static_cast<int64_t>(V))) ||
112  (!isSigned && llvm::ConstantInt::isValueValidForType(type, static_cast<uint64_t>(V))));
113  constant = llvm::ConstantInt::get(type, static_cast<uint64_t>(V), isSigned);
114  }
115 
116  assert(constant);
117  return constant;
118  }
119 
120  /// @brief Return an LLVM constant which holds an uintptr_t, representing
121  /// the current address of the given value.
122  /// @param C The LLVMContext
123  /// @param V The address of a given type to convert to an LLVM constant
124  static inline llvm::Constant*
125  get(llvm::LLVMContext& C, const T* const V)
126  {
127  return LLVMType<uintptr_t>::get(C,
128  reinterpret_cast<uintptr_t>(V));
129  }
130 };
131 
132 template <typename T, size_t S>
133 struct LLVMType<T[S]>
134 {
135  static_assert(S != 0,
136  "Zero size array types are not supported for automatic LLVM "
137  "Type conversion");
138 
139  static inline llvm::Type*
140  get(llvm::LLVMContext& C) {
141  return llvm::ArrayType::get(LLVMType<T>::get(C), S);
142  }
143  static inline llvm::Constant*
144  get(llvm::LLVMContext& C, const T(&array)[S]) {
145  return llvm::ConstantDataArray::get(C, array);
146  }
147  static inline llvm::Constant*
148  get(llvm::LLVMContext& C, const T(*array)[S])
149  {
150  return LLVMType<uintptr_t>::get(C,
151  reinterpret_cast<uintptr_t>(array));
152  }
153 };
154 
155 template <typename T>
156 struct LLVMType<T*>
157 {
158  static inline llvm::PointerType*
159  get(llvm::LLVMContext& C) {
160  return LLVMType<T>::get(C)->getPointerTo(0);
161  }
162 };
163 
164 template <>
165 struct LLVMType<char> : public LLVMType<uint8_t>
166 {
167  static_assert(std::is_same<uint8_t, unsigned char>::value,
168  "This library requires std::uint8_t to be implemented as unsigned char.");
169 };
170 
171 template <>
172 struct LLVMType<codegen::String>
173 {
174  static inline llvm::StructType*
175  get(llvm::LLVMContext& C) {
176  const std::vector<llvm::Type*> types {
177  LLVMType<char*>::get(C), // ptr
179  LLVMType<int64_t>::get(C) // size
180  };
181  return llvm::StructType::get(C, types);
182  }
183  static inline llvm::Constant*
184  get(llvm::LLVMContext& C, const codegen::String* const string)
185  {
186  return LLVMType<uintptr_t>::get(C,
187  reinterpret_cast<uintptr_t>(string));
188  }
189 };
190 
191 template <>
192 struct LLVMType<void>
193 {
194  static inline llvm::Type*
195  get(llvm::LLVMContext& C) {
196  return llvm::Type::getVoidTy(C);
197  }
198 };
199 
200 /// @note void* implemented as signed int_t* to match clang IR generation
201 template <> struct LLVMType<void*> : public LLVMType<int_t<sizeof(void*)>::type*> {};
202 
203 template <typename T> struct LLVMType<const T> : public LLVMType<T> {};
204 template <typename T> struct LLVMType<const T*> : public LLVMType<T*> {};
205 
206 /// @brief Alias mapping between two types, a frontend type T1 and a backend
207 /// type T2. This class is the intended interface for binding objects
208 /// which implement supported backend AX/IR types to this given backend
209 /// type. More specifically, it's current and expected usage is limited
210 /// to objects which hold a single member of a supported backend type
211 /// and implements a StandardLayoutType as defined by the standard.
212 /// Fundamentally, T1->T2 mapping should be supported by
213 /// reinterpret_cast<> as defined by the type aliasing rules.
214 /// @note The static asserts provide preliminary checks but are by no means
215 /// a guarantee that a provided mapping is correct. Ensure the above
216 /// requirements are met when instantiating an alias.
217 template <typename T1, typename T2>
219 {
221 
222  static_assert(sizeof(T1) == sizeof(T2),
223  "T1 differs in size to T2 during alias mapping. Types should have "
224  "the same memory layout.");
225  static_assert(std::is_standard_layout<T1>::value,
226  "T1 in instantiation of an AliasTypeMap does not have a standard layout. "
227  "This will most likely cause undefined behaviour when attempting to map "
228  "T1->T2.");
229 
230  static inline llvm::Type*
231  get(llvm::LLVMContext& C) {
232  return LLVMTypeT::get(C);
233  }
234  static inline llvm::Constant*
235  get(llvm::LLVMContext& C, const T1& value) {
236  return LLVMTypeT::get(C, reinterpret_cast<const T2&>(value));
237  }
238  static inline llvm::Constant*
239  get(llvm::LLVMContext& C, const T1* const value) {
240  return LLVMTypeT::get(C, reinterpret_cast<const T2* const>(value));
241  }
242 };
243 
244 /// @brief Supported aliasing for VDB math types, allowing use in external
245 /// function signatures.
246 template <typename T> struct LLVMType<math::Vec2<T>> : public AliasTypeMap<math::Vec2<T>, T[2]> {};
247 template <typename T> struct LLVMType<math::Vec3<T>> : public AliasTypeMap<math::Vec3<T>, T[3]> {};
248 template <typename T> struct LLVMType<math::Vec4<T>> : public AliasTypeMap<math::Vec4<T>, T[4]> {};
249 template <typename T> struct LLVMType<math::Mat3<T>> : public AliasTypeMap<math::Mat3<T>, T[9]> {};
250 template <typename T> struct LLVMType<math::Mat4<T>> : public AliasTypeMap<math::Mat4<T>, T[16]> {};
251 
252 ///////////////////////////////////////////////////////////////////////////
253 ///////////////////////////////////////////////////////////////////////////
254 
255 /// @brief Templated function traits which provides compile-time index access to
256 /// the types of the function signature
257 ///
258 template<typename SignatureT>
260 
261 template<typename R, typename... Args>
262 struct FunctionTraits<R(&)(Args...)> : public FunctionTraits<R(Args...)> {};
263 
264 template<typename R, typename... Args>
265 struct FunctionTraits<R(*)(Args...)> : public FunctionTraits<R(Args...)> {};
266 
267 template<typename ReturnT, typename ...Args>
268 struct FunctionTraits<ReturnT(Args...)>
269 {
270  using ReturnType = ReturnT;
271  using SignatureType = ReturnType(Args...);
272  static const size_t N_ARGS = sizeof...(Args);
273 
274  template <size_t I>
275  struct Arg
276  {
277  public:
278  static_assert(I < N_ARGS,
279  "Invalid index specified for function argument access");
280  using Type = typename std::tuple_element<I, std::tuple<Args...>>::type;
281  static_assert(!std::is_reference<Type>::value,
282  "Reference types/arguments are not supported for automatic "
283  "LLVM Type conversion. Use pointers instead.");
284  };
285 };
286 
287 ///////////////////////////////////////////////////////////////////////////
288 ///////////////////////////////////////////////////////////////////////////
289 
290 /// @brief Returns an llvm Constant holding a scalar value
291 /// @param t The scalar constant
292 /// @param type The LLVM type. Can differ from the type of t, in which
293 /// case the value will be cast to the llvm type
294 ///
295 template <typename T>
296 inline llvm::Constant*
297 llvmConstant(const T t, llvm::Type* type)
298 {
299  static_assert(std::is_floating_point<T>::value || std::is_integral<T>::value,
300  "T type for llvmConstant must be a floating point or integral type.");
301 
302  if (type->isIntegerTy()) {
303  return llvm::ConstantInt::get(type, static_cast<uint64_t>(t), /*signed*/true);
304  }
305  else {
306  assert(type->isFloatingPointTy());
307  return llvm::ConstantFP::get(type, static_cast<double>(t));
308  }
309 }
310 
311 /// @brief Returns an llvm IntegerType given a requested size and context
312 /// @param size The number of bits of the integer type
313 /// @param C The LLVMContext to request the Type from.
314 ///
315 llvm::IntegerType* llvmIntType(const uint32_t size, llvm::LLVMContext& C);
316 
317 /// @brief Returns an llvm floating point Type given a requested size and context
318 /// @param size The size of the float to request, i.e. float - 32, double - 64 etc.
319 /// @param C The LLVMContext to request the Type from.
320 ///
321 llvm::Type* llvmFloatType(const uint32_t size, llvm::LLVMContext& C);
322 
323 /// @brief Returns an llvm type representing a type defined by a string.
324 /// @note For string types, this function returns the element type, not the
325 /// object type! The llvm type representing a char block of memory
326 /// is LLVMType<char*>::get(C);
327 /// @param type The AX token type
328 /// @param C The LLVMContext to request the Type from.
329 ///
330 llvm::Type* llvmTypeFromToken(const ast::tokens::CoreType& type, llvm::LLVMContext& C);
331 
332 /// @brief Return a corresponding AX token which represents the given LLVM Type.
333 /// @note If the type does not exist in AX, ast::tokens::UNKNOWN is returned.
334 /// Must not be a nullptr.
335 /// @param type a valid LLVM Type
336 ///
337 ast::tokens::CoreType tokenFromLLVMType(const llvm::Type* type);
338 
339 } // namespace codegen
340 } // namespace ax
341 } // namespace OPENVDB_VERSION_NAME
342 } // namespace openvdb
343 
344 #endif // OPENVDB_AX_CODEGEN_TYPES_HAS_BEEN_INCLUDED
345 
Provides the class definition for the equivalent IR representation and logic for strings in AX.
Various function and operator tokens used throughout the AST and code generation.
OpenVDB AX Exceptions.
Definition: Exceptions.h:36
3x3 matrix class.
Definition: Mat3.h:29
4x4 -matrix class.
Definition: Mat4.h:24
Definition: Vec2.h:24
Definition: Vec3.h:24
Definition: Vec4.h:25
CoreType
Definition: Tokens.h:32
llvm::IntegerType * llvmIntType(const uint32_t size, llvm::LLVMContext &C)
Returns an llvm IntegerType given a requested size and context.
llvm::Type * llvmTypeFromToken(const ast::tokens::CoreType &type, llvm::LLVMContext &C)
Returns an llvm type representing a type defined by a string.
llvm::Type * llvmFloatType(const uint32_t size, llvm::LLVMContext &C)
Returns an llvm floating point Type given a requested size and context.
ast::tokens::CoreType tokenFromLLVMType(const llvm::Type *type)
Return a corresponding AX token which represents the given LLVM Type.
llvm::Constant * llvmConstant(const T t, llvm::Type *type)
Returns an llvm Constant holding a scalar value.
Definition: Types.h:297
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Alias mapping between two types, a frontend type T1 and a backend type T2. This class is the intended...
Definition: Types.h:219
static llvm::Type * get(llvm::LLVMContext &C)
Definition: Types.h:231
static llvm::Constant * get(llvm::LLVMContext &C, const T1 &value)
Definition: Types.h:235
static llvm::Constant * get(llvm::LLVMContext &C, const T1 *const value)
Definition: Types.h:239
typename std::tuple_element< I, std::tuple< Args... > >::type Type
Definition: Types.h:280
ReturnType(Args...) SignatureType
Definition: Types.h:271
Templated function traits which provides compile-time index access to the types of the function signa...
Definition: Types.h:259
static llvm::PointerType * get(llvm::LLVMContext &C)
Definition: Types.h:159
static llvm::Type * get(llvm::LLVMContext &C)
Definition: Types.h:140
static llvm::Constant * get(llvm::LLVMContext &C, const T(*array)[S])
Definition: Types.h:148
static llvm::Constant * get(llvm::LLVMContext &C, const T(&array)[S])
Definition: Types.h:144
static llvm::Constant * get(llvm::LLVMContext &C, const codegen::String *const string)
Definition: Types.h:184
static llvm::StructType * get(llvm::LLVMContext &C)
Definition: Types.h:175
static llvm::Type * get(llvm::LLVMContext &C)
Definition: Types.h:195
LLVM type mapping from pod types.
Definition: Types.h:55
static llvm::Constant * get(llvm::LLVMContext &C, const T V)
Return an LLVM constant Value which represents T value.
Definition: Types.h:98
static llvm::Type * get(llvm::LLVMContext &C)
Return an LLVM type which represents T.
Definition: Types.h:66
static llvm::Constant * get(llvm::LLVMContext &C, const T *const V)
Return an LLVM constant which holds an uintptr_t, representing the current address of the given value...
Definition: Types.h:125
An extremely basic but native representation of a string class with SSO support. This exists to provi...
Definition: String.h:34
int16_t type
Definition: Types.h:39
int32_t type
Definition: Types.h:40
int64_t type
Definition: Types.h:41
int8_t type
Definition: Types.h:38
Definition: Types.h:37
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:180