mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Translation of switch statement for wasm backend.
This commit is contained in:
parent
8d18003808
commit
e2bfb1a663
@ -24,6 +24,7 @@
|
||||
#include <libdevcore/CommonData.h>
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
@ -62,7 +63,7 @@ void WordSizeTransform::operator()(If& _if)
|
||||
|
||||
void WordSizeTransform::operator()(Switch&)
|
||||
{
|
||||
yulAssert(false, "Switch statement not implemented.");
|
||||
yulAssert(false, "Switch statement has to be handled inside the containing block.");
|
||||
}
|
||||
|
||||
void WordSizeTransform::operator()(ForLoop& _for)
|
||||
@ -153,6 +154,8 @@ void WordSizeTransform::operator()(Block& _block)
|
||||
else
|
||||
yulAssert(false, "");
|
||||
}
|
||||
else if (_s.type() == typeid(Switch))
|
||||
return handleSwitch(boost::get<Switch>(_s));
|
||||
else
|
||||
visit(_s);
|
||||
return boost::none;
|
||||
@ -206,6 +209,110 @@ void WordSizeTransform::rewriteFunctionCallArguments(vector<Expression>& _args)
|
||||
);
|
||||
}
|
||||
|
||||
vector<Statement> WordSizeTransform::handleSwitchInternal(
|
||||
langutil::SourceLocation const& _location,
|
||||
vector<YulString> const& _splitExpressions,
|
||||
vector<Case> _cases,
|
||||
YulString _runDefaultFlag,
|
||||
size_t _depth
|
||||
)
|
||||
{
|
||||
if (_depth == 4)
|
||||
{
|
||||
yulAssert(_cases.size() == 1, "");
|
||||
return std::move(_cases.front().body.statements);
|
||||
}
|
||||
|
||||
// Extract current 64 bit segment and group by it.
|
||||
map<u256, vector<Case>> cases;
|
||||
for (Case& c: _cases)
|
||||
{
|
||||
yulAssert(c.value, "Default case still present.");
|
||||
cases[
|
||||
(valueOfLiteral(*c.value) >> (256 - 64 * (_depth + 1))) &
|
||||
std::numeric_limits<uint64_t>::max()
|
||||
].emplace_back(std::move(c));
|
||||
}
|
||||
|
||||
Switch ret{
|
||||
_location,
|
||||
make_unique<Expression>(Identifier{_location, _splitExpressions.at(_depth)}),
|
||||
{}
|
||||
};
|
||||
|
||||
for (auto& c: cases)
|
||||
{
|
||||
Literal label{_location, LiteralKind::Number, YulString(c.first.str()), "u64"_yulstring};
|
||||
ret.cases.emplace_back(Case{
|
||||
c.second.front().location,
|
||||
make_unique<Literal>(std::move(label)),
|
||||
Block{_location, handleSwitchInternal(
|
||||
_location,
|
||||
_splitExpressions,
|
||||
std::move(c.second),
|
||||
_runDefaultFlag,
|
||||
_depth + 1
|
||||
)}
|
||||
});
|
||||
}
|
||||
if (!_runDefaultFlag.empty())
|
||||
ret.cases.emplace_back(Case{
|
||||
_location,
|
||||
nullptr,
|
||||
Block{_location, make_vector<Statement>(
|
||||
Assignment{
|
||||
_location,
|
||||
{{_location, _runDefaultFlag}},
|
||||
make_unique<Expression>(Literal{_location, LiteralKind::Number, "1"_yulstring, "u64"_yulstring})
|
||||
}
|
||||
)}
|
||||
});
|
||||
return make_vector<Statement>(std::move(ret));
|
||||
}
|
||||
|
||||
std::vector<Statement> WordSizeTransform::handleSwitch(Switch& _switch)
|
||||
{
|
||||
for (auto& c: _switch.cases)
|
||||
(*this)(c.body);
|
||||
|
||||
// Turns the switch into a quadruply-nested switch plus
|
||||
// a flag that tells to execute the default case after all the switches.
|
||||
vector<Statement> ret;
|
||||
|
||||
YulString runDefaultFlag;
|
||||
Case defaultCase;
|
||||
if (!_switch.cases.back().value)
|
||||
{
|
||||
runDefaultFlag = m_nameDispenser.newName("run_default"_yulstring);
|
||||
defaultCase = std::move(_switch.cases.back());
|
||||
_switch.cases.pop_back();
|
||||
ret.emplace_back(VariableDeclaration{
|
||||
_switch.location,
|
||||
{TypedName{_switch.location, runDefaultFlag, "u64"_yulstring}},
|
||||
{}
|
||||
});
|
||||
}
|
||||
vector<YulString> splitExpressions;
|
||||
for (auto const& expr: expandValue(*_switch.expression))
|
||||
splitExpressions.emplace_back(boost::get<Identifier>(*expr).name);
|
||||
|
||||
ret += handleSwitchInternal(
|
||||
_switch.location,
|
||||
splitExpressions,
|
||||
std::move(_switch.cases),
|
||||
runDefaultFlag,
|
||||
0
|
||||
);
|
||||
if (!runDefaultFlag.empty())
|
||||
ret.emplace_back(If{
|
||||
_switch.location,
|
||||
make_unique<Expression>(Identifier{_switch.location, runDefaultFlag}),
|
||||
std::move(defaultCase.body)
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
array<YulString, 4> WordSizeTransform::generateU64IdentifierNames(YulString const& _s)
|
||||
{
|
||||
yulAssert(m_variableMapping.find(_s) == m_variableMapping.end(), "");
|
||||
@ -242,7 +349,7 @@ array<unique_ptr<Expression>, 4> WordSizeTransform::expandValue(Expression const
|
||||
}
|
||||
}
|
||||
else
|
||||
yulAssert(false, "");
|
||||
yulAssert(false, "Invalid expression to split.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/optimiser/NameDispenser.h>
|
||||
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
@ -78,6 +80,15 @@ private:
|
||||
void rewriteIdentifierList(std::vector<Identifier>&);
|
||||
void rewriteFunctionCallArguments(std::vector<Expression>&);
|
||||
|
||||
std::vector<Statement> handleSwitch(Switch& _switch);
|
||||
std::vector<Statement> handleSwitchInternal(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::vector<YulString> const& _splitExpressions,
|
||||
std::vector<Case> _cases,
|
||||
YulString _runDefaultFlag,
|
||||
size_t _depth
|
||||
);
|
||||
|
||||
std::array<YulString, 4> generateU64IdentifierNames(YulString const& _s);
|
||||
std::array<std::unique_ptr<Expression>, 4> expandValue(Expression const& _e);
|
||||
std::vector<Expression> expandValueToVector(Expression const& _e);
|
||||
|
71
test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul
Normal file
71
test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul
Normal file
@ -0,0 +1,71 @@
|
||||
{
|
||||
switch calldataload(0)
|
||||
case 0 { sstore(0, 1) }
|
||||
case 1 { sstore(1, 1) }
|
||||
case 2 { sstore(2, 1) }
|
||||
case 3 { sstore(3, 1) }
|
||||
}
|
||||
// ====
|
||||
// step: wordSizeTransform
|
||||
// ----
|
||||
// {
|
||||
// let _1_0 := 0
|
||||
// let _1_1 := 0
|
||||
// let _1_2 := 0
|
||||
// let _1_3 := 0
|
||||
// let _2_0, _2_1, _2_2, _2_3 := calldataload(_1_0, _1_1, _1_2, _1_3)
|
||||
// switch _2_0
|
||||
// case 0 {
|
||||
// switch _2_1
|
||||
// case 0 {
|
||||
// switch _2_2
|
||||
// case 0 {
|
||||
// switch _2_3
|
||||
// case 0 {
|
||||
// let _3_0 := 0
|
||||
// let _3_1 := 0
|
||||
// let _3_2 := 0
|
||||
// let _3_3 := 1
|
||||
// let _4_0 := 0
|
||||
// let _4_1 := 0
|
||||
// let _4_2 := 0
|
||||
// let _4_3 := 0
|
||||
// sstore(_4_0, _4_1, _4_2, _4_3, _3_0, _3_1, _3_2, _3_3)
|
||||
// }
|
||||
// case 1 {
|
||||
// let _5_0 := 0
|
||||
// let _5_1 := 0
|
||||
// let _5_2 := 0
|
||||
// let _5_3 := 1
|
||||
// let _6_0 := 0
|
||||
// let _6_1 := 0
|
||||
// let _6_2 := 0
|
||||
// let _6_3 := 1
|
||||
// sstore(_6_0, _6_1, _6_2, _6_3, _5_0, _5_1, _5_2, _5_3)
|
||||
// }
|
||||
// case 2 {
|
||||
// let _7_0 := 0
|
||||
// let _7_1 := 0
|
||||
// let _7_2 := 0
|
||||
// let _7_3 := 1
|
||||
// let _8_0 := 0
|
||||
// let _8_1 := 0
|
||||
// let _8_2 := 0
|
||||
// let _8_3 := 2
|
||||
// sstore(_8_0, _8_1, _8_2, _8_3, _7_0, _7_1, _7_2, _7_3)
|
||||
// }
|
||||
// case 3 {
|
||||
// let _9_0 := 0
|
||||
// let _9_1 := 0
|
||||
// let _9_2 := 0
|
||||
// let _9_3 := 1
|
||||
// let _10_0 := 0
|
||||
// let _10_1 := 0
|
||||
// let _10_2 := 0
|
||||
// let _10_3 := 3
|
||||
// sstore(_10_0, _10_1, _10_2, _10_3, _9_0, _9_1, _9_2, _9_3)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
77
test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul
Normal file
77
test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
switch calldataload(0)
|
||||
case 0x01000000000000000000000000000000000000010 { sstore(0, 1) }
|
||||
case 0x02000000000000000000000000000000000000010 { sstore(1, 1) }
|
||||
case 0x01000000000000000000000000000000000000020 { sstore(2, 1) }
|
||||
case 0x02000000000000000000000000000000000000020 { sstore(3, 1) }
|
||||
}
|
||||
// ====
|
||||
// step: wordSizeTransform
|
||||
// ----
|
||||
// {
|
||||
// let _1_0 := 0
|
||||
// let _1_1 := 0
|
||||
// let _1_2 := 0
|
||||
// let _1_3 := 0
|
||||
// let _2_0, _2_1, _2_2, _2_3 := calldataload(_1_0, _1_1, _1_2, _1_3)
|
||||
// switch _2_0
|
||||
// case 0 {
|
||||
// switch _2_1
|
||||
// case 268435456 {
|
||||
// switch _2_2
|
||||
// case 0 {
|
||||
// switch _2_3
|
||||
// case 16 {
|
||||
// let _3_0 := 0
|
||||
// let _3_1 := 0
|
||||
// let _3_2 := 0
|
||||
// let _3_3 := 1
|
||||
// let _4_0 := 0
|
||||
// let _4_1 := 0
|
||||
// let _4_2 := 0
|
||||
// let _4_3 := 0
|
||||
// sstore(_4_0, _4_1, _4_2, _4_3, _3_0, _3_1, _3_2, _3_3)
|
||||
// }
|
||||
// case 32 {
|
||||
// let _7_0 := 0
|
||||
// let _7_1 := 0
|
||||
// let _7_2 := 0
|
||||
// let _7_3 := 1
|
||||
// let _8_0 := 0
|
||||
// let _8_1 := 0
|
||||
// let _8_2 := 0
|
||||
// let _8_3 := 2
|
||||
// sstore(_8_0, _8_1, _8_2, _8_3, _7_0, _7_1, _7_2, _7_3)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// case 536870912 {
|
||||
// switch _2_2
|
||||
// case 0 {
|
||||
// switch _2_3
|
||||
// case 16 {
|
||||
// let _5_0 := 0
|
||||
// let _5_1 := 0
|
||||
// let _5_2 := 0
|
||||
// let _5_3 := 1
|
||||
// let _6_0 := 0
|
||||
// let _6_1 := 0
|
||||
// let _6_2 := 0
|
||||
// let _6_3 := 1
|
||||
// sstore(_6_0, _6_1, _6_2, _6_3, _5_0, _5_1, _5_2, _5_3)
|
||||
// }
|
||||
// case 32 {
|
||||
// let _9_0 := 0
|
||||
// let _9_1 := 0
|
||||
// let _9_2 := 0
|
||||
// let _9_3 := 1
|
||||
// let _10_0 := 0
|
||||
// let _10_1 := 0
|
||||
// let _10_2 := 0
|
||||
// let _10_3 := 3
|
||||
// sstore(_10_0, _10_1, _10_2, _10_3, _9_0, _9_1, _9_2, _9_3)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
89
test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul
Normal file
89
test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul
Normal file
@ -0,0 +1,89 @@
|
||||
{
|
||||
switch calldataload(0)
|
||||
case 0 { sstore(0, 1) }
|
||||
case 1 { sstore(1, 1) }
|
||||
case 2 { sstore(2, 1) }
|
||||
case 3 { sstore(3, 1) }
|
||||
default { sstore(8, 9) }
|
||||
}
|
||||
// ====
|
||||
// step: wordSizeTransform
|
||||
// ----
|
||||
// {
|
||||
// let _1_0 := 0
|
||||
// let _1_1 := 0
|
||||
// let _1_2 := 0
|
||||
// let _1_3 := 0
|
||||
// let _2_0, _2_1, _2_2, _2_3 := calldataload(_1_0, _1_1, _1_2, _1_3)
|
||||
// let run_default
|
||||
// switch _2_0
|
||||
// case 0 {
|
||||
// switch _2_1
|
||||
// case 0 {
|
||||
// switch _2_2
|
||||
// case 0 {
|
||||
// switch _2_3
|
||||
// case 0 {
|
||||
// let _3_0 := 0
|
||||
// let _3_1 := 0
|
||||
// let _3_2 := 0
|
||||
// let _3_3 := 1
|
||||
// let _4_0 := 0
|
||||
// let _4_1 := 0
|
||||
// let _4_2 := 0
|
||||
// let _4_3 := 0
|
||||
// sstore(_4_0, _4_1, _4_2, _4_3, _3_0, _3_1, _3_2, _3_3)
|
||||
// }
|
||||
// case 1 {
|
||||
// let _5_0 := 0
|
||||
// let _5_1 := 0
|
||||
// let _5_2 := 0
|
||||
// let _5_3 := 1
|
||||
// let _6_0 := 0
|
||||
// let _6_1 := 0
|
||||
// let _6_2 := 0
|
||||
// let _6_3 := 1
|
||||
// sstore(_6_0, _6_1, _6_2, _6_3, _5_0, _5_1, _5_2, _5_3)
|
||||
// }
|
||||
// case 2 {
|
||||
// let _7_0 := 0
|
||||
// let _7_1 := 0
|
||||
// let _7_2 := 0
|
||||
// let _7_3 := 1
|
||||
// let _8_0 := 0
|
||||
// let _8_1 := 0
|
||||
// let _8_2 := 0
|
||||
// let _8_3 := 2
|
||||
// sstore(_8_0, _8_1, _8_2, _8_3, _7_0, _7_1, _7_2, _7_3)
|
||||
// }
|
||||
// case 3 {
|
||||
// let _9_0 := 0
|
||||
// let _9_1 := 0
|
||||
// let _9_2 := 0
|
||||
// let _9_3 := 1
|
||||
// let _10_0 := 0
|
||||
// let _10_1 := 0
|
||||
// let _10_2 := 0
|
||||
// let _10_3 := 3
|
||||
// sstore(_10_0, _10_1, _10_2, _10_3, _9_0, _9_1, _9_2, _9_3)
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// if run_default
|
||||
// {
|
||||
// let _11_0 := 0
|
||||
// let _11_1 := 0
|
||||
// let _11_2 := 0
|
||||
// let _11_3 := 9
|
||||
// let _12_0 := 0
|
||||
// let _12_1 := 0
|
||||
// let _12_2 := 0
|
||||
// let _12_3 := 8
|
||||
// sstore(_12_0, _12_1, _12_2, _12_3, _11_0, _11_1, _11_2, _11_3)
|
||||
// }
|
||||
// }
|
97
test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul
Normal file
97
test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul
Normal file
@ -0,0 +1,97 @@
|
||||
{
|
||||
switch calldataload(0)
|
||||
case 0x01000000000000000000000000000000000000010 { sstore(0, 1) }
|
||||
case 0x02000000000000000000000000000000000000010 { sstore(1, 1) }
|
||||
case 0x01000000000000000000000000000000000000020 { sstore(2, 1) }
|
||||
case 0x02000000000000000000000000000000000000020 { sstore(3, 1) }
|
||||
default { sstore(8, 9) }
|
||||
}
|
||||
// ====
|
||||
// step: wordSizeTransform
|
||||
// ----
|
||||
// {
|
||||
// let _1_0 := 0
|
||||
// let _1_1 := 0
|
||||
// let _1_2 := 0
|
||||
// let _1_3 := 0
|
||||
// let _2_0, _2_1, _2_2, _2_3 := calldataload(_1_0, _1_1, _1_2, _1_3)
|
||||
// let run_default
|
||||
// switch _2_0
|
||||
// case 0 {
|
||||
// switch _2_1
|
||||
// case 268435456 {
|
||||
// switch _2_2
|
||||
// case 0 {
|
||||
// switch _2_3
|
||||
// case 16 {
|
||||
// let _3_0 := 0
|
||||
// let _3_1 := 0
|
||||
// let _3_2 := 0
|
||||
// let _3_3 := 1
|
||||
// let _4_0 := 0
|
||||
// let _4_1 := 0
|
||||
// let _4_2 := 0
|
||||
// let _4_3 := 0
|
||||
// sstore(_4_0, _4_1, _4_2, _4_3, _3_0, _3_1, _3_2, _3_3)
|
||||
// }
|
||||
// case 32 {
|
||||
// let _7_0 := 0
|
||||
// let _7_1 := 0
|
||||
// let _7_2 := 0
|
||||
// let _7_3 := 1
|
||||
// let _8_0 := 0
|
||||
// let _8_1 := 0
|
||||
// let _8_2 := 0
|
||||
// let _8_3 := 2
|
||||
// sstore(_8_0, _8_1, _8_2, _8_3, _7_0, _7_1, _7_2, _7_3)
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// }
|
||||
// case 536870912 {
|
||||
// switch _2_2
|
||||
// case 0 {
|
||||
// switch _2_3
|
||||
// case 16 {
|
||||
// let _5_0 := 0
|
||||
// let _5_1 := 0
|
||||
// let _5_2 := 0
|
||||
// let _5_3 := 1
|
||||
// let _6_0 := 0
|
||||
// let _6_1 := 0
|
||||
// let _6_2 := 0
|
||||
// let _6_3 := 1
|
||||
// sstore(_6_0, _6_1, _6_2, _6_3, _5_0, _5_1, _5_2, _5_3)
|
||||
// }
|
||||
// case 32 {
|
||||
// let _9_0 := 0
|
||||
// let _9_1 := 0
|
||||
// let _9_2 := 0
|
||||
// let _9_3 := 1
|
||||
// let _10_0 := 0
|
||||
// let _10_1 := 0
|
||||
// let _10_2 := 0
|
||||
// let _10_3 := 3
|
||||
// sstore(_10_0, _10_1, _10_2, _10_3, _9_0, _9_1, _9_2, _9_3)
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// }
|
||||
// default { run_default := 1 }
|
||||
// if run_default
|
||||
// {
|
||||
// let _11_0 := 0
|
||||
// let _11_1 := 0
|
||||
// let _11_2 := 0
|
||||
// let _11_3 := 9
|
||||
// let _12_0 := 0
|
||||
// let _12_1 := 0
|
||||
// let _12_2 := 0
|
||||
// let _12_3 := 8
|
||||
// sstore(_12_0, _12_1, _12_2, _12_3, _11_0, _11_1, _11_2, _11_3)
|
||||
// }
|
||||
// }
|
29
test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul
Normal file
29
test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
switch calldataload(0)
|
||||
default { sstore(8, 9) }
|
||||
}
|
||||
// ====
|
||||
// step: wordSizeTransform
|
||||
// ----
|
||||
// {
|
||||
// let _1_0 := 0
|
||||
// let _1_1 := 0
|
||||
// let _1_2 := 0
|
||||
// let _1_3 := 0
|
||||
// let _2_0, _2_1, _2_2, _2_3 := calldataload(_1_0, _1_1, _1_2, _1_3)
|
||||
// let run_default
|
||||
// switch _2_0
|
||||
// default { run_default := 1 }
|
||||
// if run_default
|
||||
// {
|
||||
// let _3_0 := 0
|
||||
// let _3_1 := 0
|
||||
// let _3_2 := 0
|
||||
// let _3_3 := 9
|
||||
// let _4_0 := 0
|
||||
// let _4_1 := 0
|
||||
// let _4_2 := 0
|
||||
// let _4_3 := 8
|
||||
// sstore(_4_0, _4_1, _4_2, _4_3, _3_0, _3_1, _3_2, _3_3)
|
||||
// }
|
||||
// }
|
Loading…
Reference in New Issue
Block a user