aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md1
-rw-r--r--libevmasm/RuleList.h10
-rwxr-xr-xscripts/tests.sh9
-rw-r--r--test/libsolidity/InlineAssembly.cpp2
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp129
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()
}