GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/ast/Scanners.cc
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 174 201 86.6%
Functions: 18 21 85.7%
Branches: 227 348 65.2%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file ast/Scanners.cc
5
6 #include "Scanners.h"
7 #include "Visitor.h"
8
9 #include <string>
10 #include <map>
11
12 namespace openvdb {
13 OPENVDB_USE_VERSION_NAMESPACE
14 namespace OPENVDB_VERSION_NAME {
15
16 namespace ax {
17 namespace ast {
18
19 namespace {
20
21 template <typename NodeT, typename OpT>
22 struct VariableDependencyVisitor :
23 public ast::VisitNodeType<NodeT, OpT,
24 VariableDependencyVisitor<NodeT, OpT>>
25 {
26 using BaseT = ast::VisitNodeType<NodeT, OpT,
27 VariableDependencyVisitor<NodeT, OpT>>;
28 using BaseT::traverse;
29 using BaseT::visit;
30
31 VariableDependencyVisitor(const OpT& op) : BaseT(op) {}
32 ~VariableDependencyVisitor() = default;
33
34 5373 bool traverse(const ast::Loop* loop)
35 {
36
1/2
✓ Branch 0 taken 5373 times.
✗ Branch 1 not taken.
5373 if (!loop) return true;
37
2/2
✓ Branch 1 taken 5367 times.
✓ Branch 2 taken 6 times.
5373 if (!this->traverse(loop->initial())) return false;
38
2/2
✓ Branch 1 taken 4847 times.
✓ Branch 2 taken 520 times.
5367 if (!this->traverse(loop->condition())) return false;
39
2/2
✓ Branch 1 taken 4837 times.
✓ Branch 2 taken 10 times.
4847 if (!this->traverse(loop->iteration())) return false;
40
2/2
✓ Branch 0 taken 753 times.
✓ Branch 1 taken 4084 times.
4837 if (!this->traverse(loop->body())) return false;
41 if (!this->visit(loop)) return false;
42 return true;
43 }
44 };
45
46 /// @brief For a given variable at a particular position in an AST, find all
47 /// attributes, locals and external variables which it depends on (i.e. any
48 /// Attribute, Local or ExternalVariable AST nodes which impacts the given
49 /// variables value) by recursively traversing through all connected paths.
50 /// This includes both direct and indirect influences; for example, a direct
51 /// assignment "@b = @a;" and an indirect code branch "if (@a) @b = 1";
52 /// @note This is position dependent in regards to the given variables location.
53 /// Any code which writes to this variable after the given usage will not be
54 /// cataloged in the output dependency vector.
55 /// @warning This does not currently handle scoped local variable re-declarations
56 /// and instead will end up adding matching names as extra dependencies
57 /// @todo: fix this for scoped variables, capturing of all instances, and not adding
58 /// dependencies between different branches of conditionals
59 19309 void variableDependencies(const ast::Variable& var,
60 std::vector<const ast::Variable*>& dependencies)
61 {
62 // external variables are read-only i.e. have no dependencies
63
2/2
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 19232 times.
19309 if (var.nodetype() == ast::Node::ExternalVariableNode) return;
64
65 // Get the root node
66 const ast::Node* root = &var;
67
2/2
✓ Branch 0 taken 69553 times.
✓ Branch 1 taken 19232 times.
88785 while (const ast::Node* parent = root->parent()) {
68 root = parent;
69 }
70
71 // collect all occurrences of this var up to and including
72 // it's current usage, terminating traversal afterwards
73 const bool attributeVisit =
74
1/2
✓ Branch 2 taken 19232 times.
✗ Branch 3 not taken.
19232 (var.nodetype() == ast::Node::AttributeNode);
75
76 std::vector<const ast::Variable*> usage;
77
78 auto collect =
79 338127 [&var, &usage, attributeVisit]
80
2/2
✓ Branch 0 taken 30583 times.
✓ Branch 1 taken 82719 times.
113302 (const ast::Variable& use) -> bool
81 {
82
2/2
✓ Branch 0 taken 190052 times.
✓ Branch 1 taken 148075 times.
338127 if (attributeVisit) {
83
2/2
✓ Branch 1 taken 132633 times.
✓ Branch 2 taken 57419 times.
190052 if (use.nodetype() != ast::Node::AttributeNode) return true;
84 132633 const auto& attrib = static_cast<const ast::Attribute&>(var);
85 const auto& useAttrib = static_cast<const ast::Attribute&>(use);
86
2/2
✓ Branch 1 taken 20272 times.
✓ Branch 2 taken 112361 times.
132633 if (attrib.tokenname() != useAttrib.tokenname()) return true;
87 }
88 else {
89
2/2
✓ Branch 1 taken 113302 times.
✓ Branch 2 taken 34773 times.
148075 if (use.nodetype() != ast::Node::LocalNode) return true;
90
2/2
✓ Branch 0 taken 30583 times.
✓ Branch 1 taken 82719 times.
113302 if (use.name() != var.name()) return true;
91 }
92 50855 usage.emplace_back(&use);
93 50855 return &use != &var;
94
1/2
✓ Branch 1 taken 19232 times.
✗ Branch 2 not taken.
19232 };
95
96 VariableDependencyVisitor<ast::Variable, decltype(collect)>
97 depVisitor(collect);
98
1/2
✓ Branch 1 taken 19232 times.
✗ Branch 2 not taken.
19232 depVisitor.traverse(root);
99
100 // The list of nodes which can be considered dependencies to collect
101 using ListT = openvdb::TypeList<
102 ast::Attribute,
103 ast::Local,
104 ast::ExternalVariable>;
105
106 // small lambda to check to see if a dep is already being tracked
107 30927 auto hasDep = [&](const ast::Variable* dep) -> bool {
108 30927 return (std::find(dependencies.cbegin(), dependencies.cend(), dep) !=
109 30927 dependencies.cend());
110 19232 };
111 // recursively traverse all usages and resolve dependencies
112
2/2
✓ Branch 0 taken 50855 times.
✓ Branch 1 taken 19232 times.
70087 for (const auto& use : usage)
113 {
114 50855 const ast::Node* child = use;
115 // track writable for conditionals
116 bool written = false;
117
2/2
✓ Branch 0 taken 215360 times.
✓ Branch 1 taken 50855 times.
266215 while (const ast::Node* parent = child->parent()) {
118
1/2
✓ Branch 1 taken 215360 times.
✗ Branch 2 not taken.
215360 const ast::Node::NodeType type = parent->nodetype();
119
2/2
✓ Branch 0 taken 3885 times.
✓ Branch 1 taken 211475 times.
215360 if (type == ast::Node::CrementNode) {
120 written = true;
121
2/2
✓ Branch 1 taken 2617 times.
✓ Branch 2 taken 1268 times.
3885 if (!hasDep(use)) {
122
1/2
✓ Branch 1 taken 1268 times.
✗ Branch 2 not taken.
1268 dependencies.emplace_back(use);
123 }
124 }
125
2/2
✓ Branch 0 taken 1454 times.
✓ Branch 1 taken 210021 times.
211475 else if (type == ast::Node::ConditionalStatementNode) {
126 const ast::ConditionalStatement* conditional =
127 static_cast<const ast::ConditionalStatement*>(parent);
128 const ast::Expression* condition = conditional->condition();
129 // traverse down and collect variables
130
2/2
✓ Branch 0 taken 1229 times.
✓ Branch 1 taken 225 times.
1454 if (child != condition){
131 std::vector<const ast::Variable*> vars;
132
1/2
✓ Branch 1 taken 225 times.
✗ Branch 2 not taken.
225 collectNodeTypes<ListT>(*condition, vars);
133 // find next deps
134
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 225 times.
371 for (const ast::Variable* dep : vars) {
135 // don't add this dep if it's not being written to. Unlike
136 // all other visits, the conditionals dictate program flow.
137 // Values in the conditional expression only link to the
138 // current usage if the current usage is being modified
139
4/4
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 52 times.
✓ Branch 3 taken 37 times.
✓ Branch 4 taken 57 times.
146 if (!written || hasDep(dep)) continue;
140
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 dependencies.emplace_back(dep);
141
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 variableDependencies(*dep, dependencies);
142 }
143 }
144 }
145
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 209786 times.
210021 else if (type == ast::Node::TernaryOperatorNode) {
146 const ast::TernaryOperator* ternary =
147 static_cast<const ast::TernaryOperator*>(parent);
148 const ast::Expression* condition = ternary->condition();
149 // traverse down and collect variables
150
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 108 times.
235 if (child != condition) {
151 std::vector<const ast::Variable*> vars;
152
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
108 collectNodeTypes<ListT>(*condition, vars);
153 // find next deps
154
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 108 times.
184 for (const ast::Variable* dep : vars) {
155 // don't add this dep if it's not being written to. Unlike
156 // all other visits, the conditionals dictate program flow.
157 // Values in the conditional expression only link to the
158 // current usage if the current usage is being modified
159
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 69 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 2 times.
76 if (!written || hasDep(dep)) continue;
160
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 dependencies.emplace_back(dep);
161
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 variableDependencies(*dep, dependencies);
162 }
163 }
164 }
165
2/2
✓ Branch 0 taken 14404 times.
✓ Branch 1 taken 195382 times.
209786 else if (type == ast::Node::LoopNode) {
166 const ast::Loop* loop =
167 static_cast<const ast::Loop*>(parent);
168 const ast::Statement* condition = loop->condition();
169 // traverse down and collect variables
170
2/2
✓ Branch 0 taken 2495 times.
✓ Branch 1 taken 11909 times.
14404 if (child != condition) {
171 std::vector<const ast::Variable*> vars;
172 // if the condition is a comma operator the last element determines flow
173
3/4
✓ Branch 1 taken 11909 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 116 times.
✓ Branch 4 taken 11793 times.
11909 if (condition->nodetype() == ast::Node::NodeType::CommaOperatorNode) {
174 const ast::CommaOperator*
175 comma = static_cast<const ast::CommaOperator*>(condition);
176
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 if (!comma->empty()) {
177
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 const ast::Expression* lastExpression = comma->child(comma->size()-1);
178
1/2
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
116 collectNodeTypes<ListT>(*lastExpression, vars);
179 }
180 }
181 else {
182 collectNodeTypes<ListT>(*condition, vars);
183 }
184 // find next deps
185
2/2
✓ Branch 0 taken 10152 times.
✓ Branch 1 taken 11909 times.
22061 for (const ast::Variable* dep : vars) {
186 // don't add this dep if it's not being written to. Unlike
187 // all other visits, the conditionals dictate program flow.
188 // Values in the conditional expression only link to the
189 // current usage if the current usage is being modified
190
4/4
✓ Branch 0 taken 6801 times.
✓ Branch 1 taken 3351 times.
✓ Branch 3 taken 493 times.
✓ Branch 4 taken 6308 times.
10152 if (!written || hasDep(dep)) continue;
191
1/2
✓ Branch 1 taken 493 times.
✗ Branch 2 not taken.
493 dependencies.emplace_back(dep);
192
1/2
✓ Branch 1 taken 493 times.
✗ Branch 2 not taken.
493 variableDependencies(*dep, dependencies);
193 }
194 }
195
196 }
197
2/2
✓ Branch 0 taken 35475 times.
✓ Branch 1 taken 159907 times.
195382 else if (type == ast::Node::AssignExpressionNode) {
198 const ast::AssignExpression* assignment =
199 static_cast<const ast::AssignExpression*>(parent);
200
2/2
✓ Branch 0 taken 18131 times.
✓ Branch 1 taken 17344 times.
35475 if (assignment->lhs() == child) {
201 written = true;
202 // add self dependency if compound
203
2/2
✓ Branch 0 taken 1616 times.
✓ Branch 1 taken 15728 times.
17344 if (assignment->isCompound()) {
204
2/2
✓ Branch 1 taken 1592 times.
✓ Branch 2 taken 24 times.
1616 if (!hasDep(use)) {
205
1/2
✓ Branch 1 taken 1592 times.
✗ Branch 2 not taken.
1592 dependencies.emplace_back(use);
206 }
207 }
208 // traverse down and collect variables
209 std::vector<const ast::Variable*> vars;
210
1/2
✓ Branch 1 taken 17344 times.
✗ Branch 2 not taken.
17344 collectNodeTypes<ListT>(*assignment->rhs(), vars);
211 // find next deps
212
2/2
✓ Branch 0 taken 12475 times.
✓ Branch 1 taken 17344 times.
29819 for (const ast::Variable* dep : vars) {
213
2/2
✓ Branch 1 taken 5351 times.
✓ Branch 2 taken 7124 times.
12475 if (hasDep(dep)) continue;
214
1/2
✓ Branch 1 taken 7124 times.
✗ Branch 2 not taken.
7124 dependencies.emplace_back(dep);
215
1/2
✓ Branch 1 taken 7124 times.
✗ Branch 2 not taken.
7124 variableDependencies(*dep, dependencies);
216 }
217 }
218 }
219
2/2
✓ Branch 0 taken 9258 times.
✓ Branch 1 taken 150649 times.
159907 else if (type == ast::Node::DeclareLocalNode) {
220 const ast::DeclareLocal* declareLocal =
221 static_cast<const ast::DeclareLocal*>(parent);
222
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 9114 times.
✓ Branch 2 taken 331 times.
✓ Branch 3 taken 8783 times.
9258 if (declareLocal->local() == child && declareLocal->hasInit()) {
223 std::vector<const ast::Variable*> vars;
224 written = true;
225 // traverse down and collect variables
226
1/2
✓ Branch 1 taken 8783 times.
✗ Branch 2 not taken.
8783 collectNodeTypes<ListT>(*declareLocal->init(), vars);
227
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 8783 times.
8861 for (const ast::Variable* dep : vars) {
228
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 75 times.
78 if (hasDep(dep)) continue;
229
1/2
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
75 dependencies.emplace_back(dep);
230
1/2
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
75 variableDependencies(*dep, dependencies);
231 }
232 }
233 }
234
2/2
✓ Branch 0 taken 145782 times.
✓ Branch 1 taken 4867 times.
150649 else if (type == ast::Node::FunctionCallNode) {
235 written = true;
236 // @todo We currently can't detect if attributes are being passed by
237 // pointer and being modified automatically. We have to link this
238 // attribute to any other attribute passes into the function
239 const ast::FunctionCall* call =
240 static_cast<const ast::FunctionCall*>(parent);
241 // traverse down and collect variables
242 std::vector<const ast::Variable*> vars;
243
2/2
✓ Branch 0 taken 6614 times.
✓ Branch 1 taken 4867 times.
11481 for (size_t i = 0; i < call->children(); ++i) {
244
1/2
✓ Branch 1 taken 6614 times.
✗ Branch 2 not taken.
6614 collectNodeTypes<ListT>(*call->child(i), vars);
245 }
246 // only append dependencies here if they haven't already been visited
247 // due to recursion issues
248
2/2
✓ Branch 0 taken 5971 times.
✓ Branch 1 taken 4867 times.
10838 for (const ast::Variable* dep : vars) {
249 // make sure the dep doesn't already exist in the container, otherwise
250 // we can get into issues where functions with multiple arguments
251 // constantly try to check themselves
252 // @note should be removed with function refactoring
253
2/2
✓ Branch 1 taken 4628 times.
✓ Branch 2 taken 1343 times.
5971 if (hasDep(dep)) continue;
254
1/2
✓ Branch 1 taken 1343 times.
✗ Branch 2 not taken.
1343 dependencies.emplace_back(dep);
255
1/2
✓ Branch 1 taken 1343 times.
✗ Branch 2 not taken.
1343 variableDependencies(*dep, dependencies);
256 }
257 }
258 child = parent;
259 }
260 }
261 }
262
263
264 } // anonymous namespace
265
266 bool usesAttribute(const ast::Node& node,
267 const std::string& name,
268 const tokens::CoreType type)
269 {
270 bool found = false;
271 visitNodeType<ast::Attribute>(node,
272 [&](const ast::Attribute& attrib) -> bool {
273 assert(!found);
274 if (type != tokens::UNKNOWN) {
275 if (attrib.type() != type) return true;
276 }
277 if (attrib.name() != name) return true;
278 found = true;
279 return false;
280 });
281
282 return found;
283 }
284
285 bool writesToAttribute(const ast::Node& node,
286 const std::string& name,
287 const tokens::CoreType type)
288 {
289 std::vector<const ast::Variable*> vars;
290 catalogueVariables(node, nullptr, &vars, &vars, false, true);
291
292 // See if any attributes in the result vec match the given name/type
293 for (const ast::Variable* var : vars) {
294 assert(var->isType<ast::Attribute>());
295 const ast::Attribute* attrib = static_cast<const ast::Attribute*>(var);
296 if (type != tokens::UNKNOWN) {
297 if (attrib->type() != type) continue;
298 }
299 if (attrib->name() != name) continue;
300 return true;
301 }
302
303 return false;
304 }
305
306
1/2
✓ Branch 0 taken 1537 times.
✗ Branch 1 not taken.
1537 void catalogueVariables(const ast::Node& node,
307 std::vector<const ast::Variable*>* readOnly,
308 std::vector<const ast::Variable*>* writeOnly,
309 std::vector<const ast::Variable*>* readWrite,
310 const bool locals,
311 const bool attributes)
312 {
313 std::vector<const ast::Variable*> vars;
314
315 if (locals) {
316 collectNodeTypes<ast::Local>(node, vars);
317 }
318
1/2
✓ Branch 0 taken 1537 times.
✗ Branch 1 not taken.
1537 if (attributes) {
319 collectNodeType<ast::Attribute>(node, vars);
320 }
321
322
2/2
✓ Branch 0 taken 12091 times.
✓ Branch 1 taken 1537 times.
13628 for (const ast::Variable* var : vars) {
323 // traverse upwards, see if we're embedded in an assign or crement expression
324 const ast::Node* child = var;
325 const ast::Node* parent = child->parent();
326 bool read = false, write = false;
327
4/4
✓ Branch 0 taken 35673 times.
✓ Branch 1 taken 1176 times.
✓ Branch 2 taken 24758 times.
✓ Branch 3 taken 10915 times.
36849 while (parent && !(write && read)) {
328
1/2
✓ Branch 1 taken 24758 times.
✗ Branch 2 not taken.
24758 const ast::Node::NodeType type = parent->nodetype();
329 // crement operations read and write
330
2/2
✓ Branch 0 taken 24158 times.
✓ Branch 1 taken 600 times.
24758 if (type == ast::Node::CrementNode) {
331 read = write = true;
332 }
333
2/2
✓ Branch 0 taken 11545 times.
✓ Branch 1 taken 12613 times.
24158 else if (type == ast::Node::AssignExpressionNode) {
334 const ast::AssignExpression* assignment =
335 static_cast<const ast::AssignExpression*>(parent);
336
2/2
✓ Branch 0 taken 10291 times.
✓ Branch 1 taken 1254 times.
11545 if (assignment->lhs() == child) {
337
2/2
✓ Branch 0 taken 9196 times.
✓ Branch 1 taken 1095 times.
10291 if (assignment->isCompound()) {
338 // +=, *=, /= etc
339 read = write = true;
340 }
341 else {
342 // op = op
343 write = true;
344 }
345 }
346 else {
347 read = true;
348 }
349 }
350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12613 times.
12613 else if (type == ast::Node::DeclareLocalNode) {
351 const ast::DeclareLocal* declareLocal =
352 static_cast<const ast::DeclareLocal*>(parent);
353 if (declareLocal->local() == child) {
354 if (declareLocal->hasInit()) {
355 write = true;
356 }
357 }
358 }
359
2/2
✓ Branch 0 taken 12589 times.
✓ Branch 1 taken 24 times.
12613 else if (type == ast::Node::FunctionCallNode) {
360 // @todo We currently can't detect if attributes are being passed by
361 // pointer and being modified automatically. This is a major limitation
362 // as it means any attribute passed into any function directly must
363 // be marked as writeable
364 read = write = true;
365 }
366 else {
367 read = true;
368 }
369 child = parent;
370 parent = child->parent();
371 }
372
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12091 times.
12091 assert(read || write);
374
4/6
✓ Branch 0 taken 12091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10915 times.
✓ Branch 3 taken 1176 times.
✓ Branch 5 taken 10915 times.
✗ Branch 6 not taken.
12091 if (readWrite && read && write) readWrite->emplace_back(var);
375
4/6
✓ Branch 0 taken 12091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1176 times.
✓ Branch 3 taken 10915 times.
✓ Branch 5 taken 1176 times.
✗ Branch 6 not taken.
12091 if (readOnly && read && !write) readOnly->emplace_back(var);
376
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12091 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
12091 if (writeOnly && !read && write) writeOnly->emplace_back(var);
377 }
378 1537 }
379
380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1537 times.
1537 void catalogueAttributeTokens(const ast::Node& node,
381 std::vector<std::string>* readOnly,
382 std::vector<std::string>* writeOnly,
383 std::vector<std::string>* readWrite)
384 {
385 std::vector<const ast::Variable*> readOnlyVars;
386 std::vector<const ast::Variable*> writeOnlyVars;
387 std::vector<const ast::Variable*> readWriteVars;
388
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1537 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1537 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1537 times.
✓ Branch 7 taken 1537 times.
✗ Branch 8 not taken.
1537 catalogueVariables(node,
389 (readOnly ? &readOnlyVars : nullptr),
390 (writeOnly ? &writeOnlyVars : nullptr),
391 (readWrite ? &readWriteVars : nullptr),
392 false, // locals
393 true); // attributes
394
395 // fill a single map with the access patterns for all attributes
396 // .first = read, .second = write
397 // @note use a map rather than an unordered_map to preserve order
398 // of the output vectors on different platforms (the AX compiler
399 // doesn't care about the order but it's reasonable to expect
400 // an attribute has the same index from one platform to the next).
401 std::map<std::string, std::pair<bool,bool>> accessmap;
402
403 4611 auto addAccesses = [&](const std::vector<const ast::Variable*>& vars,
404 const bool read,
405 const bool write)
406 {
407
2/2
✓ Branch 0 taken 12091 times.
✓ Branch 1 taken 4611 times.
16702 for (const ast::Variable* var : vars) {
408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12091 times.
12091 assert(var->isType<ast::Attribute>());
409 const ast::Attribute* attrib = static_cast<const ast::Attribute*>(var);
410
1/2
✓ Branch 1 taken 12091 times.
✗ Branch 2 not taken.
12091 auto& access = accessmap[attrib->tokenname()];
411 12091 access.first |= read;
412 12091 access.second |= write;
413 }
414 4611 };
415
416
1/2
✓ Branch 1 taken 1537 times.
✗ Branch 2 not taken.
1537 addAccesses(readWriteVars, true, true);
417
1/2
✓ Branch 1 taken 1537 times.
✗ Branch 2 not taken.
1537 addAccesses(writeOnlyVars, false, true);
418
1/2
✓ Branch 1 taken 1537 times.
✗ Branch 2 not taken.
1537 addAccesses(readOnlyVars, true, false);
419
420 // set the results from the access map
421
2/2
✓ Branch 0 taken 10149 times.
✓ Branch 1 taken 1537 times.
11686 for (const auto& result : accessmap) {
422 const std::pair<bool,bool>& pair = result.second;
423
4/6
✓ Branch 0 taken 10149 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10149 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9860 times.
✓ Branch 5 taken 289 times.
10149 if (readWrite && pair.first && pair.second) {
424
1/2
✓ Branch 1 taken 9860 times.
✗ Branch 2 not taken.
9860 readWrite->emplace_back(result.first);
425 }
426
2/6
✓ Branch 0 taken 289 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 289 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
289 else if (writeOnly && !pair.first && pair.second) {
427 writeOnly->emplace_back(result.first);
428 }
429
3/6
✓ Branch 0 taken 289 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 289 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 289 times.
✗ Branch 5 not taken.
289 else if (readOnly && pair.first && !pair.second) {
430
1/2
✓ Branch 1 taken 289 times.
✗ Branch 2 not taken.
289 readOnly->emplace_back(result.first);
431 }
432 }
433 1537 }
434
435 template <bool First>
436 struct UseVisitor :
437 public ast::Visitor<UseVisitor<First>>
438 {
439 using ast::Visitor<UseVisitor<First>>::traverse;
440 using ast::Visitor<UseVisitor<First>>::visit;
441
442 // reverse the ast traversal if !First
443 inline bool reverseChildVisits() const { return !First; }
444
445 20604 UseVisitor(const std::string& tokenOrName)
446 : mToken(tokenOrName)
447 , mAttribute(false)
448
1/2
✓ Branch 2 taken 10302 times.
✗ Branch 3 not taken.
20604 , mVar(nullptr) {
449 // rebuild the expected token if necessary
450 std::string name, type;
451
1/2
✓ Branch 1 taken 10302 times.
✗ Branch 2 not taken.
20604 mAttribute = ast::Attribute::nametypeFromToken(mToken, &name, &type);
452
1/2
✓ Branch 0 taken 10302 times.
✗ Branch 1 not taken.
20604 if (mAttribute) {
453
1/2
✓ Branch 1 taken 10302 times.
✗ Branch 2 not taken.
41208 mToken = type + ast::Attribute::symbolseparator() + name;
454 }
455 20604 }
456 ~UseVisitor() = default;
457
458 1100 bool traverse(const ast::Loop* loop)
459 {
460
1/2
✓ Branch 0 taken 550 times.
✗ Branch 1 not taken.
1100 if (!loop) return true;
461 const ast::tokens::LoopToken type = loop->loopType();
462
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 512 times.
1100 if (type == ast::tokens::DO) {
463 if (!this->reverseChildVisits()) {
464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if (!this->traverse(loop->body())) return false;
465 if (!this->traverse(loop->condition())) return false;
466 }
467 else {
468
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 1 times.
74 if (!this->traverse(loop->condition())) return false;
469
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
72 if (!this->traverse(loop->body())) return false;
470 }
471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
72 assert(!loop->initial());
472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
72 assert(!loop->iteration());
473 }
474 else {
475 if (!this->reverseChildVisits()) {
476
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 2 times.
26 if (!this->traverse(loop->initial())) return false;
477
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 times.
22 if (!this->traverse(loop->condition())) return false;
478
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 times.
20 if (!this->traverse(loop->iteration())) return false;
479
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
18 if (!this->traverse(loop->body())) return false;
480 }
481 else {
482
2/2
✓ Branch 0 taken 462 times.
✓ Branch 1 taken 37 times.
998 if (!this->traverse(loop->body())) return false;
483
2/2
✓ Branch 1 taken 460 times.
✓ Branch 2 taken 2 times.
924 if (!this->traverse(loop->iteration())) return false;
484
2/2
✓ Branch 1 taken 458 times.
✓ Branch 2 taken 2 times.
920 if (!this->traverse(loop->condition())) return false;
485
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 456 times.
916 if (!this->traverse(loop->initial())) return false;
486 }
487 }
488
489 if (!this->visit(loop)) return false;
490 return true;
491 }
492
493 154678 inline bool visit(const ast::Attribute* node) {
494
1/2
✓ Branch 0 taken 77339 times.
✗ Branch 1 not taken.
154678 if (!mAttribute) return true;
495
2/2
✓ Branch 1 taken 10302 times.
✓ Branch 2 taken 67037 times.
309356 if (node->tokenname() != mToken) return true;
496 20604 mVar = node;
497 20604 return false;
498 }
499 inline bool visit(const ast::Local* node) {
500
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 41217 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
41242 if (mAttribute) return true;
501 if (node->name() != mToken) return true;
502 mVar = node;
503 return false;
504 }
505
506 10302 const ast::Variable* var() const { return mVar; }
507 private:
508 std::string mToken;
509 bool mAttribute;
510 const ast::Variable* mVar;
511 };
512
513 10212 void attributeDependencyTokens(const ast::Tree& tree,
514 const std::string& name,
515 const tokens::CoreType type,
516 std::vector<std::string>& dependencies)
517 {
518 10212 const std::string token = ast::Attribute::tokenFromNameType(name, type);
519
1/2
✓ Branch 1 taken 10212 times.
✗ Branch 2 not taken.
10212 const ast::Variable* var = lastUse(tree, token);
520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10212 times.
10212 if (!var) return;
521
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10212 times.
10212 assert(var->isType<ast::Attribute>());
522
523 std::vector<const ast::Variable*> deps;
524
1/2
✓ Branch 1 taken 10212 times.
✗ Branch 2 not taken.
10212 variableDependencies(*var, deps);
525
526
2/2
✓ Branch 0 taken 11957 times.
✓ Branch 1 taken 10212 times.
22169 for (const auto& dep : deps) {
527
3/4
✓ Branch 1 taken 11957 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7768 times.
✓ Branch 4 taken 4189 times.
11957 if (dep->nodetype() != ast::Node::AttributeNode) continue;
528
2/6
✓ Branch 1 taken 4189 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4189 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8378 dependencies.emplace_back(static_cast<const ast::Attribute*>(dep)->tokenname());
529 }
530
531 10212 std::sort(dependencies.begin(), dependencies.end());
532 10212 auto iter = std::unique(dependencies.begin(), dependencies.end());
533
2/2
✓ Branch 1 taken 5638 times.
✓ Branch 2 taken 4574 times.
10212 dependencies.erase(iter, dependencies.end());
534 }
535
536 45 const ast::Variable* firstUse(const ast::Node& node, const std::string& tokenOrName)
537 {
538 45 UseVisitor<true> visitor(tokenOrName);
539
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 visitor.traverse(&node);
540 45 return visitor.var();
541 }
542
543 10257 const ast::Variable* lastUse(const ast::Node& node, const std::string& tokenOrName)
544 {
545 10257 UseVisitor<false> visitor(tokenOrName);
546
1/2
✓ Branch 1 taken 10257 times.
✗ Branch 2 not taken.
10257 visitor.traverse(&node);
547 10257 return visitor.var();
548 }
549
550 5232 bool callsFunction(const ast::Node& node, const std::string& name)
551 {
552 5232 bool found = false;
553 5232 visitNodeType<ast::FunctionCall>(node,
554 [&](const ast::FunctionCall& call) -> bool {
555
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 17098 times.
17121 if (call.name() != name) return true;
556 23 found = true;
557 23 return false;
558 });
559
560 5232 return found;
561 }
562
563 930 void linearize(const ast::Node& node, std::vector<const ast::Node*>& list)
564 {
565 collectNodeType<ast::Node>(node, list);
566 930 }
567
568 } // namespace ast
569 } // namespace ax
570 } // namespace OPENVDB_VERSION_NAME
571 } // namespace openvdb
572
573
574