blob: 901b4cedae6a0292ef74d3d167a73c3f095fac31 [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;
};
} // 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);
}
// 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);
}
TIntermFunctionPrototype *RetypeOpaqueVariablesHelper::convertFunctionPrototype(
TSymbolTable *symbolTable,
const TFunction *oldFunction)
{
if (mReplacedFunctionParams.empty())
{
return nullptr;
}
// Create a new function prototype for replacement.
TFunction *replacementFunction = new TFunction(
symbolTable, oldFunction->name(), SymbolType::UserDefined,
new TType(oldFunction->getReturnType()), oldFunction->isKnownToNotHaveSideEffects());
for (size_t paramIndex = 0; paramIndex < oldFunction->getParamCount(); ++paramIndex)
{
const TVariable *param = oldFunction->getParam(paramIndex);
TVariable *replacement = nullptr;
auto replaced = mReplacedFunctionParams.find(param);
if (replaced != mReplacedFunctionParams.end())
{
replacement = replaced->second;
}
else
{
replacement = new TVariable(symbolTable, param->name(), new TType(param->getType()),
SymbolType::UserDefined);
}
replacementFunction->addParameter(replacement);
}
mReplacedFunctions[oldFunction] = replacementFunction;
TIntermFunctionPrototype *replacementPrototype =
new TIntermFunctionPrototype(replacementFunction);
return replacementPrototype;
}
TIntermAggregate *RetypeOpaqueVariablesHelper::convertASTFunction(TIntermAggregate *node)
{
// See if the function needs replacement at all.
const TFunction *function = node->getFunction();
auto replacedFunction = mReplacedFunctions.find(function);
if (replacedFunction == mReplacedFunctions.end())
{
return nullptr;
}
// Arguments to this call are staged to be replaced at the same time.
TFunction *substituteFunction = replacedFunction->second;
TIntermSequence *substituteArguments = new TIntermSequence;
for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
{
TIntermNode *param = node->getChildNode(paramIndex);
TIntermNode *replacement = nullptr;
auto replacedArg = mReplacedFunctionCallArgs.top().find(param);
if (replacedArg != mReplacedFunctionCallArgs.top().end())
{
replacement = replacedArg->second;
}
else
{
replacement = param->getAsTyped()->deepCopy();
}
substituteArguments->push_back(replacement);
}
return TIntermAggregate::CreateFunctionCall(*substituteFunction, substituteArguments);
}
} // namespace sh