diff --git a/libyul/optimiser/Metrics.cpp b/libyul/optimiser/Metrics.cpp index b3cc3411a..02b5a7179 100644 --- a/libyul/optimiser/Metrics.cpp +++ b/libyul/optimiser/Metrics.cpp @@ -63,6 +63,16 @@ void CodeSize::visit(Statement const& _statement) { if (_statement.type() == typeid(FunctionDefinition) && m_ignoreFunctions) return; + else if ( + _statement.type() == typeid(If) || + _statement.type() == typeid(Break) || + _statement.type() == typeid(Continue) + ) + m_size += 2; + else if (_statement.type() == typeid(ForLoop)) + m_size += 3; + else if (_statement.type() == typeid(Switch)) + m_size += 1 + 2 * boost::get(_statement).cases.size(); else if (!( _statement.type() == typeid(Block) || _statement.type() == typeid(ExpressionStatement) || diff --git a/libyul/optimiser/Metrics.h b/libyul/optimiser/Metrics.h index c0f6a9cd0..1620d4d33 100644 --- a/libyul/optimiser/Metrics.h +++ b/libyul/optimiser/Metrics.h @@ -37,6 +37,11 @@ namespace yul * - variable references * - variable declarations (only the right hand side has a cost) * - assignments (only the value has a cost) + * + * As another exception, each statement incurs and additional cost of one + * per jump/branch. This means if, break and continue statements have a cost of 2, + * switch statements have a cost of 1 plus the number of cases times two, + * and for loops cost 3. */ class CodeSize: public ASTWalker { diff --git a/test/cmdlineTests/gas_test_abiv2_optimize_yul/output b/test/cmdlineTests/gas_test_abiv2_optimize_yul/output index 9b385e47f..9c8ddfb3d 100644 --- a/test/cmdlineTests/gas_test_abiv2_optimize_yul/output +++ b/test/cmdlineTests/gas_test_abiv2_optimize_yul/output @@ -2,7 +2,7 @@ ======= gas_test_abiv2_optimize_yul/input.sol:C ======= Gas estimation: construction: - 651 + 616600 = 617251 + 645 + 608800 = 609445 external: a(): 429 b(uint256): 884 diff --git a/test/libyul/Metrics.cpp b/test/libyul/Metrics.cpp index 185a37552..3fa849c23 100644 --- a/test/libyul/Metrics.cpp +++ b/test/libyul/Metrics.cpp @@ -110,6 +110,69 @@ BOOST_AUTO_TEST_CASE(assignment_complex) BOOST_CHECK_EQUAL(codeSize("{ let a let x := mload(a) a := sload(x) }"), 2); } +BOOST_AUTO_TEST_CASE(empty_for_loop) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ for {} 1 {} {} }" + ), 4); +} + +BOOST_AUTO_TEST_CASE(break_statement) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ for {} 1 {} { break } }" + ), 6); +} + +BOOST_AUTO_TEST_CASE(continue_statement) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ for {} 1 {} { continue } }" + ), 6); +} + +BOOST_AUTO_TEST_CASE(regular_for_loop) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ for { let x := 0 } lt(x, 10) { x := add(x, 1) } { mstore(x, 1) } }" + ), 10); +} + +BOOST_AUTO_TEST_CASE(if_statement) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ if 1 {} }" + ), 3); +} + +BOOST_AUTO_TEST_CASE(switch_statement_tiny) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ switch calldatasize() default {} }" + ), 4); +} + +BOOST_AUTO_TEST_CASE(switch_statement_small) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ switch calldatasize() case 0 {} default {} }" + ), 6); +} + +BOOST_AUTO_TEST_CASE(switch_statement_medium) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ switch calldatasize() case 0 {} case 1 {} case 2 {} }" + ), 8); +} + +BOOST_AUTO_TEST_CASE(switch_statement_large) +{ + BOOST_CHECK_EQUAL(codeSize( + "{ switch calldatasize() case 0 {} case 1 {} case 2 {} default {} }" + ), 10); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul index 4c1991e39..312de61f0 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul @@ -476,44 +476,30 @@ // i := add(i, 1) // } // { -// let _4 := mload(srcPtr) -// let pos_1 := pos -// let srcPtr_1 := _4 -// let i_1 := _2 -// for { -// } -// lt(i_1, 0x3) -// { -// i_1 := add(i_1, 1) -// } -// { -// mstore(pos_1, and(mload(srcPtr_1), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) -// srcPtr_1 := add(srcPtr_1, _1) -// pos_1 := add(pos_1, _1) -// } +// abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(mload(srcPtr), pos) // srcPtr := add(srcPtr, _1) // pos := add(pos, 0x60) // } -// let _5 := mload(64) -// let _6 := mload(_1) -// if slt(sub(_5, _6), 128) +// let _4 := mload(64) +// let _5 := mload(_1) +// if slt(sub(_4, _5), 128) // { // revert(_2, _2) // } -// let offset := calldataload(add(_6, 64)) -// let _7 := 0xffffffffffffffff -// if gt(offset, _7) +// let offset := calldataload(add(_5, 64)) +// let _6 := 0xffffffffffffffff +// if gt(offset, _6) // { // revert(_2, _2) // } -// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_6, offset), _5) -// let offset_1 := calldataload(add(_6, 96)) -// if gt(offset_1, _7) +// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_5, offset), _4) +// let offset_1 := calldataload(add(_5, 96)) +// if gt(offset_1, _6) // { // revert(_2, _2) // } -// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_6, offset_1), _5) -// sstore(calldataload(_6), calldataload(add(_6, _1))) +// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_5, offset_1), _4) +// sstore(calldataload(_5), calldataload(add(_5, _1))) // sstore(value2, value3) // sstore(_2, pos) // } @@ -601,6 +587,22 @@ // src := add(src, _1) // } // } +// function abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(value, pos) +// { +// let srcPtr := value +// let i := 0 +// for { +// } +// lt(i, 0x3) +// { +// i := add(i, 1) +// } +// { +// mstore(pos, and(mload(srcPtr), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) +// srcPtr := add(srcPtr, 0x20) +// pos := add(pos, 0x20) +// } +// } // function allocateMemory(size) -> memPtr // { // memPtr := mload(64)