mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Side-effects of user-defined functions.
This commit is contained in:
parent
9a6357ab09
commit
1c5845e3f2
@ -23,6 +23,9 @@
|
||||
|
||||
#include <libyul/optimiser/Metrics.h>
|
||||
#include <libyul/optimiser/SyntacticalEquality.h>
|
||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/SideEffects.h>
|
||||
#include <libyul/Exceptions.h>
|
||||
#include <libyul/AsmData.h>
|
||||
#include <libyul/Dialect.h>
|
||||
@ -31,6 +34,23 @@ using namespace std;
|
||||
using namespace dev;
|
||||
using namespace yul;
|
||||
|
||||
void CommonSubexpressionEliminator::run(Dialect const& _dialect, Block& _ast)
|
||||
{
|
||||
CommonSubexpressionEliminator cse{
|
||||
_dialect,
|
||||
SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast))
|
||||
};
|
||||
cse(_ast);
|
||||
}
|
||||
|
||||
CommonSubexpressionEliminator::CommonSubexpressionEliminator(
|
||||
Dialect const& _dialect,
|
||||
map<YulString, SideEffects> _functionSideEffects
|
||||
):
|
||||
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects))
|
||||
{
|
||||
}
|
||||
|
||||
void CommonSubexpressionEliminator::visit(Expression& _e)
|
||||
{
|
||||
bool descend = true;
|
||||
|
@ -27,6 +27,7 @@ namespace yul
|
||||
{
|
||||
|
||||
struct Dialect;
|
||||
struct SideEffects;
|
||||
|
||||
/**
|
||||
* Optimisation stage that replaces expressions known to be the current value of a variable
|
||||
@ -37,7 +38,14 @@ struct Dialect;
|
||||
class CommonSubexpressionEliminator: public DataFlowAnalyzer
|
||||
{
|
||||
public:
|
||||
CommonSubexpressionEliminator(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
|
||||
/// Runs the CSE pass. @a _ast needs to be the complete AST of the program!
|
||||
static void run(Dialect const& _dialect, Block& _ast);
|
||||
|
||||
private:
|
||||
CommonSubexpressionEliminator(
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, SideEffects> _functionSideEffects
|
||||
);
|
||||
|
||||
protected:
|
||||
using ASTModifier::visit;
|
||||
|
@ -211,7 +211,7 @@ void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expres
|
||||
{
|
||||
clearValues(_variables);
|
||||
|
||||
MovableChecker movableChecker{m_dialect};
|
||||
MovableChecker movableChecker{m_dialect, &m_functionSideEffects};
|
||||
if (_value)
|
||||
movableChecker.visit(*_value);
|
||||
else
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <libyul/optimiser/KnowledgeBase.h>
|
||||
#include <libyul/YulString.h>
|
||||
#include <libyul/AsmData.h>
|
||||
#include <libyul/SideEffects.h>
|
||||
|
||||
// TODO avoid
|
||||
#include <libevmasm/Instruction.h>
|
||||
@ -38,6 +39,7 @@
|
||||
namespace yul
|
||||
{
|
||||
struct Dialect;
|
||||
struct SideEffects;
|
||||
|
||||
/**
|
||||
* Base class to perform data flow analysis during AST walks.
|
||||
@ -67,8 +69,16 @@ struct Dialect;
|
||||
class DataFlowAnalyzer: public ASTModifier
|
||||
{
|
||||
public:
|
||||
explicit DataFlowAnalyzer(Dialect const& _dialect):
|
||||
/// @param _functionSideEffects
|
||||
/// Side-effects of user-defined functions. Worst-case side-effects are assumed
|
||||
/// if this is not provided or the function is not found.
|
||||
/// The parameter is mostly used to determine movability of expressions.
|
||||
explicit DataFlowAnalyzer(
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, SideEffects> _functionSideEffects = {}
|
||||
):
|
||||
m_dialect(_dialect),
|
||||
m_functionSideEffects(std::move(_functionSideEffects)),
|
||||
m_knowledgeBase(_dialect, m_value)
|
||||
{}
|
||||
|
||||
@ -124,6 +134,9 @@ protected:
|
||||
) const;
|
||||
|
||||
Dialect const& m_dialect;
|
||||
/// Side-effects of user-defined functions. Worst-case side-effects are assumed
|
||||
/// if this is not provided or the function is not found.
|
||||
std::map<YulString, SideEffects> m_functionSideEffects;
|
||||
|
||||
/// Current values of variables, always movable.
|
||||
std::map<YulString, Expression const*> m_value;
|
||||
|
@ -64,8 +64,11 @@ void SideEffectsCollector::operator()(FunctionCall const& _functionCall)
|
||||
{
|
||||
ASTWalker::operator()(_functionCall);
|
||||
|
||||
if (BuiltinFunction const* f = m_dialect.builtin(_functionCall.functionName.name))
|
||||
YulString functionName = _functionCall.functionName.name;
|
||||
if (BuiltinFunction const* f = m_dialect.builtin(functionName))
|
||||
m_sideEffects += f->sideEffects;
|
||||
else if (m_functionSideEffects && m_functionSideEffects->count(functionName))
|
||||
m_sideEffects += m_functionSideEffects->at(functionName);
|
||||
else
|
||||
m_sideEffects += SideEffects::worst();
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/SideEffects.h>
|
||||
#include <libyul/AsmData.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
@ -36,7 +37,10 @@ struct Dialect;
|
||||
class SideEffectsCollector: public ASTWalker
|
||||
{
|
||||
public:
|
||||
explicit SideEffectsCollector(Dialect const& _dialect): m_dialect(_dialect) {}
|
||||
explicit SideEffectsCollector(
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
|
||||
): m_dialect(_dialect), m_functionSideEffects(_functionSideEffects) {}
|
||||
SideEffectsCollector(Dialect const& _dialect, Expression const& _expression);
|
||||
SideEffectsCollector(Dialect const& _dialect, Statement const& _statement);
|
||||
SideEffectsCollector(Dialect const& _dialect, Block const& _ast);
|
||||
@ -59,6 +63,7 @@ public:
|
||||
|
||||
private:
|
||||
Dialect const& m_dialect;
|
||||
std::map<YulString, SideEffects> const* m_functionSideEffects = nullptr;
|
||||
SideEffects m_sideEffects;
|
||||
};
|
||||
|
||||
@ -108,7 +113,10 @@ private:
|
||||
class MovableChecker: public SideEffectsCollector
|
||||
{
|
||||
public:
|
||||
explicit MovableChecker(Dialect const& _dialect): SideEffectsCollector(_dialect) {}
|
||||
explicit MovableChecker(
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
|
||||
): SideEffectsCollector(_dialect, _functionSideEffects) {}
|
||||
MovableChecker(Dialect const& _dialect, Expression const& _expression);
|
||||
|
||||
void operator()(Identifier const& _identifier) override;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <libyul/optimiser/Disambiguator.h>
|
||||
#include <libyul/optimiser/VarDeclInitializer.h>
|
||||
#include <libyul/optimiser/BlockFlattener.h>
|
||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
||||
#include <libyul/optimiser/DeadCodeEliminator.h>
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
@ -37,6 +38,7 @@
|
||||
#include <libyul/optimiser/UnusedPruner.h>
|
||||
#include <libyul/optimiser/ExpressionSimplifier.h>
|
||||
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/optimiser/SSAReverser.h>
|
||||
#include <libyul/optimiser/SSATransform.h>
|
||||
#include <libyul/optimiser/StackCompressor.h>
|
||||
@ -114,7 +116,8 @@ void OptimiserSuite::run(
|
||||
RedundantAssignEliminator::run(_dialect, ast);
|
||||
|
||||
ExpressionSimplifier::run(_dialect, ast);
|
||||
CommonSubexpressionEliminator{_dialect}(ast);
|
||||
|
||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||
}
|
||||
|
||||
{
|
||||
@ -126,16 +129,17 @@ void OptimiserSuite::run(
|
||||
DeadCodeEliminator{_dialect}(ast);
|
||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
||||
}
|
||||
|
||||
{
|
||||
// simplify again
|
||||
CommonSubexpressionEliminator{_dialect}(ast);
|
||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
||||
}
|
||||
|
||||
{
|
||||
// reverse SSA
|
||||
SSAReverser::run(ast);
|
||||
CommonSubexpressionEliminator{_dialect}(ast);
|
||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
||||
|
||||
ExpressionJoiner::run(ast);
|
||||
@ -156,7 +160,7 @@ void OptimiserSuite::run(
|
||||
SSATransform::run(ast, dispenser);
|
||||
RedundantAssignEliminator::run(_dialect, ast);
|
||||
RedundantAssignEliminator::run(_dialect, ast);
|
||||
CommonSubexpressionEliminator{_dialect}(ast);
|
||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||
}
|
||||
|
||||
{
|
||||
@ -177,12 +181,12 @@ void OptimiserSuite::run(
|
||||
BlockFlattener{}(ast);
|
||||
DeadCodeEliminator{_dialect}(ast);
|
||||
ControlFlowSimplifier{_dialect}(ast);
|
||||
CommonSubexpressionEliminator{_dialect}(ast);
|
||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||
SSATransform::run(ast, dispenser);
|
||||
RedundantAssignEliminator::run(_dialect, ast);
|
||||
RedundantAssignEliminator::run(_dialect, ast);
|
||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
||||
CommonSubexpressionEliminator{_dialect}(ast);
|
||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,7 +201,7 @@ void OptimiserSuite::run(
|
||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
||||
|
||||
SSAReverser::run(ast);
|
||||
CommonSubexpressionEliminator{_dialect}(ast);
|
||||
CommonSubexpressionEliminator::run(_dialect, ast);
|
||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
||||
|
||||
ExpressionJoiner::run(ast);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <libyul/optimiser/ControlFlowSimplifier.h>
|
||||
#include <libyul/optimiser/DeadCodeEliminator.h>
|
||||
#include <libyul/optimiser/Disambiguator.h>
|
||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
||||
#include <libyul/optimiser/NameCollector.h>
|
||||
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
||||
@ -45,6 +46,7 @@
|
||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||
#include <libyul/optimiser/SSAReverser.h>
|
||||
#include <libyul/optimiser/SSATransform.h>
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
||||
#include <libyul/optimiser/StructuralSimplifier.h>
|
||||
#include <libyul/optimiser/StackCompressor.h>
|
||||
@ -149,7 +151,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
||||
else if (m_optimizerStep == "commonSubexpressionEliminator")
|
||||
{
|
||||
disambiguate();
|
||||
(CommonSubexpressionEliminator{*m_dialect})(*m_ast);
|
||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
||||
}
|
||||
else if (m_optimizerStep == "expressionSplitter")
|
||||
{
|
||||
@ -218,7 +220,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
||||
ForLoopInitRewriter{}(*m_ast);
|
||||
CommonSubexpressionEliminator{*m_dialect}(*m_ast);
|
||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
||||
UnusedPruner::runUntilStabilised(*m_dialect, *m_ast);
|
||||
DeadCodeEliminator{*m_dialect}(*m_ast);
|
||||
@ -260,7 +262,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
||||
ForLoopInitRewriter{}(*m_ast);
|
||||
NameDispenser nameDispenser{*m_dialect, *m_ast};
|
||||
ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast);
|
||||
CommonSubexpressionEliminator{*m_dialect}(*m_ast);
|
||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
||||
|
||||
LoadResolver::run(*m_dialect, *m_ast);
|
||||
@ -298,7 +300,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
||||
RedundantAssignEliminator::run(*m_dialect, *m_ast);
|
||||
// reverse SSA
|
||||
SSAReverser::run(*m_ast);
|
||||
CommonSubexpressionEliminator{*m_dialect}(*m_ast);
|
||||
CommonSubexpressionEliminator::run(*m_dialect, *m_ast);
|
||||
UnusedPruner::runUntilStabilised(*m_dialect, *m_ast);
|
||||
}
|
||||
else if (m_optimizerStep == "stackCompressor")
|
||||
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
function double(x) -> y { y := add(x, x) }
|
||||
function double_with_se(x) -> y { y := add(x, x) mstore(40, 4) }
|
||||
let i := mload(3)
|
||||
let a := double(i)
|
||||
let b := double(i)
|
||||
let c := double_with_se(i)
|
||||
let d := double_with_se(i)
|
||||
}
|
||||
// ====
|
||||
// step: commonSubexpressionEliminator
|
||||
// ----
|
||||
// {
|
||||
// function double(x) -> y
|
||||
// { y := add(x, x) }
|
||||
// function double_with_se(x_1) -> y_2
|
||||
// {
|
||||
// y_2 := add(x_1, x_1)
|
||||
// mstore(40, 4)
|
||||
// }
|
||||
// let i := mload(3)
|
||||
// let a := double(i)
|
||||
// let b := a
|
||||
// let c := double_with_se(i)
|
||||
// let d := double_with_se(i)
|
||||
// }
|
@ -151,7 +151,7 @@ public:
|
||||
ForLoopConditionIntoBody{}(*m_ast);
|
||||
break;
|
||||
case 'c':
|
||||
(CommonSubexpressionEliminator{m_dialect})(*m_ast);
|
||||
CommonSubexpressionEliminator::run(m_dialect, *m_ast);
|
||||
break;
|
||||
case 'd':
|
||||
(VarDeclInitializer{})(*m_ast);
|
||||
|
Loading…
Reference in New Issue
Block a user