mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Take non-continuing control-flow into account.
This commit is contained in:
parent
90a147d371
commit
bc127bcc6d
@ -24,6 +24,7 @@
|
||||
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||
#include <libyul/ControlFlowSideEffectsCollector.h>
|
||||
#include <libyul/AST.h>
|
||||
#include <libyul/AsmPrinter.h>
|
||||
|
||||
@ -42,7 +43,10 @@ using namespace solidity::yul;
|
||||
|
||||
void UnusedAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
||||
{
|
||||
UnusedAssignEliminator rae{_context.dialect};
|
||||
UnusedAssignEliminator rae{
|
||||
_context.dialect,
|
||||
ControlFlowSideEffectsCollector{_context.dialect, _ast}.functionSideEffectsNamed()
|
||||
};
|
||||
rae(_ast);
|
||||
|
||||
rae.m_storesToRemove += rae.m_allStores - rae.m_usedStores;
|
||||
@ -74,10 +78,27 @@ void UnusedAssignEliminator::operator()(FunctionDefinition const& _functionDefin
|
||||
UnusedStoreBase::operator()(_functionDefinition);
|
||||
}
|
||||
|
||||
void UnusedAssignEliminator::operator()(FunctionCall const& _functionCall)
|
||||
{
|
||||
UnusedStoreBase::operator()(_functionCall);
|
||||
|
||||
ControlFlowSideEffects sideEffects;
|
||||
if (auto builtin = m_dialect.builtin(_functionCall.functionName.name))
|
||||
sideEffects = builtin->controlFlowSideEffects;
|
||||
else
|
||||
sideEffects = m_controlFlowSideEffects.at(_functionCall.functionName.name);
|
||||
|
||||
if (!sideEffects.canContinue)
|
||||
// We do not return from the current function, so it is OK to also
|
||||
// clear the return variables.
|
||||
m_activeStores.clear();
|
||||
}
|
||||
|
||||
void UnusedAssignEliminator::operator()(Leave const&)
|
||||
{
|
||||
for (YulString name: m_returnVariables)
|
||||
markUsed(name);
|
||||
m_activeStores.clear();
|
||||
}
|
||||
|
||||
void UnusedAssignEliminator::operator()(Block const& _block)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/optimiser/OptimiserStep.h>
|
||||
#include <libyul/optimiser/UnusedStoreBase.h>
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@ -99,7 +100,11 @@ struct Dialect;
|
||||
* For switch statements that have a "default"-case, there is no control-flow
|
||||
* part that skips the switch.
|
||||
*
|
||||
* At ``leave`` statements, all return variables are set to "used".
|
||||
* At ``leave`` statements, all return variables are set to "used" and the set of active statements
|
||||
* is cleared.
|
||||
*
|
||||
* If a function or builtin is called that does not continue, the set of active statements is
|
||||
* cleared for all variables.
|
||||
*
|
||||
* In the second traversal, all assignments that are not marked as "used" are removed.
|
||||
*
|
||||
@ -114,11 +119,18 @@ public:
|
||||
static constexpr char const* name{"UnusedAssignEliminator"};
|
||||
static void run(OptimiserStepContext&, Block& _ast);
|
||||
|
||||
explicit UnusedAssignEliminator(Dialect const& _dialect): UnusedStoreBase(_dialect) {}
|
||||
explicit UnusedAssignEliminator(
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, ControlFlowSideEffects> _controlFlowSideEffects
|
||||
):
|
||||
UnusedStoreBase(_dialect),
|
||||
m_controlFlowSideEffects(_controlFlowSideEffects)
|
||||
{}
|
||||
|
||||
void operator()(Identifier const& _identifier) override;
|
||||
void operator()(Assignment const& _assignment) override;
|
||||
void operator()(FunctionDefinition const&) override;
|
||||
void operator()(FunctionCall const& _functionCall) override;
|
||||
void operator()(Leave const&) override;
|
||||
void operator()(Block const& _block) override;
|
||||
|
||||
@ -132,6 +144,7 @@ private:
|
||||
void markUsed(YulString _variable);
|
||||
|
||||
std::set<YulString> m_returnVariables;
|
||||
std::map<YulString, ControlFlowSideEffects> m_controlFlowSideEffects;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
{
|
||||
function g() {
|
||||
if calldataload(10) { revert(0, 0) }
|
||||
}
|
||||
function f() {
|
||||
let a := calldataload(0)
|
||||
if calldataload(1) {
|
||||
// this can NOT be removed
|
||||
a := 2
|
||||
g()
|
||||
}
|
||||
sstore(0, a)
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// step: unusedAssignEliminator
|
||||
//
|
||||
// {
|
||||
// function g()
|
||||
// {
|
||||
// if calldataload(10) { revert(0, 0) }
|
||||
// }
|
||||
// function f()
|
||||
// {
|
||||
// let a := calldataload(0)
|
||||
// if calldataload(1)
|
||||
// {
|
||||
// a := 2
|
||||
// g()
|
||||
// }
|
||||
// sstore(0, a)
|
||||
// }
|
||||
// }
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
function f() {
|
||||
let a := calldataload(0)
|
||||
if calldataload(1) {
|
||||
// this can be removed
|
||||
a := 2
|
||||
leave
|
||||
}
|
||||
sstore(0, a)
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// step: unusedAssignEliminator
|
||||
//
|
||||
// {
|
||||
// function f()
|
||||
// {
|
||||
// let a := calldataload(0)
|
||||
// if calldataload(1) { leave }
|
||||
// sstore(0, a)
|
||||
// }
|
||||
// }
|
@ -12,10 +12,6 @@
|
||||
//
|
||||
// {
|
||||
// let a := calldataload(0)
|
||||
// if calldataload(1)
|
||||
// {
|
||||
// a := 2
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// if calldataload(1) { revert(0, 0) }
|
||||
// sstore(0, a)
|
||||
// }
|
||||
|
Loading…
Reference in New Issue
Block a user