diff --git a/Changelog.md b/Changelog.md index 8697c8a3d..f057db3d6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,8 @@ Language Features: Compiler Features: * SMTChecker: Support arithmetic compound assignment operators. + * Optimizer: Add rule for shifts by constants larger than 255 for Constantinople. + * Optimizer: Add rule to simplify certain ANDs and SHL combinations * Yul: Adds break and continue keywords to for-loop syntax. diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h index f989fb801..eecef224e 100644 --- a/libevmasm/RuleList.h +++ b/libevmasm/RuleList.h @@ -216,7 +216,7 @@ std::vector> simplificationRuleListPart4( template std::vector> simplificationRuleListPart5( - Pattern, + Pattern A, Pattern, Pattern, Pattern X, @@ -236,6 +236,22 @@ std::vector> simplificationRuleListPart5( }); } + // Replace SHL >=256, X with 0 + rules.push_back({ + {Instruction::SHL, {A, X}}, + [=]() -> Pattern { return u256(0); }, + true, + [=]() { return A.d() >= 256; } + }); + + // Replace SHR >=256, X with 0 + rules.push_back({ + {Instruction::SHR, {A, X}}, + [=]() -> Pattern { return u256(0); }, + true, + [=]() { return A.d() >= 256; } + }); + for (auto const& op: std::vector{ Instruction::ADDRESS, Instruction::CALLER, @@ -375,6 +391,30 @@ std::vector> simplificationRuleListPart7( false }); + + std::function feasibilityFunction = [=]() { + if (B.d() > 256) + return false; + unsigned bAsUint = static_cast(B.d()); + return (A.d() & (u256(-1) >> bAsUint)) == (u256(-1) >> bAsUint); + }; + + rules.push_back({ + // AND(A, SHR(B, X)) -> A & ((2^256-1) >> B) == ((2^256-1) >> B) + {Instruction::AND, {A, {Instruction::SHR, {B, X}}}}, + [=]() -> Pattern { return {Instruction::SHR, {B, X}}; }, + false, + feasibilityFunction + }); + + rules.push_back({ + // AND(SHR(B, X), A) -> ((2^256-1) >> B) & A == ((2^256-1) >> B) + {Instruction::AND, {{Instruction::SHR, {B, X}}, A}}, + [=]() -> Pattern { return {Instruction::SHR, {B, X}}; }, + false, + feasibilityFunction + }); + return rules; } diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index 97632e348..869e91c83 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -1180,6 +1180,84 @@ BOOST_AUTO_TEST_CASE(cse_sub_zero) }); } +BOOST_AUTO_TEST_CASE(cse_remove_redundant_shift_masking) +{ + if (!dev::test::Options::get().evmVersion().hasBitwiseShifting()) + return; + + for (int i = 1; i < 256; i++) + { + checkCSE({ + u256(boost::multiprecision::pow(u256(2), i)-1), + Instruction::CALLVALUE, + u256(256-i), + Instruction::SHR, + Instruction::AND + }, { + Instruction::CALLVALUE, + u256(256-i), + Instruction::SHR, + }); + + checkCSE({ + Instruction::CALLVALUE, + u256(256-i), + Instruction::SHR, + u256(boost::multiprecision::pow(u256(2), i)-1), + Instruction::AND + }, { + Instruction::CALLVALUE, + u256(256-i), + Instruction::SHR, + }); + } + + // Check that opt. does NOT trigger + for (int i = 1; i < 255; i++) + { + checkCSE({ + u256(boost::multiprecision::pow(u256(2), i)-1), + Instruction::CALLVALUE, + u256(255-i), + Instruction::SHR, + Instruction::AND + }, { // Opt. did some reordering + Instruction::CALLVALUE, + u256(255-i), + Instruction::SHR, + u256(boost::multiprecision::pow(u256(2), i)-1), + Instruction::AND + }); + + checkCSE({ + Instruction::CALLVALUE, + u256(255-i), + Instruction::SHR, + u256(boost::multiprecision::pow(u256(2), i)-1), + Instruction::AND + }, { // Opt. did some reordering + u256(boost::multiprecision::pow(u256(2), i)-1), + Instruction::CALLVALUE, + u256(255-i), + Instruction::SHR, + Instruction::AND + }); + } + + //(x >> (31*8)) & 0xffffffff + checkCSE({ + Instruction::CALLVALUE, + u256(31*8), + Instruction::SHR, + u256(0xffffffff), + Instruction::AND + }, { + Instruction::CALLVALUE, + u256(31*8), + Instruction::SHR + }); +} + BOOST_AUTO_TEST_CASE(cse_remove_unwanted_masking_of_address) { vector ops{ @@ -1250,6 +1328,48 @@ BOOST_AUTO_TEST_CASE(cse_remove_unwanted_masking_of_address) }); } +BOOST_AUTO_TEST_CASE(cse_replace_too_large_shift) +{ + if (!dev::test::Options::get().evmVersion().hasBitwiseShifting()) + return; + + checkCSE({ + Instruction::CALLVALUE, + u256(299), + Instruction::SHL + }, { + u256(0) + }); + + checkCSE({ + Instruction::CALLVALUE, + u256(299), + Instruction::SHR + }, { + u256(0) + }); + + checkCSE({ + Instruction::CALLVALUE, + u256(255), + Instruction::SHL + }, { + Instruction::CALLVALUE, + u256(255), + Instruction::SHL + }); + + checkCSE({ + Instruction::CALLVALUE, + u256(255), + Instruction::SHR + }, { + Instruction::CALLVALUE, + u256(255), + Instruction::SHR + }); +} + BOOST_AUTO_TEST_SUITE_END() }