Merge pull request #6213 from ethereum/iszeroJump

Peephole optimizer for "iszero iszero <tag> jumpi".
This commit is contained in:
chriseth 2019-03-07 18:16:29 +01:00 committed by GitHub
commit 5c4a3aa270
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 169 additions and 96 deletions

View File

@ -5,6 +5,7 @@ Language Features:
Compiler Features: Compiler Features:
* Peephole Optimizer: Remove double ``iszero`` before ``jumpi``.
* SMTChecker: Support enums without typecast. * SMTChecker: Support enums without typecast.
* SMTChecker: Support one-dimensional arrays. * SMTChecker: Support one-dimensional arrays.
* Yul Optimizer: Add rule to remove empty default switch cases * Yul Optimizer: Add rule to remove empty default switch cases

View File

@ -45,6 +45,14 @@ struct ApplyRule
{ {
}; };
template <class Method> template <class Method>
struct ApplyRule<Method, 4>
{
static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator<AssemblyItems> _out)
{
return Method::applySimple(_in[0], _in[1], _in[2], _in[3], _out);
}
};
template <class Method>
struct ApplyRule<Method, 3> struct ApplyRule<Method, 3>
{ {
static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator<AssemblyItems> _out) static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator<AssemblyItems> _out)
@ -197,6 +205,32 @@ struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison, 2>
} }
}; };
struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod<IsZeroIsZeroJumpI, 4>
{
static size_t applySimple(
AssemblyItem const& _iszero1,
AssemblyItem const& _iszero2,
AssemblyItem const& _pushTag,
AssemblyItem const& _jumpi,
std::back_insert_iterator<AssemblyItems> _out
)
{
if (
_iszero1 == Instruction::ISZERO &&
_iszero2 == Instruction::ISZERO &&
_pushTag.type() == PushTag &&
_jumpi == Instruction::JUMPI
)
{
*_out = _pushTag;
*_out = _jumpi;
return true;
}
else
return false;
}
};
struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext, 3> struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext, 3>
{ {
static size_t applySimple( static size_t applySimple(
@ -320,7 +354,12 @@ bool PeepholeOptimiser::optimise()
{ {
OptimiserState state {m_items, 0, std::back_inserter(m_optimisedItems)}; OptimiserState state {m_items, 0, std::back_inserter(m_optimisedItems)};
while (state.i < m_items.size()) while (state.i < m_items.size())
applyMethods(state, PushPop(), OpPop(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(), JumpToNext(), UnreachableCode(), TagConjunctions(), TruthyAnd(), Identity()); applyMethods(
state,
PushPop(), OpPop(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(),
IsZeroIsZeroJumpI(), JumpToNext(), UnreachableCode(),
TagConjunctions(), TruthyAnd(), Identity()
);
if (m_optimisedItems.size() < m_items.size() || ( if (m_optimisedItems.size() < m_items.size() || (
m_optimisedItems.size() == m_items.size() && ( m_optimisedItems.size() == m_items.size() && (
eth::bytesRequired(m_optimisedItems, 3) < eth::bytesRequired(m_items, 3) || eth::bytesRequired(m_optimisedItems, 3) < eth::bytesRequired(m_items, 3) ||

View File

@ -2,6 +2,6 @@
======= data_storage/input.sol:C ======= ======= data_storage/input.sol:C =======
Gas estimation: Gas estimation:
construction: construction:
300 + 258600 = 258900 294 + 255000 = 255294
external: external:
f(): 258 f(): 252

View File

@ -2,10 +2,10 @@
======= gas_test_abiv2/input.sol:C ======= ======= gas_test_abiv2/input.sol:C =======
Gas estimation: Gas estimation:
construction: construction:
1147 + 1103000 = 1104147 1140 + 1096600 = 1097740
external: external:
a(): 530 a(): 530
b(uint256): 1124 b(uint256): 1118
f1(uint256): 586 f1(uint256): 586
f2(uint256[],string[],uint16,address): infinite f2(uint256[],string[],uint16,address): infinite
f3(uint16[],string[],uint16,address): infinite f3(uint16[],string[],uint16,address): infinite

View File

@ -2,10 +2,10 @@
======= gas_test_abiv2_optimize_yul/input.sol:C ======= ======= gas_test_abiv2_optimize_yul/input.sol:C =======
Gas estimation: Gas estimation:
construction: construction:
651 + 617400 = 618051 651 + 617200 = 617851
external: external:
a(): 429 a(): 429
b(uint256): 887 b(uint256): 884
f1(uint256): 351 f1(uint256): 351
f2(uint256[],string[],uint16,address): infinite f2(uint256[],string[],uint16,address): infinite
f3(uint16[],string[],uint16,address): infinite f3(uint16[],string[],uint16,address): infinite

View File

@ -2,52 +2,52 @@
======= gas_test_dispatch/input.sol:Large ======= ======= gas_test_dispatch/input.sol:Large =======
Gas estimation: Gas estimation:
construction: construction:
683 + 650600 = 651283 670 + 635000 = 635670
external: external:
a(): 451 a(): 451
b(uint256): 852 b(uint256): 846
f0(uint256): 433 f0(uint256): 427
f1(uint256): 40764 f1(uint256): 40752
f2(uint256): 20705 f2(uint256): 20693
f3(uint256): 20793 f3(uint256): 20781
f4(uint256): 20771 f4(uint256): 20759
f5(uint256): 20749 f5(uint256): 20737
f6(uint256): 20772 f6(uint256): 20760
f7(uint256): 20684 f7(uint256): 20672
f8(uint256): 20684 f8(uint256): 20672
f9(uint256): 20706 f9(uint256): 20694
g0(uint256): 319 g0(uint256): 313
g1(uint256): 40719 g1(uint256): 40707
g2(uint256): 20682 g2(uint256): 20670
g3(uint256): 20770 g3(uint256): 20758
g4(uint256): 20748 g4(uint256): 20736
g5(uint256): 20704 g5(uint256): 20692
g6(uint256): 20727 g6(uint256): 20715
g7(uint256): 20726 g7(uint256): 20714
g8(uint256): 20704 g8(uint256): 20692
g9(uint256): 20661 g9(uint256): 20649
======= gas_test_dispatch/input.sol:Medium ======= ======= gas_test_dispatch/input.sol:Medium =======
Gas estimation: Gas estimation:
construction: construction:
300 + 256800 = 257100 294 + 251200 = 251494
external: external:
a(): 428 a(): 428
b(uint256): 852 b(uint256): 846
f1(uint256): 40675 f1(uint256): 40663
f2(uint256): 20705 f2(uint256): 20693
f3(uint256): 20749 f3(uint256): 20737
g0(uint256): 319 g0(uint256): 313
g7(uint256): 20704 g7(uint256): 20692
g8(uint256): 20682 g8(uint256): 20670
g9(uint256): 20638 g9(uint256): 20626
======= gas_test_dispatch/input.sol:Small ======= ======= gas_test_dispatch/input.sol:Small =======
Gas estimation: Gas estimation:
construction: construction:
129 + 83000 = 83129 129 + 81800 = 81929
external: external:
fallback: 118 fallback: 118
a(): 383 a(): 383
b(uint256): 808 b(uint256): 802
f1(uint256): 40675 f1(uint256): 40663

View File

@ -2,52 +2,52 @@
======= gas_test_dispatch_optimize/input.sol:Large ======= ======= gas_test_dispatch_optimize/input.sol:Large =======
Gas estimation: Gas estimation:
construction: construction:
300 + 259200 = 259500 300 + 260400 = 260700
external: external:
a(): 398 a(): 398
b(uint256): 1108 b(uint256): 1105
f0(uint256): 334 f0(uint256): 334
f1(uint256): 40898 f1(uint256): 40892
f2(uint256): 20958 f2(uint256): 20952
f3(uint256): 21046 f3(uint256): 21040
f4(uint256): 21024 f4(uint256): 21018
f5(uint256): 21002 f5(uint256): 20996
f6(uint256): 20914 f6(uint256): 20908
f7(uint256): 20694 f7(uint256): 20688
f8(uint256): 20826 f8(uint256): 20820
f9(uint256): 20848 f9(uint256): 20842
g0(uint256): 574 g0(uint256): 574
g1(uint256): 40610 g1(uint256): 40604
g2(uint256): 20692 g2(uint256): 20686
g3(uint256): 20780 g3(uint256): 20774
g4(uint256): 20758 g4(uint256): 20752
g5(uint256): 20846 g5(uint256): 20840
g6(uint256): 20626 g6(uint256): 20620
g7(uint256): 20736 g7(uint256): 20730
g8(uint256): 20714 g8(uint256): 20708
g9(uint256): 20560 g9(uint256): 20554
======= gas_test_dispatch_optimize/input.sol:Medium ======= ======= gas_test_dispatch_optimize/input.sol:Medium =======
Gas estimation: Gas estimation:
construction: construction:
183 + 140200 = 140383 183 + 140800 = 140983
external: external:
a(): 398 a(): 398
b(uint256): 866 b(uint256): 863
f1(uint256): 40678 f1(uint256): 40672
f2(uint256): 20716 f2(uint256): 20710
f3(uint256): 20760 f3(uint256): 20754
g0(uint256): 332 g0(uint256): 332
g7(uint256): 20626 g7(uint256): 20620
g8(uint256): 20604 g8(uint256): 20598
g9(uint256): 20560 g9(uint256): 20554
======= gas_test_dispatch_optimize/input.sol:Small ======= ======= gas_test_dispatch_optimize/input.sol:Small =======
Gas estimation: Gas estimation:
construction: construction:
117 + 64600 = 64717 111 + 64000 = 64111
external: external:
fallback: 118 fallback: 118
a(): 376 a(): 376
b(uint256): 756 b(uint256): 753
f1(uint256): 40612 f1(uint256): 40606

View File

@ -969,27 +969,60 @@ BOOST_AUTO_TEST_CASE(peephole_swap_comparison)
BOOST_AUTO_TEST_CASE(peephole_truthy_and) BOOST_AUTO_TEST_CASE(peephole_truthy_and)
{ {
AssemblyItems items{ AssemblyItems items{
AssemblyItem(Tag, 1), AssemblyItem(Tag, 1),
Instruction::BALANCE, Instruction::BALANCE,
u256(0), u256(0),
Instruction::NOT, Instruction::NOT,
Instruction::AND, Instruction::AND,
AssemblyItem(PushTag, 1), AssemblyItem(PushTag, 1),
Instruction::JUMPI Instruction::JUMPI
}; };
AssemblyItems expectation{ AssemblyItems expectation{
AssemblyItem(Tag, 1), AssemblyItem(Tag, 1),
Instruction::BALANCE, Instruction::BALANCE,
AssemblyItem(PushTag, 1), AssemblyItem(PushTag, 1),
Instruction::JUMPI Instruction::JUMPI
}; };
PeepholeOptimiser peepOpt(items); PeepholeOptimiser peepOpt(items);
BOOST_REQUIRE(peepOpt.optimise()); BOOST_REQUIRE(peepOpt.optimise());
BOOST_CHECK_EQUAL_COLLECTIONS( BOOST_CHECK_EQUAL_COLLECTIONS(
items.begin(), items.end(), items.begin(), items.end(),
expectation.begin(), expectation.end() expectation.begin(), expectation.end()
); );
}
BOOST_AUTO_TEST_CASE(peephole_iszero_iszero_jumpi)
{
AssemblyItems items{
AssemblyItem(Tag, 1),
u256(0),
Instruction::CALLDATALOAD,
Instruction::ISZERO,
Instruction::ISZERO,
AssemblyItem(PushTag, 1),
Instruction::JUMPI,
u256(0),
u256(0x20),
Instruction::RETURN
};
AssemblyItems expectation{
AssemblyItem(Tag, 1),
u256(0),
Instruction::CALLDATALOAD,
AssemblyItem(PushTag, 1),
Instruction::JUMPI,
u256(0),
u256(0x20),
Instruction::RETURN
};
PeepholeOptimiser peepOpt(items);
BOOST_REQUIRE(peepOpt.optimise());
BOOST_CHECK_EQUAL_COLLECTIONS(
items.begin(), items.end(),
expectation.begin(), expectation.end()
);
} }
BOOST_AUTO_TEST_CASE(jumpdest_removal) BOOST_AUTO_TEST_CASE(jumpdest_removal)

View File

@ -69,12 +69,12 @@ BOOST_AUTO_TEST_CASE(string_storage)
compileAndRun(sourceCode); compileAndRun(sourceCode);
if (Options::get().evmVersion() <= EVMVersion::byzantium()) if (Options::get().evmVersion() <= EVMVersion::byzantium())
CHECK_GAS(134435, 130591, 100); CHECK_GAS(133899, 130591, 100);
// This is only correct on >=Constantinople. // This is only correct on >=Constantinople.
else if (Options::get().useABIEncoderV2) else if (Options::get().useABIEncoderV2)
CHECK_GAS(151819, 136003, 100); CHECK_GAS(151283, 136003, 100);
else else
CHECK_GAS(127225, 120159, 100); CHECK_GAS(126689, 120159, 100);
if (Options::get().evmVersion() >= EVMVersion::byzantium()) if (Options::get().evmVersion() >= EVMVersion::byzantium())
{ {
callContractFunction("f()"); callContractFunction("f()");