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 class ReplaceVariablesTraverser : public TIntermTraverser
44 {
45   public:
ReplaceVariablesTraverser(const VariableReplacementMap & variableMap)46     ReplaceVariablesTraverser(const VariableReplacementMap &variableMap)
47         : TIntermTraverser(true, false, false), mVariableMap(variableMap)
48     {}
49 
visitSymbol(TIntermSymbol * node)50     void visitSymbol(TIntermSymbol *node) override
51     {
52         auto iter = mVariableMap.find(&node->variable());
53         if (iter != mVariableMap.end())
54         {
55             queueReplacement(iter->second->deepCopy(), OriginalNode::IS_DROPPED);
56         }
57     }
58 
59   private:
60     const VariableReplacementMap &mVariableMap;
61 };
62 
63 class GetDeclaratorReplacementsTraverser : public TIntermTraverser
64 {
65   public:
GetDeclaratorReplacementsTraverser(TSymbolTable * symbolTable,VariableReplacementMap * variableMap)66     GetDeclaratorReplacementsTraverser(TSymbolTable *symbolTable,
67                                        VariableReplacementMap *variableMap)
68         : TIntermTraverser(true, false, false, symbolTable), mVariableMap(variableMap)
69     {}
70 
visitDeclaration(Visit visit,TIntermDeclaration * node)71     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
72     {
73         const TIntermSequence &sequence = *(node->getSequence());
74 
75         for (TIntermNode *decl : sequence)
76         {
77             TIntermSymbol *asSymbol = decl->getAsSymbolNode();
78             TIntermBinary *asBinary = decl->getAsBinaryNode();
79 
80             if (asBinary != nullptr)
81             {
82                 ASSERT(asBinary->getOp() == EOpInitialize);
83                 asSymbol = asBinary->getLeft()->getAsSymbolNode();
84             }
85 
86             ASSERT(asSymbol);
87             const TVariable &variable = asSymbol->variable();
88 
89             ASSERT(mVariableMap->find(&variable) == mVariableMap->end());
90 
91             const TVariable *replacementVariable = new TVariable(
92                 mSymbolTable, variable.name(), &variable.getType(), variable.symbolType());
93 
94             (*mVariableMap)[&variable] = new TIntermSymbol(replacementVariable);
95         }
96 
97         return false;
98     }
99 
100   private:
101     VariableReplacementMap *mVariableMap;
102 };
103 
104 }  // anonymous namespace
105 
106 // Replaces every occurrence of a variable with another variable.
ReplaceVariable(TCompiler * compiler,TIntermBlock * root,const TVariable * toBeReplaced,const TVariable * replacement)107 ANGLE_NO_DISCARD bool ReplaceVariable(TCompiler *compiler,
108                                       TIntermBlock *root,
109                                       const TVariable *toBeReplaced,
110                                       const TVariable *replacement)
111 {
112     ReplaceVariableTraverser traverser(toBeReplaced, new TIntermSymbol(replacement));
113     root->traverse(&traverser);
114     return traverser.updateTree(compiler, root);
115 }
116 
ReplaceVariables(TCompiler * compiler,TIntermBlock * root,const VariableReplacementMap & variableMap)117 ANGLE_NO_DISCARD bool ReplaceVariables(TCompiler *compiler,
118                                        TIntermBlock *root,
119                                        const VariableReplacementMap &variableMap)
120 {
121     ReplaceVariablesTraverser traverser(variableMap);
122     root->traverse(&traverser);
123     return traverser.updateTree(compiler, root);
124 }
125 
GetDeclaratorReplacements(TSymbolTable * symbolTable,TIntermBlock * root,VariableReplacementMap * variableMap)126 void GetDeclaratorReplacements(TSymbolTable *symbolTable,
127                                TIntermBlock *root,
128                                VariableReplacementMap *variableMap)
129 {
130     GetDeclaratorReplacementsTraverser traverser(symbolTable, variableMap);
131     root->traverse(&traverser);
132 }
133 
134 // Replaces every occurrence of a variable with a TIntermNode.
ReplaceVariableWithTyped(TCompiler * compiler,TIntermBlock * root,const TVariable * toBeReplaced,const TIntermTyped * replacement)135 ANGLE_NO_DISCARD bool ReplaceVariableWithTyped(TCompiler *compiler,
136                                                TIntermBlock *root,
137                                                const TVariable *toBeReplaced,
138                                                const TIntermTyped *replacement)
139 {
140     ReplaceVariableTraverser traverser(toBeReplaced, replacement);
141     root->traverse(&traverser);
142     return traverser.updateTree(compiler, root);
143 }
144 
145 }  // namespace sh
146