OpenVDB 10.0.1
Loading...
Searching...
No Matches
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
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
30namespace openvdb {
32namespace OPENVDB_VERSION_NAME {
33
34namespace ax {
35namespace codegen {
36
37template <size_t Bits> struct int_t;
38template <> struct int_t<8> { using type = int8_t; };
39template <> struct int_t<16> { using type = int16_t; };
40template <> struct int_t<32> { using type = int32_t; };
41template <> 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.
53template <typename T>
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 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
104 if (std::is_floating_point<T>::value) {
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 {
129 reinterpret_cast<uintptr_t>(V));
130 }
131};
132
133template <typename T, size_t S>
134struct 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 {
152 reinterpret_cast<uintptr_t>(array));
153 }
154};
155
156template <typename T>
157struct LLVMType<T*>
158{
159 static inline llvm::PointerType*
160 get(llvm::LLVMContext& C) {
161 return LLVMType<T>::get(C)->getPointerTo(0);
162 }
163};
164
165template <>
166struct LLVMType<char> : public LLVMType<uint8_t>
167{
168 static_assert(std::is_same<uint8_t, unsigned char>::value,
169 "This library requires std::uint8_t to be implemented as unsigned char.");
170};
171
172template <>
173struct 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 {
188 reinterpret_cast<uintptr_t>(string));
189 }
190};
191
192template <>
193struct 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 int8_t* to match clang IR generation
202template <> struct LLVMType<void*> : public LLVMType<int8_t*> {};
203template <> 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
223template <typename T> struct LLVMType<const T> : public LLVMType<T> {};
224template <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.
237template <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.");
245 static_assert(std::is_standard_layout<T1>::value,
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.
266template <typename T> struct LLVMType<openvdb::math::Vec2<T>> : public AliasTypeMap<openvdb::math::Vec2<T>, T[2]> {};
267template <typename T> struct LLVMType<openvdb::math::Vec3<T>> : public AliasTypeMap<openvdb::math::Vec3<T>, T[3]> {};
268template <typename T> struct LLVMType<openvdb::math::Vec4<T>> : public AliasTypeMap<openvdb::math::Vec4<T>, T[4]> {};
269template <typename T> struct LLVMType<openvdb::math::Mat3<T>> : public AliasTypeMap<openvdb::math::Mat3<T>, T[9]> {};
270template <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///
278template<typename SignatureT>
280
281template<typename R, typename... Args>
282struct FunctionTraits<R(&)(Args...)> : public FunctionTraits<R(Args...)> {};
283
284template<typename R, typename... Args>
285struct 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
291template<typename R, typename... Args>
292struct FunctionTraits<R(Args...) noexcept> : public FunctionTraits<R(Args...)> {};
293
294template<typename R, typename... Args>
295struct FunctionTraits<R(*)(Args...) noexcept> : public FunctionTraits<R(Args...)> {};
296#endif
297
298template<typename ReturnT, typename ...Args>
299struct 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///
326template <typename T>
327inline llvm::Constant*
328llvmConstant(const T t, llvm::Type* type)
329{
330 static_assert(std::is_floating_point<T>::value || std::is_integral<T>::value,
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///
346OPENVDB_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///
352OPENVDB_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///
361OPENVDB_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:31
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 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:328
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::Constant * get(llvm::LLVMContext &C, const T1 *const value)
Definition Types.h:259
static llvm::Constant * get(llvm::LLVMContext &C, const T1 &value)
Definition Types.h:255
static llvm::Type * get(llvm::LLVMContext &C)
Definition Types.h:251
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::Constant * get(llvm::LLVMContext &C, const T(&array)[S])
Definition Types.h:145
static llvm::Constant * get(llvm::LLVMContext &C, const T(*array)[S])
Definition Types.h:149
static llvm::Type * get(llvm::LLVMContext &C)
Definition Types.h:141
static llvm::StructType * get(llvm::LLVMContext &C)
Definition Types.h:176
static llvm::Constant * get(llvm::LLVMContext &C, const codegen::String *const string)
Definition Types.h:185
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::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
static llvm::Type * get(llvm::LLVMContext &C)
Return an LLVM type which represents T.
Definition Types.h:66
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