Skip to content

Commit

Permalink
Add new Peephole Optimiser method (deduplicateNextTag)
Browse files Browse the repository at this point in the history
  • Loading branch information
matheusaaguiar committed Jun 27, 2024
1 parent ff12e94 commit 9b1792f
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 3 deletions.
99 changes: 96 additions & 3 deletions libevmasm/PeepholeOptimiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ struct DoubleSwap: SimplePeepholeOptimizerMethod<DoubleSwap>
}
};

struct DoublePush: SimplePeepholeOptimizerMethod<DoublePush>
struct DoublePush
{
static bool apply(OptimiserState& _state)
{
Expand Down Expand Up @@ -498,6 +498,99 @@ struct UnreachableCode
}
};

struct DeduplicateNextTagSize3 : SimplePeepholeOptimizerMethod<DeduplicateNextTagSize3>
{
static bool applySimple(
AssemblyItem const& _precedingItem,
AssemblyItem const& _itemA,
AssemblyItem const& _itemB,
AssemblyItem const& _breakingItem,
AssemblyItem const& _tag,
AssemblyItem const& _itemC,
AssemblyItem const& _itemD,
AssemblyItem const& _breakingItem2,
std::back_insert_iterator<AssemblyItems> _out
)
{
if (
_precedingItem.type() != Tag &&
_itemA == _itemC &&
_itemB == _itemD &&
_breakingItem == _breakingItem2 &&
_tag.type() == Tag &&
SemanticInformation::terminatesControlFlow(_breakingItem)
)
{
*_out = _precedingItem;
*_out = _tag;
*_out = _itemC;
*_out = _itemD;
*_out = _breakingItem2;
return true;
}

return false;
}
};

struct DeduplicateNextTagSize2 : SimplePeepholeOptimizerMethod<DeduplicateNextTagSize2>
{
static bool applySimple(
AssemblyItem const& _precedingItem,
AssemblyItem const& _itemA,
AssemblyItem const& _breakingItem,
AssemblyItem const& _tag,
AssemblyItem const& _itemC,
AssemblyItem const& _breakingItem2,
std::back_insert_iterator<AssemblyItems> _out
)
{
if (
_precedingItem.type() != Tag &&
_itemA == _itemC &&
_breakingItem == _breakingItem2 &&
_tag.type() == Tag &&
SemanticInformation::terminatesControlFlow(_breakingItem)
)
{
*_out = _precedingItem;
*_out = _tag;
*_out = _itemC;
*_out = _breakingItem2;
return true;
}

return false;
}
};

struct DeduplicateNextTagSize1 : SimplePeepholeOptimizerMethod<DeduplicateNextTagSize1>
{
static bool applySimple(
AssemblyItem const& _precedingItem,
AssemblyItem const& _breakingItem,
AssemblyItem const& _tag,
AssemblyItem const& _breakingItem2,
std::back_insert_iterator<AssemblyItems> _out
)
{
if (
_precedingItem.type() != Tag &&
_breakingItem == _breakingItem2 &&
_tag.type() == Tag &&
SemanticInformation::terminatesControlFlow(_breakingItem)
)
{
*_out = _precedingItem;
*_out = _tag;
*_out = _breakingItem2;
return true;
}

return false;
}
};

void applyMethods(OptimiserState&)
{
assertThrow(false, OptimizerException, "Peephole optimizer failed to apply identity.");
Expand Down Expand Up @@ -526,8 +619,8 @@ bool PeepholeOptimiser::optimise()
applyMethods(
state,
PushPop(), OpPop(), OpStop(), OpReturnRevert(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(),
DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(),
TagConjunctions(), TruthyAnd(), Identity()
DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(), DeduplicateNextTagSize3(),
DeduplicateNextTagSize2(), DeduplicateNextTagSize1(), TagConjunctions(), TruthyAnd(), Identity()
);
if (m_optimisedItems.size() < m_items.size() || (
m_optimisedItems.size() == m_items.size() && (
Expand Down
7 changes: 7 additions & 0 deletions libevmasm/SemanticInformation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,13 @@ bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
}
}

bool SemanticInformation::terminatesControlFlow(AssemblyItem const& _item)
{
if (_item.type() != evmasm::Operation)
return false;
return terminatesControlFlow(_item.instruction());
}

bool SemanticInformation::terminatesControlFlow(Instruction _instruction)
{
switch (_instruction)
Expand Down
1 change: 1 addition & 0 deletions libevmasm/SemanticInformation.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct SemanticInformation
static bool isSwapInstruction(AssemblyItem const& _item);
static bool isJumpInstruction(AssemblyItem const& _item);
static bool altersControlFlow(AssemblyItem const& _item);
static bool terminatesControlFlow(AssemblyItem const& _item);
static bool terminatesControlFlow(Instruction _instruction);
static bool reverts(Instruction _instruction);
/// @returns false if the value put on the stack by _item depends on anything else than
Expand Down
75 changes: 75 additions & 0 deletions test/libevmasm/Optimiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,81 @@ BOOST_AUTO_TEST_CASE(clear_unreachable_code)
);
}

BOOST_AUTO_TEST_CASE(deduplicateNextTagBlockSize3)
{
AssemblyItems items{
Instruction::JUMP,
u256(0),
u256(1),
Instruction::REVERT,
AssemblyItem(Tag, 2),
u256(0),
u256(1),
Instruction::REVERT
};

AssemblyItems expectation{
Instruction::JUMP,
AssemblyItem(Tag, 2),
u256(0),
u256(1),
Instruction::REVERT
};
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(deduplicateNextTagBlockSize2)
{
AssemblyItems items{
Instruction::JUMP,
u256(0),
Instruction::SELFDESTRUCT,
AssemblyItem(Tag, 2),
u256(0),
Instruction::SELFDESTRUCT
};

AssemblyItems expectation{
Instruction::JUMP,
AssemblyItem(Tag, 2),
u256(0),
Instruction::SELFDESTRUCT
};
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(deduplicateNextTagBlockSize1)
{
AssemblyItems items{
Instruction::JUMP,
Instruction::STOP,
AssemblyItem(Tag, 2),
Instruction::STOP
};

AssemblyItems expectation{
Instruction::JUMP,
AssemblyItem(Tag, 2),
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(peephole_double_push)
{
AssemblyItems items{
Expand Down

0 comments on commit 9b1792f

Please sign in to comment.