blob: 42777ee88b782ff3793620c5f178de3f689bc27a [file] [log] [blame]
//
// 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.cpp: Replace all references to a specific variable in the AST with references to
// another variable.
#include "compiler/translator/tree_util/ReplaceVariable.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/Symbol.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
class ReplaceVariableTraverser : public TIntermTraverser
{
public:
ReplaceVariableTraverser(const TVariable *toBeReplaced, const TIntermTyped *replacement)
: TIntermTraverser(true, false, false),
mToBeReplaced(toBeReplaced),
mReplacement(replacement)
{}
void visitSymbol(TIntermSymbol *node) override
{
if (&node->variable() == mToBeReplaced)
{
queueReplacement(mReplacement->deepCopy(), OriginalNode::IS_DROPPED);
}
}
private:
const TVariable *const mToBeReplaced;
const TIntermTyped *const mReplacement;
};
class ReplaceVariablesTraverser : public TIntermTraverser
{
public:
ReplaceVariablesTraverser(const VariableReplacementMap &variableMap)
: TIntermTraverser(true, false, false), mVariableMap(variableMap)
{}
void visitSymbol(TIntermSymbol *node) override
{
auto iter = mVariableMap.find(&node->variable());
if (iter != mVariableMap.end())
{
queueReplacement(iter->second->deepCopy(), OriginalNode::IS_DROPPED);
}
}
private:
const VariableReplacementMap &mVariableMap;
};
class GetDeclaratorReplacementsTraverser : public TIntermTraverser
{
public:
GetDeclaratorReplacementsTraverser(TSymbolTable *symbolTable,
VariableReplacementMap *variableMap)
: TIntermTraverser(true, false, false, symbolTable), mVariableMap(variableMap)
{}
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
{
const TIntermSequence &sequence = *(node->getSequence());
for (TIntermNode *decl : sequence)
{
TIntermSymbol *asSymbol = decl->getAsSymbolNode();
TIntermBinary *asBinary = decl->getAsBinaryNode();
if (asBinary != nullptr)
{
ASSERT(asBinary->getOp() == EOpInitialize);
asSymbol = asBinary->getLeft()->getAsSymbolNode();
}
ASSERT(asSymbol);
const TVariable &variable = asSymbol->variable();
ASSERT(mVariableMap->find(&variable) == mVariableMap->end());
const TVariable *replacementVariable = new TVariable(
mSymbolTable, variable.name(), &variable.getType(), variable.symbolType());
(*mVariableMap)[&variable] = new TIntermSymbol(replacementVariable);
}
return false;
}
private:
VariableReplacementMap *mVariableMap;
};
} // anonymous namespace
// Replaces every occurrence of a variable with another variable.
ANGLE_NO_DISCARD bool ReplaceVariable(TCompiler *compiler,
TIntermBlock *root,
const TVariable *toBeReplaced,
const TVariable *replacement)
{
ReplaceVariableTraverser traverser(toBeReplaced, new TIntermSymbol(replacement));
root->traverse(&traverser);
return traverser.updateTree(compiler, root);
}
ANGLE_NO_DISCARD bool ReplaceVariables(TCompiler *compiler,
TIntermBlock *root,
const VariableReplacementMap &variableMap)
{
ReplaceVariablesTraverser traverser(variableMap);
root->traverse(&traverser);
return traverser.updateTree(compiler, root);
}
void GetDeclaratorReplacements(TSymbolTable *symbolTable,
TIntermBlock *root,
VariableReplacementMap *variableMap)
{
GetDeclaratorReplacementsTraverser traverser(symbolTable, variableMap);
root->traverse(&traverser);
}
// Replaces every occurrence of a variable with a TIntermNode.
ANGLE_NO_DISCARD bool ReplaceVariableWithTyped(TCompiler *compiler,
TIntermBlock *root,
const TVariable *toBeReplaced,
const TIntermTyped *replacement)
{
ReplaceVariableTraverser traverser(toBeReplaced, replacement);
root->traverse(&traverser);
return traverser.updateTree(compiler, root);
}
} // namespace sh