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