mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7251 from ethereum/sideEffectsForUserDefinedFunctions
Side effects for user defined functions
This commit is contained in:
commit
029941a168
@ -6,6 +6,7 @@ Language Features:
|
|||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
* Optimizer: Add rule that replaces the BYTE opcode by 0 if the first argument is larger than 31.
|
* Optimizer: Add rule that replaces the BYTE opcode by 0 if the first argument is larger than 31.
|
||||||
|
* Yul Optimizer: Take side-effect-freeness of user-defined functions into account.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/Metrics.h>
|
#include <libyul/optimiser/Metrics.h>
|
||||||
#include <libyul/optimiser/SyntacticalEquality.h>
|
#include <libyul/optimiser/SyntacticalEquality.h>
|
||||||
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
|
#include <libyul/optimiser/Semantics.h>
|
||||||
|
#include <libyul/SideEffects.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>
|
||||||
@ -31,6 +34,23 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void CommonSubexpressionEliminator::run(Dialect const& _dialect, Block& _ast)
|
||||||
|
{
|
||||||
|
CommonSubexpressionEliminator cse{
|
||||||
|
_dialect,
|
||||||
|
SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast))
|
||||||
|
};
|
||||||
|
cse(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommonSubexpressionEliminator::CommonSubexpressionEliminator(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
map<YulString, SideEffects> _functionSideEffects
|
||||||
|
):
|
||||||
|
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void CommonSubexpressionEliminator::visit(Expression& _e)
|
void CommonSubexpressionEliminator::visit(Expression& _e)
|
||||||
{
|
{
|
||||||
bool descend = true;
|
bool descend = true;
|
||||||
|
@ -27,6 +27,7 @@ namespace yul
|
|||||||
{
|
{
|
||||||
|
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct SideEffects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimisation stage that replaces expressions known to be the current value of a variable
|
* Optimisation stage that replaces expressions known to be the current value of a variable
|
||||||
@ -37,7 +38,14 @@ struct Dialect;
|
|||||||
class CommonSubexpressionEliminator: public DataFlowAnalyzer
|
class CommonSubexpressionEliminator: public DataFlowAnalyzer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CommonSubexpressionEliminator(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
|
/// Runs the CSE pass. @a _ast needs to be the complete AST of the program!
|
||||||
|
static void run(Dialect const& _dialect, Block& _ast);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CommonSubexpressionEliminator(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
std::map<YulString, SideEffects> _functionSideEffects
|
||||||
|
);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using ASTModifier::visit;
|
using ASTModifier::visit;
|
||||||
|
@ -211,7 +211,7 @@ void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expres
|
|||||||
{
|
{
|
||||||
clearValues(_variables);
|
clearValues(_variables);
|
||||||
|
|
||||||
MovableChecker movableChecker{m_dialect};
|
MovableChecker movableChecker{m_dialect, &m_functionSideEffects};
|
||||||
if (_value)
|
if (_value)
|
||||||
movableChecker.visit(*_value);
|
movableChecker.visit(*_value);
|
||||||
else
|
else
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <libyul/optimiser/KnowledgeBase.h>
|
#include <libyul/optimiser/KnowledgeBase.h>
|
||||||
#include <libyul/YulString.h>
|
#include <libyul/YulString.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
|
#include <libyul/SideEffects.h>
|
||||||
|
|
||||||
// TODO avoid
|
// TODO avoid
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
@ -38,6 +39,7 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct SideEffects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class to perform data flow analysis during AST walks.
|
* Base class to perform data flow analysis during AST walks.
|
||||||
@ -67,8 +69,16 @@ struct Dialect;
|
|||||||
class DataFlowAnalyzer: public ASTModifier
|
class DataFlowAnalyzer: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DataFlowAnalyzer(Dialect const& _dialect):
|
/// @param _functionSideEffects
|
||||||
|
/// Side-effects of user-defined functions. Worst-case side-effects are assumed
|
||||||
|
/// if this is not provided or the function is not found.
|
||||||
|
/// The parameter is mostly used to determine movability of expressions.
|
||||||
|
explicit DataFlowAnalyzer(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
std::map<YulString, SideEffects> _functionSideEffects = {}
|
||||||
|
):
|
||||||
m_dialect(_dialect),
|
m_dialect(_dialect),
|
||||||
|
m_functionSideEffects(std::move(_functionSideEffects)),
|
||||||
m_knowledgeBase(_dialect, m_value)
|
m_knowledgeBase(_dialect, m_value)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -124,6 +134,9 @@ protected:
|
|||||||
) const;
|
) const;
|
||||||
|
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
|
/// Side-effects of user-defined functions. Worst-case side-effects are assumed
|
||||||
|
/// if this is not provided or the function is not found.
|
||||||
|
std::map<YulString, SideEffects> m_functionSideEffects;
|
||||||
|
|
||||||
/// Current values of variables, always movable.
|
/// Current values of variables, always movable.
|
||||||
std::map<YulString, Expression const*> m_value;
|
std::map<YulString, Expression const*> m_value;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
@ -64,8 +68,11 @@ void SideEffectsCollector::operator()(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
ASTWalker::operator()(_functionCall);
|
ASTWalker::operator()(_functionCall);
|
||||||
|
|
||||||
if (BuiltinFunction const* f = m_dialect.builtin(_functionCall.functionName.name))
|
YulString functionName = _functionCall.functionName.name;
|
||||||
|
if (BuiltinFunction const* f = m_dialect.builtin(functionName))
|
||||||
m_sideEffects += f->sideEffects;
|
m_sideEffects += f->sideEffects;
|
||||||
|
else if (m_functionSideEffects && m_functionSideEffects->count(functionName))
|
||||||
|
m_sideEffects += m_functionSideEffects->at(functionName);
|
||||||
else
|
else
|
||||||
m_sideEffects += SideEffects::worst();
|
m_sideEffects += SideEffects::worst();
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <libyul/SideEffects.h>
|
#include <libyul/SideEffects.h>
|
||||||
|
#include <libyul/AsmData.h>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -36,8 +37,15 @@ struct Dialect;
|
|||||||
class SideEffectsCollector: public ASTWalker
|
class SideEffectsCollector: public ASTWalker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SideEffectsCollector(Dialect const& _dialect): m_dialect(_dialect) {}
|
explicit SideEffectsCollector(
|
||||||
SideEffectsCollector(Dialect const& _dialect, Expression const& _expression);
|
Dialect const& _dialect,
|
||||||
|
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
|
||||||
|
): m_dialect(_dialect), m_functionSideEffects(_functionSideEffects) {}
|
||||||
|
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);
|
||||||
|
|
||||||
@ -59,6 +67,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
|
std::map<YulString, SideEffects> const* m_functionSideEffects = nullptr;
|
||||||
SideEffects m_sideEffects;
|
SideEffects m_sideEffects;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,7 +117,10 @@ private:
|
|||||||
class MovableChecker: public SideEffectsCollector
|
class MovableChecker: public SideEffectsCollector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit MovableChecker(Dialect const& _dialect): SideEffectsCollector(_dialect) {}
|
explicit MovableChecker(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
|
||||||
|
): SideEffectsCollector(_dialect, _functionSideEffects) {}
|
||||||
MovableChecker(Dialect const& _dialect, Expression const& _expression);
|
MovableChecker(Dialect const& _dialect, Expression const& _expression);
|
||||||
|
|
||||||
void operator()(Identifier const& _identifier) override;
|
void operator()(Identifier const& _identifier) override;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libyul/optimiser/Disambiguator.h>
|
#include <libyul/optimiser/Disambiguator.h>
|
||||||
#include <libyul/optimiser/VarDeclInitializer.h>
|
#include <libyul/optimiser/VarDeclInitializer.h>
|
||||||
#include <libyul/optimiser/BlockFlattener.h>
|
#include <libyul/optimiser/BlockFlattener.h>
|
||||||
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
||||||
#include <libyul/optimiser/DeadCodeEliminator.h>
|
#include <libyul/optimiser/DeadCodeEliminator.h>
|
||||||
#include <libyul/optimiser/FunctionGrouper.h>
|
#include <libyul/optimiser/FunctionGrouper.h>
|
||||||
@ -37,6 +38,7 @@
|
|||||||
#include <libyul/optimiser/UnusedPruner.h>
|
#include <libyul/optimiser/UnusedPruner.h>
|
||||||
#include <libyul/optimiser/ExpressionSimplifier.h>
|
#include <libyul/optimiser/ExpressionSimplifier.h>
|
||||||
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
||||||
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/SSAReverser.h>
|
#include <libyul/optimiser/SSAReverser.h>
|
||||||
#include <libyul/optimiser/SSATransform.h>
|
#include <libyul/optimiser/SSATransform.h>
|
||||||
#include <libyul/optimiser/StackCompressor.h>
|
#include <libyul/optimiser/StackCompressor.h>
|
||||||
@ -85,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);
|
||||||
@ -114,7 +116,8 @@ void OptimiserSuite::run(
|
|||||||
RedundantAssignEliminator::run(_dialect, ast);
|
RedundantAssignEliminator::run(_dialect, ast);
|
||||||
|
|
||||||
ExpressionSimplifier::run(_dialect, ast);
|
ExpressionSimplifier::run(_dialect, ast);
|
||||||
CommonSubexpressionEliminator{_dialect}(ast);
|
|
||||||
|
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -124,19 +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{_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{_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);
|
||||||
@ -147,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -156,7 +160,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);
|
||||||
CommonSubexpressionEliminator{_dialect}(ast);
|
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -177,12 +181,12 @@ void OptimiserSuite::run(
|
|||||||
BlockFlattener{}(ast);
|
BlockFlattener{}(ast);
|
||||||
DeadCodeEliminator{_dialect}(ast);
|
DeadCodeEliminator{_dialect}(ast);
|
||||||
ControlFlowSimplifier{_dialect}(ast);
|
ControlFlowSimplifier{_dialect}(ast);
|
||||||
CommonSubexpressionEliminator{_dialect}(ast);
|
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||||
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{_dialect}(ast);
|
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,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{_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;
|
||||||
};
|
};
|
||||||
|
@ -7,24 +7,16 @@
|
|||||||
(local $_1 i64)
|
(local $_1 i64)
|
||||||
(local $pos i64)
|
(local $pos i64)
|
||||||
(local $_2 i64)
|
(local $_2 i64)
|
||||||
(local $_3 i64)
|
|
||||||
(local $hi i64)
|
(local $hi i64)
|
||||||
(local $_4 i64)
|
(local $y i64)
|
||||||
(local $hi_1 i64)
|
(local $hi_1 i64)
|
||||||
(local $hi_2 i64)
|
|
||||||
(local $hi_3 i64)
|
|
||||||
(local $hi_4 i64)
|
|
||||||
(set_local $_1 (i64.const 0))
|
(set_local $_1 (i64.const 0))
|
||||||
(set_local $pos (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (i64.const 64)))
|
(set_local $pos (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (i64.const 64)))
|
||||||
(set_local $_2 (i64.const 32))
|
(set_local $_2 (i64.const 65280))
|
||||||
(set_local $_3 (i64.shr_u (get_local $_1) (i64.const 16)))
|
(set_local $hi (i64.shl (i64.or (i64.shl (i64.or (i64.and (i64.shl (get_local $_1) (i64.const 8)) (get_local $_2)) (i64.and (i64.shr_u (get_local $_1) (i64.const 8)) (i64.const 255))) (i64.const 16)) (call $endian_swap_16 (i64.shr_u (get_local $_1) (i64.const 16)))) (i64.const 32)))
|
||||||
(set_local $hi (i64.shl (i64.or (i64.shl (i64.or (i64.and (i64.shl (get_local $_1) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (get_local $_1) (i64.const 8)) (i64.const 255))) (i64.const 16)) (call $endian_swap_16 (get_local $_3))) (get_local $_2)))
|
(set_local $y (i64.or (get_local $hi) (call $endian_swap_32 (i64.shr_u (get_local $_1) (i64.const 32)))))
|
||||||
(set_local $_4 (i64.shr_u (get_local $_1) (get_local $_2)))
|
(i64.store (get_local $pos) (get_local $y)) (i64.store (i64.add (get_local $pos) (i64.const 8)) (get_local $y)) (i64.store (i64.add (get_local $pos) (i64.const 16)) (get_local $y)) (set_local $hi_1 (i64.shl (i64.or (i64.shl (i64.or (i64.and (i64.shl (i64.const 64) (i64.const 8)) (get_local $_2)) (i64.and (i64.shr_u (i64.const 64) (i64.const 8)) (i64.const 255))) (i64.const 16)) (call $endian_swap_16 (i64.shr_u (i64.const 64) (i64.const 16)))) (i64.const 32)))
|
||||||
(i64.store (get_local $pos) (i64.or (get_local $hi) (call $endian_swap_32 (get_local $_4)))) (set_local $hi_1 (i64.shl (call $endian_swap_16 (get_local $_1)) (i64.const 16)))
|
(i64.store (i64.add (get_local $pos) (i64.const 24)) (i64.or (get_local $hi_1) (call $endian_swap_32 (i64.shr_u (i64.const 64) (i64.const 32))))) (call $eth.revert (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)))
|
||||||
(set_local $hi_2 (i64.shl (i64.or (get_local $hi_1) (call $endian_swap_16 (get_local $_3))) (get_local $_2)))
|
|
||||||
(i64.store (i64.add (get_local $pos) (i64.const 8)) (i64.or (get_local $hi_2) (call $endian_swap_32 (get_local $_4)))) (set_local $hi_3 (i64.shl (call $endian_swap_32 (get_local $_1)) (get_local $_2)))
|
|
||||||
(i64.store (i64.add (get_local $pos) (i64.const 16)) (i64.or (get_local $hi_3) (call $endian_swap_32 (get_local $_4)))) (set_local $hi_4 (i64.shl (call $endian_swap_32 (i64.const 64)) (get_local $_2)))
|
|
||||||
(i64.store (i64.add (get_local $pos) (i64.const 24)) (i64.or (get_local $hi_4) (call $endian_swap_32 (i64.shr_u (i64.const 64) (get_local $_2))))) (call $eth.revert (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
(func $u256_to_i32
|
(func $u256_to_i32
|
||||||
@ -74,44 +66,38 @@
|
|||||||
(local $_1 i64)
|
(local $_1 i64)
|
||||||
(local $pos i64)
|
(local $pos i64)
|
||||||
(local $hi i64)
|
(local $hi i64)
|
||||||
(local $_2 i64)
|
(local $y i64)
|
||||||
(local $hi_1 i64)
|
(local $hi_1 i64)
|
||||||
(local $_3 i64)
|
|
||||||
(local $hi_2 i64)
|
(local $hi_2 i64)
|
||||||
(local $hi_3 i64)
|
(local $_2 i64)
|
||||||
(local $hi_4 i64)
|
(local $_3 i64)
|
||||||
(local $_4 i64)
|
(local $_4 i64)
|
||||||
(local $_5 i64)
|
(local $_5 i64)
|
||||||
(local $_6 i64)
|
(local $_6 i64)
|
||||||
(local $_7 i64)
|
(local $_7 i64)
|
||||||
(local $_8 i64)
|
(local $_8 i64)
|
||||||
(local $_9 i64)
|
(local $_9 i64)
|
||||||
(local $_10 i64)
|
|
||||||
(local $_11 i64)
|
|
||||||
(set_local $_1 (i64.const 0))
|
(set_local $_1 (i64.const 0))
|
||||||
(set_local $pos (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (i64.const 64)))
|
(set_local $pos (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (i64.const 64)))
|
||||||
(set_local $hi (i64.shl (call $endian_swap_16 (get_local $_1)) (i64.const 16)))
|
(set_local $hi (i64.shl (i64.or (i64.shl (i64.or (i64.and (i64.shl (get_local $_1) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (get_local $_1) (i64.const 8)) (i64.const 255))) (i64.const 16)) (call $endian_swap_16 (i64.shr_u (get_local $_1) (i64.const 16)))) (i64.const 32)))
|
||||||
(set_local $_2 (i64.shr_u (get_local $_1) (i64.const 16)))
|
(set_local $y (i64.or (get_local $hi) (call $endian_swap_32 (i64.shr_u (get_local $_1) (i64.const 32)))))
|
||||||
(set_local $hi_1 (i64.shl (i64.or (get_local $hi) (call $endian_swap_16 (get_local $_2))) (i64.const 32)))
|
(i64.store (get_local $pos) (get_local $y)) (i64.store (i64.add (get_local $pos) (i64.const 8)) (get_local $y)) (i64.store (i64.add (get_local $pos) (i64.const 16)) (get_local $y)) (set_local $hi_1 (i64.shl (call $endian_swap_16 (i64.const 64)) (i64.const 16)))
|
||||||
(set_local $_3 (i64.shr_u (get_local $_1) (i64.const 32)))
|
(set_local $hi_2 (i64.shl (i64.or (get_local $hi_1) (call $endian_swap_16 (i64.shr_u (i64.const 64) (i64.const 16)))) (i64.const 32)))
|
||||||
(i64.store (get_local $pos) (i64.or (get_local $hi_1) (call $endian_swap_32 (get_local $_3)))) (set_local $hi_2 (i64.shl (call $endian_swap_16 (get_local $_1)) (i64.const 16)))
|
(i64.store (i64.add (get_local $pos) (i64.const 24)) (i64.or (get_local $hi_2) (call $endian_swap_32 (i64.shr_u (i64.const 64) (i64.const 32))))) (block
|
||||||
(set_local $hi_3 (i64.shl (i64.or (get_local $hi_2) (call $endian_swap_16 (get_local $_2))) (i64.const 32)))
|
(set_local $_2 (datasize \"C_2_deployed\"))
|
||||||
(i64.store (i64.add (get_local $pos) (i64.const 8)) (i64.or (get_local $hi_3) (call $endian_swap_32 (get_local $_3)))) (set_local $hi_4 (i64.shl (call $endian_swap_32 (get_local $_1)) (i64.const 32)))
|
(set_local $_3 (get_global $global_))
|
||||||
(i64.store (i64.add (get_local $pos) (i64.const 16)) (i64.or (get_local $hi_4) (call $endian_swap_32 (get_local $_3)))) (i64.store (i64.add (get_local $pos) (i64.const 24)) (call $endian_swap (i64.const 64))) (block
|
(set_local $_4 (get_global $global__1))
|
||||||
(set_local $_4 (datasize \"C_2_deployed\"))
|
(set_local $_5 (get_global $global__2))
|
||||||
(set_local $_5 (get_global $global_))
|
|
||||||
(set_local $_6 (get_global $global__1))
|
|
||||||
(set_local $_7 (get_global $global__2))
|
|
||||||
|
|
||||||
)
|
)
|
||||||
(block
|
(block
|
||||||
(set_local $_8 (dataoffset \"C_2_deployed\"))
|
(set_local $_6 (dataoffset \"C_2_deployed\"))
|
||||||
(set_local $_9 (get_global $global_))
|
(set_local $_7 (get_global $global_))
|
||||||
(set_local $_10 (get_global $global__1))
|
(set_local $_8 (get_global $global__1))
|
||||||
(set_local $_11 (get_global $global__2))
|
(set_local $_9 (get_global $global__2))
|
||||||
|
|
||||||
)
|
)
|
||||||
(call $eth.codeCopy (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_8) (get_local $_9) (get_local $_10) (get_local $_11)) (call $u256_to_i32 (get_local $_4) (get_local $_5) (get_local $_6) (get_local $_7))) (call $eth.finish (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_4) (get_local $_5) (get_local $_6) (get_local $_7)))
|
(call $eth.codeCopy (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_6) (get_local $_7) (get_local $_8) (get_local $_9)) (call $u256_to_i32 (get_local $_2) (get_local $_3) (get_local $_4) (get_local $_5))) (call $eth.finish (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_2) (get_local $_3) (get_local $_4) (get_local $_5)))
|
||||||
)
|
)
|
||||||
|
|
||||||
(func $u256_to_i32
|
(func $u256_to_i32
|
||||||
@ -147,16 +133,6 @@
|
|||||||
(get_local $y)
|
(get_local $y)
|
||||||
)
|
)
|
||||||
|
|
||||||
(func $endian_swap
|
|
||||||
(param $x i64)
|
|
||||||
(result i64)
|
|
||||||
(local $y i64)
|
|
||||||
(local $hi i64)
|
|
||||||
(set_local $hi (i64.shl (call $endian_swap_32 (get_local $x)) (i64.const 32)))
|
|
||||||
(set_local $y (i64.or (get_local $hi) (call $endian_swap_32 (i64.shr_u (get_local $x) (i64.const 32)))))
|
|
||||||
(get_local $y)
|
|
||||||
)
|
|
||||||
|
|
||||||
)
|
)
|
||||||
"}}}},"errors":[{"component":"general","formattedMessage":"Warning: The Yul optimiser is still experimental. Do not use it in production unless correctness of generated code is verified with extensive tests.
|
"}}}},"errors":[{"component":"general","formattedMessage":"Warning: The Yul optimiser is still experimental. Do not use it in production unless correctness of generated code is verified with extensive tests.
|
||||||
","message":"The Yul optimiser is still experimental. Do not use it in production unless correctness of generated code is verified with extensive tests.","severity":"warning","type":"Warning"}],"sources":{"A":{"id":0}}}
|
","message":"The Yul optimiser is still experimental. Do not use it in production unless correctness of generated code is verified with extensive tests.","severity":"warning","type":"Warning"}],"sources":{"A":{"id":0}}}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
||||||
#include <libyul/optimiser/DeadCodeEliminator.h>
|
#include <libyul/optimiser/DeadCodeEliminator.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/NameCollector.h>
|
#include <libyul/optimiser/NameCollector.h>
|
||||||
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
||||||
@ -45,6 +46,7 @@
|
|||||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||||
#include <libyul/optimiser/SSAReverser.h>
|
#include <libyul/optimiser/SSAReverser.h>
|
||||||
#include <libyul/optimiser/SSATransform.h>
|
#include <libyul/optimiser/SSATransform.h>
|
||||||
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
||||||
#include <libyul/optimiser/StructuralSimplifier.h>
|
#include <libyul/optimiser/StructuralSimplifier.h>
|
||||||
#include <libyul/optimiser/StackCompressor.h>
|
#include <libyul/optimiser/StackCompressor.h>
|
||||||
@ -149,7 +151,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
else if (m_optimizerStep == "commonSubexpressionEliminator")
|
else if (m_optimizerStep == "commonSubexpressionEliminator")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
(CommonSubexpressionEliminator{*m_dialect})(*m_ast);
|
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "expressionSplitter")
|
else if (m_optimizerStep == "expressionSplitter")
|
||||||
{
|
{
|
||||||
@ -218,9 +220,9 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
||||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
||||||
ForLoopInitRewriter{}(*m_ast);
|
ForLoopInitRewriter{}(*m_ast);
|
||||||
CommonSubexpressionEliminator{*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);
|
||||||
@ -228,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")
|
||||||
{
|
{
|
||||||
@ -260,12 +262,12 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
ForLoopInitRewriter{}(*m_ast);
|
ForLoopInitRewriter{}(*m_ast);
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
||||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
||||||
CommonSubexpressionEliminator{*m_dialect}(*m_ast);
|
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
||||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -298,8 +300,8 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
RedundantAssignEliminator::run(*m_dialect, *m_ast);
|
RedundantAssignEliminator::run(*m_dialect, *m_ast);
|
||||||
// reverse SSA
|
// reverse SSA
|
||||||
SSAReverser::run(*m_ast);
|
SSAReverser::run(*m_ast);
|
||||||
CommonSubexpressionEliminator{*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,26 @@
|
|||||||
|
{
|
||||||
|
function double(x) -> y { y := add(x, x) }
|
||||||
|
function double_with_se(x) -> y { y := add(x, x) mstore(40, 4) }
|
||||||
|
let i := mload(3)
|
||||||
|
let a := double(i)
|
||||||
|
let b := double(i)
|
||||||
|
let c := double_with_se(i)
|
||||||
|
let d := double_with_se(i)
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// step: commonSubexpressionEliminator
|
||||||
|
// ----
|
||||||
|
// {
|
||||||
|
// function double(x) -> y
|
||||||
|
// { y := add(x, x) }
|
||||||
|
// function double_with_se(x_1) -> y_2
|
||||||
|
// {
|
||||||
|
// y_2 := add(x_1, x_1)
|
||||||
|
// mstore(40, 4)
|
||||||
|
// }
|
||||||
|
// let i := mload(3)
|
||||||
|
// let a := double(i)
|
||||||
|
// let b := a
|
||||||
|
// let c := double_with_se(i)
|
||||||
|
// let d := double_with_se(i)
|
||||||
|
// }
|
@ -1,6 +1,6 @@
|
|||||||
// Even if the functions pass the equality check, they are not movable.
|
// Even if the functions pass the equality check, they are not movable.
|
||||||
{
|
{
|
||||||
function f() -> a { }
|
function f() -> a { mstore(1, 2) }
|
||||||
let b := sub(f(), f())
|
let b := sub(f(), f())
|
||||||
mstore(0, b)
|
mstore(0, b)
|
||||||
}
|
}
|
||||||
@ -9,6 +9,6 @@
|
|||||||
// ----
|
// ----
|
||||||
// {
|
// {
|
||||||
// function f() -> a
|
// function f() -> a
|
||||||
// { }
|
// { mstore(1, 2) }
|
||||||
// mstore(0, sub(f(), f()))
|
// mstore(0, sub(f(), f()))
|
||||||
// }
|
// }
|
||||||
|
@ -31,8 +31,5 @@
|
|||||||
// mstore8(calldataload(_5), 4)
|
// mstore8(calldataload(_5), 4)
|
||||||
// sstore(_5, mload(_2))
|
// sstore(_5, mload(_2))
|
||||||
// mstore(_2, _17)
|
// mstore(_2, _17)
|
||||||
// g()
|
|
||||||
// sstore(_5, mload(_2))
|
// sstore(_5, mload(_2))
|
||||||
// function g()
|
|
||||||
// { }
|
|
||||||
// }
|
// }
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
function f(x) -> t {
|
||||||
|
let b := 7
|
||||||
|
}
|
||||||
|
function g(x) -> t {
|
||||||
|
t := x
|
||||||
|
}
|
||||||
|
let x := f(g(2))
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// step: unusedPruner
|
||||||
|
// ----
|
||||||
|
// { }
|
@ -5,8 +5,4 @@
|
|||||||
// ====
|
// ====
|
||||||
// step: unusedPruner
|
// step: unusedPruner
|
||||||
// ----
|
// ----
|
||||||
// {
|
// { }
|
||||||
// function f() -> x, y
|
|
||||||
// { }
|
|
||||||
// let a, b := f()
|
|
||||||
// }
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
@ -151,7 +153,7 @@ public:
|
|||||||
ForLoopConditionIntoBody{}(*m_ast);
|
ForLoopConditionIntoBody{}(*m_ast);
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
(CommonSubexpressionEliminator{m_dialect})(*m_ast);
|
CommonSubexpressionEliminator::run(m_dialect, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
(VarDeclInitializer{})(*m_ast);
|
(VarDeclInitializer{})(*m_ast);
|
||||||
@ -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