Yul Optimizer: reduce switches with const arguments

This commit is contained in:
Mathias Baumann 2019-02-27 16:55:42 +01:00
parent e9543d83c7
commit c686a65876
8 changed files with 118 additions and 1 deletions

View File

@ -12,6 +12,7 @@ Compiler Features:
* Optimizer: Add rule for shifts with constants for Constantinople. * Optimizer: Add rule for shifts with constants for Constantinople.
* Optimizer: Combine multiple shifts with constant shift-by values into one. * Optimizer: Combine multiple shifts with constant shift-by values into one.
* Optimizer: Support shifts in the constant optimiser for Constantinople. * Optimizer: Support shifts in the constant optimiser for Constantinople.
* Yul Optimizer: Add rule to replace switch statements with const expr. with matching case body
Bugfixes: Bugfixes:

View File

@ -45,6 +45,26 @@ void StructuralSimplifier::operator()(Block& _block)
popScope(); popScope();
} }
boost::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const
{
Expression const* expr = &_expression;
if (expr->type() == typeid(Identifier))
{
Identifier const& ident = boost::get<Identifier>(*expr);
if (m_value.count(ident.name))
expr = m_value.at(ident.name);
}
if (expr && expr->type() == typeid(Literal))
{
Literal const& literal = boost::get<Literal>(*expr);
return valueOfNumberLiteral(literal);
}
return boost::optional<u256>();
}
void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements) void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
{ {
using OptionalStatements = boost::optional<vector<Statement>>; using OptionalStatements = boost::optional<vector<Statement>>;
@ -62,7 +82,7 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
return {vector<Statement>{}}; return {vector<Statement>{}};
return {}; return {};
}, },
[](Switch& _switchStmt) -> OptionalStatements { [&](Switch& _switchStmt) -> OptionalStatements {
if (_switchStmt.cases.size() == 1) if (_switchStmt.cases.size() == 1)
{ {
auto& switchCase = _switchStmt.cases.front(); auto& switchCase = _switchStmt.cases.front();
@ -87,6 +107,32 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
return s; return s;
} }
} }
else if (boost::optional<u256> const constExprVal = hasLiteralValue(*_switchStmt.expression))
{
Block* matchingCaseBlock = nullptr;
Case* defaultCase = nullptr;
for (auto& _case: _switchStmt.cases)
{
if (_case.value && valueOfNumberLiteral(*_case.value) == constExprVal)
{
matchingCaseBlock = &_case.body;
break;
}
else if (!_case.value)
defaultCase = &_case;
}
if (!matchingCaseBlock && defaultCase)
matchingCaseBlock = &defaultCase->body;
OptionalStatements s = vector<Statement>{};
if (matchingCaseBlock)
s->emplace_back(std::move(*matchingCaseBlock));
return s;
}
else else
return {}; return {};
}, },

View File

@ -18,6 +18,7 @@
#include <libyul/optimiser/ASTWalker.h> #include <libyul/optimiser/ASTWalker.h>
#include <libyul/optimiser/DataFlowAnalyzer.h> #include <libyul/optimiser/DataFlowAnalyzer.h>
#include <libdevcore/Common.h>
namespace yul namespace yul
{ {
@ -29,6 +30,7 @@ namespace yul
* - remove if with false condition * - remove if with false condition
* - turn switch with single case into if * - turn switch with single case into if
* - replace switch with only default case with pop(expression) and body * - replace switch with only default case with pop(expression) and body
* - replace switch with const expr with matching case body
* - remove for with false condition * - remove for with false condition
* *
* Prerequisites: Disambiguator * Prerequisites: Disambiguator
@ -46,6 +48,7 @@ private:
void simplify(std::vector<Statement>& _statements); void simplify(std::vector<Statement>& _statements);
bool expressionAlwaysTrue(Expression const& _expression); bool expressionAlwaysTrue(Expression const& _expression);
bool expressionAlwaysFalse(Expression const& _expression); bool expressionAlwaysFalse(Expression const& _expression);
boost::optional<dev::u256> hasLiteralValue(Expression const& _expression) const;
}; };
} }

View File

@ -0,0 +1,13 @@
{
mstore(f(1), 0)
function f(x) -> y {
switch x
case 0 { y := 8 }
case 1 { y := 9 }
}
}
// ----
// fullSuite
// {
// mstore(9, 0)
// }

View File

@ -0,0 +1,14 @@
{
mstore(f(3), 0)
function f(x) -> y {
switch x
case 0 { y := 8 }
case 1 { y := 9 }
default { y := 10 }
}
}
// ----
// fullSuite
// {
// mstore(10, 0)
// }

View File

@ -0,0 +1,14 @@
{
let y := 200
switch 1
case 0 { y := 8 }
case 1 { y := 9 }
}
// ----
// structuralSimplifier
// {
// let y := 200
// {
// y := 9
// }
// }

View File

@ -0,0 +1,15 @@
{
let y := 200
switch 3
case 0 { y := 8 }
case 1 { y := 9 }
default { y := 10 }
}
// ----
// structuralSimplifier
// {
// let y := 200
// {
// y := 10
// }
// }

View File

@ -0,0 +1,11 @@
{
let y := 200
switch 3
case 0 { y := 8 }
case 1 { y := 9 }
}
// ----
// structuralSimplifier
// {
// let y := 200
// }