Add inlining for old optimizer.

This commit is contained in:
Daniel Kirchner
2021-02-09 19:08:58 +01:00
parent e777cad78a
commit cb74a45fd6
43 changed files with 1463 additions and 74 deletions
+171 -1
View File
@@ -25,6 +25,7 @@
#include <libevmasm/CommonSubexpressionEliminator.h>
#include <libevmasm/PeepholeOptimiser.h>
#include <libevmasm/Inliner.h>
#include <libevmasm/JumpdestRemover.h>
#include <libevmasm/ControlFlowGraph.h>
#include <libevmasm/BlockDeduplicator.h>
@@ -1233,7 +1234,17 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
main.append(t1.toSubAssemblyTag(subId));
main.append(u256(8));
main.optimise(true, solidity::test::CommonOptions::get().evmVersion(), false, 200);
Assembly::OptimiserSettings settings;
settings.isCreation = false;
settings.runInliner = false;
settings.runJumpdestRemover = true;
settings.runPeephole = true;
settings.runDeduplicate = true;
settings.runCSE = true;
settings.runConstantOptimiser = true;
settings.evmVersion = solidity::test::CommonOptions::get().evmVersion();
settings.expectedExecutionsPerDeployment = 200;
main.optimise(settings);
AssemblyItems expectationMain{
AssemblyItem(PushSubSize, 0),
@@ -1467,6 +1478,165 @@ BOOST_AUTO_TEST_CASE(cse_replace_too_large_shift)
});
}
BOOST_AUTO_TEST_CASE(inliner)
{
AssemblyItem jumpInto{Instruction::JUMP};
jumpInto.setJumpType(AssemblyItem::JumpType::IntoFunction);
AssemblyItem jumpOutOf{Instruction::JUMP};
jumpOutOf.setJumpType(AssemblyItem::JumpType::OutOfFunction);
AssemblyItems items{
AssemblyItem(PushTag, 1),
AssemblyItem(PushTag, 2),
jumpInto,
AssemblyItem(Tag, 1),
Instruction::STOP,
AssemblyItem(Tag, 2),
Instruction::CALLVALUE,
Instruction::SWAP1,
jumpOutOf,
};
AssemblyItems expectation{
AssemblyItem(PushTag, 1),
Instruction::CALLVALUE,
Instruction::SWAP1,
Instruction::JUMP,
AssemblyItem(Tag, 1),
Instruction::STOP,
AssemblyItem(Tag, 2),
Instruction::CALLVALUE,
Instruction::SWAP1,
jumpOutOf,
};
Inliner{items, {}, 200, false, {}}.optimise();
BOOST_CHECK_EQUAL_COLLECTIONS(
items.begin(), items.end(),
expectation.begin(), expectation.end()
);
}
BOOST_AUTO_TEST_CASE(inliner_no_inline_type)
{
// Will not inline due to jump types.
AssemblyItems items{
AssemblyItem(PushTag, 1),
AssemblyItem(PushTag, 2),
Instruction::JUMP,
AssemblyItem(Tag, 1),
Instruction::STOP,
AssemblyItem(Tag, 2),
Instruction::CALLVALUE,
Instruction::SWAP1,
Instruction::JUMP,
};
Inliner{items, {}, 200, false, {}}.optimise();
BOOST_CHECK_EQUAL_COLLECTIONS(
items.begin(), items.end(),
items.begin(), items.end()
);
}
BOOST_AUTO_TEST_CASE(inliner_no_inline)
{
AssemblyItems items{
AssemblyItem(PushTag, 1),
Instruction::JUMP,
AssemblyItem(Tag, 1),
Instruction::CALLVALUE,
Instruction::JUMPI,
Instruction::JUMP,
};
AssemblyItems expectation{
AssemblyItem(PushTag, 1),
Instruction::JUMP,
AssemblyItem(Tag, 1),
Instruction::CALLVALUE,
Instruction::JUMPI,
Instruction::JUMP,
};
Inliner{items, {}, 200, false, {}}.optimise();
BOOST_CHECK_EQUAL_COLLECTIONS(
items.begin(), items.end(),
expectation.begin(), expectation.end()
);
}
BOOST_AUTO_TEST_CASE(inliner_single_jump)
{
AssemblyItem jumpInto{Instruction::JUMP};
jumpInto.setJumpType(AssemblyItem::JumpType::IntoFunction);
AssemblyItem jumpOutOf{Instruction::JUMP};
jumpOutOf.setJumpType(AssemblyItem::JumpType::OutOfFunction);
AssemblyItems items{
AssemblyItem(PushTag, 1),
AssemblyItem(PushTag, 2),
jumpInto,
AssemblyItem(Tag, 1),
Instruction::STOP,
AssemblyItem(Tag, 2),
jumpOutOf,
};
AssemblyItems expectation{
AssemblyItem(PushTag, 1),
Instruction::JUMP,
AssemblyItem(Tag, 1),
Instruction::STOP,
AssemblyItem(Tag, 2),
jumpOutOf,
};
Inliner{items, {}, 200, false, {}}.optimise();
BOOST_CHECK_EQUAL_COLLECTIONS(
items.begin(), items.end(),
expectation.begin(), expectation.end()
);
}
BOOST_AUTO_TEST_CASE(inliner_end_of_bytecode)
{
AssemblyItem jumpInto{Instruction::JUMP};
jumpInto.setJumpType(AssemblyItem::JumpType::IntoFunction);
// Cannot inline, since the block at Tag_2 does not end in a jump.
AssemblyItems items{
AssemblyItem(PushTag, 1),
AssemblyItem(PushTag, 2),
jumpInto,
AssemblyItem(Tag, 1),
Instruction::STOP,
AssemblyItem(Tag, 2),
};
Inliner{items, {}, 200, false, {}}.optimise();
BOOST_CHECK_EQUAL_COLLECTIONS(
items.begin(), items.end(),
items.begin(), items.end()
);
}
BOOST_AUTO_TEST_CASE(inliner_cse_break)
{
AssemblyItem jumpInto{Instruction::JUMP};
jumpInto.setJumpType(AssemblyItem::JumpType::IntoFunction);
AssemblyItem jumpOutOf{Instruction::JUMP};
jumpOutOf.setJumpType(AssemblyItem::JumpType::OutOfFunction);
// Could be inlined, but we only consider non-CSE-breaking blocks ending in JUMP so far.
AssemblyItems items{
AssemblyItem(PushTag, 1),
AssemblyItem(PushTag, 2),
jumpInto,
AssemblyItem(Tag, 1),
Instruction::STOP,
AssemblyItem(Tag, 2),
Instruction::STOP, // CSE breaking instruction
jumpOutOf
};
Inliner{items, {}, 200, false, {}}.optimise();
BOOST_CHECK_EQUAL_COLLECTIONS(
items.begin(), items.end(),
items.begin(), items.end()
);
}
BOOST_AUTO_TEST_SUITE_END()
} // end namespaces