solidity/libyul/optimiser/CommonSubexpressionEliminator.cpp

115 lines
3.6 KiB
C++
Raw Normal View History

2018-02-02 14:24:56 +00:00
/*(
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Optimisation stage that replaces expressions known to be the current value of a variable
* in scope by a reference to that variable.
*/
2018-10-15 09:52:35 +00:00
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
2018-02-02 14:24:56 +00:00
2018-10-15 09:52:35 +00:00
#include <libyul/optimiser/Metrics.h>
#include <libyul/optimiser/SyntacticalEquality.h>
#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/SideEffects.h>
2018-10-15 09:52:35 +00:00
#include <libyul/Exceptions.h>
#include <libyul/AsmData.h>
#include <libyul/Dialect.h>
2018-02-02 14:24:56 +00:00
using namespace std;
2019-12-11 16:31:36 +00:00
using namespace solidity;
using namespace solidity::yul;
using namespace solidity::util;
2018-02-02 14:24:56 +00:00
2019-09-23 14:32:50 +00:00
void CommonSubexpressionEliminator::run(OptimiserStepContext& _context, Block& _ast)
{
CommonSubexpressionEliminator cse{
2019-09-23 14:32:50 +00:00
_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))
{
}
2018-02-02 14:24:56 +00:00
void CommonSubexpressionEliminator::visit(Expression& _e)
{
bool descend = true;
// If this is a function call to a function that requires literal arguments,
// do not try to simplify there.
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--)
// We should not modify function arguments that have to be literals
// Note that replacing the function call entirely is fine,
// if the function call is movable.
if (!builtin->literalArgument(i - 1))
visit(funCall.arguments[i - 1]);
descend = false;
}
}
2018-10-11 17:58:09 +00:00
// We visit the inner expression first to first simplify inner expressions,
// which hopefully allows more matches.
// Note that the DataFlowAnalyzer itself only has code for visiting Statements,
// so this basically invokes the AST walker directly and thus post-visiting
// is also fine with regards to data flow analysis.
if (descend)
DataFlowAnalyzer::visit(_e);
2018-10-11 17:58:09 +00:00
if (holds_alternative<Identifier>(_e))
2018-10-11 17:58:09 +00:00
{
Identifier& identifier = std::get<Identifier>(_e);
YulString name = identifier.name;
2018-10-11 17:58:09 +00:00
if (m_value.count(name))
{
2019-11-28 13:22:17 +00:00
assertThrow(m_value.at(name).value, OptimizerException, "");
if (holds_alternative<Identifier>(*m_value.at(name).value))
2018-10-11 17:58:09 +00:00
{
2019-11-28 13:22:17 +00:00
YulString value = std::get<Identifier>(*m_value.at(name).value).name;
assertThrow(inScope(value), OptimizerException, "");
_e = Identifier{locationOf(_e), value};
2018-10-11 17:58:09 +00:00
}
}
}
else
{
// TODO this search is rather inefficient.
2019-11-28 13:22:17 +00:00
for (auto const& [variable, value]: m_value)
2018-02-02 14:24:56 +00:00
{
2019-11-28 13:22:17 +00:00
assertThrow(value.value, OptimizerException, "");
assertThrow(inScope(variable), OptimizerException, "");
if (SyntacticallyEqual{}(_e, *value.value))
2018-02-02 14:24:56 +00:00
{
2019-11-28 13:22:17 +00:00
_e = Identifier{locationOf(_e), variable};
2018-02-02 14:24:56 +00:00
break;
}
}
2018-10-11 17:58:09 +00:00
}
2018-02-02 14:24:56 +00:00
}