diff --git a/Changelog.md b/Changelog.md index 1aa6bc64b2f4..935717057b16 100644 --- a/Changelog.md +++ b/Changelog.md @@ -17,6 +17,7 @@ Language Features: * Type Checker: Warn about deprecation of `send` and `transfer` functions on instances of `address`. * Type Checker: Warn about deprecation of comparisons between variables of contract types. * Yul: Introduce builtin `clz(x)` for counting the number of leading zero bits in a 256-bit word. +* peepholeoptimiser: Peephole pattern FunctionSelectorGuard added. Compiler Features: diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index 267700e457cd..c6a51855f80a 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -489,7 +489,7 @@ struct JumpToNext: SimplePeepholeOptimizerMethod struct RJumpToNext: SimplePeepholeOptimizerMethod { - static size_t applySimple( + static bool applySimple( AssemblyItem const& _rjump, AssemblyItem const& _tag, std::back_insert_iterator _out @@ -696,6 +696,52 @@ struct DeduplicateNextTagSize1 : SimplePeepholeOptimizerMethod +{ + static bool apply(OptimiserState& _state) + { + size_t window = 6; + if (_state.i + window > _state.items.size()) + return false; + + if (_state.i == 0) + return false; + if (_state.items[_state.i - 1].type() != Tag) + return false; + + auto& a = _state.items[_state.i + 0]; + auto& b = _state.items[_state.i + 1]; + auto& c = _state.items[_state.i + 2]; + auto& d = _state.items[_state.i + 3]; + auto& e = _state.items[_state.i + 4]; + auto& f = _state.items[_state.i + 5]; + + if (a.type() != Push || a.data() != u256(4)) + return false; + + if (!(b == Instruction::CALLDATASIZE)) + return false; + if (!(c == Instruction::LT)) + return false; + if (!(d == Instruction::ISZERO)) + return false; + + if (e.type() != PushTag) + return false; + if (!(f == Instruction::JUMPI)) + return false; + + *_state.out = AssemblyItem(u256(3), a.debugData()); + *_state.out = AssemblyItem(Instruction::CALLDATASIZE, b.debugData()); + *_state.out = AssemblyItem(Instruction::GT, c.debugData()); + *_state.out = e; + *_state.out = f; + + _state.i += window; + return true; + } +}; + template void applyMethods(OptimiserState& _state) { @@ -746,6 +792,7 @@ bool PeepholeOptimiser::optimise() DeduplicateNextTagSize2, DeduplicateNextTagSize1, TagConjunctions, + FunctionSelectorGuard, TruthyAnd, Identity >(state); diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index 01e1f9ac6c83..be03747cf640 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -1479,6 +1479,44 @@ BOOST_AUTO_TEST_CASE(peephole_iszero_iszero_jumpi) ); } +BOOST_AUTO_TEST_CASE(peephole_function_selector_guard) +{ + AssemblyItem tag0 = AssemblyItem(Tag, 0); + AssemblyItem tag1 = AssemblyItem(Tag, 1); + AssemblyItem pushTag1 = AssemblyItem(PushTag, 1); + + AssemblyItems items{ + tag0, + u256(4), + Instruction::CALLDATASIZE, + Instruction::LT, + Instruction::ISZERO, + pushTag1, + Instruction::JUMPI, + tag1, + Instruction::STOP + }; + + AssemblyItems expectation{ + tag0, + u256(3), + Instruction::CALLDATASIZE, + Instruction::GT, + pushTag1, + Instruction::JUMPI, + tag1, + Instruction::STOP + }; + + PeepholeOptimiser peepOpt(items, solidity::test::CommonOptions::get().evmVersion()); + BOOST_REQUIRE(peepOpt.optimise()); + + BOOST_CHECK_EQUAL_COLLECTIONS( + items.begin(), items.end(), + expectation.begin(), expectation.end() + ); +} + BOOST_AUTO_TEST_CASE(jumpdest_removal) { AssemblyItems items{