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