mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6131 from ethereum/fix-yul-opt
Yul Optimizer: reduce switches with const arguments
This commit is contained in:
commit
3dee9c50cd
@ -12,6 +12,7 @@ Compiler Features:
|
||||
* Optimizer: Add rule for shifts with constants for Constantinople.
|
||||
* Optimizer: Combine multiple shifts with constant shift-by values into one.
|
||||
* 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:
|
||||
|
@ -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 {};
|
||||
},
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||
#include <libdevcore/Common.h>
|
||||
|
||||
namespace yul
|
||||
{
|
||||
@ -29,6 +30,7 @@ namespace yul
|
||||
* - remove if with false condition
|
||||
* - turn switch with single case into if
|
||||
* - 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
|
||||
*
|
||||
* Prerequisites: Disambiguator
|
||||
@ -46,6 +48,7 @@ private:
|
||||
void simplify(std::vector<Statement>& _statements);
|
||||
bool expressionAlwaysTrue(Expression const& _expression);
|
||||
bool expressionAlwaysFalse(Expression const& _expression);
|
||||
boost::optional<dev::u256> hasLiteralValue(Expression const& _expression) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
13
test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul
Normal file
13
test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul
Normal 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)
|
||||
// }
|
@ -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)
|
||||
// }
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
let y := 200
|
||||
switch 1
|
||||
case 0 { y := 8 }
|
||||
case 1 { y := 9 }
|
||||
}
|
||||
// ----
|
||||
// structuralSimplifier
|
||||
// {
|
||||
// let y := 200
|
||||
// {
|
||||
// y := 9
|
||||
// }
|
||||
// }
|
@ -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
|
||||
// }
|
||||
// }
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
let y := 200
|
||||
switch 3
|
||||
case 0 { y := 8 }
|
||||
case 1 { y := 9 }
|
||||
}
|
||||
// ----
|
||||
// structuralSimplifier
|
||||
// {
|
||||
// let y := 200
|
||||
// }
|
Loading…
Reference in New Issue
Block a user