Skip to content

eof: Enable peephole optimizer for EOF. #15991

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -843,8 +843,7 @@ std::map<u256, u256> const& Assembly::optimiseInternal(
}
}

// TODO: verify this for EOF.
if (_settings.runPeephole && !m_eofVersion.has_value())
if (_settings.runPeephole)
{
for (auto& codeSection: m_codeSections)
{
Expand Down
2 changes: 1 addition & 1 deletion libevmasm/AssemblyItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ class AssemblyItem
/// Shortcut that avoids constructing an AssemblyItem just to perform the comparison.
bool operator==(Instruction _instr) const
{
return type() == Operation && instruction() == _instr;
return hasInstruction() && instruction() == _instr;
}
bool operator!=(Instruction _instr) const { return !operator==(_instr); }

Expand Down
12 changes: 9 additions & 3 deletions libevmasm/PeepholeOptimiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,9 @@ struct TruthyAnd: SimplePeepholeOptimizerMethod<TruthyAnd>
}
};

/// Removes everything after a JUMP (or similar) until the next JUMPDEST.
/// Removes everything after an non-continuing instruction until the next Tag.
/// Note: JUMPF can return but to the caller's parent call frame.
/// So it won't continue from the next to the JUMPF instruction
struct UnreachableCode
{
static bool apply(OptimiserState& _state)
Expand All @@ -572,14 +574,18 @@ struct UnreachableCode
auto end = _state.items.end();
if (it == end)
return false;

if (
it[0] != Instruction::JUMP &&
it[0] != Instruction::RJUMP &&
it[0] != Instruction::RETURN &&
it[0] != Instruction::STOP &&
it[0] != Instruction::INVALID &&
it[0] != Instruction::SELFDESTRUCT &&
it[0] != Instruction::REVERT
it[0] != Instruction::REVERT &&
it[0] != Instruction::RJUMP &&
it[0] != Instruction::JUMPF &&
it[0] != Instruction::RETF &&
it[0] != Instruction::RETURNCONTRACT
)
return false;

Expand Down
7 changes: 7 additions & 0 deletions test/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,13 @@ boost::unit_test::precondition::predicate_t nonEOF()
};
}

boost::unit_test::precondition::predicate_t onEOF()
{
return [](boost::unit_test::test_unit_id) {
return solidity::test::CommonOptions::get().eofVersion().has_value();
};
}

boost::unit_test::precondition::predicate_t minEVMVersionCheck(langutil::EVMVersion _minEVMVersion)
{
return [_minEVMVersion](boost::unit_test::test_unit_id) {
Expand Down
4 changes: 4 additions & 0 deletions test/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ boost::unit_test::precondition::predicate_t minEVMVersionCheck(langutil::EVMVers
/// @return A predicate (function) that can be passed into @a boost::unit_test::precondition().
boost::unit_test::precondition::predicate_t nonEOF();

/// Helper that can be used to skip tests when the legacy bytecode is not supported by the test case.
/// @return A predicate (function) that can be passed into @a boost::unit_test::precondition().
boost::unit_test::precondition::predicate_t onEOF();

bool loadVMs(CommonOptions const& _options);

/**
Expand Down
176 changes: 176 additions & 0 deletions test/libevmasm/Optimiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,182 @@ BOOST_AUTO_TEST_CASE(clear_unreachable_code)
);
}

BOOST_AUTO_TEST_CASE(clear_unreachable_code_eof, *boost::unit_test::precondition(onEOF()))
{
for (auto const& blockTerminatingItem:
{
AssemblyItem::relativeJumpTo(AssemblyItem(Tag, 1)),
AssemblyItem::jumpToFunction(1, 0, 0),
AssemblyItem::functionReturn(),
AssemblyItem::returnContract(0),
}
)
{
AssemblyItems items{
blockTerminatingItem,
u256(0),
Instruction::SLOAD,
AssemblyItem(Tag, 2),
u256(5),
u256(6),
Instruction::SSTORE,
blockTerminatingItem,
u256(5),
u256(6)
};
AssemblyItems expectation{
blockTerminatingItem,
AssemblyItem(Tag, 2),
u256(5),
u256(6),
Instruction::SSTORE,
blockTerminatingItem,
};
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(is_zero_is_zero_rjumpi, *boost::unit_test::precondition(onEOF()))
{
AssemblyItems items{
u256(1),
Instruction::ISZERO,
Instruction::ISZERO,
AssemblyItem::conditionalRelativeJumpTo(AssemblyItem(Tag, 1)),
u256(0),
Instruction::SLOAD,
AssemblyItem(Tag, 1),
};

AssemblyItems expectation{
u256(1),
AssemblyItem::conditionalRelativeJumpTo(AssemblyItem(Tag, 1)),
u256(0),
Instruction::SLOAD,
AssemblyItem(Tag, 1),
};

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(equal_is_zero_rjumpi, *boost::unit_test::precondition(onEOF()))
{
AssemblyItems items{
u256(1),
u256(2),
Instruction::EQ,
Instruction::ISZERO,
AssemblyItem::conditionalRelativeJumpTo(AssemblyItem(Tag, 1)),
u256(0),
Instruction::SLOAD,
AssemblyItem(Tag, 1),
};

AssemblyItems expectation{
u256(1),
u256(2),
Instruction::SUB,
AssemblyItem::conditionalRelativeJumpTo(AssemblyItem(Tag, 1)),
u256(0),
Instruction::SLOAD,
AssemblyItem(Tag, 1),
};

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(double_rjump, *boost::unit_test::precondition(onEOF()))
{
AssemblyItems items{
u256(1),
AssemblyItem::conditionalRelativeJumpTo(AssemblyItem(Tag, 1)),
AssemblyItem::relativeJumpTo(AssemblyItem(Tag, 2)),
AssemblyItem(Tag, 1),
u256(0),
Instruction::SLOAD,
AssemblyItem(Tag, 2),
};

AssemblyItems expectation{
u256(1),
Instruction::ISZERO,
AssemblyItem::conditionalRelativeJumpTo(AssemblyItem(Tag, 2)),
AssemblyItem(Tag, 1),
u256(0),
Instruction::SLOAD,
AssemblyItem(Tag, 2),
};

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(rjump_to_next, *boost::unit_test::precondition(onEOF()))
{
AssemblyItems items{
AssemblyItem::relativeJumpTo(AssemblyItem(Tag, 1)),
AssemblyItem(Tag, 1),
u256(0),
Instruction::SLOAD,
};

AssemblyItems expectation{
AssemblyItem(Tag, 1),
u256(0),
Instruction::SLOAD,
};

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(rjumpi_to_next, *boost::unit_test::precondition(onEOF()))
{
AssemblyItems items{
AssemblyItem::conditionalRelativeJumpTo(AssemblyItem(Tag, 1)),
AssemblyItem(Tag, 1),
u256(0),
Instruction::SLOAD,
};

AssemblyItems expectation{
Instruction::POP,
AssemblyItem(Tag, 1),
u256(0),
Instruction::SLOAD,
};

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(deduplicateNextTagBlockSize3)
{
AssemblyItems items{
Expand Down
Loading