Conditional simplifier.

This commit is contained in:
chriseth
2019-11-01 14:01:56 +01:00
parent 1bd2b202e9
commit 5d6e983be3
20 changed files with 525 additions and 52 deletions
@@ -0,0 +1,92 @@
/*
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/>.
*/
#include <libyul/optimiser/ConditionalSimplifier.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/AsmData.h>
#include <libyul/Utilities.h>
#include <libyul/optimiser/NameCollector.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/Visitor.h>
using namespace std;
using namespace dev;
using namespace yul;
void ConditionalSimplifier::operator()(Switch& _switch)
{
visit(*_switch.expression);
if (_switch.expression->type() != typeid(Identifier))
{
ASTModifier::operator()(_switch);
return;
}
YulString expr = boost::get<Identifier>(*_switch.expression).name;
for (auto& _case: _switch.cases)
{
if (_case.value)
{
(*this)(*_case.value);
_case.body.statements.insert(_case.body.statements.begin(),
Assignment{
_case.body.location,
{Identifier{_case.body.location, expr}},
make_unique<Expression>(*_case.value)
}
);
}
(*this)(_case.body);
}
}
void ConditionalSimplifier::operator()(Block& _block)
{
iterateReplacing(
_block.statements,
[&](Statement& _s) -> std::optional<vector<Statement>>
{
visit(_s);
if (_s.type() == typeid(If))
{
If& _if = boost::get<If>(_s);
if (
_if.condition->type() == typeid(Identifier) &&
!_if.body.statements.empty() &&
TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) !=
TerminationFinder::ControlFlow::FlowOut
)
{
YulString condition = boost::get<Identifier>(*_if.condition).name;
langutil::SourceLocation location = _if.location;
return make_vector<Statement>(
std::move(_s),
Assignment{
location,
{Identifier{location, condition}},
make_unique<Expression>(Literal{
location,
LiteralKind::Number,
"0"_yulstring,
{}
})
}
);
}
}
return {};
}
);
}
+71
View File
@@ -0,0 +1,71 @@
/*
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/>.
*/
#pragma once
#include <libyul/optimiser/ASTWalker.h>
#include <libyul/optimiser/OptimiserStep.h>
#include <libyul/Dialect.h>
#include <libdevcore/Common.h>
namespace yul
{
/**
* Conditional simplifier.
*
* Inserts assignments to condition variables if the value can be determined
* from the control-flow.
*
* Destroys SSA form.
*
* Currently, this tool is very limited, mostly because we do not yet have support
* for boolean types. Since conditions only check for expressions being nonzero,
* we cannot assign a specific value.
*
* Current features:
* - switch cases: insert "<condition> := <caseLabel>"
* - after if statement with terminating control-flow, insert "<condition> := 0"
*
* Future features:
* - allow replacements by "1"
* - take termination of user-defined functions into account
*
* Works best with SSA form and if dead code removal has run before.
*
* Prerequisite: Disambiguator.
*/
class ConditionalSimplifier: public ASTModifier
{
public:
static constexpr char const* name{"ConditionalSimplifier"};
static void run(OptimiserStepContext& _context, Block& _ast)
{
ConditionalSimplifier{_context.dialect}(_ast);
}
using ASTModifier::operator();
void operator()(Switch& _switch) override;
void operator()(Block& _block) override;
private:
explicit ConditionalSimplifier(Dialect const& _dialect):
m_dialect(_dialect)
{}
Dialect const& m_dialect;
};
}
+10 -1
View File
@@ -25,6 +25,7 @@
#include <libyul/optimiser/BlockFlattener.h>
#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/optimiser/ControlFlowSimplifier.h>
#include <libyul/optimiser/ConditionalSimplifier.h>
#include <libyul/optimiser/DeadCodeEliminator.h>
#include <libyul/optimiser/FunctionGrouper.h>
#include <libyul/optimiser/FunctionHoister.h>
@@ -36,6 +37,7 @@
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
#include <libyul/optimiser/ForLoopConditionOutOfBody.h>
#include <libyul/optimiser/ForLoopInitRewriter.h>
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
#include <libyul/optimiser/Rematerialiser.h>
#include <libyul/optimiser/UnusedPruner.h>
#include <libyul/optimiser/ExpressionSimplifier.h>
@@ -96,6 +98,7 @@ void OptimiserSuite::run(
EquivalentFunctionCombiner::name,
UnusedPruner::name,
BlockFlattener::name,
ConditionalSimplifier::name,
ControlFlowSimplifier::name,
LiteralRematerialiser::name,
StructuralSimplifier::name,
@@ -130,9 +133,12 @@ void OptimiserSuite::run(
}
{
// still in SSA, perform structural simplification
// perform structural simplification
suite.runSequence({
CommonSubexpressionEliminator::name,
ConditionalSimplifier::name,
LiteralRematerialiser::name,
StructuralSimplifier::name,
ForLoopConditionOutOfBody::name,
ControlFlowSimplifier::name,
StructuralSimplifier::name,
@@ -200,6 +206,8 @@ void OptimiserSuite::run(
{
// SSA plus simplify
suite.runSequence({
ConditionalSimplifier::name,
CommonSubexpressionEliminator::name,
SSATransform::name,
RedundantAssignEliminator::name,
RedundantAssignEliminator::name,
@@ -315,6 +323,7 @@ map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
instance = optimiserStepCollection<
BlockFlattener,
CommonSubexpressionEliminator,
ConditionalSimplifier,
ControlFlowSimplifier,
DeadCodeEliminator,
EquivalentFunctionCombiner,