mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Take user function side-effects into account for unused pruner.
This commit is contained in:
parent
1c5845e3f2
commit
127bcfc69d
@ -35,8 +35,12 @@ using namespace dev;
|
|||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
|
||||||
SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Expression const& _expression):
|
SideEffectsCollector::SideEffectsCollector(
|
||||||
SideEffectsCollector(_dialect)
|
Dialect const& _dialect,
|
||||||
|
Expression const& _expression,
|
||||||
|
map<YulString, SideEffects> const* _functionSideEffects
|
||||||
|
):
|
||||||
|
SideEffectsCollector(_dialect, _functionSideEffects)
|
||||||
{
|
{
|
||||||
visit(_expression);
|
visit(_expression);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,11 @@ public:
|
|||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
|
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
|
||||||
): m_dialect(_dialect), m_functionSideEffects(_functionSideEffects) {}
|
): m_dialect(_dialect), m_functionSideEffects(_functionSideEffects) {}
|
||||||
SideEffectsCollector(Dialect const& _dialect, Expression const& _expression);
|
SideEffectsCollector(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
Expression const& _expression,
|
||||||
|
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
|
||||||
|
);
|
||||||
SideEffectsCollector(Dialect const& _dialect, Statement const& _statement);
|
SideEffectsCollector(Dialect const& _dialect, Statement const& _statement);
|
||||||
SideEffectsCollector(Dialect const& _dialect, Block const& _ast);
|
SideEffectsCollector(Dialect const& _dialect, Block const& _ast);
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ void OptimiserSuite::run(
|
|||||||
DeadCodeEliminator{_dialect}(ast);
|
DeadCodeEliminator{_dialect}(ast);
|
||||||
FunctionGrouper{}(ast);
|
FunctionGrouper{}(ast);
|
||||||
EquivalentFunctionCombiner::run(ast);
|
EquivalentFunctionCombiner::run(ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
BlockFlattener{}(ast);
|
BlockFlattener{}(ast);
|
||||||
ControlFlowSimplifier{_dialect}(ast);
|
ControlFlowSimplifier{_dialect}(ast);
|
||||||
StructuralSimplifier{_dialect}(ast);
|
StructuralSimplifier{_dialect}(ast);
|
||||||
@ -127,20 +127,20 @@ void OptimiserSuite::run(
|
|||||||
ControlFlowSimplifier{_dialect}(ast);
|
ControlFlowSimplifier{_dialect}(ast);
|
||||||
BlockFlattener{}(ast);
|
BlockFlattener{}(ast);
|
||||||
DeadCodeEliminator{_dialect}(ast);
|
DeadCodeEliminator{_dialect}(ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// simplify again
|
// simplify again
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// reverse SSA
|
// reverse SSA
|
||||||
SSAReverser::run(ast);
|
SSAReverser::run(ast);
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
|
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::run(ast);
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::run(ast);
|
||||||
@ -151,7 +151,7 @@ void OptimiserSuite::run(
|
|||||||
{
|
{
|
||||||
// run functional expression inliner
|
// run functional expression inliner
|
||||||
ExpressionInliner(_dialect, ast).run();
|
ExpressionInliner(_dialect, ast).run();
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -185,7 +185,7 @@ void OptimiserSuite::run(
|
|||||||
SSATransform::run(ast, dispenser);
|
SSATransform::run(ast, dispenser);
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
RedundantAssignEliminator::run(_dialect, ast);
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
RedundantAssignEliminator::run(_dialect, ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,19 +194,19 @@ void OptimiserSuite::run(
|
|||||||
|
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::run(ast);
|
||||||
Rematerialiser::run(_dialect, ast);
|
Rematerialiser::run(_dialect, ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::run(ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::run(ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
|
|
||||||
SSAReverser::run(ast);
|
SSAReverser::run(ast);
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
|
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::run(ast);
|
||||||
Rematerialiser::run(_dialect, ast);
|
Rematerialiser::run(_dialect, ast);
|
||||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
||||||
|
|
||||||
// This is a tuning parameter, but actually just prevents infinite loops.
|
// This is a tuning parameter, but actually just prevents infinite loops.
|
||||||
size_t stackCompressorMaxIterations = 16;
|
size_t stackCompressorMaxIterations = 16;
|
||||||
|
@ -20,12 +20,14 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/UnusedPruner.h>
|
#include <libyul/optimiser/UnusedPruner.h>
|
||||||
|
|
||||||
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
#include <libyul/optimiser/NameCollector.h>
|
#include <libyul/optimiser/NameCollector.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
#include <libyul/Dialect.h>
|
#include <libyul/Dialect.h>
|
||||||
|
#include <libyul/SideEffects.h>
|
||||||
|
|
||||||
#include <boost/algorithm/cxx11/none_of.hpp>
|
#include <boost/algorithm/cxx11/none_of.hpp>
|
||||||
|
|
||||||
@ -37,10 +39,12 @@ UnusedPruner::UnusedPruner(
|
|||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
bool _allowMSizeOptimization,
|
bool _allowMSizeOptimization,
|
||||||
|
map<YulString, SideEffects> const* _functionSideEffects,
|
||||||
set<YulString> const& _externallyUsedFunctions
|
set<YulString> const& _externallyUsedFunctions
|
||||||
):
|
):
|
||||||
m_dialect(_dialect),
|
m_dialect(_dialect),
|
||||||
m_allowMSizeOptimization(_allowMSizeOptimization)
|
m_allowMSizeOptimization(_allowMSizeOptimization),
|
||||||
|
m_functionSideEffects(_functionSideEffects)
|
||||||
{
|
{
|
||||||
m_references = ReferencesCounter::countReferences(_ast);
|
m_references = ReferencesCounter::countReferences(_ast);
|
||||||
for (auto const& f: _externallyUsedFunctions)
|
for (auto const& f: _externallyUsedFunctions)
|
||||||
@ -88,7 +92,10 @@ void UnusedPruner::operator()(Block& _block)
|
|||||||
{
|
{
|
||||||
if (!varDecl.value)
|
if (!varDecl.value)
|
||||||
statement = Block{std::move(varDecl.location), {}};
|
statement = Block{std::move(varDecl.location), {}};
|
||||||
else if (SideEffectsCollector(m_dialect, *varDecl.value).sideEffectFree(m_allowMSizeOptimization))
|
else if (
|
||||||
|
SideEffectsCollector(m_dialect, *varDecl.value, m_functionSideEffects).
|
||||||
|
sideEffectFree(m_allowMSizeOptimization)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
subtractReferences(ReferencesCounter::countReferences(*varDecl.value));
|
subtractReferences(ReferencesCounter::countReferences(*varDecl.value));
|
||||||
statement = Block{std::move(varDecl.location), {}};
|
statement = Block{std::move(varDecl.location), {}};
|
||||||
@ -104,7 +111,10 @@ void UnusedPruner::operator()(Block& _block)
|
|||||||
else if (statement.type() == typeid(ExpressionStatement))
|
else if (statement.type() == typeid(ExpressionStatement))
|
||||||
{
|
{
|
||||||
ExpressionStatement& exprStmt = boost::get<ExpressionStatement>(statement);
|
ExpressionStatement& exprStmt = boost::get<ExpressionStatement>(statement);
|
||||||
if (SideEffectsCollector(m_dialect, exprStmt.expression).sideEffectFree(m_allowMSizeOptimization))
|
if (
|
||||||
|
SideEffectsCollector(m_dialect, exprStmt.expression, m_functionSideEffects).
|
||||||
|
sideEffectFree(m_allowMSizeOptimization)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
subtractReferences(ReferencesCounter::countReferences(exprStmt.expression));
|
subtractReferences(ReferencesCounter::countReferences(exprStmt.expression));
|
||||||
statement = Block{std::move(exprStmt.location), {}};
|
statement = Block{std::move(exprStmt.location), {}};
|
||||||
@ -120,26 +130,31 @@ void UnusedPruner::runUntilStabilised(
|
|||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
bool _allowMSizeOptimization,
|
bool _allowMSizeOptimization,
|
||||||
|
map<YulString, SideEffects> const* _functionSideEffects,
|
||||||
set<YulString> const& _externallyUsedFunctions
|
set<YulString> const& _externallyUsedFunctions
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
UnusedPruner pruner(_dialect, _ast, _allowMSizeOptimization, _externallyUsedFunctions);
|
UnusedPruner pruner(
|
||||||
|
_dialect, _ast, _allowMSizeOptimization, _functionSideEffects,
|
||||||
|
_externallyUsedFunctions);
|
||||||
pruner(_ast);
|
pruner(_ast);
|
||||||
if (!pruner.shouldRunAgain())
|
if (!pruner.shouldRunAgain())
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnusedPruner::runUntilStabilised(
|
void UnusedPruner::runUntilStabilisedOnFullAST(
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
set<YulString> const& _externallyUsedFunctions
|
set<YulString> const& _externallyUsedFunctions
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
map<YulString, SideEffects> functionSideEffects =
|
||||||
|
SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast));
|
||||||
bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, _ast);
|
bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, _ast);
|
||||||
runUntilStabilised(_dialect, _ast, allowMSizeOptimization, _externallyUsedFunctions);
|
runUntilStabilised(_dialect, _ast, allowMSizeOptimization, &functionSideEffects, _externallyUsedFunctions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnusedPruner::runUntilStabilised(
|
void UnusedPruner::runUntilStabilised(
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct SideEffects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimisation stage that removes unused variables and functions and also
|
* Optimisation stage that removes unused variables and functions and also
|
||||||
@ -50,6 +51,7 @@ public:
|
|||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
bool _allowMSizeOptimization,
|
bool _allowMSizeOptimization,
|
||||||
|
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr,
|
||||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||||
);
|
);
|
||||||
UnusedPruner(
|
UnusedPruner(
|
||||||
@ -70,10 +72,15 @@ public:
|
|||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
bool _allowMSizeOptimization,
|
bool _allowMSizeOptimization,
|
||||||
|
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr,
|
||||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
static void runUntilStabilised(
|
/// Run the pruner until the code does not change anymore.
|
||||||
|
/// The provided block has to be a full AST.
|
||||||
|
/// The pruner itself determines if msize is used and which user-defined functions
|
||||||
|
/// are side-effect free.
|
||||||
|
static void runUntilStabilisedOnFullAST(
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||||
@ -97,6 +104,7 @@ private:
|
|||||||
|
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
bool m_allowMSizeOptimization = false;
|
bool m_allowMSizeOptimization = false;
|
||||||
|
std::map<YulString, SideEffects> const* m_functionSideEffects = nullptr;
|
||||||
bool m_shouldRunAgain = false;
|
bool m_shouldRunAgain = false;
|
||||||
std::map<YulString, size_t> m_references;
|
std::map<YulString, size_t> m_references;
|
||||||
};
|
};
|
||||||
|
@ -222,7 +222,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
ForLoopInitRewriter{}(*m_ast);
|
ForLoopInitRewriter{}(*m_ast);
|
||||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
||||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
||||||
UnusedPruner::runUntilStabilised(*m_dialect, *m_ast);
|
UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast);
|
||||||
DeadCodeEliminator{*m_dialect}(*m_ast);
|
DeadCodeEliminator{*m_dialect}(*m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_ast);
|
||||||
@ -230,7 +230,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
else if (m_optimizerStep == "unusedPruner")
|
else if (m_optimizerStep == "unusedPruner")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
UnusedPruner::runUntilStabilised(*m_dialect, *m_ast);
|
UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "deadCodeEliminator")
|
else if (m_optimizerStep == "deadCodeEliminator")
|
||||||
{
|
{
|
||||||
@ -267,7 +267,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
|
|
||||||
LoadResolver::run(*m_dialect, *m_ast);
|
LoadResolver::run(*m_dialect, *m_ast);
|
||||||
|
|
||||||
UnusedPruner::runUntilStabilised(*m_dialect, *m_ast);
|
UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_ast);
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
// reverse SSA
|
// reverse SSA
|
||||||
SSAReverser::run(*m_ast);
|
SSAReverser::run(*m_ast);
|
||||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
||||||
UnusedPruner::runUntilStabilised(*m_dialect, *m_ast);
|
UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "stackCompressor")
|
else if (m_optimizerStep == "stackCompressor")
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
function f(x) -> t {
|
||||||
|
let b := 7
|
||||||
|
}
|
||||||
|
function g(x) -> t {
|
||||||
|
t := x
|
||||||
|
}
|
||||||
|
let x := f(g(2))
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// step: unusedPruner
|
||||||
|
// ----
|
||||||
|
// { }
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/BlockFlattener.h>
|
#include <libyul/optimiser/BlockFlattener.h>
|
||||||
#include <libyul/optimiser/Disambiguator.h>
|
#include <libyul/optimiser/Disambiguator.h>
|
||||||
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
||||||
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
||||||
#include <libyul/optimiser/NameCollector.h>
|
#include <libyul/optimiser/NameCollector.h>
|
||||||
@ -54,6 +55,7 @@
|
|||||||
#include <libyul/optimiser/SSATransform.h>
|
#include <libyul/optimiser/SSATransform.h>
|
||||||
#include <libyul/optimiser/StackCompressor.h>
|
#include <libyul/optimiser/StackCompressor.h>
|
||||||
#include <libyul/optimiser/StructuralSimplifier.h>
|
#include <libyul/optimiser/StructuralSimplifier.h>
|
||||||
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/VarDeclInitializer.h>
|
#include <libyul/optimiser/VarDeclInitializer.h>
|
||||||
#include <libyul/optimiser/VarNameCleaner.h>
|
#include <libyul/optimiser/VarNameCleaner.h>
|
||||||
|
|
||||||
@ -187,7 +189,7 @@ public:
|
|||||||
(ControlFlowSimplifier{m_dialect})(*m_ast);
|
(ControlFlowSimplifier{m_dialect})(*m_ast);
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
UnusedPruner::runUntilStabilised(m_dialect, *m_ast);
|
UnusedPruner::runUntilStabilisedOnFullAST(m_dialect, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
DeadCodeEliminator{m_dialect}(*m_ast);
|
DeadCodeEliminator{m_dialect}(*m_ast);
|
||||||
|
Loading…
Reference in New Issue
Block a user