Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Compiler Features:
* Syntax Checker: Warn about deprecation of virtual modifiers.
* 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.
* peepholeoptimiser: Peephole pattern added.

Bugfixes:
* Assembler: Fix not using a fixed-width type for IDs being assigned to subassemblies nested more than one level away, resulting in inconsistent `--asm-json` output between target architectures.
Expand Down
49 changes: 48 additions & 1 deletion libevmasm/PeepholeOptimiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext>

struct RJumpToNext: SimplePeepholeOptimizerMethod<RJumpToNext>
{
static size_t applySimple(
static bool applySimple(
AssemblyItem const& _rjump,
AssemblyItem const& _tag,
std::back_insert_iterator<AssemblyItems> _out
Expand Down Expand Up @@ -696,6 +696,52 @@ struct DeduplicateNextTagSize1 : SimplePeepholeOptimizerMethod<DeduplicateNextTa
}
};

struct FunctionSelectorGuard: SimplePeepholeOptimizerMethod<FunctionSelectorGuard>
{
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 <typename... Method>
void applyMethods(OptimiserState& _state)
{
Expand Down Expand Up @@ -746,6 +792,7 @@ bool PeepholeOptimiser::optimise()
DeduplicateNextTagSize2,
DeduplicateNextTagSize1,
TagConjunctions,
FunctionSelectorGuard,
TruthyAnd,
Identity
>(state);
Expand Down
38 changes: 38 additions & 0 deletions test/libevmasm/Optimiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down