OpenVDB: openvdb_ax/codegen/Types.h Source File

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
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
30namespace openvdb {
31 OPENVDB_USE_VERSION_NAMESPACE
32namespace OPENVDB_VERSION_NAME {
33
34namespace ax {
35namespace 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.
53template <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 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 {
128 return LLVMType<uintptr_t>::get(C,
129 reinterpret_cast<uintptr_t>(V));
130 }
131};
132
133template <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
156template <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
165template <>
166 struct 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 <>
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
179 LLVMType<char[codegen::String::SSO_LENGTH]>::get(C), // SSO
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
192template <>
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.
237template <typename T1, typename T2>
238 struct AliasTypeMap
239{
240 using LLVMTypeT = LLVMType<T2>;
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.
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///
278template<typename SignatureT>
279 struct FunctionTraits;
280
281template<typename R, typename... Args>
282 struct FunctionTraits<R(&)(Args...)> : public FunctionTraits<R(Args...)> {};
283
284template<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
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>
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///
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///
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///
368 OPENVDB_AX_API ast::tokens::CoreType tokenFromLLVMType(const llvm::Type* type);
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
value
ValueT value
Definition: GridBuilder.h:1290
Mat3.h
Mat4.h
OPENVDB_AX_API
#define OPENVDB_AX_API
Definition: Platform.h:272
String.h
Provides the class definition for the equivalent IR representation and logic for strings in AX.
Tokens.h
Various function and operator tokens used throughout the AST and code generation.
Vec3.h
Exceptions.h
OpenVDB AX Exceptions.
openvdb::v10_0::AXCodeGenError
Definition: Exceptions.h:38
openvdb::v10_0::math::Mat3
3x3 matrix class.
Definition: Mat3.h:29
openvdb::v10_0::math::Mat4
4x4 -matrix class.
Definition: Mat4.h:31
openvdb::v10_0::math::Vec2
Definition: Vec2.h:24
openvdb::v10_0::math::Vec3
Definition: Vec3.h:24
openvdb::v10_0::math::Vec4
Definition: Vec4.h:25
openvdb::v10_0::math::internal::half
Definition: Half.h:99
openvdb::v10_0::ax::ast::tokens::CoreType
CoreType
Definition: Tokens.h:32
openvdb::v10_0::ax::codegen::llvmFloatType
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::v10_0::ax::codegen::llvmIntType
OPENVDB_AX_API llvm::IntegerType * llvmIntType(const uint32_t size, llvm::LLVMContext &C)
Returns an llvm IntegerType given a requested size and context.
openvdb::v10_0::ax::codegen::llvmTypeFromToken
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::v10_0::ax::codegen::tokenFromLLVMType
OPENVDB_AX_API ast::tokens::CoreType tokenFromLLVMType(const llvm::Type *type)
Return a corresponding AX token which represents the given LLVM Type.
openvdb::v10_0::ax::codegen::llvmConstant
llvm::Constant * llvmConstant(const T t, llvm::Type *type)
Returns an llvm Constant holding a scalar value.
Definition: Types.h:328
openvdb
Definition: Exceptions.h:13
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Types.h
openvdb::v10_0::ax::codegen::AliasTypeMap
Alias mapping between two types, a frontend type T1 and a backend type T2. This class is the intended...
Definition: Types.h:239
openvdb::v10_0::ax::codegen::AliasTypeMap::get
static llvm::Constant * get(llvm::LLVMContext &C, const T1 *const value)
Definition: Types.h:259
openvdb::v10_0::ax::codegen::AliasTypeMap::get
static llvm::Constant * get(llvm::LLVMContext &C, const T1 &value)
Definition: Types.h:255
openvdb::v10_0::ax::codegen::AliasTypeMap::get
static llvm::Type * get(llvm::LLVMContext &C)
Definition: Types.h:251
openvdb::v10_0::ax::codegen::FunctionTraits< ReturnT(Args...)>::Arg::Type
typename std::tuple_element< I, std::tuple< Args... > >::type Type
Definition: Types.h:311
openvdb::v10_0::ax::codegen::FunctionTraits< ReturnT(Args...)>::ReturnType
ReturnT ReturnType
Definition: Types.h:301
openvdb::v10_0::ax::codegen::FunctionTraits< ReturnT(Args...)>::SignatureType
ReturnType(Args...) SignatureType
Definition: Types.h:302
openvdb::v10_0::ax::codegen::FunctionTraits
Templated function traits which provides compile-time index access to the types of the function signa...
Definition: Types.h:279
openvdb::v10_0::ax::codegen::LLVMType< T * >::get
static llvm::PointerType * get(llvm::LLVMContext &C)
Definition: Types.h:160
openvdb::v10_0::ax::codegen::LLVMType< T[S]>::get
static llvm::Constant * get(llvm::LLVMContext &C, const T(&array)[S])
Definition: Types.h:145
openvdb::v10_0::ax::codegen::LLVMType< T[S]>::get
static llvm::Constant * get(llvm::LLVMContext &C, const T(*array)[S])
Definition: Types.h:149
openvdb::v10_0::ax::codegen::LLVMType< T[S]>::get
static llvm::Type * get(llvm::LLVMContext &C)
Definition: Types.h:141
openvdb::v10_0::ax::codegen::LLVMType< codegen::String >::get
static llvm::StructType * get(llvm::LLVMContext &C)
Definition: Types.h:176
openvdb::v10_0::ax::codegen::LLVMType< codegen::String >::get
static llvm::Constant * get(llvm::LLVMContext &C, const codegen::String *const string)
Definition: Types.h:185
openvdb::v10_0::ax::codegen::LLVMType< openvdb::math::half >::get
static llvm::Constant * get(llvm::LLVMContext &C, const openvdb::math::half V)
Definition: Types.h:209
openvdb::v10_0::ax::codegen::LLVMType< openvdb::math::half >::get
static llvm::Constant * get(llvm::LLVMContext &C, const openvdb::math::half *const V)
Definition: Types.h:217
openvdb::v10_0::ax::codegen::LLVMType< openvdb::math::half >::get
static llvm::Type * get(llvm::LLVMContext &C)
Definition: Types.h:208
openvdb::v10_0::ax::codegen::LLVMType< void >::get
static llvm::Type * get(llvm::LLVMContext &C)
Definition: Types.h:196
openvdb::v10_0::ax::codegen::LLVMType
LLVM type mapping from pod types.
Definition: Types.h:55
openvdb::v10_0::ax::codegen::LLVMType::get
static llvm::Constant * get(llvm::LLVMContext &C, const T V)
Return an LLVM constant Value which represents T value.
Definition: Types.h:99
openvdb::v10_0::ax::codegen::LLVMType::get
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
openvdb::v10_0::ax::codegen::LLVMType::get
static llvm::Type * get(llvm::LLVMContext &C)
Return an LLVM type which represents T.
Definition: Types.h:66
openvdb::v10_0::ax::codegen::String
An extremely basic but native representation of a string class with SSO support. This exists to provi...
Definition: String.h:34
openvdb::v10_0::ax::codegen::int_t< 16 >::type
int16_t type
Definition: Types.h:39
openvdb::v10_0::ax::codegen::int_t< 32 >::type
int32_t type
Definition: Types.h:40
openvdb::v10_0::ax::codegen::int_t< 64 >::type
int64_t type
Definition: Types.h:41
openvdb::v10_0::ax::codegen::int_t< 8 >::type
int8_t type
Definition: Types.h:38
openvdb::v10_0::ax::codegen::int_t
Definition: Types.h:37
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212