OpenVDB 12.0.0
 
Loading...
Searching...
No Matches
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
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
31namespace openvdb {
33namespace OPENVDB_VERSION_NAME {
34
35namespace ax {
36namespace codegen {
37
38template <size_t Bits> struct int_t;
39template <> struct int_t<8> { using type = int8_t; };
40template <> struct int_t<16> { using type = int16_t; };
41template <> struct int_t<32> { using type = int32_t; };
42template <> 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.
54template <typename T>
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 {
130 reinterpret_cast<uintptr_t>(V));
131 }
132};
133
134template <typename T, size_t S>
135struct 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 {
153 reinterpret_cast<uintptr_t>(array));
154 }
155};
156
157template <typename T>
158struct LLVMType<T*>
159{
160 static inline llvm::PointerType*
161 get(llvm::LLVMContext& C) {
162 return LLVMType<T>::get(C)->getPointerTo(0);
163 }
164};
165
166template <>
167struct 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
173template <>
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 {
189 reinterpret_cast<uintptr_t>(string));
190 }
191};
192
193template <>
194struct 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
203template <> struct LLVMType<void*> : public LLVMType<int8_t*> {};
204template <> 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
224template <typename T> struct LLVMType<const T> : public LLVMType<T> {};
225template <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.
238template <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.
267template <typename T> struct LLVMType<openvdb::math::Vec2<T>> : public AliasTypeMap<openvdb::math::Vec2<T>, T[2]> {};
268template <typename T> struct LLVMType<openvdb::math::Vec3<T>> : public AliasTypeMap<openvdb::math::Vec3<T>, T[3]> {};
269template <typename T> struct LLVMType<openvdb::math::Vec4<T>> : public AliasTypeMap<openvdb::math::Vec4<T>, T[4]> {};
270template <typename T> struct LLVMType<openvdb::math::Mat3<T>> : public AliasTypeMap<openvdb::math::Mat3<T>, T[9]> {};
271template <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///
279template<typename SignatureT>
281
282template<typename R, typename... Args>
283struct FunctionTraits<R(&)(Args...)> : public FunctionTraits<R(Args...)> {};
284
285template<typename R, typename... Args>
286struct 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
292template<typename R, typename... Args>
293struct FunctionTraits<R(Args...) noexcept> : public FunctionTraits<R(Args...)> {};
294
295template<typename R, typename... Args>
296struct FunctionTraits<R(*)(Args...) noexcept> : public FunctionTraits<R(Args...)> {};
297#endif
298
299template<typename ReturnT, typename ...Args>
300struct 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///
327template <typename T>
328inline llvm::Constant*
329llvmConstant(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///
347OPENVDB_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///
353OPENVDB_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///
362OPENVDB_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
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
#define OPENVDB_AX_API
Definition Platform.h:289
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:31
Definition Vec2.h:24
Definition Vec3.h:25
Definition Vec4.h:25
CoreType
Definition Tokens.h:32
Definition Codecs.h:18
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 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 * llvmTypeFromToken(const ast::tokens::CoreType &type, llvm::LLVMContext &C)
Returns an llvm type representing a type defined by a string.
OPENVDB_AX_API 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:329
internal::half half
Definition Types.h:29
const char * typeNameAsString()
Definition Types.h:516
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:240
LLVMType< T2 > LLVMTypeT
Definition Types.h:241
static llvm::Constant * get(llvm::LLVMContext &C, const T1 *const value)
Definition Types.h:260
static llvm::Constant * get(llvm::LLVMContext &C, const T1 &value)
Definition Types.h:256
static llvm::Type * get(llvm::LLVMContext &C)
Definition Types.h:252
typename std::tuple_element< I, std::tuple< Args... > >::type Type
Definition Types.h:312
static const size_t N_ARGS
Definition Types.h:304
ReturnType(Args...) SignatureType
Definition Types.h:303
Templated function traits which provides compile-time index access to the types of the function signa...
Definition Types.h:280
static llvm::PointerType * get(llvm::LLVMContext &C)
Definition Types.h:161
static llvm::Constant * get(llvm::LLVMContext &C, const T(&array)[S])
Definition Types.h:146
static llvm::Constant * get(llvm::LLVMContext &C, const T(*array)[S])
Definition Types.h:150
static llvm::Type * get(llvm::LLVMContext &C)
Definition Types.h:142
static llvm::StructType * get(llvm::LLVMContext &C)
Definition Types.h:177
static llvm::Constant * get(llvm::LLVMContext &C, const codegen::String *const string)
Definition Types.h:186
static llvm::Constant * get(llvm::LLVMContext &C, const openvdb::math::half V)
Definition Types.h:210
static llvm::Constant * get(llvm::LLVMContext &C, const openvdb::math::half *const V)
Definition Types.h:218
static llvm::Type * get(llvm::LLVMContext &C)
Definition Types.h:209
static llvm::Type * get(llvm::LLVMContext &C)
Definition Types.h:197
LLVM type mapping from pod types.
Definition Types.h:56
static llvm::Constant * get(llvm::LLVMContext &C, const T V)
Return an LLVM constant Value which represents T value.
Definition Types.h:100
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:127
static llvm::Type * get(llvm::LLVMContext &C)
Return an LLVM type which represents T.
Definition Types.h:67
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:40
int32_t type
Definition Types.h:41
int64_t type
Definition Types.h:42
int8_t type
Definition Types.h:39
#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