GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/codegen/ComputeGenerator.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 9 9 100.0%
Functions: 1 1 100.0%
Branches: 24 30 80.0%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-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
18 #include "../ast/AST.h"
19 #include "../ast/Visitor.h"
20 #include "../compiler/CompilerOptions.h"
21 #include "../compiler/Logger.h"
22
23 #include <openvdb/version.h>
24
25 #include <llvm/Analysis/TargetLibraryInfo.h>
26 #include <llvm/IR/BasicBlock.h>
27 #include <llvm/IR/Function.h>
28 #include <llvm/IR/IRBuilder.h>
29 #include <llvm/IR/LLVMContext.h>
30 #include <llvm/IR/Module.h>
31
32 #include <stack>
33
34 namespace openvdb {
35 OPENVDB_USE_VERSION_NAMESPACE
36 namespace OPENVDB_VERSION_NAME {
37
38 namespace ax {
39 namespace codegen {
40
41 /// @brief The function definition and signature which is built by the
42 /// ComputeGenerator.
43 ///
44 /// The argument structure is as follows:
45 ///
46 /// 1) - A void pointer to the CustomData
47 ///
48 struct ComputeKernel
49 {
50 /// The name of the generated function
51 static const std::string Name;
52
53 /// The signature of the generated function
54 using Signature = void(const void* const);
55 using FunctionTraitsT = codegen::FunctionTraits<Signature>;
56 static const size_t N_ARGS = FunctionTraitsT::N_ARGS;
57
58 /// The argument key names available during code generation
59 static const std::array<std::string, N_ARGS>& getArgumentKeys();
60 static std::string getDefaultName();
61 };
62
63
64 ///////////////////////////////////////////////////////////////////////////
65 ///////////////////////////////////////////////////////////////////////////
66
67 namespace codegen_internal {
68
69 /// @brief Visitor object which will generate llvm IR for a syntax tree. This
70 /// provides the majority of the code generation functionality except for
71 /// attribute access. This design allows for custom geometry to define their
72 /// IR implementations for these accesses by deriving and extending this
73 /// generator with ast::Attribute handling (see PointComputeGenerator.h and
74 /// VolumeComputeGenerator.h for examples).
75 /// @note The visit/traverse methods work slightly differently to the normal
76 /// Visitor to allow proper handling of errors and visitation history. Nodes
77 /// that inherit from ast::Expression can return false from visit() (and so
78 /// traverse()), but this will not necessarily stop traversal altogether.
79 /// Instead, any ast::Statements that are not also ast::Expressions i.e.
80 /// Block, ConditionalStatement, Loop, DeclareLocal, etc override their visit
81 /// and traverse methods to handle custom traversal order, and the catching
82 /// of failed child Expression visit/traverse calls. This allows errors in
83 /// independent Statements to not halt traversal for future Statements and so
84 /// allow capturing of multiple errors in an ast::Tree in a single call to
85 /// ComputeGenerator::generate().
86 struct OPENVDB_AX_API ComputeGenerator : public ast::Visitor<ComputeGenerator>
87 {
88 ComputeGenerator(llvm::Module& module,
89 const FunctionOptions& options,
90 FunctionRegistry& functionRegistry,
91 Logger& logger);
92
93 3632 virtual ~ComputeGenerator() = default;
94
95 bool generate(const ast::Tree&);
96
97 inline SymbolTable& globals() { return mSymbolTables.globals(); }
98 inline const SymbolTable& globals() const { return mSymbolTables.globals(); }
99
100 // Visitor pattern
101
102 using ast::Visitor<ComputeGenerator>::traverse;
103 using ast::Visitor<ComputeGenerator>::visit;
104
105 /// @brief Code generation always runs post order
106 inline bool postOrderNodes() const { return true; }
107
108 /// @brief Custom traversal of scoped blocks
109 /// @note This overrides the default traversal to incorporate
110 /// the scoping of variables declared in this block
111 bool traverse(const ast::Block* block)
112 {
113
4/8
✓ Branch 0 taken 1816 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 50 times.
✗ Branch 7 not taken.
2226 if (!block) return true;
114
8/10
✓ Branch 1 taken 1526 times.
✓ Branch 2 taken 281 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 168 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 200 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 159 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 50 times.
2395 if (!this->visit(block)) return false;
115 return true;
116 }
117
118 /// @brief Custom traversal of comma expression
119 /// @note This overrides the default traversal to handle errors
120 /// without stopping generation of entire list
121 /// @todo Replace with a binary operator that simply returns the second value
122 bool traverse(const ast::CommaOperator* comma)
123 {
124 if (!comma) return true;
125
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 176 times.
178 if (!this->visit(comma)) return false;
126 return true;
127 }
128
129
130 /// @brief Custom traversal of conditional statements
131 /// @note This overrides the default traversal to handle
132 /// branching between different code paths
133 bool traverse(const ast::ConditionalStatement* cond)
134 {
135 if (!cond) return true;
136
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 159 times.
173 if (!this->visit(cond)) return false;
137 return true;
138 }
139
140 /// @brief Custom traversal of binary operators
141 /// @note This overrides the default traversal to handle
142 /// short-circuiting in logical AND and OR
143 bool traverse(const ast::BinaryOperator* bin)
144 {
145 if (!bin) return true;
146
2/2
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 1719 times.
1844 if (!this->visit(bin)) return false;
147 return true;
148 }
149
150 /// @brief Custom traversal of ternary operators
151 /// @note This overrides the default traversal to handle
152 /// branching between different code paths
153 bool traverse(const ast::TernaryOperator* tern)
154 {
155 if (!tern) return true;
156
2/2
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 151 times.
184 if (!this->visit(tern)) return false;
157 return true;
158 }
159
160 /// @brief Custom traversal of loops
161 /// @note This overrides the default traversal to handle
162 /// branching between different code paths and the
163 /// scoping of variables in for-loop initialisation
164 bool traverse(const ast::Loop* loop)
165 {
166 if (!loop) return true;
167
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 164 times.
200 if (!this->visit(loop)) return false;
168 return true;
169 }
170
171 /// @brief Custom traversal of declarations
172 /// @note This overrides the default traversal to
173 /// handle traversal of the local and
174 /// assignment of initialiser, if it exists
175 bool traverse(const ast::DeclareLocal* decl)
176 {
177 if (!decl) return true;
178
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 3577 times.
3587 if (!this->visit(decl)) return false;
179 return true;
180 }
181
182 ///@{
183 /// @brief Visitor methods for all AST nodes which implement IR generation
184 virtual bool visit(const ast::CommaOperator*);
185 virtual bool visit(const ast::AssignExpression*);
186 virtual bool visit(const ast::Crement*);
187 virtual bool visit(const ast::FunctionCall*);
188 virtual bool visit(const ast::Attribute*);
189 virtual bool visit(const ast::Tree*);
190 virtual bool visit(const ast::Block*);
191 virtual bool visit(const ast::ConditionalStatement*);
192 virtual bool visit(const ast::Loop*);
193 virtual bool visit(const ast::Keyword*);
194 virtual bool visit(const ast::UnaryOperator*);
195 virtual bool visit(const ast::BinaryOperator*);
196 virtual bool visit(const ast::TernaryOperator*);
197 virtual bool visit(const ast::Cast*);
198 virtual bool visit(const ast::DeclareLocal*);
199 virtual bool visit(const ast::Local*);
200 virtual bool visit(const ast::ExternalVariable*);
201 virtual bool visit(const ast::ArrayUnpack*);
202 virtual bool visit(const ast::ArrayPack*);
203 virtual bool visit(const ast::Value<bool>*);
204 virtual bool visit(const ast::Value<int16_t>*);
205 virtual bool visit(const ast::Value<int32_t>*);
206 virtual bool visit(const ast::Value<int64_t>*);
207 virtual bool visit(const ast::Value<float>*);
208 virtual bool visit(const ast::Value<double>*);
209 virtual bool visit(const ast::Value<std::string>*);
210
211 template <typename ValueType>
212 typename std::enable_if<std::is_integral<ValueType>::value, bool>::type
213 visit(const ast::Value<ValueType>* node);
214 template <typename ValueType>
215
216 typename std::enable_if<std::is_floating_point<ValueType>::value, bool>::type
217 visit(const ast::Value<ValueType>* node);
218 ///@}
219
220 protected:
221
222 const FunctionGroup* getFunction(const std::string& identifier,
223 const bool allowInternal = false);
224
225 bool binaryExpression(llvm::Value*& result, llvm::Value* lhs, llvm::Value* rhs,
226 const ast::tokens::OperatorToken op, const ast::Node* node);
227 bool assignExpression(llvm::Value* lhs, llvm::Value*& rhs, const ast::Node* node);
228
229 /// @brief Clear any strings which were allocated in a given function.
230 /// This method accepts an IRBuilder which is expected to be attached to
231 /// a valid block/function. For each block in the function with a return
232 /// instruction, this function calls the appropriate memory methods to
233 /// deallocate any strings (which are alloced in the function prologue).
234 void createFreeSymbolStrings(llvm::IRBuilder<>&);
235
236 llvm::Module& mModule;
237 llvm::LLVMContext& mContext;
238 llvm::IRBuilder<> mBuilder;
239
240 // The stack of accessed values
241 std::stack<llvm::Value*> mValues;
242
243 // The stack of blocks for keyword branching
244 std::stack<std::pair<llvm::BasicBlock*, llvm::BasicBlock*>> mBreakContinueStack;
245
246 // The current scope number used to track scoped declarations
247 size_t mScopeIndex;
248
249 // The map of scope number to local variable names to values
250 SymbolTableBlocks mSymbolTables;
251
252 // The function used as the base code block
253 llvm::Function* mFunction;
254
255 const FunctionOptions mOptions;
256
257 Logger& mLog;
258
259 private:
260 FunctionRegistry& mFunctionRegistry;
261 };
262
263 } // codegen_internal
264
265 } // namespace codegen
266 } // namespace ax
267 } // namespace OPENVDB_VERSION_NAME
268 } // namespace openvdb
269
270 #endif // OPENVDB_AX_COMPUTE_GENERATOR_HAS_BEEN_INCLUDED
271
272