| // |
| // Copyright 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. |
| // |
| // ReplaceVariable.cpp: Replace all references to a specific variable in the AST with references to |
| // another variable. |
| |
| #include "compiler/translator/tree_util/ReplaceVariable.h" |
| |
| #include "compiler/translator/IntermNode.h" |
| #include "compiler/translator/Symbol.h" |
| #include "compiler/translator/tree_util/IntermTraverse.h" |
| |
| namespace sh |
| { |
| |
| namespace |
| { |
| |
| class ReplaceVariableTraverser : public TIntermTraverser |
| { |
| public: |
| ReplaceVariableTraverser(const TVariable *toBeReplaced, const TIntermTyped *replacement) |
| : TIntermTraverser(true, false, false), |
| mToBeReplaced(toBeReplaced), |
| mReplacement(replacement) |
| {} |
| |
| void visitSymbol(TIntermSymbol *node) override |
| { |
| if (&node->variable() == mToBeReplaced) |
| { |
| queueReplacement(mReplacement->deepCopy(), OriginalNode::IS_DROPPED); |
| } |
| } |
| |
| private: |
| const TVariable *const mToBeReplaced; |
| const TIntermTyped *const mReplacement; |
| }; |
| |
| class ReplaceVariablesTraverser : public TIntermTraverser |
| { |
| public: |
| ReplaceVariablesTraverser(const VariableReplacementMap &variableMap) |
| : TIntermTraverser(true, false, false), mVariableMap(variableMap) |
| {} |
| |
| void visitSymbol(TIntermSymbol *node) override |
| { |
| auto iter = mVariableMap.find(&node->variable()); |
| if (iter != mVariableMap.end()) |
| { |
| queueReplacement(iter->second->deepCopy(), OriginalNode::IS_DROPPED); |
| } |
| } |
| |
| private: |
| const VariableReplacementMap &mVariableMap; |
| }; |
| |
| class GetDeclaratorReplacementsTraverser : public TIntermTraverser |
| { |
| public: |
| GetDeclaratorReplacementsTraverser(TSymbolTable *symbolTable, |
| VariableReplacementMap *variableMap) |
| : TIntermTraverser(true, false, false, symbolTable), mVariableMap(variableMap) |
| {} |
| |
| bool visitDeclaration(Visit visit, TIntermDeclaration *node) override |
| { |
| const TIntermSequence &sequence = *(node->getSequence()); |
| |
| for (TIntermNode *decl : sequence) |
| { |
| TIntermSymbol *asSymbol = decl->getAsSymbolNode(); |
| TIntermBinary *asBinary = decl->getAsBinaryNode(); |
| |
| if (asBinary != nullptr) |
| { |
| ASSERT(asBinary->getOp() == EOpInitialize); |
| asSymbol = asBinary->getLeft()->getAsSymbolNode(); |
| } |
| |
| ASSERT(asSymbol); |
| const TVariable &variable = asSymbol->variable(); |
| |
| ASSERT(mVariableMap->find(&variable) == mVariableMap->end()); |
| |
| const TVariable *replacementVariable = new TVariable( |
| mSymbolTable, variable.name(), &variable.getType(), variable.symbolType()); |
| |
| (*mVariableMap)[&variable] = new TIntermSymbol(replacementVariable); |
| } |
| |
| return false; |
| } |
| |
| private: |
| VariableReplacementMap *mVariableMap; |
| }; |
| |
| } // anonymous namespace |
| |
| // Replaces every occurrence of a variable with another variable. |
| ANGLE_NO_DISCARD bool ReplaceVariable(TCompiler *compiler, |
| TIntermBlock *root, |
| const TVariable *toBeReplaced, |
| const TVariable *replacement) |
| { |
| ReplaceVariableTraverser traverser(toBeReplaced, new TIntermSymbol(replacement)); |
| root->traverse(&traverser); |
| return traverser.updateTree(compiler, root); |
| } |
| |
| ANGLE_NO_DISCARD bool ReplaceVariables(TCompiler *compiler, |
| TIntermBlock *root, |
| const VariableReplacementMap &variableMap) |
| { |
| ReplaceVariablesTraverser traverser(variableMap); |
| root->traverse(&traverser); |
| return traverser.updateTree(compiler, root); |
| } |
| |
| void GetDeclaratorReplacements(TSymbolTable *symbolTable, |
| TIntermBlock *root, |
| VariableReplacementMap *variableMap) |
| { |
| GetDeclaratorReplacementsTraverser traverser(symbolTable, variableMap); |
| root->traverse(&traverser); |
| } |
| |
| // Replaces every occurrence of a variable with a TIntermNode. |
| ANGLE_NO_DISCARD bool ReplaceVariableWithTyped(TCompiler *compiler, |
| TIntermBlock *root, |
| const TVariable *toBeReplaced, |
| const TIntermTyped *replacement) |
| { |
| ReplaceVariableTraverser traverser(toBeReplaced, replacement); |
| root->traverse(&traverser); |
| return traverser.updateTree(compiler, root); |
| } |
| |
| } // namespace sh |