| // | |
| // 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.h: Replace all references to a specific variable in the AST with references to | |
| // another variable. | |
| #ifndef COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_ | |
| #define COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_ | |
| #include "common/debug.h" | |
| #include <stack> | |
| #include <unordered_map> | |
| namespace sh | |
| { | |
| class TCompiler; | |
| class TFunction; | |
| class TIntermAggregate; | |
| class TIntermBlock; | |
| class TIntermFunctionPrototype; | |
| class TIntermNode; | |
| class TIntermTyped; | |
| class TSymbolTable; | |
| class TVariable; | |
| ANGLE_NO_DISCARD bool ReplaceVariable(TCompiler *compiler, | |
| TIntermBlock *root, | |
| const TVariable *toBeReplaced, | |
| const TVariable *replacement); | |
| ANGLE_NO_DISCARD bool ReplaceVariableWithTyped(TCompiler *compiler, | |
| TIntermBlock *root, | |
| const TVariable *toBeReplaced, | |
| const TIntermTyped *replacement); | |
| // A helper class to keep track of opaque variable re-typing during a pass. Unlike the above | |
| // functions, this can be used to replace all opaque variables of a certain type with another in a | |
| // pass that possibly does other related transformations. Only opaque variables are supported as | |
| // replacing local variables is not supported. | |
| // | |
| // The class uses "old" to refer to the original type of the variable and "new" to refer to the type | |
| // that will replace it. | |
| // | |
| // - replaceGlobalVariable(): Call to track a global variable that is replaced. | |
| // - in TIntermTraverser::visitFunctionPrototype(): | |
| // * Call visitFunctionPrototype(). | |
| // * For every replaced parameter, call replaceFunctionParam(). | |
| // * call convertFunctionPrototype() to convert the prototype based on the above replacements | |
| // and track the function with its replacement. | |
| // * Call replaceFunction() to track the function that is replaced. | |
| // - In PreVisit of TIntermTraverser::visitAggregate(): | |
| // * call preVisitAggregate() | |
| // - In TIntermTraverser::visitSymbol(): | |
| // * Replace non-function-call-argument symbols that refer to a global or function param with the | |
| // replacement (getVariableReplacement()). | |
| // * For function call arguments, call replaceFunctionCallArg() to track the replacement. | |
| // - In PostVisit of TIntermTraverser::visitAggregate(): | |
| // * Convert built-in functions per case. Call convertASTFunction() for non built-in functions | |
| // for the replacement to be created. | |
| // * Call postVisitAggregate() when done. | |
| // | |
| class RetypeOpaqueVariablesHelper | |
| { | |
| public: | |
| RetypeOpaqueVariablesHelper() {} | |
| ~RetypeOpaqueVariablesHelper() {} | |
| // Global variable handling: | |
| void replaceGlobalVariable(const TVariable *oldVar, TVariable *newVar) | |
| { | |
| ASSERT(mReplacedGlobalVariables.count(oldVar) == 0); | |
| mReplacedGlobalVariables[oldVar] = newVar; | |
| } | |
| TVariable *getVariableReplacement(const TVariable *oldVar) const | |
| { | |
| if (mReplacedGlobalVariables.count(oldVar) != 0) | |
| { | |
| return mReplacedGlobalVariables.at(oldVar); | |
| } | |
| else | |
| { | |
| // This function should only be called if the variable is expected to have been | |
| // replaced either way (as a global variable or a function parameter). | |
| ASSERT(mReplacedFunctionParams.count(oldVar) != 0); | |
| return mReplacedFunctionParams.at(oldVar); | |
| } | |
| } | |
| // Function parameters handling: | |
| void visitFunctionPrototype() { mReplacedFunctionParams.clear(); } | |
| void replaceFunctionParam(const TVariable *oldParam, TVariable *newParam) | |
| { | |
| ASSERT(mReplacedFunctionParams.count(oldParam) == 0); | |
| mReplacedFunctionParams[oldParam] = newParam; | |
| } | |
| TVariable *getFunctionParamReplacement(const TVariable *oldParam) const | |
| { | |
| ASSERT(mReplacedFunctionParams.count(oldParam) != 0); | |
| return mReplacedFunctionParams.at(oldParam); | |
| } | |
| // Function call arguments handling: | |
| void preVisitAggregate() { mReplacedFunctionCallArgs.emplace(); } | |
| bool isInAggregate() const { return !mReplacedFunctionCallArgs.empty(); } | |
| void postVisitAggregate() { mReplacedFunctionCallArgs.pop(); } | |
| void replaceFunctionCallArg(const TIntermNode *oldArg, TIntermTyped *newArg) | |
| { | |
| ASSERT(mReplacedFunctionCallArgs.top().count(oldArg) == 0); | |
| mReplacedFunctionCallArgs.top()[oldArg] = newArg; | |
| } | |
| TIntermTyped *getFunctionCallArgReplacement(const TIntermNode *oldArg) const | |
| { | |
| ASSERT(mReplacedFunctionCallArgs.top().count(oldArg) != 0); | |
| return mReplacedFunctionCallArgs.top().at(oldArg); | |
| } | |
| // Helper code conversion methods. | |
| TIntermFunctionPrototype *convertFunctionPrototype(TSymbolTable *symbolTable, | |
| const TFunction *oldFunction); | |
| TIntermAggregate *convertASTFunction(TIntermAggregate *node); | |
| private: | |
| // A map from the old global variable to the new one. | |
| std::unordered_map<const TVariable *, TVariable *> mReplacedGlobalVariables; | |
| // A map from functions with old type parameters to one where that's replaced with the new type. | |
| std::unordered_map<const TFunction *, TFunction *> mReplacedFunctions; | |
| // A map from function old type parameters to their replacement new type parameter for the | |
| // current function definition. | |
| std::unordered_map<const TVariable *, TVariable *> mReplacedFunctionParams; | |
| // A map from function call old type arguments to their replacement for the current function | |
| // call. | |
| std::stack<std::unordered_map<const TIntermNode *, TIntermTyped *>> mReplacedFunctionCallArgs; | |
| }; | |
| } // namespace sh | |
| #endif // COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_ |