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