Yul Optimizer: reduce switches with const arguments

This commit is contained in:
Mathias Baumann
2019-02-28 15:43:10 +01:00
parent e9543d83c7
commit c686a65876
8 changed files with 118 additions and 1 deletions
+47 -1
View File
@@ -45,6 +45,26 @@ void StructuralSimplifier::operator()(Block& _block)
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)
{
using OptionalStatements = boost::optional<vector<Statement>>;
@@ -62,7 +82,7 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
return {vector<Statement>{}};
return {};
},
[](Switch& _switchStmt) -> OptionalStatements {
[&](Switch& _switchStmt) -> OptionalStatements {
if (_switchStmt.cases.size() == 1)
{
auto& switchCase = _switchStmt.cases.front();
@@ -87,6 +107,32 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
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
return {};
},