#include <libyul/optimiser/CommonSubexpressionEliminator.h>
#include <libyul/optimiser/SyntacticalEquality.h>
#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/SideEffects.h>
#include <libyul/Exceptions.h>
#include <libyul/AST.h>
#include <libyul/Dialect.h>
#include <libyul/Utilities.h>
using namespace std;
using namespace solidity;
using namespace solidity::yul;
using namespace solidity::util;
void CommonSubexpressionEliminator::run(OptimiserStepContext& _context, Block& _ast)
{
CommonSubexpressionEliminator cse{
_context.dialect,
SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast))
};
cse(_ast);
}
CommonSubexpressionEliminator::CommonSubexpressionEliminator(
Dialect const& _dialect,
map<YulString, SideEffects> _functionSideEffects
):
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects))
{
}
void CommonSubexpressionEliminator::operator()(FunctionDefinition& _fun)
{
ScopedSaveAndRestore returnVariables(m_returnVariables, {});
for (auto const& v: _fun.returnVariables)
m_returnVariables.insert(v.name);
DataFlowAnalyzer::operator()(_fun);
}
void CommonSubexpressionEliminator::visit(Expression& _e)
{
bool descend = true;
if (holds_alternative<FunctionCall>(_e))
{
FunctionCall& funCall = std::get<FunctionCall>(_e);
if (BuiltinFunction const* builtin = m_dialect.builtin(funCall.functionName.name))
{
for (size_t i = funCall.arguments.size(); i > 0; i--)
if (!builtin->literalArgument(i - 1))
visit(funCall.arguments[i - 1]);
descend = false;
}
}
if (descend)
DataFlowAnalyzer::visit(_e);
if (Identifier const* identifier = get_if<Identifier>(&_e))
{
YulString identifierName = identifier->name;
if (AssignedValue const* assignedValue = variableValue(identifierName))
{
assertThrow(assignedValue->value, OptimizerException, "");
if (Identifier const* value = get_if<Identifier>(assignedValue->value))
if (inScope(value->name))
_e = Identifier{debugDataOf(_e), value->name};
}
}
else
{
for (auto const& [variable, value]: allValues())
{
assertThrow(value.value, OptimizerException, "");
if (
m_returnVariables.count(variable) &&
holds_alternative<Literal>(*value.value) &&
valueOfLiteral(get<Literal>(*value.value)) == 0
)
continue;
if (SyntacticallyEqual{}(_e, *value.value) && inScope(variable))
{
_e = Identifier{debugDataOf(_e), variable};
break;
}
}
}
}