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