mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12376 from ethereum/develop
Merge `develop` into `breaking`
This commit is contained in:
@@ -173,10 +173,10 @@ add_library(yul
|
||||
optimiser/OptimizerUtilities.h
|
||||
optimiser/ReasoningBasedSimplifier.cpp
|
||||
optimiser/ReasoningBasedSimplifier.h
|
||||
optimiser/RedundantAssignEliminator.cpp
|
||||
optimiser/RedundantAssignEliminator.h
|
||||
optimiser/RedundantStoreBase.cpp
|
||||
optimiser/RedundantStoreBase.h
|
||||
optimiser/UnusedAssignEliminator.cpp
|
||||
optimiser/UnusedAssignEliminator.h
|
||||
optimiser/UnusedStoreBase.cpp
|
||||
optimiser/UnusedStoreBase.h
|
||||
optimiser/Rematerialiser.cpp
|
||||
optimiser/Rematerialiser.h
|
||||
optimiser/SMTSolver.cpp
|
||||
|
||||
@@ -137,7 +137,11 @@ void EVMToEwasmTranslator::parsePolyfill()
|
||||
string(solidity::yul::wasm::polyfill::Logical) +
|
||||
string(solidity::yul::wasm::polyfill::Memory) +
|
||||
"}", "");
|
||||
m_polyfill = Parser(errorReporter, WasmDialect::instance()).parse(charStream);
|
||||
|
||||
// Passing an empty SourceLocation() here is a workaround to prevent a crash
|
||||
// when compiling from yul->ewasm. We're stripping nativeLocation and
|
||||
// originLocation from the AST (but we only really need to strip nativeLocation)
|
||||
m_polyfill = Parser(errorReporter, WasmDialect::instance(), langutil::SourceLocation()).parse(charStream);
|
||||
if (!errors.empty())
|
||||
{
|
||||
string message;
|
||||
|
||||
@@ -43,3 +43,15 @@ void BlockFlattener::operator()(Block& _block)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void BlockFlattener::run(OptimiserStepContext&, Block& _ast)
|
||||
{
|
||||
BlockFlattener flattener;
|
||||
for (auto& statement: _ast.statements)
|
||||
if (auto* block = get_if<Block>(&statement))
|
||||
flattener(*block);
|
||||
else if (auto* function = get_if<FunctionDefinition>(&statement))
|
||||
flattener(function->body);
|
||||
else
|
||||
yulAssert(false, "BlockFlattener requires the FunctionGrouper.");
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class BlockFlattener: public ASTModifier
|
||||
{
|
||||
public:
|
||||
static constexpr char const* name{"BlockFlattener"};
|
||||
static void run(OptimiserStepContext&, Block& _ast) { BlockFlattener{}(_ast); }
|
||||
static void run(OptimiserStepContext&, Block& _ast);
|
||||
|
||||
using ASTModifier::operator();
|
||||
void operator()(Block& _block) override;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <libyul/optimiser/CircularReferencesPruner.h>
|
||||
|
||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||
#include <libyul/AST.h>
|
||||
|
||||
@@ -29,6 +30,7 @@ using namespace solidity::yul;
|
||||
void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast)
|
||||
{
|
||||
CircularReferencesPruner{_context.reservedIdentifiers}(_ast);
|
||||
FunctionGrouper::run(_context, _ast);
|
||||
}
|
||||
|
||||
void CircularReferencesPruner::operator()(Block& _block)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
#include <libyul/optimiser/NameCollector.h>
|
||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||
#include <libyul/Exceptions.h>
|
||||
@@ -37,9 +38,10 @@ using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
|
||||
void ExpressionJoiner::run(OptimiserStepContext&, Block& _ast)
|
||||
void ExpressionJoiner::run(OptimiserStepContext& _context, Block& _ast)
|
||||
{
|
||||
ExpressionJoiner{_ast}(_ast);
|
||||
FunctionGrouper::run(_context, _ast);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ struct OptimiserStepContext;
|
||||
* all function definitions.
|
||||
*
|
||||
* After this step, a block is of the form
|
||||
* { { I...} F... }
|
||||
* { { I... } F... }
|
||||
* Where I are (non-function-definition) instructions and F are function definitions.
|
||||
*/
|
||||
class FunctionGrouper
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace solidity::yul
|
||||
{
|
||||
|
||||
/// Removes statements that are just empty blocks (non-recursive).
|
||||
/// If this is run on the outermost block, the FunctionGrouper should be run afterwards to keep
|
||||
/// the canonical form.
|
||||
void removeEmptyBlocks(Block& _block);
|
||||
|
||||
/// Returns true if a given literal can not be used as an identifier.
|
||||
|
||||
@@ -70,7 +70,7 @@ class NameDispenser;
|
||||
* variable references can use the SSA variable. The only exception to this rule are
|
||||
* for loop conditions, as we cannot insert a variable declaration there.
|
||||
*
|
||||
* After this stage, redundantAssignmentRemover is recommended to remove the unnecessary
|
||||
* After this stage, UnusedAssignmentEliminator is recommended to remove the unnecessary
|
||||
* intermediate assignments.
|
||||
*
|
||||
* This stage provides best results if CSE is run right before it, because
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#include <libyul/optimiser/StackLimitEvader.h>
|
||||
#include <libyul/optimiser/StructuralSimplifier.h>
|
||||
#include <libyul/optimiser/SyntacticalEquality.h>
|
||||
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
||||
#include <libyul/optimiser/UnusedAssignEliminator.h>
|
||||
#include <libyul/optimiser/VarNameCleaner.h>
|
||||
#include <libyul/optimiser/LoadResolver.h>
|
||||
#include <libyul/optimiser/LoopInvariantCodeMotion.h>
|
||||
@@ -118,7 +118,7 @@ void OptimiserSuite::run(
|
||||
|
||||
// Some steps depend on properties ensured by FunctionHoister, BlockFlattener, FunctionGrouper and
|
||||
// ForLoopInitRewriter. Run them first to be able to run arbitrary sequences safely.
|
||||
suite.runSequence("hfgo", ast);
|
||||
suite.runSequence("hgfo", ast);
|
||||
|
||||
NameSimplifier::run(suite.m_context, ast);
|
||||
// Now the user-supplied part
|
||||
@@ -219,7 +219,7 @@ map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
|
||||
LiteralRematerialiser,
|
||||
LoadResolver,
|
||||
LoopInvariantCodeMotion,
|
||||
RedundantAssignEliminator,
|
||||
UnusedAssignEliminator,
|
||||
ReasoningBasedSimplifier,
|
||||
Rematerialiser,
|
||||
SSAReverser,
|
||||
@@ -260,7 +260,7 @@ map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
|
||||
{LoadResolver::name, 'L'},
|
||||
{LoopInvariantCodeMotion::name, 'M'},
|
||||
{ReasoningBasedSimplifier::name, 'R'},
|
||||
{RedundantAssignEliminator::name, 'r'},
|
||||
{UnusedAssignEliminator::name, 'r'},
|
||||
{Rematerialiser::name, 'm'},
|
||||
{SSAReverser::name, 'V'},
|
||||
{SSATransform::name, 'a'},
|
||||
|
||||
+18
-18
@@ -20,7 +20,7 @@
|
||||
* until they go out of scope or are re-assigned.
|
||||
*/
|
||||
|
||||
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
||||
#include <libyul/optimiser/UnusedAssignEliminator.h>
|
||||
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/AST.h>
|
||||
@@ -33,36 +33,36 @@ using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
|
||||
void RedundantAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
||||
void UnusedAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
||||
{
|
||||
RedundantAssignEliminator rae{_context.dialect};
|
||||
UnusedAssignEliminator rae{_context.dialect};
|
||||
rae(_ast);
|
||||
|
||||
StatementRemover remover{rae.m_pendingRemovals};
|
||||
remover(_ast);
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::operator()(Identifier const& _identifier)
|
||||
void UnusedAssignEliminator::operator()(Identifier const& _identifier)
|
||||
{
|
||||
changeUndecidedTo(_identifier.name, State::Used);
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::operator()(VariableDeclaration const& _variableDeclaration)
|
||||
void UnusedAssignEliminator::operator()(VariableDeclaration const& _variableDeclaration)
|
||||
{
|
||||
RedundantStoreBase::operator()(_variableDeclaration);
|
||||
UnusedStoreBase::operator()(_variableDeclaration);
|
||||
|
||||
for (auto const& var: _variableDeclaration.variables)
|
||||
m_declaredVariables.emplace(var.name);
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::operator()(Assignment const& _assignment)
|
||||
void UnusedAssignEliminator::operator()(Assignment const& _assignment)
|
||||
{
|
||||
visit(*_assignment.value);
|
||||
for (auto const& var: _assignment.variableNames)
|
||||
changeUndecidedTo(var.name, State::Unused);
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::operator()(FunctionDefinition const& _functionDefinition)
|
||||
void UnusedAssignEliminator::operator()(FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
ScopedSaveAndRestore outerDeclaredVariables(m_declaredVariables, {});
|
||||
ScopedSaveAndRestore outerReturnVariables(m_returnVariables, {});
|
||||
@@ -70,28 +70,28 @@ void RedundantAssignEliminator::operator()(FunctionDefinition const& _functionDe
|
||||
for (auto const& retParam: _functionDefinition.returnVariables)
|
||||
m_returnVariables.insert(retParam.name);
|
||||
|
||||
RedundantStoreBase::operator()(_functionDefinition);
|
||||
UnusedStoreBase::operator()(_functionDefinition);
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::operator()(Leave const&)
|
||||
void UnusedAssignEliminator::operator()(Leave const&)
|
||||
{
|
||||
for (YulString name: m_returnVariables)
|
||||
changeUndecidedTo(name, State::Used);
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::operator()(Block const& _block)
|
||||
void UnusedAssignEliminator::operator()(Block const& _block)
|
||||
{
|
||||
ScopedSaveAndRestore outerDeclaredVariables(m_declaredVariables, {});
|
||||
|
||||
RedundantStoreBase::operator()(_block);
|
||||
UnusedStoreBase::operator()(_block);
|
||||
|
||||
for (auto const& var: m_declaredVariables)
|
||||
finalize(var, State::Unused);
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::visit(Statement const& _statement)
|
||||
void UnusedAssignEliminator::visit(Statement const& _statement)
|
||||
{
|
||||
RedundantStoreBase::visit(_statement);
|
||||
UnusedStoreBase::visit(_statement);
|
||||
|
||||
if (auto const* assignment = get_if<Assignment>(&_statement))
|
||||
if (assignment->variableNames.size() == 1)
|
||||
@@ -99,7 +99,7 @@ void RedundantAssignEliminator::visit(Statement const& _statement)
|
||||
m_stores[assignment->variableNames.front().name][&_statement];
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::shortcutNestedLoop(TrackedStores const& _zeroRuns)
|
||||
void UnusedAssignEliminator::shortcutNestedLoop(TrackedStores const& _zeroRuns)
|
||||
{
|
||||
// Shortcut to avoid horrible runtime:
|
||||
// Change all assignments that were newly introduced in the for loop to "used".
|
||||
@@ -116,7 +116,7 @@ void RedundantAssignEliminator::shortcutNestedLoop(TrackedStores const& _zeroRun
|
||||
}
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::finalizeFunctionDefinition(FunctionDefinition const& _functionDefinition)
|
||||
void UnusedAssignEliminator::finalizeFunctionDefinition(FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
for (auto const& param: _functionDefinition.parameters)
|
||||
finalize(param.name, State::Unused);
|
||||
@@ -124,14 +124,14 @@ void RedundantAssignEliminator::finalizeFunctionDefinition(FunctionDefinition co
|
||||
finalize(retParam.name, State::Used);
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState)
|
||||
void UnusedAssignEliminator::changeUndecidedTo(YulString _variable, UnusedAssignEliminator::State _newState)
|
||||
{
|
||||
for (auto& assignment: m_stores[_variable])
|
||||
if (assignment.second == State::Undecided)
|
||||
assignment.second = _newState;
|
||||
}
|
||||
|
||||
void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEliminator::State _finalState)
|
||||
void UnusedAssignEliminator::finalize(YulString _variable, UnusedAssignEliminator::State _finalState)
|
||||
{
|
||||
std::map<Statement const*, State> stores = std::move(m_stores[_variable]);
|
||||
m_stores.erase(_variable);
|
||||
+5
-5
@@ -25,7 +25,7 @@
|
||||
#include <libyul/ASTForward.h>
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/optimiser/OptimiserStep.h>
|
||||
#include <libyul/optimiser/RedundantStoreBase.h>
|
||||
#include <libyul/optimiser/UnusedStoreBase.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -107,13 +107,13 @@ struct Dialect;
|
||||
*
|
||||
* Prerequisite: Disambiguator, ForLoopInitRewriter.
|
||||
*/
|
||||
class RedundantAssignEliminator: public RedundantStoreBase
|
||||
class UnusedAssignEliminator: public UnusedStoreBase
|
||||
{
|
||||
public:
|
||||
static constexpr char const* name{"RedundantAssignEliminator"};
|
||||
static constexpr char const* name{"UnusedAssignEliminator"};
|
||||
static void run(OptimiserStepContext&, Block& _ast);
|
||||
|
||||
explicit RedundantAssignEliminator(Dialect const& _dialect): RedundantStoreBase(_dialect) {}
|
||||
explicit UnusedAssignEliminator(Dialect const& _dialect): UnusedStoreBase(_dialect) {}
|
||||
|
||||
void operator()(Identifier const& _identifier) override;
|
||||
void operator()(VariableDeclaration const& _variableDeclaration) override;
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
void operator()(Leave const&) override;
|
||||
void operator()(Block const& _block) override;
|
||||
|
||||
using RedundantStoreBase::visit;
|
||||
using UnusedStoreBase::visit;
|
||||
void visit(Statement const& _statement) override;
|
||||
|
||||
private:
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <libyul/optimiser/UnusedPruner.h>
|
||||
|
||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
#include <libyul/optimiser/NameCollector.h>
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||
@@ -33,6 +34,12 @@ using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
|
||||
void UnusedPruner::run(OptimiserStepContext& _context, Block& _ast)
|
||||
{
|
||||
UnusedPruner::runUntilStabilisedOnFullAST(_context.dialect, _ast, _context.reservedIdentifiers);
|
||||
FunctionGrouper::run(_context, _ast);
|
||||
}
|
||||
|
||||
UnusedPruner::UnusedPruner(
|
||||
Dialect const& _dialect,
|
||||
Block& _ast,
|
||||
|
||||
@@ -50,9 +50,7 @@ class UnusedPruner: public ASTModifier
|
||||
{
|
||||
public:
|
||||
static constexpr char const* name{"UnusedPruner"};
|
||||
static void run(OptimiserStepContext& _context, Block& _ast) {
|
||||
UnusedPruner::runUntilStabilisedOnFullAST(_context.dialect, _ast, _context.reservedIdentifiers);
|
||||
}
|
||||
static void run(OptimiserStepContext& _context, Block& _ast);
|
||||
|
||||
|
||||
using ASTModifier::operator();
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
/**
|
||||
* Base class for both RedundantAssignEliminator and RedundantStoreEliminator.
|
||||
* Base class for both UnusedAssignEliminator and UnusedStoreEliminator.
|
||||
*/
|
||||
|
||||
#include <libyul/optimiser/RedundantStoreBase.h>
|
||||
#include <libyul/optimiser/UnusedStoreBase.h>
|
||||
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/optimiser/OptimiserStep.h>
|
||||
@@ -33,7 +33,7 @@ using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
|
||||
void RedundantStoreBase::operator()(If const& _if)
|
||||
void UnusedStoreBase::operator()(If const& _if)
|
||||
{
|
||||
visit(*_if.condition);
|
||||
|
||||
@@ -43,7 +43,7 @@ void RedundantStoreBase::operator()(If const& _if)
|
||||
merge(m_stores, move(skipBranch));
|
||||
}
|
||||
|
||||
void RedundantStoreBase::operator()(Switch const& _switch)
|
||||
void UnusedStoreBase::operator()(Switch const& _switch)
|
||||
{
|
||||
visit(*_switch.expression);
|
||||
|
||||
@@ -69,7 +69,7 @@ void RedundantStoreBase::operator()(Switch const& _switch)
|
||||
merge(m_stores, move(branch));
|
||||
}
|
||||
|
||||
void RedundantStoreBase::operator()(FunctionDefinition const& _functionDefinition)
|
||||
void UnusedStoreBase::operator()(FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
ScopedSaveAndRestore outerAssignments(m_stores, {});
|
||||
ScopedSaveAndRestore forLoopInfo(m_forLoopInfo, {});
|
||||
@@ -79,7 +79,7 @@ void RedundantStoreBase::operator()(FunctionDefinition const& _functionDefinitio
|
||||
finalizeFunctionDefinition(_functionDefinition);
|
||||
}
|
||||
|
||||
void RedundantStoreBase::operator()(ForLoop const& _forLoop)
|
||||
void UnusedStoreBase::operator()(ForLoop const& _forLoop)
|
||||
{
|
||||
ScopedSaveAndRestore outerForLoopInfo(m_forLoopInfo, {});
|
||||
ScopedSaveAndRestore forLoopNestingDepth(m_forLoopNestingDepth, m_forLoopNestingDepth + 1);
|
||||
@@ -127,19 +127,19 @@ void RedundantStoreBase::operator()(ForLoop const& _forLoop)
|
||||
m_forLoopInfo.pendingBreakStmts.clear();
|
||||
}
|
||||
|
||||
void RedundantStoreBase::operator()(Break const&)
|
||||
void UnusedStoreBase::operator()(Break const&)
|
||||
{
|
||||
m_forLoopInfo.pendingBreakStmts.emplace_back(move(m_stores));
|
||||
m_stores.clear();
|
||||
}
|
||||
|
||||
void RedundantStoreBase::operator()(Continue const&)
|
||||
void UnusedStoreBase::operator()(Continue const&)
|
||||
{
|
||||
m_forLoopInfo.pendingContinueStmts.emplace_back(move(m_stores));
|
||||
m_stores.clear();
|
||||
}
|
||||
|
||||
void RedundantStoreBase::merge(TrackedStores& _target, TrackedStores&& _other)
|
||||
void UnusedStoreBase::merge(TrackedStores& _target, TrackedStores&& _other)
|
||||
{
|
||||
util::joinMap(_target, move(_other), [](
|
||||
map<Statement const*, State>& _assignmentHere,
|
||||
@@ -150,7 +150,7 @@ void RedundantStoreBase::merge(TrackedStores& _target, TrackedStores&& _other)
|
||||
});
|
||||
}
|
||||
|
||||
void RedundantStoreBase::merge(TrackedStores& _target, vector<TrackedStores>&& _source)
|
||||
void UnusedStoreBase::merge(TrackedStores& _target, vector<TrackedStores>&& _source)
|
||||
{
|
||||
for (TrackedStores& ts: _source)
|
||||
merge(_target, move(ts));
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
/**
|
||||
* Base class for both RedundantAssignEliminator and RedundantStoreEliminator.
|
||||
* Base class for both UnusedAssignEliminator and UnusedStoreEliminator.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -34,14 +34,19 @@ namespace solidity::yul
|
||||
struct Dialect;
|
||||
|
||||
/**
|
||||
* Base class for both RedundantAssignEliminator and RedundantStoreEliminator.
|
||||
* Base class for both UnusedAssignEliminator and UnusedStoreEliminator.
|
||||
*
|
||||
* The class tracks the state of abstract "stores" (assignments or mstore/sstore
|
||||
* statements) across the control-flow. It is the job of the derived class to create
|
||||
* the stores and track references, but the base class adjusts their "used state" at
|
||||
* control-flow splits and joins.
|
||||
*
|
||||
* Prerequisite: Disambiguator, ForLoopInitRewriter.
|
||||
*/
|
||||
class RedundantStoreBase: public ASTWalker
|
||||
class UnusedStoreBase: public ASTWalker
|
||||
{
|
||||
public:
|
||||
explicit RedundantStoreBase(Dialect const& _dialect): m_dialect(_dialect) {}
|
||||
explicit UnusedStoreBase(Dialect const& _dialect): m_dialect(_dialect) {}
|
||||
|
||||
using ASTWalker::operator();
|
||||
void operator()(If const& _if) override;
|
||||
Reference in New Issue
Block a user