OpenVDB  12.1.0
ComputeGenerator.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/ComputeGenerator.h
5 ///
6 /// @authors Nick Avramoussis, Matt Warner, Francisco Gochez, Richard Jones
7 ///
8 /// @brief The core visitor framework for code generation
9 ///
10 
11 #ifndef OPENVDB_AX_COMPUTE_GENERATOR_HAS_BEEN_INCLUDED
12 #define OPENVDB_AX_COMPUTE_GENERATOR_HAS_BEEN_INCLUDED
13 
14 #include "FunctionRegistry.h"
15 #include "FunctionTypes.h"
16 #include "SymbolTable.h"
17 #include "Value.h"
18 
19 #include "../ast/AST.h"
20 #include "../ast/Visitor.h"
21 #include "../compiler/CompilerOptions.h"
22 #include "../compiler/Logger.h"
23 
24 #include <openvdb/version.h>
25 
26 #include <llvm/Analysis/TargetLibraryInfo.h>
27 #include <llvm/IR/BasicBlock.h>
28 #include <llvm/IR/Function.h>
29 #include <llvm/IR/IRBuilder.h>
30 #include <llvm/IR/LLVMContext.h>
31 #include <llvm/IR/Module.h>
32 
33 #include <stack>
34 
35 namespace openvdb {
37 namespace OPENVDB_VERSION_NAME {
38 
39 namespace ax {
40 namespace codegen {
41 
42 /// @brief The function definition and signature which is built by the
43 /// ComputeGenerator.
44 ///
45 /// The argument structure is as follows:
46 ///
47 /// 1) - A void pointer to the CustomData
48 ///
50 {
51  /// The name of the generated function
52  static const std::string Name;
53 
54  /// The signature of the generated function
55  using Signature = void(const void* const);
57  static const size_t N_ARGS = FunctionTraitsT::N_ARGS;
58 
59  /// The argument key names available during code generation
60  static const std::array<std::string, N_ARGS>& getArgumentKeys();
61  static std::string getDefaultName();
62 };
63 
64 
65 ///////////////////////////////////////////////////////////////////////////
66 ///////////////////////////////////////////////////////////////////////////
67 
68 namespace codegen_internal {
69 
70 /// @brief Visitor object which will generate llvm IR for a syntax tree. This
71 /// provides the majority of the code generation functionality except for
72 /// attribute access. This design allows for custom geometry to define their
73 /// IR implementations for these accesses by deriving and extending this
74 /// generator with ast::Attribute handling (see PointComputeGenerator.h and
75 /// VolumeComputeGenerator.h for examples).
76 /// @note The visit/traverse methods work slightly differently to the normal
77 /// Visitor to allow proper handling of errors and visitation history. Nodes
78 /// that inherit from ast::Expression can return false from visit() (and so
79 /// traverse()), but this will not necessarily stop traversal altogether.
80 /// Instead, any ast::Statements that are not also ast::Expressions i.e.
81 /// Block, ConditionalStatement, Loop, DeclareLocal, etc override their visit
82 /// and traverse methods to handle custom traversal order, and the catching
83 /// of failed child Expression visit/traverse calls. This allows errors in
84 /// independent Statements to not halt traversal for future Statements and so
85 /// allow capturing of multiple errors in an ast::Tree in a single call to
86 /// ComputeGenerator::generate().
87 struct OPENVDB_AX_API ComputeGenerator : public ast::Visitor<ComputeGenerator>
88 {
89  ComputeGenerator(llvm::Module& module,
90  const FunctionOptions& options,
91  FunctionRegistry& functionRegistry,
92  Logger& logger);
93 
94  virtual ~ComputeGenerator();
95 
96  bool generate(const ast::Tree&);
97 
98  inline SymbolTable<llvm::Value*>& globals() { return mSymbolTables.globals(); }
99  inline const SymbolTable<llvm::Value*>& globals() const { return mSymbolTables.globals(); }
100 
101  // Visitor pattern
102 
105 
106  /// @brief Code generation always runs post order
107  inline bool postOrderNodes() const { return true; }
108 
109  /// @brief Custom traversal of scoped blocks
110  /// @note This overrides the default traversal to incorporate
111  /// the scoping of variables declared in this block
112  bool traverse(const ast::Block* block)
113  {
114  if (!block) return true;
115  if (!this->visit(block)) return false;
116  return true;
117  }
118 
119  /// @brief Custom traversal of comma expression
120  /// @note This overrides the default traversal to handle errors
121  /// without stopping generation of entire list
122  /// @todo Replace with a binary operator that simply returns the second value
123  bool traverse(const ast::CommaOperator* comma)
124  {
125  if (!comma) return true;
126  if (!this->visit(comma)) return false;
127  return true;
128  }
129 
130 
131  /// @brief Custom traversal of conditional statements
132  /// @note This overrides the default traversal to handle
133  /// branching between different code paths
135  {
136  if (!cond) return true;
137  if (!this->visit(cond)) return false;
138  return true;
139  }
140 
141  /// @brief Custom traversal of binary operators
142  /// @note This overrides the default traversal to handle
143  /// short-circuiting in logical AND and OR
144  bool traverse(const ast::BinaryOperator* bin)
145  {
146  if (!bin) return true;
147  if (!this->visit(bin)) return false;
148  return true;
149  }
150 
151  /// @brief Custom traversal of ternary operators
152  /// @note This overrides the default traversal to handle
153  /// branching between different code paths
154  bool traverse(const ast::TernaryOperator* tern)
155  {
156  if (!tern) return true;
157  if (!this->visit(tern)) return false;
158  return true;
159  }
160 
161  /// @brief Custom traversal of loops
162  /// @note This overrides the default traversal to handle
163  /// branching between different code paths and the
164  /// scoping of variables in for-loop initialisation
165  bool traverse(const ast::Loop* loop)
166  {
167  if (!loop) return true;
168  if (!this->visit(loop)) return false;
169  return true;
170  }
171 
172  /// @brief Custom traversal of declarations
173  /// @note This overrides the default traversal to
174  /// handle traversal of the local and
175  /// assignment of initialiser, if it exists
176  bool traverse(const ast::DeclareLocal* decl)
177  {
178  if (!decl) return true;
179  if (!this->visit(decl)) return false;
180  return true;
181  }
182 
183  ///@{
184  /// @brief Visitor methods for all AST nodes which implement IR generation
185  virtual bool visit(const ast::CommaOperator*);
186  virtual bool visit(const ast::AssignExpression*);
187  virtual bool visit(const ast::Crement*);
188  virtual bool visit(const ast::FunctionCall*);
189  virtual bool visit(const ast::Attribute*);
190  virtual bool visit(const ast::Tree*);
191  virtual bool visit(const ast::Block*);
192  virtual bool visit(const ast::ConditionalStatement*);
193  virtual bool visit(const ast::Loop*);
194  virtual bool visit(const ast::Keyword*);
195  virtual bool visit(const ast::UnaryOperator*);
196  virtual bool visit(const ast::BinaryOperator*);
197  virtual bool visit(const ast::TernaryOperator*);
198  virtual bool visit(const ast::Cast*);
199  virtual bool visit(const ast::DeclareLocal*);
200  virtual bool visit(const ast::Local*);
201  virtual bool visit(const ast::ExternalVariable*);
202  virtual bool visit(const ast::ArrayUnpack*);
203  virtual bool visit(const ast::ArrayPack*);
204  virtual bool visit(const ast::Value<bool>*);
205  virtual bool visit(const ast::Value<int16_t>*);
206  virtual bool visit(const ast::Value<int32_t>*);
207  virtual bool visit(const ast::Value<int64_t>*);
208  virtual bool visit(const ast::Value<float>*);
209  virtual bool visit(const ast::Value<double>*);
210  virtual bool visit(const ast::Value<std::string>*);
211 
212  template <typename ValueType>
213  typename std::enable_if<std::is_integral<ValueType>::value, bool>::type
214  visit(const ast::Value<ValueType>* node);
215  template <typename ValueType>
216 
217  typename std::enable_if<std::is_floating_point<ValueType>::value, bool>::type
218  visit(const ast::Value<ValueType>* node);
219  ///@}
220 
221 protected:
222  const FunctionGroup* getFunction(const std::string& identifier,
223  const bool allowInternal = false);
224 
225  /// @brief Clear any strings which were allocated in a given function.
226  /// This method accepts an IRBuilder which is expected to be attached to
227  /// a valid block/function. For each block in the function with a return
228  /// instruction, this function calls the appropriate memory methods to
229  /// deallocate any strings (which are alloced in the function prologue).
230  void createFreeSymbolStrings(llvm::IRBuilder<>&);
231 
232  llvm::Module& mModule;
233  llvm::LLVMContext& mContext;
234  llvm::IRBuilder<> mBuilder;
235 
236  // The stack of accessed values and their underlying types
237  std::stack<Value> mValues;
238 
239  // The stack of blocks for keyword branching
240  std::stack<std::pair<llvm::BasicBlock*, llvm::BasicBlock*>> mBreakContinueStack;
241 
242  // The current scope number used to track scoped declarations
243  size_t mScopeIndex;
244 
245  // The map of scope number to local variable names to values
247 
248  // The function used as the base code block
249  llvm::Function* mFunction;
250 
252 
254 
255 private:
256  FunctionRegistry& mFunctionRegistry;
257 };
258 
259 } // codegen_internal
260 
261 } // namespace codegen
262 } // namespace ax
263 } // namespace OPENVDB_VERSION_NAME
264 } // namespace openvdb
265 
266 #endif // OPENVDB_AX_COMPUTE_GENERATOR_HAS_BEEN_INCLUDED
267 
ConditionalStatements represents all combinations of &#39;if&#39;, &#39;else&#39; and &#39;else if&#39; syntax and semantics...
Definition: AST.h:864
Attributes represent any access to a primitive value, typically associated with the &#39;@&#39; symbol syntax...
Definition: AST.h:1874
A TernaryOperator represents a ternary (conditional) expression &#39;a ? b : c&#39; which evaluates to &#39;b&#39; if...
Definition: AST.h:1092
const FunctionOptions mOptions
Definition: ComputeGenerator.h:251
A BinaryOperator represents a single binary operation between a left hand side (LHS) and right hand s...
Definition: AST.h:988
size_t mScopeIndex
Definition: ComputeGenerator.h:243
ExternalVariable represent any access to external (custom) data, typically associated with the &#39;$&#39; sy...
Definition: AST.h:2002
bool traverse(const ast::TernaryOperator *tern)
Custom traversal of ternary operators.
Definition: ComputeGenerator.h:154
#define OPENVDB_AX_API
Definition: Platform.h:312
Options that control how functions behave.
Definition: CompilerOptions.h:24
DeclareLocal AST nodes symbolize a single type declaration of a local variable. These store the local...
Definition: AST.h:2139
A Tree is the highest concrete (non-abstract) node in the entire AX AST hierarchy. It represents an entire conversion of a valid AX string.
Definition: AST.h:562
llvm::Function * mFunction
Definition: ComputeGenerator.h:249
ArrayUnpack represent indexing operations into AX container types, primarily vectors and matrices ind...
Definition: AST.h:1686
ArrayPacks represent temporary container creations of arbitrary sizes, typically generated through th...
Definition: AST.h:1785
bool traverse(const ast::Loop *loop)
Custom traversal of loops.
Definition: ComputeGenerator.h:165
A map of unique ids to symbol tables which can be used to represent local variables within a program...
Definition: SymbolTable.h:115
The function definition and signature which is built by the ComputeGenerator.
Definition: ComputeGenerator.h:49
Contains frameworks for creating custom AX functions which can be registered within the FunctionRegis...
const SymbolTable< llvm::Value * > & globals() const
Definition: ComputeGenerator.h:99
Keywords represent keyword statements defining changes in execution. These include those that define ...
Definition: AST.h:1641
static const std::string Name
The name of the generated function.
Definition: ComputeGenerator.h:52
Contains the global function registration definition which described all available user front end fun...
bool traverse(const ast::CommaOperator *comma)
Custom traversal of comma expression.
Definition: ComputeGenerator.h:123
A Crement node represents a single increment &#39;++&#39; and decrement &#39;–&#39; operation. As well as it&#39;s creme...
Definition: AST.h:1294
A group of functions which all have the same name but different signatures. For example: float abs(fl...
Definition: FunctionTypes.h:1389
llvm::Module & mModule
Definition: ComputeGenerator.h:232
A UnaryOperator represents a single unary operation on an expression. The operation type is stored as...
Definition: AST.h:1389
bool traverse(const ast::DeclareLocal *decl)
Custom traversal of declarations.
Definition: ComputeGenerator.h:176
Loops represent for, while and do-while loop constructs. These all consist of a condition - evaluated...
Definition: AST.h:708
void(const void *const) Signature
The signature of the generated function.
Definition: ComputeGenerator.h:55
Definition: Exceptions.h:13
Specialization of Values for strings.
Definition: AST.h:2335
std::stack< std::pair< llvm::BasicBlock *, llvm::BasicBlock * > > mBreakContinueStack
Definition: ComputeGenerator.h:240
The function registry which is used for function code generation. Each time a function is visited wit...
Definition: FunctionRegistry.h:39
Contains the symbol table which holds mappings of variables names to llvm::Values.
Cast nodes represent the conversion of an underlying expression to a target type. Cast nodes are typi...
Definition: AST.h:1464
bool postOrderNodes() const
Code generation always runs post order.
Definition: ComputeGenerator.h:107
A Block node represents a scoped list of statements. It may comprise of 0 or more statements...
Definition: AST.h:476
bool traverse(const ast::Block *block)
Custom traversal of scoped blocks.
Definition: ComputeGenerator.h:112
Logger for collecting errors and warnings that occur during AX compilation.
Definition: Logger.h:57
A Value (literal) AST node holds either literal text or absolute value information on all numerical...
Definition: AST.h:2253
FunctionCalls represent a single call to a function and any provided arguments. The argument list can...
Definition: AST.h:1541
Intermediate representation of supported AX values.
SymbolTableBlocks mSymbolTables
Definition: ComputeGenerator.h:246
Local AST nodes represent a single accesses to a local variable. The only store the name of the varia...
Definition: AST.h:2112
Logger & mLog
Definition: ComputeGenerator.h:253
SymbolTable< llvm::Value * > & globals()
Definition: ComputeGenerator.h:98
The Visitor class uses the Curiously Recursive Template Pattern (CRTP) to provide a customizable inte...
Definition: Visitor.h:95
bool traverse(const ast::BinaryOperator *bin)
Custom traversal of binary operators.
Definition: ComputeGenerator.h:144
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
bool traverse(const ast::ConditionalStatement *cond)
Custom traversal of conditional statements.
Definition: ComputeGenerator.h:134
llvm::LLVMContext & mContext
Definition: ComputeGenerator.h:233
std::stack< Value > mValues
Definition: ComputeGenerator.h:237
Templated function traits which provides compile-time index access to the types of the function signa...
Definition: Types.h:311
AssignExpressions represents a similar object construction to a BinaryOperator. AssignExpressions can...
Definition: AST.h:1198
A symbol table which can be used to represent a single scoped set of a programs variables. This is simply an unordered map of strings to llvm::Values.
Definition: SymbolTable.h:37
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
Visitor object which will generate llvm IR for a syntax tree. This provides the majority of the code ...
Definition: ComputeGenerator.h:87
llvm::IRBuilder mBuilder
Definition: ComputeGenerator.h:234