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