mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow msize optimization only if it is not present.
This commit is contained in:
parent
afe887adc1
commit
d7b5ea6761
@ -55,7 +55,7 @@ void ExpressionInliner::visit(Expression& _expression)
|
||||
|
||||
bool movable = boost::algorithm::all_of(
|
||||
funCall.arguments,
|
||||
[=](Expression const& _arg) { return MovableChecker(m_dialect, _arg).movable(); }
|
||||
[=](Expression const& _arg) { return SideEffectsCollector(m_dialect, _arg).movable(); }
|
||||
);
|
||||
if (m_inlinableFunctions.count(funCall.functionName.name) && movable)
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ void ExpressionSimplifier::visit(Expression& _expression)
|
||||
// so if the value of the variable is not movable, the expression that references
|
||||
// the variable still is.
|
||||
|
||||
if (match->removesNonConstants && !MovableChecker(m_dialect, _expression).movable())
|
||||
if (match->removesNonConstants && !SideEffectsCollector(m_dialect, _expression).movable())
|
||||
return;
|
||||
_expression = match->action().toExpression(locationOf(_expression));
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ void RedundantAssignEliminator::finalize(
|
||||
{
|
||||
State const state = assignment.second == State::Undecided ? _finalState : assignment.second;
|
||||
|
||||
if (state == State::Unused && MovableChecker{*m_dialect, *assignment.first->value}.movable())
|
||||
if (state == State::Unused && SideEffectsCollector{*m_dialect, *assignment.first->value}.movable())
|
||||
// TODO the only point where we actually need this
|
||||
// to be a set is for the for loop
|
||||
m_pendingRemovals.insert(assignment.first);
|
||||
|
@ -45,7 +45,13 @@ public:
|
||||
void operator()(FunctionCall const& _functionCall) override;
|
||||
|
||||
bool movable() const { return m_movable; }
|
||||
bool sideEffectFree() const { return m_sideEffectFree; }
|
||||
bool sideEffectFree(bool _allowMSizeModification = false) const
|
||||
{
|
||||
if (_allowMSizeModification)
|
||||
return sideEffectFreeIfNoMSize();
|
||||
else
|
||||
return m_sideEffectFree;
|
||||
}
|
||||
bool sideEffectFreeIfNoMSize() const { return m_sideEffectFreeIfNoMSize; }
|
||||
bool containsMSize() const { return m_containsMSize; }
|
||||
|
||||
|
@ -187,7 +187,7 @@ bool Pattern::matches(
|
||||
assertThrow(firstMatch, OptimizerException, "Match set but to null.");
|
||||
return
|
||||
SyntacticallyEqual{}(*firstMatch, _expr) &&
|
||||
MovableChecker(_dialect, _expr).movable();
|
||||
SideEffectsCollector(_dialect, _expr).movable();
|
||||
}
|
||||
else if (m_kind == PatternKind::Any)
|
||||
(*m_matchGroups)[m_matchGroup] = &_expr;
|
||||
|
@ -113,7 +113,12 @@ public:
|
||||
};
|
||||
|
||||
template <typename ASTNode>
|
||||
void eliminateVariables(Dialect const& _dialect, ASTNode& _node, size_t _numVariables)
|
||||
void eliminateVariables(
|
||||
Dialect const& _dialect,
|
||||
ASTNode& _node,
|
||||
size_t _numVariables,
|
||||
bool _allowMSizeOptimization
|
||||
)
|
||||
{
|
||||
RematCandidateSelector selector{_dialect};
|
||||
selector(_node);
|
||||
@ -143,7 +148,7 @@ void eliminateVariables(Dialect const& _dialect, ASTNode& _node, size_t _numVari
|
||||
}
|
||||
|
||||
Rematerialiser::run(_dialect, _node, std::move(varsToEliminate));
|
||||
UnusedPruner::runUntilStabilised(_dialect, _node);
|
||||
UnusedPruner::runUntilStabilised(_dialect, _node, _allowMSizeOptimization);
|
||||
}
|
||||
|
||||
}
|
||||
@ -159,6 +164,7 @@ bool StackCompressor::run(
|
||||
_ast.statements.size() > 0 && _ast.statements.at(0).type() == typeid(Block),
|
||||
"Need to run the function grouper before the stack compressor."
|
||||
);
|
||||
bool allowMSizeOptimzation = !SideEffectsCollector(_dialect, _ast).containsMSize();
|
||||
for (size_t iterations = 0; iterations < _maxIterations; iterations++)
|
||||
{
|
||||
map<YulString, int> stackSurplus = CompilabilityChecker::run(_dialect, _ast, _optimizeStackAllocation);
|
||||
@ -168,7 +174,12 @@ bool StackCompressor::run(
|
||||
if (stackSurplus.count(YulString{}))
|
||||
{
|
||||
yulAssert(stackSurplus.at({}) > 0, "Invalid surplus value.");
|
||||
eliminateVariables(_dialect, boost::get<Block>(_ast.statements.at(0)), stackSurplus.at({}));
|
||||
eliminateVariables(
|
||||
_dialect,
|
||||
boost::get<Block>(_ast.statements.at(0)),
|
||||
stackSurplus.at({}),
|
||||
allowMSizeOptimzation
|
||||
);
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < _ast.statements.size(); ++i)
|
||||
@ -178,7 +189,12 @@ bool StackCompressor::run(
|
||||
continue;
|
||||
|
||||
yulAssert(stackSurplus.at(fun.name) > 0, "Invalid surplus value.");
|
||||
eliminateVariables(_dialect, fun, stackSurplus.at(fun.name));
|
||||
eliminateVariables(
|
||||
_dialect,
|
||||
fun,
|
||||
stackSurplus.at(fun.name),
|
||||
allowMSizeOptimzation
|
||||
);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -32,16 +32,28 @@ using namespace std;
|
||||
using namespace dev;
|
||||
using namespace yul;
|
||||
|
||||
UnusedPruner::UnusedPruner(Dialect const& _dialect, Block& _ast, set<YulString> const& _externallyUsedFunctions):
|
||||
m_dialect(_dialect)
|
||||
UnusedPruner::UnusedPruner(
|
||||
Dialect const& _dialect,
|
||||
Block& _ast,
|
||||
bool _allowMSizeOptimization,
|
||||
set<YulString> const& _externallyUsedFunctions
|
||||
):
|
||||
m_dialect(_dialect),
|
||||
m_allowMSizeOptimization(_allowMSizeOptimization)
|
||||
{
|
||||
m_references = ReferencesCounter::countReferences(_ast);
|
||||
for (auto const& f: _externallyUsedFunctions)
|
||||
++m_references[f];
|
||||
}
|
||||
|
||||
UnusedPruner::UnusedPruner(Dialect const& _dialect, FunctionDefinition& _function, set<YulString> const& _externallyUsedFunctions):
|
||||
m_dialect(_dialect)
|
||||
UnusedPruner::UnusedPruner(
|
||||
Dialect const& _dialect,
|
||||
FunctionDefinition& _function,
|
||||
bool _allowMSizeOptimization,
|
||||
set<YulString> const& _externallyUsedFunctions
|
||||
):
|
||||
m_dialect(_dialect),
|
||||
m_allowMSizeOptimization(_allowMSizeOptimization)
|
||||
{
|
||||
m_references = ReferencesCounter::countReferences(_function);
|
||||
for (auto const& f: _externallyUsedFunctions)
|
||||
@ -75,7 +87,7 @@ void UnusedPruner::operator()(Block& _block)
|
||||
{
|
||||
if (!varDecl.value)
|
||||
statement = Block{std::move(varDecl.location), {}};
|
||||
else if (MovableChecker(m_dialect, *varDecl.value).sideEffectFree())
|
||||
else if (SideEffectsCollector(m_dialect, *varDecl.value).sideEffectFree(m_allowMSizeOptimization))
|
||||
{
|
||||
subtractReferences(ReferencesCounter::countReferences(*varDecl.value));
|
||||
statement = Block{std::move(varDecl.location), {}};
|
||||
@ -93,7 +105,7 @@ void UnusedPruner::operator()(Block& _block)
|
||||
else if (statement.type() == typeid(ExpressionStatement))
|
||||
{
|
||||
ExpressionStatement& exprStmt = boost::get<ExpressionStatement>(statement);
|
||||
if (MovableChecker(m_dialect, exprStmt.expression).sideEffectFree())
|
||||
if (SideEffectsCollector(m_dialect, exprStmt.expression).sideEffectFree(m_allowMSizeOptimization))
|
||||
{
|
||||
subtractReferences(ReferencesCounter::countReferences(exprStmt.expression));
|
||||
statement = Block{std::move(exprStmt.location), {}};
|
||||
@ -108,27 +120,41 @@ void UnusedPruner::operator()(Block& _block)
|
||||
void UnusedPruner::runUntilStabilised(
|
||||
Dialect const& _dialect,
|
||||
Block& _ast,
|
||||
bool _allowMSizeOptization,
|
||||
set<YulString> const& _externallyUsedFunctions
|
||||
)
|
||||
{
|
||||
_allowMSizeOptization = !SideEffectsCollector(_dialect, _ast).containsMSize();
|
||||
|
||||
while (true)
|
||||
{
|
||||
UnusedPruner pruner(_dialect, _ast, _externallyUsedFunctions);
|
||||
UnusedPruner pruner(_dialect, _ast, _allowMSizeOptization, _externallyUsedFunctions);
|
||||
pruner(_ast);
|
||||
if (!pruner.shouldRunAgain())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void UnusedPruner::runUntilStabilised(
|
||||
Dialect const& _dialect,
|
||||
Block& _ast,
|
||||
set<YulString> const& _externallyUsedFunctions
|
||||
)
|
||||
{
|
||||
bool allowMSizeOptimization = !SideEffectsCollector(_dialect, _ast).containsMSize();
|
||||
runUntilStabilised(_dialect, _ast, allowMSizeOptimization, _externallyUsedFunctions);
|
||||
}
|
||||
|
||||
void UnusedPruner::runUntilStabilised(
|
||||
Dialect const& _dialect,
|
||||
FunctionDefinition& _function,
|
||||
bool _allowMSizeOptimization,
|
||||
set<YulString> const& _externallyUsedFunctions
|
||||
)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
UnusedPruner pruner(_dialect, _function, _externallyUsedFunctions);
|
||||
UnusedPruner pruner(_dialect, _function, _allowMSizeOptimization, _externallyUsedFunctions);
|
||||
pruner(_function);
|
||||
if (!pruner.shouldRunAgain())
|
||||
return;
|
||||
|
@ -44,11 +44,13 @@ public:
|
||||
UnusedPruner(
|
||||
Dialect const& _dialect,
|
||||
Block& _ast,
|
||||
bool _allowMSizeOptimization,
|
||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||
);
|
||||
UnusedPruner(
|
||||
Dialect const& _dialect,
|
||||
FunctionDefinition& _function,
|
||||
bool _allowMSizeOptimization,
|
||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||
);
|
||||
|
||||
@ -59,6 +61,13 @@ public:
|
||||
bool shouldRunAgain() const { return m_shouldRunAgain; }
|
||||
|
||||
// Run the pruner until the code does not change anymore.
|
||||
static void runUntilStabilised(
|
||||
Dialect const& _dialect,
|
||||
Block& _ast,
|
||||
bool _allowMSizeOptization,
|
||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||
);
|
||||
|
||||
static void runUntilStabilised(
|
||||
Dialect const& _dialect,
|
||||
Block& _ast,
|
||||
@ -67,9 +76,13 @@ public:
|
||||
|
||||
// Run the pruner until the code does not change anymore.
|
||||
// Only run on the given function.
|
||||
// @param _allowMSizeOptimization if true, allows to remove instructions
|
||||
// whose only side-effect is a potential change of the return value of
|
||||
// the msize instruction.
|
||||
static void runUntilStabilised(
|
||||
Dialect const& _dialect,
|
||||
FunctionDefinition& _functionDefinition,
|
||||
bool _allowMSizeOptimization,
|
||||
std::set<YulString> const& _externallyUsedFunctions = {}
|
||||
);
|
||||
|
||||
@ -78,6 +91,7 @@ private:
|
||||
void subtractReferences(std::map<YulString, size_t> const& _subtrahend);
|
||||
|
||||
Dialect const& m_dialect;
|
||||
bool m_allowMSizeOptimization = false;
|
||||
bool m_shouldRunAgain = false;
|
||||
std::map<YulString, size_t> m_references;
|
||||
};
|
||||
|
12
test/libyul/yulOptimizerTests/unusedPruner/msize.yul
Normal file
12
test/libyul/yulOptimizerTests/unusedPruner/msize.yul
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
let a := 1
|
||||
let b := mload(10)
|
||||
sstore(0, msize())
|
||||
}
|
||||
// ====
|
||||
// step: unusedPruner
|
||||
// ----
|
||||
// {
|
||||
// pop(mload(10))
|
||||
// sstore(0, msize())
|
||||
// }
|
9
test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul
Normal file
9
test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
let a := 1
|
||||
let b := mload(10)
|
||||
sstore(0, 5)
|
||||
}
|
||||
// ====
|
||||
// step: unusedPruner
|
||||
// ----
|
||||
// { sstore(0, 5) }
|
Loading…
Reference in New Issue
Block a user