File: | root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp |
Warning: | line 300, column 5 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // | |||
2 | // Copyright 2002 The ANGLE Project Authors. All rights reserved. | |||
3 | // Use of this source code is governed by a BSD-style license that can be | |||
4 | // found in the LICENSE file. | |||
5 | // | |||
6 | ||||
7 | #include "compiler/translator/tree_util/IntermTraverse.h" | |||
8 | ||||
9 | #include "compiler/translator/Compiler.h" | |||
10 | #include "compiler/translator/InfoSink.h" | |||
11 | #include "compiler/translator/SymbolTable.h" | |||
12 | #include "compiler/translator/tree_util/IntermNode_util.h" | |||
13 | #include "compiler/translator/util.h" | |||
14 | ||||
15 | namespace sh | |||
16 | { | |||
17 | ||||
18 | // Traverse the intermediate representation tree, and call a node type specific visit function for | |||
19 | // each node. Traversal is done recursively through the node member function traverse(). Nodes with | |||
20 | // children can have their whole subtree skipped if preVisit is turned on and the type specific | |||
21 | // function returns false. | |||
22 | template <typename T> | |||
23 | void TIntermTraverser::traverse(T *node) | |||
24 | { | |||
25 | ScopedNodeInTraversalPath addToPath(this, node); | |||
26 | if (!addToPath.isWithinDepthLimit()) | |||
27 | return; | |||
28 | ||||
29 | bool visit = true; | |||
30 | ||||
31 | // Visit the node before children if pre-visiting. | |||
32 | if (preVisit) | |||
33 | visit = node->visit(PreVisit, this); | |||
34 | ||||
35 | if (visit) | |||
36 | { | |||
37 | size_t childIndex = 0; | |||
38 | size_t childCount = node->getChildCount(); | |||
39 | ||||
40 | while (childIndex < childCount && visit) | |||
41 | { | |||
42 | mCurrentChildIndex = childIndex; | |||
43 | node->getChildNode(childIndex)->traverse(this); | |||
44 | mCurrentChildIndex = childIndex; | |||
45 | ||||
46 | if (inVisit && childIndex != childCount - 1) | |||
47 | { | |||
48 | visit = node->visit(InVisit, this); | |||
49 | } | |||
50 | ++childIndex; | |||
51 | } | |||
52 | ||||
53 | if (visit && postVisit) | |||
54 | node->visit(PostVisit, this); | |||
55 | } | |||
56 | } | |||
57 | ||||
58 | // Instantiate template for RewriteAtomicFunctionExpressions, in case this gets inlined thus not | |||
59 | // exported from the TU. | |||
60 | template void TIntermTraverser::traverse(TIntermNode *); | |||
61 | ||||
62 | void TIntermNode::traverse(TIntermTraverser *it) | |||
63 | { | |||
64 | it->traverse(this); | |||
65 | } | |||
66 | ||||
67 | void TIntermSymbol::traverse(TIntermTraverser *it) | |||
68 | { | |||
69 | TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); | |||
70 | it->visitSymbol(this); | |||
71 | } | |||
72 | ||||
73 | void TIntermConstantUnion::traverse(TIntermTraverser *it) | |||
74 | { | |||
75 | TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); | |||
76 | it->visitConstantUnion(this); | |||
77 | } | |||
78 | ||||
79 | void TIntermFunctionPrototype::traverse(TIntermTraverser *it) | |||
80 | { | |||
81 | TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); | |||
82 | it->visitFunctionPrototype(this); | |||
83 | } | |||
84 | ||||
85 | void TIntermBinary::traverse(TIntermTraverser *it) | |||
86 | { | |||
87 | it->traverseBinary(this); | |||
88 | } | |||
89 | ||||
90 | void TIntermUnary::traverse(TIntermTraverser *it) | |||
91 | { | |||
92 | it->traverseUnary(this); | |||
93 | } | |||
94 | ||||
95 | void TIntermFunctionDefinition::traverse(TIntermTraverser *it) | |||
96 | { | |||
97 | it->traverseFunctionDefinition(this); | |||
98 | } | |||
99 | ||||
100 | void TIntermBlock::traverse(TIntermTraverser *it) | |||
101 | { | |||
102 | it->traverseBlock(this); | |||
103 | } | |||
104 | ||||
105 | void TIntermAggregate::traverse(TIntermTraverser *it) | |||
106 | { | |||
107 | it->traverseAggregate(this); | |||
108 | } | |||
109 | ||||
110 | void TIntermLoop::traverse(TIntermTraverser *it) | |||
111 | { | |||
112 | it->traverseLoop(this); | |||
113 | } | |||
114 | ||||
115 | void TIntermPreprocessorDirective::traverse(TIntermTraverser *it) | |||
116 | { | |||
117 | it->visitPreprocessorDirective(this); | |||
118 | } | |||
119 | ||||
120 | bool TIntermSymbol::visit(Visit visit, TIntermTraverser *it) | |||
121 | { | |||
122 | it->visitSymbol(this); | |||
123 | return false; | |||
124 | } | |||
125 | ||||
126 | bool TIntermConstantUnion::visit(Visit visit, TIntermTraverser *it) | |||
127 | { | |||
128 | it->visitConstantUnion(this); | |||
129 | return false; | |||
130 | } | |||
131 | ||||
132 | bool TIntermFunctionPrototype::visit(Visit visit, TIntermTraverser *it) | |||
133 | { | |||
134 | it->visitFunctionPrototype(this); | |||
135 | return false; | |||
136 | } | |||
137 | ||||
138 | bool TIntermFunctionDefinition::visit(Visit visit, TIntermTraverser *it) | |||
139 | { | |||
140 | return it->visitFunctionDefinition(visit, this); | |||
141 | } | |||
142 | ||||
143 | bool TIntermUnary::visit(Visit visit, TIntermTraverser *it) | |||
144 | { | |||
145 | return it->visitUnary(visit, this); | |||
146 | } | |||
147 | ||||
148 | bool TIntermSwizzle::visit(Visit visit, TIntermTraverser *it) | |||
149 | { | |||
150 | return it->visitSwizzle(visit, this); | |||
151 | } | |||
152 | ||||
153 | bool TIntermBinary::visit(Visit visit, TIntermTraverser *it) | |||
154 | { | |||
155 | return it->visitBinary(visit, this); | |||
156 | } | |||
157 | ||||
158 | bool TIntermTernary::visit(Visit visit, TIntermTraverser *it) | |||
159 | { | |||
160 | return it->visitTernary(visit, this); | |||
161 | } | |||
162 | ||||
163 | bool TIntermAggregate::visit(Visit visit, TIntermTraverser *it) | |||
164 | { | |||
165 | return it->visitAggregate(visit, this); | |||
166 | } | |||
167 | ||||
168 | bool TIntermDeclaration::visit(Visit visit, TIntermTraverser *it) | |||
169 | { | |||
170 | return it->visitDeclaration(visit, this); | |||
171 | } | |||
172 | ||||
173 | bool TIntermGlobalQualifierDeclaration::visit(Visit visit, TIntermTraverser *it) | |||
174 | { | |||
175 | return it->visitGlobalQualifierDeclaration(visit, this); | |||
176 | } | |||
177 | ||||
178 | bool TIntermBlock::visit(Visit visit, TIntermTraverser *it) | |||
179 | { | |||
180 | return it->visitBlock(visit, this); | |||
181 | } | |||
182 | ||||
183 | bool TIntermIfElse::visit(Visit visit, TIntermTraverser *it) | |||
184 | { | |||
185 | return it->visitIfElse(visit, this); | |||
186 | } | |||
187 | ||||
188 | bool TIntermLoop::visit(Visit visit, TIntermTraverser *it) | |||
189 | { | |||
190 | return it->visitLoop(visit, this); | |||
191 | } | |||
192 | ||||
193 | bool TIntermBranch::visit(Visit visit, TIntermTraverser *it) | |||
194 | { | |||
195 | return it->visitBranch(visit, this); | |||
196 | } | |||
197 | ||||
198 | bool TIntermSwitch::visit(Visit visit, TIntermTraverser *it) | |||
199 | { | |||
200 | return it->visitSwitch(visit, this); | |||
201 | } | |||
202 | ||||
203 | bool TIntermCase::visit(Visit visit, TIntermTraverser *it) | |||
204 | { | |||
205 | return it->visitCase(visit, this); | |||
206 | } | |||
207 | ||||
208 | bool TIntermPreprocessorDirective::visit(Visit visit, TIntermTraverser *it) | |||
209 | { | |||
210 | it->visitPreprocessorDirective(this); | |||
211 | return false; | |||
212 | } | |||
213 | ||||
214 | TIntermTraverser::TIntermTraverser(bool preVisit, | |||
215 | bool inVisit, | |||
216 | bool postVisit, | |||
217 | TSymbolTable *symbolTable) | |||
218 | : preVisit(preVisit), | |||
219 | inVisit(inVisit), | |||
220 | postVisit(postVisit), | |||
221 | mMaxDepth(0), | |||
222 | mMaxAllowedDepth(std::numeric_limits<int>::max()), | |||
223 | mInGlobalScope(true), | |||
224 | mSymbolTable(symbolTable), | |||
225 | mCurrentChildIndex(0) | |||
226 | { | |||
227 | // Only enabling inVisit is not supported. | |||
228 | ASSERT(!(inVisit && !preVisit && !postVisit))(!(inVisit && !preVisit && !postVisit) ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 228, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 228 << "): " << "!(inVisit && !preVisit && !postVisit)" )); | |||
229 | } | |||
230 | ||||
231 | TIntermTraverser::~TIntermTraverser() {} | |||
232 | ||||
233 | void TIntermTraverser::setMaxAllowedDepth(int depth) | |||
234 | { | |||
235 | mMaxAllowedDepth = depth; | |||
236 | } | |||
237 | ||||
238 | const TIntermBlock *TIntermTraverser::getParentBlock() const | |||
239 | { | |||
240 | if (!mParentBlockStack.empty()) | |||
241 | { | |||
242 | return mParentBlockStack.back().node; | |||
243 | } | |||
244 | return nullptr; | |||
245 | } | |||
246 | ||||
247 | void TIntermTraverser::pushParentBlock(TIntermBlock *node) | |||
248 | { | |||
249 | mParentBlockStack.push_back(ParentBlock(node, 0)); | |||
250 | } | |||
251 | ||||
252 | void TIntermTraverser::incrementParentBlockPos() | |||
253 | { | |||
254 | ++mParentBlockStack.back().pos; | |||
255 | } | |||
256 | ||||
257 | void TIntermTraverser::popParentBlock() | |||
258 | { | |||
259 | ASSERT(!mParentBlockStack.empty())(!mParentBlockStack.empty() ? static_cast<void>(0) : (! ((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL) )) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 259, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 259 << "): " << "!mParentBlockStack.empty()" )); | |||
260 | mParentBlockStack.pop_back(); | |||
261 | } | |||
262 | ||||
263 | void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions) | |||
264 | { | |||
265 | TIntermSequence emptyInsertionsAfter; | |||
266 | insertStatementsInParentBlock(insertions, emptyInsertionsAfter); | |||
267 | } | |||
268 | ||||
269 | void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore, | |||
270 | const TIntermSequence &insertionsAfter) | |||
271 | { | |||
272 | ASSERT(!mParentBlockStack.empty())(!mParentBlockStack.empty() ? static_cast<void>(0) : (! ((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL) )) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 272, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 272 << "): " << "!mParentBlockStack.empty()" )); | |||
273 | ParentBlock &parentBlock = mParentBlockStack.back(); | |||
274 | if (mPath.back() == parentBlock.node) | |||
275 | { | |||
276 | ASSERT(mParentBlockStack.size() >= 2u)(mParentBlockStack.size() >= 2u ? static_cast<void>( 0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 276, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 276 << "): " << "mParentBlockStack.size() >= 2u" )); | |||
277 | // The current node is a block node, so the parent block is not the topmost one in the block | |||
278 | // stack, but the one below that. | |||
279 | parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u); | |||
280 | } | |||
281 | NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore, | |||
282 | insertionsAfter); | |||
283 | mInsertions.push_back(insert); | |||
284 | } | |||
285 | ||||
286 | void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement) | |||
287 | { | |||
288 | TIntermSequence insertions; | |||
289 | insertions.push_back(statement); | |||
290 | insertStatementsInParentBlock(insertions); | |||
291 | } | |||
292 | ||||
293 | void TIntermTraverser::insertStatementsInBlockAtPosition(TIntermBlock *parent, | |||
294 | size_t position, | |||
295 | const TIntermSequence &insertionsBefore, | |||
296 | const TIntermSequence &insertionsAfter) | |||
297 | { | |||
298 | ASSERT(parent)(parent ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 298, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 298 << "): " << "parent")); | |||
| ||||
299 | ASSERT(position >= 0)(position >= 0 ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 299, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 299 << "): " << "position >= 0" )); | |||
300 | ASSERT(position < parent->getChildCount())(position < parent->getChildCount() ? static_cast<void >(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl ::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 300, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 300 << "): " << "position < parent->getChildCount()" )); | |||
| ||||
301 | ||||
302 | mInsertions.emplace_back(parent, position, insertionsBefore, insertionsAfter); | |||
303 | } | |||
304 | ||||
305 | void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter) | |||
306 | { | |||
307 | mInFunctionCallOutParameter = inOutParameter; | |||
308 | } | |||
309 | ||||
310 | bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const | |||
311 | { | |||
312 | return mInFunctionCallOutParameter; | |||
313 | } | |||
314 | ||||
315 | void TIntermTraverser::traverseBinary(TIntermBinary *node) | |||
316 | { | |||
317 | traverse(node); | |||
318 | } | |||
319 | ||||
320 | void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node) | |||
321 | { | |||
322 | ScopedNodeInTraversalPath addToPath(this, node); | |||
323 | if (!addToPath.isWithinDepthLimit()) | |||
324 | return; | |||
325 | ||||
326 | bool visit = true; | |||
327 | ||||
328 | // visit the node before children if pre-visiting. | |||
329 | if (preVisit) | |||
330 | visit = node->visit(PreVisit, this); | |||
331 | ||||
332 | // Visit the children, in the right order. | |||
333 | if (visit) | |||
334 | { | |||
335 | if (node->isAssignment()) | |||
336 | { | |||
337 | ASSERT(!isLValueRequiredHere())(!isLValueRequiredHere() ? static_cast<void>(0) : (!((:: gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 337, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 337 << "): " << "!isLValueRequiredHere()" )); | |||
338 | setOperatorRequiresLValue(true); | |||
339 | } | |||
340 | ||||
341 | node->getLeft()->traverse(this); | |||
342 | ||||
343 | if (node->isAssignment()) | |||
344 | setOperatorRequiresLValue(false); | |||
345 | ||||
346 | if (inVisit) | |||
347 | visit = node->visit(InVisit, this); | |||
348 | ||||
349 | if (visit) | |||
350 | { | |||
351 | // Some binary operations like indexing can be inside an expression which must be an | |||
352 | // l-value. | |||
353 | bool parentOperatorRequiresLValue = operatorRequiresLValue(); | |||
354 | bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter(); | |||
355 | ||||
356 | // Index is not required to be an l-value even when the surrounding expression is | |||
357 | // required to be an l-value. | |||
358 | TOperator op = node->getOp(); | |||
359 | if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock || | |||
360 | op == EOpIndexDirectStruct || op == EOpIndexIndirect) | |||
361 | { | |||
362 | setOperatorRequiresLValue(false); | |||
363 | setInFunctionCallOutParameter(false); | |||
364 | } | |||
365 | ||||
366 | node->getRight()->traverse(this); | |||
367 | ||||
368 | setOperatorRequiresLValue(parentOperatorRequiresLValue); | |||
369 | setInFunctionCallOutParameter(parentInFunctionCallOutParameter); | |||
370 | ||||
371 | // Visit the node after the children, if requested and the traversal | |||
372 | // hasn't been cancelled yet. | |||
373 | if (postVisit) | |||
374 | visit = node->visit(PostVisit, this); | |||
375 | } | |||
376 | } | |||
377 | } | |||
378 | ||||
379 | void TIntermTraverser::traverseUnary(TIntermUnary *node) | |||
380 | { | |||
381 | traverse(node); | |||
382 | } | |||
383 | ||||
384 | void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node) | |||
385 | { | |||
386 | ScopedNodeInTraversalPath addToPath(this, node); | |||
387 | if (!addToPath.isWithinDepthLimit()) | |||
388 | return; | |||
389 | ||||
390 | bool visit = true; | |||
391 | ||||
392 | if (preVisit) | |||
393 | visit = node->visit(PreVisit, this); | |||
394 | ||||
395 | if (visit) | |||
396 | { | |||
397 | ASSERT(!operatorRequiresLValue())(!operatorRequiresLValue() ? static_cast<void>(0) : (!( (::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL)) ) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 397, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 397 << "): " << "!operatorRequiresLValue()" )); | |||
398 | switch (node->getOp()) | |||
399 | { | |||
400 | case EOpPostIncrement: | |||
401 | case EOpPostDecrement: | |||
402 | case EOpPreIncrement: | |||
403 | case EOpPreDecrement: | |||
404 | setOperatorRequiresLValue(true); | |||
405 | break; | |||
406 | default: | |||
407 | break; | |||
408 | } | |||
409 | ||||
410 | node->getOperand()->traverse(this); | |||
411 | ||||
412 | setOperatorRequiresLValue(false); | |||
413 | ||||
414 | if (postVisit) | |||
415 | visit = node->visit(PostVisit, this); | |||
416 | } | |||
417 | } | |||
418 | ||||
419 | // Traverse a function definition node. This keeps track of global scope. | |||
420 | void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node) | |||
421 | { | |||
422 | ScopedNodeInTraversalPath addToPath(this, node); | |||
423 | if (!addToPath.isWithinDepthLimit()) | |||
424 | return; | |||
425 | ||||
426 | bool visit = true; | |||
427 | ||||
428 | if (preVisit) | |||
429 | visit = node->visit(PreVisit, this); | |||
430 | ||||
431 | if (visit) | |||
432 | { | |||
433 | mCurrentChildIndex = 0; | |||
434 | node->getFunctionPrototype()->traverse(this); | |||
435 | mCurrentChildIndex = 0; | |||
436 | ||||
437 | if (inVisit) | |||
438 | visit = node->visit(InVisit, this); | |||
439 | if (visit) | |||
440 | { | |||
441 | mInGlobalScope = false; | |||
442 | mCurrentChildIndex = 1; | |||
443 | node->getBody()->traverse(this); | |||
444 | mCurrentChildIndex = 1; | |||
445 | mInGlobalScope = true; | |||
446 | if (postVisit) | |||
447 | visit = node->visit(PostVisit, this); | |||
448 | } | |||
449 | } | |||
450 | } | |||
451 | ||||
452 | // Traverse a block node. This keeps track of the position of traversed child nodes within the block | |||
453 | // so that nodes may be inserted before or after them. | |||
454 | void TIntermTraverser::traverseBlock(TIntermBlock *node) | |||
455 | { | |||
456 | ScopedNodeInTraversalPath addToPath(this, node); | |||
457 | if (!addToPath.isWithinDepthLimit()) | |||
458 | return; | |||
459 | ||||
460 | pushParentBlock(node); | |||
461 | ||||
462 | bool visit = true; | |||
463 | ||||
464 | TIntermSequence *sequence = node->getSequence(); | |||
465 | ||||
466 | if (preVisit) | |||
467 | visit = node->visit(PreVisit, this); | |||
468 | ||||
469 | if (visit) | |||
470 | { | |||
471 | for (size_t childIndex = 0; childIndex < sequence->size(); ++childIndex) | |||
472 | { | |||
473 | TIntermNode *child = (*sequence)[childIndex]; | |||
474 | if (visit) | |||
475 | { | |||
476 | mCurrentChildIndex = childIndex; | |||
477 | child->traverse(this); | |||
478 | mCurrentChildIndex = childIndex; | |||
479 | ||||
480 | if (inVisit) | |||
481 | { | |||
482 | if (child != sequence->back()) | |||
483 | visit = node->visit(InVisit, this); | |||
484 | } | |||
485 | ||||
486 | incrementParentBlockPos(); | |||
487 | } | |||
488 | } | |||
489 | ||||
490 | if (visit && postVisit) | |||
491 | visit = node->visit(PostVisit, this); | |||
492 | } | |||
493 | ||||
494 | popParentBlock(); | |||
495 | } | |||
496 | ||||
497 | void TIntermTraverser::traverseAggregate(TIntermAggregate *node) | |||
498 | { | |||
499 | traverse(node); | |||
500 | } | |||
501 | ||||
502 | bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a, | |||
503 | const NodeInsertMultipleEntry &b) | |||
504 | { | |||
505 | if (a.parent != b.parent) | |||
506 | { | |||
507 | return a.parent < b.parent; | |||
508 | } | |||
509 | return a.position < b.position; | |||
510 | } | |||
511 | ||||
512 | bool TIntermTraverser::updateTree(TCompiler *compiler, TIntermNode *node) | |||
513 | { | |||
514 | // Sort the insertions so that insertion position is increasing and same position insertions are | |||
515 | // not reordered. The insertions are processed in reverse order so that multiple insertions to | |||
516 | // the same parent node are handled correctly. | |||
517 | std::stable_sort(mInsertions.begin(), mInsertions.end(), CompareInsertion); | |||
518 | for (size_t ii = 0; ii < mInsertions.size(); ++ii) | |||
519 | { | |||
520 | // If two insertions are to the same position, insert them in the order they were specified. | |||
521 | // The std::stable_sort call above will automatically guarantee this. | |||
522 | const NodeInsertMultipleEntry &insertion = mInsertions[mInsertions.size() - ii - 1]; | |||
523 | ASSERT(insertion.parent)(insertion.parent ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 523, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 523 << "): " << "insertion.parent" )); | |||
524 | if (!insertion.insertionsAfter.empty()) | |||
525 | { | |||
526 | bool inserted = insertion.parent->insertChildNodes(insertion.position + 1, | |||
527 | insertion.insertionsAfter); | |||
528 | ASSERT(inserted)(inserted ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 528, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 528 << "): " << "inserted" )); | |||
529 | } | |||
530 | if (!insertion.insertionsBefore.empty()) | |||
531 | { | |||
532 | bool inserted = | |||
533 | insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore); | |||
534 | ASSERT(inserted)(inserted ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 534, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 534 << "): " << "inserted" )); | |||
535 | } | |||
536 | } | |||
537 | for (size_t ii = 0; ii < mReplacements.size(); ++ii) | |||
538 | { | |||
539 | const NodeUpdateEntry &replacement = mReplacements[ii]; | |||
540 | ASSERT(replacement.parent)(replacement.parent ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 540, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 540 << "): " << "replacement.parent" )); | |||
541 | bool replaced = | |||
542 | replacement.parent->replaceChildNode(replacement.original, replacement.replacement); | |||
543 | ASSERT(replaced)(replaced ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 543, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 543 << "): " << "replaced" )); | |||
544 | ||||
545 | // Make sure the precision is not accidentally dropped. It's ok if the precision is not the | |||
546 | // same, as the transformations are allowed to replace an expression with one that is | |||
547 | // temporarily evaluated at a different (likely higher) precision. | |||
548 | TIntermTyped *originalAsTyped = replacement.original->getAsTyped(); | |||
549 | TIntermTyped *replacementAsTyped = | |||
550 | replacement.replacement ? replacement.replacement->getAsTyped() : nullptr; | |||
551 | if (originalAsTyped != nullptr && replacementAsTyped != nullptr) | |||
552 | { | |||
553 | const TType &originalType = originalAsTyped->getType(); | |||
554 | const TType &replacementType = replacementAsTyped->getType(); | |||
555 | ASSERT(!IsPrecisionApplicableToType(originalType.getBasicType()) ||(!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType .getPrecision() != EbpUndefined ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 558, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 558 << "): " << "!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType.getPrecision() != EbpUndefined" )) | |||
556 | !IsPrecisionApplicableToType(replacementType.getBasicType()) ||(!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType .getPrecision() != EbpUndefined ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 558, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 558 << "): " << "!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType.getPrecision() != EbpUndefined" )) | |||
557 | originalType.getPrecision() == EbpUndefined ||(!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType .getPrecision() != EbpUndefined ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 558, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 558 << "): " << "!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType.getPrecision() != EbpUndefined" )) | |||
558 | replacementType.getPrecision() != EbpUndefined)(!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType .getPrecision() != EbpUndefined ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 558, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 558 << "): " << "!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType.getPrecision() != EbpUndefined" )); | |||
559 | } | |||
560 | ||||
561 | if (!replacement.originalBecomesChildOfReplacement) | |||
562 | { | |||
563 | // In AST traversing, a parent is visited before its children. | |||
564 | // After we replace a node, if its immediate child is to | |||
565 | // be replaced, we need to make sure we don't update the replaced | |||
566 | // node; instead, we update the replacement node. | |||
567 | for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj) | |||
568 | { | |||
569 | NodeUpdateEntry &replacement2 = mReplacements[jj]; | |||
570 | if (replacement2.parent == replacement.original) | |||
571 | replacement2.parent = replacement.replacement; | |||
572 | } | |||
573 | } | |||
574 | } | |||
575 | for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii) | |||
576 | { | |||
577 | const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii]; | |||
578 | ASSERT(replacement.parent)(replacement.parent ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 578, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 578 << "): " << "replacement.parent" )); | |||
579 | bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original, | |||
580 | replacement.replacements); | |||
581 | ASSERT(replaced)(replaced ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 581, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 581 << "): " << "replaced" )); | |||
582 | } | |||
583 | ||||
584 | clearReplacementQueue(); | |||
585 | ||||
586 | return compiler->validateAST(node); | |||
587 | } | |||
588 | ||||
589 | void TIntermTraverser::clearReplacementQueue() | |||
590 | { | |||
591 | mReplacements.clear(); | |||
592 | mMultiReplacements.clear(); | |||
593 | mInsertions.clear(); | |||
594 | } | |||
595 | ||||
596 | void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus) | |||
597 | { | |||
598 | queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus); | |||
599 | } | |||
600 | ||||
601 | void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent, | |||
602 | TIntermNode *original, | |||
603 | TIntermNode *replacement, | |||
604 | OriginalNode originalStatus) | |||
605 | { | |||
606 | bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD); | |||
607 | mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild)); | |||
608 | } | |||
609 | ||||
610 | void TIntermTraverser::queueAccessChainReplacement(TIntermTyped *replacement) | |||
611 | { | |||
612 | uint32_t ancestorIndex = 0; | |||
613 | TIntermTyped *toReplace = nullptr; | |||
614 | while (true) | |||
615 | { | |||
616 | TIntermNode *ancestor = getAncestorNode(ancestorIndex); | |||
617 | ASSERT(ancestor != nullptr)(ancestor != nullptr ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 617, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 617 << "): " << "ancestor != nullptr" )); | |||
618 | ||||
619 | TIntermBinary *asBinary = ancestor->getAsBinaryNode(); | |||
620 | if (asBinary == nullptr || | |||
621 | (asBinary->getOp() != EOpIndexDirect && asBinary->getOp() != EOpIndexIndirect)) | |||
622 | { | |||
623 | break; | |||
624 | } | |||
625 | ||||
626 | replacement = new TIntermBinary(asBinary->getOp(), replacement, asBinary->getRight()); | |||
627 | toReplace = asBinary; | |||
628 | ||||
629 | ++ancestorIndex; | |||
630 | } | |||
631 | ||||
632 | if (toReplace == nullptr) | |||
633 | { | |||
634 | queueReplacement(replacement, OriginalNode::IS_DROPPED); | |||
635 | } | |||
636 | else | |||
637 | { | |||
638 | queueReplacementWithParent(getAncestorNode(ancestorIndex), toReplace, replacement, | |||
639 | OriginalNode::IS_DROPPED); | |||
640 | } | |||
641 | } | |||
642 | ||||
643 | TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisitIn, | |||
644 | bool inVisitIn, | |||
645 | bool postVisitIn, | |||
646 | TSymbolTable *symbolTable) | |||
647 | : TIntermTraverser(preVisitIn, inVisitIn, postVisitIn, symbolTable), | |||
648 | mOperatorRequiresLValue(false), | |||
649 | mInFunctionCallOutParameter(false) | |||
650 | { | |||
651 | ASSERT(symbolTable)(symbolTable ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 651, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 651 << "): " << "symbolTable" )); | |||
652 | } | |||
653 | ||||
654 | void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node) | |||
655 | { | |||
656 | ScopedNodeInTraversalPath addToPath(this, node); | |||
657 | if (!addToPath.isWithinDepthLimit()) | |||
658 | return; | |||
659 | ||||
660 | bool visit = true; | |||
661 | ||||
662 | TIntermSequence *sequence = node->getSequence(); | |||
663 | ||||
664 | if (preVisit) | |||
665 | visit = node->visit(PreVisit, this); | |||
666 | ||||
667 | if (visit) | |||
668 | { | |||
669 | size_t paramIndex = 0u; | |||
670 | for (auto *child : *sequence) | |||
671 | { | |||
672 | if (visit) | |||
673 | { | |||
674 | if (node->getFunction()) | |||
675 | { | |||
676 | // Both built-ins and user defined functions should have the function symbol | |||
677 | // set. | |||
678 | ASSERT(paramIndex < node->getFunction()->getParamCount())(paramIndex < node->getFunction()->getParamCount() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 678, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 678 << "): " << "paramIndex < node->getFunction()->getParamCount()" )); | |||
679 | TQualifier qualifier = | |||
680 | node->getFunction()->getParam(paramIndex)->getType().getQualifier(); | |||
681 | setInFunctionCallOutParameter(qualifier == EvqParamOut || | |||
682 | qualifier == EvqParamInOut); | |||
683 | ++paramIndex; | |||
684 | } | |||
685 | else | |||
686 | { | |||
687 | ASSERT(node->isConstructor())(node->isConstructor() ? static_cast<void>(0) : (!(( ::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" , __FUNCTION__, 687, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp" << ":" << 687 << "): " << "node->isConstructor()" )); | |||
688 | } | |||
689 | child->traverse(this); | |||
690 | if (inVisit) | |||
691 | { | |||
692 | if (child != sequence->back()) | |||
693 | visit = node->visit(InVisit, this); | |||
694 | } | |||
695 | } | |||
696 | } | |||
697 | setInFunctionCallOutParameter(false); | |||
698 | ||||
699 | if (visit && postVisit) | |||
700 | visit = node->visit(PostVisit, this); | |||
701 | } | |||
702 | } | |||
703 | ||||
704 | void TIntermTraverser::traverseLoop(TIntermLoop *node) | |||
705 | { | |||
706 | traverse(node); | |||
707 | } | |||
708 | } // namespace sh |