OpenVDB  12.0.0
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 
88 namespace openvdb {
90 namespace OPENVDB_VERSION_NAME {
91 
92 namespace ax {
93 namespace 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 
102 template <typename T, size_t _SIZE = 1>
103 struct ArgType {
104  using Type = T;
105  static const size_t SIZE = _SIZE;
106  using ArrayType = Type[SIZE];
108 };
109 
110 template <typename T, size_t S>
111 struct 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 
133 template <typename T> struct TypeToSymbol { static inline std::string s() { return "?"; } };
134 template <> struct TypeToSymbol<void> { static inline std::string s() { return "v"; } };
135 template <> struct TypeToSymbol<char> { static inline std::string s() { return "c"; } };
136 template <> struct TypeToSymbol<uint8_t> { static inline std::string s() { return "u8"; } };
137 template <> struct TypeToSymbol<uint16_t> { static inline std::string s() { return "us"; } };
138 template <> struct TypeToSymbol<uint32_t> { static inline std::string s() { return "ui"; } };
139 template <> struct TypeToSymbol<uint64_t> { static inline std::string s() { return "ul"; } };
140 template <> struct TypeToSymbol<int8_t> { static inline std::string s() { return "8"; } };
141 template <> struct TypeToSymbol<int16_t> { static inline std::string s() { return "s"; } };
142 template <> struct TypeToSymbol<int32_t> { static inline std::string s() { return "i"; } };
143 template <> struct TypeToSymbol<int64_t> { static inline std::string s() { return "l"; } };
144 template <> struct TypeToSymbol<float> { static inline std::string s() { return "f"; } };
145 template <> struct TypeToSymbol<double> { static inline std::string s() { return "d"; } };
146 template <> struct TypeToSymbol<codegen::String> { static inline std::string s() { return "a"; } };
147 
148 template <typename T>
149 struct TypeToSymbol<T*> {
150  static inline std::string s() { return TypeToSymbol<T>::s() + "*"; }
151 };
152 
153 template <typename T, size_t S>
154 struct TypeToSymbol<T[S]> {
155  static inline std::string s() { return TypeToSymbol<T>::s() + std::to_string(S); }
156 };
157 
158 template <typename T, size_t S> struct TypeToSymbol<ArgType<T,S>> : public TypeToSymbol<T[S]> {};
159 template <typename T> struct TypeToSymbol<math::Vec2<T>> : public TypeToSymbol<T[2]> {};
160 template <typename T> struct TypeToSymbol<math::Vec3<T>> : public TypeToSymbol<T[3]> {};
161 template <typename T> struct TypeToSymbol<math::Vec4<T>> : public TypeToSymbol<T[4]> {};
162 template <typename T> struct TypeToSymbol<math::Mat3<T>> : public TypeToSymbol<T[9]> {};
163 template <typename T> struct TypeToSymbol<math::Mat4<T>> : public TypeToSymbol<T[16]> {};
164 template <typename T> struct TypeToSymbol<const T> : public TypeToSymbol<T> {};
165 template <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 ///
173 template <typename SignatureT, size_t I = FunctionTraits<SignatureT>::N_ARGS>
175 {
176  using ArgT = typename FunctionTraits<SignatureT>::template Arg<I-1>;
177  using ArgumentValueType = typename ArgT::Type;
178 
179  template <typename OpT>
180  static void apply(const OpT& op, const bool forwards) {
181  if (forwards) {
184  }
185  else {
188  }
189  }
190 };
191 
192 template <typename SignatureT>
193 struct 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 ///
207 template <typename SignatureT>
208 inline llvm::Type*
209 llvmTypesFromSignature(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 ///
231 template <typename SignatureT>
232 inline llvm::FunctionType*
233 llvmFunctionTypeFromSignature(llvm::LLVMContext& C)
234 {
235  std::vector<llvm::Type*> types;
236  llvm::Type* returnType =
237  llvmTypesFromSignature<SignatureT>(C, &types);
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.
254 OPENVDB_AX_API void
255 printSignature(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
357  enum SignatureMatch { None = 0, Size, Implicit, Explicit };
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 
445 protected:
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 
458 private:
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 ///
493 template <typename SignatureT, typename DerivedFunction>
494 struct 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 
509 private:
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 
517 public:
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 
572 protected:
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.
579 struct 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 
597 protected:
598  CFunctionBase(const size_t size,
599  const std::string& symbol)
600  : Function(size, symbol)
601  , mConstantFold(false) {}
602 
603 private:
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 ///
612 template <typename SignatureT>
613 struct CFunction : public CFunctionBase
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  {
635  return llvmTypesFromSignature<SignatureT>(C, &types);
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 
674 private:
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 
724 protected:
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)
743  : Function(size, symbol)
744  , mGen(gen)
745  , mEmbedIR(false) {}
746  ~IRFunctionBase() override = default;
747 
749  bool mEmbedIR;
750 };
751 
752 /// @brief Represents a concrete IR function.
753 template <typename SignatureT>
754 struct IRFunction : public IRFunctionBase
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  {
765  return llvmTypesFromSignature<SignatureT>(C, &types);
766  }
767 };
768 
769 /// @brief Represents a concrete C function binding with the first argument as
770 /// its return type.
771 template <typename SignatureT>
772 struct 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.
782 template <typename SignatureT>
783 struct IRFunctionSRet : public SRetFunction<SignatureT, IRFunction<SignatureT>>
784 {
786  IRFunctionSRet(const std::string& symbol,
787  const IRFunctionBase::GeneratorCb& gen)
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 
862 private:
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 {
880  C, IR, Any
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 
1065  inline FunctionGroup::UniquePtr get() const
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 
1114 private:
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) + "." +
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 
const GeneratorCb mGen
Definition: FunctionTypes.h:748
LLVM type mapping from pod types.
Definition: Types.h:55
uint64_t address() const override final
Returns the global address of this function.
Definition: FunctionTypes.h:638
static std::string s()
Definition: FunctionTypes.h:138
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
Object to array conversion methods to allow functions to return vector types. These containers provid...
Definition: FunctionTypes.h:103
Represents a concrete IR function.
Definition: FunctionTypes.h:754
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
ArrayType mData
Definition: FunctionTypes.h:107
const std::vector< const char * > & dependencies() const
Definition: FunctionTypes.h:428
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Templated interface class for SRET functions. This struct provides the interface for functions that w...
Definition: FunctionTypes.h:494
const char * argName(const size_t idx) const
Returns the descriptive name of the given argument index.
Definition: FunctionTypes.h:394
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorCb &cb, const char *symbol=nullptr)
Definition: FunctionTypes.h:913
typename FunctionTraits< SignatureT >::template Arg< I-1 > ArgT
Definition: FunctionTypes.h:176
The base/abstract definition for an IR function.
Definition: FunctionTypes.h:679
Function(const size_t size, const std::string &symbol)
Definition: FunctionTypes.h:271
CFunctionSRet(const std::string &symbol, const SignatureT function)
Definition: FunctionTypes.h:775
FunctionBuilder & setArgumentNames(const std::vector< const char * > &names)
Definition: FunctionTypes.h:976
The base class for all C bindings.
Definition: FunctionTypes.h:579
const char * name() const
Definition: FunctionTypes.h:859
T Type
Definition: FunctionTypes.h:104
const char * symbol() const
The function symbol name.
Definition: FunctionTypes.h:387
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
Alias mapping between two types, a frontend type T1 and a backend type T2. This class is the intended...
Definition: Types.h:239
#define OPENVDB_AX_API
Definition: Platform.h:289
static std::string s()
Definition: FunctionTypes.h:134
static std::string s()
Definition: FunctionTypes.h:145
Templated argument iterator which implements various small functions per argument type...
Definition: FunctionTypes.h:174
llvm::FunctionType * llvmFunctionTypeFromSignature(llvm::LLVMContext &C)
Generate an LLVM FunctionType from a function signature.
Definition: FunctionTypes.h:233
Type[SIZE] ArrayType
Definition: FunctionTypes.h:106
std::vector< Function::Ptr > FunctionList
Definition: FunctionTypes.h:797
std::unique_ptr< FunctionGroup > UniquePtr
Definition: FunctionTypes.h:796
Consolidated llvm types for most supported types.
OPENVDB_AX_API void print(const ast::Node &node, const bool numberStatements=true, std::ostream &os=std::cout, const char *indent=" ")
Writes a descriptive printout of a Node hierarchy into a target stream.
static std::string s()
Definition: FunctionTypes.h:142
static std::string s()
Definition: FunctionTypes.h:150
static std::string s()
Definition: FunctionTypes.h:144
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
static std::string s()
Definition: FunctionTypes.h:133
FunctionBuilder & setConstantFold(bool on)
Definition: FunctionTypes.h:975
Represents a concrete IR function with the first argument as its return type.
Definition: FunctionTypes.h:783
void setDependencies(std::vector< const char * > deps)
Definition: FunctionTypes.h:429
OutGridT XformOp & op
Definition: ValueTransformer.h:139
FunctionBuilder & setDocumentation(const char *doc)
Definition: FunctionTypes.h:1062
bool hasParamAttribute(const size_t i, const llvm::Attribute::AttrKind &kind) const
Builder methods.
Definition: FunctionTypes.h:416
FunctionBuilder & setEmbedIR(bool on)
Definition: FunctionTypes.h:974
const FunctionList & list() const
Accessor to the underlying function signature list.
Definition: FunctionTypes.h:858
FunctionBuilder & addDependency(const char *name)
Definition: FunctionTypes.h:970
std::shared_ptr< Settings > Ptr
Definition: FunctionTypes.h:885
bool mEmbedIR
Definition: FunctionTypes.h:749
static std::string s()
Definition: FunctionTypes.h:140
FunctionBuilder & addSignature(const Signature *ptr, const char *symbol=nullptr)
Definition: FunctionTypes.h:938
FunctionGroup(const char *name, const char *doc, const FunctionList &list)
Definition: FunctionTypes.h:799
static std::string s()
Definition: FunctionTypes.h:155
std::shared_ptr< FunctionGroup > Ptr
Definition: FunctionTypes.h:795
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
CFunctionBase(const size_t size, const std::string &symbol)
Definition: FunctionTypes.h:598
The FunctionBuilder class provides a builder pattern framework to allow easy and valid construction o...
Definition: FunctionTypes.h:877
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
Represents a concrete C function binding.
Definition: FunctionTypes.h:613
static std::string s()
Definition: FunctionTypes.h:139
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
Constant folding support structure.
Definition: ConstantFolding.h:35
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&#39;s body.
Definition: FunctionTypes.h:693
typename ArgT::Type ArgumentValueType
Definition: FunctionTypes.h:177
FunctionBuilder & addFunctionAttribute(const llvm::Attribute::AttrKind attr)
Definition: FunctionTypes.h:1057
llvm::Value * fold(const std::vector< llvm::Value * > &args, llvm::LLVMContext &C) const override final
Definition: FunctionTypes.h:652
IRFunction(const std::string &symbol, const GeneratorCb &gen)
Definition: FunctionTypes.h:759
IRFunctionSRet(const std::string &symbol, const IRFunctionBase::GeneratorCb &gen)
Definition: FunctionTypes.h:786
FunctionBuilder(const char *name)
Definition: FunctionTypes.h:906
DeclPreferrence
Definition: FunctionTypes.h:879
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
Definition: FunctionTypes.h:357
void verifyResultType(const llvm::Type *result, const llvm::Type *expected) const
Definition: FunctionTypes.h:729
static std::string s()
Definition: FunctionTypes.h:146
Definition: Exceptions.h:13
void setRetAttributes(const std::vector< llvm::Attribute::AttrKind > &in)
Definition: FunctionTypes.h:435
FunctionBuilder & setPreferredImpl(DeclPreferrence pref)
Definition: FunctionTypes.h:1063
void setArgumentNames(std::vector< const char * > names)
Definition: FunctionTypes.h:426
todo
Definition: FunctionTypes.h:793
bool hasConstantFold() const
Definition: FunctionTypes.h:590
static void apply(const OpT &, const bool)
Definition: FunctionTypes.h:196
static std::string s()
Definition: FunctionTypes.h:135
void setFnAttributes(const std::vector< llvm::Attribute::AttrKind > &in)
Definition: FunctionTypes.h:431
FunctionBuilder & addSignature(const IRFunctionBase::GeneratorCb &cb, const Signature *ptr, const char *symbol=nullptr)
Definition: FunctionTypes.h:963
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:143
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
bool hasEmbedIR() const
Definition: FunctionTypes.h:698
FunctionBuilder & addParameterAttribute(const size_t idx, const llvm::Attribute::AttrKind attr)
Definition: FunctionTypes.h:1045
size_t size() const
The number of arguments that this function has.
Definition: FunctionTypes.h:383
static std::string s()
Definition: FunctionTypes.h:137
CFunction(const std::string &symbol, SignatureT *function)
Definition: FunctionTypes.h:627
Constant folding for C++ bindings.
Templated function traits which provides compile-time index access to the types of the function signa...
Definition: Types.h:280
static std::string s()
Definition: FunctionTypes.h:136
The base/abstract representation of an AX function. Derived classes must implement the Function::type...
Definition: FunctionTypes.h:267
const char * doc() const
Definition: FunctionTypes.h:860
Represents a concrete C function binding with the first argument as its return type.
Definition: FunctionTypes.h:772
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.
An extremely basic but native representation of a string class with SSO support. This exists to provi...
Definition: String.h:33
Utility code generation methods for performing various llvm operations.
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
SRetFunction(Args &&...ts)
Forward all arguments to the derived class.
Definition: FunctionTypes.h:575
bool isDefault() const
Definition: FunctionTypes.h:887
void llvmTypeToString(const llvm::Type *const type, std::string &str)
Prints an llvm type to a std string.
Definition: Utils.h:134
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
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
void setParamAttributes(const size_t i, const std::vector< llvm::Attribute::AttrKind > &in)
Definition: FunctionTypes.h:439
SignatureMatch
The result type from calls to Function::match.
Definition: FunctionTypes.h:357
virtual llvm::Value * fold(const std::vector< llvm::Value * > &, llvm::LLVMContext &) const
Definition: FunctionTypes.h:592
std::shared_ptr< Function > Ptr
Definition: FunctionTypes.h:269
static void apply(const OpT &op, const bool forwards)
Definition: FunctionTypes.h:180
static std::string s()
Definition: FunctionTypes.h:141
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
IRFunctionBase(const std::string &symbol, const GeneratorCb &gen, const size_t size)
Definition: FunctionTypes.h:740
void setConstantFold(bool on)
Definition: FunctionTypes.h:589
FunctionBuilder & addReturnAttribute(const llvm::Attribute::AttrKind attr)
Definition: FunctionTypes.h:1051
Definition: Exceptions.h:38