From 8047171a131779a6f1816339a0a380a51da7b548 Mon Sep 17 00:00:00 2001 From: Reuben Rodrigues Date: Thu, 8 Sep 2022 15:28:57 +0200 Subject: [PATCH] PeepholeOptimizer: StaticIfComparisons --- libevmasm/PeepholeOptimiser.cpp | 88 ++++++++++++++++++++++++++++++++- test/libevmasm/Optimiser.cpp | 64 ++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 1 deletion(-) diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index 334903c92..6efc849a9 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -428,6 +428,92 @@ struct TruthyAnd: SimplePeepholeOptimizerMethod } }; +// if(a == true) -> if (a) +struct TruthyEqualComparison: SimplePeepholeOptimizerMethod{ + static bool applySimple( + AssemblyItem const& _iszero, + AssemblyItem const& _iszero1, + AssemblyItem const& _push1, + AssemblyItem const& _eq, + std::back_insert_iterator + ) + { + if ( + _iszero == Instruction::ISZERO && + _iszero1 == Instruction::ISZERO && + _push1.type() == Push && _push1.data() == 1 && + _eq == Instruction::EQ + ) + { + return true; + } else + return false; + } +}; + +// if(a != true) -> if(!a) +struct TruthyInequalComparison: SimplePeepholeOptimizerMethod{ + static bool applySimple( + AssemblyItem const& _iszero, + AssemblyItem const& _iszero1, + AssemblyItem const& _push1, + AssemblyItem const& _sub, + AssemblyItem const& _pushTag, + AssemblyItem const& _jumpi, + std::back_insert_iterator _out + ) + { + if ( + _iszero == Instruction::ISZERO && + _iszero1 == Instruction::ISZERO && + _push1.type() == Push && _push1.data() == 1 && + _sub == Instruction::SUB && + _pushTag.type() == PushTag && + _jumpi == Instruction::JUMPI + ) + { + *_out = _iszero; + *_out = _pushTag; + *_out = _jumpi; + return true; + } else + return false; + } +}; + +// if(true != a) -> if(!a) +struct ReverseTruthyInequalComparison: SimplePeepholeOptimizerMethod{ + static bool applySimple( + AssemblyItem const& _push1, + AssemblyItem const& _swap1, + AssemblyItem const& _iszero, + AssemblyItem const& _iszero1, + AssemblyItem const& _sub, + AssemblyItem const& _pushTag, + AssemblyItem const& _jumpi, + std::back_insert_iterator _out + ) + { + if ( + _push1.type() == Push && _push1.data() == 1 && + SemanticInformation::isSwapInstruction(_swap1) && + getSwapNumber(_swap1.instruction()) == 1 && + _iszero == Instruction::ISZERO && + _iszero1 == Instruction::ISZERO && + _sub == Instruction::SUB && + _pushTag.type() == PushTag && + _jumpi == Instruction::JUMPI + ) + { + *_out = _iszero; + *_out = _pushTag; + *_out = _jumpi; + return true; + } else + return false; + } +}; + /// Removes everything after a JUMP (or similar) until the next JUMPDEST. struct UnreachableCode { @@ -488,7 +574,7 @@ bool PeepholeOptimiser::optimise() while (state.i < m_items.size()) applyMethods( state, - PushPop(), OpPop(), OpStop(), OpReturnRevert(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(), + TruthyEqualComparison(), TruthyInequalComparison(), ReverseTruthyInequalComparison(), PushPop(), OpPop(), OpStop(), OpReturnRevert(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(), DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(), TagConjunctions(), TruthyAnd(), Identity() ); diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index 6fc3c5a74..e98ab6acf 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -975,6 +975,70 @@ BOOST_AUTO_TEST_CASE(block_deduplicator_loops) BOOST_CHECK_EQUAL(pushTags.size(), 1); } +BOOST_AUTO_TEST_CASE(peephole_truthy_equal_comparison) +{ + AssemblyItems items{ + Instruction::ISZERO, + Instruction::ISZERO, + AssemblyItem(Push, 1), + Instruction::EQ, + }; + AssemblyItems expectation{}; + PeepholeOptimiser peepOpt(items); + BOOST_REQUIRE(peepOpt.optimise()); + BOOST_CHECK_EQUAL_COLLECTIONS( + items.begin(), items.end(), + expectation.begin(), expectation.end() + ); +} + +BOOST_AUTO_TEST_CASE(peephole_truthy_inequal_comparison) +{ + AssemblyItems items{ + Instruction::ISZERO, + Instruction::ISZERO, + AssemblyItem(Push, 1), + Instruction::SUB, + AssemblyItem(PushTag, 1), + Instruction::JUMPI + }; + AssemblyItems expectation{ + Instruction::ISZERO, + AssemblyItem(PushTag, 1), + Instruction::JUMPI + }; + PeepholeOptimiser peepOpt(items); + BOOST_REQUIRE(peepOpt.optimise()); + BOOST_CHECK_EQUAL_COLLECTIONS( + items.begin(), items.end(), + expectation.begin(), expectation.end() + ); +} + +BOOST_AUTO_TEST_CASE(peephole_reverse_truthy_inequal_comparison) +{ + AssemblyItems items{ + AssemblyItem(Push, 1), + Instruction::SWAP1, + Instruction::ISZERO, + Instruction::ISZERO, + Instruction::SUB, + AssemblyItem(PushTag, 1), + Instruction::JUMPI + }; + AssemblyItems expectation{ + Instruction::ISZERO, + AssemblyItem(PushTag, 1), + Instruction::JUMPI + }; + PeepholeOptimiser peepOpt(items); + BOOST_REQUIRE(peepOpt.optimise()); + BOOST_CHECK_EQUAL_COLLECTIONS( + items.begin(), items.end(), + expectation.begin(), expectation.end() + ); +} + BOOST_AUTO_TEST_CASE(clear_unreachable_code) { AssemblyItems items{