OpenVDB 9.0.0
FunctionTypes.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/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 "Utils.h" // isValidCast
71#include "ConstantFolding.h"
72
73#include <openvdb/version.h>
74
75#include <llvm/IR/Constants.h>
76#include <llvm/IR/IRBuilder.h>
77#include <llvm/IR/Module.h>
78
79#include <algorithm>
80#include <functional>
81#include <memory>
82#include <stack>
83#include <type_traits>
84#include <unordered_map>
85#include <vector>
86
87namespace openvdb {
89namespace OPENVDB_VERSION_NAME {
90
91namespace ax {
92namespace codegen {
93
94////////////////////////////////////////////////////////////////////////////////
95////////////////////////////////////////////////////////////////////////////////
96
97/// @brief Object to array conversion methods to allow functions to return
98/// vector types. These containers provided an interface for automatic
99/// conversion of C++ objects to LLVM types as array types.
100
101template <typename T, size_t _SIZE = 1>
102struct ArgType {
103 using Type = T;
104 static const size_t SIZE = _SIZE;
105 using ArrayType = Type[SIZE];
107};
108
109template <typename T, size_t S>
110struct LLVMType<ArgType<T,S>> : public AliasTypeMap<ArgType<T,S>, T[S]> {};
111
125
126////////////////////////////////////////////////////////////////////////////////
127
128/// @brief Type to symbol conversions - these characters are used to build each
129/// functions unique signature. They differ from standard AX or LLVM
130/// syntax to be as short as possible i.e. vec4d, [4 x double] = d4
131
132template <typename T> struct TypeToSymbol { static inline std::string s() { return "?"; } };
133template <> struct TypeToSymbol<void> { static inline std::string s() { return "v"; } };
134template <> struct TypeToSymbol<char> { static inline std::string s() { return "c"; } };
135template <> struct TypeToSymbol<int16_t> { static inline std::string s() { return "s"; } };
136template <> struct TypeToSymbol<int32_t> { static inline std::string s() { return "i"; } };
137template <> struct TypeToSymbol<int64_t> { static inline std::string s() { return "l"; } };
138template <> struct TypeToSymbol<float> { static inline std::string s() { return "f"; } };
139template <> struct TypeToSymbol<double> { static inline std::string s() { return "d"; } };
140template <> struct TypeToSymbol<codegen::String> { static inline std::string s() { return "a"; } };
141
142template <typename T>
143struct TypeToSymbol<T*> {
144 static inline std::string s() { return TypeToSymbol<T>::s() + "*"; }
145};
146
147template <typename T, size_t S>
148struct TypeToSymbol<T[S]> {
149 static inline std::string s() { return TypeToSymbol<T>::s() + std::to_string(S); }
150};
151
152template <typename T, size_t S> struct TypeToSymbol<ArgType<T,S>> : public TypeToSymbol<T[S]> {};
153template <typename T> struct TypeToSymbol<math::Vec2<T>> : public TypeToSymbol<T[2]> {};
154template <typename T> struct TypeToSymbol<math::Vec3<T>> : public TypeToSymbol<T[3]> {};
155template <typename T> struct TypeToSymbol<math::Vec4<T>> : public TypeToSymbol<T[4]> {};
156template <typename T> struct TypeToSymbol<math::Mat3<T>> : public TypeToSymbol<T[9]> {};
157template <typename T> struct TypeToSymbol<math::Mat4<T>> : public TypeToSymbol<T[16]> {};
158template <typename T> struct TypeToSymbol<const T> : public TypeToSymbol<T> {};
159template <typename T> struct TypeToSymbol<const T*> : public TypeToSymbol<T*> {};
160
161////////////////////////////////////////////////////////////////////////////////
162////////////////////////////////////////////////////////////////////////////////
163
164/// @brief Templated argument iterator which implements various small functions
165/// per argument type, resolved at compile time.
166///
167template <typename SignatureT, size_t I = FunctionTraits<SignatureT>::N_ARGS>
169{
171 using ArgumentValueType = typename ArgT::Type;
172
173 template <typename OpT>
174 static void apply(const OpT& op, const bool forwards) {
175 if (forwards) {
177 op(ArgumentValueType());
178 }
179 else {
180 op(ArgumentValueType());
182 }
183 }
184};
185
186template <typename SignatureT>
187struct ArgumentIterator<SignatureT, 0>
188{
189 template <typename OpT>
190 static void apply(const OpT&, const bool) {}
191};
192
193////////////////////////////////////////////////////////////////////////////////
194////////////////////////////////////////////////////////////////////////////////
195
196/// @brief Populate a vector of llvm types from a function signature declaration.
197///
198/// @param C The llvm context
199/// @param types A vector of types to populate
200///
201template <typename SignatureT>
202inline llvm::Type*
203llvmTypesFromSignature(llvm::LLVMContext& C,
204 std::vector<llvm::Type*>* types = nullptr)
205{
206 using Traits = FunctionTraits<SignatureT>;
207 using ArgumentIteratorT =
209
210 if (types) {
211 types->reserve(Traits::N_ARGS);
212 auto callback = [&types, &C](auto type) {
213 using Type = decltype(type);
214 types->emplace_back(LLVMType<Type>::get(C));
215 };
216 ArgumentIteratorT::apply(callback, /*forwards*/true);
217 }
219}
220
221/// @brief Generate an LLVM FunctionType from a function signature
222///
223/// @param C The llvm context
224///
225template <typename SignatureT>
226inline llvm::FunctionType*
227llvmFunctionTypeFromSignature(llvm::LLVMContext& C)
228{
229 std::vector<llvm::Type*> types;
230 llvm::Type* returnType =
231 llvmTypesFromSignature<SignatureT>(C, &types);
232 return llvm::FunctionType::get(/*Result=*/returnType,
233 /*Params=*/llvm::ArrayRef<llvm::Type*>(types),
234 /*isVarArg=*/false);
235}
236
237/// @brief Print a function signature to the provided ostream.
238///
239/// @param os The stream to print to
240/// @param types The function argument types
241/// @param returnType The return type of the function. Must not be a nullptr
242/// @param name The name of the function. If not provided, the return type
243/// neighbours the first parenthesis
244/// @param names Names of the function parameters. If a name is nullptr, it
245/// skipped
246/// @param axTypes Whether to try and convert the llvm::Types provided to
247/// AX types. If false, the llvm types are used.
248void
249printSignature(std::ostream& os,
250 const std::vector<llvm::Type*>& types,
251 const llvm::Type* returnType,
252 const char* name = nullptr,
253 const std::vector<const char*>& names = {},
254 const bool axTypes = false);
255
256////////////////////////////////////////////////////////////////////////////////
257////////////////////////////////////////////////////////////////////////////////
258
259/// @brief The base/abstract representation of an AX function. Derived classes
260/// must implement the Function::types call to describe their signature.
262{
263 using Ptr = std::shared_ptr<Function>;
264
265 Function(const size_t size, const std::string& symbol)
266 : mSize(size)
267 , mSymbol(symbol)
268 , mAttributes(nullptr)
269 , mNames()
270 , mDeps() {
271 // symbol must be a valid string
272 assert(!symbol.empty());
273 }
274
275 virtual ~Function() = default;
276
277 /// @brief Populate a vector of llvm::Types which describe this function
278 /// signature. This method is used by Function::create,
279 /// Function::print and Function::match.
280 virtual llvm::Type* types(std::vector<llvm::Type*>&, llvm::LLVMContext&) const = 0;
281
282 /// @brief Converts and creates this AX function into a llvm Function.
283 /// @details This method uses the result from Function::types() to construct
284 /// a llvm::FunctionType and a subsequent a llvm::Function. Any
285 /// parameter, return or function attributes are also added to the
286 /// function. If a module is provided, the module if first checked
287 /// to see if the function already exists. If it does, it is
288 /// immediately returned. If the function doesn't exist in the
289 /// module, its prototype is created and also inserted into the end
290 /// of the modules function list. If no module is provided, the
291 /// function is left detached and must be added to a valid Module
292 /// to be callable.
293 /// @warning If a module is not provided, the caller takes ownership of the
294 /// returned function and is responsible for deallocating it.
295 /// @note The body of the function is left to derived classes to
296 /// implement. As you need a Module to generate the prototype/body,
297 /// this function serves two purposes. The first is to return the
298 /// detached function signature if only a context is provided.
299 /// The second is to ensure the function prototype and body (if
300 /// required) is inserted into the module prior to returning.
301 /// @note It is possible to end up with function symbol collisions if you
302 /// do not have unique function symbols in your module
303 ///
304 /// @param C The LLVM Context
305 /// @param M The Module to write the function to
306 virtual llvm::Function*
307 create(llvm::LLVMContext& C, llvm::Module* M = nullptr) const;
308
309 /// @brief Convenience method which always uses the provided module to find
310 /// the function or insert it if necessary.
311 /// @param M The llvm::Module to use
312 llvm::Function* create(llvm::Module& M) const {
313 return this->create(M.getContext(), &M);
314 }
315
316 /// @brief Convenience method for calling M.getFunction(symbol). Returns a
317 /// nullptr if the function has not yet been created or if it is
318 /// embedded IR.
319 /// @param M The llvm::Module to use
320 llvm::Function* get(const llvm::Module& M) const;
321
322 /// @brief Uses the IRBuilder to create a call to this function with the
323 /// given arguments, creating the function and inserting it into the
324 /// IRBuilder's Module if necessary (through Function::create).
325 /// Returns the result of the function call which can be a nullptr
326 /// if the function is a non-sret void call.
327 /// @note The IRBuilder must have a valid llvm Module/Function/Block
328 /// attached
329 /// @note If the number of provided arguments do not match the size of the
330 /// current function, invalid IR will be generated.
331 /// @note If the provided argument types do not match the current function
332 /// and cast is false, invalid IR will be generated. Additionally,
333 /// invalid IR will be generated if cast is true but no valid cast
334 /// exists for a given argument.
335 /// @note When casting arguments, the readonly flags of the function are
336 /// not checked (unlike Function::match). Casting an argument will
337 /// cause a new copy of the argument to be created and passed to the
338 /// function. These new values do not propagate back any changes to
339 /// the original argument. Separate functions for all writable
340 /// argument types must be created.
341 ///
342 /// @param args The llvm Value arguments to call this function with
343 /// @param B The llvm IRBuilder
344 /// @param cast Whether to allow implicit casting of arguments
345 virtual llvm::Value*
346 call(const std::vector<llvm::Value*>& args,
347 llvm::IRBuilder<>& B,
348 const bool cast = false) const;
349
350 /// @brief The result type from calls to Function::match
351 enum SignatureMatch { None = 0, Size, Implicit, Explicit };
352
353 /// @brief The base implementation for determining how a vector of llvm
354 /// arguments translates to this functions signature. Returns an
355 /// enum which represents the available mapping.
356 /// @details This method calls types() to figure out the function signature,
357 /// then compares each argument type to the type in the input
358 /// vector. If the types match exactly, an Explicit match is found.
359 /// If the sizes of the inputs and signature differ, no match is
360 /// found and None is returned. If however, the sizes match and
361 /// there exists a valid implicit cast from the input type to the
362 /// signature type for every input, an Implicit match is returned.
363 /// Finally, if the sizes match but there is no implicit cast
364 /// mapping, Size is returned.
365 /// i8 -> i32 : Implicit
366 /// i32 -> i32 : Explicit
367 /// str -> i32 : Size
368 /// (i32,i32) -> i32 : None
369 /// @note Due to the way CFunctionSRet is implemented, the LLVM Context
370 /// must be provided in case we have a zero arg function signature
371 /// with a SRET.
372 /// @param inputs The input types
373 /// @param C The LLVM Context
374 virtual SignatureMatch match(const std::vector<llvm::Type*>& inputs, llvm::LLVMContext& C) const;
375
376 /// @brief The number of arguments that this function has
377 inline size_t size() const { return mSize; }
378
379 /// @brief The function symbol name.
380 /// @details This will be used as its identifier in IR and must be unique.
381 inline const char* symbol() const { return mSymbol.c_str(); }
382
383 /// @brief Returns the descriptive name of the given argument index
384 /// @details If the index is greater than the number of arguments, an empty
385 /// string is returned.
386 ///
387 /// @param idx The index of the argument
388 inline const char* argName(const size_t idx) const {
389 return idx < mNames.size() ? mNames[idx] : "";
390 }
391
392 /// @brief Print this function's signature to the provided ostream.
393 /// @details This is intended to return a descriptive front end user string
394 /// rather than the function's IR representation. This function is
395 /// virtual so that derived classes can customize how they present
396 /// frontend information.
397 /// @sa printSignature
398 ///
399 /// @param C The llvm context
400 /// @param os The ostream to print to
401 /// @param name The name to insert into the description.
402 /// @param axTypes Whether to print llvm IR or AX Types.
403 virtual void print(llvm::LLVMContext& C,
404 std::ostream& os,
405 const char* name = nullptr,
406 const bool axTypes = true) const;
407
408 /// Builder methods
409
410 inline bool hasParamAttribute(const size_t i,
411 const llvm::Attribute::AttrKind& kind) const
412 {
413 if (!mAttributes) return false;
414 const auto iter = mAttributes->mParamAttrs.find(i);
415 if (iter == mAttributes->mParamAttrs.end()) return false;
416 const auto& vec = iter->second;
417 return std::find(vec.begin(), vec.end(), kind) != vec.end();
418 }
419
420 inline void setArgumentNames(std::vector<const char*> names) { mNames = names; }
421
422 const std::vector<const char*>& dependencies() const { return mDeps; }
423 inline void setDependencies(std::vector<const char*> deps) { mDeps = deps; }
424
425 inline void setFnAttributes(const std::vector<llvm::Attribute::AttrKind>& in)
426 {
427 this->attrs().mFnAttrs = in;
428 }
429 inline void setRetAttributes(const std::vector<llvm::Attribute::AttrKind>& in)
430 {
431 this->attrs().mRetAttrs = in;
432 }
433 inline void setParamAttributes(const size_t i,
434 const std::vector<llvm::Attribute::AttrKind>& in)
435 {
436 this->attrs().mParamAttrs[i] = in;
437 }
438
439protected:
440
441 /// @brief Cast the provided arguments to the given type as supported by
442 /// implicit casting of function types. If the types already match
443 /// OR if a cast cannot be performed, nothing is done to the argument.
444 /// @todo This should really be generalized out for Function::call and
445 /// Function::match to both use. However, due to SRET functions,
446 /// this logic must be performed somewhere in the Function class
447 /// hierarchy and not in FunctionGroup
448 static void cast(std::vector<llvm::Value*>& args,
449 const std::vector<llvm::Type*>& types,
450 llvm::IRBuilder<>& B);
451
452private:
453
454 struct Attributes {
455 std::vector<llvm::Attribute::AttrKind> mFnAttrs, mRetAttrs;
456 std::map<size_t, std::vector<llvm::Attribute::AttrKind>> mParamAttrs;
457 };
458
459 inline Attributes& attrs() {
460 if (!mAttributes) mAttributes.reset(new Attributes());
461 return *mAttributes;
462 }
463
464 llvm::AttributeList flattenAttrs(llvm::LLVMContext& C) const;
465
466 const size_t mSize;
467 const std::string mSymbol;
468 std::unique_ptr<Attributes> mAttributes;
469 std::vector<const char*> mNames;
470 std::vector<const char*> mDeps;
471};
472
473/// @brief Templated interface class for SRET functions. This struct provides
474/// the interface for functions that wish to return arrays (vectors or
475/// matrices) by internally remapping the first argument for the user.
476/// As far as LLVM and any bindings are concerned, the function
477/// signature remains unchanged - however the first argument becomes
478/// "invisible" to the user and is instead allocated by LLVM before the
479/// function is executed. Importantly, the argument has no impact on
480/// the user facing AX signature and doesn't affect declaration selection.
481/// @note This class is not intended to be instantiated directly, but instead
482/// used by derived implementation which hold a valid implementations
483/// of member functions required to create a llvm::Function (such as
484/// Function::types and Function::call). This exists as an interface to
485/// avoid virtual inheritance.
486///
487template <typename SignatureT, typename DerivedFunction>
488struct SRetFunction : public DerivedFunction
489{
490 using Ptr = std::shared_ptr<SRetFunction<SignatureT, DerivedFunction>>;
492
493 // check there actually are arguments
494 static_assert(Traits::N_ARGS > 0,
495 "SRET Function object has been setup with the first argument as the return "
496 "value, however the provided signature is empty.");
497
498 // check no return value exists
500 "SRET Function object has been setup with the first argument as the return "
501 "value and a non void return type.");
502
503private:
504
505 using FirstArgument = typename Traits::template Arg<0>::Type;
507 "SRET Function object has been setup with the first argument as the return "
508 "value, but this argument it is not a pointer type.");
509 using SRetType = typename std::remove_pointer<FirstArgument>::type;
510
511public:
512
513 /// @brief Override of match which inserts the SRET type such that the base
514 /// class methods ignore it.
515 Function::SignatureMatch match(const std::vector<llvm::Type*>& args,
516 llvm::LLVMContext& C) const override
517 {
518 // append return type and right rotate
519 std::vector<llvm::Type*> inputs(args);
520 inputs.emplace_back(LLVMType<SRetType*>::get(C));
521 std::rotate(inputs.rbegin(), inputs.rbegin() + 1, inputs.rend());
522 return DerivedFunction::match(inputs, C);
523 }
524
525 /// @brief Override of call which allocates the required SRET llvm::Value
526 /// for this function.
527 /// @note Unlike other function where the returned llvm::Value* is a
528 /// llvm::CallInst (which also represents the return value),
529 /// SRET functions return the allocated 1st argument i.e. not a
530 /// llvm::CallInst
531 llvm::Value*
532 call(const std::vector<llvm::Value*>& args,
533 llvm::IRBuilder<>& B,
534 const bool cast) const override
535 {
536 // append return value and right rotate
537 std::vector<llvm::Value*> inputs(args);
538 llvm::Type* sret = LLVMType<SRetType>::get(B.getContext());
539 inputs.emplace_back(insertStaticAlloca(B, sret));
540 std::rotate(inputs.rbegin(), inputs.rbegin() + 1, inputs.rend());
541 DerivedFunction::call(inputs, B, cast);
542 return inputs.front();
543 }
544
545 /// @brief Override of print to avoid printing out the SRET type
546 void print(llvm::LLVMContext& C,
547 std::ostream& os,
548 const char* name = nullptr,
549 const bool axTypes = true) const override
550 {
551 std::vector<llvm::Type*> current;
552 llvm::Type* ret = this->types(current, C);
553 // left rotate
554 std::rotate(current.begin(), current.begin() + 1, current.end());
555 ret = current.back();
556 current.pop_back();
557
558 std::vector<const char*> names;
559 names.reserve(this->size());
560 for (size_t i = 0; i < this->size()-1; ++i) {
561 names.emplace_back(this->argName(i));
562 }
563 printSignature(os, current, ret, name, names, axTypes);
564 }
565
566protected:
567 /// @brief Forward all arguments to the derived class
568 template <typename ...Args>
569 SRetFunction(Args&&... ts) : DerivedFunction(ts...) {}
570};
571
572/// @brief The base class for all C bindings.
573struct CFunctionBase : public Function
574{
575 using Ptr = std::shared_ptr<CFunctionBase>;
576
577 ~CFunctionBase() override = default;
578
579 /// @brief Returns the global address of this function.
580 /// @note This is only required for C bindings.
581 virtual uint64_t address() const = 0;
582
583 inline void setConstantFold(bool on) { mConstantFold = on; }
584 inline bool hasConstantFold() const { return mConstantFold; }
585
586 inline virtual llvm::Value* fold(const std::vector<llvm::Value*>&,
587 llvm::LLVMContext&) const {
588 return nullptr;
589 }
590
591protected:
592 CFunctionBase(const size_t size,
593 const std::string& symbol)
594 : Function(size, symbol)
595 , mConstantFold(false) {}
596
597private:
598 bool mConstantFold;
599};
600
601/// @brief Represents a concrete C function binding.
602///
603/// @note This struct is templated on the signature to allow for evaluation of
604/// the arguments to llvm types from any llvm context.
605///
606template <typename SignatureT>
608{
610 using Ptr = std::shared_ptr<CFunctionT>;
612
613 // Assert that the return argument is not a pointer (relaxed for void* for mallocs).
614 // Note that this is relaxed for IR functions where it's allowed if the function is
615 // forcefully inlined.
618 "CFunction object has been setup with a pointer return argument. C bindings "
619 "cannot return memory locations to LLVM - Consider using a CFunctionSRet.");
620
621 CFunction(const std::string& symbol, const SignatureT function)
622 : CFunctionBase(Traits::N_ARGS, symbol)
623 , mFunction(function) {}
624
625 ~CFunction() override = default;
626
627 inline llvm::Type* types(std::vector<llvm::Type*>& types, llvm::LLVMContext& C) const override
628 {
629 return llvmTypesFromSignature<SignatureT>(C, &types);
630 }
631
632 inline uint64_t address() const override final {
633 return reinterpret_cast<uint64_t>(mFunction);
634 }
635
636 llvm::Value*
637 call(const std::vector<llvm::Value*>& args,
638 llvm::IRBuilder<>& B,
639 const bool cast) const override
640 {
641 llvm::Value* result = this->fold(args, B.getContext());
642 if (result) return result;
643 return Function::call(args, B, cast);
644 }
645
646 llvm::Value* fold(const std::vector<llvm::Value*>& args, llvm::LLVMContext& C) const override final
647 {
648 auto allconst =
649 [](const std::vector<llvm::Value*>& vals) -> bool {
650 for (auto& value : vals) {
651 if (!llvm::isa<llvm::Constant>(value)) return false;
652 }
653 return true;
654 };
655
656 if (!this->hasConstantFold()) return nullptr;
657 if (!allconst(args)) return nullptr;
658 std::vector<llvm::Constant*> constants;
659 constants.reserve(args.size());
660 for (auto& value : args) {
661 constants.emplace_back(llvm::cast<llvm::Constant>(value));
662 }
663
664 // no guarantee that fold() will be able to cast all arguments
665 return ConstantFolder<SignatureT>::fold(constants, *mFunction, C);
666 }
667
668private:
669 const SignatureT* mFunction;
670};
671
672/// @brief The base/abstract definition for an IR function.
674{
675 using Ptr = std::shared_ptr<IRFunctionBase>;
676
677 /// @brief The IR callback function which will write the LLVM IR for this
678 /// function's body.
679 /// @details The first argument is the vector of functional arguments. i.e.
680 /// a representation of the value that the callback has been invoked
681 /// with.
682 /// The last argument is the IR builder which should be used to
683 /// generate the function body IR.
684 /// @note You can return a nullptr from this method which will represent
685 /// a ret void, a ret void instruction, or an actual value
686 using GeneratorCb = std::function<llvm::Value*
687 (const std::vector<llvm::Value*>&, llvm::IRBuilder<>&)>;
688
689 llvm::Type* types(std::vector<llvm::Type*>& types,
690 llvm::LLVMContext& C) const override = 0;
691
692 /// @brief Enable or disable the embedding of IR. Embedded IR is currently
693 /// required for function which use parent function parameters.
694 inline void setEmbedIR(bool on) { mEmbedIR = on; }
695 inline bool hasEmbedIR() const { return mEmbedIR; }
696
697 /// @brief Override for the creation of an IR function. This ensures that
698 /// the body and prototype of the function are generated if a Module
699 /// is provided.
700 /// @note A nullptr is returned if mEmbedIR is true and no action is
701 /// performed.
702 /// @note Throws if this function has been initialized with a nullptr
703 /// generator callback. In this case, the function prototype will
704 /// be created, but not the function body.
705 /// @note Throws if the return type of the generator callback does not
706 /// match the function prototype. In this case, both the prototype
707 /// and the function body will be created and inserted, but the IR
708 /// will be invalid.
709 llvm::Function*
710 create(llvm::LLVMContext& C, llvm::Module* M) const override;
711
712 /// @brief Override for call, which is only necessary if mEmbedIR is true,
713 /// as the IR generation for embedded functions is delayed until
714 /// the function is called. If mEmbedIR is false, this simply calls
715 /// Function::call
716 llvm::Value*
717 call(const std::vector<llvm::Value*>& args,
718 llvm::IRBuilder<>& B,
719 const bool cast) const override;
720
721protected:
722
723 // @todo This should ideally live in FunctionGroup::execute, but the return
724 // type is allowed to differ for sret C bindings.
725 inline void
726 verifyResultType(const llvm::Type* result, const llvm::Type* expected) const
727 {
728 if (result == expected) return;
729 std::string source, target;
730 if (result) llvmTypeToString(result, source);
731 llvmTypeToString(expected, target);
732 OPENVDB_THROW(AXCodeGenError, "Function \"" + std::string(this->symbol()) +
733 "\" has been invoked with a mismatching return type. Expected: \"" +
734 target + "\", got \"" + source + "\".");
735 }
736
737 IRFunctionBase(const std::string& symbol,
738 const GeneratorCb& gen,
739 const size_t size)
740 : Function(size, symbol)
741 , mGen(gen)
742 , mEmbedIR(false) {}
743 ~IRFunctionBase() override = default;
744
747};
748
749/// @brief Represents a concrete IR function.
750template <typename SignatureT>
752{
754 using Ptr = std::shared_ptr<IRFunction>;
755
756 IRFunction(const std::string& symbol, const GeneratorCb& gen)
757 : IRFunctionBase(symbol, gen, Traits::N_ARGS) {}
758
759 inline llvm::Type*
760 types(std::vector<llvm::Type*>& types, llvm::LLVMContext& C) const override
761 {
762 return llvmTypesFromSignature<SignatureT>(C, &types);
763 }
764};
765
766/// @brief Represents a concrete C function binding with the first argument as
767/// its return type.
768template <typename SignatureT>
769struct CFunctionSRet : public SRetFunction<SignatureT, CFunction<SignatureT>>
770{
772 CFunctionSRet(const std::string& symbol, const SignatureT function)
773 : BaseT(symbol, function) {}
774 ~CFunctionSRet() override = default;
775};
776
777/// @brief Represents a concrete IR function with the first argument as
778/// its return type.
779template <typename SignatureT>
780struct IRFunctionSRet : public SRetFunction<SignatureT, IRFunction<SignatureT>>
781{
783 IRFunctionSRet(const std::string& symbol,
785 : BaseT(symbol, gen) {}
786 ~IRFunctionSRet() override = default;
787};
788
789/// @brief todo
791{
792 using Ptr = std::shared_ptr<FunctionGroup>;
793 using UniquePtr = std::unique_ptr<FunctionGroup>;
794 using FunctionList = std::vector<Function::Ptr>;
795
796 FunctionGroup(const char* name,
797 const char* doc,
798 const FunctionList& list)
799 : mName(name)
800 , mDoc(doc)
801 , mFunctionList(list) {}
802 ~FunctionGroup() = default;
803
804 /// @brief Given a vector of llvm types, automatically returns the best
805 /// possible function declaration from the stored function list. The
806 /// 'best' declaration is determined by the provided types
807 /// compatibility to each functions signature.
808 /// @note If multiple implicit matches are found, the first match is
809 /// returned.
810 /// @note Returns a nullptr if no compatible match was found or if the
811 /// function list is empty. A compatible match is defined as an
812 /// Explicit or Implicit match.
813 ///
814 /// @param types A vector of types representing the function argument types
815 /// @param C The llvm context
816 /// @param type If provided, type is set to the type of match that occurred
817 const Function*
818 match(const std::vector<llvm::Type*>& types,
819 llvm::LLVMContext& C,
820 Function::SignatureMatch* type = nullptr) const;
821
822 /// @brief Given a vector of llvm values, find the best possible function
823 /// signature, generate and execute the function body. Returns the
824 /// return value of the function (nullptr if void). The behaviour
825 /// is undefined if a valid match does not exist. For such cases,
826 /// call the second version of FunctionGroup::execute.
827 /// @note This function will throw if no valid return is provided by the
828 /// matched declaration implementation.
829 ///
830 /// @param args A vector of values representing the function arguments
831 /// @param B The current llvm IRBuilder
832 llvm::Value*
833 execute(const std::vector<llvm::Value*>& args,
834 llvm::IRBuilder<>& B) const;
835
836 /// @brief Given a vector of llvm values, find the best possible function
837 /// signature, generate and execute the function body. Returns the
838 /// Function that was selected and executed or a nullptr if no
839 /// valid match was found. Sets the result variable to the return
840 /// value of the function (nullptr if void). If no match is found,
841 /// the result variable if left unset.
842 /// @note This function will throw if no valid return is provided by the
843 /// matched declaration implementation.
844 ///
845 /// @param args A vector of values representing the function arguments
846 /// @param B The current llvm IRBuilder
847 /// @param result The result to set. nullptr on void return.
848 /// @return The matched function. nullptr if no match was found
849 const Function*
850 execute(const std::vector<llvm::Value*>& args,
851 llvm::IRBuilder<>& B,
852 llvm::Value*& result) const;
853
854 /// @brief Accessor to the underlying function signature list
855 inline const FunctionList& list() const { return mFunctionList; }
856 const char* name() const { return mName; }
857 const char* doc() const { return mDoc; }
858
859private:
860 const char* mName;
861 const char* mDoc;
862 const FunctionList mFunctionList;
863};
864
865/// @brief The FunctionBuilder class provides a builder pattern framework to
866/// allow easy and valid construction of AX functions. There are a
867/// number of complex tasks which may need to be performed during
868/// construction of C or IR function which are delegated to this
869/// builder, whilst ensuring that the constructed functions are
870/// guaranteed to be valid.
871/// @details Use the FunctionBuilder::addSignature methods to append function
872/// signatures. Finalize the group of functions with
873/// FunctionBuilder::get.
875{
877 C, IR, Any
878 };
879
880 struct Settings
881 {
882 using Ptr = std::shared_ptr<Settings>;
883
884 inline bool isDefault() const {
885 if (mNames) return false;
886 if (!mDeps.empty()) return false;
887 if (mConstantFold || mEmbedIR) return false;
888 if (!mFnAttrs.empty()) return false;
889 if (!mRetAttrs.empty()) return false;
890 if (!mParamAttrs.empty()) return false;
891 return true;
892 }
893
894 std::shared_ptr<std::vector<const char*>> mNames = nullptr;
895 std::vector<const char*> mDeps = {};
896 bool mConstantFold = false;
897 bool mEmbedIR = false;
898 std::vector<llvm::Attribute::AttrKind> mFnAttrs = {};
899 std::vector<llvm::Attribute::AttrKind> mRetAttrs = {};
900 std::map<size_t, std::vector<llvm::Attribute::AttrKind>> mParamAttrs = {};
901 };
902
903 FunctionBuilder(const char* name)
904 : mName(name)
905 , mCurrentSettings(new Settings()) {}
906
907
908 template <typename Signature, bool SRet = false>
909 inline FunctionBuilder&
911 const char* symbol = nullptr)
912 {
913 using IRFType = typename std::conditional
915 using IRPtr = typename IRFType::Ptr;
916
917 Settings::Ptr settings = mCurrentSettings;
918 if (!mCurrentSettings->isDefault()) {
919 settings.reset(new Settings());
920 }
921
922 std::string s;
923 if (symbol) s = std::string(symbol);
924 else s = this->genSymbol<Signature>();
925
926 auto ir = IRPtr(new IRFType(s, cb));
927 mIRFunctions.emplace_back(ir);
928 mSettings[ir.get()] = settings;
929 mCurrentSettings = settings;
930 return *this;
931 }
932
933 template <typename Signature, bool SRet = false>
934 inline FunctionBuilder&
935 addSignature(const Signature* ptr,
936 const char* symbol = nullptr)
937 {
938 using CFType = typename std::conditional
940 using CPtr = typename CFType::Ptr;
941
942 Settings::Ptr settings = mCurrentSettings;
943 if (!mCurrentSettings->isDefault()) {
944 settings.reset(new Settings());
945 }
946
947 std::string s;
948 if (symbol) s = std::string(symbol);
949 else s = this->genSymbol<Signature>();
950
951 auto c = CPtr(new CFType(s, ptr));
952 mCFunctions.emplace_back(c);
953 mSettings[c.get()] = settings;
954 mCurrentSettings = settings;
955 return *this;
956 }
957
958 template <typename Signature, bool SRet = false>
959 inline FunctionBuilder&
960 addSignature(const IRFunctionBase::GeneratorCb& cb, const Signature* ptr, const char* symbol = nullptr)
961 {
962 this->addSignature<Signature, SRet>(cb, symbol);
963 this->addSignature<Signature, SRet>(ptr, symbol);
964 return *this;
965 }
966
967 inline FunctionBuilder& addDependency(const char* name) {
968 mCurrentSettings->mDeps.emplace_back(name); return *this;
969 }
970
971 inline FunctionBuilder& setEmbedIR(bool on) { mCurrentSettings->mEmbedIR = on; return *this; }
972 inline FunctionBuilder& setConstantFold(bool on) { mCurrentSettings->mConstantFold = on; return *this; }
973 inline FunctionBuilder& setArgumentNames(const std::vector<const char*>& names) {
974 mCurrentSettings->mNames.reset(new std::vector<const char*>(names));
975 return *this;
976 }
977
978 /// @details Parameter and Function Attributes. When designing a C binding,
979 /// llvm will be unable to assign parameter markings to the return
980 /// type, function body or parameter attributes due to there not
981 /// being any visibility on the function itself during codegen.
982 /// The best way to ensure performant C bindings is to ensure
983 /// that the function is marked with the required llvm parameters.
984 /// Some of the heavy hitters (which can have the most impact)
985 /// are below:
986 ///
987 /// Functions:
988 /// - norecurse
989 /// This function attribute indicates that the function does
990 /// not call itself either directly or indirectly down any
991 /// possible call path.
992 ///
993 /// - willreturn
994 /// This function attribute indicates that a call of this
995 /// function will either exhibit undefined behavior or comes
996 /// back and continues execution at a point in the existing
997 /// call stack that includes the current invocation.
998 ///
999 /// - nounwind
1000 /// This function attribute indicates that the function never
1001 /// raises an exception.
1002 ///
1003 /// - readnone
1004 /// On a function, this attribute indicates that the function
1005 /// computes its result (or decides to unwind an exception) based
1006 /// strictly on its arguments, without dereferencing any pointer
1007 /// arguments or otherwise accessing any mutable state (e.g. memory,
1008 /// control registers, etc) visible to caller functions.
1009 ///
1010 /// - readonly
1011 /// On a function, this attribute indicates that the function
1012 /// does not write through any pointer arguments (including byval
1013 /// arguments) or otherwise modify any state (e.g. memory, control
1014 /// registers, etc) visible to caller functions.
1015 /// control registers, etc) visible to caller functions.
1016 ///
1017 /// - writeonly
1018 /// On a function, this attribute indicates that the function may
1019 /// write to but does not read from memory.
1020 ///
1021 /// Parameters:
1022 /// - noalias
1023 /// This indicates that objects accessed via pointer values based
1024 /// on the argument or return value are not also accessed, during
1025 /// the execution of the function, via pointer values not based on
1026 /// the argument or return value.
1027 ///
1028 /// - nonnull
1029 /// This indicates that the parameter or return pointer is not null.
1030 ///
1031 /// - readonly
1032 /// Indicates that the function does not write through this pointer
1033 /// argument, even though it may write to the memory that the pointer
1034 /// points to.
1035 ///
1036 /// - writeonly
1037 /// Indicates that the function may write to but does not read through
1038 /// this pointer argument (even though it may read from the memory
1039 /// that the pointer points to).
1040 ///
1041 inline FunctionBuilder&
1042 addParameterAttribute(const size_t idx, const llvm::Attribute::AttrKind attr) {
1043 mCurrentSettings->mParamAttrs[idx].emplace_back(attr);
1044 return *this;
1045 }
1046
1047 inline FunctionBuilder&
1048 addReturnAttribute(const llvm::Attribute::AttrKind attr) {
1049 mCurrentSettings->mRetAttrs.emplace_back(attr);
1050 return *this;
1051 }
1052
1053 inline FunctionBuilder&
1054 addFunctionAttribute(const llvm::Attribute::AttrKind attr) {
1055 mCurrentSettings->mFnAttrs.emplace_back(attr);
1056 return *this;
1057 }
1058
1059 inline FunctionBuilder& setDocumentation(const char* doc) { mDoc = doc; return *this; }
1060 inline FunctionBuilder& setPreferredImpl(DeclPreferrence pref) { mDeclPref = pref; return *this; }
1061
1063 {
1064 for (auto& decl : mCFunctions) {
1065 const auto& s = mSettings.at(decl.get());
1066 decl->setDependencies(s->mDeps);
1067 decl->setConstantFold(s->mConstantFold);
1068 if (!s->mFnAttrs.empty()) decl->setFnAttributes(s->mFnAttrs);
1069 if (!s->mRetAttrs.empty()) decl->setRetAttributes(s->mRetAttrs);
1070 if (!s->mParamAttrs.empty()) {
1071 for (auto& idxAttrs : s->mParamAttrs) {
1072 if (idxAttrs.first > decl->size()) continue;
1073 decl->setParamAttributes(idxAttrs.first, idxAttrs.second);
1074 }
1075 }
1076 if (s->mNames) decl->setArgumentNames(*s->mNames);
1077 }
1078
1079 for (auto& decl : mIRFunctions) {
1080 const auto& s = mSettings.at(decl.get());
1081 decl->setDependencies(s->mDeps);
1082 decl->setEmbedIR(s->mEmbedIR);
1083 if (!s->mFnAttrs.empty()) decl->setFnAttributes(s->mFnAttrs);
1084 if (!s->mRetAttrs.empty()) decl->setRetAttributes(s->mRetAttrs);
1085 if (!s->mParamAttrs.empty()) {
1086 for (auto& idxAttrs : s->mParamAttrs) {
1087 if (idxAttrs.first > decl->size()) continue;
1088 decl->setParamAttributes(idxAttrs.first, idxAttrs.second);
1089 }
1090 }
1091 if (s->mNames) decl->setArgumentNames(*s->mNames);
1092 }
1093
1094 std::vector<Function::Ptr> functions;
1095
1096 if (mDeclPref == DeclPreferrence::IR) {
1097 functions.insert(functions.end(), mIRFunctions.begin(), mIRFunctions.end());
1098 }
1099 if (mDeclPref == DeclPreferrence::C) {
1100 functions.insert(functions.end(), mCFunctions.begin(), mCFunctions.end());
1101 }
1102 if (functions.empty()) {
1103 functions.insert(functions.end(), mIRFunctions.begin(), mIRFunctions.end());
1104 functions.insert(functions.end(), mCFunctions.begin(), mCFunctions.end());
1105 }
1106
1107 FunctionGroup::UniquePtr group(new FunctionGroup(mName, mDoc, functions));
1108 return group;
1109 }
1110
1111private:
1112
1113 template <typename Signature>
1114 std::string genSymbol() const
1115 {
1116 using Traits = FunctionTraits<Signature>;
1117
1118 std::string args;
1119 auto callback = [&args](auto type) {
1120 using Type = decltype(type);
1121 args += TypeToSymbol<Type>::s();
1122 };
1123
1124 ArgumentIterator<Signature>::apply(callback, /*forwards*/true);
1125 /// @note important to prefix all symbols with "ax." so that
1126 /// they will never conflict with internal llvm symbol
1127 /// names (such as standard library methods e.g, cos, cosh
1128
1129 // assemble the symbol
1130 return "ax." + std::string(this->mName) + "." +
1131 TypeToSymbol<typename Traits::ReturnType>::s() + args;
1132 }
1133
1134 const char* mName = "";
1135 const char* mDoc = "";
1136 DeclPreferrence mDeclPref = IR;
1137 std::vector<CFunctionBase::Ptr> mCFunctions = {};
1138 std::vector<IRFunctionBase::Ptr> mIRFunctions = {};
1139 std::map<const Function*, Settings::Ptr> mSettings = {};
1140 Settings::Ptr mCurrentSettings = nullptr;
1141};
1142
1143} // namespace codegen
1144} // namespace ax
1145} // namespace OPENVDB_VERSION_NAME
1146} // namespace openvdb
1147
1148#endif // OPENVDB_AX_CODEGEN_FUNCTION_TYPES_HAS_BEEN_INCLUDED
1149
Constant folding for C++ bindings.
ValueT value
Definition: GridBuilder.h:1287
Consolidated llvm types for most supported types.
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
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:123
void printSignature(std::ostream &os, const std::vector< llvm::Type * > &types, const llvm::Type *returnType, const char *name=nullptr, const std::vector< const char * > &names={}, const bool axTypes=false)
Print a function signature to the provided ostream.
llvm::FunctionType * llvmFunctionTypeFromSignature(llvm::LLVMContext &C)
Generate an LLVM FunctionType from a function signature.
Definition: FunctionTypes.h:227
void llvmTypeToString(const llvm::Type *const type, std::string &str)
Prints an llvm type to a std string.
Definition: Utils.h:70
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:203
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Utility classes and functions for OpenVDB plugins.
Alias mapping between two types, a frontend type T1 and a backend type T2. This class is the intended...
Definition: Types.h:219
Object to array conversion methods to allow functions to return vector types. These containers provid...
Definition: FunctionTypes.h:102
T Type
Definition: FunctionTypes.h:103
ArrayType mData
Definition: FunctionTypes.h:106
Type[SIZE] ArrayType
Definition: FunctionTypes.h:105
static void apply(const OpT &, const bool)
Definition: FunctionTypes.h:190
Templated argument iterator which implements various small functions per argument type,...
Definition: FunctionTypes.h:169
static void apply(const OpT &op, const bool forwards)
Definition: FunctionTypes.h:174
typename FunctionTraits< SignatureT >::template Arg< I-1 > ArgT
Definition: FunctionTypes.h:170
typename ArgT::Type ArgumentValueType
Definition: FunctionTypes.h:171
The base class for all C bindings.
Definition: FunctionTypes.h:574
bool hasConstantFold() const
Definition: FunctionTypes.h:584
void setConstantFold(bool on)
Definition: FunctionTypes.h:583
virtual llvm::Value * fold(const std::vector< llvm::Value * > &, llvm::LLVMContext &) const
Definition: FunctionTypes.h:586
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:592
Represents a concrete C function binding with the first argument as its return type.
Definition: FunctionTypes.h:770
CFunctionSRet(const std::string &symbol, const SignatureT function)
Definition: FunctionTypes.h:772
Represents a concrete C function binding.
Definition: FunctionTypes.h:608
uint64_t address() const override final
Returns the global address of this function.
Definition: FunctionTypes.h:632
CFunction(const std::string &symbol, const SignatureT function)
Definition: FunctionTypes.h:621
llvm::Value * call(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B, const bool cast) const override
Uses the IRBuilder to create a call to this function with the given arguments, creating the function ...
Definition: FunctionTypes.h:637
llvm::Type * types(std::vector< llvm::Type * > &types, llvm::LLVMContext &C) const override
Populate a vector of llvm::Types which describe this function signature. This method is used by Funct...
Definition: FunctionTypes.h:627
llvm::Value * fold(const std::vector< llvm::Value * > &args, llvm::LLVMContext &C) const override final
Definition: FunctionTypes.h:646
Constant folding support structure.
Definition: ConstantFolding.h:35
std::shared_ptr< Settings > Ptr
Definition: FunctionTypes.h:882
bool isDefault() const
Definition: FunctionTypes.h:884
The FunctionBuilder class provides a builder pattern framework to allow easy and valid construction o...
Definition: FunctionTypes.h:875
FunctionGroup::UniquePtr get() const
Definition: FunctionTypes.h:1062
FunctionBuilder & addFunctionAttribute(const llvm::Attribute::AttrKind attr)
Definition: FunctionTypes.h:1054
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorCb &cb, const Signature *ptr, const char *symbol=nullptr)
Definition: FunctionTypes.h:960
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorCb &cb, const char *symbol=nullptr)
Definition: FunctionTypes.h:910
FunctionBuilder & addParameterAttribute(const size_t idx, const llvm::Attribute::AttrKind attr)
Definition: FunctionTypes.h:1042
FunctionBuilder & setPreferredImpl(DeclPreferrence pref)
Definition: FunctionTypes.h:1060
DeclPreferrence
Definition: FunctionTypes.h:876
@ C
Definition: FunctionTypes.h:877
FunctionBuilder & addDependency(const char *name)
Definition: FunctionTypes.h:967
FunctionBuilder & setConstantFold(bool on)
Definition: FunctionTypes.h:972
FunctionBuilder & addSignature(const Signature *ptr, const char *symbol=nullptr)
Definition: FunctionTypes.h:935
FunctionBuilder(const char *name)
Definition: FunctionTypes.h:903
FunctionBuilder & addReturnAttribute(const llvm::Attribute::AttrKind attr)
Definition: FunctionTypes.h:1048
FunctionBuilder & setArgumentNames(const std::vector< const char * > &names)
Definition: FunctionTypes.h:973
FunctionBuilder & setDocumentation(const char *doc)
Definition: FunctionTypes.h:1059
FunctionBuilder & setEmbedIR(bool on)
Definition: FunctionTypes.h:971
todo
Definition: FunctionTypes.h:791
std::vector< Function::Ptr > FunctionList
Definition: FunctionTypes.h:794
std::shared_ptr< FunctionGroup > Ptr
Definition: FunctionTypes.h:792
std::unique_ptr< FunctionGroup > UniquePtr
Definition: FunctionTypes.h:793
const Function * match(const std::vector< llvm::Type * > &types, llvm::LLVMContext &C, Function::SignatureMatch *type=nullptr) const
Given a vector of llvm types, automatically returns the best possible function declaration from the s...
const char * name() const
Definition: FunctionTypes.h:856
llvm::Value * execute(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B) const
Given a vector of llvm values, find the best possible function signature, generate and execute the fu...
const char * doc() const
Definition: FunctionTypes.h:857
const Function * execute(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B, llvm::Value *&result) const
Given a vector of llvm values, find the best possible function signature, generate and execute the fu...
const FunctionList & list() const
Accessor to the underlying function signature list.
Definition: FunctionTypes.h:855
FunctionGroup(const char *name, const char *doc, const FunctionList &list)
Definition: FunctionTypes.h:796
Templated function traits which provides compile-time index access to the types of the function signa...
Definition: Types.h:259
The base/abstract representation of an AX function. Derived classes must implement the Function::type...
Definition: FunctionTypes.h:262
const std::vector< const char * > & dependencies() const
Definition: FunctionTypes.h:422
const char * argName(const size_t idx) const
Returns the descriptive name of the given argument index.
Definition: FunctionTypes.h:388
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.
void setDependencies(std::vector< const char * > deps)
Definition: FunctionTypes.h:423
size_t size() const
The number of arguments that this function has.
Definition: FunctionTypes.h:377
virtual llvm::Function * create(llvm::LLVMContext &C, llvm::Module *M=nullptr) const
Converts and creates this AX function into a llvm Function.
void setParamAttributes(const size_t i, const std::vector< llvm::Attribute::AttrKind > &in)
Definition: FunctionTypes.h:433
static void cast(std::vector< llvm::Value * > &args, const std::vector< llvm::Type * > &types, llvm::IRBuilder<> &B)
Cast the provided arguments to the given type as supported by implicit casting of function types....
Function(const size_t size, const std::string &symbol)
Definition: FunctionTypes.h:265
void setRetAttributes(const std::vector< llvm::Attribute::AttrKind > &in)
Definition: FunctionTypes.h:429
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:312
void setFnAttributes(const std::vector< llvm::Attribute::AttrKind > &in)
Definition: FunctionTypes.h:425
std::shared_ptr< Function > Ptr
Definition: FunctionTypes.h:263
virtual llvm::Value * call(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B, const bool cast=false) const
Uses the IRBuilder to create a call to this function with the given arguments, creating the function ...
bool hasParamAttribute(const size_t i, const llvm::Attribute::AttrKind &kind) const
Builder methods.
Definition: FunctionTypes.h:410
virtual SignatureMatch match(const std::vector< llvm::Type * > &inputs, llvm::LLVMContext &C) const
The base implementation for determining how a vector of llvm arguments translates to this functions s...
const char * symbol() const
The function symbol name.
Definition: FunctionTypes.h:381
virtual llvm::Type * types(std::vector< llvm::Type * > &, llvm::LLVMContext &) const =0
Populate a vector of llvm::Types which describe this function signature. This method is used by Funct...
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:351
void setArgumentNames(std::vector< const char * > names)
Definition: FunctionTypes.h:420
The base/abstract definition for an IR function.
Definition: FunctionTypes.h:674
std::function< llvm::Value *(const std::vector< llvm::Value * > &, llvm::IRBuilder<> &)> GeneratorCb
The IR callback function which will write the LLVM IR for this function's body.
Definition: FunctionTypes.h:687
bool hasEmbedIR() const
Definition: FunctionTypes.h:695
void setEmbedIR(bool on)
Enable or disable the embedding of IR. Embedded IR is currently required for function which use paren...
Definition: FunctionTypes.h:694
llvm::Value * call(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B, const bool cast) const override
Override for call, which is only necessary if mEmbedIR is true, as the IR generation for embedded fun...
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...
const GeneratorCb mGen
Definition: FunctionTypes.h:745
llvm::Type * types(std::vector< llvm::Type * > &types, llvm::LLVMContext &C) const override=0
Populate a vector of llvm::Types which describe this function signature. This method is used by Funct...
bool mEmbedIR
Definition: FunctionTypes.h:746
IRFunctionBase(const std::string &symbol, const GeneratorCb &gen, const size_t size)
Definition: FunctionTypes.h:737
void verifyResultType(const llvm::Type *result, const llvm::Type *expected) const
Definition: FunctionTypes.h:726
Represents a concrete IR function with the first argument as its return type.
Definition: FunctionTypes.h:781
IRFunctionSRet(const std::string &symbol, const IRFunctionBase::GeneratorCb &gen)
Definition: FunctionTypes.h:783
Represents a concrete IR function.
Definition: FunctionTypes.h:752
llvm::Type * types(std::vector< llvm::Type * > &types, llvm::LLVMContext &C) const override
Populate a vector of llvm::Types which describe this function signature. This method is used by Funct...
Definition: FunctionTypes.h:760
IRFunction(const std::string &symbol, const GeneratorCb &gen)
Definition: FunctionTypes.h:756
LLVM type mapping from pod types.
Definition: Types.h:55
Templated interface class for SRET functions. This struct provides the interface for functions that w...
Definition: FunctionTypes.h:489
std::shared_ptr< SRetFunction< SignatureT, DerivedFunction > > Ptr
Definition: FunctionTypes.h:490
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:546
llvm::Value * call(const std::vector< llvm::Value * > &args, llvm::IRBuilder<> &B, const bool cast) const override
Override of call which allocates the required SRET llvm::Value for this function.
Definition: FunctionTypes.h:532
SRetFunction(Args &&... ts)
Forward all arguments to the derived class.
Definition: FunctionTypes.h:569
Function::SignatureMatch match(const std::vector< llvm::Type * > &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:515
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:144
static std::string s()
Definition: FunctionTypes.h:149
static std::string s()
Definition: FunctionTypes.h:134
static std::string s()
Definition: FunctionTypes.h:140
static std::string s()
Definition: FunctionTypes.h:139
static std::string s()
Definition: FunctionTypes.h:138
static std::string s()
Definition: FunctionTypes.h:135
static std::string s()
Definition: FunctionTypes.h:136
static std::string s()
Definition: FunctionTypes.h:137
static std::string s()
Definition: FunctionTypes.h:133
Type to symbol conversions - these characters are used to build each functions unique signature....
Definition: FunctionTypes.h:132
static std::string s()
Definition: FunctionTypes.h:132
#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