mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7485 from ethereum/develop
Merge develop into develop_060
This commit is contained in:
commit
ca714a2d3d
@ -142,7 +142,7 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
|
|||||||
ssl,
|
ssl,
|
||||||
string("This variable is of storage pointer type and can be ") +
|
string("This variable is of storage pointer type and can be ") +
|
||||||
(variableOccurrence->kind() == VariableOccurrence::Kind::Return ? "returned" : "accessed") +
|
(variableOccurrence->kind() == VariableOccurrence::Kind::Return ? "returned" : "accessed") +
|
||||||
" without prior assignment."
|
" without prior assignment, which would lead to undefined behaviour."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -621,8 +621,8 @@ void SMTEncoder::visitFunctionIdentifier(Identifier const& _identifier)
|
|||||||
auto const& fType = dynamic_cast<FunctionType const&>(*_identifier.annotation().type);
|
auto const& fType = dynamic_cast<FunctionType const&>(*_identifier.annotation().type);
|
||||||
if (fType.returnParameterTypes().size() == 1)
|
if (fType.returnParameterTypes().size() == 1)
|
||||||
{
|
{
|
||||||
defineGlobalVariable(fType.richIdentifier(), _identifier);
|
defineGlobalVariable(fType.identifier(), _identifier);
|
||||||
m_context.createExpression(_identifier, m_context.globalSymbol(fType.richIdentifier()));
|
m_context.createExpression(_identifier, m_context.globalSymbol(fType.identifier()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ void SMTLib2Interface::reset()
|
|||||||
m_accumulatedOutput.emplace_back();
|
m_accumulatedOutput.emplace_back();
|
||||||
m_variables.clear();
|
m_variables.clear();
|
||||||
write("(set-option :produce-models true)");
|
write("(set-option :produce-models true)");
|
||||||
write("(set-logic QF_UFLIA)");
|
write("(set-logic ALL)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMTLib2Interface::push()
|
void SMTLib2Interface::push()
|
||||||
@ -126,9 +126,24 @@ string SMTLib2Interface::toSExpr(smt::Expression const& _expr)
|
|||||||
{
|
{
|
||||||
if (_expr.arguments.empty())
|
if (_expr.arguments.empty())
|
||||||
return _expr.name;
|
return _expr.name;
|
||||||
std::string sexpr = "(" + _expr.name;
|
|
||||||
for (auto const& arg: _expr.arguments)
|
std::string sexpr = "(";
|
||||||
sexpr += " " + toSExpr(arg);
|
if (_expr.name == "const_array")
|
||||||
|
{
|
||||||
|
solAssert(_expr.arguments.size() == 2, "");
|
||||||
|
auto sortSort = std::dynamic_pointer_cast<SortSort>(_expr.arguments.at(0).sort);
|
||||||
|
solAssert(sortSort, "");
|
||||||
|
auto arraySort = dynamic_pointer_cast<ArraySort>(sortSort->inner);
|
||||||
|
solAssert(arraySort, "");
|
||||||
|
sexpr += "(as const " + toSmtLibSort(*arraySort) + ") ";
|
||||||
|
sexpr += toSExpr(_expr.arguments.at(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sexpr += _expr.name;
|
||||||
|
for (auto const& arg: _expr.arguments)
|
||||||
|
sexpr += " " + toSExpr(arg);
|
||||||
|
}
|
||||||
sexpr += ")";
|
sexpr += ")";
|
||||||
return sexpr;
|
return sexpr;
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,7 @@ add_library(yul
|
|||||||
optimiser/NameDispenser.h
|
optimiser/NameDispenser.h
|
||||||
optimiser/NameDisplacer.cpp
|
optimiser/NameDisplacer.cpp
|
||||||
optimiser/NameDisplacer.h
|
optimiser/NameDisplacer.h
|
||||||
|
optimiser/OptimiserStep.h
|
||||||
optimiser/OptimizerUtilities.cpp
|
optimiser/OptimizerUtilities.cpp
|
||||||
optimiser/OptimizerUtilities.h
|
optimiser/OptimizerUtilities.h
|
||||||
optimiser/RedundantAssignEliminator.cpp
|
optimiser/RedundantAssignEliminator.cpp
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <libyul/optimiser/FunctionHoister.h>
|
#include <libyul/optimiser/FunctionHoister.h>
|
||||||
#include <libyul/optimiser/Disambiguator.h>
|
#include <libyul/optimiser/Disambiguator.h>
|
||||||
#include <libyul/optimiser/NameDisplacer.h>
|
#include <libyul/optimiser/NameDisplacer.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
#include <libyul/AsmParser.h>
|
#include <libyul/AsmParser.h>
|
||||||
#include <libyul/AsmAnalysis.h>
|
#include <libyul/AsmAnalysis.h>
|
||||||
@ -637,11 +638,14 @@ Object EVMToEWasmTranslator::run(Object const& _object)
|
|||||||
parsePolyfill();
|
parsePolyfill();
|
||||||
|
|
||||||
Block ast = boost::get<Block>(Disambiguator(m_dialect, *_object.analysisInfo)(*_object.code));
|
Block ast = boost::get<Block>(Disambiguator(m_dialect, *_object.analysisInfo)(*_object.code));
|
||||||
NameDispenser nameDispenser{m_dialect, ast};
|
set<YulString> reservedIdentifiers;
|
||||||
FunctionHoister{}(ast);
|
NameDispenser nameDispenser{m_dialect, ast, reservedIdentifiers};
|
||||||
FunctionGrouper{}(ast);
|
OptimiserStepContext context{m_dialect, nameDispenser, reservedIdentifiers};
|
||||||
|
|
||||||
|
FunctionHoister::run(context, ast);
|
||||||
|
FunctionGrouper::run(context, ast);
|
||||||
MainFunction{}(ast);
|
MainFunction{}(ast);
|
||||||
ExpressionSplitter{m_dialect, nameDispenser}(ast);
|
ExpressionSplitter::run(context, ast);
|
||||||
WordSizeTransform::run(m_dialect, ast, nameDispenser);
|
WordSizeTransform::run(m_dialect, ast, nameDispenser);
|
||||||
|
|
||||||
NameDisplacer{nameDispenser, m_polyfillFunctions}(ast);
|
NameDisplacer{nameDispenser, m_polyfillFunctions}(ast);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -24,8 +25,14 @@ namespace yul
|
|||||||
class BlockFlattener: public ASTModifier
|
class BlockFlattener: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"BlockFlattener"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast) { BlockFlattener{}(_ast); }
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BlockFlattener() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,11 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
void CommonSubexpressionEliminator::run(Dialect const& _dialect, Block& _ast)
|
void CommonSubexpressionEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
CommonSubexpressionEliminator cse{
|
CommonSubexpressionEliminator cse{
|
||||||
_dialect,
|
_context.dialect,
|
||||||
SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast))
|
SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast))
|
||||||
};
|
};
|
||||||
cse(_ast);
|
cse(_ast);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -38,8 +39,8 @@ struct SideEffects;
|
|||||||
class CommonSubexpressionEliminator: public DataFlowAnalyzer
|
class CommonSubexpressionEliminator: public DataFlowAnalyzer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Runs the CSE pass. @a _ast needs to be the complete AST of the program!
|
static constexpr char const* name{"CommonSubexpressionEliminator"};
|
||||||
static void run(Dialect const& _dialect, Block& _ast);
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CommonSubexpressionEliminator(
|
CommonSubexpressionEliminator(
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
#include <libyul/Utilities.h>
|
#include <libyul/Utilities.h>
|
||||||
#include <libyul/Dialect.h>
|
#include <libyul/Dialect.h>
|
||||||
@ -125,6 +126,11 @@ OptionalStatements reduceSingleCaseSwitch(Dialect const& _dialect, Switch& _swit
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ControlFlowSimplifier::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
ControlFlowSimplifier{_context.dialect}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
void ControlFlowSimplifier::operator()(Block& _block)
|
void ControlFlowSimplifier::operator()(Block& _block)
|
||||||
{
|
{
|
||||||
simplify(_block.statements);
|
simplify(_block.statements);
|
||||||
|
@ -17,10 +17,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplifies several control-flow structures:
|
* Simplifies several control-flow structures:
|
||||||
@ -46,7 +48,8 @@ struct Dialect;
|
|||||||
class ControlFlowSimplifier: public ASTModifier
|
class ControlFlowSimplifier: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ControlFlowSimplifier(Dialect const& _dialect): m_dialect(_dialect) {}
|
static constexpr char const* name{"ControlFlowSimplifier"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(Break&) override { ++m_numBreakStatements; }
|
void operator()(Break&) override { ++m_numBreakStatements; }
|
||||||
@ -56,6 +59,8 @@ public:
|
|||||||
void visit(Statement& _st) override;
|
void visit(Statement& _st) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ControlFlowSimplifier(Dialect const& _dialect): m_dialect(_dialect) {}
|
||||||
|
|
||||||
void simplify(std::vector<Statement>& _statements);
|
void simplify(std::vector<Statement>& _statements);
|
||||||
|
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/DeadCodeEliminator.h>
|
#include <libyul/optimiser/DeadCodeEliminator.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
|
|
||||||
#include <libevmasm/SemanticInformation.h>
|
#include <libevmasm/SemanticInformation.h>
|
||||||
@ -32,6 +33,11 @@ using namespace dev;
|
|||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
|
||||||
|
void DeadCodeEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
DeadCodeEliminator{_context.dialect}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
void DeadCodeEliminator::operator()(ForLoop& _for)
|
void DeadCodeEliminator::operator()(ForLoop& _for)
|
||||||
{
|
{
|
||||||
yulAssert(_for.pre.statements.empty(), "DeadCodeEliminator needs ForLoopInitRewriter as a prerequisite.");
|
yulAssert(_for.pre.statements.empty(), "DeadCodeEliminator needs ForLoopInitRewriter as a prerequisite.");
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimisation stage that removes unreachable code
|
* Optimisation stage that removes unreachable code
|
||||||
@ -47,13 +48,16 @@ struct Dialect;
|
|||||||
class DeadCodeEliminator: public ASTModifier
|
class DeadCodeEliminator: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeadCodeEliminator(Dialect const& _dialect): m_dialect(_dialect) {}
|
static constexpr char const* name{"DeadCodeEliminator"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(ForLoop& _for) override;
|
void operator()(ForLoop& _for) override;
|
||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
DeadCodeEliminator(Dialect const& _dialect): m_dialect(_dialect) {}
|
||||||
|
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
void EquivalentFunctionCombiner::run(Block& _ast)
|
void EquivalentFunctionCombiner::run(OptimiserStepContext&, Block& _ast)
|
||||||
{
|
{
|
||||||
EquivalentFunctionCombiner{EquivalentFunctionDetector::run(_ast)}(_ast);
|
EquivalentFunctionCombiner{EquivalentFunctionDetector::run(_ast)}(_ast);
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,14 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <libyul/optimiser/EquivalentFunctionDetector.h>
|
#include <libyul/optimiser/EquivalentFunctionDetector.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimiser component that detects syntactically equivalent functions and replaces all calls to any of them by calls
|
* Optimiser component that detects syntactically equivalent functions and replaces all calls to any of them by calls
|
||||||
* to one particular of them.
|
* to one particular of them.
|
||||||
@ -35,7 +38,8 @@ namespace yul
|
|||||||
class EquivalentFunctionCombiner: public ASTModifier
|
class EquivalentFunctionCombiner: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void run(Block& _ast);
|
static constexpr char const* name{"EquivalentFunctionCombiner"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(FunctionCall& _funCall) override;
|
void operator()(FunctionCall& _funCall) override;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <libyul/optimiser/NameCollector.h>
|
#include <libyul/optimiser/NameCollector.h>
|
||||||
#include <libyul/optimiser/Substitution.h>
|
#include <libyul/optimiser/Substitution.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
|
|
||||||
@ -32,13 +33,12 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
void ExpressionInliner::run()
|
void ExpressionInliner::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
InlinableExpressionFunctionFinder funFinder;
|
InlinableExpressionFunctionFinder funFinder;
|
||||||
funFinder(m_block);
|
funFinder(_ast);
|
||||||
m_inlinableFunctions = funFinder.inlinableFunctions();
|
ExpressionInliner inliner{_context.dialect, funFinder.inlinableFunctions()};
|
||||||
|
inliner(_ast);
|
||||||
(*this)(m_block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionInliner::operator()(FunctionDefinition& _fun)
|
void ExpressionInliner::operator()(FunctionDefinition& _fun)
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimiser component that modifies an AST in place, inlining functions that can be
|
* Optimiser component that modifies an AST in place, inlining functions that can be
|
||||||
@ -48,11 +49,8 @@ struct Dialect;
|
|||||||
class ExpressionInliner: public ASTModifier
|
class ExpressionInliner: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ExpressionInliner(Dialect const& _dialect, Block& _block):
|
static constexpr char const* name{"ExpressionInliner"};
|
||||||
m_block(_block), m_dialect(_dialect)
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
{}
|
|
||||||
|
|
||||||
void run();
|
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(FunctionDefinition& _fun) override;
|
void operator()(FunctionDefinition& _fun) override;
|
||||||
@ -60,13 +58,18 @@ public:
|
|||||||
void visit(Expression& _expression) override;
|
void visit(Expression& _expression) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<YulString, FunctionDefinition const*> m_inlinableFunctions;
|
ExpressionInliner(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
std::map<YulString, FunctionDefinition const*> const& _inlinableFunctions
|
||||||
|
): m_dialect(_dialect), m_inlinableFunctions(_inlinableFunctions)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Dialect const& m_dialect;
|
||||||
|
std::map<YulString, FunctionDefinition const*> const& m_inlinableFunctions;
|
||||||
|
|
||||||
std::map<YulString, YulString> m_varReplacements;
|
std::map<YulString, YulString> m_varReplacements;
|
||||||
/// Set of functions we are currently visiting inside.
|
/// Set of functions we are currently visiting inside.
|
||||||
std::set<YulString> m_currentFunctions;
|
std::set<YulString> m_currentFunctions;
|
||||||
|
|
||||||
Block& m_block;
|
|
||||||
Dialect const& m_dialect;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,12 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void ExpressionJoiner::run(OptimiserStepContext&, Block& _ast)
|
||||||
|
{
|
||||||
|
ExpressionJoiner{_ast}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExpressionJoiner::operator()(FunctionalInstruction& _instruction)
|
void ExpressionJoiner::operator()(FunctionalInstruction& _instruction)
|
||||||
{
|
{
|
||||||
handleArguments(_instruction.arguments);
|
handleArguments(_instruction.arguments);
|
||||||
@ -78,11 +84,6 @@ void ExpressionJoiner::visit(Expression& _e)
|
|||||||
ASTModifier::visit(_e);
|
ASTModifier::visit(_e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionJoiner::run(Block& _ast)
|
|
||||||
{
|
|
||||||
ExpressionJoiner{_ast}(_ast);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionJoiner::ExpressionJoiner(Block& _ast)
|
ExpressionJoiner::ExpressionJoiner(Block& _ast)
|
||||||
{
|
{
|
||||||
m_references = ReferencesCounter::countReferences(_ast);
|
m_references = ReferencesCounter::countReferences(_ast);
|
||||||
|
@ -29,6 +29,7 @@ namespace yul
|
|||||||
{
|
{
|
||||||
|
|
||||||
class NameCollector;
|
class NameCollector;
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +71,8 @@ class NameCollector;
|
|||||||
class ExpressionJoiner: public ASTModifier
|
class ExpressionJoiner: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void run(Block& _ast);
|
static constexpr char const* name{"ExpressionJoiner"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ExpressionJoiner(Block& _ast);
|
explicit ExpressionJoiner(Block& _ast);
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/SimplificationRules.h>
|
#include <libyul/optimiser/SimplificationRules.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/SSAValueTracker.h>
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
|
|
||||||
#include <libdevcore/CommonData.h>
|
#include <libdevcore/CommonData.h>
|
||||||
@ -31,6 +31,11 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void ExpressionSimplifier::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
ExpressionSimplifier{_context.dialect}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
void ExpressionSimplifier::visit(Expression& _expression)
|
void ExpressionSimplifier::visit(Expression& _expression)
|
||||||
{
|
{
|
||||||
ASTModifier::visit(_expression);
|
ASTModifier::visit(_expression);
|
||||||
@ -48,8 +53,3 @@ void ExpressionSimplifier::visit(Expression& _expression)
|
|||||||
_expression = match->action().toExpression(locationOf(_expression));
|
_expression = match->action().toExpression(locationOf(_expression));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionSimplifier::run(Dialect const& _dialect, Block& _ast)
|
|
||||||
{
|
|
||||||
ExpressionSimplifier{_dialect}(_ast);
|
|
||||||
}
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies simplification rules to all expressions.
|
* Applies simplification rules to all expressions.
|
||||||
@ -41,10 +42,12 @@ struct Dialect;
|
|||||||
class ExpressionSimplifier: public DataFlowAnalyzer
|
class ExpressionSimplifier: public DataFlowAnalyzer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"ExpressionSimplifier"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
virtual void visit(Expression& _expression);
|
virtual void visit(Expression& _expression);
|
||||||
|
|
||||||
static void run(Dialect const& _dialect, Block& _ast);
|
|
||||||
private:
|
private:
|
||||||
explicit ExpressionSimplifier(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
|
explicit ExpressionSimplifier(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
|
||||||
};
|
};
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <libyul/optimiser/ExpressionSplitter.h>
|
#include <libyul/optimiser/ExpressionSplitter.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
#include <libyul/Dialect.h>
|
#include <libyul/Dialect.h>
|
||||||
@ -35,6 +36,11 @@ using namespace dev;
|
|||||||
using namespace langutil;
|
using namespace langutil;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void ExpressionSplitter::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
ExpressionSplitter{_context.dialect, _context.dispenser}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
void ExpressionSplitter::operator()(FunctionalInstruction& _instruction)
|
void ExpressionSplitter::operator()(FunctionalInstruction& _instruction)
|
||||||
{
|
{
|
||||||
for (auto& arg: _instruction.arguments | boost::adaptors::reversed)
|
for (auto& arg: _instruction.arguments | boost::adaptors::reversed)
|
||||||
|
@ -32,7 +32,7 @@ namespace yul
|
|||||||
|
|
||||||
class NameCollector;
|
class NameCollector;
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimiser component that modifies an AST in place, turning complex
|
* Optimiser component that modifies an AST in place, turning complex
|
||||||
@ -58,9 +58,8 @@ struct Dialect;
|
|||||||
class ExpressionSplitter: public ASTModifier
|
class ExpressionSplitter: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ExpressionSplitter(Dialect const& _dialect, NameDispenser& _nameDispenser):
|
static constexpr char const* name{"ExpressionSplitter"};
|
||||||
m_dialect(_dialect), m_nameDispenser(_nameDispenser)
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
{ }
|
|
||||||
|
|
||||||
void operator()(FunctionalInstruction&) override;
|
void operator()(FunctionalInstruction&) override;
|
||||||
void operator()(FunctionCall&) override;
|
void operator()(FunctionCall&) override;
|
||||||
@ -70,6 +69,10 @@ public:
|
|||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit ExpressionSplitter(Dialect const& _dialect, NameDispenser& _nameDispenser):
|
||||||
|
m_dialect(_dialect), m_nameDispenser(_nameDispenser)
|
||||||
|
{ }
|
||||||
|
|
||||||
/// Replaces the expression by a variable if it is a function call or functional
|
/// Replaces the expression by a variable if it is a function call or functional
|
||||||
/// instruction. The declaration of the variable is appended to m_statementsToPrefix.
|
/// instruction. The declaration of the variable is appended to m_statementsToPrefix.
|
||||||
/// Recurses via visit().
|
/// Recurses via visit().
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
|
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
#include <libdevcore/CommonData.h>
|
#include <libdevcore/CommonData.h>
|
||||||
|
|
||||||
@ -23,6 +24,11 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void ForLoopConditionIntoBody::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
ForLoopConditionIntoBody{_context.dialect}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
|
void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
|
||||||
{
|
{
|
||||||
if (m_dialect.booleanNegationFunction() && _forLoop.condition->type() != typeid(Literal))
|
if (m_dialect.booleanNegationFunction() && _forLoop.condition->type() != typeid(Literal))
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rewrites ForLoop by moving iteration condition into the ForLoop body.
|
* Rewrites ForLoop by moving iteration condition into the ForLoop body.
|
||||||
* For example, `for {} lt(a, b) {} { mstore(1, 2) }` will become
|
* For example, `for {} lt(a, b) {} { mstore(1, 2) }` will become
|
||||||
@ -40,11 +42,15 @@ namespace yul
|
|||||||
class ForLoopConditionIntoBody: public ASTModifier
|
class ForLoopConditionIntoBody: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ForLoopConditionIntoBody(Dialect const& _dialect): m_dialect(_dialect) {}
|
static constexpr char const* name{"ForLoopConditionIntoBody"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(ForLoop& _forLoop) override;
|
void operator()(ForLoop& _forLoop) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ForLoopConditionIntoBody(Dialect const& _dialect): m_dialect(_dialect) {}
|
||||||
|
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,6 +25,11 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void ForLoopConditionOutOfBody::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
ForLoopConditionOutOfBody{_context.dialect}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop)
|
void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop)
|
||||||
{
|
{
|
||||||
ASTModifier::operator()(_forLoop);
|
ASTModifier::operator()(_forLoop);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/Dialect.h>
|
#include <libyul/Dialect.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
@ -56,13 +57,17 @@ namespace yul
|
|||||||
class ForLoopConditionOutOfBody: public ASTModifier
|
class ForLoopConditionOutOfBody: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ForLoopConditionOutOfBody(Dialect const& _dialect):
|
static constexpr char const* name{"ForLoopConditionOutOfBody"};
|
||||||
m_dialect(_dialect)
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
{}
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(ForLoop& _forLoop) override;
|
void operator()(ForLoop& _forLoop) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ForLoopConditionOutOfBody(Dialect const& _dialect):
|
||||||
|
m_dialect(_dialect)
|
||||||
|
{}
|
||||||
|
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -29,8 +30,17 @@ namespace yul
|
|||||||
class ForLoopInitRewriter: public ASTModifier
|
class ForLoopInitRewriter: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"ForLoopInitRewriter"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast)
|
||||||
|
{
|
||||||
|
ForLoopInitRewriter{}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ForLoopInitRewriter() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,11 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void FullInliner::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
FullInliner{_ast, _context.dispenser}.run();
|
||||||
|
}
|
||||||
|
|
||||||
FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
|
FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
|
||||||
m_ast(_ast), m_nameDispenser(_dispenser)
|
m_ast(_ast), m_nameDispenser(_dispenser)
|
||||||
{
|
{
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <libyul/optimiser/ASTCopier.h>
|
#include <libyul/optimiser/ASTCopier.h>
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <libyul/optimiser/NameDispenser.h>
|
#include <libyul/optimiser/NameDispenser.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
|
|
||||||
#include <liblangutil/SourceLocation.h>
|
#include <liblangutil/SourceLocation.h>
|
||||||
@ -69,9 +70,8 @@ class NameCollector;
|
|||||||
class FullInliner: public ASTModifier
|
class FullInliner: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit FullInliner(Block& _ast, NameDispenser& _dispenser);
|
static constexpr char const* name{"FullInliner"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
void run();
|
|
||||||
|
|
||||||
/// Inlining heuristic.
|
/// Inlining heuristic.
|
||||||
/// @param _callSite the name of the function in which the function call is located.
|
/// @param _callSite the name of the function in which the function call is located.
|
||||||
@ -91,6 +91,9 @@ public:
|
|||||||
void tentativelyUpdateCodeSize(YulString _function, YulString _callSite);
|
void tentativelyUpdateCodeSize(YulString _function, YulString _callSite);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FullInliner(Block& _ast, NameDispenser& _dispenser);
|
||||||
|
void run();
|
||||||
|
|
||||||
void updateCodeSize(FunctionDefinition const& _fun);
|
void updateCodeSize(FunctionDefinition const& _fun);
|
||||||
void handleBlock(YulString _currentFunctionName, Block& _block);
|
void handleBlock(YulString _currentFunctionName, Block& _block);
|
||||||
bool recursive(FunctionDefinition const& _fun) const;
|
bool recursive(FunctionDefinition const& _fun) const;
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves all instructions in a block into a new block at the start of the block, followed by
|
* Moves all instructions in a block into a new block at the start of the block, followed by
|
||||||
* all function definitions.
|
* all function definitions.
|
||||||
@ -37,9 +39,14 @@ namespace yul
|
|||||||
class FunctionGrouper
|
class FunctionGrouper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"FunctionGrouper"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast) { FunctionGrouper{}(_ast); }
|
||||||
|
|
||||||
void operator()(Block& _block);
|
void operator()(Block& _block);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FunctionGrouper() = default;
|
||||||
|
|
||||||
bool alreadyGrouped(Block const& _block);
|
bool alreadyGrouped(Block const& _block);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves all functions to the top-level scope.
|
* Moves all functions to the top-level scope.
|
||||||
@ -37,10 +38,15 @@ namespace yul
|
|||||||
class FunctionHoister: public ASTModifier
|
class FunctionHoister: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"FunctionHoister"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast) { FunctionHoister{}(_ast); }
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
virtual void operator()(Block& _block);
|
virtual void operator()(Block& _block);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FunctionHoister() = default;
|
||||||
|
|
||||||
bool m_isTopLevel = true;
|
bool m_isTopLevel = true;
|
||||||
std::vector<Statement> m_functions;
|
std::vector<Statement> m_functions;
|
||||||
};
|
};
|
||||||
|
@ -31,12 +31,12 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
void LoadResolver::run(Dialect const& _dialect, Block& _ast)
|
void LoadResolver::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
bool containsMSize = MSizeFinder::containsMSize(_dialect, _ast);
|
bool containsMSize = MSizeFinder::containsMSize(_context.dialect, _ast);
|
||||||
LoadResolver{
|
LoadResolver{
|
||||||
_dialect,
|
_context.dialect,
|
||||||
SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast)),
|
SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast)),
|
||||||
!containsMSize
|
!containsMSize
|
||||||
}(_ast);
|
}(_ast);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
@ -41,8 +42,9 @@ struct BuiltinFunctionForEVM;
|
|||||||
class LoadResolver: public DataFlowAnalyzer
|
class LoadResolver: public DataFlowAnalyzer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"LoadResolver"};
|
||||||
/// Run the load resolver on the given complete AST.
|
/// Run the load resolver on the given complete AST.
|
||||||
static void run(Dialect const& _dialect, Block& _ast);
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LoadResolver(
|
LoadResolver(
|
||||||
|
@ -26,13 +26,21 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct OptimiserStepContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prerequisites: Function Grouper
|
* Prerequisites: Function Grouper
|
||||||
*/
|
*/
|
||||||
class MainFunction
|
class MainFunction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"MainFunction"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast) { MainFunction{}(_ast); }
|
||||||
|
|
||||||
void operator()(Block& _block);
|
void operator()(Block& _block);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MainFunction() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
65
libyul/optimiser/OptimiserStep.h
Normal file
65
libyul/optimiser/OptimiserStep.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libyul/Exceptions.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace yul
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Dialect;
|
||||||
|
struct Block;
|
||||||
|
class YulString;
|
||||||
|
class NameDispenser;
|
||||||
|
|
||||||
|
struct OptimiserStepContext
|
||||||
|
{
|
||||||
|
Dialect const& dialect;
|
||||||
|
NameDispenser& dispenser;
|
||||||
|
std::set<YulString> const& reservedIdentifiers;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construction to create dynamically callable objects out of the
|
||||||
|
* statically callable optimiser steps.
|
||||||
|
*/
|
||||||
|
struct OptimiserStep
|
||||||
|
{
|
||||||
|
explicit OptimiserStep(std::string _name): name(std::move(_name)) {}
|
||||||
|
virtual ~OptimiserStep() = default;
|
||||||
|
|
||||||
|
virtual void run(OptimiserStepContext&, Block&) const = 0;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Step>
|
||||||
|
struct OptimiserStepInstance: public OptimiserStep
|
||||||
|
{
|
||||||
|
OptimiserStepInstance(): OptimiserStep{Step::name} {}
|
||||||
|
void run(OptimiserStepContext& _context, Block& _ast) const override
|
||||||
|
{
|
||||||
|
Step::run(_context, _ast);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -32,6 +32,15 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void RedundantAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
RedundantAssignEliminator rae{_context.dialect};
|
||||||
|
rae(_ast);
|
||||||
|
|
||||||
|
AssignmentRemover remover{rae.m_pendingRemovals};
|
||||||
|
remover(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Identifier const& _identifier)
|
void RedundantAssignEliminator::operator()(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
changeUndecidedTo(_identifier.name, State::Used);
|
changeUndecidedTo(_identifier.name, State::Used);
|
||||||
@ -204,14 +213,6 @@ void RedundantAssignEliminator::operator()(Block const& _block)
|
|||||||
swap(m_declaredVariables, outerDeclaredVariables);
|
swap(m_declaredVariables, outerDeclaredVariables);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::run(Dialect const& _dialect, Block& _ast)
|
|
||||||
{
|
|
||||||
RedundantAssignEliminator rae{_dialect};
|
|
||||||
rae(_ast);
|
|
||||||
|
|
||||||
AssignmentRemover remover{rae.m_pendingRemovals};
|
|
||||||
remover(_ast);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class K, class V, class F>
|
template <class K, class V, class F>
|
||||||
void joinMap(std::map<K, V>& _a, std::map<K, V>&& _b, F _conflictSolver)
|
void joinMap(std::map<K, V>& _a, std::map<K, V>&& _b, F _conflictSolver)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -105,6 +106,9 @@ struct Dialect;
|
|||||||
class RedundantAssignEliminator: public ASTWalker
|
class RedundantAssignEliminator: public ASTWalker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"RedundantAssignEliminator"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
explicit RedundantAssignEliminator(Dialect const& _dialect): m_dialect(&_dialect) {}
|
explicit RedundantAssignEliminator(Dialect const& _dialect): m_dialect(&_dialect) {}
|
||||||
RedundantAssignEliminator() = delete;
|
RedundantAssignEliminator() = delete;
|
||||||
RedundantAssignEliminator(RedundantAssignEliminator const&) = delete;
|
RedundantAssignEliminator(RedundantAssignEliminator const&) = delete;
|
||||||
@ -123,8 +127,6 @@ public:
|
|||||||
void operator()(Continue const&) override;
|
void operator()(Continue const&) override;
|
||||||
void operator()(Block const& _block) override;
|
void operator()(Block const& _block) override;
|
||||||
|
|
||||||
static void run(Dialect const& _dialect, Block& _ast);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class State
|
class State
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -38,6 +39,12 @@ namespace yul
|
|||||||
class Rematerialiser: public DataFlowAnalyzer
|
class Rematerialiser: public DataFlowAnalyzer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"Rematerialiser"};
|
||||||
|
static void run(
|
||||||
|
OptimiserStepContext& _context,
|
||||||
|
Block& _ast
|
||||||
|
) { run(_context.dialect, _ast); }
|
||||||
|
|
||||||
static void run(
|
static void run(
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
@ -80,12 +87,19 @@ protected:
|
|||||||
class LiteralRematerialiser: public DataFlowAnalyzer
|
class LiteralRematerialiser: public DataFlowAnalyzer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LiteralRematerialiser(Dialect const& _dialect):
|
static constexpr char const* name{"LiteralRematerialiser"};
|
||||||
DataFlowAnalyzer(_dialect)
|
static void run(
|
||||||
{}
|
OptimiserStepContext& _context,
|
||||||
|
Block& _ast
|
||||||
|
) { LiteralRematerialiser{_context.dialect}(_ast); }
|
||||||
|
|
||||||
using ASTModifier::visit;
|
using ASTModifier::visit;
|
||||||
void visit(Expression& _e) override;
|
void visit(Expression& _e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LiteralRematerialiser(Dialect const& _dialect):
|
||||||
|
DataFlowAnalyzer(_dialect)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
void SSAReverser::run(Block& _block)
|
void SSAReverser::run(OptimiserStepContext&, Block& _block)
|
||||||
{
|
{
|
||||||
AssignmentCounter assignmentCounter;
|
AssignmentCounter assignmentCounter;
|
||||||
assignmentCounter(_block);
|
assignmentCounter(_block);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -69,12 +70,15 @@ class AssignmentCounter;
|
|||||||
class SSAReverser: public ASTModifier
|
class SSAReverser: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"SSAReverser"};
|
||||||
|
static void run(OptimiserStepContext& _context, Block& _ast);
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
|
|
||||||
static void run(Block& _block);
|
|
||||||
private:
|
private:
|
||||||
SSAReverser(AssignmentCounter const& _assignmentCounter): m_assignmentCounter(_assignmentCounter) {}
|
explicit SSAReverser(AssignmentCounter const& _assignmentCounter): m_assignmentCounter(_assignmentCounter) {}
|
||||||
|
|
||||||
AssignmentCounter const& m_assignmentCounter;
|
AssignmentCounter const& m_assignmentCounter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -373,12 +373,12 @@ void PropagateValues::operator()(Block& _block)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSATransform::run(Block& _ast, NameDispenser& _nameDispenser)
|
void SSATransform::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
Assignments assignments;
|
Assignments assignments;
|
||||||
assignments(_ast);
|
assignments(_ast);
|
||||||
IntroduceSSA{_nameDispenser, assignments.names()}(_ast);
|
IntroduceSSA{_context.dispenser, assignments.names()}(_ast);
|
||||||
IntroduceControlFlowSSA{_nameDispenser, assignments.names()}(_ast);
|
IntroduceControlFlowSSA{_context.dispenser, assignments.names()}(_ast);
|
||||||
PropagateValues{assignments.names()}(_ast);
|
PropagateValues{assignments.names()}(_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
#include <liblangutil/SourceLocation.h>
|
#include <liblangutil/SourceLocation.h>
|
||||||
|
|
||||||
@ -89,7 +90,8 @@ class NameDispenser;
|
|||||||
class SSATransform: public ASTModifier
|
class SSATransform: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void run(Block& _ast, NameDispenser& _nameDispenser);
|
static constexpr char const* name{"SSATransform"};
|
||||||
|
static void run(OptimiserStepContext& _context, Block& _ast);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,11 @@ OptionalStatements replaceConstArgSwitch(Switch& _switchStmt, u256 const& _const
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StructuralSimplifier::run(OptimiserStepContext&, Block& _ast)
|
||||||
|
{
|
||||||
|
StructuralSimplifier{}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
void StructuralSimplifier::operator()(Block& _block)
|
void StructuralSimplifier::operator()(Block& _block)
|
||||||
{
|
{
|
||||||
simplify(_block.statements);
|
simplify(_block.statements);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
@ -39,9 +40,14 @@ namespace yul
|
|||||||
class StructuralSimplifier: public ASTModifier
|
class StructuralSimplifier: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"StructuralSimplifier"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
private:
|
private:
|
||||||
|
StructuralSimplifier() = default;
|
||||||
|
|
||||||
void simplify(std::vector<Statement>& _statements);
|
void simplify(std::vector<Statement>& _statements);
|
||||||
bool expressionAlwaysTrue(Expression const& _expression);
|
bool expressionAlwaysTrue(Expression const& _expression);
|
||||||
bool expressionAlwaysFalse(Expression const& _expression);
|
bool expressionAlwaysFalse(Expression const& _expression);
|
||||||
|
@ -83,26 +83,28 @@ void OptimiserSuite::run(
|
|||||||
)(*_object.code));
|
)(*_object.code));
|
||||||
Block& ast = *_object.code;
|
Block& ast = *_object.code;
|
||||||
|
|
||||||
VarDeclInitializer{}(ast);
|
OptimiserSuite suite(_dialect, reservedIdentifiers, Debug::None, ast);
|
||||||
FunctionHoister{}(ast);
|
|
||||||
BlockFlattener{}(ast);
|
suite.runSequence({
|
||||||
ForLoopInitRewriter{}(ast);
|
VarDeclInitializer::name,
|
||||||
DeadCodeEliminator{_dialect}(ast);
|
FunctionHoister::name,
|
||||||
FunctionGrouper{}(ast);
|
BlockFlattener::name,
|
||||||
EquivalentFunctionCombiner::run(ast);
|
ForLoopInitRewriter::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
DeadCodeEliminator::name,
|
||||||
BlockFlattener{}(ast);
|
FunctionGrouper::name,
|
||||||
ControlFlowSimplifier{_dialect}(ast);
|
EquivalentFunctionCombiner::name,
|
||||||
LiteralRematerialiser{_dialect}(ast);
|
UnusedPruner::name,
|
||||||
StructuralSimplifier{}(ast);
|
BlockFlattener::name,
|
||||||
ControlFlowSimplifier{_dialect}(ast);
|
ControlFlowSimplifier::name,
|
||||||
ForLoopConditionIntoBody{_dialect}(ast);
|
LiteralRematerialiser::name,
|
||||||
BlockFlattener{}(ast);
|
StructuralSimplifier::name,
|
||||||
|
ControlFlowSimplifier::name,
|
||||||
|
ForLoopConditionIntoBody::name,
|
||||||
|
BlockFlattener::name
|
||||||
|
}, ast);
|
||||||
|
|
||||||
// None of the above can make stack problems worse.
|
// None of the above can make stack problems worse.
|
||||||
|
|
||||||
NameDispenser dispenser{_dialect, ast, reservedIdentifiers};
|
|
||||||
|
|
||||||
size_t codeSize = 0;
|
size_t codeSize = 0;
|
||||||
for (size_t rounds = 0; rounds < 12; ++rounds)
|
for (size_t rounds = 0; rounds < 12; ++rounds)
|
||||||
{
|
{
|
||||||
@ -115,120 +117,138 @@ void OptimiserSuite::run(
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Turn into SSA and simplify
|
// Turn into SSA and simplify
|
||||||
ExpressionSplitter{_dialect, dispenser}(ast);
|
suite.runSequence({
|
||||||
SSATransform::run(ast, dispenser);
|
ExpressionSplitter::name,
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
SSATransform::name,
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
RedundantAssignEliminator::name,
|
||||||
|
RedundantAssignEliminator::name,
|
||||||
ExpressionSimplifier::run(_dialect, ast);
|
ExpressionSimplifier::name,
|
||||||
|
CommonSubexpressionEliminator::name,
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
LoadResolver::name
|
||||||
LoadResolver::run(_dialect, ast);
|
}, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// still in SSA, perform structural simplification
|
// still in SSA, perform structural simplification
|
||||||
LiteralRematerialiser{_dialect}(ast);
|
suite.runSequence({
|
||||||
ForLoopConditionOutOfBody{_dialect}(ast);
|
LiteralRematerialiser::name,
|
||||||
ControlFlowSimplifier{_dialect}(ast);
|
ForLoopConditionOutOfBody::name,
|
||||||
StructuralSimplifier{}(ast);
|
ControlFlowSimplifier::name,
|
||||||
ControlFlowSimplifier{_dialect}(ast);
|
StructuralSimplifier::name,
|
||||||
BlockFlattener{}(ast);
|
ControlFlowSimplifier::name,
|
||||||
DeadCodeEliminator{_dialect}(ast);
|
BlockFlattener::name,
|
||||||
ForLoopConditionIntoBody{_dialect}(ast);
|
DeadCodeEliminator::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
ForLoopConditionIntoBody::name,
|
||||||
|
UnusedPruner::name
|
||||||
|
}, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// simplify again
|
// simplify again
|
||||||
LoadResolver::run(_dialect, ast);
|
suite.runSequence({
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
LoadResolver::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
CommonSubexpressionEliminator::name,
|
||||||
|
UnusedPruner::name,
|
||||||
|
}, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// reverse SSA
|
// reverse SSA
|
||||||
SSAReverser::run(ast);
|
suite.runSequence({
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
SSAReverser::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
CommonSubexpressionEliminator::name,
|
||||||
|
UnusedPruner::name,
|
||||||
|
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::name,
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::name,
|
||||||
|
}, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
// should have good "compilability" property here.
|
// should have good "compilability" property here.
|
||||||
|
|
||||||
{
|
{
|
||||||
// run functional expression inliner
|
// run functional expression inliner
|
||||||
ExpressionInliner(_dialect, ast).run();
|
suite.runSequence({
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
ExpressionInliner::name,
|
||||||
|
UnusedPruner::name,
|
||||||
|
}, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Turn into SSA again and simplify
|
// Turn into SSA again and simplify
|
||||||
ExpressionSplitter{_dialect, dispenser}(ast);
|
suite.runSequence({
|
||||||
SSATransform::run(ast, dispenser);
|
ExpressionSplitter::name,
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
SSATransform::name,
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
RedundantAssignEliminator::name,
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
RedundantAssignEliminator::name,
|
||||||
LoadResolver::run(_dialect, ast);
|
CommonSubexpressionEliminator::name,
|
||||||
|
LoadResolver::name,
|
||||||
|
}, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// run full inliner
|
// run full inliner
|
||||||
FunctionGrouper{}(ast);
|
suite.runSequence({
|
||||||
EquivalentFunctionCombiner::run(ast);
|
FunctionGrouper::name,
|
||||||
FullInliner{ast, dispenser}.run();
|
EquivalentFunctionCombiner::name,
|
||||||
BlockFlattener{}(ast);
|
FullInliner::name,
|
||||||
|
BlockFlattener::name
|
||||||
|
}, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// SSA plus simplify
|
// SSA plus simplify
|
||||||
SSATransform::run(ast, dispenser);
|
suite.runSequence({
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
SSATransform::name,
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
RedundantAssignEliminator::name,
|
||||||
LoadResolver::run(_dialect, ast);
|
RedundantAssignEliminator::name,
|
||||||
ExpressionSimplifier::run(_dialect, ast);
|
LoadResolver::name,
|
||||||
LiteralRematerialiser{_dialect}(ast);
|
ExpressionSimplifier::name,
|
||||||
ForLoopConditionOutOfBody{_dialect}(ast);
|
LiteralRematerialiser::name,
|
||||||
StructuralSimplifier{}(ast);
|
ForLoopConditionOutOfBody::name,
|
||||||
BlockFlattener{}(ast);
|
StructuralSimplifier::name,
|
||||||
DeadCodeEliminator{_dialect}(ast);
|
BlockFlattener::name,
|
||||||
ControlFlowSimplifier{_dialect}(ast);
|
DeadCodeEliminator::name,
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
ControlFlowSimplifier::name,
|
||||||
SSATransform::run(ast, dispenser);
|
CommonSubexpressionEliminator::name,
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
SSATransform::name,
|
||||||
RedundantAssignEliminator::run(_dialect, ast);
|
RedundantAssignEliminator::name,
|
||||||
ForLoopConditionIntoBody{_dialect}(ast);
|
RedundantAssignEliminator::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
ForLoopConditionIntoBody::name,
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
UnusedPruner::name,
|
||||||
|
CommonSubexpressionEliminator::name,
|
||||||
|
}, ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make source short and pretty.
|
// Make source short and pretty.
|
||||||
|
|
||||||
ExpressionJoiner::run(ast);
|
suite.runSequence({
|
||||||
Rematerialiser::run(_dialect, ast);
|
ExpressionJoiner::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
Rematerialiser::name,
|
||||||
ExpressionJoiner::run(ast);
|
UnusedPruner::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
ExpressionJoiner::name,
|
||||||
ExpressionJoiner::run(ast);
|
UnusedPruner::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
ExpressionJoiner::name,
|
||||||
|
UnusedPruner::name,
|
||||||
|
|
||||||
SSAReverser::run(ast);
|
SSAReverser::name,
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
CommonSubexpressionEliminator::name,
|
||||||
LiteralRematerialiser{_dialect}(ast);
|
LiteralRematerialiser::name,
|
||||||
ForLoopConditionOutOfBody{_dialect}(ast);
|
ForLoopConditionOutOfBody::name,
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
CommonSubexpressionEliminator::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::name,
|
||||||
|
|
||||||
ExpressionJoiner::run(ast);
|
ExpressionJoiner::name,
|
||||||
Rematerialiser::run(_dialect, ast);
|
Rematerialiser::name,
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
|
UnusedPruner::name,
|
||||||
|
}, ast);
|
||||||
|
|
||||||
// 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;
|
||||||
FunctionGrouper{}(ast);
|
suite.runSequence({
|
||||||
|
FunctionGrouper::name
|
||||||
|
}, ast);
|
||||||
// We ignore the return value because we will get a much better error
|
// We ignore the return value because we will get a much better error
|
||||||
// message once we perform code generation.
|
// message once we perform code generation.
|
||||||
StackCompressor::run(
|
StackCompressor::run(
|
||||||
@ -237,14 +257,16 @@ void OptimiserSuite::run(
|
|||||||
_optimizeStackAllocation,
|
_optimizeStackAllocation,
|
||||||
stackCompressorMaxIterations
|
stackCompressorMaxIterations
|
||||||
);
|
);
|
||||||
BlockFlattener{}(ast);
|
suite.runSequence({
|
||||||
DeadCodeEliminator{_dialect}(ast);
|
BlockFlattener::name,
|
||||||
ControlFlowSimplifier{_dialect}(ast);
|
DeadCodeEliminator::name,
|
||||||
LiteralRematerialiser{_dialect}(ast);
|
ControlFlowSimplifier::name,
|
||||||
ForLoopConditionOutOfBody{_dialect}(ast);
|
LiteralRematerialiser::name,
|
||||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
ForLoopConditionOutOfBody::name,
|
||||||
|
CommonSubexpressionEliminator::name,
|
||||||
|
|
||||||
FunctionGrouper{}(ast);
|
FunctionGrouper::name,
|
||||||
|
}, ast);
|
||||||
|
|
||||||
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
||||||
{
|
{
|
||||||
@ -258,7 +280,73 @@ void OptimiserSuite::run(
|
|||||||
if (ast.statements.size() > 1 && boost::get<Block>(ast.statements.front()).statements.empty())
|
if (ast.statements.size() > 1 && boost::get<Block>(ast.statements.front()).statements.empty())
|
||||||
ast.statements.erase(ast.statements.begin());
|
ast.statements.erase(ast.statements.begin());
|
||||||
}
|
}
|
||||||
VarNameCleaner{ast, _dialect, reservedIdentifiers}(ast);
|
suite.runSequence({
|
||||||
|
VarNameCleaner::name
|
||||||
|
}, ast);
|
||||||
|
|
||||||
*_object.analysisInfo = AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object);
|
*_object.analysisInfo = AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
template <class... Step>
|
||||||
|
map<string, unique_ptr<OptimiserStep>> optimiserStepCollection()
|
||||||
|
{
|
||||||
|
map<string, unique_ptr<OptimiserStep>> ret;
|
||||||
|
for (unique_ptr<OptimiserStep>& s: make_vector<unique_ptr<OptimiserStep>>(
|
||||||
|
(make_unique<OptimiserStepInstance<Step>>())...
|
||||||
|
))
|
||||||
|
{
|
||||||
|
yulAssert(!ret.count(s->name), "");
|
||||||
|
ret[s->name] = std::move(s);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
|
||||||
|
{
|
||||||
|
static map<string, unique_ptr<OptimiserStep>> instance;
|
||||||
|
if (instance.empty())
|
||||||
|
instance = optimiserStepCollection<
|
||||||
|
BlockFlattener,
|
||||||
|
CommonSubexpressionEliminator,
|
||||||
|
ControlFlowSimplifier,
|
||||||
|
DeadCodeEliminator,
|
||||||
|
EquivalentFunctionCombiner,
|
||||||
|
ExpressionInliner,
|
||||||
|
ExpressionJoiner,
|
||||||
|
ExpressionSimplifier,
|
||||||
|
ExpressionSplitter,
|
||||||
|
ForLoopConditionIntoBody,
|
||||||
|
ForLoopConditionOutOfBody,
|
||||||
|
ForLoopInitRewriter,
|
||||||
|
FullInliner,
|
||||||
|
FunctionGrouper,
|
||||||
|
FunctionHoister,
|
||||||
|
LiteralRematerialiser,
|
||||||
|
LoadResolver,
|
||||||
|
RedundantAssignEliminator,
|
||||||
|
Rematerialiser,
|
||||||
|
SSAReverser,
|
||||||
|
SSATransform,
|
||||||
|
StructuralSimplifier,
|
||||||
|
UnusedPruner,
|
||||||
|
VarDeclInitializer,
|
||||||
|
VarNameCleaner
|
||||||
|
>();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast)
|
||||||
|
{
|
||||||
|
for (string const& step: _steps)
|
||||||
|
{
|
||||||
|
if (m_debug == Debug::PrintStep)
|
||||||
|
cout << "Running " << step << endl;
|
||||||
|
allSteps().at(step)->run(m_context, _ast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,9 +22,13 @@
|
|||||||
|
|
||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
#include <libyul/YulString.h>
|
#include <libyul/YulString.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
#include <libyul/optimiser/NameDispenser.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -41,6 +45,11 @@ struct Object;
|
|||||||
class OptimiserSuite
|
class OptimiserSuite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class Debug
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
PrintStep
|
||||||
|
};
|
||||||
static void run(
|
static void run(
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
GasMeter const* _meter,
|
GasMeter const* _meter,
|
||||||
@ -48,6 +57,26 @@ public:
|
|||||||
bool _optimizeStackAllocation,
|
bool _optimizeStackAllocation,
|
||||||
std::set<YulString> const& _externallyUsedIdentifiers = {}
|
std::set<YulString> const& _externallyUsedIdentifiers = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void runSequence(std::vector<std::string> const& _steps, Block& _ast);
|
||||||
|
|
||||||
|
static std::map<std::string, std::unique_ptr<OptimiserStep>> const& allSteps();
|
||||||
|
|
||||||
|
private:
|
||||||
|
OptimiserSuite(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
std::set<YulString> const& _externallyUsedIdentifiers,
|
||||||
|
Debug _debug,
|
||||||
|
Block& _ast
|
||||||
|
):
|
||||||
|
m_dispenser{_dialect, _ast, _externallyUsedIdentifiers},
|
||||||
|
m_context{_dialect, m_dispenser, _externallyUsedIdentifiers},
|
||||||
|
m_debug(_debug)
|
||||||
|
{}
|
||||||
|
|
||||||
|
NameDispenser m_dispenser;
|
||||||
|
OptimiserStepContext m_context;
|
||||||
|
Debug m_debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/YulString.h>
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -47,19 +48,11 @@ struct SideEffects;
|
|||||||
class UnusedPruner: public ASTModifier
|
class UnusedPruner: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
UnusedPruner(
|
static constexpr char const* name{"UnusedPruner"};
|
||||||
Dialect const& _dialect,
|
static void run(OptimiserStepContext& _context, Block& _ast) {
|
||||||
Block& _ast,
|
UnusedPruner::runUntilStabilisedOnFullAST(_context.dialect, _ast, _context.reservedIdentifiers);
|
||||||
bool _allowMSizeOptimization,
|
}
|
||||||
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr,
|
|
||||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
|
||||||
);
|
|
||||||
UnusedPruner(
|
|
||||||
Dialect const& _dialect,
|
|
||||||
FunctionDefinition& _function,
|
|
||||||
bool _allowMSizeOptimization,
|
|
||||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
|
||||||
);
|
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
@ -76,6 +69,15 @@ public:
|
|||||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static void run(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
Block& _ast,
|
||||||
|
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
runUntilStabilisedOnFullAST(_dialect, _ast, _externallyUsedFunctions);
|
||||||
|
}
|
||||||
|
|
||||||
/// Run the pruner until the code does not change anymore.
|
/// Run the pruner until the code does not change anymore.
|
||||||
/// The provided block has to be a full AST.
|
/// The provided block has to be a full AST.
|
||||||
/// The pruner itself determines if msize is used and which user-defined functions
|
/// The pruner itself determines if msize is used and which user-defined functions
|
||||||
@ -99,6 +101,20 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
UnusedPruner(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
Block& _ast,
|
||||||
|
bool _allowMSizeOptimization,
|
||||||
|
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr,
|
||||||
|
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||||
|
);
|
||||||
|
UnusedPruner(
|
||||||
|
Dialect const& _dialect,
|
||||||
|
FunctionDefinition& _function,
|
||||||
|
bool _allowMSizeOptimization,
|
||||||
|
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||||
|
);
|
||||||
|
|
||||||
bool used(YulString _name) const;
|
bool used(YulString _name) const;
|
||||||
void subtractReferences(std::map<YulString, size_t> const& _subtrahend);
|
void subtractReferences(std::map<YulString, size_t> const& _subtrahend);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -32,6 +33,9 @@ namespace yul
|
|||||||
class VarDeclInitializer: public ASTModifier
|
class VarDeclInitializer: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr char const* name{"VarDeclInitializer"};
|
||||||
|
static void run(OptimiserStepContext&, Block& _ast) { VarDeclInitializer{}(_ast); }
|
||||||
|
|
||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <libyul/YulString.h>
|
#include <libyul/YulString.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -43,11 +44,11 @@ struct Dialect;
|
|||||||
class VarNameCleaner: public ASTModifier
|
class VarNameCleaner: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VarNameCleaner(
|
static constexpr char const* name{"VarNameCleaner"};
|
||||||
Block const& _ast,
|
static void run(OptimiserStepContext& _context, Block& _ast)
|
||||||
Dialect const& _dialect,
|
{
|
||||||
std::set<YulString> _blacklist = {}
|
VarNameCleaner{_ast, _context.dialect, _context.reservedIdentifiers}(_ast);
|
||||||
);
|
}
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(VariableDeclaration& _varDecl) override;
|
void operator()(VariableDeclaration& _varDecl) override;
|
||||||
@ -55,6 +56,12 @@ public:
|
|||||||
void operator()(FunctionDefinition& _funDef) override;
|
void operator()(FunctionDefinition& _funDef) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
VarNameCleaner(
|
||||||
|
Block const& _ast,
|
||||||
|
Dialect const& _dialect,
|
||||||
|
std::set<YulString> _blacklist = {}
|
||||||
|
);
|
||||||
|
|
||||||
/// Tries to rename a list of variables.
|
/// Tries to rename a list of variables.
|
||||||
void renameVariables(std::vector<TypedName>& _variables);
|
void renameVariables(std::vector<TypedName>& _variables);
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
{
|
{
|
||||||
"smtlib2responses":
|
"smtlib2responses":
|
||||||
{
|
{
|
||||||
"0x047d0c67d7e03c5ac96ca227d1e19ba63257f4ab19cef30029413219ec8963af": "sat\n((|EVALEXPR_0| 0))\n",
|
"0x82fb8ee094f0f56b7a63a74177b54a1710d6fc531d426f288c18f36b76cf6a8b": "sat\n((|EVALEXPR_0| 1))\n",
|
||||||
"0xada7569fb01a9b3e2823517ed40dcc99b11fb1e433e6e3ec8a8713f6f95753d3": "sat\n((|EVALEXPR_0| 1))\n"
|
"0xb524e7c577188e2e36f0e67fead51269fa0f8b8fb41bff2d973dcf584d38cd1e": "sat\n((|EVALEXPR_0| 0))\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
{
|
{
|
||||||
"smtlib2responses":
|
"smtlib2responses":
|
||||||
{
|
{
|
||||||
"0x2e32517a1410b1a16decd448bb9bac7789d7cf1c6f98703ed6bacfcad6abebfb": "sat\n((|EVALEXPR_0| 0))\n"
|
"0x45c37a9829e623d7838d82b547d297cd446d6b5faff36c53a56862fcee50fb41": "sat\n((|EVALEXPR_0| 0))\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,4 @@ contract C {
|
|||||||
function f() internal pure returns (mapping(uint=>uint) storage r) { }
|
function f() internal pure returns (mapping(uint=>uint) storage r) { }
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (53-82): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (53-82): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -2,4 +2,4 @@ contract C {
|
|||||||
function f() internal pure returns (mapping(uint=>uint) storage) {}
|
function f() internal pure returns (mapping(uint=>uint) storage) {}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (53-80): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (53-80): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -7,4 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (87-96): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (87-96): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -45,12 +45,12 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// Warning: (146-151): Unreachable code.
|
// Warning: (146-151): Unreachable code.
|
||||||
// Warning: (169-174): Unreachable code.
|
// Warning: (169-174): Unreachable code.
|
||||||
// TypeError: (223-234): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (223-234): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// Warning: (316-321): Unreachable code.
|
// Warning: (316-321): Unreachable code.
|
||||||
// TypeError: (440-451): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (440-451): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (654-665): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (654-665): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (871-882): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (871-882): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// Warning: (933-938): Unreachable code.
|
// Warning: (933-938): Unreachable code.
|
||||||
|
@ -12,5 +12,5 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (182-193): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (182-193): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -14,5 +14,5 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (96-107): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (96-107): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (186-197): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (186-197): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -18,5 +18,5 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (249-258): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (249-258): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (367-376): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (367-376): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -13,6 +13,6 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (176-187): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (176-187): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (264-275): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (264-275): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -9,5 +9,5 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (96-107): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (96-107): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (200-211): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (200-211): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment.
|
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -6,4 +6,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (92-116): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (92-116): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -5,4 +5,4 @@ contract C {
|
|||||||
function f() m1(b) m2(b = s) internal view returns (uint[] storage b) {}
|
function f() m1(b) m2(b = s) internal view returns (uint[] storage b) {}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (129-130): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (129-130): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -10,4 +10,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (120-121): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (120-121): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -10,4 +10,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (120-121): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (120-121): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -7,4 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (94-95): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (94-95): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (109-110): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (109-110): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -8,9 +8,9 @@ library L {
|
|||||||
function i(uint[] calldata, uint[] storage) external pure returns (S storage x) {return x; }
|
function i(uint[] calldata, uint[] storage) external pure returns (S storage x) {return x; }
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (197-198): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (197-198): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (203-204): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (203-204): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (359-360): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (359-360): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (365-366): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (365-366): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (460-461): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (460-461): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
// TypeError: (557-558): This variable is of storage pointer type and can be accessed without prior assignment.
|
// TypeError: (557-558): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include <libyul/optimiser/ExpressionSimplifier.h>
|
#include <libyul/optimiser/ExpressionSimplifier.h>
|
||||||
#include <libyul/optimiser/UnusedPruner.h>
|
#include <libyul/optimiser/UnusedPruner.h>
|
||||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.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/Semantics.h>
|
||||||
@ -114,21 +115,23 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
return TestResult::FatalError;
|
return TestResult::FatalError;
|
||||||
|
|
||||||
soltestAssert(m_dialect, "Dialect not set.");
|
soltestAssert(m_dialect, "Dialect not set.");
|
||||||
|
|
||||||
|
updateContext();
|
||||||
|
|
||||||
if (m_optimizerStep == "disambiguator")
|
if (m_optimizerStep == "disambiguator")
|
||||||
disambiguate();
|
disambiguate();
|
||||||
else if (m_optimizerStep == "nameDisplacer")
|
else if (m_optimizerStep == "nameDisplacer")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
|
||||||
NameDisplacer{
|
NameDisplacer{
|
||||||
nameDispenser,
|
*m_nameDispenser,
|
||||||
{"illegal1"_yulstring, "illegal2"_yulstring, "illegal3"_yulstring, "illegal4"_yulstring, "illegal5"_yulstring}
|
{"illegal1"_yulstring, "illegal2"_yulstring, "illegal3"_yulstring, "illegal4"_yulstring, "illegal5"_yulstring}
|
||||||
}(*m_ast);
|
}(*m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "blockFlattener")
|
else if (m_optimizerStep == "blockFlattener")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
BlockFlattener{}(*m_ast);
|
BlockFlattener::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "constantOptimiser")
|
else if (m_optimizerStep == "constantOptimiser")
|
||||||
{
|
{
|
||||||
@ -136,193 +139,182 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
ConstantOptimiser{dynamic_cast<EVMDialect const&>(*m_dialect), meter}(*m_ast);
|
ConstantOptimiser{dynamic_cast<EVMDialect const&>(*m_dialect), meter}(*m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "varDeclInitializer")
|
else if (m_optimizerStep == "varDeclInitializer")
|
||||||
VarDeclInitializer{}(*m_ast);
|
VarDeclInitializer::run(*m_context, *m_ast);
|
||||||
else if (m_optimizerStep == "varNameCleaner")
|
else if (m_optimizerStep == "varNameCleaner")
|
||||||
VarNameCleaner{*m_ast, *m_dialect}(*m_ast);
|
VarNameCleaner::run(*m_context, *m_ast);
|
||||||
else if (m_optimizerStep == "forLoopConditionIntoBody")
|
else if (m_optimizerStep == "forLoopConditionIntoBody")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ForLoopConditionIntoBody{*m_dialect}(*m_ast);
|
ForLoopConditionIntoBody::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "forLoopInitRewriter")
|
else if (m_optimizerStep == "forLoopInitRewriter")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ForLoopInitRewriter{}(*m_ast);
|
ForLoopInitRewriter::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "commonSubexpressionEliminator")
|
else if (m_optimizerStep == "commonSubexpressionEliminator")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
CommonSubexpressionEliminator::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "expressionSplitter")
|
else if (m_optimizerStep == "expressionSplitter")
|
||||||
{
|
ExpressionSplitter::run(*m_context, *m_ast);
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
|
||||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
|
||||||
}
|
|
||||||
else if (m_optimizerStep == "expressionJoiner")
|
else if (m_optimizerStep == "expressionJoiner")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "splitJoin")
|
else if (m_optimizerStep == "splitJoin")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
ExpressionSplitter::run(*m_context, *m_ast);
|
||||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
ExpressionJoiner::run(*m_context, *m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_context, *m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "functionGrouper")
|
else if (m_optimizerStep == "functionGrouper")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
(FunctionGrouper{})(*m_ast);
|
FunctionGrouper::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "functionHoister")
|
else if (m_optimizerStep == "functionHoister")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
(FunctionHoister{})(*m_ast);
|
FunctionHoister::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "expressionInliner")
|
else if (m_optimizerStep == "expressionInliner")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ExpressionInliner(*m_dialect, *m_ast).run();
|
ExpressionInliner::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "fullInliner")
|
else if (m_optimizerStep == "fullInliner")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
(FunctionHoister{})(*m_ast);
|
FunctionHoister::run(*m_context, *m_ast);
|
||||||
(FunctionGrouper{})(*m_ast);
|
FunctionGrouper::run(*m_context, *m_ast);
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
ExpressionSplitter::run(*m_context, *m_ast);
|
||||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
FullInliner::run(*m_context, *m_ast);
|
||||||
FullInliner(*m_ast, nameDispenser).run();
|
ExpressionJoiner::run(*m_context, *m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "mainFunction")
|
else if (m_optimizerStep == "mainFunction")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
(FunctionGrouper{})(*m_ast);
|
FunctionGrouper::run(*m_context, *m_ast);
|
||||||
(MainFunction{})(*m_ast);
|
MainFunction::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "rematerialiser")
|
else if (m_optimizerStep == "rematerialiser")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
Rematerialiser::run(*m_dialect, *m_ast);
|
Rematerialiser::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "expressionSimplifier")
|
else if (m_optimizerStep == "expressionSimplifier")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
ExpressionSimplifier::run(*m_context, *m_ast);
|
||||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
ExpressionSimplifier::run(*m_context, *m_ast);
|
||||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
ExpressionSimplifier::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "fullSimplify")
|
else if (m_optimizerStep == "fullSimplify")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
ExpressionSplitter::run(*m_context, *m_ast);
|
||||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
ForLoopInitRewriter::run(*m_context, *m_ast);
|
||||||
ForLoopInitRewriter{}(*m_ast);
|
CommonSubexpressionEliminator::run(*m_context, *m_ast);
|
||||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
ExpressionSimplifier::run(*m_context, *m_ast);
|
||||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
UnusedPruner::run(*m_context, *m_ast);
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast);
|
DeadCodeEliminator::run(*m_context, *m_ast);
|
||||||
DeadCodeEliminator{*m_dialect}(*m_ast);
|
ExpressionJoiner::run(*m_context, *m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_context, *m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "unusedPruner")
|
else if (m_optimizerStep == "unusedPruner")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast);
|
UnusedPruner::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "deadCodeEliminator")
|
else if (m_optimizerStep == "deadCodeEliminator")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ForLoopInitRewriter{}(*m_ast);
|
ForLoopInitRewriter::run(*m_context, *m_ast);
|
||||||
DeadCodeEliminator{*m_dialect}(*m_ast);
|
DeadCodeEliminator::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "ssaTransform")
|
else if (m_optimizerStep == "ssaTransform")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
SSATransform::run(*m_context, *m_ast);
|
||||||
SSATransform::run(*m_ast, nameDispenser);
|
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "redundantAssignEliminator")
|
else if (m_optimizerStep == "redundantAssignEliminator")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
RedundantAssignEliminator::run(*m_dialect, *m_ast);
|
RedundantAssignEliminator::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "ssaPlusCleanup")
|
else if (m_optimizerStep == "ssaPlusCleanup")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
SSATransform::run(*m_context, *m_ast);
|
||||||
SSATransform::run(*m_ast, nameDispenser);
|
RedundantAssignEliminator::run(*m_context, *m_ast);
|
||||||
RedundantAssignEliminator::run(*m_dialect, *m_ast);
|
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "loadResolver")
|
else if (m_optimizerStep == "loadResolver")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ForLoopInitRewriter{}(*m_ast);
|
ForLoopInitRewriter::run(*m_context, *m_ast);
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
ExpressionSplitter::run(*m_context, *m_ast);
|
||||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
CommonSubexpressionEliminator::run(*m_context, *m_ast);
|
||||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
ExpressionSimplifier::run(*m_context, *m_ast);
|
||||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
|
||||||
|
|
||||||
LoadResolver::run(*m_dialect, *m_ast);
|
LoadResolver::run(*m_context, *m_ast);
|
||||||
|
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast);
|
UnusedPruner::run(*m_context, *m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_context, *m_ast);
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "controlFlowSimplifier")
|
else if (m_optimizerStep == "controlFlowSimplifier")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ControlFlowSimplifier{*m_dialect}(*m_ast);
|
ControlFlowSimplifier::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "structuralSimplifier")
|
else if (m_optimizerStep == "structuralSimplifier")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
ForLoopInitRewriter{}(*m_ast);
|
ForLoopInitRewriter::run(*m_context, *m_ast);
|
||||||
LiteralRematerialiser{*m_dialect}(*m_ast);
|
LiteralRematerialiser::run(*m_context, *m_ast);
|
||||||
StructuralSimplifier{}(*m_ast);
|
StructuralSimplifier::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "equivalentFunctionCombiner")
|
else if (m_optimizerStep == "equivalentFunctionCombiner")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
EquivalentFunctionCombiner::run(*m_ast);
|
EquivalentFunctionCombiner::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "ssaReverser")
|
else if (m_optimizerStep == "ssaReverser")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
SSAReverser::run(*m_ast);
|
SSAReverser::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "ssaAndBack")
|
else if (m_optimizerStep == "ssaAndBack")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
// apply SSA
|
// apply SSA
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
SSATransform::run(*m_context, *m_ast);
|
||||||
SSATransform::run(*m_ast, nameDispenser);
|
RedundantAssignEliminator::run(*m_context, *m_ast);
|
||||||
RedundantAssignEliminator::run(*m_dialect, *m_ast);
|
|
||||||
// reverse SSA
|
// reverse SSA
|
||||||
SSAReverser::run(*m_ast);
|
SSAReverser::run(*m_context, *m_ast);
|
||||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
CommonSubexpressionEliminator::run(*m_context, *m_ast);
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast);
|
UnusedPruner::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "stackCompressor")
|
else if (m_optimizerStep == "stackCompressor")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
(FunctionGrouper{})(*m_ast);
|
FunctionGrouper::run(*m_context, *m_ast);
|
||||||
size_t maxIterations = 16;
|
size_t maxIterations = 16;
|
||||||
Object obj;
|
Object obj;
|
||||||
obj.code = m_ast;
|
obj.code = m_ast;
|
||||||
StackCompressor::run(*m_dialect, obj, true, maxIterations);
|
StackCompressor::run(*m_dialect, obj, true, maxIterations);
|
||||||
m_ast = obj.code;
|
m_ast = obj.code;
|
||||||
(BlockFlattener{})(*m_ast);
|
BlockFlattener::run(*m_context, *m_ast);
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "wordSizeTransform")
|
else if (m_optimizerStep == "wordSizeTransform")
|
||||||
{
|
{
|
||||||
disambiguate();
|
disambiguate();
|
||||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
ExpressionSplitter::run(*m_context, *m_ast);
|
||||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
WordSizeTransform::run(*m_dialect, *m_ast, *m_nameDispenser);
|
||||||
WordSizeTransform::run(*m_dialect, *m_ast, nameDispenser);
|
|
||||||
}
|
}
|
||||||
else if (m_optimizerStep == "fullSuite")
|
else if (m_optimizerStep == "fullSuite")
|
||||||
{
|
{
|
||||||
@ -413,6 +405,13 @@ void YulOptimizerTest::disambiguate()
|
|||||||
{
|
{
|
||||||
*m_ast = boost::get<Block>(Disambiguator(*m_dialect, *m_analysisInfo)(*m_ast));
|
*m_ast = boost::get<Block>(Disambiguator(*m_dialect, *m_analysisInfo)(*m_ast));
|
||||||
m_analysisInfo.reset();
|
m_analysisInfo.reset();
|
||||||
|
updateContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void YulOptimizerTest::updateContext()
|
||||||
|
{
|
||||||
|
m_nameDispenser = make_unique<NameDispenser>(*m_dialect, *m_ast, m_reservedIdentifiers);
|
||||||
|
m_context = unique_ptr<OptimiserStepContext>(new OptimiserStepContext{*m_dialect, *m_nameDispenser, m_reservedIdentifiers});
|
||||||
}
|
}
|
||||||
|
|
||||||
void YulOptimizerTest::printErrors(ostream& _stream, ErrorList const& _errors)
|
void YulOptimizerTest::printErrors(ostream& _stream, ErrorList const& _errors)
|
||||||
|
@ -19,6 +19,14 @@
|
|||||||
|
|
||||||
#include <test/TestCase.h>
|
#include <test/TestCase.h>
|
||||||
|
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
#include <libyul/optimiser/NameDispenser.h>
|
||||||
|
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace langutil
|
namespace langutil
|
||||||
{
|
{
|
||||||
class Scanner;
|
class Scanner;
|
||||||
@ -58,6 +66,7 @@ private:
|
|||||||
void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const;
|
void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const;
|
||||||
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
|
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
|
||||||
void disambiguate();
|
void disambiguate();
|
||||||
|
void updateContext();
|
||||||
|
|
||||||
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
|
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
|
||||||
|
|
||||||
@ -67,6 +76,10 @@ private:
|
|||||||
std::string m_expectation;
|
std::string m_expectation;
|
||||||
|
|
||||||
Dialect const* m_dialect = nullptr;
|
Dialect const* m_dialect = nullptr;
|
||||||
|
std::set<YulString> m_reservedIdentifiers;
|
||||||
|
std::unique_ptr<NameDispenser> m_nameDispenser;
|
||||||
|
std::unique_ptr<OptimiserStepContext> m_context;
|
||||||
|
|
||||||
std::shared_ptr<Block> m_ast;
|
std::shared_ptr<Block> m_ast;
|
||||||
std::shared_ptr<AsmAnalysisInfo> m_analysisInfo;
|
std::shared_ptr<AsmAnalysisInfo> m_analysisInfo;
|
||||||
std::string m_obtainedResult;
|
std::string m_obtainedResult;
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include <libyul/optimiser/UnusedPruner.h>
|
#include <libyul/optimiser/UnusedPruner.h>
|
||||||
#include <libyul/optimiser/DeadCodeEliminator.h>
|
#include <libyul/optimiser/DeadCodeEliminator.h>
|
||||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
||||||
#include <libyul/optimiser/SSAReverser.h>
|
#include <libyul/optimiser/SSAReverser.h>
|
||||||
#include <libyul/optimiser/SSATransform.h>
|
#include <libyul/optimiser/SSATransform.h>
|
||||||
@ -126,11 +127,12 @@ public:
|
|||||||
cout << source << endl;
|
cout << source << endl;
|
||||||
if (!parse(source))
|
if (!parse(source))
|
||||||
return;
|
return;
|
||||||
|
set<YulString> reservedIdentifiers;
|
||||||
if (!disambiguated)
|
if (!disambiguated)
|
||||||
{
|
{
|
||||||
*m_ast = boost::get<yul::Block>(Disambiguator(m_dialect, *m_analysisInfo)(*m_ast));
|
*m_ast = boost::get<yul::Block>(Disambiguator(m_dialect, *m_analysisInfo)(*m_ast));
|
||||||
m_analysisInfo.reset();
|
m_analysisInfo.reset();
|
||||||
m_nameDispenser = make_shared<NameDispenser>(m_dialect, *m_ast);
|
m_nameDispenser = make_shared<NameDispenser>(m_dialect, *m_ast, reservedIdentifiers);
|
||||||
disambiguated = true;
|
disambiguated = true;
|
||||||
}
|
}
|
||||||
cout << "(q)quit/(f)flatten/(c)se/initialize var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl;
|
cout << "(q)quit/(f)flatten/(c)se/initialize var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl;
|
||||||
@ -141,78 +143,83 @@ public:
|
|||||||
cout.flush();
|
cout.flush();
|
||||||
int option = readStandardInputChar();
|
int option = readStandardInputChar();
|
||||||
cout << ' ' << char(option) << endl;
|
cout << ' ' << char(option) << endl;
|
||||||
|
|
||||||
|
OptimiserStepContext context{m_dialect, *m_nameDispenser, reservedIdentifiers};
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
case 'q':
|
case 'q':
|
||||||
return;
|
return;
|
||||||
case 'f':
|
case 'f':
|
||||||
BlockFlattener{}(*m_ast);
|
BlockFlattener::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
ForLoopInitRewriter{}(*m_ast);
|
ForLoopInitRewriter::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
ForLoopConditionOutOfBody{m_dialect}(*m_ast);
|
ForLoopConditionOutOfBody::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
ForLoopConditionIntoBody{m_dialect}(*m_ast);
|
ForLoopConditionIntoBody::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
CommonSubexpressionEliminator::run(m_dialect, *m_ast);
|
CommonSubexpressionEliminator::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
(VarDeclInitializer{})(*m_ast);
|
VarDeclInitializer::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
VarNameCleaner{*m_ast, m_dialect}(*m_ast);
|
VarNameCleaner::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
ExpressionSplitter{m_dialect, *m_nameDispenser}(*m_ast);
|
ExpressionSplitter::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
ExpressionJoiner::run(*m_ast);
|
ExpressionJoiner::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
(FunctionGrouper{})(*m_ast);
|
FunctionGrouper::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
(FunctionHoister{})(*m_ast);
|
FunctionHoister::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
ExpressionInliner{m_dialect, *m_ast}.run();
|
ExpressionInliner::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
FullInliner(*m_ast, *m_nameDispenser).run();
|
FullInliner::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
ExpressionSimplifier::run(m_dialect, *m_ast);
|
ExpressionSimplifier::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
StructuralSimplifier{}(*m_ast);
|
StructuralSimplifier::run(context, *m_ast);
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
LiteralRematerialiser::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
(ControlFlowSimplifier{m_dialect})(*m_ast);
|
ControlFlowSimplifier::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(m_dialect, *m_ast);
|
UnusedPruner::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
DeadCodeEliminator{m_dialect}(*m_ast);
|
DeadCodeEliminator::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
SSATransform::run(*m_ast, *m_nameDispenser);
|
SSATransform::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
RedundantAssignEliminator::run(m_dialect, *m_ast);
|
RedundantAssignEliminator::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
Rematerialiser::run(m_dialect, *m_ast);
|
Rematerialiser::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
EquivalentFunctionCombiner::run(*m_ast);
|
EquivalentFunctionCombiner::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
SSAReverser::run(*m_ast);
|
SSAReverser::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
{
|
{
|
||||||
@ -222,7 +229,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'L':
|
case 'L':
|
||||||
LoadResolver::run(m_dialect, *m_ast);
|
LoadResolver::run(context, *m_ast);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cout << "Unknown option." << endl;
|
cout << "Unknown option." << endl;
|
||||||
|
Loading…
Reference in New Issue
Block a user