Commit cccf2b00 by Olli Etuaho Committed by Commit Bot

Reorganize AST traversal utility code

Define TIntermTraverser and TIntermLValueTrackingTraverser in a separate header file. hash() function is moved out from TIntermTraverser as it is not related to the core functionality of traversing and transforming ASTs. Also reorganize some traversers to follow common conventions: - Intermediate output is now in OutputTree.h/.cpp - Max tree depth check is now in IsASTDepthBelowLimit.h/.cpp BUG=angleproject:1490 TEST=angle_unittests Change-Id: Id4968aa9d4e24d0c5bac90dc147fc9f310de0184 Reviewed-on: https://chromium-review.googlesource.com/559531Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent a3e1f5f7
......@@ -60,6 +60,7 @@
'compiler/translator/FindSymbolNode.h',
'compiler/translator/FlagStd140Structs.cpp',
'compiler/translator/FlagStd140Structs.h',
'compiler/translator/HashNames.cpp',
'compiler/translator/HashNames.h',
'compiler/translator/InfoSink.cpp',
'compiler/translator/InfoSink.h',
......@@ -75,11 +76,16 @@
'compiler/translator/IntermNodePatternMatcher.cpp',
'compiler/translator/IntermNodePatternMatcher.h',
'compiler/translator/IntermTraverse.cpp',
'compiler/translator/IntermTraverse.h',
'compiler/translator/Intermediate.h',
'compiler/translator/Intermediate.cpp',
'compiler/translator/IsASTDepthBelowLimit.cpp',
'compiler/translator/IsASTDepthBelowLimit.h',
'compiler/translator/NodeSearch.h',
'compiler/translator/Operator.cpp',
'compiler/translator/Operator.h',
'compiler/translator/OutputTree.cpp',
'compiler/translator/OutputTree.h',
'compiler/translator/ParamType.h',
'compiler/translator/ParseContext.cpp',
'compiler/translator/ParseContext.h',
......@@ -151,7 +157,6 @@
'compiler/translator/glslang_lex.cpp',
'compiler/translator/glslang_tab.cpp',
'compiler/translator/glslang_tab.h',
'compiler/translator/intermOut.cpp',
'compiler/translator/length_limits.h',
'compiler/translator/util.cpp',
'compiler/translator/util.h',
......
......@@ -9,6 +9,7 @@
#include "compiler/translator/ASTMetadataHLSL.h"
#include "compiler/translator/CallDAG.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
......
......@@ -6,7 +6,7 @@
#include "compiler/translator/AddAndTrueToLoopCondition.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -9,7 +9,7 @@
#include "compiler/translator/ArrayReturnValueToOutParameter.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -10,7 +10,7 @@
#include "BreakVariableAliasingInInnerLoops.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
// A HLSL compiler developer gave us more details on the root cause and the workaround needed:
// The root problem is that if the HLSL compiler is applying aliasing information even on
......
......@@ -4,10 +4,11 @@
// found in the LICENSE file.
//
#include "angle_gl.h"
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/SymbolTable.h"
#include "angle_gl.h"
#include "compiler/translator/Cache.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
......
......@@ -11,6 +11,7 @@
#include "compiler/translator/CallDAG.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
......
......@@ -20,6 +20,8 @@
#include "compiler/translator/Initialize.h"
#include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/IntermNodePatternMatcher.h"
#include "compiler/translator/IsASTDepthBelowLimit.h"
#include "compiler/translator/OutputTree.h"
#include "compiler/translator/ParseContext.h"
#include "compiler/translator/PruneEmptyDeclarations.h"
#include "compiler/translator/RegenerateStructNames.h"
......@@ -578,7 +580,7 @@ bool TCompiler::compile(const char *const shaderStrings[],
if (root)
{
if (compileOptions & SH_INTERMEDIATE_TREE)
TIntermediate::outputTree(root, infoSink.info);
OutputTree(root, infoSink.info);
if (compileOptions & SH_OBJECT_CODE)
translate(root, compileOptions);
......@@ -910,10 +912,7 @@ bool TCompiler::pruneUnusedFunctions(TIntermBlock *root)
bool TCompiler::limitExpressionComplexity(TIntermBlock *root)
{
TMaxDepthTraverser traverser(maxExpressionComplexity + 1);
root->traverse(&traverser);
if (traverser.getMaxDepth() > maxExpressionComplexity)
if (!IsASTDepthBelowLimit(root, maxExpressionComplexity))
{
mDiagnostics.globalError("Expression too complex.");
return false;
......
......@@ -11,7 +11,7 @@
#include "compiler/translator/FindMain.h"
#include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
......
......@@ -14,7 +14,7 @@
#include "compiler/translator/EmulateGLFragColorBroadcast.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -7,11 +7,11 @@
#ifndef COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
#define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
#include "GLSLANG/ShaderLang.h"
#include "common/angleutils.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/IntermTraverse.h"
// This class gathers all compound assignments from the AST and can then write
// the functions required for their precision emulation. This way there is no
......
......@@ -11,7 +11,7 @@
#include <cmath>
#include <cstdlib>
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -12,7 +12,7 @@
#include <set>
#include <string>
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -8,7 +8,7 @@
#include "compiler/translator/FindSymbolNode.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -7,7 +7,7 @@
#ifndef COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
#define COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
//
// Copyright (c) 2017 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.
//
#include "compiler/translator/HashNames.h"
namespace sh
{
TString HashName(const TString &name, ShHashFunction64 hashFunction)
{
if (hashFunction == nullptr || name.empty())
return name;
khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
TStringStream stream;
stream << HASHED_NAME_PREFIX << std::hex << number;
TString hashedName = stream.str();
return hashedName;
}
} // namespace sh
......@@ -9,10 +9,20 @@
#include <map>
#include "compiler/translator/IntermNode.h"
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/Common.h"
#define HASHED_NAME_PREFIX "webgl_"
namespace sh
{
typedef std::map<TPersistString, TPersistString> NameMap;
// Return the original name if hash function pointer is NULL;
// otherwise return the hashed name.
TString HashName(const TString &name, ShHashFunction64 hashFunction);
} // namespace sh
#endif // COMPILER_TRANSLATOR_HASHNAMES_H_
......@@ -9,7 +9,7 @@
#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
......
......@@ -18,7 +18,6 @@
#include "common/mathutil.h"
#include "common/matrix_utils.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
......@@ -3306,149 +3305,4 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
return resultArray;
}
// static
TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
{
if (hashFunction == nullptr || name.empty())
return name;
khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
TStringStream stream;
stream << HASHED_NAME_PREFIX << std::hex << number;
TString hashedName = stream.str();
return hashedName;
}
bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
const NodeInsertMultipleEntry &b)
{
if (a.parent != b.parent)
{
return a.parent > b.parent;
}
return a.position > b.position;
}
void TIntermTraverser::updateTree()
{
// Sort the insertions so that insertion position is decreasing. This way multiple insertions to
// the same parent node are handled correctly.
std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
for (size_t ii = 0; ii < mInsertions.size(); ++ii)
{
// We can't know here what the intended ordering of two insertions to the same position is,
// so it is not supported.
ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
mInsertions[ii].parent != mInsertions[ii - 1].parent);
const NodeInsertMultipleEntry &insertion = mInsertions[ii];
ASSERT(insertion.parent);
if (!insertion.insertionsAfter.empty())
{
bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
insertion.insertionsAfter);
ASSERT(inserted);
}
if (!insertion.insertionsBefore.empty())
{
bool inserted =
insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
ASSERT(inserted);
}
}
for (size_t ii = 0; ii < mReplacements.size(); ++ii)
{
const NodeUpdateEntry &replacement = mReplacements[ii];
ASSERT(replacement.parent);
bool replaced =
replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
ASSERT(replaced);
if (!replacement.originalBecomesChildOfReplacement)
{
// In AST traversing, a parent is visited before its children.
// After we replace a node, if its immediate child is to
// be replaced, we need to make sure we don't update the replaced
// node; instead, we update the replacement node.
for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
{
NodeUpdateEntry &replacement2 = mReplacements[jj];
if (replacement2.parent == replacement.original)
replacement2.parent = replacement.replacement;
}
}
}
for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
{
const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
ASSERT(replacement.parent);
bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
replacement.replacements);
ASSERT(replaced);
}
clearReplacementQueue();
}
void TIntermTraverser::clearReplacementQueue()
{
mReplacements.clear();
mMultiReplacements.clear();
mInsertions.clear();
}
void TIntermTraverser::queueReplacement(TIntermNode *original,
TIntermNode *replacement,
OriginalNode originalStatus)
{
queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
}
void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
TIntermNode *original,
TIntermNode *replacement,
OriginalNode originalStatus)
{
bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
}
TName TIntermTraverser::GetInternalFunctionName(const char *name)
{
TString nameStr(name);
TName nameObj(nameStr);
nameObj.setInternal(true);
return nameObj;
}
TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
const TType &returnType,
const char *name,
const TSymbolUniqueId &functionId)
{
TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
return functionNode;
}
TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
const TType &returnType,
const char *name,
TIntermBlock *functionBody,
const TSymbolUniqueId &functionId)
{
TIntermFunctionPrototype *prototypeNode =
CreateInternalFunctionPrototypeNode(returnType, name, functionId);
return new TIntermFunctionDefinition(prototypeNode, functionBody);
}
TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
const TType &returnType,
const char *name,
const TSymbolUniqueId &functionId,
TIntermSequence *arguments)
{
TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
returnType, functionId, GetInternalFunctionName(name), arguments);
return functionNode;
}
} // namespace sh
......@@ -910,391 +910,6 @@ class TIntermCase : public TIntermNode
TIntermTyped *mCondition;
};
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.
//
// The traverse*() functions may also be overridden do other bookkeeping on the tree to provide
// contextual information to the visit functions, such as whether the node is the target of an
// assignment.
//
// When using this, just fill in the methods for nodes you want visited.
// Return false from a pre-visit to skip visiting that node's subtree.
//
class TIntermTraverser : angle::NonCopyable
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TIntermTraverser(bool preVisit, bool inVisit, bool postVisit);
virtual ~TIntermTraverser();
virtual void visitSymbol(TIntermSymbol *node) {}
virtual void visitRaw(TIntermRaw *node) {}
virtual void visitConstantUnion(TIntermConstantUnion *node) {}
virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; }
virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; }
virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; }
virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
virtual bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
{
return true;
}
virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
{
return true;
}
virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; }
virtual bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
{
return true;
}
virtual bool visitDeclaration(Visit visit, TIntermDeclaration *node) { return true; }
virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
// 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 traverseRaw(TIntermRaw *node);
virtual void traverseConstantUnion(TIntermConstantUnion *node);
virtual void traverseSwizzle(TIntermSwizzle *node);
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; }
// Return the original name if hash function pointer is NULL;
// otherwise return the hashed name.
static TString hash(const TString &name, ShHashFunction64 hashFunction);
// If traversers need to replace nodes, they can add the replacements in
// mReplacements/mMultiReplacements during traversal and the user of the traverser should call
// this function after traversal to perform them.
void updateTree();
// Start creating temporary symbols from the given temporary symbol index + 1.
void useTemporaryId(TSymbolUniqueId *temporaryId);
static TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(
const TType &returnType,
const char *name,
const TSymbolUniqueId &functionId);
static TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(
const TType &returnType,
const char *name,
TIntermBlock *functionBody,
const TSymbolUniqueId &functionId);
static TIntermAggregate *CreateInternalFunctionCallNode(const TType &returnType,
const char *name,
const TSymbolUniqueId &functionId,
TIntermSequence *arguments);
protected:
// Should only be called from traverse*() functions
void incrementDepth(TIntermNode *current)
{
mDepth++;
mMaxDepth = std::max(mMaxDepth, mDepth);
mPath.push_back(current);
}
// Should only be called from traverse*() functions
void decrementDepth()
{
mDepth--;
mPath.pop_back();
}
// RAII helper for incrementDepth/decrementDepth
class ScopedNodeInTraversalPath
{
public:
ScopedNodeInTraversalPath(TIntermTraverser *traverser, TIntermNode *current)
: mTraverser(traverser)
{
mTraverser->incrementDepth(current);
}
~ScopedNodeInTraversalPath() { mTraverser->decrementDepth(); }
private:
TIntermTraverser *mTraverser;
};
TIntermNode *getParentNode() { return mPath.size() <= 1 ? nullptr : mPath[mPath.size() - 2u]; }
// Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode()
TIntermNode *getAncestorNode(unsigned int n)
{
if (mPath.size() > n + 1u)
{
return mPath[mPath.size() - n - 2u];
}
return nullptr;
}
void pushParentBlock(TIntermBlock *node);
void incrementParentBlockPos();
void popParentBlock();
// To replace a single node with multiple nodes on the parent aggregate node
struct NodeReplaceWithMultipleEntry
{
NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent,
TIntermNode *_original,
TIntermSequence _replacements)
: parent(_parent), original(_original), replacements(_replacements)
{
}
TIntermAggregateBase *parent;
TIntermNode *original;
TIntermSequence replacements;
};
// To insert multiple nodes on the parent aggregate node
struct NodeInsertMultipleEntry
{
NodeInsertMultipleEntry(TIntermBlock *_parent,
TIntermSequence::size_type _position,
TIntermSequence _insertionsBefore,
TIntermSequence _insertionsAfter)
: parent(_parent),
position(_position),
insertionsBefore(_insertionsBefore),
insertionsAfter(_insertionsAfter)
{
}
TIntermBlock *parent;
TIntermSequence::size_type position;
TIntermSequence insertionsBefore;
TIntermSequence insertionsAfter;
};
// Helper to insert statements in the parent block (sequence) of the node currently being
// traversed.
// The statements will be inserted before the node being traversed once updateTree is called.
// Should only be called during PreVisit or PostVisit from sequence nodes.
// Note that two insertions to the same position in the same block are not supported.
void insertStatementsInParentBlock(const TIntermSequence &insertions);
// Same as above, but supports simultaneous insertion of statements before and after the node
// currently being traversed.
void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
const TIntermSequence &insertionsAfter);
// Helper to insert a single statement.
void insertStatementInParentBlock(TIntermNode *statement);
// Helper to create a temporary symbol node with the given qualifier.
TIntermSymbol *createTempSymbol(const TType &type, TQualifier qualifier);
// Helper to create a temporary symbol node.
TIntermSymbol *createTempSymbol(const TType &type);
// Create a node that declares but doesn't initialize a temporary symbol.
TIntermDeclaration *createTempDeclaration(const TType &type);
// Create a node that initializes the current temporary symbol with initializer having the given
// qualifier.
TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
// Create a node that initializes the current temporary symbol with initializer.
TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer);
// Create a node that assigns rightNode to the current temporary symbol.
TIntermBinary *createTempAssignment(TIntermTyped *rightNode);
// Increment temporary symbol index.
void nextTemporaryId();
enum class OriginalNode
{
BECOMES_CHILD,
IS_DROPPED
};
void clearReplacementQueue();
void queueReplacement(TIntermNode *original,
TIntermNode *replacement,
OriginalNode originalStatus);
void queueReplacementWithParent(TIntermNode *parent,
TIntermNode *original,
TIntermNode *replacement,
OriginalNode originalStatus);
const bool preVisit;
const bool inVisit;
const bool postVisit;
int mDepth;
int mMaxDepth;
bool mInGlobalScope;
// During traversing, save all the changes that need to happen into
// mReplacements/mMultiReplacements, then do them by calling updateTree().
// Multi replacements are processed after single replacements.
std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
std::vector<NodeInsertMultipleEntry> mInsertions;
private:
static TName GetInternalFunctionName(const char *name);
static bool CompareInsertion(const NodeInsertMultipleEntry &a,
const NodeInsertMultipleEntry &b);
// To replace a single node with another on the parent node
struct NodeUpdateEntry
{
NodeUpdateEntry(TIntermNode *_parent,
TIntermNode *_original,
TIntermNode *_replacement,
bool _originalBecomesChildOfReplacement)
: parent(_parent),
original(_original),
replacement(_replacement),
originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement)
{
}
TIntermNode *parent;
TIntermNode *original;
TIntermNode *replacement;
bool originalBecomesChildOfReplacement;
};
struct ParentBlock
{
ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn)
: node(nodeIn), pos(posIn)
{
}
TIntermBlock *node;
TIntermSequence::size_type pos;
};
std::vector<NodeUpdateEntry> mReplacements;
// All the nodes from root to the current node during traversing.
TVector<TIntermNode *> mPath;
// All the code blocks from the root to the current node's parent during traversal.
std::vector<ParentBlock> mParentBlockStack;
TSymbolUniqueId *mTemporaryId;
};
// Traverser parent class that tracks where a node is a destination of a write operation and so is
// required to be an l-value.
class TLValueTrackingTraverser : public TIntermTraverser
{
public:
TLValueTrackingTraverser(bool preVisit,
bool inVisit,
bool postVisit,
const TSymbolTable &symbolTable,
int shaderVersion)
: TIntermTraverser(preVisit, inVisit, postVisit),
mOperatorRequiresLValue(false),
mInFunctionCallOutParameter(false),
mSymbolTable(symbolTable),
mShaderVersion(shaderVersion)
{
}
virtual ~TLValueTrackingTraverser() {}
void traverseBinary(TIntermBinary *node) final;
void traverseUnary(TIntermUnary *node) final;
void traverseFunctionPrototype(TIntermFunctionPrototype *node) final;
void traverseAggregate(TIntermAggregate *node) final;
protected:
bool isLValueRequiredHere() const
{
return mOperatorRequiresLValue || mInFunctionCallOutParameter;
}
private:
// Track whether an l-value is required in the node that is currently being traversed by the
// surrounding operator.
// Use isLValueRequiredHere to check all conditions which require an l-value.
void setOperatorRequiresLValue(bool lValueRequired)
{
mOperatorRequiresLValue = lValueRequired;
}
bool operatorRequiresLValue() const { return mOperatorRequiresLValue; }
// Add a function encountered during traversal to the function map.
void addToFunctionMap(const TSymbolUniqueId &id, TIntermSequence *paramSequence);
// Return true if the prototype or definition of the function being called has been encountered
// during traversal.
bool isInFunctionMap(const TIntermAggregate *callNode) const;
// Return the parameters sequence from the function definition or prototype.
TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode);
// Track whether an l-value is required inside a function call.
void setInFunctionCallOutParameter(bool inOutParameter);
bool isInFunctionCallOutParameter() const;
bool mOperatorRequiresLValue;
bool mInFunctionCallOutParameter;
// Map from function symbol id values to their parameter sequences
TMap<int, TIntermSequence *> mFunctionMap;
const TSymbolTable &mSymbolTable;
const int mShaderVersion;
};
//
// For traversing the tree, and computing max depth.
// Takes a maximum depth limit to prevent stack overflow.
//
class TMaxDepthTraverser : public TIntermTraverser
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TMaxDepthTraverser(int depthLimit)
: TIntermTraverser(true, true, false), mDepthLimit(depthLimit)
{
}
bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); }
bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); }
bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
protected:
bool depthCheck() const { return mMaxDepth < mDepthLimit; }
int mDepthLimit;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_INTERMNODE_H_
......@@ -4,7 +4,8 @@
// found in the LICENSE file.
//
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/SymbolTable.h"
......@@ -621,6 +622,152 @@ void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
visitAggregate(PostVisit, node);
}
bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
const NodeInsertMultipleEntry &b)
{
if (a.parent != b.parent)
{
return a.parent > b.parent;
}
return a.position > b.position;
}
void TIntermTraverser::updateTree()
{
// Sort the insertions so that insertion position is decreasing. This way multiple insertions to
// the same parent node are handled correctly.
std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
for (size_t ii = 0; ii < mInsertions.size(); ++ii)
{
// We can't know here what the intended ordering of two insertions to the same position is,
// so it is not supported.
ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
mInsertions[ii].parent != mInsertions[ii - 1].parent);
const NodeInsertMultipleEntry &insertion = mInsertions[ii];
ASSERT(insertion.parent);
if (!insertion.insertionsAfter.empty())
{
bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
insertion.insertionsAfter);
ASSERT(inserted);
}
if (!insertion.insertionsBefore.empty())
{
bool inserted =
insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
ASSERT(inserted);
}
}
for (size_t ii = 0; ii < mReplacements.size(); ++ii)
{
const NodeUpdateEntry &replacement = mReplacements[ii];
ASSERT(replacement.parent);
bool replaced =
replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
ASSERT(replaced);
if (!replacement.originalBecomesChildOfReplacement)
{
// In AST traversing, a parent is visited before its children.
// After we replace a node, if its immediate child is to
// be replaced, we need to make sure we don't update the replaced
// node; instead, we update the replacement node.
for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
{
NodeUpdateEntry &replacement2 = mReplacements[jj];
if (replacement2.parent == replacement.original)
replacement2.parent = replacement.replacement;
}
}
}
for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
{
const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
ASSERT(replacement.parent);
bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
replacement.replacements);
ASSERT(replaced);
}
clearReplacementQueue();
}
void TIntermTraverser::clearReplacementQueue()
{
mReplacements.clear();
mMultiReplacements.clear();
mInsertions.clear();
}
void TIntermTraverser::queueReplacement(TIntermNode *original,
TIntermNode *replacement,
OriginalNode originalStatus)
{
queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
}
void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
TIntermNode *original,
TIntermNode *replacement,
OriginalNode originalStatus)
{
bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
}
TName TIntermTraverser::GetInternalFunctionName(const char *name)
{
TString nameStr(name);
TName nameObj(nameStr);
nameObj.setInternal(true);
return nameObj;
}
TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
const TType &returnType,
const char *name,
const TSymbolUniqueId &functionId)
{
TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
return functionNode;
}
TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
const TType &returnType,
const char *name,
TIntermBlock *functionBody,
const TSymbolUniqueId &functionId)
{
TIntermFunctionPrototype *prototypeNode =
CreateInternalFunctionPrototypeNode(returnType, name, functionId);
return new TIntermFunctionDefinition(prototypeNode, functionBody);
}
TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
const TType &returnType,
const char *name,
const TSymbolUniqueId &functionId,
TIntermSequence *arguments)
{
TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
returnType, functionId, GetInternalFunctionName(name), arguments);
return functionNode;
}
TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
bool inVisit,
bool postVisit,
const TSymbolTable &symbolTable,
int shaderVersion)
: TIntermTraverser(preVisit, inVisit, postVisit),
mOperatorRequiresLValue(false),
mInFunctionCallOutParameter(false),
mSymbolTable(symbolTable),
mShaderVersion(shaderVersion)
{
}
void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
{
TIntermSequence *sequence = node->getSequence();
......
//
// Copyright (c) 2017 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.
//
// IntermTraverse.h : base classes for AST traversers that walk the AST and
// also have the ability to transform it by replacing nodes.
#ifndef COMPILER_TRANSLATOR_INTERMTRAVERSE_H_
#define COMPILER_TRANSLATOR_INTERMTRAVERSE_H_
#include "compiler/translator/IntermNode.h"
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.
//
// The traverse*() functions may also be overridden do other bookkeeping on the tree to provide
// contextual information to the visit functions, such as whether the node is the target of an
// assignment.
//
// When using this, just fill in the methods for nodes you want visited.
// Return false from a pre-visit to skip visiting that node's subtree.
//
class TIntermTraverser : angle::NonCopyable
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TIntermTraverser(bool preVisit, bool inVisit, bool postVisit);
virtual ~TIntermTraverser();
virtual void visitSymbol(TIntermSymbol *node) {}
virtual void visitRaw(TIntermRaw *node) {}
virtual void visitConstantUnion(TIntermConstantUnion *node) {}
virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; }
virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; }
virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; }
virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
virtual bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
{
return true;
}
virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
{
return true;
}
virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; }
virtual bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
{
return true;
}
virtual bool visitDeclaration(Visit visit, TIntermDeclaration *node) { return true; }
virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
// 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 traverseRaw(TIntermRaw *node);
virtual void traverseConstantUnion(TIntermConstantUnion *node);
virtual void traverseSwizzle(TIntermSwizzle *node);
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; }
// If traversers need to replace nodes, they can add the replacements in
// mReplacements/mMultiReplacements during traversal and the user of the traverser should call
// this function after traversal to perform them.
void updateTree();
// Start creating temporary symbols from the given temporary symbol index + 1.
void useTemporaryId(TSymbolUniqueId *temporaryId);
static TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(
const TType &returnType,
const char *name,
const TSymbolUniqueId &functionId);
static TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(
const TType &returnType,
const char *name,
TIntermBlock *functionBody,
const TSymbolUniqueId &functionId);
static TIntermAggregate *CreateInternalFunctionCallNode(const TType &returnType,
const char *name,
const TSymbolUniqueId &functionId,
TIntermSequence *arguments);
protected:
// Should only be called from traverse*() functions
void incrementDepth(TIntermNode *current)
{
mDepth++;
mMaxDepth = std::max(mMaxDepth, mDepth);
mPath.push_back(current);
}
// Should only be called from traverse*() functions
void decrementDepth()
{
mDepth--;
mPath.pop_back();
}
// RAII helper for incrementDepth/decrementDepth
class ScopedNodeInTraversalPath
{
public:
ScopedNodeInTraversalPath(TIntermTraverser *traverser, TIntermNode *current)
: mTraverser(traverser)
{
mTraverser->incrementDepth(current);
}
~ScopedNodeInTraversalPath() { mTraverser->decrementDepth(); }
private:
TIntermTraverser *mTraverser;
};
TIntermNode *getParentNode() { return mPath.size() <= 1 ? nullptr : mPath[mPath.size() - 2u]; }
// Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode()
TIntermNode *getAncestorNode(unsigned int n)
{
if (mPath.size() > n + 1u)
{
return mPath[mPath.size() - n - 2u];
}
return nullptr;
}
void pushParentBlock(TIntermBlock *node);
void incrementParentBlockPos();
void popParentBlock();
// To replace a single node with multiple nodes on the parent aggregate node
struct NodeReplaceWithMultipleEntry
{
NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent,
TIntermNode *_original,
TIntermSequence _replacements)
: parent(_parent), original(_original), replacements(_replacements)
{
}
TIntermAggregateBase *parent;
TIntermNode *original;
TIntermSequence replacements;
};
// To insert multiple nodes on the parent aggregate node
struct NodeInsertMultipleEntry
{
NodeInsertMultipleEntry(TIntermBlock *_parent,
TIntermSequence::size_type _position,
TIntermSequence _insertionsBefore,
TIntermSequence _insertionsAfter)
: parent(_parent),
position(_position),
insertionsBefore(_insertionsBefore),
insertionsAfter(_insertionsAfter)
{
}
TIntermBlock *parent;
TIntermSequence::size_type position;
TIntermSequence insertionsBefore;
TIntermSequence insertionsAfter;
};
// Helper to insert statements in the parent block (sequence) of the node currently being
// traversed.
// The statements will be inserted before the node being traversed once updateTree is called.
// Should only be called during PreVisit or PostVisit from sequence nodes.
// Note that two insertions to the same position in the same block are not supported.
void insertStatementsInParentBlock(const TIntermSequence &insertions);
// Same as above, but supports simultaneous insertion of statements before and after the node
// currently being traversed.
void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
const TIntermSequence &insertionsAfter);
// Helper to insert a single statement.
void insertStatementInParentBlock(TIntermNode *statement);
// Helper to create a temporary symbol node with the given qualifier.
TIntermSymbol *createTempSymbol(const TType &type, TQualifier qualifier);
// Helper to create a temporary symbol node.
TIntermSymbol *createTempSymbol(const TType &type);
// Create a node that declares but doesn't initialize a temporary symbol.
TIntermDeclaration *createTempDeclaration(const TType &type);
// Create a node that initializes the current temporary symbol with initializer having the given
// qualifier.
TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
// Create a node that initializes the current temporary symbol with initializer.
TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer);
// Create a node that assigns rightNode to the current temporary symbol.
TIntermBinary *createTempAssignment(TIntermTyped *rightNode);
// Increment temporary symbol index.
void nextTemporaryId();
enum class OriginalNode
{
BECOMES_CHILD,
IS_DROPPED
};
void clearReplacementQueue();
void queueReplacement(TIntermNode *original,
TIntermNode *replacement,
OriginalNode originalStatus);
void queueReplacementWithParent(TIntermNode *parent,
TIntermNode *original,
TIntermNode *replacement,
OriginalNode originalStatus);
const bool preVisit;
const bool inVisit;
const bool postVisit;
int mDepth;
int mMaxDepth;
bool mInGlobalScope;
// During traversing, save all the changes that need to happen into
// mReplacements/mMultiReplacements, then do them by calling updateTree().
// Multi replacements are processed after single replacements.
std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
std::vector<NodeInsertMultipleEntry> mInsertions;
private:
static TName GetInternalFunctionName(const char *name);
static bool CompareInsertion(const NodeInsertMultipleEntry &a,
const NodeInsertMultipleEntry &b);
// To replace a single node with another on the parent node
struct NodeUpdateEntry
{
NodeUpdateEntry(TIntermNode *_parent,
TIntermNode *_original,
TIntermNode *_replacement,
bool _originalBecomesChildOfReplacement)
: parent(_parent),
original(_original),
replacement(_replacement),
originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement)
{
}
TIntermNode *parent;
TIntermNode *original;
TIntermNode *replacement;
bool originalBecomesChildOfReplacement;
};
struct ParentBlock
{
ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn)
: node(nodeIn), pos(posIn)
{
}
TIntermBlock *node;
TIntermSequence::size_type pos;
};
std::vector<NodeUpdateEntry> mReplacements;
// All the nodes from root to the current node during traversing.
TVector<TIntermNode *> mPath;
// All the code blocks from the root to the current node's parent during traversal.
std::vector<ParentBlock> mParentBlockStack;
TSymbolUniqueId *mTemporaryId;
};
// Traverser parent class that tracks where a node is a destination of a write operation and so is
// required to be an l-value.
class TLValueTrackingTraverser : public TIntermTraverser
{
public:
TLValueTrackingTraverser(bool preVisit,
bool inVisit,
bool postVisit,
const TSymbolTable &symbolTable,
int shaderVersion);
virtual ~TLValueTrackingTraverser() {}
void traverseBinary(TIntermBinary *node) final;
void traverseUnary(TIntermUnary *node) final;
void traverseFunctionPrototype(TIntermFunctionPrototype *node) final;
void traverseAggregate(TIntermAggregate *node) final;
protected:
bool isLValueRequiredHere() const
{
return mOperatorRequiresLValue || mInFunctionCallOutParameter;
}
private:
// Track whether an l-value is required in the node that is currently being traversed by the
// surrounding operator.
// Use isLValueRequiredHere to check all conditions which require an l-value.
void setOperatorRequiresLValue(bool lValueRequired)
{
mOperatorRequiresLValue = lValueRequired;
}
bool operatorRequiresLValue() const { return mOperatorRequiresLValue; }
// Add a function encountered during traversal to the function map.
void addToFunctionMap(const TSymbolUniqueId &id, TIntermSequence *paramSequence);
// Return true if the prototype or definition of the function being called has been encountered
// during traversal.
bool isInFunctionMap(const TIntermAggregate *callNode) const;
// Return the parameters sequence from the function definition or prototype.
TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode);
// Track whether an l-value is required inside a function call.
void setInFunctionCallOutParameter(bool inOutParameter);
bool isInFunctionCallOutParameter() const;
bool mOperatorRequiresLValue;
bool mInFunctionCallOutParameter;
// Map from function symbol id values to their parameter sequences
TMap<int, TIntermSequence *> mFunctionMap;
const TSymbolTable &mSymbolTable;
const int mShaderVersion;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_INTERMTRAVERSE_H_
......@@ -54,8 +54,6 @@ class TIntermediate
const TVectorFields &fields,
const TSourceLoc &dotLocation);
static void outputTree(TIntermNode *, TInfoSinkBase &);
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
private:
......
//
// Copyright (c) 2017 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.
//
#include "compiler/translator/IsASTDepthBelowLimit.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
namespace
{
// Traverse the tree and compute max depth. Takes a maximum depth limit to prevent stack overflow.
class MaxDepthTraverser : public TIntermTraverser
{
public:
MaxDepthTraverser(int depthLimit) : TIntermTraverser(true, true, false), mDepthLimit(depthLimit)
{
}
bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
bool visitSwizzle(Visit, TIntermSwizzle *) override { return depthCheck(); }
bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); }
bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); }
bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
protected:
bool depthCheck() const { return mMaxDepth < mDepthLimit; }
int mDepthLimit;
};
} // anonymous namespace
bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth)
{
MaxDepthTraverser traverser(maxDepth + 1);
root->traverse(&traverser);
return traverser.getMaxDepth() <= maxDepth;
}
} // namespace sh
//
// Copyright (c) 2017 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.
//
// IsASTDepthBelowLimit: Check whether AST depth is below a specific limit.
#ifndef COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
#define COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
namespace sh
{
class TIntermNode;
bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth);
} // namespace sh
#endif // COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
......@@ -9,7 +9,7 @@
#ifndef COMPILER_TRANSLATOR_NODESEARCH_H_
#define COMPILER_TRANSLATOR_NODESEARCH_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -6,6 +6,8 @@
#include "compiler/translator/OutputGLSL.h"
#include "compiler/translator/Compiler.h"
namespace sh
{
......
......@@ -8,6 +8,7 @@
#include "common/debug.h"
#include "common/mathutil.h"
#include "compiler/translator/Compiler.h"
#include <cfloat>
......@@ -1160,7 +1161,7 @@ TString TOutputGLSLBase::hashName(const TName &name)
NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
if (it != mNameMap.end())
return it->second.c_str();
TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
TString hashedName = HashName(name.getString(), mHashFunction);
mNameMap[name.getString().c_str()] = hashedName.c_str();
return hashedName;
}
......
......@@ -9,8 +9,9 @@
#include <set>
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/ParseContext.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -13,8 +13,8 @@
#include "angle_gl.h"
#include "compiler/translator/ASTMetadataHLSL.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/ParseContext.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/IntermTraverse.h"
class BuiltInFunctionEmulator;
......
//
// Copyright (c) 2002-2014 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.
//
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
namespace
{
void OutputFunction(TInfoSinkBase &out, const char *str, TFunctionSymbolInfo *info)
{
const char *internal = info->getNameObj().isInternal() ? " (internal function)" : "";
out << str << internal << ": " << info->getNameObj().getString() << " (symbol id "
<< info->getId().get() << ")";
}
// Two purposes:
// 1. Show an example of how to iterate tree. Functions can also directly call traverse() on
// children themselves to have finer grained control over the process than shown here, though
// that's not recommended if it can be avoided.
// 2. Print out a text based description of the tree.
// The traverser subclass is used to carry along data from node to node in the traversal.
class TOutputTraverser : public TIntermTraverser
{
public:
TOutputTraverser(TInfoSinkBase &out) : TIntermTraverser(true, false, false), mOut(out) {}
protected:
void visitSymbol(TIntermSymbol *) override;
void visitConstantUnion(TIntermConstantUnion *) override;
bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
bool visitBinary(Visit visit, TIntermBinary *) override;
bool visitUnary(Visit visit, TIntermUnary *) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
bool visitIfElse(Visit visit, TIntermIfElse *node) override;
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
bool visitCase(Visit visit, TIntermCase *node) override;
bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *) override;
bool visitBlock(Visit visit, TIntermBlock *) override;
bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
bool visitLoop(Visit visit, TIntermLoop *) override;
bool visitBranch(Visit visit, TIntermBranch *) override;
TInfoSinkBase &mOut;
};
//
// Helper functions for printing, not part of traversing.
//
void OutputTreeText(TInfoSinkBase &out, TIntermNode *node, const int depth)
{
int i;
out.location(node->getLine().first_file, node->getLine().first_line);
for (i = 0; i < depth; ++i)
out << " ";
}
//
// The rest of the file are the traversal functions. The last one
// is the one that starts the traversal.
//
// Return true from interior nodes to have the external traversal
// continue on to children. If you process children yourself,
// return false.
//
void TOutputTraverser::visitSymbol(TIntermSymbol *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "'" << node->getSymbol() << "' ";
mOut << "(symbol id " << node->getId() << ") ";
mOut << "(" << node->getCompleteString() << ")";
mOut << "\n";
}
bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "vector swizzle (";
node->writeOffsetsAsXYZW(&mOut);
mOut << ")";
mOut << " (" << node->getCompleteString() << ")";
mOut << "\n";
return true;
}
bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
{
OutputTreeText(mOut, node, mDepth);
switch (node->getOp())
{
case EOpComma:
mOut << "comma";
break;
case EOpAssign:
mOut << "move second child to first child";
break;
case EOpInitialize:
mOut << "initialize first child with second child";
break;
case EOpAddAssign:
mOut << "add second child into first child";
break;
case EOpSubAssign:
mOut << "subtract second child into first child";
break;
case EOpMulAssign:
mOut << "multiply second child into first child";
break;
case EOpVectorTimesMatrixAssign:
mOut << "matrix mult second child into first child";
break;
case EOpVectorTimesScalarAssign:
mOut << "vector scale second child into first child";
break;
case EOpMatrixTimesScalarAssign:
mOut << "matrix scale second child into first child";
break;
case EOpMatrixTimesMatrixAssign:
mOut << "matrix mult second child into first child";
break;
case EOpDivAssign:
mOut << "divide second child into first child";
break;
case EOpIModAssign:
mOut << "modulo second child into first child";
break;
case EOpBitShiftLeftAssign:
mOut << "bit-wise shift first child left by second child";
break;
case EOpBitShiftRightAssign:
mOut << "bit-wise shift first child right by second child";
break;
case EOpBitwiseAndAssign:
mOut << "bit-wise and second child into first child";
break;
case EOpBitwiseXorAssign:
mOut << "bit-wise xor second child into first child";
break;
case EOpBitwiseOrAssign:
mOut << "bit-wise or second child into first child";
break;
case EOpIndexDirect:
mOut << "direct index";
break;
case EOpIndexIndirect:
mOut << "indirect index";
break;
case EOpIndexDirectStruct:
mOut << "direct index for structure";
break;
case EOpIndexDirectInterfaceBlock:
mOut << "direct index for interface block";
break;
case EOpAdd:
mOut << "add";
break;
case EOpSub:
mOut << "subtract";
break;
case EOpMul:
mOut << "component-wise multiply";
break;
case EOpDiv:
mOut << "divide";
break;
case EOpIMod:
mOut << "modulo";
break;
case EOpBitShiftLeft:
mOut << "bit-wise shift left";
break;
case EOpBitShiftRight:
mOut << "bit-wise shift right";
break;
case EOpBitwiseAnd:
mOut << "bit-wise and";
break;
case EOpBitwiseXor:
mOut << "bit-wise xor";
break;
case EOpBitwiseOr:
mOut << "bit-wise or";
break;
case EOpEqual:
mOut << "Compare Equal";
break;
case EOpNotEqual:
mOut << "Compare Not Equal";
break;
case EOpLessThan:
mOut << "Compare Less Than";
break;
case EOpGreaterThan:
mOut << "Compare Greater Than";
break;
case EOpLessThanEqual:
mOut << "Compare Less Than or Equal";
break;
case EOpGreaterThanEqual:
mOut << "Compare Greater Than or Equal";
break;
case EOpVectorTimesScalar:
mOut << "vector-scale";
break;
case EOpVectorTimesMatrix:
mOut << "vector-times-matrix";
break;
case EOpMatrixTimesVector:
mOut << "matrix-times-vector";
break;
case EOpMatrixTimesScalar:
mOut << "matrix-scale";
break;
case EOpMatrixTimesMatrix:
mOut << "matrix-multiply";
break;
case EOpLogicalOr:
mOut << "logical-or";
break;
case EOpLogicalXor:
mOut << "logical-xor";
break;
case EOpLogicalAnd:
mOut << "logical-and";
break;
default:
mOut << "<unknown op>";
}
mOut << " (" << node->getCompleteString() << ")";
mOut << "\n";
// Special handling for direct indexes. Because constant
// unions are not aware they are struct indexes, treat them
// here where we have that contextual knowledge.
if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
{
node->getLeft()->traverse(this);
TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
ASSERT(intermConstantUnion);
OutputTreeText(mOut, intermConstantUnion, mDepth + 1);
// The following code finds the field name from the constant union
const TConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer();
const TStructure *structure = node->getLeft()->getType().getStruct();
const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
ASSERT(structure || interfaceBlock);
const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
const TField *field = fields[constantUnion->getIConst()];
mOut << constantUnion->getIConst() << " (field '" << field->name() << "')";
mOut << "\n";
return false;
}
return true;
}
bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
{
OutputTreeText(mOut, node, mDepth);
switch (node->getOp())
{
// Give verbose names for ops that have special syntax and some built-in functions that are
// easy to confuse with others, but mostly use GLSL names for functions.
case EOpNegative:
mOut << "Negate value";
break;
case EOpPositive:
mOut << "Positive sign";
break;
case EOpLogicalNot:
mOut << "negation";
break;
case EOpBitwiseNot:
mOut << "bit-wise not";
break;
case EOpPostIncrement:
mOut << "Post-Increment";
break;
case EOpPostDecrement:
mOut << "Post-Decrement";
break;
case EOpPreIncrement:
mOut << "Pre-Increment";
break;
case EOpPreDecrement:
mOut << "Pre-Decrement";
break;
case EOpLogicalNotComponentWise:
mOut << "component-wise not";
break;
default:
mOut << GetOperatorString(node->getOp());
break;
}
mOut << " (" << node->getCompleteString() << ")";
mOut << "\n";
return true;
}
bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "Function Definition:\n";
mOut << "\n";
return true;
}
bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "Invariant Declaration:\n";
return true;
}
bool TOutputTraverser::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
{
OutputTreeText(mOut, node, mDepth);
OutputFunction(mOut, "Function Prototype", node->getFunctionSymbolInfo());
mOut << " (" << node->getCompleteString() << ")";
mOut << "\n";
return true;
}
bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
OutputTreeText(mOut, node, mDepth);
if (node->getOp() == EOpNull)
{
mOut.prefix(SH_ERROR);
mOut << "node is still EOpNull!\n";
return true;
}
// Give verbose names for some built-in functions that are easy to confuse with others, but
// mostly use GLSL names for functions.
switch (node->getOp())
{
case EOpCallFunctionInAST:
OutputFunction(mOut, "Call an user-defined function", node->getFunctionSymbolInfo());
break;
case EOpCallInternalRawFunction:
OutputFunction(mOut, "Call an internal function with raw implementation",
node->getFunctionSymbolInfo());
break;
case EOpCallBuiltInFunction:
OutputFunction(mOut, "Call a built-in function", node->getFunctionSymbolInfo());
break;
case EOpConstruct:
// The type of the constructor will be printed below.
mOut << "Construct";
break;
case EOpEqualComponentWise:
mOut << "component-wise equal";
break;
case EOpNotEqualComponentWise:
mOut << "component-wise not equal";
break;
case EOpLessThanComponentWise:
mOut << "component-wise less than";
break;
case EOpGreaterThanComponentWise:
mOut << "component-wise greater than";
break;
case EOpLessThanEqualComponentWise:
mOut << "component-wise less than or equal";
break;
case EOpGreaterThanEqualComponentWise:
mOut << "component-wise greater than or equal";
break;
case EOpDot:
mOut << "dot product";
break;
case EOpCross:
mOut << "cross product";
break;
case EOpMulMatrixComponentWise:
mOut << "component-wise multiply";
break;
default:
mOut << GetOperatorString(node->getOp());
break;
}
mOut << " (" << node->getCompleteString() << ")";
mOut << "\n";
return true;
}
bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "Code block\n";
return true;
}
bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "Declaration\n";
return true;
}
bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "Ternary selection";
mOut << " (" << node->getCompleteString() << ")\n";
++mDepth;
OutputTreeText(mOut, node, mDepth);
mOut << "Condition\n";
node->getCondition()->traverse(this);
OutputTreeText(mOut, node, mDepth);
if (node->getTrueExpression())
{
mOut << "true case\n";
node->getTrueExpression()->traverse(this);
}
if (node->getFalseExpression())
{
OutputTreeText(mOut, node, mDepth);
mOut << "false case\n";
node->getFalseExpression()->traverse(this);
}
--mDepth;
return false;
}
bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "If test\n";
++mDepth;
OutputTreeText(mOut, node, mDepth);
mOut << "Condition\n";
node->getCondition()->traverse(this);
OutputTreeText(mOut, node, mDepth);
if (node->getTrueBlock())
{
mOut << "true case\n";
node->getTrueBlock()->traverse(this);
}
else
{
mOut << "true case is null\n";
}
if (node->getFalseBlock())
{
OutputTreeText(mOut, node, mDepth);
mOut << "false case\n";
node->getFalseBlock()->traverse(this);
}
--mDepth;
return false;
}
bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "Switch\n";
return true;
}
bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
{
OutputTreeText(mOut, node, mDepth);
if (node->getCondition() == nullptr)
{
mOut << "Default\n";
}
else
{
mOut << "Case\n";
}
return true;
}
void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
{
size_t size = node->getType().getObjectSize();
for (size_t i = 0; i < size; i++)
{
OutputTreeText(mOut, node, mDepth);
switch (node->getUnionArrayPointer()[i].getType())
{
case EbtBool:
if (node->getUnionArrayPointer()[i].getBConst())
mOut << "true";
else
mOut << "false";
mOut << " ("
<< "const bool"
<< ")";
mOut << "\n";
break;
case EbtFloat:
mOut << node->getUnionArrayPointer()[i].getFConst();
mOut << " (const float)\n";
break;
case EbtInt:
mOut << node->getUnionArrayPointer()[i].getIConst();
mOut << " (const int)\n";
break;
case EbtUInt:
mOut << node->getUnionArrayPointer()[i].getUConst();
mOut << " (const uint)\n";
break;
case EbtYuvCscStandardEXT:
mOut << getYuvCscStandardEXTString(
node->getUnionArrayPointer()[i].getYuvCscStandardEXTConst());
mOut << " (const yuvCscStandardEXT)\n";
break;
default:
mOut.prefix(SH_ERROR);
mOut << "Unknown constant\n";
break;
}
}
}
bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
{
OutputTreeText(mOut, node, mDepth);
mOut << "Loop with condition ";
if (node->getType() == ELoopDoWhile)
mOut << "not ";
mOut << "tested first\n";
++mDepth;
OutputTreeText(mOut, node, mDepth);
if (node->getCondition())
{
mOut << "Loop Condition\n";
node->getCondition()->traverse(this);
}
else
{
mOut << "No loop condition\n";
}
OutputTreeText(mOut, node, mDepth);
if (node->getBody())
{
mOut << "Loop Body\n";
node->getBody()->traverse(this);
}
else
{
mOut << "No loop body\n";
}
if (node->getExpression())
{
OutputTreeText(mOut, node, mDepth);
mOut << "Loop Terminal Expression\n";
node->getExpression()->traverse(this);
}
--mDepth;
return false;
}
bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
{
OutputTreeText(mOut, node, mDepth);
switch (node->getFlowOp())
{
case EOpKill:
mOut << "Branch: Kill";
break;
case EOpBreak:
mOut << "Branch: Break";
break;
case EOpContinue:
mOut << "Branch: Continue";
break;
case EOpReturn:
mOut << "Branch: Return";
break;
default:
mOut << "Branch: Unknown Branch";
break;
}
if (node->getExpression())
{
mOut << " with expression\n";
++mDepth;
node->getExpression()->traverse(this);
--mDepth;
}
else
{
mOut << "\n";
}
return false;
}
} // anonymous namespace
void OutputTree(TIntermNode *root, TInfoSinkBase &out)
{
TOutputTraverser it(out);
ASSERT(root);
root->traverse(&it);
}
} // namespace sh
//
// Copyright (c) 2017 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.
//
// Output the AST intermediate representation of the GLSL code.
#ifndef COMPILER_TRANSLATOR_OUTPUTTREE_H_
#define COMPILER_TRANSLATOR_OUTPUTTREE_H_
namespace sh
{
class TIntermNode;
class TInfoSinkBase;
// Output the AST along with metadata.
void OutputTree(TIntermNode *root, TInfoSinkBase &out);
} // namespace sh
#endif // COMPILER_TRANSLATOR_OUTPUTTREE_H_
\ No newline at end of file
......@@ -8,7 +8,7 @@
#include "compiler/translator/PruneEmptyDeclarations.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -7,7 +7,7 @@
#include "compiler/translator/PrunePureLiteralStatements.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -17,7 +17,7 @@
#include "compiler/translator/RecordConstantPrecision.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -7,7 +7,7 @@
#ifndef COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_
#define COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_
#include "compiler/translator/Intermediate.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
#include <set>
......
......@@ -10,8 +10,8 @@
#include "compiler/translator/RemoveDynamicIndexing.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNodePatternMatcher.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
......
......@@ -6,7 +6,7 @@
#include "compiler/translator/RemoveInvariantDeclaration.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -11,7 +11,7 @@
#include "compiler/translator/RemovePow.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -7,7 +7,7 @@
#ifndef COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_
#define COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -9,7 +9,7 @@
#include "compiler/translator/RewriteDoWhile.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -9,7 +9,7 @@
#include "compiler/translator/RewriteTexelFetchOffset.h"
#include "common/angleutils.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
......
......@@ -6,7 +6,7 @@
#include "compiler/translator/RewriteUnaryMinusOperatorFloat.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -8,7 +8,7 @@
#include "compiler/translator/RewriteUnaryMinusOperatorInt.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -15,7 +15,7 @@
#include "angle_gl.h"
#include "common/angleutils.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -9,7 +9,7 @@
#ifndef COMPILER_TRANSLATOR_SEARCHSYMBOL_H_
#define COMPILER_TRANSLATOR_SEARCHSYMBOL_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/ParseContext.h"
namespace sh
......
......@@ -15,7 +15,7 @@
#include "compiler/translator/SeparateDeclarations.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -11,8 +11,8 @@
#include "compiler/translator/SeparateExpressionsReturningArrays.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNodePatternMatcher.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -10,8 +10,8 @@
#include "compiler/translator/SimplifyLoopConditions.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNodePatternMatcher.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -11,8 +11,8 @@
#include "compiler/translator/SplitSequenceOperator.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNodePatternMatcher.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -11,7 +11,7 @@
#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_
#include "common/angleutils.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -11,8 +11,8 @@
#include "compiler/translator/UnfoldShortCircuitToIf.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNodePatternMatcher.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -6,6 +6,7 @@
#include "compiler/translator/ValidateGlobalInitializer.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/ParseContext.h"
namespace sh
......
......@@ -8,6 +8,7 @@
#include "angle_gl.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/ParseContext.h"
namespace sh
......
......@@ -15,7 +15,7 @@
#include "angle_gl.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/FindSymbolNode.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
......
......@@ -12,7 +12,7 @@
#include <set>
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/ParseContext.h"
namespace sh
......
......@@ -6,8 +6,8 @@
#include "compiler/translator/ValidateSwitch.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -8,7 +8,8 @@
#include "angle_gl.h"
#include "common/utilities.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
......@@ -440,7 +441,7 @@ void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
}
}
variableOut->name = name.c_str();
variableOut->mappedName = TIntermTraverser::hash(name, mHashFunction).c_str();
variableOut->mappedName = HashName(name, mHashFunction).c_str();
variableOut->arraySize = type.getArraySize();
}
......@@ -504,8 +505,7 @@ InterfaceBlock CollectVariablesTraverser::recordInterfaceBlock(const TIntermSymb
InterfaceBlock interfaceBlock;
interfaceBlock.name = blockType->name().c_str();
interfaceBlock.mappedName =
TIntermTraverser::hash(blockType->name().c_str(), mHashFunction).c_str();
interfaceBlock.mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
interfaceBlock.instanceName =
(blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
interfaceBlock.arraySize = variable.getArraySize();
......
......@@ -7,7 +7,7 @@
#ifndef COMPILER_TRANSLATOR_VERSIONGLSL_H_
#define COMPILER_TRANSLATOR_VERSIONGLSL_H_
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/Pragma.h"
......
//
// Copyright (c) 2002-2014 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.
//
#include "compiler/translator/Intermediate.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
namespace
{
void OutputFunction(TInfoSinkBase &out, const char *str, TFunctionSymbolInfo *info)
{
const char *internal = info->getNameObj().isInternal() ? " (internal function)" : "";
out << str << internal << ": " << info->getNameObj().getString() << " (symbol id "
<< info->getId().get() << ")";
}
//
// Two purposes:
// 1. Show an example of how to iterate tree. Functions can
// also directly call Traverse() on children themselves to
// have finer grained control over the process than shown here.
// See the last function for how to get started.
// 2. Print out a text based description of the tree.
//
//
// Use this class to carry along data from node to node in
// the traversal
//
class TOutputTraverser : public TIntermTraverser
{
public:
TOutputTraverser(TInfoSinkBase &i) : TIntermTraverser(true, false, false), sink(i) {}
TInfoSinkBase &sink;
protected:
void visitSymbol(TIntermSymbol *) override;
void visitConstantUnion(TIntermConstantUnion *) override;
bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
bool visitBinary(Visit visit, TIntermBinary *) override;
bool visitUnary(Visit visit, TIntermUnary *) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
bool visitIfElse(Visit visit, TIntermIfElse *node) override;
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
bool visitCase(Visit visit, TIntermCase *node) override;
bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *) override;
bool visitBlock(Visit visit, TIntermBlock *) override;
bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
bool visitLoop(Visit visit, TIntermLoop *) override;
bool visitBranch(Visit visit, TIntermBranch *) override;
};
//
// Helper functions for printing, not part of traversing.
//
void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
{
int i;
sink.location(node->getLine().first_file, node->getLine().first_line);
for (i = 0; i < depth; ++i)
sink << " ";
}
} // namespace anonymous
//
// The rest of the file are the traversal functions. The last one
// is the one that starts the traversal.
//
// Return true from interior nodes to have the external traversal
// continue on to children. If you process children yourself,
// return false.
//
void TOutputTraverser::visitSymbol(TIntermSymbol *node)
{
OutputTreeText(sink, node, mDepth);
sink << "'" << node->getSymbol() << "' ";
sink << "(symbol id " << node->getId() << ") ";
sink << "(" << node->getCompleteString() << ")";
sink << "\n";
}
bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "vector swizzle (";
node->writeOffsetsAsXYZW(&out);
out << ")";
out << " (" << node->getCompleteString() << ")";
out << "\n";
return true;
}
bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
switch (node->getOp())
{
case EOpComma:
out << "comma";
break;
case EOpAssign:
out << "move second child to first child";
break;
case EOpInitialize:
out << "initialize first child with second child";
break;
case EOpAddAssign:
out << "add second child into first child";
break;
case EOpSubAssign:
out << "subtract second child into first child";
break;
case EOpMulAssign:
out << "multiply second child into first child";
break;
case EOpVectorTimesMatrixAssign:
out << "matrix mult second child into first child";
break;
case EOpVectorTimesScalarAssign:
out << "vector scale second child into first child";
break;
case EOpMatrixTimesScalarAssign:
out << "matrix scale second child into first child";
break;
case EOpMatrixTimesMatrixAssign:
out << "matrix mult second child into first child";
break;
case EOpDivAssign:
out << "divide second child into first child";
break;
case EOpIModAssign:
out << "modulo second child into first child";
break;
case EOpBitShiftLeftAssign:
out << "bit-wise shift first child left by second child";
break;
case EOpBitShiftRightAssign:
out << "bit-wise shift first child right by second child";
break;
case EOpBitwiseAndAssign:
out << "bit-wise and second child into first child";
break;
case EOpBitwiseXorAssign:
out << "bit-wise xor second child into first child";
break;
case EOpBitwiseOrAssign:
out << "bit-wise or second child into first child";
break;
case EOpIndexDirect:
out << "direct index";
break;
case EOpIndexIndirect:
out << "indirect index";
break;
case EOpIndexDirectStruct:
out << "direct index for structure";
break;
case EOpIndexDirectInterfaceBlock:
out << "direct index for interface block";
break;
case EOpAdd:
out << "add";
break;
case EOpSub:
out << "subtract";
break;
case EOpMul:
out << "component-wise multiply";
break;
case EOpDiv:
out << "divide";
break;
case EOpIMod:
out << "modulo";
break;
case EOpBitShiftLeft:
out << "bit-wise shift left";
break;
case EOpBitShiftRight:
out << "bit-wise shift right";
break;
case EOpBitwiseAnd:
out << "bit-wise and";
break;
case EOpBitwiseXor:
out << "bit-wise xor";
break;
case EOpBitwiseOr:
out << "bit-wise or";
break;
case EOpEqual:
out << "Compare Equal";
break;
case EOpNotEqual:
out << "Compare Not Equal";
break;
case EOpLessThan:
out << "Compare Less Than";
break;
case EOpGreaterThan:
out << "Compare Greater Than";
break;
case EOpLessThanEqual:
out << "Compare Less Than or Equal";
break;
case EOpGreaterThanEqual:
out << "Compare Greater Than or Equal";
break;
case EOpVectorTimesScalar:
out << "vector-scale";
break;
case EOpVectorTimesMatrix:
out << "vector-times-matrix";
break;
case EOpMatrixTimesVector:
out << "matrix-times-vector";
break;
case EOpMatrixTimesScalar:
out << "matrix-scale";
break;
case EOpMatrixTimesMatrix:
out << "matrix-multiply";
break;
case EOpLogicalOr:
out << "logical-or";
break;
case EOpLogicalXor:
out << "logical-xor";
break;
case EOpLogicalAnd:
out << "logical-and";
break;
default:
out << "<unknown op>";
}
out << " (" << node->getCompleteString() << ")";
out << "\n";
// Special handling for direct indexes. Because constant
// unions are not aware they are struct indexes, treat them
// here where we have that contextual knowledge.
if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
{
node->getLeft()->traverse(this);
TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
ASSERT(intermConstantUnion);
OutputTreeText(out, intermConstantUnion, mDepth + 1);
// The following code finds the field name from the constant union
const TConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer();
const TStructure *structure = node->getLeft()->getType().getStruct();
const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
ASSERT(structure || interfaceBlock);
const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
const TField *field = fields[constantUnion->getIConst()];
out << constantUnion->getIConst() << " (field '" << field->name() << "')";
out << "\n";
return false;
}
return true;
}
bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
switch (node->getOp())
{
// Give verbose names for ops that have special syntax and some built-in functions that are
// easy to confuse with others, but mostly use GLSL names for functions.
case EOpNegative:
out << "Negate value";
break;
case EOpPositive:
out << "Positive sign";
break;
case EOpLogicalNot:
out << "negation";
break;
case EOpBitwiseNot:
out << "bit-wise not";
break;
case EOpPostIncrement:
out << "Post-Increment";
break;
case EOpPostDecrement:
out << "Post-Decrement";
break;
case EOpPreIncrement:
out << "Pre-Increment";
break;
case EOpPreDecrement:
out << "Pre-Decrement";
break;
case EOpLogicalNotComponentWise:
out << "component-wise not";
break;
default:
out << GetOperatorString(node->getOp());
break;
}
out << " (" << node->getCompleteString() << ")";
out << "\n";
return true;
}
bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Function Definition:\n";
out << "\n";
return true;
}
bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Invariant Declaration:\n";
return true;
}
bool TOutputTraverser::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
OutputFunction(out, "Function Prototype", node->getFunctionSymbolInfo());
out << " (" << node->getCompleteString() << ")";
out << "\n";
return true;
}
bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
if (node->getOp() == EOpNull)
{
out.prefix(SH_ERROR);
out << "node is still EOpNull!\n";
return true;
}
// Give verbose names for some built-in functions that are easy to confuse with others, but
// mostly use GLSL names for functions.
switch (node->getOp())
{
case EOpCallFunctionInAST:
OutputFunction(out, "Call an user-defined function", node->getFunctionSymbolInfo());
break;
case EOpCallInternalRawFunction:
OutputFunction(out, "Call an internal function with raw implementation",
node->getFunctionSymbolInfo());
break;
case EOpCallBuiltInFunction:
OutputFunction(out, "Call a built-in function", node->getFunctionSymbolInfo());
break;
case EOpConstruct:
// The type of the constructor will be printed below.
out << "Construct";
break;
case EOpEqualComponentWise:
out << "component-wise equal";
break;
case EOpNotEqualComponentWise:
out << "component-wise not equal";
break;
case EOpLessThanComponentWise:
out << "component-wise less than";
break;
case EOpGreaterThanComponentWise:
out << "component-wise greater than";
break;
case EOpLessThanEqualComponentWise:
out << "component-wise less than or equal";
break;
case EOpGreaterThanEqualComponentWise:
out << "component-wise greater than or equal";
break;
case EOpDot:
out << "dot product";
break;
case EOpCross:
out << "cross product";
break;
case EOpMulMatrixComponentWise:
out << "component-wise multiply";
break;
default:
out << GetOperatorString(node->getOp());
break;
}
out << " (" << node->getCompleteString() << ")";
out << "\n";
return true;
}
bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Code block\n";
return true;
}
bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Declaration\n";
return true;
}
bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Ternary selection";
out << " (" << node->getCompleteString() << ")\n";
++mDepth;
OutputTreeText(sink, node, mDepth);
out << "Condition\n";
node->getCondition()->traverse(this);
OutputTreeText(sink, node, mDepth);
if (node->getTrueExpression())
{
out << "true case\n";
node->getTrueExpression()->traverse(this);
}
if (node->getFalseExpression())
{
OutputTreeText(sink, node, mDepth);
out << "false case\n";
node->getFalseExpression()->traverse(this);
}
--mDepth;
return false;
}
bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "If test\n";
++mDepth;
OutputTreeText(sink, node, mDepth);
out << "Condition\n";
node->getCondition()->traverse(this);
OutputTreeText(sink, node, mDepth);
if (node->getTrueBlock())
{
out << "true case\n";
node->getTrueBlock()->traverse(this);
}
else
{
out << "true case is null\n";
}
if (node->getFalseBlock())
{
OutputTreeText(sink, node, mDepth);
out << "false case\n";
node->getFalseBlock()->traverse(this);
}
--mDepth;
return false;
}
bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Switch\n";
return true;
}
bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
if (node->getCondition() == nullptr)
{
out << "Default\n";
}
else
{
out << "Case\n";
}
return true;
}
void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
{
TInfoSinkBase &out = sink;
size_t size = node->getType().getObjectSize();
for (size_t i = 0; i < size; i++)
{
OutputTreeText(out, node, mDepth);
switch (node->getUnionArrayPointer()[i].getType())
{
case EbtBool:
if (node->getUnionArrayPointer()[i].getBConst())
out << "true";
else
out << "false";
out << " ("
<< "const bool"
<< ")";
out << "\n";
break;
case EbtFloat:
out << node->getUnionArrayPointer()[i].getFConst();
out << " (const float)\n";
break;
case EbtInt:
out << node->getUnionArrayPointer()[i].getIConst();
out << " (const int)\n";
break;
case EbtUInt:
out << node->getUnionArrayPointer()[i].getUConst();
out << " (const uint)\n";
break;
case EbtYuvCscStandardEXT:
out << getYuvCscStandardEXTString(
node->getUnionArrayPointer()[i].getYuvCscStandardEXTConst());
out << " (const yuvCscStandardEXT)\n";
break;
default:
out.prefix(SH_ERROR);
out << "Unknown constant\n";
break;
}
}
}
bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
out << "Loop with condition ";
if (node->getType() == ELoopDoWhile)
out << "not ";
out << "tested first\n";
++mDepth;
OutputTreeText(sink, node, mDepth);
if (node->getCondition())
{
out << "Loop Condition\n";
node->getCondition()->traverse(this);
}
else
{
out << "No loop condition\n";
}
OutputTreeText(sink, node, mDepth);
if (node->getBody())
{
out << "Loop Body\n";
node->getBody()->traverse(this);
}
else
{
out << "No loop body\n";
}
if (node->getExpression())
{
OutputTreeText(sink, node, mDepth);
out << "Loop Terminal Expression\n";
node->getExpression()->traverse(this);
}
--mDepth;
return false;
}
bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
{
TInfoSinkBase &out = sink;
OutputTreeText(out, node, mDepth);
switch (node->getFlowOp())
{
case EOpKill:
out << "Branch: Kill";
break;
case EOpBreak:
out << "Branch: Break";
break;
case EOpContinue:
out << "Branch: Continue";
break;
case EOpReturn:
out << "Branch: Return";
break;
default:
out << "Branch: Unknown Branch";
break;
}
if (node->getExpression())
{
out << " with expression\n";
++mDepth;
node->getExpression()->traverse(this);
--mDepth;
}
else
{
out << "\n";
}
return false;
}
//
// This function is the one to call externally to start the traversal.
// Individual functions can be initialized to 0 to skip processing of that
// type of node. Its children will still be processed.
//
void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink)
{
TOutputTraverser it(infoSink);
ASSERT(root);
root->traverse(&it);
}
} // namespace sh
......@@ -10,7 +10,7 @@
#include "common/angleutils.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "tests/test_utils/ShaderCompileTreeTest.h"
#include <algorithm>
......
......@@ -8,7 +8,7 @@
//
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "tests/test_utils/ShaderCompileTreeTest.h"
#include "tests/test_utils/compiler_test.h"
......
......@@ -13,7 +13,7 @@
#include <vector>
#include "common/mathutil.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermTraverse.h"
#include "tests/test_utils/ShaderCompileTreeTest.h"
namespace sh
......
......@@ -9,6 +9,7 @@
#include "tests/test_utils/ShaderCompileTreeTest.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/TranslatorESSL.h"
namespace sh
......
......@@ -10,6 +10,7 @@
#include "angle_gl.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
......
......@@ -25,6 +25,8 @@
#include "third_party/compiler/ArrayBoundsClamper.h"
#include "compiler/translator/IntermTraverse.h"
// The built-in 'clamp' instruction only accepts floats and returns a float. I
// iterated a few times with our driver team who examined the output from our
// compiler - they said the multiple casts generates more code than a single
......
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