| // | |
| // 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; | |
| }; | |
| } // 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); | |
| } | |
| // 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); | |
| } | |
| TIntermFunctionPrototype *RetypeOpaqueVariablesHelper::convertFunctionPrototype( | |
| TSymbolTable *symbolTable, | |
| const TFunction *oldFunction) | |
| { | |
| if (mReplacedFunctionParams.empty()) | |
| { | |
| return nullptr; | |
| } | |
| // Create a new function prototype for replacement. | |
| TFunction *replacementFunction = new TFunction( | |
| symbolTable, oldFunction->name(), SymbolType::UserDefined, | |
| new TType(oldFunction->getReturnType()), oldFunction->isKnownToNotHaveSideEffects()); | |
| for (size_t paramIndex = 0; paramIndex < oldFunction->getParamCount(); ++paramIndex) | |
| { | |
| const TVariable *param = oldFunction->getParam(paramIndex); | |
| TVariable *replacement = nullptr; | |
| auto replaced = mReplacedFunctionParams.find(param); | |
| if (replaced != mReplacedFunctionParams.end()) | |
| { | |
| replacement = replaced->second; | |
| } | |
| else | |
| { | |
| replacement = new TVariable(symbolTable, param->name(), new TType(param->getType()), | |
| SymbolType::UserDefined); | |
| } | |
| replacementFunction->addParameter(replacement); | |
| } | |
| mReplacedFunctions[oldFunction] = replacementFunction; | |
| TIntermFunctionPrototype *replacementPrototype = | |
| new TIntermFunctionPrototype(replacementFunction); | |
| return replacementPrototype; | |
| } | |
| TIntermAggregate *RetypeOpaqueVariablesHelper::convertASTFunction(TIntermAggregate *node) | |
| { | |
| // See if the function needs replacement at all. | |
| const TFunction *function = node->getFunction(); | |
| auto replacedFunction = mReplacedFunctions.find(function); | |
| if (replacedFunction == mReplacedFunctions.end()) | |
| { | |
| return nullptr; | |
| } | |
| // Arguments to this call are staged to be replaced at the same time. | |
| TFunction *substituteFunction = replacedFunction->second; | |
| TIntermSequence *substituteArguments = new TIntermSequence; | |
| for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex) | |
| { | |
| TIntermNode *param = node->getChildNode(paramIndex); | |
| TIntermNode *replacement = nullptr; | |
| auto replacedArg = mReplacedFunctionCallArgs.top().find(param); | |
| if (replacedArg != mReplacedFunctionCallArgs.top().end()) | |
| { | |
| replacement = replacedArg->second; | |
| } | |
| else | |
| { | |
| replacement = param->getAsTyped()->deepCopy(); | |
| } | |
| substituteArguments->push_back(replacement); | |
| } | |
| return TIntermAggregate::CreateFunctionCall(*substituteFunction, substituteArguments); | |
| } | |
| } // namespace sh |