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/Semantics.h>
|
||||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||||
|
#include <libyul/ControlFlowSideEffectsCollector.h>
|
||||||
#include <libyul/AST.h>
|
#include <libyul/AST.h>
|
||||||
#include <libyul/AsmPrinter.h>
|
#include <libyul/AsmPrinter.h>
|
||||||
|
|
||||||
@ -42,7 +43,10 @@ using namespace solidity::yul;
|
|||||||
|
|
||||||
void UnusedAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
void UnusedAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
UnusedAssignEliminator rae{_context.dialect};
|
UnusedAssignEliminator rae{
|
||||||
|
_context.dialect,
|
||||||
|
ControlFlowSideEffectsCollector{_context.dialect, _ast}.functionSideEffectsNamed()
|
||||||
|
};
|
||||||
rae(_ast);
|
rae(_ast);
|
||||||
|
|
||||||
rae.m_storesToRemove += rae.m_allStores - rae.m_usedStores;
|
rae.m_storesToRemove += rae.m_allStores - rae.m_usedStores;
|
||||||
@ -74,10 +78,27 @@ void UnusedAssignEliminator::operator()(FunctionDefinition const& _functionDefin
|
|||||||
UnusedStoreBase::operator()(_functionDefinition);
|
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&)
|
void UnusedAssignEliminator::operator()(Leave const&)
|
||||||
{
|
{
|
||||||
for (YulString name: m_returnVariables)
|
for (YulString name: m_returnVariables)
|
||||||
markUsed(name);
|
markUsed(name);
|
||||||
|
m_activeStores.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnusedAssignEliminator::operator()(Block const& _block)
|
void UnusedAssignEliminator::operator()(Block const& _block)
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <libyul/optimiser/OptimiserStep.h>
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/optimiser/UnusedStoreBase.h>
|
#include <libyul/optimiser/UnusedStoreBase.h>
|
||||||
|
#include <libyul/optimiser/Semantics.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -99,7 +100,11 @@ struct Dialect;
|
|||||||
* For switch statements that have a "default"-case, there is no control-flow
|
* For switch statements that have a "default"-case, there is no control-flow
|
||||||
* part that skips the switch.
|
* 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.
|
* 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 constexpr char const* name{"UnusedAssignEliminator"};
|
||||||
static void run(OptimiserStepContext&, Block& _ast);
|
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()(Identifier const& _identifier) override;
|
||||||
void operator()(Assignment const& _assignment) override;
|
void operator()(Assignment const& _assignment) override;
|
||||||
void operator()(FunctionDefinition const&) override;
|
void operator()(FunctionDefinition const&) override;
|
||||||
|
void operator()(FunctionCall const& _functionCall) override;
|
||||||
void operator()(Leave const&) override;
|
void operator()(Leave const&) override;
|
||||||
void operator()(Block const& _block) override;
|
void operator()(Block const& _block) override;
|
||||||
|
|
||||||
@ -132,6 +144,7 @@ private:
|
|||||||
void markUsed(YulString _variable);
|
void markUsed(YulString _variable);
|
||||||
|
|
||||||
std::set<YulString> m_returnVariables;
|
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)
|
// let a := calldataload(0)
|
||||||
// if calldataload(1)
|
// if calldataload(1) { revert(0, 0) }
|
||||||
// {
|
|
||||||
// a := 2
|
|
||||||
// revert(0, 0)
|
|
||||||
// }
|
|
||||||
// sstore(0, a)
|
// sstore(0, a)
|
||||||
// }
|
// }
|
||||||
|
Loading…
Reference in New Issue
Block a user