OpenVDB 14.0.0
Loading...
Searching...
No Matches
FunctionTypes.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/FunctionTypes.h
5///
6/// @authors Nick Avramoussis
7///
8/// @brief Contains frameworks for creating custom AX functions which can
9/// be registered within the FunctionRegistry and used during code
10/// generation. The intended and safest way to build a function is to
11/// use the FunctionBuilder struct with its addSignature methods. Note
12/// that the derived Function classes provided can also be subclassed
13/// for more granular control, however may be subject to more substantial
14/// API changes.
15///
16/// @details There are a variety of different ways to build a function
17/// which are tailored towards different function types. The two currently
18/// supported function implementations are C Bindings and IR generation.
19/// Additionally, depending on the return type of the function, you may
20/// need to declare your function an SRET (structural return) function.
21///
22/// C Bindings:
23/// As the name suggests, the CFunction class infrastructure provides
24/// the quickest and easiest way to bind to methods in your host
25/// application. The most important thing to consider when choosing
26/// this approach is performance. LLVM will have no knowledge of the
27/// function body during optimization passes. Depending on the
28/// implementation of your method and the user's usage from AX, C
29/// bindings may be subject to limited optimizations in comparison to
30/// IR functions. For example, a static function which is called from
31/// within a loop cannot be unrolled. See the CFunction templated
32/// class.
33///
34/// IR Functions:
35/// IR Functions expect implementations to generate the body of the
36/// function directly into IR during code generation. This ensures
37/// optimal performance during optimization passes however can be
38/// trickier to design. Note that, in the future, AX functions will
39/// be internally supported to provide a better solution for
40/// IR generated functions. See the IRFunction templated class.
41///
42/// SRET Functions:
43/// Both C Bindings and IR Functions can be marked as SRET methods.
44/// SRET methods, in AX, are any function which returns a value which
45/// is not a scalar (e.g. vectors, matrices). This follows the same
46/// optimization logic as clang which will rebuild function signatures
47/// with their return type as the first argument if the return type is
48/// greater than a given size. You should never attempt to return
49/// alloca's directly from functions (unless malloced).
50///
51/// Some other things to consider:
52/// - Ensure C Binding dependencies have been correctly mapped.
53/// - Avoid calling B.CreateAlloca inside of IR functions - instead
54/// rely on the utility method insertStaticAlloca() where possible.
55/// - Ensure both floating point and integer argument signatures are
56/// provided if you wish to avoid floats truncating.
57/// - Array arguments (vectors/matrices) are always passed by pointer.
58/// Scalar arguments are always passed by copy.
59/// - Ensure array arguments which will not be modified are marked as
60/// readonly. Currently, only array arguments can be passed by
61/// "reference".
62/// - Ensure function bodies, return types and parameters and marked
63/// with desirable llvm attributes.
64///
65
66#ifndef OPENVDB_AX_CODEGEN_FUNCTION_TYPES_HAS_BEEN_INCLUDED
67#define OPENVDB_AX_CODEGEN_FUNCTION_TYPES_HAS_BEEN_INCLUDED
68
69#include "Types.h"
70#include "Value.h"
71#include "Utils.h" // isValidCast
72#include "ConstantFolding.h"
73
74#include <openvdb/version.h>
75#include <openvdb/util/Assert.h>
76
77#include <llvm/ADT/SmallVector.h>
78#include <llvm/IR/Constants.h>
79#include <llvm/IR/IRBuilder.h>
80#include <llvm/IR/Module.h>
81
82#include <algorithm>
83#include <functional>
84#include <memory>
85#include <stack>
86#include <type_traits>
87#include <map>
88#include <vector>
89
90
91namespace openvdb {
93namespace OPENVDB_VERSION_NAME {
94
95namespace ax {
96namespace codegen {
97
98struct Function; // fwd
99
100////////////////////////////////////////////////////////////////////////////////
101////////////////////////////////////////////////////////////////////////////////
102
103/// @brief Typedef a stack allocated array with malloc grow support for
104/// anything which is relatively small and bases its container size on the
105/// number of function arguments.
106/// @note LLVM computes N as 3 (currently) for Value types, but we explicitly
107/// set this as this is a well-motivates choice for average/median amount of
108/// function arguments in builtin AX functions.
109template <typename T>
110using SmallArgumentVector = llvm::SmallVector<T, 3>;
111
112/// @brief Object to array conversion methods to allow functions to return
113/// vector types. These containers provided an interface for automatic
114/// conversion of C++ objects to LLVM types as array types.
115
116template <typename T, size_t _SIZE = 1>
117struct ArgType {
118 using Type = T;
119 static const size_t SIZE = _SIZE;
122};
123
124template <typename T, size_t S>
125struct LLVMType<ArgType<T,S>> : public AliasTypeMap<ArgType<T,S>, T[S]> {};
126
140
141////////////////////////////////////////////////////////////////////////////////
142
143/// @brief Type to symbol conversions - these characters are used to build each
144/// functions unique signature. They differ from standard AX or LLVM
145/// syntax to be as short as possible i.e. vec4d, [4 x double] = d4
146
147template <typename T> struct TypeToSymbol { static inline std::string s() { return "?"; } };
148template <> struct TypeToSymbol<void> { static inline std::string s() { return "v"; } };
149template <> struct TypeToSymbol<char> { static inline std::string s() { return "c"; } };
150template <> struct TypeToSymbol<uint8_t> { static inline std::string s() { return "u8"; } };
151template <> struct TypeToSymbol<uint16_t> { static inline std::string s() { return "us"; } };
152template <> struct TypeToSymbol<uint32_t> { static inline std::string s() { return "ui"; } };
153template <> struct TypeToSymbol<uint64_t> { static inline std::string s() { return "ul"; } };
154template <> struct TypeToSymbol<int8_t> { static inline std::string s() { return "8"; } };
155template <> struct TypeToSymbol<int16_t> { static inline std::string s() { return "s"; } };
156template <> struct TypeToSymbol<int32_t> { static inline std::string s() { return "i"; } };
157template <> struct TypeToSymbol<int64_t> { static inline std::string s() { return "l"; } };
158template <> struct TypeToSymbol<float> { static inline std::string s() { return "f"; } };
159template <> struct TypeToSymbol<double> { static inline std::string s() { return "d"; } };
160template <> struct TypeToSymbol<codegen::String> { static inline std::string s() { return "a"; } };
161
162template <typename T>
163struct TypeToSymbol<T*> {
164 static inline std::string s() { return TypeToSymbol<T>::s() + "*"; }
165};
166
167template <typename T, size_t S>
168struct TypeToSymbol<T[S]> {
169 static inline std::string s() { return TypeToSymbol<T>::s() + std::to_string(S); }
170};
171
172template <typename T, size_t S> struct TypeToSymbol<ArgType<T,S>> : public TypeToSymbol<T[S]> {};
173template <typename T> struct TypeToSymbol<math::Vec2<T>> : public TypeToSymbol<T[2]> {};
174template <typename T> struct TypeToSymbol<math::Vec3<T>> : public TypeToSymbol<T[3]> {};
175template <typename T> struct TypeToSymbol<math::Vec4<T>> : public TypeToSymbol<T[4]> {};
176template <typename T> struct TypeToSymbol<math::Mat3<T>> : public TypeToSymbol<T[9]> {};
177template <typename T> struct TypeToSymbol<math::Mat4<T>> : public TypeToSymbol<T[16]> {};
178template <typename T> struct TypeToSymbol<const T> : public TypeToSymbol<T> {};
179template <typename T> struct TypeToSymbol<const T*> : public TypeToSymbol<T*> {};
180
181////////////////////////////////////////////////////////////////////////////////
182////////////////////////////////////////////////////////////////////////////////
183
184/// @brief Templated argument iterator which implements various small functions
185/// per argument type, resolved at compile time.
186///
187template <typename SignatureT, size_t I = FunctionTraits<SignatureT>::N_ARGS>
189{
191 using ArgumentValueType = typename ArgT::Type;
192
193 /// @brief Whether this signature contains types that are representable
194 /// in AX's Value type.
195 static const bool IsNativeSignature =
198
199 template <typename OpT>
200 static void apply(const OpT& op, const bool forwards) {
201 if (forwards) {
203 op(ArgumentValueType());
204 }
205 else {
206 op(ArgumentValueType());
208 }
209 }
210};
211
212template <typename SignatureT>
213struct ArgumentIterator<SignatureT, 0>
214{
215 static const bool IsNativeSignature = true;
216 template <typename OpT>
217 static void apply(const OpT&, const bool) {}
218};
219
220////////////////////////////////////////////////////////////////////////////////
221////////////////////////////////////////////////////////////////////////////////
222
223/// @brief Metadata associated with a function argument or return value.
225{
226 explicit ArgInfo(const Value& val)
227 : ArgInfo(val.GetUnderlyingType(), val.IsPtr() ? 1 : 0) {}
228 explicit ArgInfo(llvm::Type* utype) : ArgInfo(utype, 0) {}
229 ArgInfo(llvm::Type* utype, uint8_t ptrs, bool ret = false)
230 : mUType(utype), mPtrs(ptrs), mReturn(ret) {
231 OPENVDB_ASSERT(mUType);
232 OPENVDB_ASSERT(!mUType->isPointerTy());
233 // void*'s need to be provided as int8_t's
234 OPENVDB_ASSERT(!(mUType->isVoidTy() && mPtrs > 0));
235 }
236 ArgInfo(ArgInfo&&) = default;
237 ArgInfo(const ArgInfo&) = default;
238 ArgInfo& operator=(ArgInfo&&) = default;
239 ArgInfo& operator=(const ArgInfo&) = default;
240 bool operator==(const ArgInfo& other) const
241 {
242 return
243 mUType == other.mUType &&
244 mPtrs == other.mPtrs &&
245 mReturn == other.mReturn;
246 }
247 bool operator!=(const ArgInfo& other) const { return !this->operator==(other); }
248 bool IsMatchingType(const ArgInfo& other) const
249 {
250 return
251 mUType == other.mUType &&
252 mPtrs == other.mPtrs;
253 }
254 bool IsPtr() const { return mPtrs > 0; }
255 uint8_t NumPtrs() const { return mPtrs; }
256 bool IsNative() const { return Value::Supports(mUType) && mPtrs <= 1; }
257 bool IsVoid() const { return mUType->isVoidTy(); }
258 bool IsReturn() const { return mReturn; }
259 llvm::Type* GetUnderlyingType() const { return mUType; }
260 llvm::Type* GetType() const
261 {
262 llvm::Type* type = mUType;
263 for (uint8_t i = 0; i < mPtrs; ++i) {
264 type = llvm::PointerType::get(type, 0);
265 }
266 return type;
267 }
268 void SetIsReturn() { mReturn = true; }
269private:
270 llvm::Type* mUType; // the underlying argument type
271 uint8_t mPtrs; // num ptrs to the type
272 // true if this is the return argument. For Sret functions, both the
273 // void return and first argument are marked as true.
274 bool mReturn;
275};
276
277/// @brief Container of ArgInfos. This class makes up part of the Function
278/// API for querying signature information.
280{
281public:
283
284 ArgInfoVector() = default;
285 ArgInfoVector(const std::initializer_list<ArgInfo>& info)
286 : mInfoVec(info) {}
288 ArgInfoVector(const ArgInfoVector&) = default;
291
292 bool operator==(const ArgInfoVector& other) const { return mInfoVec == other.mInfoVec; }
293 bool operator!=(const ArgInfoVector& other) const { return !this->operator==(other); }
294
295 auto begin() { return mInfoVec.begin(); }
296 auto end() { return mInfoVec.end(); }
297 auto begin() const { return mInfoVec.begin(); }
298 auto end() const { return mInfoVec.end(); }
299 auto rbegin() { return mInfoVec.rbegin(); }
300 auto rend() { return mInfoVec.rend(); }
301 auto rbegin() const { return mInfoVec.rbegin(); }
302 auto rend() const { return mInfoVec.rend(); }
303 auto& front() { return mInfoVec.front(); }
304 auto& front() const { return mInfoVec.front(); }
305 auto& back() { return mInfoVec.back(); }
306 auto& back() const { return mInfoVec.back(); }
307 auto pop_back() { return mInfoVec.pop_back(); }
308 auto clear() { return mInfoVec.clear(); }
309 auto size() const { return mInfoVec.size(); }
310 auto empty() const { return mInfoVec.empty(); }
311 auto erase(ContainerT::const_iterator iter) { return mInfoVec.erase(iter); }
312
313 void reserve(size_t i) { mInfoVec.reserve(i); }
314 template <typename ...Args>
315 void emplace_back(Args&& ...args) { mInfoVec.emplace_back(std::move(args)...); }
316 ArgInfo& operator[](size_t pos)
317 {
318 OPENVDB_ASSERT(pos < mInfoVec.size());
319 return mInfoVec[pos];
320 }
321 const ArgInfo& operator[](size_t pos) const
322 {
323 OPENVDB_ASSERT(pos < mInfoVec.size());
324 return mInfoVec[pos];
325 }
326
328 {
330 types.reserve(mInfoVec.size());
331 for (auto& info : mInfoVec) {
332 types.emplace_back(info.GetType());
333 }
334 return types;
335 }
336
337private:
338 ContainerT mInfoVec;
339};
340
341/// @brief Wrapper struct to represent "native" function arguments; that is,
342/// the set of Value type that the AX grammar supports. NativeArguments
343/// have two benefits; they support casting and implicit function matching
344/// through FunctionGroups and can be used directly in IR generators (to
345/// leverage the AX Value API). Functions can still be generated and called
346/// with "non-native" arguments, but in these cases FunctionGroup::execute
347/// must result in an explicit signature match
349{
350 NativeArguments() = default;
351 NativeArguments(const std::initializer_list<Value>& args)
352 : mArgs(args) {}
353 explicit NativeArguments(const std::vector<Value>& args)
354 : mArgs(args.begin(), args.end()) {}
359 size_t size() const { return mArgs.size(); }
360 Value& operator[](size_t pos)
361 {
362 OPENVDB_ASSERT(pos < mArgs.size());
363 return mArgs[pos];
364 }
365 const Value& operator[](size_t pos) const
366 {
367 OPENVDB_ASSERT(pos < mArgs.size());
368 return mArgs[pos];
369 }
370 void AddArg(const Value& val) { mArgs.emplace_back(val); }
371 /// @brief Cast these arguments to match the given function's signature
372 OPENVDB_AX_API NativeArguments Cast(const Function& F, llvm::IRBuilder<>& B) const;
373private:
375};
376
377/// @brief Arbitrary, potentially "non-native" arguments. This wrapper struct
378/// can be used when generating function which cannot be called from AX
379/// itself (e.g. VDB accessor functions or Volume/Point kernels etc). They
380/// do not support implicit function signature matching or casting.
382{
383 Arguments() = default;
384
385 /// @brief Create a set of arguments from native arguments. The function
386 /// framework typically works on generic arguments types.
387 explicit Arguments(const NativeArguments& args) {
388 mArgs.reserve(args.size());
389 mTypes.reserve(args.size());
390 for (size_t i = 0; i < args.size(); ++i) {
391 this->AddArg(args[i]);
392 }
393 }
394
395 Arguments(Arguments&&) = default;
396 Arguments(const Arguments&) = default;
398 Arguments& operator=(const Arguments&) = default;
399
400 size_t size() const { return mArgs.size(); }
401
402 bool AreNativeValues() const
403 {
404 for (const auto& types : mTypes) {
405 if (!types.IsNative()) return false;
406 }
407 return true;
408 }
409
410 Value AsNativeValue(const size_t i) const
411 {
412 OPENVDB_ASSERT(mTypes[i].IsNative());
413 return Value(mArgs[i], mTypes[i].GetUnderlyingType());
414 }
415
417 {
419 NativeArguments args;
420 for (size_t i = 0; i < mArgs.size(); ++i) {
421 args.AddArg(this->AsNativeValue(i));
422 }
423 return args;
424 }
425
426 const llvm::ArrayRef<llvm::Value*> AsLLVMValues() const { return mArgs; }
427 const ArgInfo& GetArgInfo(size_t pos) const { return mTypes[pos]; }
428 const ArgInfoVector& GetArgInfo() const { return mTypes; }
429
430 llvm::Value* operator[](size_t pos) const
431 {
432 OPENVDB_ASSERT(pos < mTypes.size());
433 return mArgs[pos];
434 }
435
436 void AddArg(llvm::Value* val, const ArgInfo& type)
437 {
438 mArgs.emplace_back(val);
439 mTypes.emplace_back(type);
440 }
441
442 void AddArg(const Value& val)
443 {
444 mArgs.emplace_back(val.GetValue());
445 mTypes.emplace_back(val);
446 }
447
448 void PrependArg(const Value& val)
449 {
450 this->AddArg(val);
451 std::rotate(mArgs.rbegin(), mArgs.rbegin() + 1, mArgs.rend());
452 std::rotate(mTypes.rbegin(), mTypes.rbegin() + 1, mTypes.rend());
453 }
454
455private:
457 ArgInfoVector mTypes;
458};
459
460///////////////////////////////////////////////////////////////////////////////
461///////////////////////////////////////////////////////////////////////////////
462
463/// @brief Populate a vector of llvm types from a function signature
464/// declaration.
465/// @warning From LLVM 16 onwards, pointer argument type cannot be
466/// introspected
467///
468/// @param C The llvm context
469/// @param types A vector of types to populate
470///
471template <typename SignatureT>
472inline llvm::Type*
473llvmTypesFromSignature(llvm::LLVMContext& C,
474 std::vector<llvm::Type*>* types = nullptr)
475{
476 using Traits = FunctionTraits<SignatureT>;
477 using ArgumentIteratorT =
479
480 if (types) {
481 types->reserve(Traits::N_ARGS);
482 auto callback = [&types, &C](auto type) {
483 using Type = decltype(type);
484 types->emplace_back(LLVMType<Type>::get(C));
485 };
486 ArgumentIteratorT::apply(callback, /*forwards*/true);
487 }
488 using Type = typename Traits::ReturnType;
489 return LLVMType<Type>::get(C);
490}
491
492/// @brief Populate a vector of ArgInfos from a function signature
493/// declaration.
494///
495/// @param C The llvm context
496/// @param types A ArgInfoVector to populate
497///
498template <typename SignatureT>
499inline ArgInfo
500llvmArgTypesFromSignature(llvm::LLVMContext& C,
501 ArgInfoVector* types = nullptr)
502{
503 using Traits = FunctionTraits<SignatureT>;
504 using ArgumentIteratorT =
506
507 if (types)
508 {
509 types->reserve(Traits::N_ARGS);
510 auto callback = [&types, &C](auto type)
511 {
512 using UnderlyingType = std::remove_cv_t<typename RemoveAllPtrTypes<decltype(type)>::Type>;
513 static constexpr auto NPtrs = CountNPtrs<decltype(type)>::value;
514 static constexpr bool IsVoid = std::is_same_v<UnderlyingType, void>;
515 // args can't be void without pts
516 static_assert(!IsVoid || NPtrs > 0);
517 // void* arguments alias to int8_t
518 using Type = std::conditional_t<IsVoid, int8_t, UnderlyingType>;
519 types->emplace_back(LLVMType<Type>::get(C), NPtrs);
520 };
521 ArgumentIteratorT::apply(callback, /*forwards*/true);
522 }
523
524 using UnderlyingType = std::remove_cv_t<typename RemoveAllPtrTypes<typename Traits::ReturnType>::Type>;
525 static constexpr auto NPtrs = CountNPtrs<typename Traits::ReturnType>::value;
526
527 if constexpr (std::is_same_v<UnderlyingType, void> && NPtrs > 0)
528 {
529 // if underlying type is void, alias to int8_t if its a void*
530 ArgInfo ret{LLVMType<int8_t>::get(C), NPtrs};
531 ret.SetIsReturn();
532 return ret;
533 }
534 else {
536 ret.SetIsReturn();
537 return ret;
538 }
539}
540
541
542/// @brief Generate an LLVM FunctionType from a function signature
543///
544/// @param C The llvm context
545///
546template <typename SignatureT>
547inline llvm::FunctionType*
548llvmFunctionTypeFromSignature(llvm::LLVMContext& C)
549{
550 ArgInfoVector types;
551 ArgInfo returnType =
553 return llvm::FunctionType::get(returnType.GetType(),
554 types.AsLLVMTypes(), /*isVarArg=*/false);
555}
556
557/// @brief Print a function signature to the provided ostream.
558///
559/// @param os The stream to print to
560/// @param types The function argument types
561/// @param returnType The return type of the function. Must not be a nullptr
562/// @param name The name of the function. If not provided, the return type
563/// neighbours the first parenthesis
564/// @param names Names of the function parameters. If a name is nullptr, it
565/// skipped
566/// @param axTypes Whether to try and convert the llvm::Types provided to
567/// AX types. If false, the llvm types are used.
569printSignature(std::ostream& os,
570 const ArgInfoVector& types,
571 const ArgInfo& returnType,
572 const char* name = nullptr,
573 const llvm::ArrayRef<const char*>& names = {},
574 const bool axTypes = false);
575
576///////////////////////////////////////////////////////////////////////////////
577////////////////////////////////////////////////////////////////////////////////
578
579/// Forward declare builder for private access to Function types
580struct FunctionBuilder;
581
582/// @brief The base/abstract representation of an AX function. Derived classes
583/// must implement the Function::types call to describe their signature.
585{
586 using Ptr = std::shared_ptr<Function>;
587
588 Function(const size_t size, const std::string& symbol)
589 : mSize(size)
590 , mSymbol(symbol)
591 , mAttributes(nullptr)
592 , mNames()
593 , mDeps() {
594 // symbol must be a valid string
595 OPENVDB_ASSERT(!symbol.empty());
596 }
597
598 virtual ~Function() = default;
599
600 /// @brief Populate a vector of ArgInfos which describe this function
601 /// signature. This method is used by Function::create,
602 /// Function::print and Function::match.
603 virtual ArgInfo types(ArgInfoVector&, llvm::LLVMContext&) const = 0;
604
605 /// @brief Converts and creates this AX function into a llvm Function.
606 /// @details This method uses the result from Function::types() to construct
607 /// a llvm::FunctionType and a subsequent a llvm::Function. Any
608 /// parameter, return or function attributes are also added to the
609 /// function. If a module is provided, the module if first checked
610 /// to see if the function already exists. If it does, it is
611 /// immediately returned. If the function doesn't exist in the
612 /// module, its prototype is created and also inserted into the end
613 /// of the modules function list. If no module is provided, the
614 /// function is left detached and must be added to a valid Module
615 /// to be callable.
616 /// @warning If a module is not provided, the caller takes ownership of the
617 /// returned function and is responsible for deallocating it.
618 /// @note The body of the function is left to derived classes to
619 /// implement. As you need a Module to generate the prototype/body,
620 /// this function serves two purposes. The first is to return the
621 /// detached function signature if only a context is provided.
622 /// The second is to ensure the function prototype and body (if
623 /// required) is inserted into the module prior to returning.
624 /// @note It is possible to end up with function symbol collisions if you
625 /// do not have unique function symbols in your module
626 ///
627 /// @param C The LLVM Context
628 /// @param M The Module to write the function to
629 virtual llvm::Function*
630 create(llvm::LLVMContext& C, llvm::Module* M = nullptr) const;
631
632 /// @brief Convenience method which always uses the provided module to find
633 /// the function or insert it if necessary.
634 /// @param M The llvm::Module to use
635 llvm::Function* create(llvm::Module& M) const {
636 return this->create(M.getContext(), &M);
637 }
638
639 /// @brief Convenience method for calling M.getFunction(symbol). Returns a
640 /// nullptr if the function has not yet been created or if it is
641 /// embedded IR.
642 /// @param M The llvm::Module to use
643 llvm::Function* get(const llvm::Module& M) const;
644
645 /// @brief Uses the IRBuilder to create a call to this function with the
646 /// given arguments, creating the function and inserting it into the
647 /// IRBuilder's Module if necessary (through Function::create).
648 /// Returns the result of the function call which can be a nullptr
649 /// if the function is a non-sret void call.
650 /// @note The IRBuilder must have a valid llvm Module/Function/Block
651 /// attached
652 /// @note If the number of provided arguments do not match the size of the
653 /// current function, invalid IR will be generated.
654 /// @note If the provided argument types do not match the current function
655 /// and cast is false, invalid IR will be generated. Additionally,
656 /// invalid IR will be generated if cast is true but no valid cast
657 /// exists for a given argument.
658 /// @note When casting arguments, the readonly flags of the function are
659 /// not checked (unlike Function::match). Casting an argument will
660 /// cause a new copy of the argument to be created and passed to the
661 /// function. These new values do not propagate back any changes to
662 /// the original argument. Separate functions for all writable
663 /// argument types must be created.
664 ///
665 /// @param args The llvm Value arguments to call this function with
666 /// @param B The llvm IRBuilder
667 /// From LLVM 16 onwards, this version of call does not support argument
668 /// casting. This must be performed using the NativeArguments struct
669 virtual llvm::Value*
670 call(const std::vector<llvm::Value*>& args,
671 llvm::IRBuilder<>& B) const;
672
673 virtual Value call(const Arguments& args, llvm::IRBuilder<>& B) const;
674
675 Value call(const NativeArguments& args, llvm::IRBuilder<>& B) const
676 {
677 return this->call(Arguments(args.Cast(*this, B)), B);
678 }
679
680 /// @brief The result type from calls to Function::match
681 /// @note Function::match cannot return Ambiguous - this is only returned
682 /// by the FunctionGroup API.
684 {
685 None = 0, // Mismatching argument sizes
686 Size, // Correct number of arguments but incompatible types
687 Implicit, // Correct number of arguments and castable types
688 Ambiguous, // Correct number of arguments and castable types but multiple available signatures
689 Explicit // Correct number of arguments and types match exactly
690 };
691
692 /// @brief The base implementation for determining how a vector of llvm
693 /// arguments translates to this functions signature. Returns an
694 /// enum which represents the available mapping.
695 /// @details This method calls types() to figure out the function signature,
696 /// then compares each argument type to the type in the input
697 /// vector. If the types match exactly, an Explicit match is found.
698 /// If the sizes of the inputs and signature differ, no match is
699 /// found and None is returned. If however, the sizes match and
700 /// there exists a valid implicit cast from the input type to the
701 /// signature type for every input, an Implicit match is returned.
702 /// Finally, if the sizes match but there is no implicit cast
703 /// mapping, Size is returned.
704 /// i8 -> i32 : Implicit
705 /// i32 -> i32 : Explicit
706 /// str -> i32 : Size
707 /// (i32,i32) -> i32 : None
708 /// Never returns Ambiguous (this state is used by FunctionGroup)
709 /// @note Due to the way CFunctionSRet is implemented, the LLVM Context
710 /// must be provided in case we have a zero arg function signature
711 /// with a SRET.
712 /// @param inputs The input types
713 /// @param C The LLVM Context
714 virtual SignatureMatch match(const ArgInfoVector& inputs, llvm::LLVMContext& C) const;
715
716 /// @brief The number of arguments that this function has
717 inline size_t size() const { return mSize; }
718
719 /// @brief The function symbol name.
720 /// @details This will be used as its identifier in IR and must be unique.
721 inline const char* symbol() const { return mSymbol.c_str(); }
722
723 /// @brief Returns the descriptive name of the given argument index
724 /// @details If the index is greater than the number of arguments, an empty
725 /// string is returned.
726 ///
727 /// @param idx The index of the argument
728 inline const char* argName(const size_t idx) const
729 {
730 return idx < mNames.size() ? mNames[idx] : "";
731 }
732
733 /// @brief Print this function's signature to the provided ostream.
734 /// @details This is intended to return a descriptive front end user string
735 /// rather than the function's IR representation. This function is
736 /// virtual so that derived classes can customize how they present
737 /// frontend information.
738 /// @sa printSignature
739 ///
740 /// @param C The llvm context
741 /// @param os The ostream to print to
742 /// @param name The name to insert into the description.
743 /// @param axTypes Whether to print llvm IR or AX Types.
744 virtual void print(llvm::LLVMContext& C,
745 std::ostream& os,
746 const char* name = nullptr,
747 const bool axTypes = true) const;
748
749 const SmallArgumentVector<const char*>& dependencies() const { return mDeps; }
750
751private:
752 friend FunctionBuilder;
753
754 enum class Type {
755 kNormal,
756 kBuiltin,
757 kKernel
758 };
759
760 struct Attributes
761 {
762 SmallArgumentVector<llvm::Attribute::AttrKind> mFnAttrs, mRetAttrs;
763 std::map<size_t, SmallArgumentVector<llvm::Attribute::AttrKind>> mParamAttrs;
764 bool mReadOnly {false};
765 Type mType {Type::kNormal};
766 };
767
768 inline Attributes& attrs()
769 {
770 if (!mAttributes) mAttributes.reset(new Attributes());
771 return *mAttributes;
772 }
773
774 /// @brief Temporary method until we move to ArgInfo introspection
775 bool IsParamReadOnly(const size_t idx) const
776 {
777 if (!mAttributes) return false; // can't be certain if no attrs set
778 if (mAttributes->mReadOnly) return true;
779 // @todo REMOVE - switch to using writable info on the ArgInfo types
780 const auto iter = mAttributes->mParamAttrs.find(idx);
781 if (iter == mAttributes->mParamAttrs.end()) return false;
782 const auto& vec = iter->second;
783 return std::find(vec.begin(), vec.end(),
784 llvm::Attribute::AttrKind::ReadOnly) != vec.end();
785 }
786
787 llvm::AttributeList flattenAttrs(llvm::Function* F) const;
788
789private:
790 const size_t mSize;
791 const std::string mSymbol;
792 std::unique_ptr<Attributes> mAttributes;
793 SmallArgumentVector<const char*> mNames;
794 SmallArgumentVector<const char*> mDeps;
795};
796
797/// @brief Templated interface class for SRET functions. This struct provides
798/// the interface for functions that wish to return arrays (vectors or
799/// matrices) by internally remapping the first argument for the user.
800/// As far as LLVM and any bindings are concerned, the function
801/// signature remains unchanged - however the first argument becomes
802/// "invisible" to the user and is instead allocated by LLVM before the
803/// function is executed. Importantly, the argument has no impact on
804/// the user facing AX signature and doesn't affect declaration selection.
805/// @note This class is not intended to be instantiated directly, but instead
806/// used by derived implementation which hold a valid implementations
807/// of member functions required to create a llvm::Function (such as
808/// Function::types and Function::call). This exists as an interface to
809/// avoid virtual inheritance.
810///
811template <typename SignatureT, typename DerivedFunction>
812struct SRetFunction : public DerivedFunction
813{
814 using Ptr = std::shared_ptr<SRetFunction<SignatureT, DerivedFunction>>;
816
817 // check there actually are arguments
818 static_assert(Traits::N_ARGS > 0,
819 "SRET Function object has been setup with the first argument as the return "
820 "value, however the provided signature is empty.");
821
822 // check no return value exists
823 static_assert(std::is_same<typename Traits::ReturnType, void>::value,
824 "SRET Function object has been setup with the first argument as the return "
825 "value and a non void return type.");
826
827private:
828
829 using FirstArgument = typename Traits::template Arg<0>::Type;
830 static_assert(std::is_pointer<FirstArgument>::value,
831 "SRET Function object has been setup with the first argument as the return "
832 "value, but this argument it is not a pointer type.");
833 static_assert(!std::is_const_v<FirstArgument>,
834 "SRET Function object has been setup with the first argument as the return "
835 "value, but this argument is const.");
836 using SRetType = typename std::remove_pointer<FirstArgument>::type;
837
838public:
839
840 /// @brief Overide the ArgInfo type method. This does NOT change the arg
841 /// order, it simply marks the first argument as a return argument. Note
842 /// that the void ret type is also left as a return type.
843 ArgInfo types(ArgInfoVector& args, llvm::LLVMContext& C) const override
844 {
845 ArgInfo ret = DerivedFunction::types(args, C);
846 OPENVDB_ASSERT(!args.empty());
847 OPENVDB_ASSERT(ret.IsVoid());
848 OPENVDB_ASSERT(!args[0].IsVoid());
849 OPENVDB_ASSERT(args[0].IsPtr());
850 args[0].SetIsReturn();
851 return ret;
852 }
853
854 /// @brief Override of match which inserts the SRET type such that the base
855 /// class methods ignore it.
857 const ArgInfoVector& args,
858 llvm::LLVMContext& C) const override
859 {
860 ArgInfoVector inputs(args);
861 // Create a dummy sret ptr type for derived match impls
862 llvm::Type* stype = LLVMType<SRetType>::get(C);
863 // llvm::Constant* zero = llvmConstant(0, llvm::Type::getInt64Ty(C));
864 // llvm::Constant* dummy = llvm::ConstantExpr::getPointerCast(zero, stype->getPointerTo());
865 inputs.emplace_back(stype, 1);
866 inputs.back().SetIsReturn();
867 std::rotate(inputs.rbegin(), inputs.rbegin() + 1, inputs.rend());
868 return DerivedFunction::match(inputs, C);
869 }
870
871 /// @brief Override of call which allocates the required SRET llvm::Value
872 /// for this function.
873 /// @note Unlike other function where the returned llvm::Value* is a
874 /// llvm::CallInst (which also represents the return value),
875 /// SRET functions return the allocated 1st argument i.e. not a
876 /// llvm::CallInst
877 llvm::Value*
878 call(const std::vector<llvm::Value*>& args,
879 llvm::IRBuilder<>& B) const override
880 {
881 // append return value and right rotate
882 std::vector<llvm::Value*> inputs(args);
883 llvm::Type* sret = LLVMType<SRetType>::get(B.getContext());
884 inputs.emplace_back(insertStaticAlloca(B, sret));
885 std::rotate(inputs.rbegin(), inputs.rbegin() + 1, inputs.rend());
886 DerivedFunction::call(inputs, B);
887 return inputs.front();
888 }
889
890 Value call(const Arguments& args, llvm::IRBuilder<>& B) const override
891 {
892 // append return value and right rotate
893 Arguments inputs(args);
894 Value sret = Value::Alloc(B, LLVMType<SRetType>::get(B.getContext()));
895 inputs.PrependArg(sret);
896 DerivedFunction::call(inputs, B);
897 return sret;
898 }
899
900 /// @brief Override of print to avoid printing out the SRET type
901 void print(llvm::LLVMContext& C,
902 std::ostream& os,
903 const char* name = nullptr,
904 const bool axTypes = true) const override
905 {
906 ArgInfoVector current;
907 ArgInfo ret = this->types(current, C);
908 // left rotate
909 std::rotate(current.begin(), current.begin() + 1, current.end());
910 ret = current.back();
911 current.pop_back();
912
914 names.reserve(this->size());
915 for (size_t i = 0; i < this->size()-1; ++i) {
916 names.emplace_back(this->argName(i));
917 }
918 printSignature(os, current, ret, name, names, axTypes);
919 }
920
921protected:
922 /// @brief Forward all arguments to the derived class
923 template <typename ...Args>
924 SRetFunction(Args&&... ts) : DerivedFunction(ts...) {}
925};
926
927/// @brief The base class for all C bindings.
928struct CFunctionBase : public Function
929{
930 using Ptr = std::shared_ptr<CFunctionBase>;
931
932 ~CFunctionBase() override = default;
933
934 /// @brief Returns the global address of this function.
935 /// @note This is only required for C bindings.
936 virtual uint64_t address() const = 0;
937
938 inline void setConstantFold(bool on) { mConstantFold = on; }
939 inline bool hasConstantFold() const { return mConstantFold; }
940
941 inline virtual llvm::Value* fold(
942 const llvm::ArrayRef<llvm::Value*>&,
943 llvm::LLVMContext&) const
944 {
945 return nullptr;
946 }
947
948protected:
949 CFunctionBase(const size_t size,
950 const std::string& symbol)
952 , mConstantFold(false) {}
953
954private:
955 bool mConstantFold;
956};
957
958/// @brief Represents a concrete C function binding.
959///
960/// @note This struct is templated on the signature to allow for evaluation of
961/// the arguments to llvm types from any llvm context.
962///
963template <typename SignatureT>
965{
967 using Ptr = std::shared_ptr<CFunctionT>;
969
970 // Assert that the return argument is not a pointer (relaxed for void* for mallocs).
971 // Note that this is relaxed for IR functions where it's allowed if the function is
972 // forcefully inlined.
973 static_assert(std::is_same<typename Traits::ReturnType, void*>::value ||
974 !std::is_pointer<typename Traits::ReturnType>::value,
975 "CFunction object has been setup with a pointer return argument. C bindings "
976 "cannot return memory locations to LLVM - Consider using a CFunctionSRet.");
977
978 CFunction(const std::string& symbol, SignatureT* function)
979 : CFunctionBase(Traits::N_ARGS, symbol)
980 , mFunction(function) {}
981
982 ~CFunction() override = default;
983
984 inline ArgInfo types(ArgInfoVector& types, llvm::LLVMContext& C) const override
985 {
987 }
988
989 inline uint64_t address() const override final
990 {
991 return reinterpret_cast<uint64_t>(mFunction);
992 }
993
994 llvm::Value*
995 call(const std::vector<llvm::Value*>& args,
996 llvm::IRBuilder<>& B) const override
997 {
998 llvm::Value* result = this->fold(args, B.getContext());
999 if (result) return result;
1000 return Function::call(args, B);
1001 }
1002
1003 Value call(const Arguments& args, llvm::IRBuilder<>& B) const override
1004 {
1005 llvm::Constant* result = this->fold(args.AsLLVMValues(), B.getContext());
1006 if (result) return Value(result);
1007 return Function::call(args, B);
1008 }
1009
1010 llvm::Constant* fold(const llvm::ArrayRef<llvm::Value*>& args, llvm::LLVMContext& C) const override final
1011 {
1012 if (!this->hasConstantFold()) return nullptr;
1014 for (auto& value : args) {
1015 if (!llvm::isa<llvm::Constant>(value)) return nullptr;
1016 constants.emplace_back(llvm::cast<llvm::Constant>(value));
1017 }
1018 // no guarantee that fold() will be able to cast all arguments
1019 return ConstantFolder<SignatureT>::fold(constants, *mFunction, C);
1020 }
1021
1022private:
1023 SignatureT* mFunction;
1024};
1025
1026/// @brief The base/abstract definition for an IR function.
1028{
1029 using Ptr = std::shared_ptr<IRFunctionBase>;
1030
1031 /// @brief The IR callback function which will write the LLVM IR for this
1032 /// function's body.
1033 /// @details The first argument is the vector of functional arguments. i.e.
1034 /// a representation of the value that the callback has been invoked
1035 /// with.
1036 /// The last argument is the IR builder which should be used to
1037 /// generate the function body IR.
1038 /// @note You can return a ret void instruction, an actual value or
1039 /// Value::Invalid() which will cause the function framework to
1040 /// insert a ret void if necessary.
1041 using GeneratorNativeCb = std::function<Value
1042 (const NativeArguments&, llvm::IRBuilder<>&)>;
1043
1044 using GeneratorArgumentsCb = std::function<Value
1045 (const Arguments&, llvm::IRBuilder<>&)>;
1046
1047 /// @brief Legacy callback, will eventually be deprecated in favour of
1048 /// using the GeneratorArgumentsCb
1049 using GeneratorCb = std::function<llvm::Value*
1050 (const std::vector<llvm::Value*>&,
1051 llvm::IRBuilder<>&)>;
1052
1053 /// @brief Enable or disable the embedding of IR. Embedded IR is currently
1054 /// required for function which use parent function parameters.
1055 inline void setEmbedIR(bool on) { mEmbedIR = on; }
1056 inline bool hasEmbedIR() const { return mEmbedIR; }
1057
1058 /// @brief Override for the creation of an IR function. This ensures that
1059 /// the body and prototype of the function are generated if a Module
1060 /// is provided.
1061 /// @note A nullptr is returned if mEmbedIR is true and no action is
1062 /// performed.
1063 /// @note Throws if this function has been initialized with a nullptr
1064 /// generator callback. In this case, the function prototype will
1065 /// be created, but not the function body.
1066 /// @note Throws if the return type of the generator callback does not
1067 /// match the function prototype. In this case, both the prototype
1068 /// and the function body will be created and inserted, but the IR
1069 /// will be invalid.
1070 llvm::Function*
1071 create(llvm::LLVMContext& C, llvm::Module* M) const override;
1072
1073 /// @brief Override for call, which is only necessary if mEmbedIR is true,
1074 /// as the IR generation for embedded functions is delayed until
1075 /// the function is called. If mEmbedIR is false, this simply calls
1076 /// Function::call
1077 llvm::Value*
1078 call(const std::vector<llvm::Value*>& args,
1079 llvm::IRBuilder<>& B) const override;
1080
1081 Value call(const Arguments& args, llvm::IRBuilder<>&) const override;
1082
1083protected:
1084
1085 // @todo This should ideally live in FunctionGroup::execute, but the return
1086 // type is allowed to differ for sret C bindings.
1087 inline void
1088 verifyResultType(const llvm::Type* result, const llvm::Type* expected) const
1089 {
1090 if (result == expected) return;
1091 std::string source, target;
1092 if (result) llvmTypeToString(result, source);
1093 llvmTypeToString(expected, target);
1094 OPENVDB_THROW(AXCodeGenError, "Function \"" + std::string(this->symbol()) +
1095 "\" has been invoked with a mismatching return type. Expected: \"" +
1096 target + "\", got \"" + source + "\".");
1097 }
1098 IRFunctionBase(const std::string& symbol,
1099 const GeneratorCb& gen,
1100 const size_t size)
1101 : Function(size, symbol)
1102 , mGen([this, gen](const Arguments& args, llvm::IRBuilder<>& B) {
1103 llvm::Value* result = gen(args.AsLLVMValues(), B);
1104 if (!result) return Value::Invalid();
1105 // For older callbacks, we have to figure out the type from the
1106 // function signature if the return type is a ptr (from LLVM 16
1107 // onwards)
1108 if (result->getType()->isPointerTy())
1109 {
1110 ArgInfoVector unused;
1111 ArgInfo r = this->types(unused, result->getContext());
1112 return Value(result, r.GetUnderlyingType());
1113 }
1114 else {
1115 // otherwise, can we introspec the type directly
1116 return Value(result, result->getType());
1117 }
1118 })
1119 , mEmbedIR(false) {}
1120 IRFunctionBase(const std::string& symbol,
1121 const GeneratorNativeCb& gen,
1122 const size_t size)
1123 : Function(size, symbol)
1124 , mGen([gen](const Arguments& args, llvm::IRBuilder<>& B) {
1125 OPENVDB_ASSERT(args.AreNativeValues());
1126 return gen(args.AsNativeValues(), B);
1127 })
1128 , mEmbedIR(false) {}
1129 IRFunctionBase(const std::string& symbol,
1130 const GeneratorArgumentsCb& gen,
1131 const size_t size)
1132 : Function(size, symbol)
1133 , mGen(gen)
1134 , mEmbedIR(false) {}
1135 ~IRFunctionBase() override = default;
1136
1139};
1140
1141/// @brief Represents a concrete IR function.
1142template <typename SignatureT>
1144{
1146 using Ptr = std::shared_ptr<IRFunction>;
1147
1148 IRFunction(const std::string& symbol, const GeneratorCb& gen)
1149 : IRFunctionBase(symbol, gen, Traits::N_ARGS) {}
1150 IRFunction(const std::string& symbol, const GeneratorNativeCb& gen)
1151 : IRFunctionBase(symbol, gen, Traits::N_ARGS) {}
1152 IRFunction(const std::string& symbol, const GeneratorArgumentsCb& gen)
1153 : IRFunctionBase(symbol, gen, Traits::N_ARGS) {}
1154
1155 inline ArgInfo types(ArgInfoVector& types, llvm::LLVMContext& C) const override
1156 {
1158 }
1159};
1160
1161/// @brief Represents a concrete C function binding with the first argument as
1162/// its return type.
1163template <typename SignatureT>
1164struct CFunctionSRet : public SRetFunction<SignatureT, CFunction<SignatureT>>
1165{
1167 CFunctionSRet(const std::string& symbol, const SignatureT function)
1168 : BaseT(symbol, function) {}
1169 ~CFunctionSRet() override = default;
1170};
1171
1172/// @brief Represents a concrete IR function with the first argument as
1173/// its return type.
1174template <typename SignatureT>
1175struct IRFunctionSRet : public SRetFunction<SignatureT, IRFunction<SignatureT>>
1176{
1178 IRFunctionSRet(const std::string& symbol,
1179 const IRFunctionBase::GeneratorCb& gen)
1180 : BaseT(symbol, gen) {}
1181 IRFunctionSRet(const std::string& symbol,
1183 : BaseT(symbol, gen) {}
1184 IRFunctionSRet(const std::string& symbol,
1186 : BaseT(symbol, gen) {}
1187
1188 ~IRFunctionSRet() override = default;
1189};
1190
1191/// @brief A group of functions which all have the same name but different
1192/// signatures. For example:
1193/// float abs(float)
1194/// double abs(double)
1195/// As well as serving as a way of grouping common functions, this class
1196/// provides an API for selecting the best possible function signature,
1197/// should a match exist, against a provided set of argument types.
1199{
1200 using Ptr = std::shared_ptr<FunctionGroup>;
1201 using UniquePtr = std::unique_ptr<FunctionGroup>;
1202 using FunctionList = std::vector<Function::Ptr>;
1203
1204 FunctionGroup(const char* name,
1205 const char* doc,
1206 const FunctionList& list)
1207 : mName(name)
1208 , mDoc(doc)
1209 , mFunctionList(list) {
1210 // Can't verify signatures yet without an LLVM context, asserted on demand
1212 }
1213 ~FunctionGroup() = default;
1214
1215 /// @brief Verify the function symbol names in this group (must be unique).
1217
1218 /// @brief Verify the function signatures in this group (must be unique).
1219 bool HasUniqueTypeSignatures(llvm::LLVMContext& C) const;
1220
1221 /// @brief Given a vector of args, automatically returns the best
1222 /// possible function declaration from the stored function list. The
1223 /// 'best' declaration is determined by the provided types
1224 /// compatibility to each functions signature.
1225 /// @note Returns a nullptr if no compatible match was found or if the
1226 /// function list is empty. A compatible match is defined as an
1227 /// Explicit, Implicit or Ambiguous match (where the latter returns
1228 /// the first matched implicit function where other implicit
1229 /// matches exist).
1230 ///
1231 /// @note If multiple implicit matches are found, the first match is
1232 /// returned and 'type' is set to Ambiguous (if provided).
1233 /// @warning All funcions in this group must implement the types(ArgInfo)
1234 /// virtual function, which is optional in LLVM 15 but required from
1235 /// LLVM 16.
1236 ///
1237 /// @param args Args representing the function argument types
1238 /// @param C The llvm context
1239 std::pair<const Function*, Function::SignatureMatch>
1240 match(const ArgInfoVector& args, llvm::LLVMContext& C) const;
1241
1242 /// @brief Given a set of Arguments, find an EXPLICIT signature match,
1243 /// generate and execute the function body. If no explicit match
1244 /// exists, Value::Invalid() is returned.
1245 /// @note To ensure something is matched/executed, consider calling
1246 /// match() and Function::call instead. This method should only be
1247 /// used by internal methods that can assert an explicit match
1248 /// exists.
1249 ///
1250 /// @param args Function arguments
1251 /// @param B The current llvm IRBuilder
1252 Value execute(const Arguments& args, llvm::IRBuilder<>& B) const;
1253
1254 /// @brief Given a set of NativeArguments, find the best possible function
1255 /// signature, generate and execute the function body. Returns the
1256 /// return value of the function or Value::Invalid() if no Explicit
1257 /// or Implicit match is found.
1258 /// @note This function will throw if no valid return is provided by the
1259 /// matched declaration implementation.
1260 ///
1261 /// @param args Natively supported function arguments
1262 /// @param B The current llvm IRBuilder
1263 Value execute(const NativeArguments& args, llvm::IRBuilder<>& B) const;
1264
1265 /// @brief Accessor to the underlying function signature list
1266 inline const FunctionList& list() const { return mFunctionList; }
1267 const char* name() const { return mName; }
1268 const char* doc() const { return mDoc; }
1269
1270private:
1271 const char* mName;
1272 const char* mDoc;
1273 const FunctionList mFunctionList;
1274};
1275
1276/// @brief The FunctionBuilder class provides a builder pattern framework to
1277/// allow easy and valid construction of AX functions. There are a
1278/// number of complex tasks which may need to be performed during
1279/// construction of C or IR function which are delegated to this
1280/// builder, whilst ensuring that the constructed functions are
1281/// guaranteed to be valid.
1282/// @details Use the FunctionBuilder::addSignature methods to append function
1283/// signatures. Finalize the group of functions with
1284/// FunctionBuilder::get.
1286{
1289 };
1290
1292 {
1293 using Ptr = std::shared_ptr<Settings>;
1294
1295 inline bool isDefault() const
1296 {
1297 if (mNames) return false;
1298 if (mType != Function::Type::kNormal) return false;
1299 if (!mDeps.empty()) return false;
1300 if (mConstantFold || mEmbedIR || mReadOnly) return false;
1301 if (!mFnAttrs.empty()) return false;
1302 if (!mRetAttrs.empty()) return false;
1303 if (!mParamAttrs.empty()) return false;
1304 return true;
1305 }
1306
1307 std::unique_ptr<SmallArgumentVector<const char*>> mNames = nullptr;
1309 bool mConstantFold = false;
1310 bool mEmbedIR = false;
1311 bool mReadOnly = false;
1312 Function::Type mType = Function::Type::kNormal;
1315 std::map<size_t, SmallArgumentVector<llvm::Attribute::AttrKind>> mParamAttrs = {};
1316 };
1317
1318 FunctionBuilder(const char* name)
1319 : mName(name)
1320 , mCurrentSettings(std::make_shared<Settings>()) {}
1321
1322 // C-Binding
1323 template <typename Signature, bool SRet = false>
1324 inline FunctionBuilder&
1325 addSignature(const Signature* ptr, const char* symbol = nullptr)
1326 {
1327 using CFType = typename std::conditional
1329 const std::string s = symbol ? symbol : this->genSymbol<Signature>();
1330 this->addSignatureImpl<CFType>(s, ptr);
1331 return *this;
1332 }
1333
1334 // Non native Binding
1335 template <typename Signature, bool SRet = false>
1336 inline FunctionBuilder&
1338 const char* symbol = nullptr)
1339 {
1340 using IRFType = typename std::conditional
1342 OPENVDB_ASSERT(!(SRet && mCurrentSettings->mReadOnly));
1343 const std::string s = symbol ? symbol : this->genSymbol<Signature>();
1344 this->addSignatureImpl<IRFType>(s, cb);
1345 return *this;
1346 }
1347
1348 // Non native Binding
1349 template <typename Signature, bool SRet = false>
1350 inline FunctionBuilder&
1351 addSignature(const IRFunctionBase::GeneratorCb& cb, const Signature* ptr, const char* symbol = nullptr)
1352 {
1353 this->addSignature<Signature, SRet>(cb, symbol);
1354 this->addSignature<Signature, SRet>(ptr, symbol);
1355 return *this;
1356 }
1357
1358 // Native Binding
1359 template <typename Signature, bool SRet = false>
1360 inline FunctionBuilder&
1361 addSignature(const IRFunctionBase::GeneratorNativeCb& cb, const char* symbol = nullptr)
1362 {
1364 using IRFType = typename std::conditional
1366 OPENVDB_ASSERT(!(SRet && mCurrentSettings->mReadOnly));
1367 const std::string s = symbol ? symbol : this->genSymbol<Signature>();
1368 this->addSignatureImpl<IRFType>(s, cb);
1369 return *this;
1370 }
1371
1372 // Native Binding
1373 template <typename Signature, bool SRet = false>
1374 inline FunctionBuilder&
1375 addSignature(const IRFunctionBase::GeneratorNativeCb& cb, const Signature* ptr, const char* symbol = nullptr)
1376 {
1378 this->addSignature<Signature, SRet>(cb, symbol);
1379 this->addSignature<Signature, SRet>(ptr, symbol);
1380 return *this;
1381 }
1382
1383 // Native Binding
1384 template <typename Signature, bool SRet = false>
1385 inline FunctionBuilder&
1387 const char* symbol = nullptr)
1388 {
1389 using IRFType = typename std::conditional
1391 OPENVDB_ASSERT(!(SRet && mCurrentSettings->mReadOnly));
1392 const std::string s = symbol ? symbol : this->genSymbol<Signature>();
1393 this->addSignatureImpl<IRFType>(s, cb);
1394 return *this;
1395 }
1396
1397 // Native Binding
1398 template <typename Signature, bool SRet = false>
1399 inline FunctionBuilder&
1400 addSignature(const IRFunctionBase::GeneratorArgumentsCb& cb, const Signature* ptr, const char* symbol = nullptr)
1401 {
1402 this->addSignature<Signature, SRet>(cb, symbol);
1403 this->addSignature<Signature, SRet>(ptr, symbol);
1404 return *this;
1405 }
1406
1407 inline FunctionBuilder& addDependency(const char* name)
1408 {
1409 mCurrentSettings->mDeps.emplace_back(name); return *this;
1410 }
1411
1412 inline FunctionBuilder& setEmbedIR(bool on) { mCurrentSettings->mEmbedIR = on; return *this; }
1413 inline FunctionBuilder& setConstantFold(bool on) { mCurrentSettings->mConstantFold = on; return *this; }
1414 inline FunctionBuilder& setArgumentNames(const std::vector<const char*>& names)
1415 {
1416 mCurrentSettings->mNames = std::make_unique<SmallArgumentVector<const char*>>();
1417 mCurrentSettings->mNames->assign(names.begin(), names.end());
1418 return *this;
1419 }
1420
1421 /// @brief Parameter and Function Attributes. When designing a C binding,
1422 /// llvm will be unable to assign parameter markings to the return
1423 /// type, function body or parameter attributes due to there not
1424 /// being any visibility on the function itself during codegen.
1425 /// The best way to ensure performant C bindings is to ensure
1426 /// that the function is marked with the required llvm parameters.
1427 /// @note Some of the most common are shown in FunctionBuilder::setBuiltin,
1428 /// but also consider FunctionBuilder::setReadOnly
1429 inline FunctionBuilder&
1430 addParameterAttribute(const size_t idx, const llvm::Attribute::AttrKind attr)
1431 {
1432 mCurrentSettings->mParamAttrs[idx].emplace_back(attr);
1433 return *this;
1434 }
1435
1436 inline FunctionBuilder&
1437 addReturnAttribute(const llvm::Attribute::AttrKind attr)
1438 {
1439 mCurrentSettings->mRetAttrs.emplace_back(attr);
1440 return *this;
1441 }
1442
1443 inline FunctionBuilder&
1444 addFunctionAttribute(const llvm::Attribute::AttrKind attr)
1445 {
1446 mCurrentSettings->mFnAttrs.emplace_back(attr);
1447 return *this;
1448 }
1449
1450 /// @brief Mark functions currently sharing settings with as "readonly".
1451 /// This enables the strictest possible memory effects for this function
1452 /// in llvm and implies that the function does not write to any memory
1453 /// (i.e. CreateStore) and only reads memory directly from its function
1454 /// arguments (i.e. nothing external to the function). Functions marked
1455 /// as "readonly" but do not adhere to the above will cause UB.
1456 /// @note Obviously invalid for SRET functions!
1457 inline FunctionBuilder&
1458 setReadOnly(const bool on)
1459 {
1460 mCurrentSettings->mReadOnly = on;
1461 return *this;
1462 }
1463
1464 /// @brief Mark functions currently sharing settings as builtin AX methods.
1465 /// At compile time, this causes the IR function body, arguments and
1466 /// return value to be marked with a set of default attributes that
1467 /// apply to all builtin methods, as they are expected to only be called
1468 /// by AX programs. Currently this results in:
1469 ///
1470 /// Function Attributes:
1471 /// llvm::Attribute::NoFree
1472 /// llvm::Attribute::WillReturn
1473 /// llvm::Attribute::NoRecurse
1474 /// llvm::Attribute::NoUnwind
1475 /// llvm::Attribute::AlwaysInline
1476 /// Return Attributes: -
1477 /// Parameter Attributes (Ptrs):
1478 /// llvm::Attribute::NonNull
1479 /// llvm::Attribute::NoUndef
1480 /// llvm::Attribute::NoFree
1481 /// llvm::Attribute::NoCapture / (llvm::CaptureInfo::none() from LLVM 21)
1482 ///
1483 /// @warning Attributes in this method may be extended - as such, you
1484 /// should mark external function with individual attributes instead of
1485 /// calling this.
1486 inline FunctionBuilder&
1488 {
1489 // note that we have to defer the attribute setting to compile time as
1490 // various attributes need to know the function types. Would be nice if
1491 // we could do it all in the builder.
1492 mCurrentSettings->mType = Function::Type::kBuiltin;
1493 return *this;
1494 }
1495
1496 /// @brief Mark this function as an external kernel entry point. Should
1497 /// only be used by the ComputeGenerators. Results in a number of function
1498 /// attributes/parameters being set.
1499 inline FunctionBuilder&
1501 {
1502 mCurrentSettings->mType = Function::Type::kKernel;
1503 return *this;
1504 }
1505
1506 inline FunctionBuilder& setDocumentation(const char* doc)
1507 {
1508 mDoc = doc;
1509 return *this;
1510 }
1511
1513 {
1514 mDeclPref = pref;
1515 return *this;
1516 }
1517
1519 {
1520 for (auto& decl : mCFunctions)
1521 {
1522 const auto& s = mSettings.at(decl.get());
1523 if (s->mNames) decl->mNames = *s->mNames;
1524 decl->mDeps = s->mDeps;
1525 decl->setConstantFold(s->mConstantFold);
1526 if (!s->mFnAttrs.empty()) decl->attrs().mFnAttrs = s->mFnAttrs;
1527 if (!s->mRetAttrs.empty()) decl->attrs().mRetAttrs = s->mRetAttrs;
1528 if (!s->mParamAttrs.empty()) {
1529 for (auto& idxAttrs : s->mParamAttrs) {
1530 if (idxAttrs.first > decl->size()) continue;
1531 decl->attrs().mParamAttrs[idxAttrs.first] = idxAttrs.second;
1532 }
1533 }
1534 if (s->mReadOnly) decl->attrs().mReadOnly = true;
1535 if (s->mType != Function::Type::kNormal) {
1536 decl->attrs().mType = s->mType;
1537 }
1538 }
1539
1540 for (auto& decl : mIRFunctions)
1541 {
1542 const auto& s = mSettings.at(decl.get());
1543 if (s->mNames) decl->mNames = *s->mNames;
1544 decl->mDeps = s->mDeps;
1545 decl->setEmbedIR(s->mEmbedIR);
1546 if (!s->mFnAttrs.empty()) decl->attrs().mFnAttrs = s->mFnAttrs;
1547 if (!s->mRetAttrs.empty()) decl->attrs().mRetAttrs = s->mRetAttrs;
1548 if (!s->mParamAttrs.empty()) {
1549 for (auto& idxAttrs : s->mParamAttrs) {
1550 if (idxAttrs.first > decl->size()) continue;
1551 decl->attrs().mParamAttrs[idxAttrs.first] = idxAttrs.second;
1552 }
1553 }
1554 if (s->mReadOnly) decl->attrs().mReadOnly = true;
1555 if (s->mType != Function::Type::kNormal) {
1556 decl->attrs().mType = s->mType;
1557 }
1558 }
1559
1561
1562 if (mDeclPref == DeclPreferrence::IR) {
1563 functions.insert(functions.end(), mIRFunctions.begin(), mIRFunctions.end());
1564 }
1565 if (mDeclPref == DeclPreferrence::C) {
1566 functions.insert(functions.end(), mCFunctions.begin(), mCFunctions.end());
1567 }
1568 if (functions.empty()) {
1569 functions.insert(functions.end(), mIRFunctions.begin(), mIRFunctions.end());
1570 functions.insert(functions.end(), mCFunctions.begin(), mCFunctions.end());
1571 }
1572
1573 return std::make_unique<FunctionGroup>(mName, mDoc, std::move(functions));
1574 }
1575
1576private:
1577 template <typename FunctionT, typename...Args>
1578 inline FunctionBuilder& addSignatureImpl(Args&& ...args)
1579 {
1580 Settings::Ptr settings = mCurrentSettings;
1581 if (!mCurrentSettings->isDefault()) {
1582 settings = std::make_shared<Settings>();
1583 }
1584 auto ptr = std::make_shared<FunctionT>(std::move(args)...);
1585 if constexpr (std::is_base_of_v<IRFunctionBase, FunctionT>) {
1586 mIRFunctions.emplace_back(ptr);
1587 }
1588 else {
1589 static_assert(std::is_base_of_v<CFunctionBase, FunctionT>);
1590 mCFunctions.emplace_back(ptr);
1591 }
1592 mSettings[ptr.get()] = settings;
1593 mCurrentSettings = settings;
1594 return *this;
1595 }
1596
1597 template <typename Signature>
1598 std::string genSymbol() const
1599 {
1600 using Traits = FunctionTraits<Signature>;
1601
1602 std::string args;
1603 auto callback = [&args](auto type) {
1604 using Type = decltype(type);
1605 args += TypeToSymbol<Type>::s();
1606 };
1607
1608 ArgumentIterator<Signature>::apply(callback, /*forwards*/true);
1609 /// @note important to prefix all symbols with "ax." so that
1610 /// they will never conflict with internal llvm symbol
1611 /// names (such as standard library methods e.g, cos, cosh
1612
1613 // assemble the symbol
1614 return "ax." + std::string(this->mName) + "." +
1615 TypeToSymbol<typename Traits::ReturnType>::s() + args;
1616 }
1617
1618private:
1619 const char* mName = "";
1620 const char* mDoc = "";
1621 DeclPreferrence mDeclPref = IR;
1622 std::vector<CFunctionBase::Ptr> mCFunctions = {};
1623 std::vector<IRFunctionBase::Ptr> mIRFunctions = {};
1624 std::map<const Function*, Settings::Ptr> mSettings = {};
1625 Settings::Ptr mCurrentSettings = nullptr;
1626};
1627
1628} // namespace codegen
1629} // namespace ax
1630} // namespace OPENVDB_VERSION_NAME
1631} // namespace openvdb
1632
1633#endif // OPENVDB_AX_CODEGEN_FUNCTION_TYPES_HAS_BEEN_INCLUDED
1634
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Constant folding for C++ bindings.
#define OPENVDB_AX_API
Definition Platform.h:307
Intermediate representation of supported AX values.
Consolidated llvm types for most supported types.
Definition Exceptions.h:38
Intermediate representation wrapper for supported value types in AX as immutable instances.
Definition Value.h:63
static Value Alloc(llvm::IRBuilder<> &B, llvm::Type *type, llvm::Value *size=nullptr)
Emit IR inserting an allocation at the front of the BasicBlock pointed to by the provided IRBuilder....
Definition Value.h:124
llvm::Value * GetValue() const
Access the underlying llvm Value.
Definition Value.h:672
static Value Invalid()
Return an invalid Value. This is used to represent various fail cases. Note that the operator bool(Va...
Definition Value.h:88
static bool Supports(llvm::Type *utype)
Return true if the underlying type held by utype is supported via the interface of this Value class.
Definition Value.h:109
Definition Codecs.h:18
ArgType< float, 16 > M4F
Definition FunctionTypes.h:139
llvm::Type * llvmTypesFromSignature(llvm::LLVMContext &C, std::vector< llvm::Type * > *types=nullptr)
Populate a vector of llvm types from a function signature declaration.
Definition FunctionTypes.h:473
ArgType< double, 2 > V2D
Definition FunctionTypes.h:127
ArgType< int32_t, 4 > V4I
Definition FunctionTypes.h:135
ArgInfo llvmArgTypesFromSignature(llvm::LLVMContext &C, ArgInfoVector *types=nullptr)
Populate a vector of ArgInfos from a function signature declaration.
Definition FunctionTypes.h:500
ArgType< float, 3 > V3F
Definition FunctionTypes.h:131
llvm::Value * insertStaticAlloca(llvm::IRBuilder<> &B, llvm::Type *type, llvm::Value *size=nullptr)
Insert a stack allocation at the beginning of the current function of the provided type and size....
Definition Utils.h:101
void llvmTypeToString(const llvm::Type *const type, std::string &str)
Prints an llvm type to a std string.
Definition Utils.h:64
ArgType< double, 9 > M3D
Definition FunctionTypes.h:136
ArgType< double, 16 > M4D
Definition FunctionTypes.h:138
ArgType< float, 4 > V4F
Definition FunctionTypes.h:134
ArgType< int32_t, 3 > V3I
Definition FunctionTypes.h:132
llvm::FunctionType * llvmFunctionTypeFromSignature(llvm::LLVMContext &C)
Generate an LLVM FunctionType from a function signature.
Definition FunctionTypes.h:548
ArgType< double, 4 > V4D
Definition FunctionTypes.h:133
OPENVDB_AX_API void printSignature(std::ostream &os, const ArgInfoVector &types, const ArgInfo &returnType, const char *name=nullptr, const llvm::ArrayRef< const char * > &names={}, const bool axTypes=false)
Print a function signature to the provided ostream.
ArgType< float, 9 > M3F
Definition FunctionTypes.h:137
ArgType< int32_t, 2 > V2I
Definition FunctionTypes.h:129
llvm::SmallVector< T, 3 > SmallArgumentVector
Typedef a stack allocated array with malloc grow support for anything which is relatively small and b...
Definition FunctionTypes.h:110
ArgType< float, 2 > V2F
Definition FunctionTypes.h:128
ArgType< double, 3 > V3D
Definition FunctionTypes.h:130
Definition OpenSimplexNoise.h:31
Definition Exceptions.h:13
Definition Coord.h:590
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Utility code generation methods for performing various llvm operations.
Alias mapping between two types, a frontend type T1 and a backend type T2. This class is the intended...
Definition Types.h:253
Container of ArgInfos. This class makes up part of the Function API for querying signature informatio...
Definition FunctionTypes.h:280
auto size() const
Definition FunctionTypes.h:309
bool operator!=(const ArgInfoVector &other) const
Definition FunctionTypes.h:293
SmallArgumentVector< llvm::Type * > AsLLVMTypes() const
Definition FunctionTypes.h:327
ArgInfoVector & operator=(const ArgInfoVector &)=default
ArgInfoVector(const ArgInfoVector &)=default
auto clear()
Definition FunctionTypes.h:308
auto rend() const
Definition FunctionTypes.h:302
void reserve(size_t i)
Definition FunctionTypes.h:313
auto rend()
Definition FunctionTypes.h:300
auto erase(ContainerT::const_iterator iter)
Definition FunctionTypes.h:311
auto & back()
Definition FunctionTypes.h:305
SmallArgumentVector< ArgInfo > ContainerT
Definition FunctionTypes.h:282
auto & front()
Definition FunctionTypes.h:303
auto end()
Definition FunctionTypes.h:296
ArgInfo & operator[](size_t pos)
Definition FunctionTypes.h:316
const ArgInfo & operator[](size_t pos) const
Definition FunctionTypes.h:321
auto empty() const
Definition FunctionTypes.h:310
auto pop_back()
Definition FunctionTypes.h:307
auto & front() const
Definition FunctionTypes.h:304
void emplace_back(Args &&...args)
Definition FunctionTypes.h:315
auto rbegin()
Definition FunctionTypes.h:299
ArgInfoVector(ArgInfoVector &&)=default
auto & back() const
Definition FunctionTypes.h:306
ArgInfoVector & operator=(ArgInfoVector &&)=default
auto rbegin() const
Definition FunctionTypes.h:301
auto begin() const
Definition FunctionTypes.h:297
auto begin()
Definition FunctionTypes.h:295
auto end() const
Definition FunctionTypes.h:298
ArgInfoVector(const std::initializer_list< ArgInfo > &info)
Definition FunctionTypes.h:285
bool operator==(const ArgInfoVector &other) const
Definition FunctionTypes.h:292
Metadata associated with a function argument or return value.
Definition FunctionTypes.h:225
ArgInfo & operator=(ArgInfo &&)=default
bool IsPtr() const
Definition FunctionTypes.h:254
ArgInfo(llvm::Type *utype)
Definition FunctionTypes.h:228
bool IsVoid() const
Definition FunctionTypes.h:257
ArgInfo(const Value &val)
Definition FunctionTypes.h:226
bool IsNative() const
Definition FunctionTypes.h:256
ArgInfo(const ArgInfo &)=default
bool operator!=(const ArgInfo &other) const
Definition FunctionTypes.h:247
uint8_t NumPtrs() const
Definition FunctionTypes.h:255
bool IsReturn() const
Definition FunctionTypes.h:258
ArgInfo & operator=(const ArgInfo &)=default
bool operator==(const ArgInfo &other) const
Definition FunctionTypes.h:240
bool IsMatchingType(const ArgInfo &other) const
Definition FunctionTypes.h:248
llvm::Type * GetUnderlyingType() const
Definition FunctionTypes.h:259
ArgInfo(llvm::Type *utype, uint8_t ptrs, bool ret=false)
Definition FunctionTypes.h:229
void SetIsReturn()
Definition FunctionTypes.h:268
llvm::Type * GetType() const
Definition FunctionTypes.h:260
Object to array conversion methods to allow functions to return vector types. These containers provid...
Definition FunctionTypes.h:117
T Type
Definition FunctionTypes.h:118
static const size_t SIZE
Definition FunctionTypes.h:119
ArrayType mmArgs
Definition FunctionTypes.h:121
Type[SIZE] ArrayType
Definition FunctionTypes.h:120
static const bool IsNativeSignature
Definition FunctionTypes.h:215
static void apply(const OpT &, const bool)
Definition FunctionTypes.h:217
Templated argument iterator which implements various small functions per argument type,...
Definition FunctionTypes.h:189
static const bool IsNativeSignature
Whether this signature contains types that are representable in AX's Value type.
Definition FunctionTypes.h:195
static void apply(const OpT &op, const bool forwards)
Definition FunctionTypes.h:200
typename FunctionTraits< SignatureT >::template Arg< I-1 > ArgT
Definition FunctionTypes.h:190
typename ArgT::Type ArgumentValueType
Definition FunctionTypes.h:191
Arbitrary, potentially "non-native" arguments. This wrapper struct can be used when generating functi...
Definition FunctionTypes.h:382
const ArgInfo & GetArgInfo(size_t pos) const
Definition FunctionTypes.h:427
Value AsNativeValue(const size_t i) const
Definition FunctionTypes.h:410
const llvm::ArrayRef< llvm::Value * > AsLLVMValues() const
Definition FunctionTypes.h:426
size_t size() const
Definition FunctionTypes.h:400
void AddArg(const Value &val)
Definition FunctionTypes.h:442
NativeArguments AsNativeValues() const
Definition FunctionTypes.h:416
Arguments(const Arguments &)=default
Arguments & operator=(const Arguments &)=default
Arguments(const NativeArguments &args)
Create a set of arguments from native arguments. The function framework typically works on generic ar...
Definition FunctionTypes.h:387
void AddArg(llvm::Value *val, const ArgInfo &type)
Definition FunctionTypes.h:436
Arguments & operator=(Arguments &&)=default
bool AreNativeValues() const
Definition FunctionTypes.h:402
void PrependArg(const Value &val)
Definition FunctionTypes.h:448
llvm::Value * operator[](size_t pos) const
Definition FunctionTypes.h:430
const ArgInfoVector & GetArgInfo() const
Definition FunctionTypes.h:428
bool hasConstantFold() const
Definition FunctionTypes.h:939
void setConstantFold(bool on)
Definition FunctionTypes.h:938
virtual llvm::Value * fold(const llvm::ArrayRef< llvm::Value * > &, llvm::LLVMContext &) const
Definition FunctionTypes.h:941
virtual uint64_t address() const =0
Returns the global address of this function.
CFunctionBase(const size_t size, const std::string &symbol)
Definition FunctionTypes.h:949
std::shared_ptr< CFunctionBase > Ptr
Definition FunctionTypes.h:930
Represents a concrete C function binding with the first argument as its return type.
Definition FunctionTypes.h:1165
CFunctionSRet(const std::string &symbol, const SignatureT function)
Definition FunctionTypes.h:1167
SRetFunction< SignatureT, CFunction< SignatureT > > BaseT
Definition FunctionTypes.h:1166
Represents a concrete C function binding.
Definition FunctionTypes.h:965
std::shared_ptr< CFunctionT > Ptr
Definition FunctionTypes.h:967
Value call(const Arguments &args, llvm::IRBuilder<> &B) const override
Definition FunctionTypes.h:1003
uint64_t address() const override final
Returns the global address of this function.
Definition FunctionTypes.h:989
FunctionTraits< SignatureT > Traits
Definition FunctionTypes.h:968
ArgInfo types(ArgInfoVector &types, llvm::LLVMContext &C) const override
Populate a vector of ArgInfos which describe this function signature. This method is used by Function...
Definition FunctionTypes.h:984
llvm::Constant * fold(const llvm::ArrayRef< llvm::Value * > &args, llvm::LLVMContext &C) const override final
Definition FunctionTypes.h:1010
llvm::Value * call(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B) const override
Uses the IRBuilder to create a call to this function with the given arguments, creating the function ...
Definition FunctionTypes.h:995
CFunction(const std::string &symbol, SignatureT *function)
Definition FunctionTypes.h:978
CFunction< SignatureT > CFunctionT
Definition FunctionTypes.h:966
static llvm::Constant * fold(const llvm::ArrayRef< llvm::Constant * > &args, const SignatureT &function, llvm::LLVMContext &C, Tys &&... ts)
Definition ConstantFolding.h:56
static constexpr uint8_t value
Definition Types.h:50
std::unique_ptr< SmallArgumentVector< const char * > > mNames
Definition FunctionTypes.h:1307
bool mReadOnly
Definition FunctionTypes.h:1311
std::shared_ptr< Settings > Ptr
Definition FunctionTypes.h:1293
SmallArgumentVector< const char * > mDeps
Definition FunctionTypes.h:1308
bool isDefault() const
Definition FunctionTypes.h:1295
Function::Type mType
Definition FunctionTypes.h:1312
bool mEmbedIR
Definition FunctionTypes.h:1310
SmallArgumentVector< llvm::Attribute::AttrKind > mFnAttrs
Definition FunctionTypes.h:1313
std::map< size_t, SmallArgumentVector< llvm::Attribute::AttrKind > > mParamAttrs
Definition FunctionTypes.h:1315
bool mConstantFold
Definition FunctionTypes.h:1309
SmallArgumentVector< llvm::Attribute::AttrKind > mRetAttrs
Definition FunctionTypes.h:1314
The FunctionBuilder class provides a builder pattern framework to allow easy and valid construction o...
Definition FunctionTypes.h:1286
FunctionGroup::UniquePtr get() const
Definition FunctionTypes.h:1518
FunctionBuilder & addFunctionAttribute(const llvm::Attribute::AttrKind attr)
Definition FunctionTypes.h:1444
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorCb &cb, const Signature *ptr, const char *symbol=nullptr)
Definition FunctionTypes.h:1351
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorCb &cb, const char *symbol=nullptr)
Definition FunctionTypes.h:1337
FunctionBuilder & addParameterAttribute(const size_t idx, const llvm::Attribute::AttrKind attr)
Parameter and Function Attributes. When designing a C binding, llvm will be unable to assign paramete...
Definition FunctionTypes.h:1430
FunctionBuilder & setPreferredImpl(DeclPreferrence pref)
Definition FunctionTypes.h:1512
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorArgumentsCb &cb, const Signature *ptr, const char *symbol=nullptr)
Definition FunctionTypes.h:1400
DeclPreferrence
Definition FunctionTypes.h:1287
@ IR
Definition FunctionTypes.h:1288
@ C
Definition FunctionTypes.h:1288
@ Any
Definition FunctionTypes.h:1288
FunctionBuilder & addDependency(const char *name)
Definition FunctionTypes.h:1407
FunctionBuilder & setConstantFold(bool on)
Definition FunctionTypes.h:1413
FunctionBuilder & addSignature(const Signature *ptr, const char *symbol=nullptr)
Definition FunctionTypes.h:1325
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorNativeCb &cb, const Signature *ptr, const char *symbol=nullptr)
Definition FunctionTypes.h:1375
FunctionBuilder(const char *name)
Definition FunctionTypes.h:1318
FunctionBuilder & addReturnAttribute(const llvm::Attribute::AttrKind attr)
Definition FunctionTypes.h:1437
FunctionBuilder & setArgumentNames(const std::vector< const char * > &names)
Definition FunctionTypes.h:1414
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorNativeCb &cb, const char *symbol=nullptr)
Definition FunctionTypes.h:1361
FunctionBuilder & setReadOnly(const bool on)
Mark functions currently sharing settings with as "readonly". This enables the strictest possible mem...
Definition FunctionTypes.h:1458
FunctionBuilder & setExternalKernel()
Mark this function as an external kernel entry point. Should only be used by the ComputeGenerators....
Definition FunctionTypes.h:1500
FunctionBuilder & setDocumentation(const char *doc)
Definition FunctionTypes.h:1506
FunctionBuilder & setBuiltin()
Mark functions currently sharing settings as builtin AX methods. At compile time, this causes the IR ...
Definition FunctionTypes.h:1487
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorArgumentsCb &cb, const char *symbol=nullptr)
Definition FunctionTypes.h:1386
FunctionBuilder & setEmbedIR(bool on)
Definition FunctionTypes.h:1412
bool HasUniqueTypeSignatures(llvm::LLVMContext &C) const
Verify the function signatures in this group (must be unique).
Value execute(const NativeArguments &args, llvm::IRBuilder<> &B) const
Given a set of NativeArguments, find the best possible function signature, generate and execute the f...
std::vector< Function::Ptr > FunctionList
Definition FunctionTypes.h:1202
Value execute(const Arguments &args, llvm::IRBuilder<> &B) const
Given a set of Arguments, find an EXPLICIT signature match, generate and execute the function body....
std::pair< const Function *, Function::SignatureMatch > match(const ArgInfoVector &args, llvm::LLVMContext &C) const
Given a vector of args, automatically returns the best possible function declaration from the stored ...
std::shared_ptr< FunctionGroup > Ptr
Definition FunctionTypes.h:1200
std::unique_ptr< FunctionGroup > UniquePtr
Definition FunctionTypes.h:1201
bool HasUniqueFunctionSymbols() const
Verify the function symbol names in this group (must be unique).
const char * name() const
Definition FunctionTypes.h:1267
const char * doc() const
Definition FunctionTypes.h:1268
const FunctionList & list() const
Accessor to the underlying function signature list.
Definition FunctionTypes.h:1266
FunctionGroup(const char *name, const char *doc, const FunctionList &list)
Definition FunctionTypes.h:1204
Templated function traits which provides compile-time index access to the types of the function signa...
Definition Types.h:295
The base/abstract representation of an AX function. Derived classes must implement the Function::type...
Definition FunctionTypes.h:585
virtual SignatureMatch match(const ArgInfoVector &inputs, llvm::LLVMContext &C) const
The base implementation for determining how a vector of llvm arguments translates to this functions s...
Value call(const NativeArguments &args, llvm::IRBuilder<> &B) const
Definition FunctionTypes.h:675
const char * argName(const size_t idx) const
Returns the descriptive name of the given argument index.
Definition FunctionTypes.h:728
virtual void print(llvm::LLVMContext &C, std::ostream &os, const char *name=nullptr, const bool axTypes=true) const
Print this function's signature to the provided ostream.
size_t size() const
The number of arguments that this function has.
Definition FunctionTypes.h:717
virtual llvm::Function * create(llvm::LLVMContext &C, llvm::Module *M=nullptr) const
Converts and creates this AX function into a llvm Function.
virtual llvm::Value * call(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B) const
Uses the IRBuilder to create a call to this function with the given arguments, creating the function ...
Function(const size_t size, const std::string &symbol)
Definition FunctionTypes.h:588
const SmallArgumentVector< const char * > & dependencies() const
Definition FunctionTypes.h:749
llvm::Function * create(llvm::Module &M) const
Convenience method which always uses the provided module to find the function or insert it if necessa...
Definition FunctionTypes.h:635
std::shared_ptr< Function > Ptr
Definition FunctionTypes.h:586
const char * symbol() const
The function symbol name.
Definition FunctionTypes.h:721
virtual ArgInfo types(ArgInfoVector &, llvm::LLVMContext &) const =0
Populate a vector of ArgInfos which describe this function signature. This method is used by Function...
llvm::Function * get(const llvm::Module &M) const
Convenience method for calling M.getFunction(symbol). Returns a nullptr if the function has not yet b...
SignatureMatch
The result type from calls to Function::match.
Definition FunctionTypes.h:684
@ Implicit
Definition FunctionTypes.h:687
@ Ambiguous
Definition FunctionTypes.h:688
@ None
Definition FunctionTypes.h:685
@ Explicit
Definition FunctionTypes.h:689
@ Size
Definition FunctionTypes.h:686
virtual Value call(const Arguments &args, llvm::IRBuilder<> &B) const
IRFunctionBase(const std::string &symbol, const GeneratorNativeCb &gen, const size_t size)
Definition FunctionTypes.h:1120
bool hasEmbedIR() const
Definition FunctionTypes.h:1056
void setEmbedIR(bool on)
Enable or disable the embedding of IR. Embedded IR is currently required for function which use paren...
Definition FunctionTypes.h:1055
std::shared_ptr< IRFunctionBase > Ptr
Definition FunctionTypes.h:1029
const GeneratorArgumentsCb mGen
Definition FunctionTypes.h:1137
llvm::Function * create(llvm::LLVMContext &C, llvm::Module *M) const override
Override for the creation of an IR function. This ensures that the body and prototype of the function...
std::function< llvm::Value *(const std::vector< llvm::Value * > &, llvm::IRBuilder<> &)> GeneratorCb
Legacy callback, will eventually be deprecated in favour of using the GeneratorArgumentsCb.
Definition FunctionTypes.h:1049
Value call(const Arguments &args, llvm::IRBuilder<> &) const override
bool mEmbedIR
Definition FunctionTypes.h:1138
llvm::Value * call(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B) const override
Override for call, which is only necessary if mEmbedIR is true, as the IR generation for embedded fun...
IRFunctionBase(const std::string &symbol, const GeneratorCb &gen, const size_t size)
Definition FunctionTypes.h:1098
void verifyResultType(const llvm::Type *result, const llvm::Type *expected) const
Definition FunctionTypes.h:1088
std::function< Value(const NativeArguments &, llvm::IRBuilder<> &)> GeneratorNativeCb
The IR callback function which will write the LLVM IR for this function's body.
Definition FunctionTypes.h:1041
std::function< Value(const Arguments &, llvm::IRBuilder<> &)> GeneratorArgumentsCb
Definition FunctionTypes.h:1044
IRFunctionBase(const std::string &symbol, const GeneratorArgumentsCb &gen, const size_t size)
Definition FunctionTypes.h:1129
Represents a concrete IR function with the first argument as its return type.
Definition FunctionTypes.h:1176
IRFunctionSRet(const std::string &symbol, const IRFunctionBase::GeneratorCb &gen)
Definition FunctionTypes.h:1178
IRFunctionSRet(const std::string &symbol, const IRFunctionBase::GeneratorArgumentsCb &gen)
Definition FunctionTypes.h:1184
IRFunctionSRet(const std::string &symbol, const IRFunctionBase::GeneratorNativeCb &gen)
Definition FunctionTypes.h:1181
SRetFunction< SignatureT, IRFunction< SignatureT > > BaseT
Definition FunctionTypes.h:1177
Represents a concrete IR function.
Definition FunctionTypes.h:1144
IRFunction(const std::string &symbol, const GeneratorArgumentsCb &gen)
Definition FunctionTypes.h:1152
FunctionTraits< SignatureT > Traits
Definition FunctionTypes.h:1145
ArgInfo types(ArgInfoVector &types, llvm::LLVMContext &C) const override
Populate a vector of ArgInfos which describe this function signature. This method is used by Function...
Definition FunctionTypes.h:1155
IRFunction(const std::string &symbol, const GeneratorCb &gen)
Definition FunctionTypes.h:1148
IRFunction(const std::string &symbol, const GeneratorNativeCb &gen)
Definition FunctionTypes.h:1150
std::shared_ptr< IRFunction > Ptr
Definition FunctionTypes.h:1146
LLVM type mapping from pod types.
Definition Types.h:68
static const bool CXXUTypeIsNativeType
Definition Types.h:76
static llvm::Type * get(llvm::LLVMContext &C)
Return an LLVM type which represents T.
Definition Types.h:81
Wrapper struct to represent "native" function arguments; that is, the set of Value type that the AX g...
Definition FunctionTypes.h:349
size_t size() const
Definition FunctionTypes.h:359
NativeArguments & operator=(const NativeArguments &)=default
void AddArg(const Value &val)
Definition FunctionTypes.h:370
NativeArguments(const std::initializer_list< Value > &args)
Definition FunctionTypes.h:351
OPENVDB_AX_API NativeArguments Cast(const Function &F, llvm::IRBuilder<> &B) const
Cast these arguments to match the given function's signature.
NativeArguments(const std::vector< Value > &args)
Definition FunctionTypes.h:353
Value & operator[](size_t pos)
Definition FunctionTypes.h:360
NativeArguments & operator=(NativeArguments &&)=default
const Value & operator[](size_t pos) const
Definition FunctionTypes.h:365
NativeArguments(NativeArguments &&)=default
NativeArguments(const NativeArguments &)=default
void print(llvm::LLVMContext &C, std::ostream &os, const char *name=nullptr, const bool axTypes=true) const override
Override of print to avoid printing out the SRET type.
Definition FunctionTypes.h:901
Value call(const Arguments &args, llvm::IRBuilder<> &B) const override
Definition FunctionTypes.h:890
std::shared_ptr< SRetFunction< SignatureT, DerivedFunction > > Ptr
Definition FunctionTypes.h:814
FunctionTraits< SignatureT > Traits
Definition FunctionTypes.h:815
Function::SignatureMatch match(const ArgInfoVector &args, llvm::LLVMContext &C) const override
Override of match which inserts the SRET type such that the base class methods ignore it.
Definition FunctionTypes.h:856
SRetFunction(Args &&... ts)
Forward all arguments to the derived class.
Definition FunctionTypes.h:924
llvm::Value * call(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B) const override
Override of call which allocates the required SRET llvm::Value for this function.
Definition FunctionTypes.h:878
ArgInfo types(ArgInfoVector &args, llvm::LLVMContext &C) const override
Overide the ArgInfo type method. This does NOT change the arg order, it simply marks the first argume...
Definition FunctionTypes.h:843
An extremely basic but native representation of a string class with SSO support. This exists to provi...
Definition String.h:34
static std::string s()
Definition FunctionTypes.h:164
static std::string s()
Definition FunctionTypes.h:169
static std::string s()
Definition FunctionTypes.h:149
static std::string s()
Definition FunctionTypes.h:160
static std::string s()
Definition FunctionTypes.h:159
static std::string s()
Definition FunctionTypes.h:158
static std::string s()
Definition FunctionTypes.h:155
static std::string s()
Definition FunctionTypes.h:156
static std::string s()
Definition FunctionTypes.h:157
static std::string s()
Definition FunctionTypes.h:154
static std::string s()
Definition FunctionTypes.h:151
static std::string s()
Definition FunctionTypes.h:152
static std::string s()
Definition FunctionTypes.h:153
static std::string s()
Definition FunctionTypes.h:150
static std::string s()
Definition FunctionTypes.h:148
Type to symbol conversions - these characters are used to build each functions unique signature....
Definition FunctionTypes.h:147
static std::string s()
Definition FunctionTypes.h:147
#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:291