• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ReplaceVariable.h: Replace all references to a specific variable in the AST with references to
7 // another variable.
8 
9 #ifndef COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_
10 #define COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_
11 
12 #include "common/debug.h"
13 
14 #include <stack>
15 #include <unordered_map>
16 
17 namespace sh
18 {
19 
20 class TCompiler;
21 class TFunction;
22 class TIntermAggregate;
23 class TIntermBlock;
24 class TIntermFunctionPrototype;
25 class TIntermNode;
26 class TIntermTyped;
27 class TSymbolTable;
28 class TVariable;
29 
30 ANGLE_NO_DISCARD bool ReplaceVariable(TCompiler *compiler,
31                                       TIntermBlock *root,
32                                       const TVariable *toBeReplaced,
33                                       const TVariable *replacement);
34 ANGLE_NO_DISCARD bool ReplaceVariableWithTyped(TCompiler *compiler,
35                                                TIntermBlock *root,
36                                                const TVariable *toBeReplaced,
37                                                const TIntermTyped *replacement);
38 
39 // A helper class to keep track of opaque variable re-typing during a pass.  Unlike the above
40 // functions, this can be used to replace all opaque variables of a certain type with another in a
41 // pass that possibly does other related transformations.  Only opaque variables are supported as
42 // replacing local variables is not supported.
43 //
44 // The class uses "old" to refer to the original type of the variable and "new" to refer to the type
45 // that will replace it.
46 //
47 // - replaceGlobalVariable(): Call to track a global variable that is replaced.
48 // - in TIntermTraverser::visitFunctionPrototype():
49 //   * Call visitFunctionPrototype().
50 //   * For every replaced parameter, call replaceFunctionParam().
51 //   * call convertFunctionPrototype() to convert the prototype based on the above replacements
52 //     and track the function with its replacement.
53 //   * Call replaceFunction() to track the function that is replaced.
54 // - In PreVisit of TIntermTraverser::visitAggregate():
55 //   * call preVisitAggregate()
56 // - In TIntermTraverser::visitSymbol():
57 //   * Replace non-function-call-argument symbols that refer to a global or function param with the
58 //     replacement (getVariableReplacement()).
59 //   * For function call arguments, call replaceFunctionCallArg() to track the replacement.
60 // - In PostVisit of TIntermTraverser::visitAggregate():
61 //   * Convert built-in functions per case.  Call convertASTFunction() for non built-in functions
62 //     for the replacement to be created.
63 //   * Call postVisitAggregate() when done.
64 //
65 class RetypeOpaqueVariablesHelper
66 {
67   public:
RetypeOpaqueVariablesHelper()68     RetypeOpaqueVariablesHelper() {}
~RetypeOpaqueVariablesHelper()69     ~RetypeOpaqueVariablesHelper() {}
70 
71     // Global variable handling:
replaceGlobalVariable(const TVariable * oldVar,TVariable * newVar)72     void replaceGlobalVariable(const TVariable *oldVar, TVariable *newVar)
73     {
74         ASSERT(mReplacedGlobalVariables.count(oldVar) == 0);
75         mReplacedGlobalVariables[oldVar] = newVar;
76     }
getVariableReplacement(const TVariable * oldVar)77     TVariable *getVariableReplacement(const TVariable *oldVar) const
78     {
79         if (mReplacedGlobalVariables.count(oldVar) != 0)
80         {
81             return mReplacedGlobalVariables.at(oldVar);
82         }
83         else
84         {
85             // This function should only be called if the variable is expected to have been
86             // replaced either way (as a global variable or a function parameter).
87             ASSERT(mReplacedFunctionParams.count(oldVar) != 0);
88             return mReplacedFunctionParams.at(oldVar);
89         }
90     }
91 
92     // Function parameters handling:
visitFunctionPrototype()93     void visitFunctionPrototype() { mReplacedFunctionParams.clear(); }
replaceFunctionParam(const TVariable * oldParam,TVariable * newParam)94     void replaceFunctionParam(const TVariable *oldParam, TVariable *newParam)
95     {
96         ASSERT(mReplacedFunctionParams.count(oldParam) == 0);
97         mReplacedFunctionParams[oldParam] = newParam;
98     }
getFunctionParamReplacement(const TVariable * oldParam)99     TVariable *getFunctionParamReplacement(const TVariable *oldParam) const
100     {
101         ASSERT(mReplacedFunctionParams.count(oldParam) != 0);
102         return mReplacedFunctionParams.at(oldParam);
103     }
104 
105     // Function call arguments handling:
preVisitAggregate()106     void preVisitAggregate() { mReplacedFunctionCallArgs.emplace(); }
isInAggregate()107     bool isInAggregate() const { return !mReplacedFunctionCallArgs.empty(); }
postVisitAggregate()108     void postVisitAggregate() { mReplacedFunctionCallArgs.pop(); }
replaceFunctionCallArg(const TIntermNode * oldArg,TIntermTyped * newArg)109     void replaceFunctionCallArg(const TIntermNode *oldArg, TIntermTyped *newArg)
110     {
111         ASSERT(mReplacedFunctionCallArgs.top().count(oldArg) == 0);
112         mReplacedFunctionCallArgs.top()[oldArg] = newArg;
113     }
getFunctionCallArgReplacement(const TIntermNode * oldArg)114     TIntermTyped *getFunctionCallArgReplacement(const TIntermNode *oldArg) const
115     {
116         ASSERT(mReplacedFunctionCallArgs.top().count(oldArg) != 0);
117         return mReplacedFunctionCallArgs.top().at(oldArg);
118     }
119 
120     // Helper code conversion methods.
121     TIntermFunctionPrototype *convertFunctionPrototype(TSymbolTable *symbolTable,
122                                                        const TFunction *oldFunction);
123     TIntermAggregate *convertASTFunction(TIntermAggregate *node);
124 
125   private:
126     // A map from the old global variable to the new one.
127     std::unordered_map<const TVariable *, TVariable *> mReplacedGlobalVariables;
128 
129     // A map from functions with old type parameters to one where that's replaced with the new type.
130     std::unordered_map<const TFunction *, TFunction *> mReplacedFunctions;
131 
132     // A map from function old type parameters to their replacement new type parameter for the
133     // current function definition.
134     std::unordered_map<const TVariable *, TVariable *> mReplacedFunctionParams;
135 
136     // A map from function call old type arguments to their replacement for the current function
137     // call.
138     std::stack<std::unordered_map<const TIntermNode *, TIntermTyped *>> mReplacedFunctionCallArgs;
139 };
140 
141 }  // namespace sh
142 
143 #endif  // COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_
144