mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Yul Optimizer: reduce switches with const arguments
This commit is contained in:
parent
e9543d83c7
commit
c686a65876
@ -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:
|
||||||
|
@ -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 {};
|
||||||
},
|
},
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
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