Commit c9c259cc by Olli Etuaho Committed by Commit Bot

Add a shared traverse() function for most node types

The traversal logic for many node types is essentially the same. Use a single traverse() function for all simple node types instead of having different ones for each node type. Special traversal code is only needed for those node types where the traversal logic is overridden in specific traversers or which do special bookkeeping. This makes traverser behavior a bit more consistent: InVisit calls are now done for all node types, including if/else, ternary and loop nodes. Also false returned from visit function will always skip traversing the next children of that node. This reduces shader_translator binary size on Windows by 8 kilobytes. The added helper functions will also make it easier to implement alternative more efficient traversers. Unfortunately this also regresses compiler perf tests by around 2-3%. BUG=angleproject:2662 TEST=angle_unittests, angle_end2end_tests Change-Id: I3cb1256297b66e1db4b133b8fb84a24c349a9e29 Reviewed-on: https://chromium-review.googlesource.com/1133009Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 5598148b
......@@ -197,6 +197,7 @@
'compiler/translator/tree_util/ReplaceVariable.h',
'compiler/translator/tree_util/RunAtTheEndOfShader.cpp',
'compiler/translator/tree_util/RunAtTheEndOfShader.h',
'compiler/translator/tree_util/Visit.h',
'third_party/compiler/ArrayBoundsClamper.cpp',
'third_party/compiler/ArrayBoundsClamper.h',
],
......
......@@ -202,6 +202,61 @@ void TIntermExpression::setTypePreservePrecision(const TType &t)
return true; \
}
unsigned int TIntermSymbol::getChildCount()
{
return 0;
}
TIntermNode *TIntermSymbol::getChildNode(unsigned int index)
{
UNREACHABLE();
return nullptr;
}
unsigned int TIntermConstantUnion::getChildCount()
{
return 0;
}
TIntermNode *TIntermConstantUnion::getChildNode(unsigned int index)
{
UNREACHABLE();
return nullptr;
}
unsigned int TIntermLoop::getChildCount()
{
return (mInit ? 1 : 0) + (mCond ? 1 : 0) + (mExpr ? 1 : 0) + (mBody ? 1 : 0);
}
TIntermNode *TIntermLoop::getChildNode(unsigned int index)
{
TIntermNode *children[4];
unsigned int childIndex = 0;
if (mInit)
{
children[childIndex] = mInit;
++childIndex;
}
if (mCond)
{
children[childIndex] = mCond;
++childIndex;
}
if (mExpr)
{
children[childIndex] = mExpr;
++childIndex;
}
if (mBody)
{
children[childIndex] = mBody;
++childIndex;
}
ASSERT(index < childIndex);
return children[index];
}
bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
ASSERT(original != nullptr); // This risks replacing multiple children.
......@@ -212,12 +267,36 @@ bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replaceme
return false;
}
unsigned int TIntermBranch::getChildCount()
{
return (mExpression ? 1 : 0);
}
TIntermNode *TIntermBranch::getChildNode(unsigned int index)
{
ASSERT(mExpression);
ASSERT(index == 0);
return mExpression;
}
bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
return false;
}
unsigned int TIntermSwizzle::getChildCount()
{
return 1;
}
TIntermNode *TIntermSwizzle::getChildNode(unsigned int index)
{
ASSERT(mOperand);
ASSERT(index == 0);
return mOperand;
}
bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
......@@ -225,6 +304,21 @@ bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replac
return false;
}
unsigned int TIntermBinary::getChildCount()
{
return 2;
}
TIntermNode *TIntermBinary::getChildNode(unsigned int index)
{
ASSERT(index < 2);
if (index == 0)
{
return mLeft;
}
return mRight;
}
bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
......@@ -232,6 +326,18 @@ bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replace
return false;
}
unsigned int TIntermUnary::getChildCount()
{
return 1;
}
TIntermNode *TIntermUnary::getChildNode(unsigned int index)
{
ASSERT(mOperand);
ASSERT(index == 0);
return mOperand;
}
bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
......@@ -239,12 +345,39 @@ bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacem
return false;
}
unsigned int TIntermInvariantDeclaration::getChildCount()
{
return 1;
}
TIntermNode *TIntermInvariantDeclaration::getChildNode(unsigned int index)
{
ASSERT(mSymbol);
ASSERT(index == 0);
return mSymbol;
}
bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
return false;
}
unsigned int TIntermFunctionDefinition::getChildCount()
{
return 2;
}
TIntermNode *TIntermFunctionDefinition::getChildNode(unsigned int index)
{
ASSERT(index < 2);
if (index == 0)
{
return mPrototype;
}
return mBody;
}
bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
......@@ -252,21 +385,62 @@ bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermN
return false;
}
unsigned int TIntermAggregate::getChildCount()
{
return mArguments.size();
}
TIntermNode *TIntermAggregate::getChildNode(unsigned int index)
{
return mArguments[index];
}
bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
return replaceChildNodeInternal(original, replacement);
}
unsigned int TIntermBlock::getChildCount()
{
return mStatements.size();
}
TIntermNode *TIntermBlock::getChildNode(unsigned int index)
{
return mStatements[index];
}
bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
return replaceChildNodeInternal(original, replacement);
}
unsigned int TIntermFunctionPrototype::getChildCount()
{
return 0;
}
TIntermNode *TIntermFunctionPrototype::getChildNode(unsigned int index)
{
UNREACHABLE();
return nullptr;
}
bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
return false;
}
unsigned int TIntermDeclaration::getChildCount()
{
return mDeclarators.size();
}
TIntermNode *TIntermDeclaration::getChildNode(unsigned int index)
{
return mDeclarators[index];
}
bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
return replaceChildNodeInternal(original, replacement);
......@@ -700,6 +874,25 @@ void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
mDeclarators.push_back(declarator);
}
unsigned int TIntermTernary::getChildCount()
{
return 3;
}
TIntermNode *TIntermTernary::getChildNode(unsigned int index)
{
ASSERT(index < 3);
if (index == 0)
{
return mCondition;
}
if (index == 1)
{
return mTrueExpression;
}
return mFalseExpression;
}
bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
......@@ -708,6 +901,24 @@ bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replac
return false;
}
unsigned int TIntermIfElse::getChildCount()
{
return 1 + (mTrueBlock ? 1 : 0) + (mFalseBlock ? 1 : 0);
}
TIntermNode *TIntermIfElse::getChildNode(unsigned int index)
{
if (index == 0)
{
return mCondition;
}
if (mTrueBlock && index == 1)
{
return mTrueBlock;
}
return mFalseBlock;
}
bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
......@@ -716,6 +927,21 @@ bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replace
return false;
}
unsigned int TIntermSwitch::getChildCount()
{
return 2;
}
TIntermNode *TIntermSwitch::getChildNode(unsigned int index)
{
ASSERT(index < 2);
if (index == 0)
{
return mInit;
}
return mStatementList;
}
bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
......@@ -724,6 +950,18 @@ bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replace
return false;
}
unsigned int TIntermCase::getChildCount()
{
return (mCondition ? 1 : 0);
}
TIntermNode *TIntermCase::getChildNode(unsigned int index)
{
ASSERT(index == 0);
ASSERT(mCondition);
return mCondition;
}
bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
......@@ -1117,6 +1355,7 @@ TIntermLoop::TIntermLoop(TLoopType type,
TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
: TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
{
ASSERT(mCondition);
// Prune empty false blocks so that there won't be unnecessary operations done on it.
if (mFalseBlock && mFalseBlock->getSequence()->empty())
{
......@@ -1127,6 +1366,7 @@ TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlo
TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
: TIntermNode(), mInit(init), mStatementList(statementList)
{
ASSERT(mInit);
ASSERT(mStatementList);
}
......
......@@ -10,6 +10,7 @@
#define COMPILER_TRANSLATOR_TREEUTIL_INTERMTRAVERSE_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/tree_util/Visit.h"
namespace sh
{
......@@ -17,13 +18,6 @@ namespace sh
class TSymbolTable;
class TSymbolUniqueId;
enum Visit
{
PreVisit,
InVisit,
PostVisit
};
// For traversing the tree. User should derive from this class overriding the visit functions,
// and then pass an object of the subclass to a traverse method of a node.
//
......@@ -73,23 +67,21 @@ class TIntermTraverser : angle::NonCopyable
// The traverse functions contain logic for iterating over the children of the node
// and calling the visit functions in the appropriate places. They also track some
// context that may be used by the visit functions.
virtual void traverseSymbol(TIntermSymbol *node);
virtual void traverseConstantUnion(TIntermConstantUnion *node);
virtual void traverseSwizzle(TIntermSwizzle *node);
// The generic traverse() function is used for nodes that don't need special handling.
// It's templated in order to avoid virtual function calls, this gains around 2% compiler
// performance.
template <typename T>
void traverse(T *node);
// Specialized traverse functions are implemented for node types where traversal logic may need
// to be overridden or where some special bookkeeping needs to be done.
virtual void traverseBinary(TIntermBinary *node);
virtual void traverseUnary(TIntermUnary *node);
virtual void traverseTernary(TIntermTernary *node);
virtual void traverseIfElse(TIntermIfElse *node);
virtual void traverseSwitch(TIntermSwitch *node);
virtual void traverseCase(TIntermCase *node);
virtual void traverseFunctionPrototype(TIntermFunctionPrototype *node);
virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node);
virtual void traverseAggregate(TIntermAggregate *node);
virtual void traverseBlock(TIntermBlock *node);
virtual void traverseInvariantDeclaration(TIntermInvariantDeclaration *node);
virtual void traverseDeclaration(TIntermDeclaration *node);
virtual void traverseLoop(TIntermLoop *node);
virtual void traverseBranch(TIntermBranch *node);
int getMaxDepth() const { return mMaxDepth; }
......@@ -134,6 +126,10 @@ class TIntermTraverser : angle::NonCopyable
TIntermTraverser *mTraverser;
bool mWithinDepthLimit;
};
// Optimized traversal functions for leaf nodes directly access ScopedNodeInTraversalPath.
friend void TIntermSymbol::traverse(TIntermTraverser *);
friend void TIntermConstantUnion::traverse(TIntermTraverser *);
friend void TIntermFunctionPrototype::traverse(TIntermTraverser *);
TIntermNode *getParentNode() { return mPath.size() <= 1 ? nullptr : mPath[mPath.size() - 2u]; }
......
//
// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_
#define COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_
namespace sh
{
enum Visit
{
PreVisit,
InVisit,
PostVisit
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment