mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #14512 from junaire/yul-opt-kill-namespace-std
Purge using namespace std from libyul/optimiser
This commit is contained in:
		
						commit
						88b8368932
					
				@ -25,7 +25,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/Common.h>
 | 
					#include <libsolutil/Common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <range/v3/view/reverse.hpp>
 | 
					#include <range/v3/view/reverse.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
@ -34,9 +33,9 @@ void BlockFlattener::operator()(Block& _block)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	iterateReplacing(
 | 
						iterateReplacing(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[](Statement& _s) -> std::optional<vector<Statement>>
 | 
							[](Statement& _s) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (holds_alternative<Block>(_s))
 | 
								if (std::holds_alternative<Block>(_s))
 | 
				
			||||||
				return std::move(std::get<Block>(_s).statements);
 | 
									return std::move(std::get<Block>(_s).statements);
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				return {};
 | 
									return {};
 | 
				
			||||||
@ -48,9 +47,9 @@ void BlockFlattener::run(OptimiserStepContext&, Block& _ast)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	BlockFlattener flattener;
 | 
						BlockFlattener flattener;
 | 
				
			||||||
	for (auto& statement: _ast.statements)
 | 
						for (auto& statement: _ast.statements)
 | 
				
			||||||
		if (auto* block = get_if<Block>(&statement))
 | 
							if (auto* block = std::get_if<Block>(&statement))
 | 
				
			||||||
			flattener(*block);
 | 
								flattener(*block);
 | 
				
			||||||
		else if (auto* function = get_if<FunctionDefinition>(&statement))
 | 
							else if (auto* function = std::get_if<FunctionDefinition>(&statement))
 | 
				
			||||||
			flattener(function->body);
 | 
								flattener(function->body);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			yulAssert(false, "BlockFlattener requires the FunctionGrouper.");
 | 
								yulAssert(false, "BlockFlattener requires the FunctionGrouper.");
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
#include <libyul/Utilities.h>
 | 
					#include <libyul/Utilities.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,6 @@
 | 
				
			|||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
#include <stack>
 | 
					#include <stack>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
@ -36,9 +35,9 @@ namespace
 | 
				
			|||||||
struct CallGraphCycleFinder
 | 
					struct CallGraphCycleFinder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	CallGraph const& callGraph;
 | 
						CallGraph const& callGraph;
 | 
				
			||||||
	set<YulString> containedInCycle{};
 | 
						std::set<YulString> containedInCycle{};
 | 
				
			||||||
	set<YulString> visited{};
 | 
						std::set<YulString> visited{};
 | 
				
			||||||
	vector<YulString> currentPath{};
 | 
						std::vector<YulString> currentPath{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void visit(YulString _function)
 | 
						void visit(YulString _function)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -62,7 +61,7 @@ struct CallGraphCycleFinder
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set<YulString> CallGraph::recursiveFunctions() const
 | 
					std::set<YulString> CallGraph::recursiveFunctions() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	CallGraphCycleFinder cycleFinder{*this};
 | 
						CallGraphCycleFinder cycleFinder{*this};
 | 
				
			||||||
	// Visiting the root only is not enough, since there may be disconnected recursive functions.
 | 
						// Visiting the root only is not enough, since there may be disconnected recursive functions.
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/Algorithms.h>
 | 
					#include <libsolutil/Algorithms.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast)
 | 
					void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			||||||
@ -35,11 +34,11 @@ void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void CircularReferencesPruner::operator()(Block& _block)
 | 
					void CircularReferencesPruner::operator()(Block& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<YulString> functionsToKeep =
 | 
						std::set<YulString> functionsToKeep =
 | 
				
			||||||
		functionsCalledFromOutermostContext(CallGraphGenerator::callGraph(_block));
 | 
							functionsCalledFromOutermostContext(CallGraphGenerator::callGraph(_block));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto&& statement: _block.statements)
 | 
						for (auto&& statement: _block.statements)
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(statement))
 | 
							if (std::holds_alternative<FunctionDefinition>(statement))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			FunctionDefinition const& funDef = std::get<FunctionDefinition>(statement);
 | 
								FunctionDefinition const& funDef = std::get<FunctionDefinition>(statement);
 | 
				
			||||||
			if (!functionsToKeep.count(funDef.name))
 | 
								if (!functionsToKeep.count(funDef.name))
 | 
				
			||||||
@ -49,9 +48,9 @@ void CircularReferencesPruner::operator()(Block& _block)
 | 
				
			|||||||
	removeEmptyBlocks(_block);
 | 
						removeEmptyBlocks(_block);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set<YulString> CircularReferencesPruner::functionsCalledFromOutermostContext(CallGraph const& _callGraph)
 | 
					std::set<YulString> CircularReferencesPruner::functionsCalledFromOutermostContext(CallGraph const& _callGraph)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<YulString> verticesToTraverse = m_reservedIdentifiers;
 | 
						std::set<YulString> verticesToTraverse = m_reservedIdentifiers;
 | 
				
			||||||
	verticesToTraverse.insert(YulString(""));
 | 
						verticesToTraverse.insert(YulString(""));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return util::BreadthFirstSearch<YulString>{{verticesToTraverse.begin(), verticesToTraverse.end()}}.run(
 | 
						return util::BreadthFirstSearch<YulString>{{verticesToTraverse.begin(), verticesToTraverse.end()}}.run(
 | 
				
			||||||
 | 
				
			|||||||
@ -31,7 +31,6 @@
 | 
				
			|||||||
#include <libyul/Dialect.h>
 | 
					#include <libyul/Dialect.h>
 | 
				
			||||||
#include <libyul/Utilities.h>
 | 
					#include <libyul/Utilities.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
@ -47,7 +46,7 @@ void CommonSubexpressionEliminator::run(OptimiserStepContext& _context, Block& _
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CommonSubexpressionEliminator::CommonSubexpressionEliminator(
 | 
					CommonSubexpressionEliminator::CommonSubexpressionEliminator(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	map<YulString, SideEffects> _functionSideEffects
 | 
						std::map<YulString, SideEffects> _functionSideEffects
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore, std::move(_functionSideEffects))
 | 
						DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore, std::move(_functionSideEffects))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -69,7 +68,7 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
 | 
				
			|||||||
	bool descend = true;
 | 
						bool descend = true;
 | 
				
			||||||
	// If this is a function call to a function that requires literal arguments,
 | 
						// If this is a function call to a function that requires literal arguments,
 | 
				
			||||||
	// do not try to simplify there.
 | 
						// do not try to simplify there.
 | 
				
			||||||
	if (holds_alternative<FunctionCall>(_e))
 | 
						if (std::holds_alternative<FunctionCall>(_e))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		FunctionCall& funCall = std::get<FunctionCall>(_e);
 | 
							FunctionCall& funCall = std::get<FunctionCall>(_e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -94,13 +93,13 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
 | 
				
			|||||||
	if (descend)
 | 
						if (descend)
 | 
				
			||||||
		DataFlowAnalyzer::visit(_e);
 | 
							DataFlowAnalyzer::visit(_e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (Identifier const* identifier = get_if<Identifier>(&_e))
 | 
						if (Identifier const* identifier = std::get_if<Identifier>(&_e))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		YulString identifierName = identifier->name;
 | 
							YulString identifierName = identifier->name;
 | 
				
			||||||
		if (AssignedValue const* assignedValue = variableValue(identifierName))
 | 
							if (AssignedValue const* assignedValue = variableValue(identifierName))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			assertThrow(assignedValue->value, OptimizerException, "");
 | 
								assertThrow(assignedValue->value, OptimizerException, "");
 | 
				
			||||||
			if (Identifier const* value = get_if<Identifier>(assignedValue->value))
 | 
								if (Identifier const* value = std::get_if<Identifier>(assignedValue->value))
 | 
				
			||||||
				if (inScope(value->name))
 | 
									if (inScope(value->name))
 | 
				
			||||||
					_e = Identifier{debugDataOf(_e), value->name};
 | 
										_e = Identifier{debugDataOf(_e), value->name};
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -114,8 +113,8 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
 | 
				
			|||||||
				// instead of literal zeros.
 | 
									// instead of literal zeros.
 | 
				
			||||||
				if (
 | 
									if (
 | 
				
			||||||
					m_returnVariables.count(variable) &&
 | 
										m_returnVariables.count(variable) &&
 | 
				
			||||||
					holds_alternative<Literal>(*value->value) &&
 | 
										std::holds_alternative<Literal>(*value->value) &&
 | 
				
			||||||
					valueOfLiteral(get<Literal>(*value->value)) == 0
 | 
										valueOfLiteral(std::get<Literal>(*value->value)) == 0
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				// We check for syntactic equality again because the value might have changed.
 | 
									// We check for syntactic equality again because the value might have changed.
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,6 @@
 | 
				
			|||||||
#include <libyul/ControlFlowSideEffectsCollector.h>
 | 
					#include <libyul/ControlFlowSideEffectsCollector.h>
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
@ -38,7 +37,7 @@ void ConditionalSimplifier::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			|||||||
void ConditionalSimplifier::operator()(Switch& _switch)
 | 
					void ConditionalSimplifier::operator()(Switch& _switch)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	visit(*_switch.expression);
 | 
						visit(*_switch.expression);
 | 
				
			||||||
	if (!holds_alternative<Identifier>(*_switch.expression))
 | 
						if (!std::holds_alternative<Identifier>(*_switch.expression))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ASTModifier::operator()(_switch);
 | 
							ASTModifier::operator()(_switch);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@ -53,7 +52,7 @@ void ConditionalSimplifier::operator()(Switch& _switch)
 | 
				
			|||||||
				Assignment{
 | 
									Assignment{
 | 
				
			||||||
					_case.body.debugData,
 | 
										_case.body.debugData,
 | 
				
			||||||
					{Identifier{_case.body.debugData, expr}},
 | 
										{Identifier{_case.body.debugData, expr}},
 | 
				
			||||||
					make_unique<Expression>(*_case.value)
 | 
										std::make_unique<Expression>(*_case.value)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -65,14 +64,14 @@ void ConditionalSimplifier::operator()(Block& _block)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	iterateReplacing(
 | 
						iterateReplacing(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[&](Statement& _s) -> std::optional<vector<Statement>>
 | 
							[&](Statement& _s) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			visit(_s);
 | 
								visit(_s);
 | 
				
			||||||
			if (holds_alternative<If>(_s))
 | 
								if (std::holds_alternative<If>(_s))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				If& _if = std::get<If>(_s);
 | 
									If& _if = std::get<If>(_s);
 | 
				
			||||||
				if (
 | 
									if (
 | 
				
			||||||
					holds_alternative<Identifier>(*_if.condition) &&
 | 
										std::holds_alternative<Identifier>(*_if.condition) &&
 | 
				
			||||||
					!_if.body.statements.empty() &&
 | 
										!_if.body.statements.empty() &&
 | 
				
			||||||
					TerminationFinder(m_dialect, &m_functionSideEffects).controlFlowKind(_if.body.statements.back()) !=
 | 
										TerminationFinder(m_dialect, &m_functionSideEffects).controlFlowKind(_if.body.statements.back()) !=
 | 
				
			||||||
						TerminationFinder::ControlFlow::FlowOut
 | 
											TerminationFinder::ControlFlow::FlowOut
 | 
				
			||||||
@ -85,7 +84,7 @@ void ConditionalSimplifier::operator()(Block& _block)
 | 
				
			|||||||
						Assignment{
 | 
											Assignment{
 | 
				
			||||||
							debugData,
 | 
												debugData,
 | 
				
			||||||
							{Identifier{debugData, condition}},
 | 
												{Identifier{debugData, condition}},
 | 
				
			||||||
							make_unique<Expression>(m_dialect.zeroLiteralForType(m_dialect.boolType))
 | 
												std::make_unique<Expression>(m_dialect.zeroLiteralForType(m_dialect.boolType))
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					);
 | 
										);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
#include <libyul/ControlFlowSideEffectsCollector.h>
 | 
					#include <libyul/ControlFlowSideEffectsCollector.h>
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
@ -39,7 +38,7 @@ void ConditionalUnsimplifier::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			|||||||
void ConditionalUnsimplifier::operator()(Switch& _switch)
 | 
					void ConditionalUnsimplifier::operator()(Switch& _switch)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	visit(*_switch.expression);
 | 
						visit(*_switch.expression);
 | 
				
			||||||
	if (!holds_alternative<Identifier>(*_switch.expression))
 | 
						if (!std::holds_alternative<Identifier>(*_switch.expression))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ASTModifier::operator()(_switch);
 | 
							ASTModifier::operator()(_switch);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@ -52,14 +51,14 @@ void ConditionalUnsimplifier::operator()(Switch& _switch)
 | 
				
			|||||||
			(*this)(*_case.value);
 | 
								(*this)(*_case.value);
 | 
				
			||||||
			if (
 | 
								if (
 | 
				
			||||||
				!_case.body.statements.empty() &&
 | 
									!_case.body.statements.empty() &&
 | 
				
			||||||
				holds_alternative<Assignment>(_case.body.statements.front())
 | 
									std::holds_alternative<Assignment>(_case.body.statements.front())
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Assignment const& assignment = std::get<Assignment>(_case.body.statements.front());
 | 
									Assignment const& assignment = std::get<Assignment>(_case.body.statements.front());
 | 
				
			||||||
				if (
 | 
									if (
 | 
				
			||||||
					assignment.variableNames.size() == 1 &&
 | 
										assignment.variableNames.size() == 1 &&
 | 
				
			||||||
					assignment.variableNames.front().name == expr &&
 | 
										assignment.variableNames.front().name == expr &&
 | 
				
			||||||
					holds_alternative<Literal>(*assignment.value) &&
 | 
										std::holds_alternative<Literal>(*assignment.value) &&
 | 
				
			||||||
					valueOfLiteral(std::get<Literal>(*assignment.value)) == valueOfLiteral(*_case.value)
 | 
										valueOfLiteral(std::get<Literal>(*assignment.value)) == valueOfLiteral(*_case.value)
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
					_case.body.statements.erase(_case.body.statements.begin());
 | 
										_case.body.statements.erase(_case.body.statements.begin());
 | 
				
			||||||
@ -74,19 +73,19 @@ void ConditionalUnsimplifier::operator()(Block& _block)
 | 
				
			|||||||
	walkVector(_block.statements);
 | 
						walkVector(_block.statements);
 | 
				
			||||||
	iterateReplacingWindow<2>(
 | 
						iterateReplacingWindow<2>(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>>
 | 
							[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (holds_alternative<If>(_stmt1))
 | 
								if (std::holds_alternative<If>(_stmt1))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				If& _if = std::get<If>(_stmt1);
 | 
									If& _if = std::get<If>(_stmt1);
 | 
				
			||||||
				if (
 | 
									if (
 | 
				
			||||||
					holds_alternative<Identifier>(*_if.condition) &&
 | 
										std::holds_alternative<Identifier>(*_if.condition) &&
 | 
				
			||||||
					!_if.body.statements.empty()
 | 
										!_if.body.statements.empty()
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					YulString condition = std::get<Identifier>(*_if.condition).name;
 | 
										YulString condition = std::get<Identifier>(*_if.condition).name;
 | 
				
			||||||
					if (
 | 
										if (
 | 
				
			||||||
						holds_alternative<Assignment>(_stmt2) &&
 | 
											std::holds_alternative<Assignment>(_stmt2) &&
 | 
				
			||||||
						TerminationFinder(m_dialect, &m_functionSideEffects).controlFlowKind(_if.body.statements.back()) !=
 | 
											TerminationFinder(m_dialect, &m_functionSideEffects).controlFlowKind(_if.body.statements.back()) !=
 | 
				
			||||||
							TerminationFinder::ControlFlow::FlowOut
 | 
												TerminationFinder::ControlFlow::FlowOut
 | 
				
			||||||
					)
 | 
										)
 | 
				
			||||||
@ -95,7 +94,7 @@ void ConditionalUnsimplifier::operator()(Block& _block)
 | 
				
			|||||||
						if (
 | 
											if (
 | 
				
			||||||
							assignment.variableNames.size() == 1 &&
 | 
												assignment.variableNames.size() == 1 &&
 | 
				
			||||||
							assignment.variableNames.front().name == condition &&
 | 
												assignment.variableNames.front().name == condition &&
 | 
				
			||||||
							holds_alternative<Literal>(*assignment.value) &&
 | 
												std::holds_alternative<Literal>(*assignment.value) &&
 | 
				
			||||||
							valueOfLiteral(std::get<Literal>(*assignment.value)) == 0
 | 
												valueOfLiteral(std::get<Literal>(*assignment.value)) == 0
 | 
				
			||||||
						)
 | 
											)
 | 
				
			||||||
							return {make_vector<Statement>(std::move(_stmt1))};
 | 
												return {make_vector<Statement>(std::move(_stmt1))};
 | 
				
			||||||
 | 
				
			|||||||
@ -27,12 +27,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <range/v3/action/remove_if.hpp>
 | 
					#include <range/v3/action/remove_if.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using OptionalStatements = std::optional<vector<Statement>>;
 | 
					using OptionalStatements = std::optional<std::vector<Statement>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace
 | 
					namespace
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -85,13 +84,13 @@ void ControlFlowSimplifier::operator()(Block& _block)
 | 
				
			|||||||
void ControlFlowSimplifier::operator()(FunctionDefinition& _funDef)
 | 
					void ControlFlowSimplifier::operator()(FunctionDefinition& _funDef)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ASTModifier::operator()(_funDef);
 | 
						ASTModifier::operator()(_funDef);
 | 
				
			||||||
	if (!_funDef.body.statements.empty() && holds_alternative<Leave>(_funDef.body.statements.back()))
 | 
						if (!_funDef.body.statements.empty() && std::holds_alternative<Leave>(_funDef.body.statements.back()))
 | 
				
			||||||
		_funDef.body.statements.pop_back();
 | 
							_funDef.body.statements.pop_back();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ControlFlowSimplifier::visit(Statement& _st)
 | 
					void ControlFlowSimplifier::visit(Statement& _st)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<ForLoop>(_st))
 | 
						if (std::holds_alternative<ForLoop>(_st))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ForLoop& forLoop = std::get<ForLoop>(_st);
 | 
							ForLoop& forLoop = std::get<ForLoop>(_st);
 | 
				
			||||||
		yulAssert(forLoop.pre.statements.empty(), "");
 | 
							yulAssert(forLoop.pre.statements.empty(), "");
 | 
				
			||||||
@ -141,7 +140,7 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
 | 
				
			|||||||
		[&](If& _ifStmt) -> OptionalStatements {
 | 
							[&](If& _ifStmt) -> OptionalStatements {
 | 
				
			||||||
			if (_ifStmt.body.statements.empty() && m_dialect.discardFunction(m_dialect.boolType))
 | 
								if (_ifStmt.body.statements.empty() && m_dialect.discardFunction(m_dialect.boolType))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				OptionalStatements s = vector<Statement>{};
 | 
									OptionalStatements s = std::vector<Statement>{};
 | 
				
			||||||
				s->emplace_back(makeDiscardCall(
 | 
									s->emplace_back(makeDiscardCall(
 | 
				
			||||||
					_ifStmt.debugData,
 | 
										_ifStmt.debugData,
 | 
				
			||||||
					*m_dialect.discardFunction(m_dialect.boolType),
 | 
										*m_dialect.discardFunction(m_dialect.boolType),
 | 
				
			||||||
@ -197,7 +196,7 @@ OptionalStatements ControlFlowSimplifier::reduceSingleCaseSwitch(Switch& _switch
 | 
				
			|||||||
	yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!");
 | 
						yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto& switchCase = _switchStmt.cases.front();
 | 
						auto& switchCase = _switchStmt.cases.front();
 | 
				
			||||||
	shared_ptr<DebugData const> debugData = debugDataOf(*_switchStmt.expression);
 | 
						std::shared_ptr<DebugData const> debugData = debugDataOf(*_switchStmt.expression);
 | 
				
			||||||
	YulString type = m_typeInfo.typeOf(*_switchStmt.expression);
 | 
						YulString type = m_typeInfo.typeOf(*_switchStmt.expression);
 | 
				
			||||||
	if (switchCase.value)
 | 
						if (switchCase.value)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -205,7 +204,7 @@ OptionalStatements ControlFlowSimplifier::reduceSingleCaseSwitch(Switch& _switch
 | 
				
			|||||||
			return {};
 | 
								return {};
 | 
				
			||||||
		return make_vector<Statement>(If{
 | 
							return make_vector<Statement>(If{
 | 
				
			||||||
			std::move(_switchStmt.debugData),
 | 
								std::move(_switchStmt.debugData),
 | 
				
			||||||
			make_unique<Expression>(FunctionCall{
 | 
								std::make_unique<Expression>(FunctionCall{
 | 
				
			||||||
				debugData,
 | 
									debugData,
 | 
				
			||||||
				Identifier{debugData, m_dialect.equalityFunction(type)->name},
 | 
									Identifier{debugData, m_dialect.equalityFunction(type)->name},
 | 
				
			||||||
				{std::move(*switchCase.value), std::move(*_switchStmt.expression)}
 | 
									{std::move(*switchCase.value), std::move(*_switchStmt.expression)}
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <range/v3/view/reverse.hpp>
 | 
					#include <range/v3/view/reverse.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
@ -46,7 +45,7 @@ using namespace solidity::yul;
 | 
				
			|||||||
DataFlowAnalyzer::DataFlowAnalyzer(
 | 
					DataFlowAnalyzer::DataFlowAnalyzer(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	MemoryAndStorage _analyzeStores,
 | 
						MemoryAndStorage _analyzeStores,
 | 
				
			||||||
	map<YulString, SideEffects> _functionSideEffects
 | 
						std::map<YulString, SideEffects> _functionSideEffects
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	m_dialect(_dialect),
 | 
						m_dialect(_dialect),
 | 
				
			||||||
	m_functionSideEffects(std::move(_functionSideEffects)),
 | 
						m_functionSideEffects(std::move(_functionSideEffects)),
 | 
				
			||||||
@ -99,7 +98,7 @@ void DataFlowAnalyzer::operator()(ExpressionStatement& _statement)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void DataFlowAnalyzer::operator()(Assignment& _assignment)
 | 
					void DataFlowAnalyzer::operator()(Assignment& _assignment)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<YulString> names;
 | 
						std::set<YulString> names;
 | 
				
			||||||
	for (auto const& var: _assignment.variableNames)
 | 
						for (auto const& var: _assignment.variableNames)
 | 
				
			||||||
		names.emplace(var.name);
 | 
							names.emplace(var.name);
 | 
				
			||||||
	assertThrow(_assignment.value, OptimizerException, "");
 | 
						assertThrow(_assignment.value, OptimizerException, "");
 | 
				
			||||||
@ -110,7 +109,7 @@ void DataFlowAnalyzer::operator()(Assignment& _assignment)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl)
 | 
					void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<YulString> names;
 | 
						std::set<YulString> names;
 | 
				
			||||||
	for (auto const& var: _varDecl.variables)
 | 
						for (auto const& var: _varDecl.variables)
 | 
				
			||||||
		names.emplace(var.name);
 | 
							names.emplace(var.name);
 | 
				
			||||||
	m_variableScopes.back().variables += names;
 | 
						m_variableScopes.back().variables += names;
 | 
				
			||||||
@ -139,14 +138,14 @@ void DataFlowAnalyzer::operator()(Switch& _switch)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	clearKnowledgeIfInvalidated(*_switch.expression);
 | 
						clearKnowledgeIfInvalidated(*_switch.expression);
 | 
				
			||||||
	visit(*_switch.expression);
 | 
						visit(*_switch.expression);
 | 
				
			||||||
	set<YulString> assignedVariables;
 | 
						std::set<YulString> assignedVariables;
 | 
				
			||||||
	for (auto& _case: _switch.cases)
 | 
						for (auto& _case: _switch.cases)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Environment preEnvironment = m_state.environment;
 | 
							Environment preEnvironment = m_state.environment;
 | 
				
			||||||
		(*this)(_case.body);
 | 
							(*this)(_case.body);
 | 
				
			||||||
		joinKnowledge(preEnvironment);
 | 
							joinKnowledge(preEnvironment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		set<YulString> variables = assignedVariableNames(_case.body);
 | 
							std::set<YulString> variables = assignedVariableNames(_case.body);
 | 
				
			||||||
		assignedVariables += variables;
 | 
							assignedVariables += variables;
 | 
				
			||||||
		// This is a little too destructive, we could retain the old values.
 | 
							// This is a little too destructive, we could retain the old values.
 | 
				
			||||||
		clearValues(variables);
 | 
							clearValues(variables);
 | 
				
			||||||
@ -192,7 +191,7 @@ void DataFlowAnalyzer::operator()(ForLoop& _for)
 | 
				
			|||||||
	AssignmentsSinceContinue assignmentsSinceCont;
 | 
						AssignmentsSinceContinue assignmentsSinceCont;
 | 
				
			||||||
	assignmentsSinceCont(_for.body);
 | 
						assignmentsSinceCont(_for.body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set<YulString> assignedVariables =
 | 
						std::set<YulString> assignedVariables =
 | 
				
			||||||
		assignedVariableNames(_for.body) + assignedVariableNames(_for.post);
 | 
							assignedVariableNames(_for.body) + assignedVariableNames(_for.post);
 | 
				
			||||||
	clearValues(assignedVariables);
 | 
						clearValues(assignedVariables);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -223,31 +222,31 @@ void DataFlowAnalyzer::operator()(Block& _block)
 | 
				
			|||||||
	assertThrow(numScopes == m_variableScopes.size(), OptimizerException, "");
 | 
						assertThrow(numScopes == m_variableScopes.size(), OptimizerException, "");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<YulString> DataFlowAnalyzer::storageValue(YulString _key) const
 | 
					std::optional<YulString> DataFlowAnalyzer::storageValue(YulString _key) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (YulString const* value = valueOrNullptr(m_state.environment.storage, _key))
 | 
						if (YulString const* value = valueOrNullptr(m_state.environment.storage, _key))
 | 
				
			||||||
		return *value;
 | 
							return *value;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<YulString> DataFlowAnalyzer::memoryValue(YulString _key) const
 | 
					std::optional<YulString> DataFlowAnalyzer::memoryValue(YulString _key) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (YulString const* value = valueOrNullptr(m_state.environment.memory, _key))
 | 
						if (YulString const* value = valueOrNullptr(m_state.environment.memory, _key))
 | 
				
			||||||
		return *value;
 | 
							return *value;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<YulString> DataFlowAnalyzer::keccakValue(YulString _start, YulString _length) const
 | 
					std::optional<YulString> DataFlowAnalyzer::keccakValue(YulString _start, YulString _length) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (YulString const* value = valueOrNullptr(m_state.environment.keccak, make_pair(_start, _length)))
 | 
						if (YulString const* value = valueOrNullptr(m_state.environment.keccak, std::make_pair(_start, _length)))
 | 
				
			||||||
		return *value;
 | 
							return *value;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expression* _value, bool _isDeclaration)
 | 
					void DataFlowAnalyzer::handleAssignment(std::set<YulString> const& _variables, Expression* _value, bool _isDeclaration)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!_isDeclaration)
 | 
						if (!_isDeclaration)
 | 
				
			||||||
		clearValues(_variables);
 | 
							clearValues(_variables);
 | 
				
			||||||
@ -321,7 +320,7 @@ void DataFlowAnalyzer::popScope()
 | 
				
			|||||||
	m_variableScopes.pop_back();
 | 
						m_variableScopes.pop_back();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DataFlowAnalyzer::clearValues(set<YulString> _variables)
 | 
					void DataFlowAnalyzer::clearValues(std::set<YulString> _variables)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// All variables that reference variables to be cleared also have to be
 | 
						// All variables that reference variables to be cleared also have to be
 | 
				
			||||||
	// cleared, but not recursively, since only the value of the original
 | 
						// cleared, but not recursively, since only the value of the original
 | 
				
			||||||
@ -410,24 +409,24 @@ bool DataFlowAnalyzer::inScope(YulString _variableName) const
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<u256> DataFlowAnalyzer::valueOfIdentifier(YulString const& _name) const
 | 
					std::optional<u256> DataFlowAnalyzer::valueOfIdentifier(YulString const& _name) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (AssignedValue const* value = variableValue(_name))
 | 
						if (AssignedValue const* value = variableValue(_name))
 | 
				
			||||||
		if (Literal const* literal = get_if<Literal>(value->value))
 | 
							if (Literal const* literal = std::get_if<Literal>(value->value))
 | 
				
			||||||
			return valueOfLiteral(*literal);
 | 
								return valueOfLiteral(*literal);
 | 
				
			||||||
	return nullopt;
 | 
						return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<pair<YulString, YulString>> DataFlowAnalyzer::isSimpleStore(
 | 
					std::optional<std::pair<YulString, YulString>> DataFlowAnalyzer::isSimpleStore(
 | 
				
			||||||
	StoreLoadLocation _location,
 | 
						StoreLoadLocation _location,
 | 
				
			||||||
	ExpressionStatement const& _statement
 | 
						ExpressionStatement const& _statement
 | 
				
			||||||
) const
 | 
					) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (FunctionCall const* funCall = get_if<FunctionCall>(&_statement.expression))
 | 
						if (FunctionCall const* funCall = std::get_if<FunctionCall>(&_statement.expression))
 | 
				
			||||||
		if (funCall->functionName.name == m_storeFunctionName[static_cast<unsigned>(_location)])
 | 
							if (funCall->functionName.name == m_storeFunctionName[static_cast<unsigned>(_location)])
 | 
				
			||||||
			if (Identifier const* key = std::get_if<Identifier>(&funCall->arguments.front()))
 | 
								if (Identifier const* key = std::get_if<Identifier>(&funCall->arguments.front()))
 | 
				
			||||||
				if (Identifier const* value = std::get_if<Identifier>(&funCall->arguments.back()))
 | 
									if (Identifier const* value = std::get_if<Identifier>(&funCall->arguments.back()))
 | 
				
			||||||
					return make_pair(key->name, value->name);
 | 
										return std::make_pair(key->name, value->name);
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -436,21 +435,21 @@ std::optional<YulString> DataFlowAnalyzer::isSimpleLoad(
 | 
				
			|||||||
	Expression const& _expression
 | 
						Expression const& _expression
 | 
				
			||||||
) const
 | 
					) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (FunctionCall const* funCall = get_if<FunctionCall>(&_expression))
 | 
						if (FunctionCall const* funCall = std::get_if<FunctionCall>(&_expression))
 | 
				
			||||||
		if (funCall->functionName.name == m_loadFunctionName[static_cast<unsigned>(_location)])
 | 
							if (funCall->functionName.name == m_loadFunctionName[static_cast<unsigned>(_location)])
 | 
				
			||||||
			if (Identifier const* key = std::get_if<Identifier>(&funCall->arguments.front()))
 | 
								if (Identifier const* key = std::get_if<Identifier>(&funCall->arguments.front()))
 | 
				
			||||||
				return key->name;
 | 
									return key->name;
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<pair<YulString, YulString>> DataFlowAnalyzer::isKeccak(Expression const& _expression) const
 | 
					std::optional<std::pair<YulString, YulString>> DataFlowAnalyzer::isKeccak(Expression const& _expression) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (FunctionCall const* funCall = get_if<FunctionCall>(&_expression))
 | 
						if (FunctionCall const* funCall = std::get_if<FunctionCall>(&_expression))
 | 
				
			||||||
		if (funCall->functionName.name == m_dialect.hashFunction({}))
 | 
							if (funCall->functionName.name == m_dialect.hashFunction({}))
 | 
				
			||||||
			if (Identifier const* start = std::get_if<Identifier>(&funCall->arguments.at(0)))
 | 
								if (Identifier const* start = std::get_if<Identifier>(&funCall->arguments.at(0)))
 | 
				
			||||||
				if (Identifier const* length = std::get_if<Identifier>(&funCall->arguments.at(1)))
 | 
									if (Identifier const* length = std::get_if<Identifier>(&funCall->arguments.at(1)))
 | 
				
			||||||
					return make_pair(start->name, length->name);
 | 
										return std::make_pair(start->name, length->name);
 | 
				
			||||||
	return nullopt;
 | 
						return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DataFlowAnalyzer::joinKnowledge(Environment const& _olderEnvironment)
 | 
					void DataFlowAnalyzer::joinKnowledge(Environment const& _olderEnvironment)
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@
 | 
				
			|||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <limits>
 | 
					#include <limits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
@ -54,7 +53,7 @@ void DeadCodeEliminator::operator()(Block& _block)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	TerminationFinder::ControlFlow controlFlowChange;
 | 
						TerminationFinder::ControlFlow controlFlowChange;
 | 
				
			||||||
	size_t index;
 | 
						size_t index;
 | 
				
			||||||
	tie(controlFlowChange, index) = TerminationFinder{m_dialect, &m_functionSideEffects}.firstUnconditionalControlFlowChange(_block.statements);
 | 
						std::tie(controlFlowChange, index) = TerminationFinder{m_dialect, &m_functionSideEffects}.firstUnconditionalControlFlowChange(_block.statements);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Erase everything after the terminating statement that is not a function definition.
 | 
						// Erase everything after the terminating statement that is not a function definition.
 | 
				
			||||||
	if (controlFlowChange != TerminationFinder::ControlFlow::FlowOut && index != std::numeric_limits<size_t>::max())
 | 
						if (controlFlowChange != TerminationFinder::ControlFlow::FlowOut && index != std::numeric_limits<size_t>::max())
 | 
				
			||||||
@ -62,7 +61,7 @@ void DeadCodeEliminator::operator()(Block& _block)
 | 
				
			|||||||
			remove_if(
 | 
								remove_if(
 | 
				
			||||||
				_block.statements.begin() + static_cast<ptrdiff_t>(index) + 1,
 | 
									_block.statements.begin() + static_cast<ptrdiff_t>(index) + 1,
 | 
				
			||||||
				_block.statements.end(),
 | 
									_block.statements.end(),
 | 
				
			||||||
				[] (Statement const& _s) { return !holds_alternative<yul::FunctionDefinition>(_s); }
 | 
									[] (Statement const& _s) { return !std::holds_alternative<yul::FunctionDefinition>(_s); }
 | 
				
			||||||
			),
 | 
								),
 | 
				
			||||||
			_block.statements.end()
 | 
								_block.statements.end()
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,6 @@
 | 
				
			|||||||
#include <libyul/Exceptions.h>
 | 
					#include <libyul/Exceptions.h>
 | 
				
			||||||
#include <libyul/Scope.h>
 | 
					#include <libyul/Scope.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,6 @@
 | 
				
			|||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
#include <libyul/Utilities.h>
 | 
					#include <libyul/Utilities.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
using namespace solidity::evmasm;
 | 
					using namespace solidity::evmasm;
 | 
				
			||||||
@ -50,17 +49,17 @@ void EqualStoreEliminator::visit(Statement& _statement)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	// No need to consider potential changes through complex arguments since
 | 
						// No need to consider potential changes through complex arguments since
 | 
				
			||||||
	// isSimpleStore only returns something if the arguments are identifiers.
 | 
						// isSimpleStore only returns something if the arguments are identifiers.
 | 
				
			||||||
	if (ExpressionStatement const* expression = get_if<ExpressionStatement>(&_statement))
 | 
						if (ExpressionStatement const* expression = std::get_if<ExpressionStatement>(&_statement))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (auto vars = isSimpleStore(StoreLoadLocation::Storage, *expression))
 | 
							if (auto vars = isSimpleStore(StoreLoadLocation::Storage, *expression))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (optional<YulString> currentValue = storageValue(vars->first))
 | 
								if (std::optional<YulString> currentValue = storageValue(vars->first))
 | 
				
			||||||
				if (*currentValue == vars->second)
 | 
									if (*currentValue == vars->second)
 | 
				
			||||||
					m_pendingRemovals.insert(&_statement);
 | 
										m_pendingRemovals.insert(&_statement);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, *expression))
 | 
							else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, *expression))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (optional<YulString> currentValue = memoryValue(vars->first))
 | 
								if (std::optional<YulString> currentValue = memoryValue(vars->first))
 | 
				
			||||||
				if (*currentValue == vars->second)
 | 
									if (*currentValue == vars->second)
 | 
				
			||||||
					m_pendingRemovals.insert(&_statement);
 | 
										m_pendingRemovals.insert(&_statement);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,6 @@
 | 
				
			|||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
#include <libyul/optimiser/Metrics.h>
 | 
					#include <libyul/optimiser/Metrics.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -50,14 +49,14 @@ void ExpressionInliner::operator()(FunctionDefinition& _fun)
 | 
				
			|||||||
void ExpressionInliner::visit(Expression& _expression)
 | 
					void ExpressionInliner::visit(Expression& _expression)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ASTModifier::visit(_expression);
 | 
						ASTModifier::visit(_expression);
 | 
				
			||||||
	if (holds_alternative<FunctionCall>(_expression))
 | 
						if (std::holds_alternative<FunctionCall>(_expression))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		FunctionCall& funCall = std::get<FunctionCall>(_expression);
 | 
							FunctionCall& funCall = std::get<FunctionCall>(_expression);
 | 
				
			||||||
		if (!m_inlinableFunctions.count(funCall.functionName.name))
 | 
							if (!m_inlinableFunctions.count(funCall.functionName.name))
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name);
 | 
							FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		map<YulString, Expression const*> substitutions;
 | 
							std::map<YulString, Expression const*> substitutions;
 | 
				
			||||||
		for (size_t i = 0; i < funCall.arguments.size(); i++)
 | 
							for (size_t i = 0; i < funCall.arguments.size(); i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Expression const& arg = funCall.arguments[i];
 | 
								Expression const& arg = funCall.arguments[i];
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <limits>
 | 
					#include <limits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -66,7 +65,7 @@ void ExpressionJoiner::operator()(Block& _block)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void ExpressionJoiner::visit(Expression& _e)
 | 
					void ExpressionJoiner::visit(Expression& _e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<Identifier>(_e))
 | 
						if (std::holds_alternative<Identifier>(_e))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Identifier const& identifier = std::get<Identifier>(_e);
 | 
							Identifier const& identifier = std::get<Identifier>(_e);
 | 
				
			||||||
		if (isLatestStatementVarDeclJoinable(identifier))
 | 
							if (isLatestStatementVarDeclJoinable(identifier))
 | 
				
			||||||
@ -89,7 +88,7 @@ ExpressionJoiner::ExpressionJoiner(Block& _ast)
 | 
				
			|||||||
	m_references = VariableReferencesCounter::countReferences(_ast);
 | 
						m_references = VariableReferencesCounter::countReferences(_ast);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ExpressionJoiner::handleArguments(vector<Expression>& _arguments)
 | 
					void ExpressionJoiner::handleArguments(std::vector<Expression>& _arguments)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// We have to fill from left to right, but we can only
 | 
						// We have to fill from left to right, but we can only
 | 
				
			||||||
	// fill if everything to the right is just an identifier
 | 
						// fill if everything to the right is just an identifier
 | 
				
			||||||
@ -101,7 +100,7 @@ void ExpressionJoiner::handleArguments(vector<Expression>& _arguments)
 | 
				
			|||||||
	for (Expression const& arg: _arguments | ranges::views::reverse)
 | 
						for (Expression const& arg: _arguments | ranges::views::reverse)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		--i;
 | 
							--i;
 | 
				
			||||||
		if (!holds_alternative<Identifier>(arg) && !holds_alternative<Literal>(arg))
 | 
							if (!std::holds_alternative<Identifier>(arg) && !std::holds_alternative<Literal>(arg))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// i points to the last element that is neither an identifier nor a literal,
 | 
						// i points to the last element that is neither an identifier nor a literal,
 | 
				
			||||||
@ -124,7 +123,7 @@ void ExpressionJoiner::decrementLatestStatementPointer()
 | 
				
			|||||||
void ExpressionJoiner::resetLatestStatementPointer()
 | 
					void ExpressionJoiner::resetLatestStatementPointer()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_currentBlock = nullptr;
 | 
						m_currentBlock = nullptr;
 | 
				
			||||||
	m_latestStatementInBlock = numeric_limits<size_t>::max();
 | 
						m_latestStatementInBlock = std::numeric_limits<size_t>::max();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Statement* ExpressionJoiner::latestStatement()
 | 
					Statement* ExpressionJoiner::latestStatement()
 | 
				
			||||||
@ -138,7 +137,7 @@ Statement* ExpressionJoiner::latestStatement()
 | 
				
			|||||||
bool ExpressionJoiner::isLatestStatementVarDeclJoinable(Identifier const& _identifier)
 | 
					bool ExpressionJoiner::isLatestStatementVarDeclJoinable(Identifier const& _identifier)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Statement const* statement = latestStatement();
 | 
						Statement const* statement = latestStatement();
 | 
				
			||||||
	if (!statement || !holds_alternative<VariableDeclaration>(*statement))
 | 
						if (!statement || !std::holds_alternative<VariableDeclaration>(*statement))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	VariableDeclaration const& varDecl = std::get<VariableDeclaration>(*statement);
 | 
						VariableDeclaration const& varDecl = std::get<VariableDeclaration>(*statement);
 | 
				
			||||||
	if (varDecl.variables.size() != 1 || !varDecl.value)
 | 
						if (varDecl.variables.size() != 1 || !varDecl.value)
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libevmasm/SemanticInformation.h>
 | 
					#include <libevmasm/SemanticInformation.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -49,8 +48,8 @@ void ExpressionSimplifier::visit(Expression& _expression)
 | 
				
			|||||||
	))
 | 
						))
 | 
				
			||||||
		_expression = match->action().toExpression(debugDataOf(_expression), evmVersionFromDialect(m_dialect));
 | 
							_expression = match->action().toExpression(debugDataOf(_expression), evmVersionFromDialect(m_dialect));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (auto* functionCall = get_if<FunctionCall>(&_expression))
 | 
						if (auto* functionCall = std::get_if<FunctionCall>(&_expression))
 | 
				
			||||||
		if (optional<evmasm::Instruction> instruction = toEVMInstruction(m_dialect, functionCall->functionName.name))
 | 
							if (std::optional<evmasm::Instruction> instruction = toEVMInstruction(m_dialect, functionCall->functionName.name))
 | 
				
			||||||
			for (auto op: evmasm::SemanticInformation::readWriteOperations(*instruction))
 | 
								for (auto op: evmasm::SemanticInformation::readWriteOperations(*instruction))
 | 
				
			||||||
				if (op.startParameter && op.lengthParameter)
 | 
									if (op.startParameter && op.lengthParameter)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
@ -59,7 +58,7 @@ void ExpressionSimplifier::visit(Expression& _expression)
 | 
				
			|||||||
					if (
 | 
										if (
 | 
				
			||||||
						knownToBeZero(lengthArgument) &&
 | 
											knownToBeZero(lengthArgument) &&
 | 
				
			||||||
						!knownToBeZero(startArgument) &&
 | 
											!knownToBeZero(startArgument) &&
 | 
				
			||||||
						!holds_alternative<FunctionCall>(startArgument)
 | 
											!std::holds_alternative<FunctionCall>(startArgument)
 | 
				
			||||||
					)
 | 
										)
 | 
				
			||||||
						startArgument = Literal{debugDataOf(startArgument), LiteralKind::Number, "0"_yulstring, {}};
 | 
											startArgument = Literal{debugDataOf(startArgument), LiteralKind::Number, "0"_yulstring, {}};
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@ -67,9 +66,9 @@ void ExpressionSimplifier::visit(Expression& _expression)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool ExpressionSimplifier::knownToBeZero(Expression const& _expression) const
 | 
					bool ExpressionSimplifier::knownToBeZero(Expression const& _expression) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (auto const* literal = get_if<Literal>(&_expression))
 | 
						if (auto const* literal = std::get_if<Literal>(&_expression))
 | 
				
			||||||
		return valueOfLiteral(*literal) == 0;
 | 
							return valueOfLiteral(*literal) == 0;
 | 
				
			||||||
	else if (auto const* identifier = get_if<Identifier>(&_expression))
 | 
						else if (auto const* identifier = std::get_if<Identifier>(&_expression))
 | 
				
			||||||
		return valueOfIdentifier(identifier->name) == 0;
 | 
							return valueOfIdentifier(identifier->name) == 0;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
@ -75,11 +74,11 @@ void ExpressionSplitter::operator()(ForLoop& _loop)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void ExpressionSplitter::operator()(Block& _block)
 | 
					void ExpressionSplitter::operator()(Block& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vector<Statement> saved;
 | 
						std::vector<Statement> saved;
 | 
				
			||||||
	swap(saved, m_statementsToPrefix);
 | 
						swap(saved, m_statementsToPrefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function<std::optional<vector<Statement>>(Statement&)> f =
 | 
						std::function<std::optional<std::vector<Statement>>(Statement&)> f =
 | 
				
			||||||
			[&](Statement& _statement) -> std::optional<vector<Statement>> {
 | 
								[&](Statement& _statement) -> std::optional<std::vector<Statement>> {
 | 
				
			||||||
		m_statementsToPrefix.clear();
 | 
							m_statementsToPrefix.clear();
 | 
				
			||||||
		visit(_statement);
 | 
							visit(_statement);
 | 
				
			||||||
		if (m_statementsToPrefix.empty())
 | 
							if (m_statementsToPrefix.empty())
 | 
				
			||||||
@ -94,18 +93,18 @@ void ExpressionSplitter::operator()(Block& _block)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void ExpressionSplitter::outlineExpression(Expression& _expr)
 | 
					void ExpressionSplitter::outlineExpression(Expression& _expr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<Identifier>(_expr))
 | 
						if (std::holds_alternative<Identifier>(_expr))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	visit(_expr);
 | 
						visit(_expr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	shared_ptr<DebugData const> debugData = debugDataOf(_expr);
 | 
						std::shared_ptr<DebugData const> debugData = debugDataOf(_expr);
 | 
				
			||||||
	YulString var = m_nameDispenser.newName({});
 | 
						YulString var = m_nameDispenser.newName({});
 | 
				
			||||||
	YulString type = m_typeInfo.typeOf(_expr);
 | 
						YulString type = m_typeInfo.typeOf(_expr);
 | 
				
			||||||
	m_statementsToPrefix.emplace_back(VariableDeclaration{
 | 
						m_statementsToPrefix.emplace_back(VariableDeclaration{
 | 
				
			||||||
		debugData,
 | 
							debugData,
 | 
				
			||||||
		{{TypedName{debugData, var, type}}},
 | 
							{{TypedName{debugData, var, type}}},
 | 
				
			||||||
		make_unique<Expression>(std::move(_expr))
 | 
							std::make_unique<Expression>(std::move(_expr))
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	_expr = Identifier{debugData, var};
 | 
						_expr = Identifier{debugData, var};
 | 
				
			||||||
	m_typeInfo.setVariableType(var, type);
 | 
						m_typeInfo.setVariableType(var, type);
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -35,17 +34,17 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (
 | 
						if (
 | 
				
			||||||
		m_dialect.booleanNegationFunction() &&
 | 
							m_dialect.booleanNegationFunction() &&
 | 
				
			||||||
		!holds_alternative<Literal>(*_forLoop.condition) &&
 | 
							!std::holds_alternative<Literal>(*_forLoop.condition) &&
 | 
				
			||||||
		!holds_alternative<Identifier>(*_forLoop.condition)
 | 
							!std::holds_alternative<Identifier>(*_forLoop.condition)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		shared_ptr<DebugData const> debugData = debugDataOf(*_forLoop.condition);
 | 
							std::shared_ptr<DebugData const> debugData = debugDataOf(*_forLoop.condition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_forLoop.body.statements.emplace(
 | 
							_forLoop.body.statements.emplace(
 | 
				
			||||||
			begin(_forLoop.body.statements),
 | 
								begin(_forLoop.body.statements),
 | 
				
			||||||
			If {
 | 
								If {
 | 
				
			||||||
				debugData,
 | 
									debugData,
 | 
				
			||||||
				make_unique<Expression>(
 | 
									std::make_unique<Expression>(
 | 
				
			||||||
					FunctionCall {
 | 
										FunctionCall {
 | 
				
			||||||
						debugData,
 | 
											debugData,
 | 
				
			||||||
						{debugData, m_dialect.booleanNegationFunction()->name},
 | 
											{debugData, m_dialect.booleanNegationFunction()->name},
 | 
				
			||||||
@ -55,7 +54,7 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
 | 
				
			|||||||
				Block {debugData, util::make_vector<Statement>(Break{{}})}
 | 
									Block {debugData, util::make_vector<Statement>(Break{{}})}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		_forLoop.condition = make_unique<Expression>(
 | 
							_forLoop.condition = std::make_unique<Expression>(
 | 
				
			||||||
			Literal {
 | 
								Literal {
 | 
				
			||||||
				debugData,
 | 
									debugData,
 | 
				
			||||||
				LiteralKind::Boolean,
 | 
									LiteralKind::Boolean,
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,32 +37,32 @@ void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (
 | 
						if (
 | 
				
			||||||
		!m_dialect.booleanNegationFunction() ||
 | 
							!m_dialect.booleanNegationFunction() ||
 | 
				
			||||||
		!holds_alternative<Literal>(*_forLoop.condition) ||
 | 
							!std::holds_alternative<Literal>(*_forLoop.condition) ||
 | 
				
			||||||
		valueOfLiteral(std::get<Literal>(*_forLoop.condition)) == u256(0) ||
 | 
							valueOfLiteral(std::get<Literal>(*_forLoop.condition)) == u256(0) ||
 | 
				
			||||||
		_forLoop.body.statements.empty() ||
 | 
							_forLoop.body.statements.empty() ||
 | 
				
			||||||
		!holds_alternative<If>(_forLoop.body.statements.front())
 | 
							!std::holds_alternative<If>(_forLoop.body.statements.front())
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	If& firstStatement = std::get<If>(_forLoop.body.statements.front());
 | 
						If& firstStatement = std::get<If>(_forLoop.body.statements.front());
 | 
				
			||||||
	if (
 | 
						if (
 | 
				
			||||||
		firstStatement.body.statements.empty() ||
 | 
							firstStatement.body.statements.empty() ||
 | 
				
			||||||
		!holds_alternative<Break>(firstStatement.body.statements.front())
 | 
							!std::holds_alternative<Break>(firstStatement.body.statements.front())
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	if (!SideEffectsCollector(m_dialect, *firstStatement.condition).movable())
 | 
						if (!SideEffectsCollector(m_dialect, *firstStatement.condition).movable())
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	YulString iszero = m_dialect.booleanNegationFunction()->name;
 | 
						YulString iszero = m_dialect.booleanNegationFunction()->name;
 | 
				
			||||||
	shared_ptr<DebugData const> debugData = debugDataOf(*firstStatement.condition);
 | 
						std::shared_ptr<DebugData const> debugData = debugDataOf(*firstStatement.condition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (
 | 
						if (
 | 
				
			||||||
		holds_alternative<FunctionCall>(*firstStatement.condition) &&
 | 
							std::holds_alternative<FunctionCall>(*firstStatement.condition) &&
 | 
				
			||||||
		std::get<FunctionCall>(*firstStatement.condition).functionName.name == iszero
 | 
							std::get<FunctionCall>(*firstStatement.condition).functionName.name == iszero
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
		_forLoop.condition = make_unique<Expression>(std::move(std::get<FunctionCall>(*firstStatement.condition).arguments.front()));
 | 
							_forLoop.condition = std::make_unique<Expression>(std::move(std::get<FunctionCall>(*firstStatement.condition).arguments.front()));
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		_forLoop.condition = make_unique<Expression>(FunctionCall{
 | 
							_forLoop.condition = std::make_unique<Expression>(FunctionCall{
 | 
				
			||||||
			debugData,
 | 
								debugData,
 | 
				
			||||||
			Identifier{debugData, iszero},
 | 
								Identifier{debugData, iszero},
 | 
				
			||||||
			util::make_vector<Expression>(
 | 
								util::make_vector<Expression>(
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,15 +29,15 @@ void ForLoopInitRewriter::operator()(Block& _block)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	util::iterateReplacing(
 | 
						util::iterateReplacing(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[&](Statement& _stmt) -> std::optional<vector<Statement>>
 | 
							[&](Statement& _stmt) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (holds_alternative<ForLoop>(_stmt))
 | 
								if (std::holds_alternative<ForLoop>(_stmt))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				auto& forLoop = std::get<ForLoop>(_stmt);
 | 
									auto& forLoop = std::get<ForLoop>(_stmt);
 | 
				
			||||||
				(*this)(forLoop.pre);
 | 
									(*this)(forLoop.pre);
 | 
				
			||||||
				(*this)(forLoop.body);
 | 
									(*this)(forLoop.body);
 | 
				
			||||||
				(*this)(forLoop.post);
 | 
									(*this)(forLoop.post);
 | 
				
			||||||
				vector<Statement> rewrite;
 | 
									std::vector<Statement> rewrite;
 | 
				
			||||||
				swap(rewrite, forLoop.pre.statements);
 | 
									swap(rewrite, forLoop.pre.statements);
 | 
				
			||||||
				rewrite.emplace_back(std::move(forLoop));
 | 
									rewrite.emplace_back(std::move(forLoop));
 | 
				
			||||||
				return { std::move(rewrite) };
 | 
									return { std::move(rewrite) };
 | 
				
			||||||
 | 
				
			|||||||
@ -41,7 +41,6 @@
 | 
				
			|||||||
#include <range/v3/view/reverse.hpp>
 | 
					#include <range/v3/view/reverse.hpp>
 | 
				
			||||||
#include <range/v3/view/zip.hpp>
 | 
					#include <range/v3/view/zip.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -63,15 +62,15 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const&
 | 
				
			|||||||
	SSAValueTracker tracker;
 | 
						SSAValueTracker tracker;
 | 
				
			||||||
	tracker(m_ast);
 | 
						tracker(m_ast);
 | 
				
			||||||
	for (auto const& ssaValue: tracker.values())
 | 
						for (auto const& ssaValue: tracker.values())
 | 
				
			||||||
		if (ssaValue.second && holds_alternative<Literal>(*ssaValue.second))
 | 
							if (ssaValue.second && std::holds_alternative<Literal>(*ssaValue.second))
 | 
				
			||||||
			m_constants.emplace(ssaValue.first);
 | 
								m_constants.emplace(ssaValue.first);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Store size of global statements.
 | 
						// Store size of global statements.
 | 
				
			||||||
	m_functionSizes[YulString{}] = CodeSize::codeSize(_ast);
 | 
						m_functionSizes[YulString{}] = CodeSize::codeSize(_ast);
 | 
				
			||||||
	map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast);
 | 
						std::map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast);
 | 
				
			||||||
	for (auto& statement: m_ast.statements)
 | 
						for (auto& statement: m_ast.statements)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (!holds_alternative<FunctionDefinition>(statement))
 | 
							if (!std::holds_alternative<FunctionDefinition>(statement))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		FunctionDefinition& fun = std::get<FunctionDefinition>(statement);
 | 
							FunctionDefinition& fun = std::get<FunctionDefinition>(statement);
 | 
				
			||||||
		m_functions[fun.name] = &fun;
 | 
							m_functions[fun.name] = &fun;
 | 
				
			||||||
@ -84,7 +83,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const&
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check for memory guard.
 | 
						// Check for memory guard.
 | 
				
			||||||
	vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
 | 
						std::vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
 | 
				
			||||||
		_ast,
 | 
							_ast,
 | 
				
			||||||
		"memoryguard"_yulstring
 | 
							"memoryguard"_yulstring
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
@ -105,10 +104,10 @@ void FullInliner::run(Pass _pass)
 | 
				
			|||||||
	// function name) order.
 | 
						// function name) order.
 | 
				
			||||||
	// We use stable_sort below to keep the inlining order of two functions
 | 
						// We use stable_sort below to keep the inlining order of two functions
 | 
				
			||||||
	// with the same depth.
 | 
						// with the same depth.
 | 
				
			||||||
	map<YulString, size_t> depths = callDepths();
 | 
						std::map<YulString, size_t> depths = callDepths();
 | 
				
			||||||
	vector<FunctionDefinition*> functions;
 | 
						std::vector<FunctionDefinition*> functions;
 | 
				
			||||||
	for (auto& statement: m_ast.statements)
 | 
						for (auto& statement: m_ast.statements)
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(statement))
 | 
							if (std::holds_alternative<FunctionDefinition>(statement))
 | 
				
			||||||
			functions.emplace_back(&std::get<FunctionDefinition>(statement));
 | 
								functions.emplace_back(&std::get<FunctionDefinition>(statement));
 | 
				
			||||||
	std::stable_sort(functions.begin(), functions.end(), [depths](
 | 
						std::stable_sort(functions.begin(), functions.end(), [depths](
 | 
				
			||||||
		FunctionDefinition const* _a,
 | 
							FunctionDefinition const* _a,
 | 
				
			||||||
@ -123,11 +122,11 @@ void FullInliner::run(Pass _pass)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto& statement: m_ast.statements)
 | 
						for (auto& statement: m_ast.statements)
 | 
				
			||||||
		if (holds_alternative<Block>(statement))
 | 
							if (std::holds_alternative<Block>(statement))
 | 
				
			||||||
			handleBlock({}, std::get<Block>(statement));
 | 
								handleBlock({}, std::get<Block>(statement));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, size_t> FullInliner::callDepths() const
 | 
					std::map<YulString, size_t> FullInliner::callDepths() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	CallGraph cg = CallGraphGenerator::callGraph(m_ast);
 | 
						CallGraph cg = CallGraphGenerator::callGraph(m_ast);
 | 
				
			||||||
	cg.functionCalls.erase(""_yulstring);
 | 
						cg.functionCalls.erase(""_yulstring);
 | 
				
			||||||
@ -140,12 +139,12 @@ map<YulString, size_t> FullInliner::callDepths() const
 | 
				
			|||||||
			else
 | 
								else
 | 
				
			||||||
				++it;
 | 
									++it;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map<YulString, size_t> depths;
 | 
						std::map<YulString, size_t> depths;
 | 
				
			||||||
	size_t currentDepth = 0;
 | 
						size_t currentDepth = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (true)
 | 
						while (true)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		vector<YulString> removed;
 | 
							std::vector<YulString> removed;
 | 
				
			||||||
		for (auto it = cg.functionCalls.begin(); it != cg.functionCalls.end();)
 | 
							for (auto it = cg.functionCalls.begin(); it != cg.functionCalls.end();)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto const& [fun, callees] = *it;
 | 
								auto const& [fun, callees] = *it;
 | 
				
			||||||
@ -192,7 +191,7 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
 | 
				
			|||||||
	// No inlining of calls where argument expressions may have side-effects.
 | 
						// No inlining of calls where argument expressions may have side-effects.
 | 
				
			||||||
	// To avoid running into this, make sure that ExpressionSplitter runs before FullInliner.
 | 
						// To avoid running into this, make sure that ExpressionSplitter runs before FullInliner.
 | 
				
			||||||
	for (auto const& argument: _funCall.arguments)
 | 
						for (auto const& argument: _funCall.arguments)
 | 
				
			||||||
		if (!holds_alternative<Literal>(argument) && !holds_alternative<Identifier>(argument))
 | 
							if (!std::holds_alternative<Literal>(argument) && !std::holds_alternative<Identifier>(argument))
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Inline really, really tiny functions
 | 
						// Inline really, really tiny functions
 | 
				
			||||||
@ -226,8 +225,8 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
 | 
				
			|||||||
	// Constant arguments might provide a means for further optimization, so they cause a bonus.
 | 
						// Constant arguments might provide a means for further optimization, so they cause a bonus.
 | 
				
			||||||
	bool constantArg = false;
 | 
						bool constantArg = false;
 | 
				
			||||||
	for (auto const& argument: _funCall.arguments)
 | 
						for (auto const& argument: _funCall.arguments)
 | 
				
			||||||
		if (holds_alternative<Literal>(argument) || (
 | 
							if (std::holds_alternative<Literal>(argument) || (
 | 
				
			||||||
			holds_alternative<Identifier>(argument) &&
 | 
								std::holds_alternative<Identifier>(argument) &&
 | 
				
			||||||
			m_constants.count(std::get<Identifier>(argument).name)
 | 
								m_constants.count(std::get<Identifier>(argument).name)
 | 
				
			||||||
		))
 | 
							))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -255,20 +254,20 @@ void FullInliner::handleBlock(YulString _currentFunctionName, Block& _block)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool FullInliner::recursive(FunctionDefinition const& _fun) const
 | 
					bool FullInliner::recursive(FunctionDefinition const& _fun) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	map<YulString, size_t> references = ReferencesCounter::countReferences(_fun);
 | 
						std::map<YulString, size_t> references = ReferencesCounter::countReferences(_fun);
 | 
				
			||||||
	return references[_fun.name] > 0;
 | 
						return references[_fun.name] > 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InlineModifier::operator()(Block& _block)
 | 
					void InlineModifier::operator()(Block& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	function<std::optional<vector<Statement>>(Statement&)> f = [&](Statement& _statement) -> std::optional<vector<Statement>> {
 | 
						std::function<std::optional<std::vector<Statement>>(Statement&)> f = [&](Statement& _statement) -> std::optional<std::vector<Statement>> {
 | 
				
			||||||
		visit(_statement);
 | 
							visit(_statement);
 | 
				
			||||||
		return tryInlineStatement(_statement);
 | 
							return tryInlineStatement(_statement);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	util::iterateReplacing(_block.statements, f);
 | 
						util::iterateReplacing(_block.statements, f);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _statement)
 | 
					std::optional<std::vector<Statement>> InlineModifier::tryInlineStatement(Statement& _statement)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// Only inline for expression statements, assignments and variable declarations.
 | 
						// Only inline for expression statements, assignments and variable declarations.
 | 
				
			||||||
	Expression* e = std::visit(util::GenericVisitor{
 | 
						Expression* e = std::visit(util::GenericVisitor{
 | 
				
			||||||
@ -290,10 +289,10 @@ std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _
 | 
				
			|||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionCall& _funCall)
 | 
					std::vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionCall& _funCall)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vector<Statement> newStatements;
 | 
						std::vector<Statement> newStatements;
 | 
				
			||||||
	map<YulString, YulString> variableReplacements;
 | 
						std::map<YulString, YulString> variableReplacements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FunctionDefinition* function = m_driver.function(_funCall.functionName.name);
 | 
						FunctionDefinition* function = m_driver.function(_funCall.functionName.name);
 | 
				
			||||||
	assertThrow(!!function, OptimizerException, "Attempt to inline invalid function.");
 | 
						assertThrow(!!function, OptimizerException, "Attempt to inline invalid function.");
 | 
				
			||||||
@ -307,9 +306,9 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC
 | 
				
			|||||||
		variableReplacements[_existingVariable.name] = newName;
 | 
							variableReplacements[_existingVariable.name] = newName;
 | 
				
			||||||
		VariableDeclaration varDecl{_funCall.debugData, {{_funCall.debugData, newName, _existingVariable.type}}, {}};
 | 
							VariableDeclaration varDecl{_funCall.debugData, {{_funCall.debugData, newName, _existingVariable.type}}, {}};
 | 
				
			||||||
		if (_value)
 | 
							if (_value)
 | 
				
			||||||
			varDecl.value = make_unique<Expression>(std::move(*_value));
 | 
								varDecl.value = std::make_unique<Expression>(std::move(*_value));
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			varDecl.value = make_unique<Expression>(m_dialect.zeroLiteralForType(varDecl.variables.front().type));
 | 
								varDecl.value = std::make_unique<Expression>(m_dialect.zeroLiteralForType(varDecl.variables.front().type));
 | 
				
			||||||
		newStatements.emplace_back(std::move(varDecl));
 | 
							newStatements.emplace_back(std::move(varDecl));
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -329,7 +328,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC
 | 
				
			|||||||
				newStatements.emplace_back(Assignment{
 | 
									newStatements.emplace_back(Assignment{
 | 
				
			||||||
					_assignment.debugData,
 | 
										_assignment.debugData,
 | 
				
			||||||
					{_assignment.variableNames[i]},
 | 
										{_assignment.variableNames[i]},
 | 
				
			||||||
					make_unique<Expression>(Identifier{
 | 
										std::make_unique<Expression>(Identifier{
 | 
				
			||||||
						_assignment.debugData,
 | 
											_assignment.debugData,
 | 
				
			||||||
						variableReplacements.at(function->returnVariables[i].name)
 | 
											variableReplacements.at(function->returnVariables[i].name)
 | 
				
			||||||
					})
 | 
										})
 | 
				
			||||||
@ -341,7 +340,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC
 | 
				
			|||||||
				newStatements.emplace_back(VariableDeclaration{
 | 
									newStatements.emplace_back(VariableDeclaration{
 | 
				
			||||||
					_varDecl.debugData,
 | 
										_varDecl.debugData,
 | 
				
			||||||
					{std::move(_varDecl.variables[i])},
 | 
										{std::move(_varDecl.variables[i])},
 | 
				
			||||||
					make_unique<Expression>(Identifier{
 | 
										std::make_unique<Expression>(Identifier{
 | 
				
			||||||
						_varDecl.debugData,
 | 
											_varDecl.debugData,
 | 
				
			||||||
						variableReplacements.at(function->returnVariables[i].name)
 | 
											variableReplacements.at(function->returnVariables[i].name)
 | 
				
			||||||
					})
 | 
										})
 | 
				
			||||||
 | 
				
			|||||||
@ -18,11 +18,10 @@
 | 
				
			|||||||
#include <libyul/optimiser/FunctionCallFinder.h>
 | 
					#include <libyul/optimiser/FunctionCallFinder.h>
 | 
				
			||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vector<FunctionCall*> FunctionCallFinder::run(Block& _block, YulString _functionName)
 | 
					std::vector<FunctionCall*> FunctionCallFinder::run(Block& _block, YulString _functionName)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FunctionCallFinder functionCallFinder(_functionName);
 | 
						FunctionCallFinder functionCallFinder(_functionName);
 | 
				
			||||||
	functionCallFinder(_block);
 | 
						functionCallFinder(_block);
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -34,12 +33,12 @@ void FunctionGrouper::operator()(Block& _block)
 | 
				
			|||||||
	if (alreadyGrouped(_block))
 | 
						if (alreadyGrouped(_block))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vector<Statement> reordered;
 | 
						std::vector<Statement> reordered;
 | 
				
			||||||
	reordered.emplace_back(Block{_block.debugData, {}});
 | 
						reordered.emplace_back(Block{_block.debugData, {}});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto&& statement: _block.statements)
 | 
						for (auto&& statement: _block.statements)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(statement))
 | 
							if (std::holds_alternative<FunctionDefinition>(statement))
 | 
				
			||||||
			reordered.emplace_back(std::move(statement));
 | 
								reordered.emplace_back(std::move(statement));
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			std::get<Block>(reordered.front()).statements.emplace_back(std::move(statement));
 | 
								std::get<Block>(reordered.front()).statements.emplace_back(std::move(statement));
 | 
				
			||||||
@ -51,10 +50,10 @@ bool FunctionGrouper::alreadyGrouped(Block const& _block)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (_block.statements.empty())
 | 
						if (_block.statements.empty())
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (!holds_alternative<Block>(_block.statements.front()))
 | 
						if (!std::holds_alternative<Block>(_block.statements.front()))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	for (size_t i = 1; i < _block.statements.size(); ++i)
 | 
						for (size_t i = 1; i < _block.statements.size(); ++i)
 | 
				
			||||||
		if (!holds_alternative<FunctionDefinition>(_block.statements.at(i)))
 | 
							if (!std::holds_alternative<FunctionDefinition>(_block.statements.at(i)))
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,7 +37,7 @@ void FunctionHoister::operator()(Block& _block)
 | 
				
			|||||||
	for (auto&& statement: _block.statements)
 | 
						for (auto&& statement: _block.statements)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		std::visit(*this, statement);
 | 
							std::visit(*this, statement);
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(statement))
 | 
							if (std::holds_alternative<FunctionDefinition>(statement))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			m_functions.emplace_back(std::move(statement));
 | 
								m_functions.emplace_back(std::move(statement));
 | 
				
			||||||
			statement = Block{_block.debugData, {}};
 | 
								statement = Block{_block.debugData, {}};
 | 
				
			||||||
 | 
				
			|||||||
@ -32,7 +32,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <variant>
 | 
					#include <variant>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -40,11 +39,11 @@ FunctionSpecializer::LiteralArguments FunctionSpecializer::specializableArgument
 | 
				
			|||||||
	FunctionCall const& _f
 | 
						FunctionCall const& _f
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto heuristic = [&](Expression const& _e) -> optional<Expression>
 | 
						auto heuristic = [&](Expression const& _e) -> std::optional<Expression>
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (holds_alternative<Literal>(_e))
 | 
							if (std::holds_alternative<Literal>(_e))
 | 
				
			||||||
			return ASTCopier{}.translate(_e);
 | 
								return ASTCopier{}.translate(_e);
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return applyMap(_f.arguments, heuristic);
 | 
						return applyMap(_f.arguments, heuristic);
 | 
				
			||||||
@ -68,7 +67,7 @@ void FunctionSpecializer::operator()(FunctionCall& _f)
 | 
				
			|||||||
		YulString oldName = std::move(_f.functionName.name);
 | 
							YulString oldName = std::move(_f.functionName.name);
 | 
				
			||||||
		auto newName = m_nameDispenser.newName(oldName);
 | 
							auto newName = m_nameDispenser.newName(oldName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m_oldToNewMap[oldName].emplace_back(make_pair(newName, arguments));
 | 
							m_oldToNewMap[oldName].emplace_back(std::make_pair(newName, arguments));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_f.functionName.name = newName;
 | 
							_f.functionName.name = newName;
 | 
				
			||||||
		_f.arguments = util::filter(
 | 
							_f.arguments = util::filter(
 | 
				
			||||||
@ -86,27 +85,27 @@ FunctionDefinition FunctionSpecializer::specialize(
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	yulAssert(_arguments.size() == _f.parameters.size(), "");
 | 
						yulAssert(_arguments.size() == _f.parameters.size(), "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map<YulString, YulString> translatedNames = applyMap(
 | 
						std::map<YulString, YulString> translatedNames = applyMap(
 | 
				
			||||||
		NameCollector{_f, NameCollector::OnlyVariables}.names(),
 | 
							NameCollector{_f, NameCollector::OnlyVariables}.names(),
 | 
				
			||||||
		[&](auto& _name) -> pair<YulString, YulString>
 | 
							[&](auto& _name) -> std::pair<YulString, YulString>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return make_pair(_name, m_nameDispenser.newName(_name));
 | 
								return std::make_pair(_name, m_nameDispenser.newName(_name));
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		map<YulString, YulString>{}
 | 
							std::map<YulString, YulString>{}
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FunctionDefinition newFunction = get<FunctionDefinition>(FunctionCopier{translatedNames}(_f));
 | 
						FunctionDefinition newFunction = std::get<FunctionDefinition>(FunctionCopier{translatedNames}(_f));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Function parameters that will be specialized inside the body are converted into variable
 | 
						// Function parameters that will be specialized inside the body are converted into variable
 | 
				
			||||||
	// declarations.
 | 
						// declarations.
 | 
				
			||||||
	vector<Statement> missingVariableDeclarations;
 | 
						std::vector<Statement> missingVariableDeclarations;
 | 
				
			||||||
	for (auto&& [index, argument]: _arguments | ranges::views::enumerate)
 | 
						for (auto&& [index, argument]: _arguments | ranges::views::enumerate)
 | 
				
			||||||
		if (argument)
 | 
							if (argument)
 | 
				
			||||||
			missingVariableDeclarations.emplace_back(
 | 
								missingVariableDeclarations.emplace_back(
 | 
				
			||||||
				VariableDeclaration{
 | 
									VariableDeclaration{
 | 
				
			||||||
					_f.debugData,
 | 
										_f.debugData,
 | 
				
			||||||
					vector<TypedName>{newFunction.parameters[index]},
 | 
										std::vector<TypedName>{newFunction.parameters[index]},
 | 
				
			||||||
					make_unique<Expression>(std::move(*argument))
 | 
										std::make_unique<Expression>(std::move(*argument))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -134,15 +133,15 @@ void FunctionSpecializer::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
	f(_ast);
 | 
						f(_ast);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iterateReplacing(_ast.statements, [&](Statement& _s) -> optional<vector<Statement>>
 | 
						iterateReplacing(_ast.statements, [&](Statement& _s) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(_s))
 | 
							if (std::holds_alternative<FunctionDefinition>(_s))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto& functionDefinition = get<FunctionDefinition>(_s);
 | 
								auto& functionDefinition = std::get<FunctionDefinition>(_s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (f.m_oldToNewMap.count(functionDefinition.name))
 | 
								if (f.m_oldToNewMap.count(functionDefinition.name))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				vector<Statement> out = applyMap(
 | 
									std::vector<Statement> out = applyMap(
 | 
				
			||||||
					f.m_oldToNewMap.at(functionDefinition.name),
 | 
										f.m_oldToNewMap.at(functionDefinition.name),
 | 
				
			||||||
					[&](auto& _p) -> Statement
 | 
										[&](auto& _p) -> Statement
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@ -153,6 +152,6 @@ void FunctionSpecializer::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,6 @@
 | 
				
			|||||||
#include <libyul/optimiser/OptimizerUtilities.h>
 | 
					#include <libyul/optimiser/OptimizerUtilities.h>
 | 
				
			||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -46,7 +45,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		YulString retVariable = _function.returnVariables.front().name;
 | 
							YulString retVariable = _function.returnVariables.front().name;
 | 
				
			||||||
		Statement const& bodyStatement = _function.body.statements.front();
 | 
							Statement const& bodyStatement = _function.body.statements.front();
 | 
				
			||||||
		if (holds_alternative<Assignment>(bodyStatement))
 | 
							if (std::holds_alternative<Assignment>(bodyStatement))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Assignment const& assignment = std::get<Assignment>(bodyStatement);
 | 
								Assignment const& assignment = std::get<Assignment>(bodyStatement);
 | 
				
			||||||
			if (assignment.variableNames.size() == 1 && assignment.variableNames.front().name == retVariable)
 | 
								if (assignment.variableNames.size() == 1 && assignment.variableNames.front().name == retVariable)
 | 
				
			||||||
@ -57,7 +56,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
 | 
				
			|||||||
				// would not be valid here if we were searching inside a functionally inlinable
 | 
									// would not be valid here if we were searching inside a functionally inlinable
 | 
				
			||||||
				// function body.
 | 
									// function body.
 | 
				
			||||||
				assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, "");
 | 
									assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, "");
 | 
				
			||||||
				m_disallowedIdentifiers = set<YulString>{retVariable, _function.name};
 | 
									m_disallowedIdentifiers = std::set<YulString>{retVariable, _function.name};
 | 
				
			||||||
				std::visit(*this, *assignment.value);
 | 
									std::visit(*this, *assignment.value);
 | 
				
			||||||
				if (!m_foundDisallowedIdentifier)
 | 
									if (!m_foundDisallowedIdentifier)
 | 
				
			||||||
					m_inlinableFunctions[_function.name] = &_function;
 | 
										m_inlinableFunctions[_function.name] = &_function;
 | 
				
			||||||
 | 
				
			|||||||
@ -29,36 +29,35 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <variant>
 | 
					#include <variant>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
KnowledgeBase::KnowledgeBase(map<YulString, AssignedValue> const& _ssaValues):
 | 
					KnowledgeBase::KnowledgeBase(std::map<YulString, AssignedValue> const& _ssaValues):
 | 
				
			||||||
	m_valuesAreSSA(true),
 | 
						m_valuesAreSSA(true),
 | 
				
			||||||
	m_variableValues([_ssaValues](YulString _var) { return util::valueOrNullptr(_ssaValues, _var); })
 | 
						m_variableValues([_ssaValues](YulString _var) { return util::valueOrNullptr(_ssaValues, _var); })
 | 
				
			||||||
{}
 | 
					{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b)
 | 
					bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (optional<u256> difference = differenceIfKnownConstant(_a, _b))
 | 
						if (std::optional<u256> difference = differenceIfKnownConstant(_a, _b))
 | 
				
			||||||
		return difference != 0;
 | 
							return difference != 0;
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<u256> KnowledgeBase::differenceIfKnownConstant(YulString _a, YulString _b)
 | 
					std::optional<u256> KnowledgeBase::differenceIfKnownConstant(YulString _a, YulString _b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	VariableOffset offA = explore(_a);
 | 
						VariableOffset offA = explore(_a);
 | 
				
			||||||
	VariableOffset offB = explore(_b);
 | 
						VariableOffset offB = explore(_b);
 | 
				
			||||||
	if (offA.reference == offB.reference)
 | 
						if (offA.reference == offB.reference)
 | 
				
			||||||
		return offA.offset - offB.offset;
 | 
							return offA.offset - offB.offset;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool KnowledgeBase::knownToBeDifferentByAtLeast32(YulString _a, YulString _b)
 | 
					bool KnowledgeBase::knownToBeDifferentByAtLeast32(YulString _a, YulString _b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (optional<u256> difference = differenceIfKnownConstant(_a, _b))
 | 
						if (std::optional<u256> difference = differenceIfKnownConstant(_a, _b))
 | 
				
			||||||
		return difference >= 32 && difference <= u256(0) - 32;
 | 
							return difference >= 32 && difference <= u256(0) - 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
@ -69,19 +68,19 @@ bool KnowledgeBase::knownToBeZero(YulString _a)
 | 
				
			|||||||
	return valueIfKnownConstant(_a) == 0;
 | 
						return valueIfKnownConstant(_a) == 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<u256> KnowledgeBase::valueIfKnownConstant(YulString _a)
 | 
					std::optional<u256> KnowledgeBase::valueIfKnownConstant(YulString _a)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return explore(_a).absoluteValue();
 | 
						return explore(_a).absoluteValue();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<u256> KnowledgeBase::valueIfKnownConstant(Expression const& _expression)
 | 
					std::optional<u256> KnowledgeBase::valueIfKnownConstant(Expression const& _expression)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (Identifier const* ident = get_if<Identifier>(&_expression))
 | 
						if (Identifier const* ident = std::get_if<Identifier>(&_expression))
 | 
				
			||||||
		return valueIfKnownConstant(ident->name);
 | 
							return valueIfKnownConstant(ident->name);
 | 
				
			||||||
	else if (Literal const* lit = get_if<Literal>(&_expression))
 | 
						else if (Literal const* lit = std::get_if<Literal>(&_expression))
 | 
				
			||||||
		return valueOfLiteral(*lit);
 | 
							return valueOfLiteral(*lit);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
KnowledgeBase::VariableOffset KnowledgeBase::explore(YulString _var)
 | 
					KnowledgeBase::VariableOffset KnowledgeBase::explore(YulString _var)
 | 
				
			||||||
@ -105,24 +104,24 @@ KnowledgeBase::VariableOffset KnowledgeBase::explore(YulString _var)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (value)
 | 
						if (value)
 | 
				
			||||||
		if (optional<VariableOffset> offset = explore(*value))
 | 
							if (std::optional<VariableOffset> offset = explore(*value))
 | 
				
			||||||
			return setOffset(_var, *offset);
 | 
								return setOffset(_var, *offset);
 | 
				
			||||||
	return setOffset(_var, VariableOffset{_var, 0});
 | 
						return setOffset(_var, VariableOffset{_var, 0});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<KnowledgeBase::VariableOffset> KnowledgeBase::explore(Expression const& _value)
 | 
					std::optional<KnowledgeBase::VariableOffset> KnowledgeBase::explore(Expression const& _value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (Literal const* literal = get_if<Literal>(&_value))
 | 
						if (Literal const* literal = std::get_if<Literal>(&_value))
 | 
				
			||||||
		return VariableOffset{YulString{}, valueOfLiteral(*literal)};
 | 
							return VariableOffset{YulString{}, valueOfLiteral(*literal)};
 | 
				
			||||||
	else if (Identifier const* identifier = get_if<Identifier>(&_value))
 | 
						else if (Identifier const* identifier = std::get_if<Identifier>(&_value))
 | 
				
			||||||
		return explore(identifier->name);
 | 
							return explore(identifier->name);
 | 
				
			||||||
	else if (FunctionCall const* f = get_if<FunctionCall>(&_value))
 | 
						else if (FunctionCall const* f = std::get_if<FunctionCall>(&_value))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (f->functionName.name == "add"_yulstring)
 | 
							if (f->functionName.name == "add"_yulstring)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (optional<VariableOffset> a = explore(f->arguments[0]))
 | 
								if (std::optional<VariableOffset> a = explore(f->arguments[0]))
 | 
				
			||||||
				if (optional<VariableOffset> b = explore(f->arguments[1]))
 | 
									if (std::optional<VariableOffset> b = explore(f->arguments[1]))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					u256 offset = a->offset + b->offset;
 | 
										u256 offset = a->offset + b->offset;
 | 
				
			||||||
					if (a->isAbsolute())
 | 
										if (a->isAbsolute())
 | 
				
			||||||
@ -134,8 +133,8 @@ optional<KnowledgeBase::VariableOffset> KnowledgeBase::explore(Expression const&
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (f->functionName.name == "sub"_yulstring)
 | 
							else if (f->functionName.name == "sub"_yulstring)
 | 
				
			||||||
			if (optional<VariableOffset> a = explore(f->arguments[0]))
 | 
								if (std::optional<VariableOffset> a = explore(f->arguments[0]))
 | 
				
			||||||
				if (optional<VariableOffset> b = explore(f->arguments[1]))
 | 
									if (std::optional<VariableOffset> b = explore(f->arguments[1]))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					u256 offset = a->offset - b->offset;
 | 
										u256 offset = a->offset - b->offset;
 | 
				
			||||||
					if (a->reference == b->reference)
 | 
										if (a->reference == b->reference)
 | 
				
			||||||
@ -146,7 +145,7 @@ optional<KnowledgeBase::VariableOffset> KnowledgeBase::explore(Expression const&
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nullopt;
 | 
						return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Expression const* KnowledgeBase::valueOf(YulString _var)
 | 
					Expression const* KnowledgeBase::valueOf(YulString _var)
 | 
				
			||||||
@ -175,7 +174,7 @@ void KnowledgeBase::reset(YulString _var)
 | 
				
			|||||||
			m_groupMembers[offset->reference].erase(_var);
 | 
								m_groupMembers[offset->reference].erase(_var);
 | 
				
			||||||
		m_offsets.erase(_var);
 | 
							m_offsets.erase(_var);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (set<YulString>* group = util::valueOrNullptr(m_groupMembers, _var))
 | 
						if (std::set<YulString>* group = util::valueOrNullptr(m_groupMembers, _var))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// _var was a representative, we might have to find a new one.
 | 
							// _var was a representative, we might have to find a new one.
 | 
				
			||||||
		if (!group->empty())
 | 
							if (!group->empty())
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <limits>
 | 
					#include <limits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
using namespace solidity::evmasm;
 | 
					using namespace solidity::evmasm;
 | 
				
			||||||
@ -65,8 +64,8 @@ void LoadResolver::visit(Expression& _e)
 | 
				
			|||||||
			tryResolve(_e, StoreLoadLocation::Storage, funCall->arguments);
 | 
								tryResolve(_e, StoreLoadLocation::Storage, funCall->arguments);
 | 
				
			||||||
		else if (!m_containsMSize && funCall->functionName.name == m_dialect.hashFunction({}))
 | 
							else if (!m_containsMSize && funCall->functionName.name == m_dialect.hashFunction({}))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Identifier const* start = get_if<Identifier>(&funCall->arguments.at(0));
 | 
								Identifier const* start = std::get_if<Identifier>(&funCall->arguments.at(0));
 | 
				
			||||||
			Identifier const* length = get_if<Identifier>(&funCall->arguments.at(1));
 | 
								Identifier const* length = std::get_if<Identifier>(&funCall->arguments.at(1));
 | 
				
			||||||
			if (start && length)
 | 
								if (start && length)
 | 
				
			||||||
				if (auto const& value = keccakValue(start->name, length->name))
 | 
									if (auto const& value = keccakValue(start->name, length->name))
 | 
				
			||||||
					if (inScope(*value))
 | 
										if (inScope(*value))
 | 
				
			||||||
@ -82,10 +81,10 @@ void LoadResolver::visit(Expression& _e)
 | 
				
			|||||||
void LoadResolver::tryResolve(
 | 
					void LoadResolver::tryResolve(
 | 
				
			||||||
	Expression& _e,
 | 
						Expression& _e,
 | 
				
			||||||
	StoreLoadLocation _location,
 | 
						StoreLoadLocation _location,
 | 
				
			||||||
	vector<Expression> const& _arguments
 | 
						std::vector<Expression> const& _arguments
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (_arguments.empty() || !holds_alternative<Identifier>(_arguments.at(0)))
 | 
						if (_arguments.empty() || !std::holds_alternative<Identifier>(_arguments.at(0)))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	YulString key = std::get<Identifier>(_arguments.at(0)).name;
 | 
						YulString key = std::get<Identifier>(_arguments.at(0)).name;
 | 
				
			||||||
@ -126,7 +125,7 @@ void LoadResolver::tryEvaluateKeccak(
 | 
				
			|||||||
			{},
 | 
								{},
 | 
				
			||||||
			LiteralKind::Number,
 | 
								LiteralKind::Number,
 | 
				
			||||||
			// a dummy 256-bit number to represent the Keccak256 hash.
 | 
								// a dummy 256-bit number to represent the Keccak256 hash.
 | 
				
			||||||
			YulString{numeric_limits<u256>::max().str()},
 | 
								YulString{std::numeric_limits<u256>::max().str()},
 | 
				
			||||||
			{}
 | 
								{}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
@ -138,11 +137,11 @@ void LoadResolver::tryEvaluateKeccak(
 | 
				
			|||||||
	if (costOfLiteral > costOfKeccak)
 | 
						if (costOfLiteral > costOfKeccak)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	optional<YulString> value = memoryValue(memoryKey->name);
 | 
						std::optional<YulString> value = memoryValue(memoryKey->name);
 | 
				
			||||||
	if (value && inScope(*value))
 | 
						if (value && inScope(*value))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		optional<u256> memoryContent = valueOfIdentifier(*value);
 | 
							std::optional<u256> memoryContent = valueOfIdentifier(*value);
 | 
				
			||||||
		optional<u256> byteLength = valueOfIdentifier(length->name);
 | 
							std::optional<u256> byteLength = valueOfIdentifier(length->name);
 | 
				
			||||||
		if (memoryContent && byteLength && *byteLength <= 32)
 | 
							if (memoryContent && byteLength && *byteLength <= 32)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			bytes contentAsBytes = toBigEndian(*memoryContent);
 | 
								bytes contentAsBytes = toBigEndian(*memoryContent);
 | 
				
			||||||
 | 
				
			|||||||
@ -27,16 +27,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LoopInvariantCodeMotion::run(OptimiserStepContext& _context, Block& _ast)
 | 
					void LoopInvariantCodeMotion::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	map<YulString, SideEffects> functionSideEffects =
 | 
						std::map<YulString, SideEffects> functionSideEffects =
 | 
				
			||||||
		SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast));
 | 
							SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast));
 | 
				
			||||||
	bool containsMSize = MSizeFinder::containsMSize(_context.dialect, _ast);
 | 
						bool containsMSize = MSizeFinder::containsMSize(_context.dialect, _ast);
 | 
				
			||||||
	set<YulString> ssaVars = SSAValueTracker::ssaVariables(_ast);
 | 
						std::set<YulString> ssaVars = SSAValueTracker::ssaVariables(_ast);
 | 
				
			||||||
	LoopInvariantCodeMotion{_context.dialect, ssaVars, functionSideEffects, containsMSize}(_ast);
 | 
						LoopInvariantCodeMotion{_context.dialect, ssaVars, functionSideEffects, containsMSize}(_ast);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -44,11 +43,11 @@ void LoopInvariantCodeMotion::operator()(Block& _block)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	util::iterateReplacing(
 | 
						util::iterateReplacing(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[&](Statement& _s) -> optional<vector<Statement>>
 | 
							[&](Statement& _s) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			visit(_s);
 | 
								visit(_s);
 | 
				
			||||||
			if (holds_alternative<ForLoop>(_s))
 | 
								if (std::holds_alternative<ForLoop>(_s))
 | 
				
			||||||
				return rewriteLoop(get<ForLoop>(_s));
 | 
									return rewriteLoop(std::get<ForLoop>(_s));
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				return {};
 | 
									return {};
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -57,7 +56,7 @@ void LoopInvariantCodeMotion::operator()(Block& _block)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool LoopInvariantCodeMotion::canBePromoted(
 | 
					bool LoopInvariantCodeMotion::canBePromoted(
 | 
				
			||||||
	VariableDeclaration const& _varDecl,
 | 
						VariableDeclaration const& _varDecl,
 | 
				
			||||||
	set<YulString> const& _varsDefinedInCurrentScope,
 | 
						std::set<YulString> const& _varsDefinedInCurrentScope,
 | 
				
			||||||
	SideEffects const& _forLoopSideEffects
 | 
						SideEffects const& _forLoopSideEffects
 | 
				
			||||||
) const
 | 
					) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -81,29 +80,29 @@ bool LoopInvariantCodeMotion::canBePromoted(
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<vector<Statement>> LoopInvariantCodeMotion::rewriteLoop(ForLoop& _for)
 | 
					std::optional<std::vector<Statement>> LoopInvariantCodeMotion::rewriteLoop(ForLoop& _for)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	assertThrow(_for.pre.statements.empty(), OptimizerException, "");
 | 
						assertThrow(_for.pre.statements.empty(), OptimizerException, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto forLoopSideEffects =
 | 
						auto forLoopSideEffects =
 | 
				
			||||||
		SideEffectsCollector{m_dialect, _for, &m_functionSideEffects}.sideEffects();
 | 
							SideEffectsCollector{m_dialect, _for, &m_functionSideEffects}.sideEffects();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vector<Statement> replacement;
 | 
						std::vector<Statement> replacement;
 | 
				
			||||||
	for (Block* block: {&_for.post, &_for.body})
 | 
						for (Block* block: {&_for.post, &_for.body})
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		set<YulString> varsDefinedInScope;
 | 
							std::set<YulString> varsDefinedInScope;
 | 
				
			||||||
		util::iterateReplacing(
 | 
							util::iterateReplacing(
 | 
				
			||||||
			block->statements,
 | 
								block->statements,
 | 
				
			||||||
			[&](Statement& _s) -> optional<vector<Statement>>
 | 
								[&](Statement& _s) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (holds_alternative<VariableDeclaration>(_s))
 | 
									if (std::holds_alternative<VariableDeclaration>(_s))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					VariableDeclaration const& varDecl = std::get<VariableDeclaration>(_s);
 | 
										VariableDeclaration const& varDecl = std::get<VariableDeclaration>(_s);
 | 
				
			||||||
					if (canBePromoted(varDecl, varsDefinedInScope, forLoopSideEffects))
 | 
										if (canBePromoted(varDecl, varsDefinedInScope, forLoopSideEffects))
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						replacement.emplace_back(std::move(_s));
 | 
											replacement.emplace_back(std::move(_s));
 | 
				
			||||||
						// Do not add the variables declared here to varsDefinedInScope because we are moving them.
 | 
											// Do not add the variables declared here to varsDefinedInScope because we are moving them.
 | 
				
			||||||
						return vector<Statement>{};
 | 
											return std::vector<Statement>{};
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					for (auto const& var: varDecl.variables)
 | 
										for (auto const& var: varDecl.variables)
 | 
				
			||||||
						varsDefinedInScope.insert(var.name);
 | 
											varsDefinedInScope.insert(var.name);
 | 
				
			||||||
 | 
				
			|||||||
@ -30,34 +30,33 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t CodeWeights::costOf(Statement const& _statement) const
 | 
					size_t CodeWeights::costOf(Statement const& _statement) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<ExpressionStatement>(_statement))
 | 
						if (std::holds_alternative<ExpressionStatement>(_statement))
 | 
				
			||||||
		return expressionStatementCost;
 | 
							return expressionStatementCost;
 | 
				
			||||||
	else if (holds_alternative<Assignment>(_statement))
 | 
						else if (std::holds_alternative<Assignment>(_statement))
 | 
				
			||||||
		return assignmentCost;
 | 
							return assignmentCost;
 | 
				
			||||||
	else if (holds_alternative<VariableDeclaration>(_statement))
 | 
						else if (std::holds_alternative<VariableDeclaration>(_statement))
 | 
				
			||||||
		return variableDeclarationCost;
 | 
							return variableDeclarationCost;
 | 
				
			||||||
	else if (holds_alternative<FunctionDefinition>(_statement))
 | 
						else if (std::holds_alternative<FunctionDefinition>(_statement))
 | 
				
			||||||
		return functionDefinitionCost;
 | 
							return functionDefinitionCost;
 | 
				
			||||||
	else if (holds_alternative<If>(_statement))
 | 
						else if (std::holds_alternative<If>(_statement))
 | 
				
			||||||
		return ifCost;
 | 
							return ifCost;
 | 
				
			||||||
	else if (holds_alternative<Switch>(_statement))
 | 
						else if (std::holds_alternative<Switch>(_statement))
 | 
				
			||||||
		return switchCost + caseCost * std::get<Switch>(_statement).cases.size();
 | 
							return switchCost + caseCost * std::get<Switch>(_statement).cases.size();
 | 
				
			||||||
	else if (holds_alternative<ForLoop>(_statement))
 | 
						else if (std::holds_alternative<ForLoop>(_statement))
 | 
				
			||||||
		return forLoopCost;
 | 
							return forLoopCost;
 | 
				
			||||||
	else if (holds_alternative<Break>(_statement))
 | 
						else if (std::holds_alternative<Break>(_statement))
 | 
				
			||||||
		return breakCost;
 | 
							return breakCost;
 | 
				
			||||||
	else if (holds_alternative<Continue>(_statement))
 | 
						else if (std::holds_alternative<Continue>(_statement))
 | 
				
			||||||
		return continueCost;
 | 
							return continueCost;
 | 
				
			||||||
	else if (holds_alternative<Leave>(_statement))
 | 
						else if (std::holds_alternative<Leave>(_statement))
 | 
				
			||||||
		return leaveCost;
 | 
							return leaveCost;
 | 
				
			||||||
	else if (holds_alternative<Block>(_statement))
 | 
						else if (std::holds_alternative<Block>(_statement))
 | 
				
			||||||
		return blockCost;
 | 
							return blockCost;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		yulAssert(false, "If you add a new statement type, you must update CodeWeights.");
 | 
							yulAssert(false, "If you add a new statement type, you must update CodeWeights.");
 | 
				
			||||||
@ -65,11 +64,11 @@ size_t CodeWeights::costOf(Statement const& _statement) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
size_t CodeWeights::costOf(Expression const& _expression) const
 | 
					size_t CodeWeights::costOf(Expression const& _expression) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<FunctionCall>(_expression))
 | 
						if (std::holds_alternative<FunctionCall>(_expression))
 | 
				
			||||||
		return functionCallCost;
 | 
							return functionCallCost;
 | 
				
			||||||
	else if (holds_alternative<Identifier>(_expression))
 | 
						else if (std::holds_alternative<Identifier>(_expression))
 | 
				
			||||||
		return identifierCost;
 | 
							return identifierCost;
 | 
				
			||||||
	else if (Literal const* literal = get_if<Literal>(&_expression))
 | 
						else if (Literal const* literal = std::get_if<Literal>(&_expression))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Avoid strings because they could be longer than 32 bytes.
 | 
							// Avoid strings because they could be longer than 32 bytes.
 | 
				
			||||||
		if (literal->kind != LiteralKind::String && valueOfLiteral(*literal) == 0)
 | 
							if (literal->kind != LiteralKind::String && valueOfLiteral(*literal) == 0)
 | 
				
			||||||
@ -112,7 +111,7 @@ size_t CodeSize::codeSizeIncludingFunctions(Block const& _block, CodeWeights con
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void CodeSize::visit(Statement const& _statement)
 | 
					void CodeSize::visit(Statement const& _statement)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<FunctionDefinition>(_statement) && m_ignoreFunctions)
 | 
						if (std::holds_alternative<FunctionDefinition>(_statement) && m_ignoreFunctions)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_size += m_weights.costOf(_statement);
 | 
						m_size += m_weights.costOf(_statement);
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
@ -60,21 +59,21 @@ void ReferencesCounter::operator()(FunctionCall const& _funCall)
 | 
				
			|||||||
	ASTWalker::operator()(_funCall);
 | 
						ASTWalker::operator()(_funCall);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, size_t> ReferencesCounter::countReferences(Block const& _block)
 | 
					std::map<YulString, size_t> ReferencesCounter::countReferences(Block const& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ReferencesCounter counter;
 | 
						ReferencesCounter counter;
 | 
				
			||||||
	counter(_block);
 | 
						counter(_block);
 | 
				
			||||||
	return std::move(counter.m_references);
 | 
						return std::move(counter.m_references);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, size_t> ReferencesCounter::countReferences(FunctionDefinition const& _function)
 | 
					std::map<YulString, size_t> ReferencesCounter::countReferences(FunctionDefinition const& _function)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ReferencesCounter counter;
 | 
						ReferencesCounter counter;
 | 
				
			||||||
	counter(_function);
 | 
						counter(_function);
 | 
				
			||||||
	return std::move(counter.m_references);
 | 
						return std::move(counter.m_references);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, size_t> ReferencesCounter::countReferences(Expression const& _expression)
 | 
					std::map<YulString, size_t> ReferencesCounter::countReferences(Expression const& _expression)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ReferencesCounter counter;
 | 
						ReferencesCounter counter;
 | 
				
			||||||
	counter.visit(_expression);
 | 
						counter.visit(_expression);
 | 
				
			||||||
@ -86,28 +85,28 @@ void VariableReferencesCounter::operator()(Identifier const& _identifier)
 | 
				
			|||||||
	++m_references[_identifier.name];
 | 
						++m_references[_identifier.name];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, size_t> VariableReferencesCounter::countReferences(Block const& _block)
 | 
					std::map<YulString, size_t> VariableReferencesCounter::countReferences(Block const& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	VariableReferencesCounter counter;
 | 
						VariableReferencesCounter counter;
 | 
				
			||||||
	counter(_block);
 | 
						counter(_block);
 | 
				
			||||||
	return std::move(counter.m_references);
 | 
						return std::move(counter.m_references);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, size_t> VariableReferencesCounter::countReferences(FunctionDefinition const& _function)
 | 
					std::map<YulString, size_t> VariableReferencesCounter::countReferences(FunctionDefinition const& _function)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	VariableReferencesCounter counter;
 | 
						VariableReferencesCounter counter;
 | 
				
			||||||
	counter(_function);
 | 
						counter(_function);
 | 
				
			||||||
	return std::move(counter.m_references);
 | 
						return std::move(counter.m_references);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, size_t> VariableReferencesCounter::countReferences(Expression const& _expression)
 | 
					std::map<YulString, size_t> VariableReferencesCounter::countReferences(Expression const& _expression)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	VariableReferencesCounter counter;
 | 
						VariableReferencesCounter counter;
 | 
				
			||||||
	counter.visit(_expression);
 | 
						counter.visit(_expression);
 | 
				
			||||||
	return std::move(counter.m_references);
 | 
						return std::move(counter.m_references);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, size_t> VariableReferencesCounter::countReferences(Statement const& _statement)
 | 
					std::map<YulString, size_t> VariableReferencesCounter::countReferences(Statement const& _statement)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	VariableReferencesCounter counter;
 | 
						VariableReferencesCounter counter;
 | 
				
			||||||
	counter.visit(_statement);
 | 
						counter.visit(_statement);
 | 
				
			||||||
@ -149,7 +148,7 @@ std::set<YulString> solidity::yul::assignedVariableNames(Block const& _code)
 | 
				
			|||||||
	return names;
 | 
						return names;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, FunctionDefinition const*> solidity::yul::allFunctionDefinitions(Block const& _block)
 | 
					std::map<YulString, FunctionDefinition const*> solidity::yul::allFunctionDefinitions(Block const& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::map<YulString, FunctionDefinition const*> result;
 | 
						std::map<YulString, FunctionDefinition const*> result;
 | 
				
			||||||
	forEach<FunctionDefinition const>(_block, [&](FunctionDefinition const& _function) {
 | 
						forEach<FunctionDefinition const>(_block, [&](FunctionDefinition const& _function) {
 | 
				
			||||||
 | 
				
			|||||||
@ -29,18 +29,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NameDispenser::NameDispenser(Dialect const& _dialect, Block const& _ast, set<YulString> _reservedNames):
 | 
					NameDispenser::NameDispenser(Dialect const& _dialect, Block const& _ast, std::set<YulString> _reservedNames):
 | 
				
			||||||
	NameDispenser(_dialect, NameCollector(_ast).names() + _reservedNames)
 | 
						NameDispenser(_dialect, NameCollector(_ast).names() + _reservedNames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_reservedNames = std::move(_reservedNames);
 | 
						m_reservedNames = std::move(_reservedNames);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NameDispenser::NameDispenser(Dialect const& _dialect, set<YulString> _usedNames):
 | 
					NameDispenser::NameDispenser(Dialect const& _dialect, std::set<YulString> _usedNames):
 | 
				
			||||||
	m_dialect(_dialect),
 | 
						m_dialect(_dialect),
 | 
				
			||||||
	m_usedNames(std::move(_usedNames))
 | 
						m_usedNames(std::move(_usedNames))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -52,7 +51,7 @@ YulString NameDispenser::newName(YulString _nameHint)
 | 
				
			|||||||
	while (illegalName(name))
 | 
						while (illegalName(name))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_counter++;
 | 
							m_counter++;
 | 
				
			||||||
		name = YulString(_nameHint.str() + "_" + to_string(m_counter));
 | 
							name = YulString(_nameHint.str() + "_" + std::to_string(m_counter));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	m_usedNames.emplace(name);
 | 
						m_usedNames.emplace(name);
 | 
				
			||||||
	return name;
 | 
						return name;
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -64,7 +63,7 @@ void NameDisplacer::operator()(Block& _block)
 | 
				
			|||||||
	// First replace all the names of function definitions
 | 
						// First replace all the names of function definitions
 | 
				
			||||||
	// because of scoping.
 | 
						// because of scoping.
 | 
				
			||||||
	for (auto& st: _block.statements)
 | 
						for (auto& st: _block.statements)
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(st))
 | 
							if (std::holds_alternative<FunctionDefinition>(st))
 | 
				
			||||||
			checkAndReplaceNew(std::get<FunctionDefinition>(st).name);
 | 
								checkAndReplaceNew(std::get<FunctionDefinition>(st).name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ASTModifier::operator()(_block);
 | 
						ASTModifier::operator()(_block);
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,6 @@
 | 
				
			|||||||
#include <regex>
 | 
					#include <regex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
NameSimplifier::NameSimplifier(OptimiserStepContext& _context, Block const& _ast):
 | 
					NameSimplifier::NameSimplifier(OptimiserStepContext& _context, Block const& _ast):
 | 
				
			||||||
	m_context(_context)
 | 
						m_context(_context)
 | 
				
			||||||
@ -54,7 +53,7 @@ void NameSimplifier::operator()(VariableDeclaration& _varDecl)
 | 
				
			|||||||
	ASTModifier::operator()(_varDecl);
 | 
						ASTModifier::operator()(_varDecl);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NameSimplifier::renameVariables(vector<TypedName>& _variables)
 | 
					void NameSimplifier::renameVariables(std::vector<TypedName>& _variables)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (TypedName& typedName: _variables)
 | 
						for (TypedName& typedName: _variables)
 | 
				
			||||||
		translate(typedName.name);
 | 
							translate(typedName.name);
 | 
				
			||||||
@ -78,31 +77,31 @@ void NameSimplifier::findSimplification(YulString const& _name)
 | 
				
			|||||||
	if (m_translations.count(_name))
 | 
						if (m_translations.count(_name))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	string name = _name.str();
 | 
						std::string name = _name.str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static auto replacements = vector<pair<regex, string>>{
 | 
						static auto replacements = std::vector<std::pair<std::regex, std::string>>{
 | 
				
			||||||
		{regex("_\\$|\\$_"), "_"}, // remove type mangling delimiters
 | 
							{std::regex("_\\$|\\$_"), "_"}, // remove type mangling delimiters
 | 
				
			||||||
		{regex("_[0-9]+([^0-9a-fA-Fx])"), "$1"}, // removes AST IDs that are not hex.
 | 
							{std::regex("_[0-9]+([^0-9a-fA-Fx])"), "$1"}, // removes AST IDs that are not hex.
 | 
				
			||||||
		{regex("_[0-9]+$"), ""}, // removes AST IDs that are not hex.
 | 
							{std::regex("_[0-9]+$"), ""}, // removes AST IDs that are not hex.
 | 
				
			||||||
		{regex("_t_"), "_"}, // remove type prefixes
 | 
							{std::regex("_t_"), "_"}, // remove type prefixes
 | 
				
			||||||
		{regex("__"), "_"},
 | 
							{std::regex("__"), "_"},
 | 
				
			||||||
		{regex("(abi_..code.*)_to_.*"), "$1"}, // removes _to... for abi functions
 | 
							{std::regex("(abi_..code.*)_to_.*"), "$1"}, // removes _to... for abi functions
 | 
				
			||||||
		{regex("(stringliteral_?[0-9a-f][0-9a-f][0-9a-f][0-9a-f])[0-9a-f]*"), "$1"}, // shorten string literal
 | 
							{std::regex("(stringliteral_?[0-9a-f][0-9a-f][0-9a-f][0-9a-f])[0-9a-f]*"), "$1"}, // shorten string literal
 | 
				
			||||||
		{regex("tuple_"), ""},
 | 
							{std::regex("tuple_"), ""},
 | 
				
			||||||
		{regex("_memory_ptr"), ""},
 | 
							{std::regex("_memory_ptr"), ""},
 | 
				
			||||||
		{regex("_calldata_ptr"), "_calldata"},
 | 
							{std::regex("_calldata_ptr"), "_calldata"},
 | 
				
			||||||
		{regex("_fromStack"), ""},
 | 
							{std::regex("_fromStack"), ""},
 | 
				
			||||||
		{regex("_storage_storage"), "_storage"},
 | 
							{std::regex("_storage_storage"), "_storage"},
 | 
				
			||||||
		{regex("(storage.*)_?storage"), "$1"},
 | 
							{std::regex("(storage.*)_?storage"), "$1"},
 | 
				
			||||||
		{regex("_memory_memory"), "_memory"},
 | 
							{std::regex("_memory_memory"), "_memory"},
 | 
				
			||||||
		{regex("_contract\\$_([^_]*)_?"), "$1_"},
 | 
							{std::regex("_contract\\$_([^_]*)_?"), "$1_"},
 | 
				
			||||||
		{regex("index_access_(t_)?array"), "index_access"},
 | 
							{std::regex("index_access_(t_)?array"), "index_access"},
 | 
				
			||||||
		{regex("[0-9]*_$"), ""}
 | 
							{std::regex("[0-9]*_$"), ""}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto const& [pattern, substitute]: replacements)
 | 
						for (auto const& [pattern, substitute]: replacements)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		string candidate = regex_replace(name, pattern, substitute);
 | 
							std::string candidate = regex_replace(name, pattern, substitute);
 | 
				
			||||||
		if (!candidate.empty() && !m_context.dispenser.illegalName(YulString(candidate)))
 | 
							if (!candidate.empty() && !m_context.dispenser.illegalName(YulString(candidate)))
 | 
				
			||||||
			name = candidate;
 | 
								name = candidate;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -31,7 +31,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <range/v3/action/remove_if.hpp>
 | 
					#include <range/v3/action/remove_if.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::langutil;
 | 
					using namespace solidity::langutil;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
@ -40,7 +39,7 @@ using namespace solidity::yul;
 | 
				
			|||||||
void yul::removeEmptyBlocks(Block& _block)
 | 
					void yul::removeEmptyBlocks(Block& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto isEmptyBlock = [](Statement const& _st) -> bool {
 | 
						auto isEmptyBlock = [](Statement const& _st) -> bool {
 | 
				
			||||||
		return holds_alternative<Block>(_st) && std::get<Block>(_st).statements.empty();
 | 
							return std::holds_alternative<Block>(_st) && std::get<Block>(_st).statements.empty();
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	ranges::actions::remove_if(_block.statements, isEmptyBlock);
 | 
						ranges::actions::remove_if(_block.statements, isEmptyBlock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -50,12 +49,12 @@ bool yul::isRestrictedIdentifier(Dialect const& _dialect, YulString const& _iden
 | 
				
			|||||||
	return _identifier.empty() || TokenTraits::isYulKeyword(_identifier.str()) || _dialect.reservedIdentifier(_identifier);
 | 
						return _identifier.empty() || TokenTraits::isYulKeyword(_identifier.str()) || _dialect.reservedIdentifier(_identifier);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<evmasm::Instruction> yul::toEVMInstruction(Dialect const& _dialect, YulString const& _name)
 | 
					std::optional<evmasm::Instruction> yul::toEVMInstruction(Dialect const& _dialect, YulString const& _name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
 | 
						if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
 | 
				
			||||||
		if (BuiltinFunctionForEVM const* builtin = dialect->builtin(_name))
 | 
							if (BuiltinFunctionForEVM const* builtin = dialect->builtin(_name))
 | 
				
			||||||
			return builtin->instruction;
 | 
								return builtin->instruction;
 | 
				
			||||||
	return nullopt;
 | 
						return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
langutil::EVMVersion const yul::evmVersionFromDialect(Dialect const& _dialect)
 | 
					langutil::EVMVersion const yul::evmVersionFromDialect(Dialect const& _dialect)
 | 
				
			||||||
@ -69,12 +68,12 @@ void StatementRemover::operator()(Block& _block)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	util::iterateReplacing(
 | 
						util::iterateReplacing(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[&](Statement& _statement) -> std::optional<vector<Statement>>
 | 
							[&](Statement& _statement) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (m_toRemove.count(&_statement))
 | 
								if (m_toRemove.count(&_statement))
 | 
				
			||||||
				return {vector<Statement>{}};
 | 
									return {std::vector<Statement>{}};
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				return nullopt;
 | 
									return std::nullopt;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
	ASTModifier::operator()(_block);
 | 
						ASTModifier::operator()(_block);
 | 
				
			||||||
 | 
				
			|||||||
@ -28,11 +28,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <range/v3/algorithm/all_of.hpp>
 | 
					#include <range/v3/algorithm/all_of.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Rematerialiser::run(Dialect const& _dialect, Block& _ast, set<YulString> _varsToAlwaysRematerialize, bool _onlySelectedVariables)
 | 
					void Rematerialiser::run(Dialect const& _dialect, Block& _ast, std::set<YulString> _varsToAlwaysRematerialize, bool _onlySelectedVariables)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Rematerialiser{_dialect, _ast, std::move(_varsToAlwaysRematerialize), _onlySelectedVariables}(_ast);
 | 
						Rematerialiser{_dialect, _ast, std::move(_varsToAlwaysRematerialize), _onlySelectedVariables}(_ast);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -40,7 +39,7 @@ void Rematerialiser::run(Dialect const& _dialect, Block& _ast, set<YulString> _v
 | 
				
			|||||||
Rematerialiser::Rematerialiser(
 | 
					Rematerialiser::Rematerialiser(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	Block& _ast,
 | 
						Block& _ast,
 | 
				
			||||||
	set<YulString> _varsToAlwaysRematerialize,
 | 
						std::set<YulString> _varsToAlwaysRematerialize,
 | 
				
			||||||
	bool _onlySelectedVariables
 | 
						bool _onlySelectedVariables
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore),
 | 
						DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore),
 | 
				
			||||||
@ -52,7 +51,7 @@ Rematerialiser::Rematerialiser(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Rematerialiser::visit(Expression& _e)
 | 
					void Rematerialiser::visit(Expression& _e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<Identifier>(_e))
 | 
						if (std::holds_alternative<Identifier>(_e))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Identifier& identifier = std::get<Identifier>(_e);
 | 
							Identifier& identifier = std::get<Identifier>(_e);
 | 
				
			||||||
		YulString name = identifier.name;
 | 
							YulString name = identifier.name;
 | 
				
			||||||
@ -91,14 +90,14 @@ void Rematerialiser::visit(Expression& _e)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void LiteralRematerialiser::visit(Expression& _e)
 | 
					void LiteralRematerialiser::visit(Expression& _e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<Identifier>(_e))
 | 
						if (std::holds_alternative<Identifier>(_e))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Identifier& identifier = std::get<Identifier>(_e);
 | 
							Identifier& identifier = std::get<Identifier>(_e);
 | 
				
			||||||
		YulString name = identifier.name;
 | 
							YulString name = identifier.name;
 | 
				
			||||||
		if (AssignedValue const* value = variableValue(name))
 | 
							if (AssignedValue const* value = variableValue(name))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			assertThrow(value->value, OptimizerException, "");
 | 
								assertThrow(value->value, OptimizerException, "");
 | 
				
			||||||
			if (holds_alternative<Literal>(*value->value))
 | 
								if (std::holds_alternative<Literal>(*value->value))
 | 
				
			||||||
				_e = *value->value;
 | 
									_e = *value->value;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <variant>
 | 
					#include <variant>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,7 +37,7 @@ void SSAReverser::operator()(Block& _block)
 | 
				
			|||||||
	walkVector(_block.statements);
 | 
						walkVector(_block.statements);
 | 
				
			||||||
	util::iterateReplacingWindow<2>(
 | 
						util::iterateReplacingWindow<2>(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>>
 | 
							[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto* varDecl = std::get_if<VariableDeclaration>(&_stmt1);
 | 
								auto* varDecl = std::get_if<VariableDeclaration>(&_stmt1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libyul/optimiser/TypeInfo.h>
 | 
					#include <libyul/optimiser/TypeInfo.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::langutil;
 | 
					using namespace solidity::langutil;
 | 
				
			||||||
@ -47,7 +46,7 @@ class IntroduceSSA: public ASTModifier
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit IntroduceSSA(
 | 
						explicit IntroduceSSA(
 | 
				
			||||||
		NameDispenser& _nameDispenser,
 | 
							NameDispenser& _nameDispenser,
 | 
				
			||||||
		set<YulString> const& _variablesToReplace,
 | 
							std::set<YulString> const& _variablesToReplace,
 | 
				
			||||||
		TypeInfo& _typeInfo
 | 
							TypeInfo& _typeInfo
 | 
				
			||||||
	):
 | 
						):
 | 
				
			||||||
		m_nameDispenser(_nameDispenser),
 | 
							m_nameDispenser(_nameDispenser),
 | 
				
			||||||
@ -59,7 +58,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	NameDispenser& m_nameDispenser;
 | 
						NameDispenser& m_nameDispenser;
 | 
				
			||||||
	set<YulString> const& m_variablesToReplace;
 | 
						std::set<YulString> const& m_variablesToReplace;
 | 
				
			||||||
	TypeInfo const& m_typeInfo;
 | 
						TypeInfo const& m_typeInfo;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,9 +67,9 @@ void IntroduceSSA::operator()(Block& _block)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	util::iterateReplacing(
 | 
						util::iterateReplacing(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[&](Statement& _s) -> std::optional<vector<Statement>>
 | 
							[&](Statement& _s) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (holds_alternative<VariableDeclaration>(_s))
 | 
								if (std::holds_alternative<VariableDeclaration>(_s))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
 | 
									VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
 | 
				
			||||||
				if (varDecl.value)
 | 
									if (varDecl.value)
 | 
				
			||||||
@ -85,8 +84,8 @@ void IntroduceSSA::operator()(Block& _block)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				// Replace "let a := v" by "let a_1 := v  let a := a_1"
 | 
									// Replace "let a := v" by "let a_1 := v  let a := a_1"
 | 
				
			||||||
				// Replace "let a, b := v" by "let a_1, b_1 := v  let a := a_1 let b := b_2"
 | 
									// Replace "let a, b := v" by "let a_1, b_1 := v  let a := a_1 let b := b_2"
 | 
				
			||||||
				shared_ptr<DebugData const> debugData = varDecl.debugData;
 | 
									std::shared_ptr<DebugData const> debugData = varDecl.debugData;
 | 
				
			||||||
				vector<Statement> statements;
 | 
									std::vector<Statement> statements;
 | 
				
			||||||
				statements.emplace_back(VariableDeclaration{debugData, {}, std::move(varDecl.value)});
 | 
									statements.emplace_back(VariableDeclaration{debugData, {}, std::move(varDecl.value)});
 | 
				
			||||||
				TypedNameList newVariables;
 | 
									TypedNameList newVariables;
 | 
				
			||||||
				for (auto const& var: varDecl.variables)
 | 
									for (auto const& var: varDecl.variables)
 | 
				
			||||||
@ -97,13 +96,13 @@ void IntroduceSSA::operator()(Block& _block)
 | 
				
			|||||||
					statements.emplace_back(VariableDeclaration{
 | 
										statements.emplace_back(VariableDeclaration{
 | 
				
			||||||
						debugData,
 | 
											debugData,
 | 
				
			||||||
						{TypedName{debugData, oldName, var.type}},
 | 
											{TypedName{debugData, oldName, var.type}},
 | 
				
			||||||
						make_unique<Expression>(Identifier{debugData, newName})
 | 
											std::make_unique<Expression>(Identifier{debugData, newName})
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				std::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
 | 
									std::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
 | 
				
			||||||
				return { std::move(statements) };
 | 
									return { std::move(statements) };
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else if (holds_alternative<Assignment>(_s))
 | 
								else if (std::holds_alternative<Assignment>(_s))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Assignment& assignment = std::get<Assignment>(_s);
 | 
									Assignment& assignment = std::get<Assignment>(_s);
 | 
				
			||||||
				visit(*assignment.value);
 | 
									visit(*assignment.value);
 | 
				
			||||||
@ -113,7 +112,7 @@ void IntroduceSSA::operator()(Block& _block)
 | 
				
			|||||||
				// Replace "a := v" by "let a_1 := v  a := v"
 | 
									// Replace "a := v" by "let a_1 := v  a := v"
 | 
				
			||||||
				// Replace "a, b := v" by "let a_1, b_1 := v  a := a_1 b := b_2"
 | 
									// Replace "a, b := v" by "let a_1, b_1 := v  a := a_1 b := b_2"
 | 
				
			||||||
				std::shared_ptr<DebugData const> debugData = assignment.debugData;
 | 
									std::shared_ptr<DebugData const> debugData = assignment.debugData;
 | 
				
			||||||
				vector<Statement> statements;
 | 
									std::vector<Statement> statements;
 | 
				
			||||||
				statements.emplace_back(VariableDeclaration{debugData, {}, std::move(assignment.value)});
 | 
									statements.emplace_back(VariableDeclaration{debugData, {}, std::move(assignment.value)});
 | 
				
			||||||
				TypedNameList newVariables;
 | 
									TypedNameList newVariables;
 | 
				
			||||||
				for (auto const& var: assignment.variableNames)
 | 
									for (auto const& var: assignment.variableNames)
 | 
				
			||||||
@ -127,7 +126,7 @@ void IntroduceSSA::operator()(Block& _block)
 | 
				
			|||||||
					statements.emplace_back(Assignment{
 | 
										statements.emplace_back(Assignment{
 | 
				
			||||||
						debugData,
 | 
											debugData,
 | 
				
			||||||
						{Identifier{debugData, oldName}},
 | 
											{Identifier{debugData, oldName}},
 | 
				
			||||||
						make_unique<Expression>(Identifier{debugData, newName})
 | 
											std::make_unique<Expression>(Identifier{debugData, newName})
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				std::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
 | 
									std::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
 | 
				
			||||||
@ -149,7 +148,7 @@ class IntroduceControlFlowSSA: public ASTModifier
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit IntroduceControlFlowSSA(
 | 
						explicit IntroduceControlFlowSSA(
 | 
				
			||||||
		NameDispenser& _nameDispenser,
 | 
							NameDispenser& _nameDispenser,
 | 
				
			||||||
		set<YulString> const& _variablesToReplace,
 | 
							std::set<YulString> const& _variablesToReplace,
 | 
				
			||||||
		TypeInfo const& _typeInfo
 | 
							TypeInfo const& _typeInfo
 | 
				
			||||||
	):
 | 
						):
 | 
				
			||||||
		m_nameDispenser(_nameDispenser),
 | 
							m_nameDispenser(_nameDispenser),
 | 
				
			||||||
@ -164,19 +163,19 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	NameDispenser& m_nameDispenser;
 | 
						NameDispenser& m_nameDispenser;
 | 
				
			||||||
	set<YulString> const& m_variablesToReplace;
 | 
						std::set<YulString> const& m_variablesToReplace;
 | 
				
			||||||
	/// Variables (that are to be replaced) currently in scope.
 | 
						/// Variables (that are to be replaced) currently in scope.
 | 
				
			||||||
	set<YulString> m_variablesInScope;
 | 
						std::set<YulString> m_variablesInScope;
 | 
				
			||||||
	/// Set of variables that do not have a specific value.
 | 
						/// Set of variables that do not have a specific value.
 | 
				
			||||||
	set<YulString> m_variablesToReassign;
 | 
						std::set<YulString> m_variablesToReassign;
 | 
				
			||||||
	TypeInfo const& m_typeInfo;
 | 
						TypeInfo const& m_typeInfo;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void IntroduceControlFlowSSA::operator()(FunctionDefinition& _function)
 | 
					void IntroduceControlFlowSSA::operator()(FunctionDefinition& _function)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<YulString> varsInScope;
 | 
						std::set<YulString> varsInScope;
 | 
				
			||||||
	std::swap(varsInScope, m_variablesInScope);
 | 
						std::swap(varsInScope, m_variablesInScope);
 | 
				
			||||||
	set<YulString> toReassign;
 | 
						std::set<YulString> toReassign;
 | 
				
			||||||
	std::swap(toReassign, m_variablesToReassign);
 | 
						std::swap(toReassign, m_variablesToReassign);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto const& param: _function.parameters)
 | 
						for (auto const& param: _function.parameters)
 | 
				
			||||||
@ -208,7 +207,7 @@ void IntroduceControlFlowSSA::operator()(Switch& _switch)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	yulAssert(m_variablesToReassign.empty(), "");
 | 
						yulAssert(m_variablesToReassign.empty(), "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set<YulString> toReassign;
 | 
						std::set<YulString> toReassign;
 | 
				
			||||||
	for (auto& c: _switch.cases)
 | 
						for (auto& c: _switch.cases)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		(*this)(c.body);
 | 
							(*this)(c.body);
 | 
				
			||||||
@ -220,27 +219,27 @@ void IntroduceControlFlowSSA::operator()(Switch& _switch)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void IntroduceControlFlowSSA::operator()(Block& _block)
 | 
					void IntroduceControlFlowSSA::operator()(Block& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<YulString> variablesDeclaredHere;
 | 
						std::set<YulString> variablesDeclaredHere;
 | 
				
			||||||
	set<YulString> assignedVariables;
 | 
						std::set<YulString> assignedVariables;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	util::iterateReplacing(
 | 
						util::iterateReplacing(
 | 
				
			||||||
		_block.statements,
 | 
							_block.statements,
 | 
				
			||||||
		[&](Statement& _s) -> std::optional<vector<Statement>>
 | 
							[&](Statement& _s) -> std::optional<std::vector<Statement>>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			vector<Statement> toPrepend;
 | 
							std::vector<Statement> toPrepend;
 | 
				
			||||||
			for (YulString toReassign: m_variablesToReassign)
 | 
								for (YulString toReassign: m_variablesToReassign)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				YulString newName = m_nameDispenser.newName(toReassign);
 | 
									YulString newName = m_nameDispenser.newName(toReassign);
 | 
				
			||||||
				toPrepend.emplace_back(VariableDeclaration{
 | 
									toPrepend.emplace_back(VariableDeclaration{
 | 
				
			||||||
					debugDataOf(_s),
 | 
										debugDataOf(_s),
 | 
				
			||||||
					{TypedName{debugDataOf(_s), newName, m_typeInfo.typeOfVariable(toReassign)}},
 | 
										{TypedName{debugDataOf(_s), newName, m_typeInfo.typeOfVariable(toReassign)}},
 | 
				
			||||||
					make_unique<Expression>(Identifier{debugDataOf(_s), toReassign})
 | 
										std::make_unique<Expression>(Identifier{debugDataOf(_s), toReassign})
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
				assignedVariables.insert(toReassign);
 | 
									assignedVariables.insert(toReassign);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			m_variablesToReassign.clear();
 | 
								m_variablesToReassign.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (holds_alternative<VariableDeclaration>(_s))
 | 
								if (std::holds_alternative<VariableDeclaration>(_s))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
 | 
									VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
 | 
				
			||||||
				for (auto const& var: varDecl.variables)
 | 
									for (auto const& var: varDecl.variables)
 | 
				
			||||||
@ -250,7 +249,7 @@ void IntroduceControlFlowSSA::operator()(Block& _block)
 | 
				
			|||||||
						m_variablesInScope.insert(var.name);
 | 
											m_variablesInScope.insert(var.name);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else if (holds_alternative<Assignment>(_s))
 | 
								else if (std::holds_alternative<Assignment>(_s))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Assignment& assignment = std::get<Assignment>(_s);
 | 
									Assignment& assignment = std::get<Assignment>(_s);
 | 
				
			||||||
				for (auto const& var: assignment.variableNames)
 | 
									for (auto const& var: assignment.variableNames)
 | 
				
			||||||
@ -281,7 +280,7 @@ void IntroduceControlFlowSSA::operator()(Block& _block)
 | 
				
			|||||||
class PropagateValues: public ASTModifier
 | 
					class PropagateValues: public ASTModifier
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit PropagateValues(set<YulString> const& _variablesToReplace):
 | 
						explicit PropagateValues(std::set<YulString> const& _variablesToReplace):
 | 
				
			||||||
		m_variablesToReplace(_variablesToReplace)
 | 
							m_variablesToReplace(_variablesToReplace)
 | 
				
			||||||
	{ }
 | 
						{ }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -294,9 +293,9 @@ public:
 | 
				
			|||||||
private:
 | 
					private:
 | 
				
			||||||
	/// This is a set of all variables that are assigned to anywhere in the code.
 | 
						/// This is a set of all variables that are assigned to anywhere in the code.
 | 
				
			||||||
	/// Variables that are only declared but never re-assigned are not touched.
 | 
						/// Variables that are only declared but never re-assigned are not touched.
 | 
				
			||||||
	set<YulString> const& m_variablesToReplace;
 | 
						std::set<YulString> const& m_variablesToReplace;
 | 
				
			||||||
	map<YulString, YulString> m_currentVariableValues;
 | 
						std::map<YulString, YulString> m_currentVariableValues;
 | 
				
			||||||
	set<YulString> m_clearAtEndOfBlock;
 | 
						std::set<YulString> m_clearAtEndOfBlock;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PropagateValues::operator()(Identifier& _identifier)
 | 
					void PropagateValues::operator()(Identifier& _identifier)
 | 
				
			||||||
@ -316,11 +315,11 @@ void PropagateValues::operator()(VariableDeclaration& _varDecl)
 | 
				
			|||||||
	if (m_variablesToReplace.count(variable))
 | 
						if (m_variablesToReplace.count(variable))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// `let a := a_1` - regular declaration of non-SSA variable
 | 
							// `let a := a_1` - regular declaration of non-SSA variable
 | 
				
			||||||
		yulAssert(holds_alternative<Identifier>(*_varDecl.value), "");
 | 
							yulAssert(std::holds_alternative<Identifier>(*_varDecl.value), "");
 | 
				
			||||||
		m_currentVariableValues[variable] = std::get<Identifier>(*_varDecl.value).name;
 | 
							m_currentVariableValues[variable] = std::get<Identifier>(*_varDecl.value).name;
 | 
				
			||||||
		m_clearAtEndOfBlock.insert(variable);
 | 
							m_clearAtEndOfBlock.insert(variable);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (_varDecl.value && holds_alternative<Identifier>(*_varDecl.value))
 | 
						else if (_varDecl.value && std::holds_alternative<Identifier>(*_varDecl.value))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// `let a_1 := a` - assignment to SSA variable after a branch.
 | 
							// `let a_1 := a` - assignment to SSA variable after a branch.
 | 
				
			||||||
		YulString value = std::get<Identifier>(*_varDecl.value).name;
 | 
							YulString value = std::get<Identifier>(*_varDecl.value).name;
 | 
				
			||||||
@ -345,7 +344,7 @@ void PropagateValues::operator()(Assignment& _assignment)
 | 
				
			|||||||
	if (!m_variablesToReplace.count(name))
 | 
						if (!m_variablesToReplace.count(name))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	yulAssert(_assignment.value && holds_alternative<Identifier>(*_assignment.value), "");
 | 
						yulAssert(_assignment.value && std::holds_alternative<Identifier>(*_assignment.value), "");
 | 
				
			||||||
	m_currentVariableValues[name] = std::get<Identifier>(*_assignment.value).name;
 | 
						m_currentVariableValues[name] = std::get<Identifier>(*_assignment.value).name;
 | 
				
			||||||
	m_clearAtEndOfBlock.insert(name);
 | 
						m_clearAtEndOfBlock.insert(name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -364,7 +363,7 @@ void PropagateValues::operator()(ForLoop& _for)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void PropagateValues::operator()(Block& _block)
 | 
					void PropagateValues::operator()(Block& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<YulString> clearAtParentBlock = std::move(m_clearAtEndOfBlock);
 | 
						std::set<YulString> clearAtParentBlock = std::move(m_clearAtEndOfBlock);
 | 
				
			||||||
	m_clearAtEndOfBlock.clear();
 | 
						m_clearAtEndOfBlock.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ASTModifier::operator()(_block);
 | 
						ASTModifier::operator()(_block);
 | 
				
			||||||
@ -380,7 +379,7 @@ void PropagateValues::operator()(Block& _block)
 | 
				
			|||||||
void SSATransform::run(OptimiserStepContext& _context, Block& _ast)
 | 
					void SSATransform::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	TypeInfo typeInfo(_context.dialect, _ast);
 | 
						TypeInfo typeInfo(_context.dialect, _ast);
 | 
				
			||||||
	set<YulString> assignedVariables = assignedVariableNames(_ast);
 | 
						std::set<YulString> assignedVariables = assignedVariableNames(_ast);
 | 
				
			||||||
	IntroduceSSA{_context.dispenser, assignedVariables, typeInfo}(_ast);
 | 
						IntroduceSSA{_context.dispenser, assignedVariables, typeInfo}(_ast);
 | 
				
			||||||
	IntroduceControlFlowSSA{_context.dispenser, assignedVariables, typeInfo}(_ast);
 | 
						IntroduceControlFlowSSA{_context.dispenser, assignedVariables, typeInfo}(_ast);
 | 
				
			||||||
	PropagateValues{assignedVariables}(_ast);
 | 
						PropagateValues{assignedVariables}(_ast);
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -50,11 +49,11 @@ void SSAValueTracker::operator()(VariableDeclaration const& _varDecl)
 | 
				
			|||||||
		setValue(_varDecl.variables.front().name, _varDecl.value.get());
 | 
							setValue(_varDecl.variables.front().name, _varDecl.value.get());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set<YulString> SSAValueTracker::ssaVariables(Block const& _ast)
 | 
					std::set<YulString> SSAValueTracker::ssaVariables(Block const& _ast)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SSAValueTracker t;
 | 
						SSAValueTracker t;
 | 
				
			||||||
	t(_ast);
 | 
						t(_ast);
 | 
				
			||||||
	set<YulString> ssaVars;
 | 
						std::set<YulString> ssaVars;
 | 
				
			||||||
	for (auto const& value: t.values())
 | 
						for (auto const& value: t.values())
 | 
				
			||||||
		ssaVars.insert(value.first);
 | 
							ssaVars.insert(value.first);
 | 
				
			||||||
	return ssaVars;
 | 
						return ssaVars;
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <limits>
 | 
					#include <limits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -41,7 +40,7 @@ using namespace solidity::yul;
 | 
				
			|||||||
SideEffectsCollector::SideEffectsCollector(
 | 
					SideEffectsCollector::SideEffectsCollector(
 | 
				
			||||||
		Dialect const& _dialect,
 | 
							Dialect const& _dialect,
 | 
				
			||||||
		Expression const& _expression,
 | 
							Expression const& _expression,
 | 
				
			||||||
		map<YulString, SideEffects> const* _functionSideEffects
 | 
							std::map<YulString, SideEffects> const* _functionSideEffects
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	SideEffectsCollector(_dialect, _functionSideEffects)
 | 
						SideEffectsCollector(_dialect, _functionSideEffects)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -57,7 +56,7 @@ SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Statement co
 | 
				
			|||||||
SideEffectsCollector::SideEffectsCollector(
 | 
					SideEffectsCollector::SideEffectsCollector(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	Block const& _ast,
 | 
						Block const& _ast,
 | 
				
			||||||
	map<YulString, SideEffects> const* _functionSideEffects
 | 
						std::map<YulString, SideEffects> const* _functionSideEffects
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	SideEffectsCollector(_dialect, _functionSideEffects)
 | 
						SideEffectsCollector(_dialect, _functionSideEffects)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -67,7 +66,7 @@ SideEffectsCollector::SideEffectsCollector(
 | 
				
			|||||||
SideEffectsCollector::SideEffectsCollector(
 | 
					SideEffectsCollector::SideEffectsCollector(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	ForLoop const& _ast,
 | 
						ForLoop const& _ast,
 | 
				
			||||||
	map<YulString, SideEffects> const* _functionSideEffects
 | 
						std::map<YulString, SideEffects> const* _functionSideEffects
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	SideEffectsCollector(_dialect, _functionSideEffects)
 | 
						SideEffectsCollector(_dialect, _functionSideEffects)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -99,7 +98,7 @@ bool MSizeFinder::containsMSize(Dialect const& _dialect, Object const& _object)
 | 
				
			|||||||
	if (containsMSize(_dialect, *_object.code))
 | 
						if (containsMSize(_dialect, *_object.code))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (shared_ptr<ObjectNode> const& node: _object.subObjects)
 | 
						for (std::shared_ptr<ObjectNode> const& node: _object.subObjects)
 | 
				
			||||||
		if (auto const* object = dynamic_cast<Object const*>(node.get()))
 | 
							if (auto const* object = dynamic_cast<Object const*>(node.get()))
 | 
				
			||||||
			if (containsMSize(_dialect, *object))
 | 
								if (containsMSize(_dialect, *object))
 | 
				
			||||||
				return true;
 | 
									return true;
 | 
				
			||||||
@ -116,7 +115,7 @@ void MSizeFinder::operator()(FunctionCall const& _functionCall)
 | 
				
			|||||||
			m_msizeFound = true;
 | 
								m_msizeFound = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<YulString, SideEffects> SideEffectsPropagator::sideEffects(
 | 
					std::map<YulString, SideEffects> SideEffectsPropagator::sideEffects(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	CallGraph const& _directCallGraph
 | 
						CallGraph const& _directCallGraph
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -127,7 +126,7 @@ map<YulString, SideEffects> SideEffectsPropagator::sideEffects(
 | 
				
			|||||||
	// In the future, we should refine that, because the property
 | 
						// In the future, we should refine that, because the property
 | 
				
			||||||
	// is actually a bit different from "not movable".
 | 
						// is actually a bit different from "not movable".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map<YulString, SideEffects> ret;
 | 
						std::map<YulString, SideEffects> ret;
 | 
				
			||||||
	for (auto const& function: _directCallGraph.functionsWithLoops + _directCallGraph.recursiveFunctions())
 | 
						for (auto const& function: _directCallGraph.functionsWithLoops + _directCallGraph.recursiveFunctions())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ret[function].movable = false;
 | 
							ret[function].movable = false;
 | 
				
			||||||
@ -179,8 +178,8 @@ void MovableChecker::visit(Statement const&)
 | 
				
			|||||||
	assertThrow(false, OptimizerException, "Movability for statement requested.");
 | 
						assertThrow(false, OptimizerException, "Movability for statement requested.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUnconditionalControlFlowChange(
 | 
					std::pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUnconditionalControlFlowChange(
 | 
				
			||||||
	vector<Statement> const& _statements
 | 
						std::vector<Statement> const& _statements
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (size_t i = 0; i < _statements.size(); ++i)
 | 
						for (size_t i = 0; i < _statements.size(); ++i)
 | 
				
			||||||
@ -189,32 +188,32 @@ pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUncondition
 | 
				
			|||||||
		if (controlFlow != ControlFlow::FlowOut)
 | 
							if (controlFlow != ControlFlow::FlowOut)
 | 
				
			||||||
			return {controlFlow, i};
 | 
								return {controlFlow, i};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return {ControlFlow::FlowOut, numeric_limits<size_t>::max()};
 | 
						return {ControlFlow::FlowOut, std::numeric_limits<size_t>::max()};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement)
 | 
					TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (
 | 
						if (
 | 
				
			||||||
		holds_alternative<VariableDeclaration>(_statement) &&
 | 
							std::holds_alternative<VariableDeclaration>(_statement) &&
 | 
				
			||||||
		std::get<VariableDeclaration>(_statement).value &&
 | 
							std::get<VariableDeclaration>(_statement).value &&
 | 
				
			||||||
		containsNonContinuingFunctionCall(*std::get<VariableDeclaration>(_statement).value)
 | 
							containsNonContinuingFunctionCall(*std::get<VariableDeclaration>(_statement).value)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
		return ControlFlow::Terminate;
 | 
							return ControlFlow::Terminate;
 | 
				
			||||||
	else if (
 | 
						else if (
 | 
				
			||||||
		holds_alternative<Assignment>(_statement) &&
 | 
							std::holds_alternative<Assignment>(_statement) &&
 | 
				
			||||||
		containsNonContinuingFunctionCall(*std::get<Assignment>(_statement).value)
 | 
							containsNonContinuingFunctionCall(*std::get<Assignment>(_statement).value)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
		return ControlFlow::Terminate;
 | 
							return ControlFlow::Terminate;
 | 
				
			||||||
	else if (
 | 
						else if (
 | 
				
			||||||
		holds_alternative<ExpressionStatement>(_statement) &&
 | 
							std::holds_alternative<ExpressionStatement>(_statement) &&
 | 
				
			||||||
		containsNonContinuingFunctionCall(std::get<ExpressionStatement>(_statement).expression)
 | 
							containsNonContinuingFunctionCall(std::get<ExpressionStatement>(_statement).expression)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
		return ControlFlow::Terminate;
 | 
							return ControlFlow::Terminate;
 | 
				
			||||||
	else if (holds_alternative<Break>(_statement))
 | 
						else if (std::holds_alternative<Break>(_statement))
 | 
				
			||||||
		return ControlFlow::Break;
 | 
							return ControlFlow::Break;
 | 
				
			||||||
	else if (holds_alternative<Continue>(_statement))
 | 
						else if (std::holds_alternative<Continue>(_statement))
 | 
				
			||||||
		return ControlFlow::Continue;
 | 
							return ControlFlow::Continue;
 | 
				
			||||||
	else if (holds_alternative<Leave>(_statement))
 | 
						else if (std::holds_alternative<Leave>(_statement))
 | 
				
			||||||
		return ControlFlow::Leave;
 | 
							return ControlFlow::Leave;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return ControlFlow::FlowOut;
 | 
							return ControlFlow::FlowOut;
 | 
				
			||||||
 | 
				
			|||||||
@ -32,7 +32,6 @@
 | 
				
			|||||||
#include <libevmasm/RuleList.h>
 | 
					#include <libevmasm/RuleList.h>
 | 
				
			||||||
#include <libsolutil/StringUtils.h>
 | 
					#include <libsolutil/StringUtils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::evmasm;
 | 
					using namespace solidity::evmasm;
 | 
				
			||||||
using namespace solidity::langutil;
 | 
					using namespace solidity::langutil;
 | 
				
			||||||
@ -41,7 +40,7 @@ using namespace solidity::yul;
 | 
				
			|||||||
SimplificationRules::Rule const* SimplificationRules::findFirstMatch(
 | 
					SimplificationRules::Rule const* SimplificationRules::findFirstMatch(
 | 
				
			||||||
	Expression const& _expr,
 | 
						Expression const& _expr,
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	function<AssignedValue const*(YulString)> const& _ssaValues
 | 
						std::function<AssignedValue const*(YulString)> const& _ssaValues
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto instruction = instructionAndArguments(_dialect, _expr);
 | 
						auto instruction = instructionAndArguments(_dialect, _expr);
 | 
				
			||||||
@ -75,14 +74,14 @@ bool SimplificationRules::isInitialized() const
 | 
				
			|||||||
	return !m_rules[uint8_t(evmasm::Instruction::ADD)].empty();
 | 
						return !m_rules[uint8_t(evmasm::Instruction::ADD)].empty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<std::pair<evmasm::Instruction, vector<Expression> const*>>
 | 
					std::optional<std::pair<evmasm::Instruction, std::vector<Expression> const*>>
 | 
				
			||||||
	SimplificationRules::instructionAndArguments(Dialect const& _dialect, Expression const& _expr)
 | 
						SimplificationRules::instructionAndArguments(Dialect const& _dialect, Expression const& _expr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<FunctionCall>(_expr))
 | 
						if (std::holds_alternative<FunctionCall>(_expr))
 | 
				
			||||||
		if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
 | 
							if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
 | 
				
			||||||
			if (auto const* builtin = dialect->builtin(std::get<FunctionCall>(_expr).functionName.name))
 | 
								if (auto const* builtin = dialect->builtin(std::get<FunctionCall>(_expr).functionName.name))
 | 
				
			||||||
				if (builtin->instruction)
 | 
									if (builtin->instruction)
 | 
				
			||||||
					return make_pair(*builtin->instruction, &std::get<FunctionCall>(_expr).arguments);
 | 
										return std::make_pair(*builtin->instruction, &std::get<FunctionCall>(_expr).arguments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -122,14 +121,14 @@ SimplificationRules::SimplificationRules(std::optional<langutil::EVMVersion> _ev
 | 
				
			|||||||
	assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
 | 
						assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
yul::Pattern::Pattern(evmasm::Instruction _instruction, initializer_list<Pattern> _arguments):
 | 
					yul::Pattern::Pattern(evmasm::Instruction _instruction, std::initializer_list<Pattern> _arguments):
 | 
				
			||||||
	m_kind(PatternKind::Operation),
 | 
						m_kind(PatternKind::Operation),
 | 
				
			||||||
	m_instruction(_instruction),
 | 
						m_instruction(_instruction),
 | 
				
			||||||
	m_arguments(_arguments)
 | 
						m_arguments(_arguments)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _matchGroups)
 | 
					void Pattern::setMatchGroup(unsigned _group, std::map<unsigned, Expression const*>& _matchGroups)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_matchGroup = _group;
 | 
						m_matchGroup = _group;
 | 
				
			||||||
	m_matchGroups = &_matchGroups;
 | 
						m_matchGroups = &_matchGroups;
 | 
				
			||||||
@ -138,14 +137,14 @@ void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _
 | 
				
			|||||||
bool Pattern::matches(
 | 
					bool Pattern::matches(
 | 
				
			||||||
	Expression const& _expr,
 | 
						Expression const& _expr,
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	function<AssignedValue const*(YulString)> const& _ssaValues
 | 
						std::function<AssignedValue const*(YulString)> const& _ssaValues
 | 
				
			||||||
) const
 | 
					) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Expression const* expr = &_expr;
 | 
						Expression const* expr = &_expr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Resolve the variable if possible.
 | 
						// Resolve the variable if possible.
 | 
				
			||||||
	// Do not do it for "Any" because we can check identity better for variables.
 | 
						// Do not do it for "Any" because we can check identity better for variables.
 | 
				
			||||||
	if (m_kind != PatternKind::Any && holds_alternative<Identifier>(_expr))
 | 
						if (m_kind != PatternKind::Any && std::holds_alternative<Identifier>(_expr))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		YulString varName = std::get<Identifier>(_expr).name;
 | 
							YulString varName = std::get<Identifier>(_expr).name;
 | 
				
			||||||
		if (AssignedValue const* value = _ssaValues(varName))
 | 
							if (AssignedValue const* value = _ssaValues(varName))
 | 
				
			||||||
@ -156,7 +155,7 @@ bool Pattern::matches(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (m_kind == PatternKind::Constant)
 | 
						if (m_kind == PatternKind::Constant)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (!holds_alternative<Literal>(*expr))
 | 
							if (!std::holds_alternative<Literal>(*expr))
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		Literal const& literal = std::get<Literal>(*expr);
 | 
							Literal const& literal = std::get<Literal>(*expr);
 | 
				
			||||||
		if (literal.kind != LiteralKind::Number)
 | 
							if (literal.kind != LiteralKind::Number)
 | 
				
			||||||
@ -178,7 +177,7 @@ bool Pattern::matches(
 | 
				
			|||||||
			// we reject the match because side-effects could prevent us from
 | 
								// we reject the match because side-effects could prevent us from
 | 
				
			||||||
			// arbitrarily modifying the code.
 | 
								// arbitrarily modifying the code.
 | 
				
			||||||
			if (
 | 
								if (
 | 
				
			||||||
				holds_alternative<FunctionCall>(arg) ||
 | 
									std::holds_alternative<FunctionCall>(arg) ||
 | 
				
			||||||
				!m_arguments[i].matches(arg, _dialect, _ssaValues)
 | 
									!m_arguments[i].matches(arg, _dialect, _ssaValues)
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
@ -187,7 +186,7 @@ bool Pattern::matches(
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		assertThrow(m_arguments.empty(), OptimizerException, "\"Any\" should not have arguments.");
 | 
							assertThrow(m_arguments.empty(), OptimizerException, "\"Any\" should not have arguments.");
 | 
				
			||||||
		assertThrow(!holds_alternative<FunctionCall>(*expr), OptimizerException, "\"Any\" at top-level.");
 | 
							assertThrow(!std::holds_alternative<FunctionCall>(*expr), OptimizerException, "\"Any\" at top-level.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (m_matchGroup)
 | 
						if (m_matchGroup)
 | 
				
			||||||
@ -209,8 +208,8 @@ bool Pattern::matches(
 | 
				
			|||||||
			Expression const* firstMatch = (*m_matchGroups)[m_matchGroup];
 | 
								Expression const* firstMatch = (*m_matchGroups)[m_matchGroup];
 | 
				
			||||||
			assertThrow(firstMatch, OptimizerException, "Match set but to null.");
 | 
								assertThrow(firstMatch, OptimizerException, "Match set but to null.");
 | 
				
			||||||
			assertThrow(
 | 
								assertThrow(
 | 
				
			||||||
				!holds_alternative<FunctionCall>(_expr) &&
 | 
									!std::holds_alternative<FunctionCall>(_expr) &&
 | 
				
			||||||
				!holds_alternative<FunctionCall>(*firstMatch),
 | 
									!std::holds_alternative<FunctionCall>(*firstMatch),
 | 
				
			||||||
				OptimizerException,
 | 
									OptimizerException,
 | 
				
			||||||
				"Group matches have to be literals or variables."
 | 
									"Group matches have to be literals or variables."
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
@ -235,7 +234,7 @@ evmasm::Instruction Pattern::instruction() const
 | 
				
			|||||||
	return m_instruction;
 | 
						return m_instruction;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Expression Pattern::toExpression(shared_ptr<DebugData const> const& _debugData, langutil::EVMVersion _evmVersion) const
 | 
					Expression Pattern::toExpression(std::shared_ptr<DebugData const> const& _debugData, langutil::EVMVersion _evmVersion) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (matchGroup())
 | 
						if (matchGroup())
 | 
				
			||||||
		return ASTCopier().translate(matchGroupValue());
 | 
							return ASTCopier().translate(matchGroupValue());
 | 
				
			||||||
@ -246,11 +245,11 @@ Expression Pattern::toExpression(shared_ptr<DebugData const> const& _debugData,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	else if (m_kind == PatternKind::Operation)
 | 
						else if (m_kind == PatternKind::Operation)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		vector<Expression> arguments;
 | 
							std::vector<Expression> arguments;
 | 
				
			||||||
		for (auto const& arg: m_arguments)
 | 
							for (auto const& arg: m_arguments)
 | 
				
			||||||
			arguments.emplace_back(arg.toExpression(_debugData, _evmVersion));
 | 
								arguments.emplace_back(arg.toExpression(_debugData, _evmVersion));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		string name = util::toLower(instructionInfo(m_instruction, _evmVersion).name);
 | 
							std::string name = util::toLower(instructionInfo(m_instruction, _evmVersion).name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return FunctionCall{_debugData,
 | 
							return FunctionCall{_debugData,
 | 
				
			||||||
			Identifier{_debugData, YulString{name}},
 | 
								Identifier{_debugData, YulString{name}},
 | 
				
			||||||
 | 
				
			|||||||
@ -40,7 +40,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -61,9 +60,9 @@ public:
 | 
				
			|||||||
	/// @returns a map from function name to rematerialisation costs to a vector of variables to rematerialise
 | 
						/// @returns a map from function name to rematerialisation costs to a vector of variables to rematerialise
 | 
				
			||||||
	/// and variables that occur in their expression.
 | 
						/// and variables that occur in their expression.
 | 
				
			||||||
	/// While the map is sorted by cost, the contained vectors are sorted by the order of occurrence.
 | 
						/// While the map is sorted by cost, the contained vectors are sorted by the order of occurrence.
 | 
				
			||||||
	map<YulString, map<size_t, vector<YulString>>> candidates()
 | 
						std::map<YulString, std::map<size_t, std::vector<YulString>>> candidates()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		map<YulString, map<size_t, vector<YulString>>> cand;
 | 
							std::map<YulString, std::map<size_t, std::vector<YulString>>> cand;
 | 
				
			||||||
		for (auto const& [functionName, candidate]: m_candidates)
 | 
							for (auto const& [functionName, candidate]: m_candidates)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (size_t const* cost = util::valueOrNullptr(m_expressionCodeCost, candidate))
 | 
								if (size_t const* cost = util::valueOrNullptr(m_expressionCodeCost, candidate))
 | 
				
			||||||
@ -110,7 +109,7 @@ public:
 | 
				
			|||||||
	// get called on left-hand-sides of assignments.
 | 
						// get called on left-hand-sides of assignments.
 | 
				
			||||||
	void visit(Expression& _e) override
 | 
						void visit(Expression& _e) override
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (holds_alternative<Identifier>(_e))
 | 
							if (std::holds_alternative<Identifier>(_e))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			YulString name = std::get<Identifier>(_e).name;
 | 
								YulString name = std::get<Identifier>(_e).name;
 | 
				
			||||||
			if (m_expressionCodeCost.count(name))
 | 
								if (m_expressionCodeCost.count(name))
 | 
				
			||||||
@ -134,20 +133,20 @@ public:
 | 
				
			|||||||
	YulString m_currentFunctionName = {};
 | 
						YulString m_currentFunctionName = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// All candidate variables by function name, in order of occurrence.
 | 
						/// All candidate variables by function name, in order of occurrence.
 | 
				
			||||||
	vector<pair<YulString, YulString>> m_candidates;
 | 
						std::vector<std::pair<YulString, YulString>> m_candidates;
 | 
				
			||||||
	/// Candidate variables and the code cost of their value.
 | 
						/// Candidate variables and the code cost of their value.
 | 
				
			||||||
	map<YulString, size_t> m_expressionCodeCost;
 | 
						std::map<YulString, size_t> m_expressionCodeCost;
 | 
				
			||||||
	/// Number of references to each candidate variable.
 | 
						/// Number of references to each candidate variable.
 | 
				
			||||||
	map<YulString, size_t> m_numReferences;
 | 
						std::map<YulString, size_t> m_numReferences;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Selects at most @a _numVariables among @a _candidates.
 | 
					/// Selects at most @a _numVariables among @a _candidates.
 | 
				
			||||||
set<YulString> chooseVarsToEliminate(
 | 
					std::set<YulString> chooseVarsToEliminate(
 | 
				
			||||||
	map<size_t, vector<YulString>> const& _candidates,
 | 
						std::map<size_t, std::vector<YulString>> const& _candidates,
 | 
				
			||||||
	size_t _numVariables
 | 
						size_t _numVariables
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<YulString> varsToEliminate;
 | 
						std::set<YulString> varsToEliminate;
 | 
				
			||||||
	for (auto&& [cost, candidates]: _candidates)
 | 
						for (auto&& [cost, candidates]: _candidates)
 | 
				
			||||||
		for (auto&& candidate: candidates)
 | 
							for (auto&& candidate: candidates)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -161,15 +160,15 @@ set<YulString> chooseVarsToEliminate(
 | 
				
			|||||||
void eliminateVariables(
 | 
					void eliminateVariables(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	Block& _ast,
 | 
						Block& _ast,
 | 
				
			||||||
	map<YulString, int> const& _numVariables,
 | 
						std::map<YulString, int> const& _numVariables,
 | 
				
			||||||
	bool _allowMSizeOptimization
 | 
						bool _allowMSizeOptimization
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RematCandidateSelector selector{_dialect};
 | 
						RematCandidateSelector selector{_dialect};
 | 
				
			||||||
	selector(_ast);
 | 
						selector(_ast);
 | 
				
			||||||
	map<YulString, map<size_t, vector<YulString>>> candidates = selector.candidates();
 | 
						std::map<YulString, std::map<size_t, std::vector<YulString>>> candidates = selector.candidates();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set<YulString> varsToEliminate;
 | 
						std::set<YulString> varsToEliminate;
 | 
				
			||||||
	for (auto const& [functionName, numVariables]: _numVariables)
 | 
						for (auto const& [functionName, numVariables]: _numVariables)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		yulAssert(numVariables > 0);
 | 
							yulAssert(numVariables > 0);
 | 
				
			||||||
@ -178,14 +177,14 @@ void eliminateVariables(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	Rematerialiser::run(_dialect, _ast, std::move(varsToEliminate));
 | 
						Rematerialiser::run(_dialect, _ast, std::move(varsToEliminate));
 | 
				
			||||||
	// Do not remove functions.
 | 
						// Do not remove functions.
 | 
				
			||||||
	set<YulString> allFunctions = NameCollector{_ast, NameCollector::OnlyFunctions}.names();
 | 
						std::set<YulString> allFunctions = NameCollector{_ast, NameCollector::OnlyFunctions}.names();
 | 
				
			||||||
	UnusedPruner::runUntilStabilised(_dialect, _ast, _allowMSizeOptimization, nullptr, allFunctions);
 | 
						UnusedPruner::runUntilStabilised(_dialect, _ast, _allowMSizeOptimization, nullptr, allFunctions);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void eliminateVariablesOptimizedCodegen(
 | 
					void eliminateVariablesOptimizedCodegen(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	Block& _ast,
 | 
						Block& _ast,
 | 
				
			||||||
	map<YulString, vector<StackLayoutGenerator::StackTooDeep>> const& _unreachables,
 | 
						std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> const& _unreachables,
 | 
				
			||||||
	bool _allowMSizeOptimization
 | 
						bool _allowMSizeOptimization
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -195,19 +194,19 @@ void eliminateVariablesOptimizedCodegen(
 | 
				
			|||||||
	RematCandidateSelector selector{_dialect};
 | 
						RematCandidateSelector selector{_dialect};
 | 
				
			||||||
	selector(_ast);
 | 
						selector(_ast);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map<YulString, size_t> candidates;
 | 
						std::map<YulString, size_t> candidates;
 | 
				
			||||||
	for (auto const& [functionName, candidatesInFunction]: selector.candidates())
 | 
						for (auto const& [functionName, candidatesInFunction]: selector.candidates())
 | 
				
			||||||
		for (auto [cost, candidatesWithCost]: candidatesInFunction)
 | 
							for (auto [cost, candidatesWithCost]: candidatesInFunction)
 | 
				
			||||||
			for (auto candidate: candidatesWithCost)
 | 
								for (auto candidate: candidatesWithCost)
 | 
				
			||||||
				candidates[candidate] = cost;
 | 
									candidates[candidate] = cost;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set<YulString> varsToEliminate;
 | 
						std::set<YulString> varsToEliminate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: this currently ignores the fact that variables may reference other variables we want to eliminate.
 | 
						// TODO: this currently ignores the fact that variables may reference other variables we want to eliminate.
 | 
				
			||||||
	for (auto const& [functionName, unreachables]: _unreachables)
 | 
						for (auto const& [functionName, unreachables]: _unreachables)
 | 
				
			||||||
		for (auto const& unreachable: unreachables)
 | 
							for (auto const& unreachable: unreachables)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			map<size_t, vector<YulString>> suitableCandidates;
 | 
								std::map<size_t, std::vector<YulString>> suitableCandidates;
 | 
				
			||||||
			size_t neededSlots = unreachable.deficit;
 | 
								size_t neededSlots = unreachable.deficit;
 | 
				
			||||||
			for (auto varName: unreachable.variableChoices)
 | 
								for (auto varName: unreachable.variableChoices)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@ -230,7 +229,7 @@ void eliminateVariablesOptimizedCodegen(
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	Rematerialiser::run(_dialect, _ast, std::move(varsToEliminate), true);
 | 
						Rematerialiser::run(_dialect, _ast, std::move(varsToEliminate), true);
 | 
				
			||||||
	// Do not remove functions.
 | 
						// Do not remove functions.
 | 
				
			||||||
	set<YulString> allFunctions = NameCollector{_ast, NameCollector::OnlyFunctions}.names();
 | 
						std::set<YulString> allFunctions = NameCollector{_ast, NameCollector::OnlyFunctions}.names();
 | 
				
			||||||
	UnusedPruner::runUntilStabilised(_dialect, _ast, _allowMSizeOptimization, nullptr, allFunctions);
 | 
						UnusedPruner::runUntilStabilised(_dialect, _ast, _allowMSizeOptimization, nullptr, allFunctions);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -245,7 +244,7 @@ bool StackCompressor::run(
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	yulAssert(
 | 
						yulAssert(
 | 
				
			||||||
		_object.code &&
 | 
							_object.code &&
 | 
				
			||||||
		_object.code->statements.size() > 0 && holds_alternative<Block>(_object.code->statements.at(0)),
 | 
							_object.code->statements.size() > 0 && std::holds_alternative<Block>(_object.code->statements.at(0)),
 | 
				
			||||||
		"Need to run the function grouper before the stack compressor."
 | 
							"Need to run the function grouper before the stack compressor."
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
	bool usesOptimizedCodeGenerator = false;
 | 
						bool usesOptimizedCodeGenerator = false;
 | 
				
			||||||
@ -258,7 +257,7 @@ bool StackCompressor::run(
 | 
				
			|||||||
	if (usesOptimizedCodeGenerator)
 | 
						if (usesOptimizedCodeGenerator)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object);
 | 
							yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object);
 | 
				
			||||||
		unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, _dialect, *_object.code);
 | 
							std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, _dialect, *_object.code);
 | 
				
			||||||
		eliminateVariablesOptimizedCodegen(
 | 
							eliminateVariablesOptimizedCodegen(
 | 
				
			||||||
			_dialect,
 | 
								_dialect,
 | 
				
			||||||
			*_object.code,
 | 
								*_object.code,
 | 
				
			||||||
@ -269,7 +268,7 @@ bool StackCompressor::run(
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		for (size_t iterations = 0; iterations < _maxIterations; iterations++)
 | 
							for (size_t iterations = 0; iterations < _maxIterations; iterations++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			map<YulString, int> stackSurplus = CompilabilityChecker(_dialect, _object, _optimizeStackAllocation).stackDeficit;
 | 
								std::map<YulString, int> stackSurplus = CompilabilityChecker(_dialect, _object, _optimizeStackAllocation).stackDeficit;
 | 
				
			||||||
			if (stackSurplus.empty())
 | 
								if (stackSurplus.empty())
 | 
				
			||||||
				return true;
 | 
									return true;
 | 
				
			||||||
			eliminateVariables(
 | 
								eliminateVariables(
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,6 @@
 | 
				
			|||||||
#include <range/v3/view/concat.hpp>
 | 
					#include <range/v3/view/concat.hpp>
 | 
				
			||||||
#include <range/v3/view/take.hpp>
 | 
					#include <range/v3/view/take.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,16 +96,16 @@ struct MemoryOffsetAllocator
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/// Maps function names to the set of unreachable variables in that function.
 | 
						/// Maps function names to the set of unreachable variables in that function.
 | 
				
			||||||
	/// An empty variable name means that the function has too many arguments or return variables.
 | 
						/// An empty variable name means that the function has too many arguments or return variables.
 | 
				
			||||||
	map<YulString, vector<YulString>> const& unreachableVariables;
 | 
						std::map<YulString, std::vector<YulString>> const& unreachableVariables;
 | 
				
			||||||
	/// The graph of immediate function calls of all functions.
 | 
						/// The graph of immediate function calls of all functions.
 | 
				
			||||||
	map<YulString, vector<YulString>> const& callGraph;
 | 
						std::map<YulString, std::vector<YulString>> const& callGraph;
 | 
				
			||||||
	/// Maps the name of each user-defined function to its definition.
 | 
						/// Maps the name of each user-defined function to its definition.
 | 
				
			||||||
	map<YulString, FunctionDefinition const*> const& functionDefinitions;
 | 
						std::map<YulString, FunctionDefinition const*> const& functionDefinitions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Maps variable names to the memory slot the respective variable is assigned.
 | 
						/// Maps variable names to the memory slot the respective variable is assigned.
 | 
				
			||||||
	map<YulString, uint64_t> slotAllocations{};
 | 
						std::map<YulString, uint64_t> slotAllocations{};
 | 
				
			||||||
	/// Maps function names to the number of memory slots the respective function requires.
 | 
						/// Maps function names to the number of memory slots the respective function requires.
 | 
				
			||||||
	map<YulString, uint64_t> slotsRequiredForFunction{};
 | 
						std::map<YulString, uint64_t> slotsRequiredForFunction{};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
u256 literalArgumentValue(FunctionCall const& _call)
 | 
					u256 literalArgumentValue(FunctionCall const& _call)
 | 
				
			||||||
@ -131,7 +130,7 @@ void StackLimitEvader::run(
 | 
				
			|||||||
	if (evmDialect && evmDialect->evmVersion().canOverchargeGasForCall())
 | 
						if (evmDialect && evmDialect->evmVersion().canOverchargeGasForCall())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(*evmDialect, _object);
 | 
							yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(*evmDialect, _object);
 | 
				
			||||||
		unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, *evmDialect, *_object.code);
 | 
							std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, *evmDialect, *_object.code);
 | 
				
			||||||
		run(_context, _object, StackLayoutGenerator::reportStackTooDeep(*cfg));
 | 
							run(_context, _object, StackLayoutGenerator::reportStackTooDeep(*cfg));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
@ -146,10 +145,10 @@ void StackLimitEvader::run(
 | 
				
			|||||||
void StackLimitEvader::run(
 | 
					void StackLimitEvader::run(
 | 
				
			||||||
	OptimiserStepContext& _context,
 | 
						OptimiserStepContext& _context,
 | 
				
			||||||
	Object& _object,
 | 
						Object& _object,
 | 
				
			||||||
	map<YulString, vector<StackLayoutGenerator::StackTooDeep>> const& _stackTooDeepErrors
 | 
						std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> const& _stackTooDeepErrors
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	map<YulString, vector<YulString>> unreachableVariables;
 | 
						std::map<YulString, std::vector<YulString>> unreachableVariables;
 | 
				
			||||||
	for (auto&& [function, stackTooDeepErrors]: _stackTooDeepErrors)
 | 
						for (auto&& [function, stackTooDeepErrors]: _stackTooDeepErrors)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto& unreachables = unreachableVariables[function];
 | 
							auto& unreachables = unreachableVariables[function];
 | 
				
			||||||
@ -165,7 +164,7 @@ void StackLimitEvader::run(
 | 
				
			|||||||
void StackLimitEvader::run(
 | 
					void StackLimitEvader::run(
 | 
				
			||||||
	OptimiserStepContext& _context,
 | 
						OptimiserStepContext& _context,
 | 
				
			||||||
	Object& _object,
 | 
						Object& _object,
 | 
				
			||||||
	map<YulString, vector<YulString>> const& _unreachableVariables
 | 
						std::map<YulString, std::vector<YulString>> const& _unreachableVariables
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	yulAssert(_object.code, "");
 | 
						yulAssert(_object.code, "");
 | 
				
			||||||
@ -175,7 +174,7 @@ void StackLimitEvader::run(
 | 
				
			|||||||
		"StackLimitEvader can only be run on objects using the EVMDialect with object access."
 | 
							"StackLimitEvader can only be run on objects using the EVMDialect with object access."
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
 | 
						std::vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
 | 
				
			||||||
		*_object.code,
 | 
							*_object.code,
 | 
				
			||||||
		"memoryguard"_yulstring
 | 
							"memoryguard"_yulstring
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
@ -198,7 +197,7 @@ void StackLimitEvader::run(
 | 
				
			|||||||
		if (_unreachableVariables.count(function))
 | 
							if (_unreachableVariables.count(function))
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map<YulString, FunctionDefinition const*> functionDefinitions = allFunctionDefinitions(*_object.code);
 | 
						std::map<YulString, FunctionDefinition const*> functionDefinitions = allFunctionDefinitions(*_object.code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MemoryOffsetAllocator memoryOffsetAllocator{_unreachableVariables, callGraph.functionCalls, functionDefinitions};
 | 
						MemoryOffsetAllocator memoryOffsetAllocator{_unreachableVariables, callGraph.functionCalls, functionDefinitions};
 | 
				
			||||||
	uint64_t requiredSlots = memoryOffsetAllocator.run();
 | 
						uint64_t requiredSlots = memoryOffsetAllocator.run();
 | 
				
			||||||
 | 
				
			|||||||
@ -29,22 +29,21 @@
 | 
				
			|||||||
#include <range/v3/view/zip.hpp>
 | 
					#include <range/v3/view/zip.hpp>
 | 
				
			||||||
#include <range/v3/range/conversion.hpp>
 | 
					#include <range/v3/range/conversion.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace
 | 
					namespace
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
vector<Statement> generateMemoryStore(
 | 
					std::vector<Statement> generateMemoryStore(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	shared_ptr<DebugData const> const& _debugData,
 | 
						std::shared_ptr<DebugData const> const& _debugData,
 | 
				
			||||||
	YulString _mpos,
 | 
						YulString _mpos,
 | 
				
			||||||
	Expression _value
 | 
						Expression _value
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	BuiltinFunction const* memoryStoreFunction = _dialect.memoryStoreFunction(_dialect.defaultType);
 | 
						BuiltinFunction const* memoryStoreFunction = _dialect.memoryStoreFunction(_dialect.defaultType);
 | 
				
			||||||
	yulAssert(memoryStoreFunction, "");
 | 
						yulAssert(memoryStoreFunction, "");
 | 
				
			||||||
	vector<Statement> result;
 | 
						std::vector<Statement> result;
 | 
				
			||||||
	result.emplace_back(ExpressionStatement{_debugData, FunctionCall{
 | 
						result.emplace_back(ExpressionStatement{_debugData, FunctionCall{
 | 
				
			||||||
		_debugData,
 | 
							_debugData,
 | 
				
			||||||
		Identifier{_debugData, memoryStoreFunction->name},
 | 
							Identifier{_debugData, memoryStoreFunction->name},
 | 
				
			||||||
@ -77,7 +76,7 @@ FunctionCall generateMemoryLoad(Dialect const& _dialect, std::shared_ptr<DebugDa
 | 
				
			|||||||
void StackToMemoryMover::run(
 | 
					void StackToMemoryMover::run(
 | 
				
			||||||
	OptimiserStepContext& _context,
 | 
						OptimiserStepContext& _context,
 | 
				
			||||||
	u256 _reservedMemory,
 | 
						u256 _reservedMemory,
 | 
				
			||||||
	map<YulString, uint64_t> const& _memorySlots,
 | 
						std::map<YulString, uint64_t> const& _memorySlots,
 | 
				
			||||||
	uint64_t _numRequiredSlots,
 | 
						uint64_t _numRequiredSlots,
 | 
				
			||||||
	Block& _block
 | 
						Block& _block
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -91,7 +90,7 @@ void StackToMemoryMover::run(
 | 
				
			|||||||
			util::mapTuple([](YulString _name, FunctionDefinition const* _funDef) {
 | 
								util::mapTuple([](YulString _name, FunctionDefinition const* _funDef) {
 | 
				
			||||||
				return make_pair(_name, _funDef->returnVariables);
 | 
									return make_pair(_name, _funDef->returnVariables);
 | 
				
			||||||
			}),
 | 
								}),
 | 
				
			||||||
			map<YulString, TypedNameList>{}
 | 
								std::map<YulString, TypedNameList>{}
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
	stackToMemoryMover(_block);
 | 
						stackToMemoryMover(_block);
 | 
				
			||||||
@ -101,7 +100,7 @@ void StackToMemoryMover::run(
 | 
				
			|||||||
StackToMemoryMover::StackToMemoryMover(
 | 
					StackToMemoryMover::StackToMemoryMover(
 | 
				
			||||||
	OptimiserStepContext& _context,
 | 
						OptimiserStepContext& _context,
 | 
				
			||||||
	VariableMemoryOffsetTracker const& _memoryOffsetTracker,
 | 
						VariableMemoryOffsetTracker const& _memoryOffsetTracker,
 | 
				
			||||||
	map<YulString, TypedNameList> _functionReturnVariables
 | 
						std::map<YulString, TypedNameList> _functionReturnVariables
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
m_context(_context),
 | 
					m_context(_context),
 | 
				
			||||||
m_memoryOffsetTracker(_memoryOffsetTracker),
 | 
					m_memoryOffsetTracker(_memoryOffsetTracker),
 | 
				
			||||||
@ -121,7 +120,7 @@ void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition)
 | 
				
			|||||||
	// variable arguments we might generate below.
 | 
						// variable arguments we might generate below.
 | 
				
			||||||
	ASTModifier::operator()(_functionDefinition);
 | 
						ASTModifier::operator()(_functionDefinition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vector<Statement> memoryVariableInits;
 | 
						std::vector<Statement> memoryVariableInits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// All function parameters with a memory slot are moved at the beginning of the function body.
 | 
						// All function parameters with a memory slot are moved at the beginning of the function body.
 | 
				
			||||||
	for (TypedName const& param: _functionDefinition.parameters)
 | 
						for (TypedName const& param: _functionDefinition.parameters)
 | 
				
			||||||
@ -147,7 +146,7 @@ void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition)
 | 
				
			|||||||
	if (_functionDefinition.returnVariables.size() == 1 && m_memoryOffsetTracker(_functionDefinition.returnVariables.front().name))
 | 
						if (_functionDefinition.returnVariables.size() == 1 && m_memoryOffsetTracker(_functionDefinition.returnVariables.front().name))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		TypedNameList stackParameters = _functionDefinition.parameters | ranges::views::filter(
 | 
							TypedNameList stackParameters = _functionDefinition.parameters | ranges::views::filter(
 | 
				
			||||||
			not_fn(m_memoryOffsetTracker)
 | 
								std::not_fn(m_memoryOffsetTracker)
 | 
				
			||||||
		) | ranges::to<TypedNameList>;
 | 
							) | ranges::to<TypedNameList>;
 | 
				
			||||||
		// Generate new function without return variable and with only the non-moved parameters.
 | 
							// Generate new function without return variable and with only the non-moved parameters.
 | 
				
			||||||
		YulString newFunctionName = m_context.dispenser.newName(_functionDefinition.name);
 | 
							YulString newFunctionName = m_context.dispenser.newName(_functionDefinition.name);
 | 
				
			||||||
@ -173,13 +172,13 @@ void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition)
 | 
				
			|||||||
				Identifier{_functionDefinition.debugData, newFunctionName},
 | 
									Identifier{_functionDefinition.debugData, newFunctionName},
 | 
				
			||||||
				stackParameters | ranges::views::transform([&](TypedName const& _arg) {
 | 
									stackParameters | ranges::views::transform([&](TypedName const& _arg) {
 | 
				
			||||||
					return Expression{Identifier{_arg.debugData, newArgumentNames.at(_arg.name)}};
 | 
										return Expression{Identifier{_arg.debugData, newArgumentNames.at(_arg.name)}};
 | 
				
			||||||
				}) | ranges::to<vector<Expression>>
 | 
									}) | ranges::to<std::vector<Expression>>
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		_functionDefinition.body.statements.emplace_back(Assignment{
 | 
							_functionDefinition.body.statements.emplace_back(Assignment{
 | 
				
			||||||
			_functionDefinition.debugData,
 | 
								_functionDefinition.debugData,
 | 
				
			||||||
			{Identifier{_functionDefinition.debugData, _functionDefinition.returnVariables.front().name}},
 | 
								{Identifier{_functionDefinition.debugData, _functionDefinition.returnVariables.front().name}},
 | 
				
			||||||
			make_unique<Expression>(generateMemoryLoad(
 | 
								std::make_unique<Expression>(generateMemoryLoad(
 | 
				
			||||||
				m_context.dialect,
 | 
									m_context.dialect,
 | 
				
			||||||
				_functionDefinition.debugData,
 | 
									_functionDefinition.debugData,
 | 
				
			||||||
				*m_memoryOffsetTracker(_functionDefinition.returnVariables.front().name)
 | 
									*m_memoryOffsetTracker(_functionDefinition.returnVariables.front().name)
 | 
				
			||||||
@ -192,24 +191,24 @@ void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition)
 | 
				
			|||||||
		_functionDefinition.body.statements = std::move(memoryVariableInits) + std::move(_functionDefinition.body.statements);
 | 
							_functionDefinition.body.statements = std::move(memoryVariableInits) + std::move(_functionDefinition.body.statements);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_functionDefinition.returnVariables = _functionDefinition.returnVariables | ranges::views::filter(
 | 
						_functionDefinition.returnVariables = _functionDefinition.returnVariables | ranges::views::filter(
 | 
				
			||||||
		not_fn(m_memoryOffsetTracker)
 | 
							std::not_fn(m_memoryOffsetTracker)
 | 
				
			||||||
	) | ranges::to<TypedNameList>;
 | 
						) | ranges::to<TypedNameList>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StackToMemoryMover::operator()(Block& _block)
 | 
					void StackToMemoryMover::operator()(Block& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	using OptionalStatements = optional<vector<Statement>>;
 | 
						using OptionalStatements = std::optional<std::vector<Statement>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto rewriteAssignmentOrVariableDeclarationLeftHandSide = [this](
 | 
						auto rewriteAssignmentOrVariableDeclarationLeftHandSide = [this](
 | 
				
			||||||
		auto& _stmt,
 | 
							auto& _stmt,
 | 
				
			||||||
		auto& _lhsVars
 | 
							auto& _lhsVars
 | 
				
			||||||
	) -> OptionalStatements {
 | 
						) -> OptionalStatements {
 | 
				
			||||||
		using StatementType = decay_t<decltype(_stmt)>;
 | 
							using StatementType = std::decay_t<decltype(_stmt)>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto debugData = _stmt.debugData;
 | 
							auto debugData = _stmt.debugData;
 | 
				
			||||||
		if (_lhsVars.size() == 1)
 | 
							if (_lhsVars.size() == 1)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (optional<YulString> offset = m_memoryOffsetTracker(_lhsVars.front().name))
 | 
								if (std::optional<YulString> offset = m_memoryOffsetTracker(_lhsVars.front().name))
 | 
				
			||||||
				return generateMemoryStore(
 | 
									return generateMemoryStore(
 | 
				
			||||||
					m_context.dialect,
 | 
										m_context.dialect,
 | 
				
			||||||
					debugData,
 | 
										debugData,
 | 
				
			||||||
@ -219,48 +218,48 @@ void StackToMemoryMover::operator()(Block& _block)
 | 
				
			|||||||
			else
 | 
								else
 | 
				
			||||||
				return {};
 | 
									return {};
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		vector<optional<YulString>> rhsMemorySlots;
 | 
							std::vector<std::optional<YulString>> rhsMemorySlots;
 | 
				
			||||||
		if (_stmt.value)
 | 
							if (_stmt.value)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			FunctionCall const* functionCall = get_if<FunctionCall>(_stmt.value.get());
 | 
								FunctionCall const* functionCall = std::get_if<FunctionCall>(_stmt.value.get());
 | 
				
			||||||
			yulAssert(functionCall, "");
 | 
								yulAssert(functionCall, "");
 | 
				
			||||||
			if (m_context.dialect.builtin(functionCall->functionName.name))
 | 
								if (m_context.dialect.builtin(functionCall->functionName.name))
 | 
				
			||||||
				rhsMemorySlots = vector<optional<YulString>>(_lhsVars.size(), nullopt);
 | 
									rhsMemorySlots = std::vector<std::optional<YulString>>(_lhsVars.size(), std::nullopt);
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				rhsMemorySlots =
 | 
									rhsMemorySlots =
 | 
				
			||||||
					m_functionReturnVariables.at(functionCall->functionName.name) |
 | 
										m_functionReturnVariables.at(functionCall->functionName.name) |
 | 
				
			||||||
					ranges::views::transform(m_memoryOffsetTracker) |
 | 
										ranges::views::transform(m_memoryOffsetTracker) |
 | 
				
			||||||
					ranges::to<vector<optional<YulString>>>;
 | 
										ranges::to<std::vector<std::optional<YulString>>>;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			rhsMemorySlots = vector<optional<YulString>>(_lhsVars.size(), nullopt);
 | 
								rhsMemorySlots = std::vector<std::optional<YulString>>(_lhsVars.size(), std::nullopt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Nothing to do, if the right-hand-side remains entirely on the stack and
 | 
							// Nothing to do, if the right-hand-side remains entirely on the stack and
 | 
				
			||||||
		// none of the variables in the left-hand-side are moved.
 | 
							// none of the variables in the left-hand-side are moved.
 | 
				
			||||||
		if (
 | 
							if (
 | 
				
			||||||
			ranges::none_of(rhsMemorySlots, [](optional<YulString> const& _slot) { return _slot.has_value(); }) &&
 | 
								ranges::none_of(rhsMemorySlots, [](std::optional<YulString> const& _slot) { return _slot.has_value(); }) &&
 | 
				
			||||||
			!util::contains_if(_lhsVars, m_memoryOffsetTracker)
 | 
								!util::contains_if(_lhsVars, m_memoryOffsetTracker)
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
			return {};
 | 
								return {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		vector<Statement> memoryAssignments;
 | 
							std::vector<Statement> memoryAssignments;
 | 
				
			||||||
		vector<Statement> variableAssignments;
 | 
							std::vector<Statement> variableAssignments;
 | 
				
			||||||
		VariableDeclaration tempDecl{debugData, {}, std::move(_stmt.value)};
 | 
							VariableDeclaration tempDecl{debugData, {}, std::move(_stmt.value)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		yulAssert(rhsMemorySlots.size() == _lhsVars.size(), "");
 | 
							yulAssert(rhsMemorySlots.size() == _lhsVars.size(), "");
 | 
				
			||||||
		for (auto&& [lhsVar, rhsSlot]: ranges::views::zip(_lhsVars, rhsMemorySlots))
 | 
							for (auto&& [lhsVar, rhsSlot]: ranges::views::zip(_lhsVars, rhsMemorySlots))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			unique_ptr<Expression> rhs;
 | 
								std::unique_ptr<Expression> rhs;
 | 
				
			||||||
			if (rhsSlot)
 | 
								if (rhsSlot)
 | 
				
			||||||
				rhs = make_unique<Expression>(generateMemoryLoad(m_context.dialect, debugData, *rhsSlot));
 | 
									rhs = std::make_unique<Expression>(generateMemoryLoad(m_context.dialect, debugData, *rhsSlot));
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				YulString tempVarName = m_nameDispenser.newName(lhsVar.name);
 | 
									YulString tempVarName = m_nameDispenser.newName(lhsVar.name);
 | 
				
			||||||
				tempDecl.variables.emplace_back(TypedName{lhsVar.debugData, tempVarName, {}});
 | 
									tempDecl.variables.emplace_back(TypedName{lhsVar.debugData, tempVarName, {}});
 | 
				
			||||||
				rhs = make_unique<Expression>(Identifier{debugData, tempVarName});
 | 
									rhs = std::make_unique<Expression>(Identifier{debugData, tempVarName});
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (optional<YulString> offset = m_memoryOffsetTracker(lhsVar.name))
 | 
								if (std::optional<YulString> offset = m_memoryOffsetTracker(lhsVar.name))
 | 
				
			||||||
				memoryAssignments += generateMemoryStore(
 | 
									memoryAssignments += generateMemoryStore(
 | 
				
			||||||
					m_context.dialect,
 | 
										m_context.dialect,
 | 
				
			||||||
					_stmt.debugData,
 | 
										_stmt.debugData,
 | 
				
			||||||
@ -275,7 +274,7 @@ void StackToMemoryMover::operator()(Block& _block)
 | 
				
			|||||||
				});
 | 
									});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		vector<Statement> result;
 | 
							std::vector<Statement> result;
 | 
				
			||||||
		if (tempDecl.variables.empty())
 | 
							if (tempDecl.variables.empty())
 | 
				
			||||||
			result.emplace_back(ExpressionStatement{debugData, *std::move(tempDecl.value)});
 | 
								result.emplace_back(ExpressionStatement{debugData, *std::move(tempDecl.value)});
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
@ -292,9 +291,9 @@ void StackToMemoryMover::operator()(Block& _block)
 | 
				
			|||||||
		[&](Statement& _statement) -> OptionalStatements
 | 
							[&](Statement& _statement) -> OptionalStatements
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			visit(_statement);
 | 
								visit(_statement);
 | 
				
			||||||
			if (auto* assignment = get_if<Assignment>(&_statement))
 | 
								if (auto* assignment = std::get_if<Assignment>(&_statement))
 | 
				
			||||||
				return rewriteAssignmentOrVariableDeclarationLeftHandSide(*assignment, assignment->variableNames);
 | 
									return rewriteAssignmentOrVariableDeclarationLeftHandSide(*assignment, assignment->variableNames);
 | 
				
			||||||
			else if (auto* varDecl = get_if<VariableDeclaration>(&_statement))
 | 
								else if (auto* varDecl = std::get_if<VariableDeclaration>(&_statement))
 | 
				
			||||||
				return rewriteAssignmentOrVariableDeclarationLeftHandSide(*varDecl, varDecl->variables);
 | 
									return rewriteAssignmentOrVariableDeclarationLeftHandSide(*varDecl, varDecl->variables);
 | 
				
			||||||
			return {};
 | 
								return {};
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -304,12 +303,12 @@ void StackToMemoryMover::operator()(Block& _block)
 | 
				
			|||||||
void StackToMemoryMover::visit(Expression& _expression)
 | 
					void StackToMemoryMover::visit(Expression& _expression)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ASTModifier::visit(_expression);
 | 
						ASTModifier::visit(_expression);
 | 
				
			||||||
	if (Identifier* identifier = get_if<Identifier>(&_expression))
 | 
						if (Identifier* identifier = std::get_if<Identifier>(&_expression))
 | 
				
			||||||
		if (optional<YulString> offset = m_memoryOffsetTracker(identifier->name))
 | 
							if (std::optional<YulString> offset = m_memoryOffsetTracker(identifier->name))
 | 
				
			||||||
			_expression = generateMemoryLoad(m_context.dialect, identifier->debugData, *offset);
 | 
								_expression = generateMemoryLoad(m_context.dialect, identifier->debugData, *offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(YulString _variable) const
 | 
					std::optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(YulString _variable) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (m_memorySlots.count(_variable))
 | 
						if (m_memorySlots.count(_variable))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -318,15 +317,15 @@ optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(
 | 
				
			|||||||
		return YulString{toCompactHexWithPrefix(m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1))};
 | 
							return YulString{toCompactHexWithPrefix(m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1))};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(TypedName const& _variable) const
 | 
					std::optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(TypedName const& _variable) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return (*this)(_variable.name);
 | 
						return (*this)(_variable.name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(Identifier const& _variable) const
 | 
					std::optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(Identifier const& _variable) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return (*this)(_variable.name);
 | 
						return (*this)(_variable.name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -21,11 +21,10 @@
 | 
				
			|||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
#include <libsolutil/Visitor.h>
 | 
					#include <libsolutil/Visitor.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using OptionalStatements = std::optional<vector<Statement>>;
 | 
					using OptionalStatements = std::optional<std::vector<Statement>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace
 | 
					namespace
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -52,12 +51,12 @@ OptionalStatements replaceConstArgSwitch(Switch& _switchStmt, u256 const& _const
 | 
				
			|||||||
	if (matchingCaseBlock)
 | 
						if (matchingCaseBlock)
 | 
				
			||||||
		return util::make_vector<Statement>(std::move(*matchingCaseBlock));
 | 
							return util::make_vector<Statement>(std::move(*matchingCaseBlock));
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return optional<vector<Statement>>{vector<Statement>{}};
 | 
							return std::optional<std::vector<Statement>>{std::vector<Statement>{}};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<u256> hasLiteralValue(Expression const& _expression)
 | 
					std::optional<u256> hasLiteralValue(Expression const& _expression)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<Literal>(_expression))
 | 
						if (std::holds_alternative<Literal>(_expression))
 | 
				
			||||||
		return valueOfLiteral(std::get<Literal>(_expression));
 | 
							return valueOfLiteral(std::get<Literal>(_expression));
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return std::optional<u256>();
 | 
							return std::optional<u256>();
 | 
				
			||||||
@ -99,7 +98,7 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
 | 
				
			|||||||
			if (expressionAlwaysTrue(*_ifStmt.condition))
 | 
								if (expressionAlwaysTrue(*_ifStmt.condition))
 | 
				
			||||||
				return {std::move(_ifStmt.body.statements)};
 | 
									return {std::move(_ifStmt.body.statements)};
 | 
				
			||||||
			else if (expressionAlwaysFalse(*_ifStmt.condition))
 | 
								else if (expressionAlwaysFalse(*_ifStmt.condition))
 | 
				
			||||||
				return {vector<Statement>{}};
 | 
									return {std::vector<Statement>{}};
 | 
				
			||||||
			return {};
 | 
								return {};
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		[&](Switch& _switchStmt) -> OptionalStatements {
 | 
							[&](Switch& _switchStmt) -> OptionalStatements {
 | 
				
			||||||
 | 
				
			|||||||
@ -23,13 +23,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libyul/AST.h>
 | 
					#include <libyul/AST.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Expression Substitution::translate(Expression const& _expression)
 | 
					Expression Substitution::translate(Expression const& _expression)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (holds_alternative<Identifier>(_expression))
 | 
						if (std::holds_alternative<Identifier>(_expression))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		YulString name = std::get<Identifier>(_expression).name;
 | 
							YulString name = std::get<Identifier>(_expression).name;
 | 
				
			||||||
		if (m_substitutions.count(name))
 | 
							if (m_substitutions.count(name))
 | 
				
			||||||
 | 
				
			|||||||
@ -86,12 +86,12 @@
 | 
				
			|||||||
#include <fmt/format.h>
 | 
					#include <fmt/format.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
#ifdef PROFILE_OPTIMIZER_STEPS
 | 
					#ifdef PROFILE_OPTIMIZER_STEPS
 | 
				
			||||||
using namespace std::chrono;
 | 
					using namespace std::chrono;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					using namespace std::string_literals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace
 | 
					namespace
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -136,10 +136,10 @@ void OptimiserSuite::run(
 | 
				
			|||||||
	GasMeter const* _meter,
 | 
						GasMeter const* _meter,
 | 
				
			||||||
	Object& _object,
 | 
						Object& _object,
 | 
				
			||||||
	bool _optimizeStackAllocation,
 | 
						bool _optimizeStackAllocation,
 | 
				
			||||||
	string_view _optimisationSequence,
 | 
						std::string_view _optimisationSequence,
 | 
				
			||||||
	string_view _optimisationCleanupSequence,
 | 
						std::string_view _optimisationCleanupSequence,
 | 
				
			||||||
	optional<size_t> _expectedExecutionsPerDeployment,
 | 
						std::optional<size_t> _expectedExecutionsPerDeployment,
 | 
				
			||||||
	set<YulString> const& _externallyUsedIdentifiers
 | 
						std::set<YulString> const& _externallyUsedIdentifiers
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect);
 | 
						EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect);
 | 
				
			||||||
@ -148,7 +148,7 @@ void OptimiserSuite::run(
 | 
				
			|||||||
		evmDialect &&
 | 
							evmDialect &&
 | 
				
			||||||
		evmDialect->evmVersion().canOverchargeGasForCall() &&
 | 
							evmDialect->evmVersion().canOverchargeGasForCall() &&
 | 
				
			||||||
		evmDialect->providesObjectAccess();
 | 
							evmDialect->providesObjectAccess();
 | 
				
			||||||
	set<YulString> reservedIdentifiers = _externallyUsedIdentifiers;
 | 
						std::set<YulString> reservedIdentifiers = _externallyUsedIdentifiers;
 | 
				
			||||||
	reservedIdentifiers += _dialect.fixedFunctionNames();
 | 
						reservedIdentifiers += _dialect.fixedFunctionNames();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*_object.code = std::get<Block>(Disambiguator(
 | 
						*_object.code = std::get<Block>(Disambiguator(
 | 
				
			||||||
@ -226,11 +226,11 @@ namespace
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class... Step>
 | 
					template <class... Step>
 | 
				
			||||||
map<string, unique_ptr<OptimiserStep>> optimiserStepCollection()
 | 
					std::map<std::string, std::unique_ptr<OptimiserStep>> optimiserStepCollection()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	map<string, unique_ptr<OptimiserStep>> ret;
 | 
						std::map<std::string, std::unique_ptr<OptimiserStep>> ret;
 | 
				
			||||||
	for (unique_ptr<OptimiserStep>& s: util::make_vector<unique_ptr<OptimiserStep>>(
 | 
						for (std::unique_ptr<OptimiserStep>& s: util::make_vector<std::unique_ptr<OptimiserStep>>(
 | 
				
			||||||
		(make_unique<OptimiserStepInstance<Step>>())...
 | 
							(std::make_unique<OptimiserStepInstance<Step>>())...
 | 
				
			||||||
	))
 | 
						))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		yulAssert(!ret.count(s->name), "");
 | 
							yulAssert(!ret.count(s->name), "");
 | 
				
			||||||
@ -241,9 +241,9 @@ map<string, unique_ptr<OptimiserStep>> optimiserStepCollection()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
 | 
					std::map<std::string, std::unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static map<string, unique_ptr<OptimiserStep>> instance;
 | 
						static std::map<std::string, std::unique_ptr<OptimiserStep>> instance;
 | 
				
			||||||
	if (instance.empty())
 | 
						if (instance.empty())
 | 
				
			||||||
		instance = optimiserStepCollection<
 | 
							instance = optimiserStepCollection<
 | 
				
			||||||
			BlockFlattener,
 | 
								BlockFlattener,
 | 
				
			||||||
@ -284,9 +284,9 @@ map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
 | 
				
			|||||||
	return instance;
 | 
						return instance;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
 | 
					std::map<std::string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static map<string, char> lookupTable{
 | 
						static std::map<std::string, char> lookupTable{
 | 
				
			||||||
		{BlockFlattener::name,                'f'},
 | 
							{BlockFlattener::name,                'f'},
 | 
				
			||||||
		{CircularReferencesPruner::name,      'l'},
 | 
							{CircularReferencesPruner::name,      'l'},
 | 
				
			||||||
		{CommonSubexpressionEliminator::name, 'c'},
 | 
							{CommonSubexpressionEliminator::name, 'c'},
 | 
				
			||||||
@ -322,23 +322,23 @@ map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
	yulAssert(lookupTable.size() == allSteps().size(), "");
 | 
						yulAssert(lookupTable.size() == allSteps().size(), "");
 | 
				
			||||||
	yulAssert((
 | 
						yulAssert((
 | 
				
			||||||
			util::convertContainer<set<char>>(string(NonStepAbbreviations)) -
 | 
								util::convertContainer<std::set<char>>(std::string(NonStepAbbreviations)) -
 | 
				
			||||||
			util::convertContainer<set<char>>(lookupTable | ranges::views::values)
 | 
								util::convertContainer<std::set<char>>(lookupTable | ranges::views::values)
 | 
				
			||||||
		).size() == string(NonStepAbbreviations).size(),
 | 
							).size() == std::string(NonStepAbbreviations).size(),
 | 
				
			||||||
		"Step abbreviation conflicts with a character reserved for another syntactic element"
 | 
							"Step abbreviation conflicts with a character reserved for another syntactic element"
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return lookupTable;
 | 
						return lookupTable;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
map<char, string> const& OptimiserSuite::stepAbbreviationToNameMap()
 | 
					std::map<char, std::string> const& OptimiserSuite::stepAbbreviationToNameMap()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static map<char, string> lookupTable = util::invertMap(stepNameToAbbreviationMap());
 | 
						static std::map<char, std::string> lookupTable = util::invertMap(stepNameToAbbreviationMap());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return lookupTable;
 | 
						return lookupTable;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
 | 
					void OptimiserSuite::validateSequence(std::string_view _stepAbbreviations)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int8_t nestingLevel = 0;
 | 
						int8_t nestingLevel = 0;
 | 
				
			||||||
	int8_t colonDelimiters = 0;
 | 
						int8_t colonDelimiters = 0;
 | 
				
			||||||
@ -349,7 +349,7 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
 | 
				
			|||||||
		case '\n':
 | 
							case '\n':
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case '[':
 | 
							case '[':
 | 
				
			||||||
			assertThrow(nestingLevel < numeric_limits<int8_t>::max(), OptimizerException, "Brackets nested too deep");
 | 
								assertThrow(nestingLevel < std::numeric_limits<int8_t>::max(), OptimizerException, "Brackets nested too deep");
 | 
				
			||||||
			nestingLevel++;
 | 
								nestingLevel++;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case ']':
 | 
							case ']':
 | 
				
			||||||
@ -364,7 +364,7 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
 | 
				
			|||||||
		default:
 | 
							default:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			yulAssert(
 | 
								yulAssert(
 | 
				
			||||||
				string(NonStepAbbreviations).find(abbreviation) == string::npos,
 | 
									std::string(NonStepAbbreviations).find(abbreviation) == std::string::npos,
 | 
				
			||||||
				"Unhandled syntactic element in the abbreviation sequence"
 | 
									"Unhandled syntactic element in the abbreviation sequence"
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			assertThrow(
 | 
								assertThrow(
 | 
				
			||||||
@ -372,7 +372,7 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
 | 
				
			|||||||
				OptimizerException,
 | 
									OptimizerException,
 | 
				
			||||||
				"'"s + abbreviation + "' is not a valid step abbreviation"
 | 
									"'"s + abbreviation + "' is not a valid step abbreviation"
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			optional<string> invalid = allSteps().at(stepAbbreviationToNameMap().at(abbreviation))->invalidInCurrentEnvironment();
 | 
								std::optional<std::string> invalid = allSteps().at(stepAbbreviationToNameMap().at(abbreviation))->invalidInCurrentEnvironment();
 | 
				
			||||||
			assertThrow(
 | 
								assertThrow(
 | 
				
			||||||
				!invalid.has_value(),
 | 
									!invalid.has_value(),
 | 
				
			||||||
				OptimizerException,
 | 
									OptimizerException,
 | 
				
			||||||
@ -383,12 +383,12 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
 | 
				
			|||||||
	assertThrow(nestingLevel == 0, OptimizerException, "Unbalanced brackets");
 | 
						assertThrow(nestingLevel == 0, OptimizerException, "Unbalanced brackets");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bool _repeatUntilStable)
 | 
					void OptimiserSuite::runSequence(std::string_view _stepAbbreviations, Block& _ast, bool _repeatUntilStable)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	validateSequence(_stepAbbreviations);
 | 
						validateSequence(_stepAbbreviations);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// This splits 'aaa[bbb]ccc...' into 'aaa' and '[bbb]ccc...'.
 | 
						// This splits 'aaa[bbb]ccc...' into 'aaa' and '[bbb]ccc...'.
 | 
				
			||||||
	auto extractNonNestedPrefix = [](string_view _tail) -> tuple<string_view, string_view>
 | 
						auto extractNonNestedPrefix = [](std::string_view _tail) -> std::tuple<std::string_view, std::string_view>
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		for (size_t i = 0; i < _tail.size(); ++i)
 | 
							for (size_t i = 0; i < _tail.size(); ++i)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -400,7 +400,7 @@ void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bo
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// This splits '[bbb]ccc...' into 'bbb' and 'ccc...'.
 | 
						// This splits '[bbb]ccc...' into 'bbb' and 'ccc...'.
 | 
				
			||||||
	auto extractBracketContent = [](string_view _tail) -> tuple<string_view, string_view>
 | 
						auto extractBracketContent = [](std::string_view _tail) -> std::tuple<std::string_view, std::string_view>
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		yulAssert(!_tail.empty() && _tail[0] == '[');
 | 
							yulAssert(!_tail.empty() && _tail[0] == '[');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -410,7 +410,7 @@ void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bo
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			if (abbreviation == '[')
 | 
								if (abbreviation == '[')
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				yulAssert(nestingLevel < numeric_limits<int8_t>::max());
 | 
									yulAssert(nestingLevel < std::numeric_limits<int8_t>::max());
 | 
				
			||||||
				++nestingLevel;
 | 
									++nestingLevel;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else if (abbreviation == ']')
 | 
								else if (abbreviation == ']')
 | 
				
			||||||
@ -427,20 +427,20 @@ void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bo
 | 
				
			|||||||
		return {_tail.substr(1, contentLength), _tail.substr(contentLength + 2)};
 | 
							return {_tail.substr(1, contentLength), _tail.substr(contentLength + 2)};
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto abbreviationsToSteps = [](string_view _sequence) -> vector<string>
 | 
						auto abbreviationsToSteps = [](std::string_view _sequence) -> std::vector<std::string>
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		vector<string> steps;
 | 
							std::vector<std::string> steps;
 | 
				
			||||||
		for (char abbreviation: _sequence)
 | 
							for (char abbreviation: _sequence)
 | 
				
			||||||
			if (abbreviation != ' ' && abbreviation != '\n')
 | 
								if (abbreviation != ' ' && abbreviation != '\n')
 | 
				
			||||||
				steps.emplace_back(stepAbbreviationToNameMap().at(abbreviation));
 | 
									steps.emplace_back(stepAbbreviationToNameMap().at(abbreviation));
 | 
				
			||||||
		return steps;
 | 
							return steps;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vector<tuple<string_view, bool>> subsequences;
 | 
						std::vector<std::tuple<std::string_view, bool>> subsequences;
 | 
				
			||||||
	string_view tail = _stepAbbreviations;
 | 
						std::string_view tail = _stepAbbreviations;
 | 
				
			||||||
	while (!tail.empty())
 | 
						while (!tail.empty())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		string_view subsequence;
 | 
							std::string_view subsequence;
 | 
				
			||||||
		tie(subsequence, tail) = extractNonNestedPrefix(tail);
 | 
							tie(subsequence, tail) = extractNonNestedPrefix(tail);
 | 
				
			||||||
		if (subsequence.size() > 0)
 | 
							if (subsequence.size() > 0)
 | 
				
			||||||
			subsequences.push_back({subsequence, false});
 | 
								subsequences.push_back({subsequence, false});
 | 
				
			||||||
@ -474,15 +474,15 @@ void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bo
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast)
 | 
					void OptimiserSuite::runSequence(std::vector<std::string> const& _steps, Block& _ast)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unique_ptr<Block> copy;
 | 
						std::unique_ptr<Block> copy;
 | 
				
			||||||
	if (m_debug == Debug::PrintChanges)
 | 
						if (m_debug == Debug::PrintChanges)
 | 
				
			||||||
		copy = make_unique<Block>(std::get<Block>(ASTCopier{}(_ast)));
 | 
							copy = std::make_unique<Block>(std::get<Block>(ASTCopier{}(_ast)));
 | 
				
			||||||
	for (string const& step: _steps)
 | 
						for (std::string const& step: _steps)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (m_debug == Debug::PrintStep)
 | 
							if (m_debug == Debug::PrintStep)
 | 
				
			||||||
			cout << "Running " << step << endl;
 | 
								std::cout << "Running " << step << std::endl;
 | 
				
			||||||
#ifdef PROFILE_OPTIMIZER_STEPS
 | 
					#ifdef PROFILE_OPTIMIZER_STEPS
 | 
				
			||||||
		steady_clock::time_point startTime = steady_clock::now();
 | 
							steady_clock::time_point startTime = steady_clock::now();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -495,12 +495,12 @@ void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast)
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			// TODO should add switch to also compare variable names!
 | 
								// TODO should add switch to also compare variable names!
 | 
				
			||||||
			if (SyntacticallyEqual{}.statementEqual(_ast, *copy))
 | 
								if (SyntacticallyEqual{}.statementEqual(_ast, *copy))
 | 
				
			||||||
				cout << "== Running " << step << " did not cause changes." << endl;
 | 
									std::cout << "== Running " << step << " did not cause changes." << std::endl;
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				cout << "== Running " << step << " changed the AST." << endl;
 | 
									std::cout << "== Running " << step << " changed the AST." << std::endl;
 | 
				
			||||||
				cout << AsmPrinter{}(_ast) << endl;
 | 
									std::cout << AsmPrinter{}(_ast) << std::endl;
 | 
				
			||||||
				copy = make_unique<Block>(std::get<Block>(ASTCopier{}(_ast)));
 | 
									copy = std::make_unique<Block>(std::get<Block>(ASTCopier{}(_ast)));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/CommonData.h>
 | 
					#include <libsolutil/CommonData.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <libsolutil/Visitor.h>
 | 
					#include <libsolutil/Visitor.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -81,7 +80,7 @@ YulString TypeInfo::typeOf(Expression const& _expression) const
 | 
				
			|||||||
	return std::visit(GenericVisitor{
 | 
						return std::visit(GenericVisitor{
 | 
				
			||||||
		[&](FunctionCall const& _funCall) {
 | 
							[&](FunctionCall const& _funCall) {
 | 
				
			||||||
			YulString name = _funCall.functionName.name;
 | 
								YulString name = _funCall.functionName.name;
 | 
				
			||||||
			vector<YulString> const* retTypes = nullptr;
 | 
								std::vector<YulString> const* retTypes = nullptr;
 | 
				
			||||||
			if (BuiltinFunction const* fun = m_dialect.builtin(name))
 | 
								if (BuiltinFunction const* fun = m_dialect.builtin(name))
 | 
				
			||||||
				retTypes = &fun->returns;
 | 
									retTypes = &fun->returns;
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,7 +47,7 @@ void UnusedAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	uae.m_storesToRemove += uae.m_allStores - uae.m_usedStores;
 | 
						uae.m_storesToRemove += uae.m_allStores - uae.m_usedStores;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set<Statement const*> toRemove{uae.m_storesToRemove.begin(), uae.m_storesToRemove.end()};
 | 
						std::set<Statement const*> toRemove{uae.m_storesToRemove.begin(), uae.m_storesToRemove.end()};
 | 
				
			||||||
	StatementRemover remover{toRemove};
 | 
						StatementRemover remover{toRemove};
 | 
				
			||||||
	remover(_ast);
 | 
						remover(_ast);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -103,7 +102,7 @@ void UnusedAssignEliminator::operator()(Block const& _block)
 | 
				
			|||||||
	UnusedStoreBase::operator()(_block);
 | 
						UnusedStoreBase::operator()(_block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto const& statement: _block.statements)
 | 
						for (auto const& statement: _block.statements)
 | 
				
			||||||
		if (auto const* varDecl = get_if<VariableDeclaration>(&statement))
 | 
							if (auto const* varDecl = std::get_if<VariableDeclaration>(&statement))
 | 
				
			||||||
			for (auto const& var: varDecl->variables)
 | 
								for (auto const& var: varDecl->variables)
 | 
				
			||||||
				m_activeStores.erase(var.name);
 | 
									m_activeStores.erase(var.name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -112,7 +111,7 @@ void UnusedAssignEliminator::visit(Statement const& _statement)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	UnusedStoreBase::visit(_statement);
 | 
						UnusedStoreBase::visit(_statement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (auto const* assignment = get_if<Assignment>(&_statement))
 | 
						if (auto const* assignment = std::get_if<Assignment>(&_statement))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// We do not remove assignments whose values might have side-effects,
 | 
							// We do not remove assignments whose values might have side-effects,
 | 
				
			||||||
		// but clear the active stores to the assigned variables in any case.
 | 
							// but clear the active stores to the assigned variables in any case.
 | 
				
			||||||
 | 
				
			|||||||
@ -36,14 +36,13 @@
 | 
				
			|||||||
#include <optional>
 | 
					#include <optional>
 | 
				
			||||||
#include <variant>
 | 
					#include <variant>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity::util;
 | 
					using namespace solidity::util;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
using namespace solidity::yul::unusedFunctionsCommon;
 | 
					using namespace solidity::yul::unusedFunctionsCommon;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _ast)
 | 
					void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	map<YulString, size_t> references = VariableReferencesCounter::countReferences(_ast);
 | 
						std::map<YulString, size_t> references = VariableReferencesCounter::countReferences(_ast);
 | 
				
			||||||
	auto used = [&](auto v) -> bool { return references.count(v.name); };
 | 
						auto used = [&](auto v) -> bool { return references.count(v.name); };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Function name and a pair of boolean masks, the first corresponds to parameters and the second
 | 
						// Function name and a pair of boolean masks, the first corresponds to parameters and the second
 | 
				
			||||||
@ -55,12 +54,12 @@ void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _
 | 
				
			|||||||
	// Similarly for the second vector in the pair, a value `false` at index `i` indicates that the
 | 
						// Similarly for the second vector in the pair, a value `false` at index `i` indicates that the
 | 
				
			||||||
	// return parameter at index `i` in `FunctionDefinition::returnVariables` is unused inside
 | 
						// return parameter at index `i` in `FunctionDefinition::returnVariables` is unused inside
 | 
				
			||||||
	// function body.
 | 
						// function body.
 | 
				
			||||||
	map<YulString, pair<vector<bool>, vector<bool>>> usedParametersAndReturnVariables;
 | 
						std::map<YulString, std::pair<std::vector<bool>, std::vector<bool>>> usedParametersAndReturnVariables;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Step 1 of UnusedFunctionParameterPruner: Find functions whose parameters (both arguments and
 | 
						// Step 1 of UnusedFunctionParameterPruner: Find functions whose parameters (both arguments and
 | 
				
			||||||
	// return-parameters) are not used in its body.
 | 
						// return-parameters) are not used in its body.
 | 
				
			||||||
	for (auto const& statement: _ast.statements)
 | 
						for (auto const& statement: _ast.statements)
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(statement))
 | 
							if (std::holds_alternative<FunctionDefinition>(statement))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			FunctionDefinition const& f = std::get<FunctionDefinition>(statement);
 | 
								FunctionDefinition const& f = std::get<FunctionDefinition>(statement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -73,7 +72,7 @@ void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _
 | 
				
			|||||||
			};
 | 
								};
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set<YulString> functionNamesToFree = util::keys(usedParametersAndReturnVariables);
 | 
						std::set<YulString> functionNamesToFree = util::keys(usedParametersAndReturnVariables);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Step 2 of UnusedFunctionParameterPruner: Renames the function and replaces all references to
 | 
						// Step 2 of UnusedFunctionParameterPruner: Renames the function and replaces all references to
 | 
				
			||||||
	// the function, say `f`, by its new name, say `f_1`.
 | 
						// the function, say `f`, by its new name, say `f_1`.
 | 
				
			||||||
@ -91,17 +90,17 @@ void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _
 | 
				
			|||||||
	// For example: introduce a new 'linking' function `f` with the same the body as `f_1`, but with
 | 
						// For example: introduce a new 'linking' function `f` with the same the body as `f_1`, but with
 | 
				
			||||||
	// reduced parameters, i.e., `function f() -> y { y := 1 }`. Now replace the body of `f_1` with
 | 
						// reduced parameters, i.e., `function f() -> y { y := 1 }`. Now replace the body of `f_1` with
 | 
				
			||||||
	// a call to `f`, i.e., `f_1(x) -> y { y := f() }`.
 | 
						// a call to `f`, i.e., `f_1(x) -> y { y := f() }`.
 | 
				
			||||||
	iterateReplacing(_ast.statements, [&](Statement& _s) -> optional<vector<Statement>> {
 | 
						iterateReplacing(_ast.statements, [&](Statement& _s) -> std::optional<std::vector<Statement>> {
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(_s))
 | 
							if (std::holds_alternative<FunctionDefinition>(_s))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// The original function except that it has a new name (e.g., `f_1`)
 | 
								// The original function except that it has a new name (e.g., `f_1`)
 | 
				
			||||||
			FunctionDefinition& originalFunction = get<FunctionDefinition>(_s);
 | 
								FunctionDefinition& originalFunction = std::get<FunctionDefinition>(_s);
 | 
				
			||||||
			if (newToOriginalNames.count(originalFunction.name))
 | 
								if (newToOriginalNames.count(originalFunction.name))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				YulString linkingFunctionName = originalFunction.name;
 | 
									YulString linkingFunctionName = originalFunction.name;
 | 
				
			||||||
				YulString originalFunctionName = newToOriginalNames.at(linkingFunctionName);
 | 
									YulString originalFunctionName = newToOriginalNames.at(linkingFunctionName);
 | 
				
			||||||
				pair<vector<bool>, vector<bool>> used =
 | 
									std::pair<std::vector<bool>, std::vector<bool>> used =
 | 
				
			||||||
					usedParametersAndReturnVariables.at(originalFunctionName);
 | 
										usedParametersAndReturnVariables.at(originalFunctionName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				FunctionDefinition linkingFunction = createLinkingFunction(
 | 
									FunctionDefinition linkingFunction = createLinkingFunction(
 | 
				
			||||||
@ -122,6 +121,6 @@ void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nullopt;
 | 
							return std::nullopt;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@
 | 
				
			|||||||
#include <libyul/Dialect.h>
 | 
					#include <libyul/Dialect.h>
 | 
				
			||||||
#include <libyul/SideEffects.h>
 | 
					#include <libyul/SideEffects.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -44,8 +43,8 @@ UnusedPruner::UnusedPruner(
 | 
				
			|||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	Block& _ast,
 | 
						Block& _ast,
 | 
				
			||||||
	bool _allowMSizeOptimization,
 | 
						bool _allowMSizeOptimization,
 | 
				
			||||||
	map<YulString, SideEffects> const* _functionSideEffects,
 | 
						std::map<YulString, SideEffects> const* _functionSideEffects,
 | 
				
			||||||
	set<YulString> const& _externallyUsedFunctions
 | 
						std::set<YulString> const& _externallyUsedFunctions
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	m_dialect(_dialect),
 | 
						m_dialect(_dialect),
 | 
				
			||||||
	m_allowMSizeOptimization(_allowMSizeOptimization),
 | 
						m_allowMSizeOptimization(_allowMSizeOptimization),
 | 
				
			||||||
@ -60,7 +59,7 @@ UnusedPruner::UnusedPruner(
 | 
				
			|||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	FunctionDefinition& _function,
 | 
						FunctionDefinition& _function,
 | 
				
			||||||
	bool _allowMSizeOptimization,
 | 
						bool _allowMSizeOptimization,
 | 
				
			||||||
	set<YulString> const& _externallyUsedFunctions
 | 
						std::set<YulString> const& _externallyUsedFunctions
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	m_dialect(_dialect),
 | 
						m_dialect(_dialect),
 | 
				
			||||||
	m_allowMSizeOptimization(_allowMSizeOptimization)
 | 
						m_allowMSizeOptimization(_allowMSizeOptimization)
 | 
				
			||||||
@ -73,7 +72,7 @@ UnusedPruner::UnusedPruner(
 | 
				
			|||||||
void UnusedPruner::operator()(Block& _block)
 | 
					void UnusedPruner::operator()(Block& _block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (auto&& statement: _block.statements)
 | 
						for (auto&& statement: _block.statements)
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(statement))
 | 
							if (std::holds_alternative<FunctionDefinition>(statement))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			FunctionDefinition& funDef = std::get<FunctionDefinition>(statement);
 | 
								FunctionDefinition& funDef = std::get<FunctionDefinition>(statement);
 | 
				
			||||||
			if (!used(funDef.name))
 | 
								if (!used(funDef.name))
 | 
				
			||||||
@ -82,7 +81,7 @@ void UnusedPruner::operator()(Block& _block)
 | 
				
			|||||||
				statement = Block{std::move(funDef.debugData), {}};
 | 
									statement = Block{std::move(funDef.debugData), {}};
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (holds_alternative<VariableDeclaration>(statement))
 | 
							else if (std::holds_alternative<VariableDeclaration>(statement))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			VariableDeclaration& varDecl = std::get<VariableDeclaration>(statement);
 | 
								VariableDeclaration& varDecl = std::get<VariableDeclaration>(statement);
 | 
				
			||||||
			// Multi-variable declarations are special. We can only remove it
 | 
								// Multi-variable declarations are special. We can only remove it
 | 
				
			||||||
@ -114,7 +113,7 @@ void UnusedPruner::operator()(Block& _block)
 | 
				
			|||||||
					}};
 | 
										}};
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (holds_alternative<ExpressionStatement>(statement))
 | 
							else if (std::holds_alternative<ExpressionStatement>(statement))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			ExpressionStatement& exprStmt = std::get<ExpressionStatement>(statement);
 | 
								ExpressionStatement& exprStmt = std::get<ExpressionStatement>(statement);
 | 
				
			||||||
			if (
 | 
								if (
 | 
				
			||||||
@ -136,8 +135,8 @@ void UnusedPruner::runUntilStabilised(
 | 
				
			|||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	Block& _ast,
 | 
						Block& _ast,
 | 
				
			||||||
	bool _allowMSizeOptimization,
 | 
						bool _allowMSizeOptimization,
 | 
				
			||||||
	map<YulString, SideEffects> const* _functionSideEffects,
 | 
						std::map<YulString, SideEffects> const* _functionSideEffects,
 | 
				
			||||||
	set<YulString> const& _externallyUsedFunctions
 | 
						std::set<YulString> const& _externallyUsedFunctions
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	while (true)
 | 
						while (true)
 | 
				
			||||||
@ -154,10 +153,10 @@ void UnusedPruner::runUntilStabilised(
 | 
				
			|||||||
void UnusedPruner::runUntilStabilisedOnFullAST(
 | 
					void UnusedPruner::runUntilStabilisedOnFullAST(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	Block& _ast,
 | 
						Block& _ast,
 | 
				
			||||||
	set<YulString> const& _externallyUsedFunctions
 | 
						std::set<YulString> const& _externallyUsedFunctions
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	map<YulString, SideEffects> functionSideEffects =
 | 
						std::map<YulString, SideEffects> functionSideEffects =
 | 
				
			||||||
		SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast));
 | 
							SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast));
 | 
				
			||||||
	bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, _ast);
 | 
						bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, _ast);
 | 
				
			||||||
	runUntilStabilised(_dialect, _ast, allowMSizeOptimization, &functionSideEffects, _externallyUsedFunctions);
 | 
						runUntilStabilised(_dialect, _ast, allowMSizeOptimization, &functionSideEffects, _externallyUsedFunctions);
 | 
				
			||||||
@ -167,7 +166,7 @@ void UnusedPruner::runUntilStabilised(
 | 
				
			|||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	FunctionDefinition& _function,
 | 
						FunctionDefinition& _function,
 | 
				
			||||||
	bool _allowMSizeOptimization,
 | 
						bool _allowMSizeOptimization,
 | 
				
			||||||
	set<YulString> const& _externallyUsedFunctions
 | 
						std::set<YulString> const& _externallyUsedFunctions
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	while (true)
 | 
						while (true)
 | 
				
			||||||
@ -184,7 +183,7 @@ bool UnusedPruner::used(YulString _name) const
 | 
				
			|||||||
	return m_references.count(_name) && m_references.at(_name) > 0;
 | 
						return m_references.count(_name) && m_references.at(_name) > 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void UnusedPruner::subtractReferences(map<YulString, size_t> const& _subtrahend)
 | 
					void UnusedPruner::subtractReferences(std::map<YulString, size_t> const& _subtrahend)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (auto const& ref: _subtrahend)
 | 
						for (auto const& ref: _subtrahend)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <range/v3/action/remove_if.hpp>
 | 
					#include <range/v3/action/remove_if.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -50,7 +49,7 @@ void UnusedStoreBase::operator()(Switch const& _switch)
 | 
				
			|||||||
	ActiveStores const preState{m_activeStores};
 | 
						ActiveStores const preState{m_activeStores};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool hasDefault = false;
 | 
						bool hasDefault = false;
 | 
				
			||||||
	vector<ActiveStores> branches;
 | 
						std::vector<ActiveStores> branches;
 | 
				
			||||||
	for (auto const& c: _switch.cases)
 | 
						for (auto const& c: _switch.cases)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (!c.value)
 | 
							if (!c.value)
 | 
				
			||||||
@ -146,15 +145,15 @@ void UnusedStoreBase::operator()(Continue const&)
 | 
				
			|||||||
void UnusedStoreBase::merge(ActiveStores& _target, ActiveStores&& _other)
 | 
					void UnusedStoreBase::merge(ActiveStores& _target, ActiveStores&& _other)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	util::joinMap(_target, std::move(_other), [](
 | 
						util::joinMap(_target, std::move(_other), [](
 | 
				
			||||||
		set<Statement const*>& _storesHere,
 | 
							std::set<Statement const*>& _storesHere,
 | 
				
			||||||
		set<Statement const*>&& _storesThere
 | 
							std::set<Statement const*>&& _storesThere
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		_storesHere += _storesThere;
 | 
							_storesHere += _storesThere;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void UnusedStoreBase::merge(ActiveStores& _target, vector<ActiveStores>&& _source)
 | 
					void UnusedStoreBase::merge(ActiveStores& _target, std::vector<ActiveStores>&& _source)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (ActiveStores& ts: _source)
 | 
						for (ActiveStores& ts: _source)
 | 
				
			||||||
		merge(_target, std::move(ts));
 | 
							merge(_target, std::move(ts));
 | 
				
			||||||
 | 
				
			|||||||
@ -40,26 +40,25 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <range/v3/algorithm/all_of.hpp>
 | 
					#include <range/v3/algorithm/all_of.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Variable names for special constants that can never appear in actual Yul code.
 | 
					/// Variable names for special constants that can never appear in actual Yul code.
 | 
				
			||||||
static string const zero{"@ 0"};
 | 
					static std::string const zero{"@ 0"};
 | 
				
			||||||
static string const one{"@ 1"};
 | 
					static std::string const one{"@ 1"};
 | 
				
			||||||
static string const thirtyTwo{"@ 32"};
 | 
					static std::string const thirtyTwo{"@ 32"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast)
 | 
					void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	map<YulString, SideEffects> functionSideEffects = SideEffectsPropagator::sideEffects(
 | 
						std::map<YulString, SideEffects> functionSideEffects = SideEffectsPropagator::sideEffects(
 | 
				
			||||||
		_context.dialect,
 | 
							_context.dialect,
 | 
				
			||||||
		CallGraphGenerator::callGraph(_ast)
 | 
							CallGraphGenerator::callGraph(_ast)
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SSAValueTracker ssaValues;
 | 
						SSAValueTracker ssaValues;
 | 
				
			||||||
	ssaValues(_ast);
 | 
						ssaValues(_ast);
 | 
				
			||||||
	map<YulString, AssignedValue> values;
 | 
						std::map<YulString, AssignedValue> values;
 | 
				
			||||||
	for (auto const& [name, expression]: ssaValues.values())
 | 
						for (auto const& [name, expression]: ssaValues.values())
 | 
				
			||||||
		values[name] = AssignedValue{expression, {}};
 | 
							values[name] = AssignedValue{expression, {}};
 | 
				
			||||||
	Expression const zeroLiteral{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
 | 
						Expression const zeroLiteral{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
 | 
				
			||||||
@ -87,16 +86,16 @@ void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast)
 | 
				
			|||||||
	rse.markActiveAsUsed(Location::Storage);
 | 
						rse.markActiveAsUsed(Location::Storage);
 | 
				
			||||||
	rse.m_storesToRemove += rse.m_allStores - rse.m_usedStores;
 | 
						rse.m_storesToRemove += rse.m_allStores - rse.m_usedStores;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set<Statement const*> toRemove{rse.m_storesToRemove.begin(), rse.m_storesToRemove.end()};
 | 
						std::set<Statement const*> toRemove{rse.m_storesToRemove.begin(), rse.m_storesToRemove.end()};
 | 
				
			||||||
	StatementRemover remover{toRemove};
 | 
						StatementRemover remover{toRemove};
 | 
				
			||||||
	remover(_ast);
 | 
						remover(_ast);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
UnusedStoreEliminator::UnusedStoreEliminator(
 | 
					UnusedStoreEliminator::UnusedStoreEliminator(
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	map<YulString, SideEffects> const& _functionSideEffects,
 | 
						std::map<YulString, SideEffects> const& _functionSideEffects,
 | 
				
			||||||
	map<YulString, ControlFlowSideEffects> _controlFlowSideEffects,
 | 
						std::map<YulString, ControlFlowSideEffects> _controlFlowSideEffects,
 | 
				
			||||||
	map<YulString, AssignedValue> const& _ssaValues,
 | 
						std::map<YulString, AssignedValue> const& _ssaValues,
 | 
				
			||||||
	bool _ignoreMemory
 | 
						bool _ignoreMemory
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	UnusedStoreBase(_dialect),
 | 
						UnusedStoreBase(_dialect),
 | 
				
			||||||
@ -148,18 +147,18 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	UnusedStoreBase::visit(_statement);
 | 
						UnusedStoreBase::visit(_statement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto const* exprStatement = get_if<ExpressionStatement>(&_statement);
 | 
						auto const* exprStatement = std::get_if<ExpressionStatement>(&_statement);
 | 
				
			||||||
	if (!exprStatement)
 | 
						if (!exprStatement)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FunctionCall const* funCall = get_if<FunctionCall>(&exprStatement->expression);
 | 
						FunctionCall const* funCall = std::get_if<FunctionCall>(&exprStatement->expression);
 | 
				
			||||||
	yulAssert(funCall);
 | 
						yulAssert(funCall);
 | 
				
			||||||
	optional<Instruction> instruction = toEVMInstruction(m_dialect, funCall->functionName.name);
 | 
						std::optional<Instruction> instruction = toEVMInstruction(m_dialect, funCall->functionName.name);
 | 
				
			||||||
	if (!instruction)
 | 
						if (!instruction)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ranges::all_of(funCall->arguments, [](Expression const& _expr) -> bool {
 | 
						if (!ranges::all_of(funCall->arguments, [](Expression const& _expr) -> bool {
 | 
				
			||||||
		return get_if<Identifier>(&_expr) || get_if<Literal>(&_expr);
 | 
							return std::get_if<Identifier>(&_expr) || std::get_if<Literal>(&_expr);
 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -195,7 +194,7 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
 | 
				
			|||||||
			auto length = identifierNameIfSSA(funCall->arguments.at(2));
 | 
								auto length = identifierNameIfSSA(funCall->arguments.at(2));
 | 
				
			||||||
			if (length && startOffset)
 | 
								if (length && startOffset)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				FunctionCall const* lengthCall = get_if<FunctionCall>(m_ssaValues.at(*length).value);
 | 
									FunctionCall const* lengthCall = std::get_if<FunctionCall>(m_ssaValues.at(*length).value);
 | 
				
			||||||
				if (
 | 
									if (
 | 
				
			||||||
					m_knowledgeBase.knownToBeZero(*startOffset) &&
 | 
										m_knowledgeBase.knownToBeZero(*startOffset) &&
 | 
				
			||||||
					lengthCall &&
 | 
										lengthCall &&
 | 
				
			||||||
@ -207,7 +206,7 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
 | 
				
			|||||||
				return;
 | 
									return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		m_allStores.insert(&_statement);
 | 
							m_allStores.insert(&_statement);
 | 
				
			||||||
		vector<Operation> operations = operationsFromFunctionCall(*funCall);
 | 
							std::vector<Operation> operations = operationsFromFunctionCall(*funCall);
 | 
				
			||||||
		yulAssert(operations.size() == 1, "");
 | 
							yulAssert(operations.size() == 1, "");
 | 
				
			||||||
		if (operations.front().location == Location::Storage)
 | 
							if (operations.front().location == Location::Storage)
 | 
				
			||||||
			activeStorageStores().insert(&_statement);
 | 
								activeStorageStores().insert(&_statement);
 | 
				
			||||||
@ -217,7 +216,7 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFunctionCall(
 | 
					std::vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFunctionCall(
 | 
				
			||||||
	FunctionCall const& _functionCall
 | 
						FunctionCall const& _functionCall
 | 
				
			||||||
) const
 | 
					) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -230,10 +229,10 @@ vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFu
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		sideEffects = m_functionSideEffects.at(functionName);
 | 
							sideEffects = m_functionSideEffects.at(functionName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	optional<Instruction> instruction = toEVMInstruction(m_dialect, functionName);
 | 
						std::optional<Instruction> instruction = toEVMInstruction(m_dialect, functionName);
 | 
				
			||||||
	if (!instruction)
 | 
						if (!instruction)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		vector<Operation> result;
 | 
							std::vector<Operation> result;
 | 
				
			||||||
		// Unknown read is worse than unknown write.
 | 
							// Unknown read is worse than unknown write.
 | 
				
			||||||
		if (sideEffects.memory != SideEffects::Effect::None)
 | 
							if (sideEffects.memory != SideEffects::Effect::None)
 | 
				
			||||||
			result.emplace_back(Operation{Location::Memory, Effect::Read, {}, {}});
 | 
								result.emplace_back(Operation{Location::Memory, Effect::Read, {}, {}});
 | 
				
			||||||
@ -269,7 +268,7 @@ vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFu
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void UnusedStoreEliminator::applyOperation(UnusedStoreEliminator::Operation const& _operation)
 | 
					void UnusedStoreEliminator::applyOperation(UnusedStoreEliminator::Operation const& _operation)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set<Statement const*>& active =
 | 
						std::set<Statement const*>& active =
 | 
				
			||||||
		_operation.location == Location::Storage ?
 | 
							_operation.location == Location::Storage ?
 | 
				
			||||||
		activeStorageStores() :
 | 
							activeStorageStores() :
 | 
				
			||||||
		activeMemoryStores();
 | 
							activeMemoryStores();
 | 
				
			||||||
@ -324,9 +323,9 @@ bool UnusedStoreEliminator::knownUnrelated(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (_op1.start && _op1.length && _op2.start)
 | 
							if (_op1.start && _op1.length && _op2.start)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			optional<u256> length1 = m_knowledgeBase.valueIfKnownConstant(*_op1.length);
 | 
								std::optional<u256> length1 = m_knowledgeBase.valueIfKnownConstant(*_op1.length);
 | 
				
			||||||
			optional<u256> start1 = m_knowledgeBase.valueIfKnownConstant(*_op1.start);
 | 
								std::optional<u256> start1 = m_knowledgeBase.valueIfKnownConstant(*_op1.start);
 | 
				
			||||||
			optional<u256> start2 = m_knowledgeBase.valueIfKnownConstant(*_op2.start);
 | 
								std::optional<u256> start2 = m_knowledgeBase.valueIfKnownConstant(*_op2.start);
 | 
				
			||||||
			if (
 | 
								if (
 | 
				
			||||||
				(length1 && start1 && start2) &&
 | 
									(length1 && start1 && start2) &&
 | 
				
			||||||
				*start1 + *length1 >= *start1 && // no overflow
 | 
									*start1 + *length1 >= *start1 && // no overflow
 | 
				
			||||||
@ -336,9 +335,9 @@ bool UnusedStoreEliminator::knownUnrelated(
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		if (_op2.start && _op2.length && _op1.start)
 | 
							if (_op2.start && _op2.length && _op1.start)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			optional<u256> length2 = m_knowledgeBase.valueIfKnownConstant(*_op2.length);
 | 
								std::optional<u256> length2 = m_knowledgeBase.valueIfKnownConstant(*_op2.length);
 | 
				
			||||||
			optional<u256> start2 = m_knowledgeBase.valueIfKnownConstant(*_op2.start);
 | 
								std::optional<u256> start2 = m_knowledgeBase.valueIfKnownConstant(*_op2.start);
 | 
				
			||||||
			optional<u256> start1 = m_knowledgeBase.valueIfKnownConstant(*_op1.start);
 | 
								std::optional<u256> start1 = m_knowledgeBase.valueIfKnownConstant(*_op1.start);
 | 
				
			||||||
			if (
 | 
								if (
 | 
				
			||||||
				(length2 && start2 && start1) &&
 | 
									(length2 && start2 && start1) &&
 | 
				
			||||||
				*start2 + *length2 >= *start2 && // no overflow
 | 
									*start2 + *length2 >= *start2 && // no overflow
 | 
				
			||||||
@ -349,8 +348,8 @@ bool UnusedStoreEliminator::knownUnrelated(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (_op1.start && _op1.length && _op2.start && _op2.length)
 | 
							if (_op1.start && _op1.length && _op2.start && _op2.length)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			optional<u256> length1 = m_knowledgeBase.valueIfKnownConstant(*_op1.length);
 | 
								std::optional<u256> length1 = m_knowledgeBase.valueIfKnownConstant(*_op1.length);
 | 
				
			||||||
			optional<u256> length2 = m_knowledgeBase.valueIfKnownConstant(*_op2.length);
 | 
								std::optional<u256> length2 = m_knowledgeBase.valueIfKnownConstant(*_op2.length);
 | 
				
			||||||
			if (
 | 
								if (
 | 
				
			||||||
				(length1 && *length1 <= 32) &&
 | 
									(length1 && *length1 <= 32) &&
 | 
				
			||||||
				(length2 && *length2 <= 32) &&
 | 
									(length2 && *length2 <= 32) &&
 | 
				
			||||||
@ -384,13 +383,13 @@ bool UnusedStoreEliminator::knownCovered(
 | 
				
			|||||||
		// i.start <= e.start && e.start + e.length <= i.start + i.length
 | 
							// i.start <= e.start && e.start + e.length <= i.start + i.length
 | 
				
			||||||
		if (!_covered.start || !_covering.start || !_covered.length || !_covering.length)
 | 
							if (!_covered.start || !_covering.start || !_covered.length || !_covering.length)
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		optional<u256> coveredLength = m_knowledgeBase.valueIfKnownConstant(*_covered.length);
 | 
							std::optional<u256> coveredLength = m_knowledgeBase.valueIfKnownConstant(*_covered.length);
 | 
				
			||||||
		optional<u256> coveringLength = m_knowledgeBase.valueIfKnownConstant(*_covering.length);
 | 
							std::optional<u256> coveringLength = m_knowledgeBase.valueIfKnownConstant(*_covering.length);
 | 
				
			||||||
		if (*_covered.start == *_covering.start)
 | 
							if (*_covered.start == *_covering.start)
 | 
				
			||||||
			if (coveredLength && coveringLength && *coveredLength <= *coveringLength)
 | 
								if (coveredLength && coveringLength && *coveredLength <= *coveringLength)
 | 
				
			||||||
				return true;
 | 
									return true;
 | 
				
			||||||
		optional<u256> coveredStart = m_knowledgeBase.valueIfKnownConstant(*_covered.start);
 | 
							std::optional<u256> coveredStart = m_knowledgeBase.valueIfKnownConstant(*_covered.start);
 | 
				
			||||||
		optional<u256> coveringStart = m_knowledgeBase.valueIfKnownConstant(*_covering.start);
 | 
							std::optional<u256> coveringStart = m_knowledgeBase.valueIfKnownConstant(*_covering.start);
 | 
				
			||||||
		if (coveredStart && coveringStart && coveredLength && coveringLength)
 | 
							if (coveredStart && coveringStart && coveredLength && coveringLength)
 | 
				
			||||||
			if (
 | 
								if (
 | 
				
			||||||
				*coveringStart <= *coveredStart &&
 | 
									*coveringStart <= *coveredStart &&
 | 
				
			||||||
@ -408,32 +407,32 @@ bool UnusedStoreEliminator::knownCovered(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void UnusedStoreEliminator::markActiveAsUsed(
 | 
					void UnusedStoreEliminator::markActiveAsUsed(
 | 
				
			||||||
	optional<UnusedStoreEliminator::Location> _onlyLocation
 | 
						std::optional<UnusedStoreEliminator::Location> _onlyLocation
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (_onlyLocation == nullopt || _onlyLocation == Location::Memory)
 | 
						if (_onlyLocation == std::nullopt || _onlyLocation == Location::Memory)
 | 
				
			||||||
		for (Statement const* statement: activeMemoryStores())
 | 
							for (Statement const* statement: activeMemoryStores())
 | 
				
			||||||
			m_usedStores.insert(statement);
 | 
								m_usedStores.insert(statement);
 | 
				
			||||||
	if (_onlyLocation == nullopt || _onlyLocation == Location::Storage)
 | 
						if (_onlyLocation == std::nullopt || _onlyLocation == Location::Storage)
 | 
				
			||||||
		for (Statement const* statement: activeStorageStores())
 | 
							for (Statement const* statement: activeStorageStores())
 | 
				
			||||||
			m_usedStores.insert(statement);
 | 
								m_usedStores.insert(statement);
 | 
				
			||||||
	clearActive(_onlyLocation);
 | 
						clearActive(_onlyLocation);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void UnusedStoreEliminator::clearActive(
 | 
					void UnusedStoreEliminator::clearActive(
 | 
				
			||||||
	optional<UnusedStoreEliminator::Location> _onlyLocation
 | 
						std::optional<UnusedStoreEliminator::Location> _onlyLocation
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (_onlyLocation == nullopt || _onlyLocation == Location::Memory)
 | 
						if (_onlyLocation == std::nullopt || _onlyLocation == Location::Memory)
 | 
				
			||||||
		activeMemoryStores() = {};
 | 
							activeMemoryStores() = {};
 | 
				
			||||||
	if (_onlyLocation == nullopt || _onlyLocation == Location::Storage)
 | 
						if (_onlyLocation == std::nullopt || _onlyLocation == Location::Storage)
 | 
				
			||||||
		activeStorageStores() = {};
 | 
							activeStorageStores() = {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<YulString> UnusedStoreEliminator::identifierNameIfSSA(Expression const& _expression) const
 | 
					std::optional<YulString> UnusedStoreEliminator::identifierNameIfSSA(Expression const& _expression) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (Identifier const* identifier = get_if<Identifier>(&_expression))
 | 
						if (Identifier const* identifier = std::get_if<Identifier>(&_expression))
 | 
				
			||||||
		if (m_ssaValues.count(identifier->name))
 | 
							if (m_ssaValues.count(identifier->name))
 | 
				
			||||||
			return {identifier->name};
 | 
								return {identifier->name};
 | 
				
			||||||
	return nullopt;
 | 
						return std::nullopt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
#include <libsolutil/Visitor.h>
 | 
					#include <libsolutil/Visitor.h>
 | 
				
			||||||
#include <libyul/Dialect.h>
 | 
					#include <libyul/Dialect.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity;
 | 
					using namespace solidity;
 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -31,7 +30,7 @@ void VarDeclInitializer::operator()(Block& _block)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	ASTModifier::operator()(_block);
 | 
						ASTModifier::operator()(_block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	using OptionalStatements = std::optional<vector<Statement>>;
 | 
						using OptionalStatements = std::optional<std::vector<Statement>>;
 | 
				
			||||||
	util::GenericVisitor visitor{
 | 
						util::GenericVisitor visitor{
 | 
				
			||||||
		util::VisitorFallback<OptionalStatements>{},
 | 
							util::VisitorFallback<OptionalStatements>{},
 | 
				
			||||||
		[this](VariableDeclaration& _varDecl) -> OptionalStatements
 | 
							[this](VariableDeclaration& _varDecl) -> OptionalStatements
 | 
				
			||||||
@ -41,15 +40,15 @@ void VarDeclInitializer::operator()(Block& _block)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (_varDecl.variables.size() == 1)
 | 
								if (_varDecl.variables.size() == 1)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				_varDecl.value = make_unique<Expression>(m_dialect.zeroLiteralForType(_varDecl.variables.front().type));
 | 
									_varDecl.value = std::make_unique<Expression>(m_dialect.zeroLiteralForType(_varDecl.variables.front().type));
 | 
				
			||||||
				return {};
 | 
									return {};
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				OptionalStatements ret{vector<Statement>{}};
 | 
									OptionalStatements ret{std::vector<Statement>{}};
 | 
				
			||||||
				for (auto& var: _varDecl.variables)
 | 
									for (auto& var: _varDecl.variables)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					unique_ptr<Expression> expr = make_unique<Expression >(m_dialect.zeroLiteralForType(var.type));
 | 
										std::unique_ptr<Expression> expr = std::make_unique<Expression >(m_dialect.zeroLiteralForType(var.type));
 | 
				
			||||||
					ret->emplace_back(VariableDeclaration{std::move(_varDecl.debugData), {std::move(var)}, std::move(expr)});
 | 
										ret->emplace_back(VariableDeclaration{std::move(_varDecl.debugData), {std::move(var)}, std::move(expr)});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return ret;
 | 
									return ret;
 | 
				
			||||||
 | 
				
			|||||||
@ -29,20 +29,19 @@
 | 
				
			|||||||
#include <regex>
 | 
					#include <regex>
 | 
				
			||||||
#include <limits>
 | 
					#include <limits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					 | 
				
			||||||
using namespace solidity::yul;
 | 
					using namespace solidity::yul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VarNameCleaner::VarNameCleaner(
 | 
					VarNameCleaner::VarNameCleaner(
 | 
				
			||||||
	Block const& _ast,
 | 
						Block const& _ast,
 | 
				
			||||||
	Dialect const& _dialect,
 | 
						Dialect const& _dialect,
 | 
				
			||||||
	set<YulString> _namesToKeep
 | 
						std::set<YulString> _namesToKeep
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
	m_dialect{_dialect},
 | 
						m_dialect{_dialect},
 | 
				
			||||||
	m_namesToKeep{std::move(_namesToKeep)},
 | 
						m_namesToKeep{std::move(_namesToKeep)},
 | 
				
			||||||
	m_translatedNames{}
 | 
						m_translatedNames{}
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (auto const& statement: _ast.statements)
 | 
						for (auto const& statement: _ast.statements)
 | 
				
			||||||
		if (holds_alternative<FunctionDefinition>(statement))
 | 
							if (std::holds_alternative<FunctionDefinition>(statement))
 | 
				
			||||||
			m_namesToKeep.insert(std::get<FunctionDefinition>(statement).name);
 | 
								m_namesToKeep.insert(std::get<FunctionDefinition>(statement).name);
 | 
				
			||||||
	m_usedNames = m_namesToKeep;
 | 
						m_usedNames = m_namesToKeep;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -52,9 +51,9 @@ void VarNameCleaner::operator()(FunctionDefinition& _funDef)
 | 
				
			|||||||
	yulAssert(!m_insideFunction, "");
 | 
						yulAssert(!m_insideFunction, "");
 | 
				
			||||||
	m_insideFunction = true;
 | 
						m_insideFunction = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set<YulString> globalUsedNames = std::move(m_usedNames);
 | 
						std::set<YulString> globalUsedNames = std::move(m_usedNames);
 | 
				
			||||||
	m_usedNames = m_namesToKeep;
 | 
						m_usedNames = m_namesToKeep;
 | 
				
			||||||
	map<YulString, YulString> globalTranslatedNames;
 | 
						std::map<YulString, YulString> globalTranslatedNames;
 | 
				
			||||||
	swap(globalTranslatedNames, m_translatedNames);
 | 
						swap(globalTranslatedNames, m_translatedNames);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	renameVariables(_funDef.parameters);
 | 
						renameVariables(_funDef.parameters);
 | 
				
			||||||
@ -73,7 +72,7 @@ void VarNameCleaner::operator()(VariableDeclaration& _varDecl)
 | 
				
			|||||||
	ASTModifier::operator()(_varDecl);
 | 
						ASTModifier::operator()(_varDecl);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void VarNameCleaner::renameVariables(vector<TypedName>& _variables)
 | 
					void VarNameCleaner::renameVariables(std::vector<TypedName>& _variables)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (TypedName& typedName: _variables)
 | 
						for (TypedName& typedName: _variables)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -101,9 +100,9 @@ YulString VarNameCleaner::findCleanName(YulString const& _name) const
 | 
				
			|||||||
		return newName;
 | 
							return newName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// create new name with suffix (by finding a free identifier)
 | 
						// create new name with suffix (by finding a free identifier)
 | 
				
			||||||
	for (size_t i = 1; i < numeric_limits<decltype(i)>::max(); ++i)
 | 
						for (size_t i = 1; i < std::numeric_limits<decltype(i)>::max(); ++i)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		YulString newNameSuffixed = YulString{newName.str() + "_" + to_string(i)};
 | 
							YulString newNameSuffixed = YulString{newName.str() + "_" + std::to_string(i)};
 | 
				
			||||||
		if (!isUsedName(newNameSuffixed))
 | 
							if (!isUsedName(newNameSuffixed))
 | 
				
			||||||
			return newNameSuffixed;
 | 
								return newNameSuffixed;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -117,9 +116,9 @@ bool VarNameCleaner::isUsedName(YulString const& _name) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
YulString VarNameCleaner::stripSuffix(YulString const& _name) const
 | 
					YulString VarNameCleaner::stripSuffix(YulString const& _name) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static regex const suffixRegex("(_+[0-9]+)+$");
 | 
						static std::regex const suffixRegex("(_+[0-9]+)+$");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smatch suffixMatch;
 | 
						std::smatch suffixMatch;
 | 
				
			||||||
	if (regex_search(_name.str(), suffixMatch, suffixRegex))
 | 
						if (regex_search(_name.str(), suffixMatch, suffixRegex))
 | 
				
			||||||
		return {YulString{suffixMatch.prefix().str()}};
 | 
							return {YulString{suffixMatch.prefix().str()}};
 | 
				
			||||||
	return _name;
 | 
						return _name;
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,7 @@ NAMESPACE_STD_FREE_FILES=(
 | 
				
			|||||||
    libsolidity/parsing/*
 | 
					    libsolidity/parsing/*
 | 
				
			||||||
    libsolutil/*
 | 
					    libsolutil/*
 | 
				
			||||||
    libyul/backends/evm/*
 | 
					    libyul/backends/evm/*
 | 
				
			||||||
 | 
					    libyul/optimiser/*
 | 
				
			||||||
    solc/*
 | 
					    solc/*
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user