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.cpp: Replace all references to a specific variable in the AST with references to
7 // another variable.
8 
9 #include "compiler/translator/tree_util/ReplaceVariable.h"
10 
11 #include "compiler/translator/IntermNode.h"
12 #include "compiler/translator/Symbol.h"
13 #include "compiler/translator/tree_util/IntermTraverse.h"
14 
15 namespace sh
16 {
17 
18 namespace
19 {
20 
21 class ReplaceVariableTraverser : public TIntermTraverser
22 {
23   public:
ReplaceVariableTraverser(const TVariable * toBeReplaced,const TIntermTyped * replacement)24     ReplaceVariableTraverser(const TVariable *toBeReplaced, const TIntermTyped *replacement)
25         : TIntermTraverser(true, false, false),
26           mToBeReplaced(toBeReplaced),
27           mReplacement(replacement)
28     {}
29 
visitSymbol(TIntermSymbol * node)30     void visitSymbol(TIntermSymbol *node) override
31     {
32         if (&node->variable() == mToBeReplaced)
33         {
34             queueReplacement(mReplacement->deepCopy(), OriginalNode::IS_DROPPED);
35         }
36     }
37 
38   private:
39     const TVariable *const mToBeReplaced;
40     const TIntermTyped *const mReplacement;
41 };
42 
43 }  // anonymous namespace
44 
45 // Replaces every occurrence of a variable with another variable.
ReplaceVariable(TCompiler * compiler,TIntermBlock * root,const TVariable * toBeReplaced,const TVariable * replacement)46 ANGLE_NO_DISCARD bool ReplaceVariable(TCompiler *compiler,
47                                       TIntermBlock *root,
48                                       const TVariable *toBeReplaced,
49                                       const TVariable *replacement)
50 {
51     ReplaceVariableTraverser traverser(toBeReplaced, new TIntermSymbol(replacement));
52     root->traverse(&traverser);
53     return traverser.updateTree(compiler, root);
54 }
55 
56 // Replaces every occurrence of a variable with a TIntermNode.
ReplaceVariableWithTyped(TCompiler * compiler,TIntermBlock * root,const TVariable * toBeReplaced,const TIntermTyped * replacement)57 ANGLE_NO_DISCARD bool ReplaceVariableWithTyped(TCompiler *compiler,
58                                                TIntermBlock *root,
59                                                const TVariable *toBeReplaced,
60                                                const TIntermTyped *replacement)
61 {
62     ReplaceVariableTraverser traverser(toBeReplaced, replacement);
63     root->traverse(&traverser);
64     return traverser.updateTree(compiler, root);
65 }
66 
convertFunctionPrototype(TSymbolTable * symbolTable,const TFunction * oldFunction)67 TIntermFunctionPrototype *RetypeOpaqueVariablesHelper::convertFunctionPrototype(
68     TSymbolTable *symbolTable,
69     const TFunction *oldFunction)
70 {
71     if (mReplacedFunctionParams.empty())
72     {
73         return nullptr;
74     }
75 
76     // Create a new function prototype for replacement.
77     TFunction *replacementFunction = new TFunction(
78         symbolTable, oldFunction->name(), SymbolType::UserDefined,
79         new TType(oldFunction->getReturnType()), oldFunction->isKnownToNotHaveSideEffects());
80     for (size_t paramIndex = 0; paramIndex < oldFunction->getParamCount(); ++paramIndex)
81     {
82         const TVariable *param = oldFunction->getParam(paramIndex);
83         TVariable *replacement = nullptr;
84         auto replaced          = mReplacedFunctionParams.find(param);
85         if (replaced != mReplacedFunctionParams.end())
86         {
87             replacement = replaced->second;
88         }
89         else
90         {
91             replacement = new TVariable(symbolTable, param->name(), new TType(param->getType()),
92                                         SymbolType::UserDefined);
93         }
94         replacementFunction->addParameter(replacement);
95     }
96     mReplacedFunctions[oldFunction] = replacementFunction;
97 
98     TIntermFunctionPrototype *replacementPrototype =
99         new TIntermFunctionPrototype(replacementFunction);
100 
101     return replacementPrototype;
102 }
103 
convertASTFunction(TIntermAggregate * node)104 TIntermAggregate *RetypeOpaqueVariablesHelper::convertASTFunction(TIntermAggregate *node)
105 {
106     // See if the function needs replacement at all.
107     const TFunction *function = node->getFunction();
108     auto replacedFunction     = mReplacedFunctions.find(function);
109     if (replacedFunction == mReplacedFunctions.end())
110     {
111         return nullptr;
112     }
113 
114     // Arguments to this call are staged to be replaced at the same time.
115     TFunction *substituteFunction        = replacedFunction->second;
116     TIntermSequence *substituteArguments = new TIntermSequence;
117 
118     for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
119     {
120         TIntermNode *param = node->getChildNode(paramIndex);
121 
122         TIntermNode *replacement = nullptr;
123         auto replacedArg         = mReplacedFunctionCallArgs.top().find(param);
124         if (replacedArg != mReplacedFunctionCallArgs.top().end())
125         {
126             replacement = replacedArg->second;
127         }
128         else
129         {
130             replacement = param->getAsTyped()->deepCopy();
131         }
132         substituteArguments->push_back(replacement);
133     }
134 
135     return TIntermAggregate::CreateFunctionCall(*substituteFunction, substituteArguments);
136 }
137 
138 }  // namespace sh
139