diff options
author | chriseth <chris@ethereum.org> | 2018-04-11 23:18:31 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-11 23:18:31 +0800 |
commit | d50d1f0ac1841a1d287a216451e93573fc07474e (patch) | |
tree | d24720a3bdf4d78de4436d88721e907ce91a367a | |
parent | 29bde7fc2a6f6fc82b90f6963a536553b9eea04e (diff) | |
parent | 2e73ef5ac5db406e86e3a90c89d3be4b0d666073 (diff) | |
download | dexon-solidity-d50d1f0ac1841a1d287a216451e93573fc07474e.tar dexon-solidity-d50d1f0ac1841a1d287a216451e93573fc07474e.tar.gz dexon-solidity-d50d1f0ac1841a1d287a216451e93573fc07474e.tar.bz2 dexon-solidity-d50d1f0ac1841a1d287a216451e93573fc07474e.tar.lz dexon-solidity-d50d1f0ac1841a1d287a216451e93573fc07474e.tar.xz dexon-solidity-d50d1f0ac1841a1d287a216451e93573fc07474e.tar.zst dexon-solidity-d50d1f0ac1841a1d287a216451e93573fc07474e.zip |
Merge pull request #3580 from ethereum/asm-bitshift-optim
Add simplification rule for bitwise shifting
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | libevmasm/RuleList.h | 10 | ||||
-rwxr-xr-x | scripts/tests.sh | 9 | ||||
-rw-r--r-- | test/libsolidity/InlineAssembly.cpp | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 129 |
5 files changed, 150 insertions, 1 deletions
diff --git a/Changelog.md b/Changelog.md index c918f171..6df11f27 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Features: * General: Limit the number of errors output in a single run to 256. * General: Support accessing dynamic return data in post-byzantium EVMs. * Interfaces: Allow overriding external functions in interfaces with public in an implementing contract. + * Optimizer: Optimize ``SHL`` and ``SHR`` only involving constants (Constantinople only). * Optimizer: Remove useless ``SWAP1`` instruction preceding a commutative instruction (such as ``ADD``, ``MUL``, etc). * Optimizer: Replace comparison operators (``LT``, ``GT``, etc) with opposites if preceded by ``SWAP1``, e.g. ``SWAP1 LT`` is replaced with ``GT``. * Optimizer: Optimize across ``mload`` if ``msize()`` is not used. diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h index da522cec..abcf170c 100644 --- a/libevmasm/RuleList.h +++ b/libevmasm/RuleList.h @@ -89,6 +89,16 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList( u256 mask = (u256(1) << testBit) - 1; return u256(boost::multiprecision::bit_test(B.d(), testBit) ? B.d() | ~mask : B.d() & mask); }, false}, + {{Instruction::SHL, {A, B}}, [=]{ + if (A.d() > 255) + return u256(0); + return u256(bigint(B.d()) << unsigned(A.d())); + }, false}, + {{Instruction::SHR, {A, B}}, [=]{ + if (A.d() > 255) + return u256(0); + return B.d() >> unsigned(A.d()); + }, false}, // invariants involving known constants {{Instruction::ADD, {X, 0}}, [=]{ return X; }, false}, diff --git a/scripts/tests.sh b/scripts/tests.sh index 2e40f8cb..542c932a 100755 --- a/scripts/tests.sh +++ b/scripts/tests.sh @@ -99,11 +99,18 @@ then progress="" fi +EVM_VERSIONS="homestead byzantium" + +if [ "$CIRCLECI" ] || [ -z "$CI" ] +then +EVM_VERSIONS+=" constantinople" +fi + # And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer # and homestead / byzantium VM, # pointing to that IPC endpoint. for optimize in "" "--optimize" do - for vm in homestead byzantium + for vm in $EVM_VERSIONS do echo "--> Running tests using "$optimize" --evm-version "$vm"..." log="" diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 34ca33e3..0ced1792 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -783,6 +783,8 @@ BOOST_AUTO_TEST_CASE(shift) BOOST_AUTO_TEST_CASE(shift_constantinople_warning) { + if (dev::test::Options::get().evmVersion().hasBitwiseShifting()) + return; CHECK_PARSE_WARNING("{ pop(shl(10, 32)) }", Warning, "The \"shl\" instruction is only available for Constantinople-compatible VMs."); CHECK_PARSE_WARNING("{ pop(shr(10, 32)) }", Warning, "The \"shr\" instruction is only available for Constantinople-compatible VMs."); CHECK_PARSE_WARNING("{ pop(sar(10, 32)) }", Warning, "The \"sar\" instruction is only available for Constantinople-compatible VMs."); diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 5ed53a2f..39f4b03e 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -11141,6 +11141,135 @@ BOOST_AUTO_TEST_CASE(swap_peephole_optimisation) BOOST_CHECK(callContractFunction("div(uint256,uint256)", u256(0), u256(1)) == encodeArgs(u256(0))); } +BOOST_AUTO_TEST_CASE(bitwise_shifting_constantinople) +{ + if (!dev::test::Options::get().evmVersion().hasBitwiseShifting()) + return; + char const* sourceCode = R"( + contract C { + function shl(uint a, uint b) returns (uint c) { + assembly { + a + b + shl + =: c + } + } + function shr(uint a, uint b) returns (uint c) { + assembly { + a + b + shr + =: c + } + } + function sar(uint a, uint b) returns (uint c) { + assembly { + a + b + sar + =: c + } + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("shl(uint256,uint256)", u256(1), u256(2)) == encodeArgs(u256(4))); + BOOST_CHECK(callContractFunction("shl(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(1)) == encodeArgs(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"))); + BOOST_CHECK(callContractFunction("shl(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(256)) == encodeArgs(u256(0))); + BOOST_CHECK(callContractFunction("shr(uint256,uint256)", u256(3), u256(1)) == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("shr(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(1)) == encodeArgs(u256("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); + BOOST_CHECK(callContractFunction("shr(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(255)) == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("shr(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(256)) == encodeArgs(u256(0))); + BOOST_CHECK(callContractFunction("sar(uint256,uint256)", u256(3), u256(1)) == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("sar(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(1)) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); + BOOST_CHECK(callContractFunction("sar(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(255)) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); + BOOST_CHECK(callContractFunction("sar(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(256)) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); +} + +BOOST_AUTO_TEST_CASE(bitwise_shifting_constants_constantinople) +{ + if (!dev::test::Options::get().evmVersion().hasBitwiseShifting()) + return; + char const* sourceCode = R"( + contract C { + function shl_1() returns (bool) { + uint c; + assembly { + 1 + 2 + shl + =: c + } + assert(c == 4); + return true; + } + function shl_2() returns (bool) { + uint c; + assembly { + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + 1 + shl + =: c + } + assert(c == 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe); + return true; + } + function shl_3() returns (bool) { + uint c; + assembly { + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + 256 + shl + =: c + } + assert(c == 0); + return true; + } + function shr_1() returns (bool) { + uint c; + assembly { + 3 + 1 + shr + =: c + } + assert(c == 1); + return true; + } + function shr_2() returns (bool) { + uint c; + assembly { + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + 1 + shr + =: c + } + assert(c == 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + return true; + } + function shr_3() returns (bool) { + uint c; + assembly { + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + 256 + shr + =: c + } + assert(c == 0); + return true; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("shl_1()") == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("shl_2()") == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("shl_3()") == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("shr_1()") == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("shr_2()") == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("shr_3()") == encodeArgs(u256(1))); +} + BOOST_AUTO_TEST_SUITE_END() } |