mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge branch 'develop' into Akkii4-patch-1
This commit is contained in:
		
						commit
						bee0b9c9a8
					
				| @ -4,9 +4,9 @@ FetchContent_Declare( | ||||
| 	fmtlib | ||||
| 	PREFIX "${PROJECT_BINARY_DIR}/deps" | ||||
| 	DOWNLOAD_DIR "${PROJECT_SOURCE_DIR}/deps/downloads" | ||||
| 	DOWNLOAD_NAME fmt-8.0.1.tar.gz | ||||
| 	URL https://github.com/fmtlib/fmt/archive/8.0.1.tar.gz | ||||
| 	URL_HASH SHA256=b06ca3130158c625848f3fb7418f235155a4d389b2abc3a6245fb01cb0eb1e01 | ||||
| 	DOWNLOAD_NAME fmt-9.1.0.tar.gz | ||||
| 	URL https://github.com/fmtlib/fmt/archive/9.1.0.tar.gz | ||||
| 	URL_HASH SHA256=5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2 | ||||
| ) | ||||
| 
 | ||||
| if (CMAKE_VERSION VERSION_LESS "3.14.0") | ||||
|  | ||||
| @ -118,7 +118,7 @@ void SemanticTokensBuilder::encode( | ||||
| 	auto const [line, startChar] = m_charStream->translatePositionToLineColumn(_sourceLocation.start); | ||||
| 	auto const length = _sourceLocation.end - _sourceLocation.start; | ||||
| 
 | ||||
| 	lspDebug(fmt::format("encode [{}:{}..{}] {}", line, startChar, length, _tokenType)); | ||||
| 	lspDebug(fmt::format("encode [{}:{}..{}] {}", line, startChar, length, static_cast<int>(_tokenType))); | ||||
| 
 | ||||
| 	m_encodedTokens.append(line - m_lastLine); | ||||
| 	if (line == m_lastLine) | ||||
|  | ||||
| @ -28,7 +28,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/StackTooDeepString.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
|  | ||||
| @ -30,7 +30,6 @@ | ||||
| 
 | ||||
| #include <variant> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -48,9 +47,9 @@ struct MiniEVMInterpreter | ||||
| 		return std::visit(*this, _expr); | ||||
| 	} | ||||
| 
 | ||||
| 	u256 eval(evmasm::Instruction _instr, vector<Expression> const& _arguments) | ||||
| 	u256 eval(evmasm::Instruction _instr, std::vector<Expression> const& _arguments) | ||||
| 	{ | ||||
| 		vector<u256> args; | ||||
| 		std::vector<u256> args; | ||||
| 		for (auto const& arg: _arguments) | ||||
| 			args.emplace_back(eval(arg)); | ||||
| 		switch (_instr) | ||||
| @ -92,7 +91,7 @@ struct MiniEVMInterpreter | ||||
| 
 | ||||
| void ConstantOptimiser::visit(Expression& _e) | ||||
| { | ||||
| 	if (holds_alternative<Literal>(_e)) | ||||
| 	if (std::holds_alternative<Literal>(_e)) | ||||
| 	{ | ||||
| 		Literal const& literal = std::get<Literal>(_e); | ||||
| 		if (literal.kind != LiteralKind::Number) | ||||
| @ -115,7 +114,7 @@ Expression const* RepresentationFinder::tryFindRepresentation(u256 const& _value | ||||
| 		return nullptr; | ||||
| 
 | ||||
| 	Representation const& repr = findRepresentation(_value); | ||||
| 	if (holds_alternative<Literal>(*repr.expression)) | ||||
| 	if (std::holds_alternative<Literal>(*repr.expression)) | ||||
| 		return nullptr; | ||||
| 	else | ||||
| 		return repr.expression.get(); | ||||
| @ -180,7 +179,7 @@ Representation const& RepresentationFinder::findRepresentation(u256 const& _valu | ||||
| Representation RepresentationFinder::represent(u256 const& _value) const | ||||
| { | ||||
| 	Representation repr; | ||||
| 	repr.expression = make_unique<Expression>(Literal{m_debugData, LiteralKind::Number, YulString{formatNumber(_value)}, {}}); | ||||
| 	repr.expression = std::make_unique<Expression>(Literal{m_debugData, LiteralKind::Number, YulString{formatNumber(_value)}, {}}); | ||||
| 	repr.cost = m_meter.costs(*repr.expression); | ||||
| 	return repr; | ||||
| } | ||||
| @ -191,7 +190,7 @@ Representation RepresentationFinder::represent( | ||||
| ) const | ||||
| { | ||||
| 	Representation repr; | ||||
| 	repr.expression = make_unique<Expression>(FunctionCall{ | ||||
| 	repr.expression = std::make_unique<Expression>(FunctionCall{ | ||||
| 		m_debugData, | ||||
| 		Identifier{m_debugData, _instruction}, | ||||
| 		{ASTCopier{}.translate(*_argument.expression)} | ||||
| @ -207,7 +206,7 @@ Representation RepresentationFinder::represent( | ||||
| ) const | ||||
| { | ||||
| 	Representation repr; | ||||
| 	repr.expression = make_unique<Expression>(FunctionCall{ | ||||
| 	repr.expression = std::make_unique<Expression>(FunctionCall{ | ||||
| 		m_debugData, | ||||
| 		Identifier{m_debugData, _instruction}, | ||||
| 		{ASTCopier{}.translate(*_arg1.expression), ASTCopier{}.translate(*_arg2.expression)} | ||||
|  | ||||
| @ -45,7 +45,6 @@ | ||||
| 
 | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace std; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| @ -82,15 +81,15 @@ void cleanUnreachable(CFG& _cfg) | ||||
| /// Sets the ``recursive`` member to ``true`` for all recursive function calls.
 | ||||
| void markRecursiveCalls(CFG& _cfg) | ||||
| { | ||||
| 	map<CFG::BasicBlock*, vector<CFG::FunctionCall*>> callsPerBlock; | ||||
| 	std::map<CFG::BasicBlock*, std::vector<CFG::FunctionCall*>> callsPerBlock; | ||||
| 	auto const& findCalls = [&](CFG::BasicBlock* _block) | ||||
| 	{ | ||||
| 		if (auto* calls = util::valueOrNullptr(callsPerBlock, _block)) | ||||
| 			return *calls; | ||||
| 		vector<CFG::FunctionCall*>& calls = callsPerBlock[_block]; | ||||
| 		std::vector<CFG::FunctionCall*>& calls = callsPerBlock[_block]; | ||||
| 		util::BreadthFirstSearch<CFG::BasicBlock*>{{_block}}.run([&](CFG::BasicBlock* _block, auto _addChild) { | ||||
| 			for (auto& operation: _block->operations) | ||||
| 				if (auto* functionCall = get_if<CFG::FunctionCall>(&operation.operation)) | ||||
| 				if (auto* functionCall = std::get_if<CFG::FunctionCall>(&operation.operation)) | ||||
| 					calls.emplace_back(functionCall); | ||||
| 			std::visit(util::GenericVisitor{ | ||||
| 				[&](CFG::BasicBlock::MainExit const&) {}, | ||||
| @ -131,7 +130,7 @@ void markRecursiveCalls(CFG& _cfg) | ||||
| /// Entering such a block means that control flow will never return to a previously visited block.
 | ||||
| void markStartsOfSubGraphs(CFG& _cfg) | ||||
| { | ||||
| 	vector<CFG::BasicBlock*> entries; | ||||
| 	std::vector<CFG::BasicBlock*> entries; | ||||
| 	entries.emplace_back(_cfg.entry); | ||||
| 	for (auto&& functionInfo: _cfg.functionInfo | ranges::views::values) | ||||
| 		entries.emplace_back(functionInfo.entry); | ||||
| @ -141,17 +140,17 @@ void markStartsOfSubGraphs(CFG& _cfg) | ||||
| 		 * Detect bridges following Algorithm 1 in https://arxiv.org/pdf/2108.07346.pdf
 | ||||
| 		 * and mark the bridge targets as starts of sub-graphs. | ||||
| 		 */ | ||||
| 		set<CFG::BasicBlock*> visited; | ||||
| 		map<CFG::BasicBlock*, size_t> disc; | ||||
| 		map<CFG::BasicBlock*, size_t> low; | ||||
| 		map<CFG::BasicBlock*, CFG::BasicBlock*> parent; | ||||
| 		std::set<CFG::BasicBlock*> visited; | ||||
| 		std::map<CFG::BasicBlock*, size_t> disc; | ||||
| 		std::map<CFG::BasicBlock*, size_t> low; | ||||
| 		std::map<CFG::BasicBlock*, CFG::BasicBlock*> parent; | ||||
| 		size_t time = 0; | ||||
| 		auto dfs = [&](CFG::BasicBlock* _u, auto _recurse) -> void { | ||||
| 			visited.insert(_u); | ||||
| 			disc[_u] = low[_u] = time; | ||||
| 			time++; | ||||
| 
 | ||||
| 			vector<CFG::BasicBlock*> children = _u->entries; | ||||
| 			std::vector<CFG::BasicBlock*> children = _u->entries; | ||||
| 			visit(util::GenericVisitor{ | ||||
| 				[&](CFG::BasicBlock::Jump const& _jump) { | ||||
| 					children.emplace_back(_jump.target); | ||||
| @ -171,7 +170,7 @@ void markStartsOfSubGraphs(CFG& _cfg) | ||||
| 				{ | ||||
| 					parent[v] = _u; | ||||
| 					_recurse(v, _recurse); | ||||
| 					low[_u] = min(low[_u], low[v]); | ||||
| 					low[_u] = std::min(low[_u], low[v]); | ||||
| 					if (low[v] > disc[_u]) | ||||
| 					{ | ||||
| 						// _u <-> v is a cut edge in the undirected graph
 | ||||
| @ -186,7 +185,7 @@ void markStartsOfSubGraphs(CFG& _cfg) | ||||
| 					} | ||||
| 				} | ||||
| 				else if (v != parent[_u]) | ||||
| 					low[_u] = min(low[_u], disc[v]); | ||||
| 					low[_u] = std::min(low[_u], disc[v]); | ||||
| 		}; | ||||
| 		dfs(entry, dfs); | ||||
| 	} | ||||
| @ -234,7 +233,7 @@ std::unique_ptr<CFG> ControlFlowGraphBuilder::build( | ||||
| ControlFlowGraphBuilder::ControlFlowGraphBuilder( | ||||
| 	CFG& _graph, | ||||
| 	AsmAnalysisInfo const& _analysisInfo, | ||||
| 	map<FunctionDefinition const*, ControlFlowSideEffects> const& _functionSideEffects, | ||||
| 	std::map<FunctionDefinition const*, ControlFlowSideEffects> const& _functionSideEffects, | ||||
| 	Dialect const& _dialect | ||||
| ): | ||||
| 	m_graph(_graph), | ||||
| @ -271,7 +270,7 @@ void ControlFlowGraphBuilder::operator()(VariableDeclaration const& _varDecl) | ||||
| 	yulAssert(m_currentBlock, ""); | ||||
| 	auto declaredVariables = _varDecl.variables | ranges::views::transform([&](TypedName const& _var) { | ||||
| 		return VariableSlot{lookupVariable(_var.name), _var.debugData}; | ||||
| 	}) | ranges::to<vector<VariableSlot>>; | ||||
| 	}) | ranges::to<std::vector<VariableSlot>>; | ||||
| 	Stack input; | ||||
| 	if (_varDecl.value) | ||||
| 		input = visitAssignmentRightHandSide(*_varDecl.value, declaredVariables.size()); | ||||
| @ -287,7 +286,7 @@ void ControlFlowGraphBuilder::operator()(Assignment const& _assignment) | ||||
| { | ||||
| 	auto assignedVariables = _assignment.variableNames | ranges::views::transform([&](Identifier const& _var) { | ||||
| 		return VariableSlot{lookupVariable(_var.name), _var.debugData}; | ||||
| 	}) | ranges::to<vector<VariableSlot>>; | ||||
| 	}) | ranges::to<std::vector<VariableSlot>>; | ||||
| 
 | ||||
| 	Stack input = visitAssignmentRightHandSide(*_assignment.value, assignedVariables.size()); | ||||
| 	yulAssert(m_currentBlock); | ||||
| @ -314,7 +313,7 @@ void ControlFlowGraphBuilder::operator()(Block const& _block) | ||||
| { | ||||
| 	ScopedSaveAndRestore saveScope(m_scope, m_info.scopes.at(&_block).get()); | ||||
| 	for (auto const& statement: _block.statements) | ||||
| 		if (auto const* function = get_if<FunctionDefinition>(&statement)) | ||||
| 		if (auto const* function = std::get_if<FunctionDefinition>(&statement)) | ||||
| 			registerFunction(*function); | ||||
| 	for (auto const& statement: _block.statements) | ||||
| 		std::visit(*this, statement); | ||||
| @ -334,10 +333,10 @@ void ControlFlowGraphBuilder::operator()(If const& _if) | ||||
| void ControlFlowGraphBuilder::operator()(Switch const& _switch) | ||||
| { | ||||
| 	yulAssert(m_currentBlock, ""); | ||||
| 	shared_ptr<DebugData const> preSwitchDebugData = debugDataOf(_switch); | ||||
| 	std::shared_ptr<DebugData const> preSwitchDebugData = debugDataOf(_switch); | ||||
| 
 | ||||
| 	auto ghostVariableId = m_graph.ghostVariables.size(); | ||||
| 	YulString ghostVariableName("GHOST[" + to_string(ghostVariableId) + "]"); | ||||
| 	YulString ghostVariableName("GHOST[" + std::to_string(ghostVariableId) + "]"); | ||||
| 	auto& ghostVar = m_graph.ghostVariables.emplace_back(Scope::Variable{""_yulstring, ghostVariableName}); | ||||
| 
 | ||||
| 	// Artificially generate:
 | ||||
| @ -394,12 +393,12 @@ void ControlFlowGraphBuilder::operator()(Switch const& _switch) | ||||
| 
 | ||||
| void ControlFlowGraphBuilder::operator()(ForLoop const& _loop) | ||||
| { | ||||
| 	shared_ptr<DebugData const> preLoopDebugData = debugDataOf(_loop); | ||||
| 	std::shared_ptr<DebugData const> preLoopDebugData = debugDataOf(_loop); | ||||
| 	ScopedSaveAndRestore scopeRestore(m_scope, m_info.scopes.at(&_loop.pre).get()); | ||||
| 	(*this)(_loop.pre); | ||||
| 
 | ||||
| 	std::optional<bool> constantCondition; | ||||
| 	if (auto const* literalCondition = get_if<yul::Literal>(_loop.condition.get())) | ||||
| 	if (auto const* literalCondition = std::get_if<yul::Literal>(_loop.condition.get())) | ||||
| 		constantCondition = valueOfLiteral(*literalCondition) != 0; | ||||
| 
 | ||||
| 	CFG::BasicBlock& loopCondition = m_graph.makeBlock(debugDataOf(*_loop.condition)); | ||||
| @ -497,13 +496,13 @@ void ControlFlowGraphBuilder::registerFunction(FunctionDefinition const& _functi | ||||
| 				std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_param.name)), | ||||
| 				_param.debugData | ||||
| 			}; | ||||
| 		}) | ranges::to<vector>, | ||||
| 		}) | ranges::to<std::vector>, | ||||
| 		_functionDefinition.returnVariables | ranges::views::transform([&](auto const& _retVar) { | ||||
| 			return VariableSlot{ | ||||
| 				std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_retVar.name)), | ||||
| 				_retVar.debugData | ||||
| 			}; | ||||
| 		}) | ranges::to<vector>, | ||||
| 		}) | ranges::to<std::vector>, | ||||
| 		{}, | ||||
| 		m_functionSideEffects.at(&_functionDefinition).canContinue | ||||
| 	})).second; | ||||
| @ -609,7 +608,7 @@ Scope::Variable const& ControlFlowGraphBuilder::lookupVariable(YulString _name) | ||||
| } | ||||
| 
 | ||||
| void ControlFlowGraphBuilder::makeConditionalJump( | ||||
| 	shared_ptr<DebugData const> _debugData, | ||||
| 	std::shared_ptr<DebugData const> _debugData, | ||||
| 	StackSlot _condition, | ||||
| 	CFG::BasicBlock& _nonZero, | ||||
| 	CFG::BasicBlock& _zero | ||||
| @ -628,7 +627,7 @@ void ControlFlowGraphBuilder::makeConditionalJump( | ||||
| } | ||||
| 
 | ||||
| void ControlFlowGraphBuilder::jump( | ||||
| 	shared_ptr<DebugData const> _debugData, | ||||
| 	std::shared_ptr<DebugData const> _debugData, | ||||
| 	CFG::BasicBlock& _target, | ||||
| 	bool backwards | ||||
| ) | ||||
|  | ||||
| @ -42,7 +42,6 @@ | ||||
| #include <utility> | ||||
| #include <variant> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -56,9 +55,9 @@ CodeTransform::CodeTransform( | ||||
| 	BuiltinContext& _builtinContext, | ||||
| 	ExternalIdentifierAccess::CodeGenerator _identifierAccessCodeGen, | ||||
| 	UseNamedLabels _useNamedLabelsForFunctions, | ||||
| 	shared_ptr<Context> _context, | ||||
| 	vector<TypedName> _delayedReturnVariables, | ||||
| 	optional<AbstractAssembly::LabelID> _functionExitLabel | ||||
| 	std::shared_ptr<Context> _context, | ||||
| 	std::vector<TypedName> _delayedReturnVariables, | ||||
| 	std::optional<AbstractAssembly::LabelID> _functionExitLabel | ||||
| ): | ||||
| 	m_assembly(_assembly), | ||||
| 	m_info(_analysisInfo), | ||||
| @ -74,7 +73,7 @@ CodeTransform::CodeTransform( | ||||
| 	if (!m_context) | ||||
| 	{ | ||||
| 		// initialize
 | ||||
| 		m_context = make_shared<Context>(); | ||||
| 		m_context = std::make_shared<Context>(); | ||||
| 		if (m_allowStackOpt) | ||||
| 			m_context->variableReferences = VariableReferenceCounter::run(m_info, _block); | ||||
| 	} | ||||
| @ -103,7 +102,7 @@ void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop) | ||||
| 		return; | ||||
| 
 | ||||
| 	for (auto const& identifier: m_scope->identifiers) | ||||
| 		if (Scope::Variable const* var = get_if<Scope::Variable>(&identifier.second)) | ||||
| 		if (Scope::Variable const* var = std::get_if<Scope::Variable>(&identifier.second)) | ||||
| 			if (m_variablesScheduledForDeletion.count(var)) | ||||
| 				deleteVariable(*var); | ||||
| 	// Directly in a function body block, we can also delete the function arguments,
 | ||||
| @ -112,7 +111,7 @@ void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop) | ||||
| 	// effect, so we only do it before that.
 | ||||
| 	if (!returnVariablesAndFunctionExitAreSetup() && !m_scope->functionScope && m_scope->superScope && m_scope->superScope->functionScope) | ||||
| 		for (auto const& identifier: m_scope->superScope->identifiers) | ||||
| 			if (Scope::Variable const* var = get_if<Scope::Variable>(&identifier.second)) | ||||
| 			if (Scope::Variable const* var = std::get_if<Scope::Variable>(&identifier.second)) | ||||
| 				if (m_variablesScheduledForDeletion.count(var)) | ||||
| 					deleteVariable(*var); | ||||
| 
 | ||||
| @ -317,7 +316,7 @@ void CodeTransform::operator()(Switch const& _switch) | ||||
| { | ||||
| 	visitExpression(*_switch.expression); | ||||
| 	int expressionHeight = m_assembly.stackHeight(); | ||||
| 	map<Case const*, AbstractAssembly::LabelID> caseBodies; | ||||
| 	std::map<Case const*, AbstractAssembly::LabelID> caseBodies; | ||||
| 	AbstractAssembly::LabelID end = m_assembly.newLabelId(); | ||||
| 	for (Case const& c: _switch.cases) | ||||
| 	{ | ||||
| @ -447,7 +446,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) | ||||
| 
 | ||||
| 		// This vector holds the desired target positions of all stack slots and is
 | ||||
| 		// modified parallel to the actual stack.
 | ||||
| 		vector<int> stackLayout(static_cast<size_t>(m_assembly.stackHeight()), -1); | ||||
| 		std::vector<int> stackLayout(static_cast<size_t>(m_assembly.stackHeight()), -1); | ||||
| 		stackLayout[0] = static_cast<int>(_function.returnVariables.size()); // Move return label to the top
 | ||||
| 		for (auto&& [n, returnVariable]: ranges::views::enumerate(_function.returnVariables)) | ||||
| 			stackLayout.at(m_context->variableStackHeights.at( | ||||
| @ -463,7 +462,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) | ||||
| 				"The function " + | ||||
| 				_function.name.str() + | ||||
| 				" has " + | ||||
| 				to_string(stackLayout.size() - 17) + | ||||
| 				std::to_string(stackLayout.size() - 17) + | ||||
| 				" parameters or return variables too many to fit the stack size." | ||||
| 			); | ||||
| 			stackError(std::move(error), m_assembly.stackHeight() - static_cast<int>(_function.parameters.size())); | ||||
| @ -479,7 +478,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) | ||||
| 				else | ||||
| 				{ | ||||
| 					m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u)); | ||||
| 					swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back()); | ||||
| 					std::swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back()); | ||||
| 				} | ||||
| 			for (size_t i = 0; i < stackLayout.size(); ++i) | ||||
| 				yulAssert(i == static_cast<size_t>(stackLayout[i]), "Error reshuffling stack."); | ||||
| @ -571,7 +570,7 @@ void CodeTransform::operator()(Block const& _block) | ||||
| 	m_scope = m_info.scopes.at(&_block).get(); | ||||
| 
 | ||||
| 	for (auto const& statement: _block.statements) | ||||
| 		if (auto function = get_if<FunctionDefinition>(&statement)) | ||||
| 		if (auto function = std::get_if<FunctionDefinition>(&statement)) | ||||
| 			createFunctionEntryID(*function); | ||||
| 
 | ||||
| 	int blockStartStackHeight = m_assembly.stackHeight(); | ||||
| @ -579,7 +578,7 @@ void CodeTransform::operator()(Block const& _block) | ||||
| 
 | ||||
| 	bool isOutermostFunctionBodyBlock = m_scope && m_scope->superScope && m_scope->superScope->functionScope; | ||||
| 	bool performValidation = !m_allowStackOpt || !isOutermostFunctionBodyBlock; | ||||
| 	finalizeBlock(_block, performValidation ? make_optional(blockStartStackHeight) : nullopt); | ||||
| 	finalizeBlock(_block, performValidation ? std::make_optional(blockStartStackHeight) : std::nullopt); | ||||
| 	m_scope = originalScope; | ||||
| } | ||||
| 
 | ||||
| @ -588,7 +587,7 @@ void CodeTransform::createFunctionEntryID(FunctionDefinition const& _function) | ||||
| 	Scope::Function& scopeFunction = std::get<Scope::Function>(m_scope->identifiers.at(_function.name)); | ||||
| 	yulAssert(!m_context->functionEntryIDs.count(&scopeFunction), ""); | ||||
| 
 | ||||
| 	optional<size_t> astID; | ||||
| 	std::optional<size_t> astID; | ||||
| 	if (_function.debugData) | ||||
| 		astID = _function.debugData->astID; | ||||
| 
 | ||||
| @ -659,16 +658,16 @@ void CodeTransform::setupReturnVariablesAndFunctionExit() | ||||
| namespace | ||||
| { | ||||
| 
 | ||||
| bool statementNeedsReturnVariableSetup(Statement const& _statement, vector<TypedName> const& _returnVariables) | ||||
| bool statementNeedsReturnVariableSetup(Statement const& _statement, std::vector<TypedName> const& _returnVariables) | ||||
| { | ||||
| 	if (holds_alternative<FunctionDefinition>(_statement)) | ||||
| 	if (std::holds_alternative<FunctionDefinition>(_statement)) | ||||
| 		return true; | ||||
| 	if ( | ||||
| 		holds_alternative<ExpressionStatement>(_statement) || | ||||
| 		holds_alternative<Assignment>(_statement) | ||||
| 		std::holds_alternative<ExpressionStatement>(_statement) || | ||||
| 		std::holds_alternative<Assignment>(_statement) | ||||
| 	) | ||||
| 	{ | ||||
| 		map<YulString, size_t> references = VariableReferencesCounter::countReferences(_statement); | ||||
| 		std::map<YulString, size_t> references = VariableReferencesCounter::countReferences(_statement); | ||||
| 		auto isReferenced = [&references](TypedName const& _returnVariable) { | ||||
| 			return references.count(_returnVariable.name); | ||||
| 		}; | ||||
| @ -680,7 +679,7 @@ bool statementNeedsReturnVariableSetup(Statement const& _statement, vector<Typed | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void CodeTransform::visitStatements(vector<Statement> const& _statements) | ||||
| void CodeTransform::visitStatements(std::vector<Statement> const& _statements) | ||||
| { | ||||
| 	std::optional<AbstractAssembly::LabelID> jumpTarget = std::nullopt; | ||||
| 
 | ||||
| @ -716,7 +715,7 @@ void CodeTransform::visitStatements(vector<Statement> const& _statements) | ||||
| 	freeUnusedVariables(); | ||||
| } | ||||
| 
 | ||||
| void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartStackHeight) | ||||
| void CodeTransform::finalizeBlock(Block const& _block, std::optional<int> blockStartStackHeight) | ||||
| { | ||||
| 	m_assembly.setSourceLocation(originLocationOf(_block)); | ||||
| 
 | ||||
| @ -725,7 +724,7 @@ void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartS | ||||
| 	// pop variables
 | ||||
| 	yulAssert(m_info.scopes.at(&_block).get() == m_scope, ""); | ||||
| 	for (auto const& id: m_scope->identifiers) | ||||
| 		if (holds_alternative<Scope::Variable>(id.second)) | ||||
| 		if (std::holds_alternative<Scope::Variable>(id.second)) | ||||
| 		{ | ||||
| 			Scope::Variable const& var = std::get<Scope::Variable>(id.second); | ||||
| 			if (m_allowStackOpt) | ||||
| @ -740,11 +739,11 @@ void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartS | ||||
| 	if (blockStartStackHeight) | ||||
| 	{ | ||||
| 		int deposit = m_assembly.stackHeight() - *blockStartStackHeight; | ||||
| 		yulAssert(deposit == 0, "Invalid stack height at end of block: " + to_string(deposit)); | ||||
| 		yulAssert(deposit == 0, "Invalid stack height at end of block: " + std::to_string(deposit)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void CodeTransform::generateMultiAssignment(vector<Identifier> const& _variableNames) | ||||
| void CodeTransform::generateMultiAssignment(std::vector<Identifier> const& _variableNames) | ||||
| { | ||||
| 	yulAssert(m_scope, ""); | ||||
| 	for (auto const& variableName: _variableNames | ranges::views::reverse) | ||||
| @ -786,7 +785,7 @@ size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString | ||||
| 			"Variable " + | ||||
| 			_varName.str() + | ||||
| 			" is " + | ||||
| 			to_string(heightDiff - limit) + | ||||
| 			std::to_string(heightDiff - limit) + | ||||
| 			" slot(s) too deep inside the stack. " + | ||||
| 			stackTooDeepString | ||||
| 		); | ||||
| @ -798,7 +797,7 @@ size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString | ||||
| 
 | ||||
| int CodeTransform::variableStackHeight(YulString _name) const | ||||
| { | ||||
| 	Scope::Variable const* var = get_if<Scope::Variable>(m_scope->lookup(_name)); | ||||
| 	Scope::Variable const* var = std::get_if<Scope::Variable>(m_scope->lookup(_name)); | ||||
| 	yulAssert(var, ""); | ||||
| 	return static_cast<int>(m_context->variableStackHeights.at(var)); | ||||
| } | ||||
|  | ||||
| @ -38,7 +38,7 @@ | ||||
| 
 | ||||
| #include <regex> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace std::string_literals; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -46,9 +46,9 @@ using namespace solidity::util; | ||||
| namespace | ||||
| { | ||||
| 
 | ||||
| pair<YulString, BuiltinFunctionForEVM> createEVMFunction( | ||||
| std::pair<YulString, BuiltinFunctionForEVM> createEVMFunction( | ||||
| 	langutil::EVMVersion _evmVersion, | ||||
| 	string const& _name, | ||||
| 	std::string const& _name, | ||||
| 	evmasm::Instruction _instruction | ||||
| ) | ||||
| { | ||||
| @ -87,12 +87,12 @@ pair<YulString, BuiltinFunctionForEVM> createEVMFunction( | ||||
| 	return {name, std::move(f)}; | ||||
| } | ||||
| 
 | ||||
| pair<YulString, BuiltinFunctionForEVM> createFunction( | ||||
| 	string _name, | ||||
| std::pair<YulString, BuiltinFunctionForEVM> createFunction( | ||||
| 	std::string _name, | ||||
| 	size_t _params, | ||||
| 	size_t _returns, | ||||
| 	SideEffects _sideEffects, | ||||
| 	vector<optional<LiteralKind>> _literalArguments, | ||||
| 	std::vector<std::optional<LiteralKind>> _literalArguments, | ||||
| 	std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&)> _generateCode | ||||
| ) | ||||
| { | ||||
| @ -111,7 +111,7 @@ pair<YulString, BuiltinFunctionForEVM> createFunction( | ||||
| 	return {name, f}; | ||||
| } | ||||
| 
 | ||||
| set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion) | ||||
| std::set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion) | ||||
| { | ||||
| 	// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
 | ||||
| 	// basefee for VMs before london.
 | ||||
| @ -122,20 +122,20 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion) | ||||
| 
 | ||||
| 	// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
 | ||||
| 	// prevrandao for VMs before paris.
 | ||||
| 	auto prevRandaoException = [&](string const& _instrName) -> bool | ||||
| 	auto prevRandaoException = [&](std::string const& _instrName) -> bool | ||||
| 	{ | ||||
| 		// Using string comparison as the opcode is the same as for "difficulty"
 | ||||
| 		return _instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris(); | ||||
| 	}; | ||||
| 
 | ||||
| 	set<YulString> reserved; | ||||
| 	std::set<YulString> reserved; | ||||
| 	for (auto const& instr: evmasm::c_instructions) | ||||
| 	{ | ||||
| 		string name = toLower(instr.first); | ||||
| 		std::string name = toLower(instr.first); | ||||
| 		if (!baseFeeException(instr.second) && !prevRandaoException(name)) | ||||
| 			reserved.emplace(name); | ||||
| 	} | ||||
| 	reserved += vector<YulString>{ | ||||
| 	reserved += std::vector<YulString>{ | ||||
| 		"linkersymbol"_yulstring, | ||||
| 		"datasize"_yulstring, | ||||
| 		"dataoffset"_yulstring, | ||||
| @ -146,19 +146,19 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion) | ||||
| 	return reserved; | ||||
| } | ||||
| 
 | ||||
| map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess) | ||||
| std::map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess) | ||||
| { | ||||
| 
 | ||||
| 	// Exclude prevrandao as builtin for VMs before paris and difficulty for VMs after paris.
 | ||||
| 	auto prevRandaoException = [&](string const& _instrName) -> bool | ||||
| 	auto prevRandaoException = [&](std::string const& _instrName) -> bool | ||||
| 	{ | ||||
| 		return (_instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris()) || (_instrName == "difficulty" && _evmVersion >= langutil::EVMVersion::paris()); | ||||
| 	}; | ||||
| 
 | ||||
| 	map<YulString, BuiltinFunctionForEVM> builtins; | ||||
| 	std::map<YulString, BuiltinFunctionForEVM> builtins; | ||||
| 	for (auto const& instr: evmasm::c_instructions) | ||||
| 	{ | ||||
| 		string name = toLower(instr.first); | ||||
| 		std::string name = toLower(instr.first); | ||||
| 		auto const opcode = instr.second; | ||||
| 
 | ||||
| 		if ( | ||||
| @ -198,7 +198,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe | ||||
| 				BuiltinContext& | ||||
| 			) { | ||||
| 				yulAssert(_call.arguments.size() == 1, ""); | ||||
| 				Literal const* literal = get_if<Literal>(&_call.arguments.front()); | ||||
| 				Literal const* literal = std::get_if<Literal>(&_call.arguments.front()); | ||||
| 				yulAssert(literal, ""); | ||||
| 				_assembly.appendConstant(valueOfLiteral(*literal)); | ||||
| 			}) | ||||
| @ -217,10 +217,10 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe | ||||
| 				_assembly.appendAssemblySize(); | ||||
| 			else | ||||
| 			{ | ||||
| 				vector<size_t> subIdPath = | ||||
| 			std::vector<size_t> subIdPath = | ||||
| 					_context.subIDs.count(dataName) == 0 ? | ||||
| 						_context.currentObject->pathToSubObject(dataName) : | ||||
| 						vector<size_t>{_context.subIDs.at(dataName)}; | ||||
| 						std::vector<size_t>{_context.subIDs.at(dataName)}; | ||||
| 				yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); | ||||
| 				_assembly.appendDataSize(subIdPath); | ||||
| 			} | ||||
| @ -238,10 +238,10 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe | ||||
| 				_assembly.appendConstant(0); | ||||
| 			else | ||||
| 			{ | ||||
| 				vector<size_t> subIdPath = | ||||
| 			std::vector<size_t> subIdPath = | ||||
| 					_context.subIDs.count(dataName) == 0 ? | ||||
| 						_context.currentObject->pathToSubObject(dataName) : | ||||
| 						vector<size_t>{_context.subIDs.at(dataName)}; | ||||
| 						std::vector<size_t>{_context.subIDs.at(dataName)}; | ||||
| 				yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); | ||||
| 				_assembly.appendDataOffset(subIdPath); | ||||
| 			} | ||||
| @ -295,9 +295,9 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe | ||||
| 	return builtins; | ||||
| } | ||||
| 
 | ||||
| regex const& verbatimPattern() | ||||
| std::regex const& verbatimPattern() | ||||
| { | ||||
| 	regex static const pattern{"verbatim_([1-9]?[0-9])i_([1-9]?[0-9])o"}; | ||||
| 	std::regex static const pattern{"verbatim_([1-9]?[0-9])i_([1-9]?[0-9])o"}; | ||||
| 	return pattern; | ||||
| } | ||||
| 
 | ||||
| @ -316,7 +316,7 @@ BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const | ||||
| { | ||||
| 	if (m_objectAccess) | ||||
| 	{ | ||||
| 		smatch match; | ||||
| 		std::smatch match; | ||||
| 		if (regex_match(_name.str(), match, verbatimPattern())) | ||||
| 			return verbatimFunction(stoul(match[1]), stoul(match[2])); | ||||
| 	} | ||||
| @ -337,19 +337,19 @@ bool EVMDialect::reservedIdentifier(YulString _name) const | ||||
| 
 | ||||
| EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version) | ||||
| { | ||||
| 	static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects; | ||||
| 	static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialect const>> dialects; | ||||
| 	static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }}; | ||||
| 	if (!dialects[_version]) | ||||
| 		dialects[_version] = make_unique<EVMDialect>(_version, false); | ||||
| 		dialects[_version] = std::make_unique<EVMDialect>(_version, false); | ||||
| 	return *dialects[_version]; | ||||
| } | ||||
| 
 | ||||
| EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _version) | ||||
| { | ||||
| 	static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects; | ||||
| 	static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialect const>> dialects; | ||||
| 	static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }}; | ||||
| 	if (!dialects[_version]) | ||||
| 		dialects[_version] = make_unique<EVMDialect>(_version, true); | ||||
| 		dialects[_version] = std::make_unique<EVMDialect>(_version, true); | ||||
| 	return *dialects[_version]; | ||||
| } | ||||
| 
 | ||||
| @ -374,16 +374,16 @@ SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instructio | ||||
| 
 | ||||
| BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, size_t _returnVariables) const | ||||
| { | ||||
| 	pair<size_t, size_t> key{_arguments, _returnVariables}; | ||||
| 	shared_ptr<BuiltinFunctionForEVM const>& function = m_verbatimFunctions[key]; | ||||
| 	std::pair<size_t, size_t> key{_arguments, _returnVariables}; | ||||
| 	std::shared_ptr<BuiltinFunctionForEVM const>& function = m_verbatimFunctions[key]; | ||||
| 	if (!function) | ||||
| 	{ | ||||
| 		BuiltinFunctionForEVM builtinFunction = createFunction( | ||||
| 			"verbatim_" + to_string(_arguments) + "i_" + to_string(_returnVariables) + "o", | ||||
| 			"verbatim_" + std::to_string(_arguments) + "i_" + std::to_string(_returnVariables) + "o", | ||||
| 			1 + _arguments, | ||||
| 			_returnVariables, | ||||
| 			SideEffects::worst(), | ||||
| 			vector<optional<LiteralKind>>{LiteralKind::String} + vector<optional<LiteralKind>>(_arguments), | ||||
| 			std::vector<std::optional<LiteralKind>>{LiteralKind::String} + std::vector<std::optional<LiteralKind>>(_arguments), | ||||
| 			[=]( | ||||
| 				FunctionCall const& _call, | ||||
| 				AbstractAssembly& _assembly, | ||||
| @ -400,7 +400,7 @@ BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, siz | ||||
| 			} | ||||
| 		).second; | ||||
| 		builtinFunction.isMSize = true; | ||||
| 		function = make_shared<BuiltinFunctionForEVM const>(std::move(builtinFunction)); | ||||
| 		function = std::make_shared<BuiltinFunctionForEVM const>(std::move(builtinFunction)); | ||||
| 	} | ||||
| 	return function.get(); | ||||
| } | ||||
| @ -501,9 +501,9 @@ BuiltinFunctionForEVM const* EVMDialectTyped::equalityFunction(YulString _type) | ||||
| 
 | ||||
| EVMDialectTyped const& EVMDialectTyped::instance(langutil::EVMVersion _version) | ||||
| { | ||||
| 	static map<langutil::EVMVersion, unique_ptr<EVMDialectTyped const>> dialects; | ||||
| 	static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialectTyped const>> dialects; | ||||
| 	static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }}; | ||||
| 	if (!dialects[_version]) | ||||
| 		dialects[_version] = make_unique<EVMDialectTyped>(_version, true); | ||||
| 		dialects[_version] = std::make_unique<EVMDialectTyped>(_version, true); | ||||
| 	return *dialects[_version]; | ||||
| } | ||||
|  | ||||
| @ -31,7 +31,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -52,7 +51,7 @@ bigint GasMeter::combineCosts(std::pair<bigint, bigint> _costs) const | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pair<bigint, bigint> GasMeterVisitor::costs( | ||||
| std::pair<bigint, bigint> GasMeterVisitor::costs( | ||||
| 	Expression const& _expression, | ||||
| 	EVMDialect const& _dialect, | ||||
| 	bool _isCreation | ||||
| @ -63,7 +62,7 @@ pair<bigint, bigint> GasMeterVisitor::costs( | ||||
| 	return {gmv.m_runGas, gmv.m_dataGas}; | ||||
| } | ||||
| 
 | ||||
| pair<bigint, bigint> GasMeterVisitor::instructionCosts( | ||||
| std::pair<bigint, bigint> GasMeterVisitor::instructionCosts( | ||||
| 	evmasm::Instruction _instruction, | ||||
| 	EVMDialect const& _dialect, | ||||
| 	bool _isCreation | ||||
|  | ||||
| @ -33,7 +33,6 @@ | ||||
| #include <boost/algorithm/string.hpp> | ||||
| 
 | ||||
| using namespace solidity::yul; | ||||
| using namespace std; | ||||
| 
 | ||||
| void EVMObjectCompiler::compile( | ||||
| 	Object& _object, | ||||
| @ -91,12 +90,12 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) | ||||
| 		); | ||||
| 		if (!stackErrors.empty()) | ||||
| 		{ | ||||
| 			vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run( | ||||
| 			std::vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run( | ||||
| 				*_object.code, | ||||
| 				"memoryguard"_yulstring | ||||
| 			); | ||||
| 			auto stackError = stackErrors.front(); | ||||
| 			string msg = stackError.comment() ? *stackError.comment() : ""; | ||||
| 			std::string msg = stackError.comment() ? *stackError.comment() : ""; | ||||
| 			if (memoryGuardCalls.empty()) | ||||
| 				msg += "\nNo memoryguard was present. " | ||||
| 					"Consider using memory-safe assembly only and annotating it via " | ||||
|  | ||||
| @ -33,7 +33,6 @@ | ||||
| #include <memory> | ||||
| #include <functional> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -122,14 +121,14 @@ void EthAssemblyAdapter::appendAssemblySize() | ||||
| 	m_assembly.appendProgramSize(); | ||||
| } | ||||
| 
 | ||||
| pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, string _name) | ||||
| std::pair<std::shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, std::string _name) | ||||
| { | ||||
| 	shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(m_assembly.evmVersion(), _creation, std::move(_name))}; | ||||
| 	std::shared_ptr<evmasm::Assembly> assembly{std::make_shared<evmasm::Assembly>(m_assembly.evmVersion(), _creation, std::move(_name))}; | ||||
| 	auto sub = m_assembly.newSub(assembly); | ||||
| 	return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())}; | ||||
| 	return {std::make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())}; | ||||
| } | ||||
| 
 | ||||
| void EthAssemblyAdapter::appendDataOffset(vector<AbstractAssembly::SubID> const& _subPath) | ||||
| void EthAssemblyAdapter::appendDataOffset(std::vector<AbstractAssembly::SubID> const& _subPath) | ||||
| { | ||||
| 	if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end()) | ||||
| 	{ | ||||
| @ -141,7 +140,7 @@ void EthAssemblyAdapter::appendDataOffset(vector<AbstractAssembly::SubID> const& | ||||
| 	m_assembly.pushSubroutineOffset(m_assembly.encodeSubPath(_subPath)); | ||||
| } | ||||
| 
 | ||||
| void EthAssemblyAdapter::appendDataSize(vector<AbstractAssembly::SubID> const& _subPath) | ||||
| void EthAssemblyAdapter::appendDataSize(std::vector<AbstractAssembly::SubID> const& _subPath) | ||||
| { | ||||
| 	if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end()) | ||||
| 	{ | ||||
|  | ||||
| @ -28,7 +28,6 @@ | ||||
| 
 | ||||
| #include <range/v3/view/iota.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -60,12 +59,12 @@ NoOutputAssembly::LabelID NoOutputAssembly::newLabelId() | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| AbstractAssembly::LabelID NoOutputAssembly::namedLabel(string const&, size_t, size_t, optional<size_t>) | ||||
| AbstractAssembly::LabelID NoOutputAssembly::namedLabel(std::string const&, size_t, size_t, std::optional<size_t>) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| void NoOutputAssembly::appendLinkerSymbol(string const&) | ||||
| void NoOutputAssembly::appendLinkerSymbol(std::string const&) | ||||
| { | ||||
| 	yulAssert(false, "Linker symbols not yet implemented."); | ||||
| } | ||||
| @ -98,7 +97,7 @@ void NoOutputAssembly::appendAssemblySize() | ||||
| 	appendInstruction(evmasm::Instruction::PUSH1); | ||||
| } | ||||
| 
 | ||||
| pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string) | ||||
| std::pair<std::shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string) | ||||
| { | ||||
| 	yulAssert(false, "Sub assemblies not implemented."); | ||||
| 	return {}; | ||||
|  | ||||
| @ -38,9 +38,8 @@ | ||||
| 
 | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace std; | ||||
| 
 | ||||
| vector<StackTooDeepError> OptimizedEVMCodeTransform::run( | ||||
| std::vector<StackTooDeepError> OptimizedEVMCodeTransform::run( | ||||
| 	AbstractAssembly& _assembly, | ||||
| 	AsmAnalysisInfo& _analysisInfo, | ||||
| 	Block const& _block, | ||||
| @ -81,7 +80,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call) | ||||
| 		// Assert that we got the correct return label on stack.
 | ||||
| 		if (_call.canContinue) | ||||
| 		{ | ||||
| 			auto const* returnLabelSlot = get_if<FunctionCallReturnLabelSlot>( | ||||
| 			auto const* returnLabelSlot = std::get_if<FunctionCallReturnLabelSlot>( | ||||
| 				&m_stack.at(m_stack.size() - _call.functionCall.get().arguments.size() - 1) | ||||
| 			); | ||||
| 			yulAssert(returnLabelSlot && &returnLabelSlot->call.get() == &_call.functionCall.get(), ""); | ||||
| @ -160,7 +159,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::Assignment const& _assignment) | ||||
| 
 | ||||
| 	// Invalidate occurrences of the assigned variables.
 | ||||
| 	for (auto& currentSlot: m_stack) | ||||
| 		if (VariableSlot const* varSlot = get_if<VariableSlot>(¤tSlot)) | ||||
| 		if (VariableSlot const* varSlot = std::get_if<VariableSlot>(¤tSlot)) | ||||
| 			if (util::contains(_assignment.variables, *varSlot)) | ||||
| 				currentSlot = JunkSlot{}; | ||||
| 
 | ||||
| @ -185,8 +184,8 @@ OptimizedEVMCodeTransform::OptimizedEVMCodeTransform( | ||||
| 	m_dfg(_dfg), | ||||
| 	m_stackLayout(_stackLayout), | ||||
| 	m_functionLabels([&](){ | ||||
| 		map<CFG::FunctionInfo const*, AbstractAssembly::LabelID> functionLabels; | ||||
| 		set<YulString> assignedFunctionNames; | ||||
| 		std::map<CFG::FunctionInfo const*, AbstractAssembly::LabelID> functionLabels; | ||||
| 		std::set<YulString> assignedFunctionNames; | ||||
| 		for (Scope::Function const* function: m_dfg.functions) | ||||
| 		{ | ||||
| 			CFG::FunctionInfo const& functionInfo = m_dfg.functionInfo.at(function); | ||||
| @ -199,7 +198,7 @@ OptimizedEVMCodeTransform::OptimizedEVMCodeTransform( | ||||
| 					function->name.str(), | ||||
| 					function->arguments.size(), | ||||
| 					function->returns.size(), | ||||
| 					functionInfo.debugData ? functionInfo.debugData->astID : nullopt | ||||
| 					functionInfo.debugData ? functionInfo.debugData->astID : std::nullopt | ||||
| 				) : | ||||
| 				m_assembly.newLabelId(); | ||||
| 		} | ||||
| @ -212,7 +211,7 @@ void OptimizedEVMCodeTransform::assertLayoutCompatibility(Stack const& _currentS | ||||
| { | ||||
| 	yulAssert(_currentStack.size() == _desiredStack.size(), ""); | ||||
| 	for (auto&& [currentSlot, desiredSlot]: ranges::zip_view(_currentStack, _desiredStack)) | ||||
| 		yulAssert(holds_alternative<JunkSlot>(desiredSlot) || currentSlot == desiredSlot, ""); | ||||
| 		yulAssert(std::holds_alternative<JunkSlot>(desiredSlot) || currentSlot == desiredSlot, ""); | ||||
| } | ||||
| 
 | ||||
| AbstractAssembly::LabelID OptimizedEVMCodeTransform::getFunctionLabel(Scope::Function const& _function) | ||||
| @ -224,15 +223,15 @@ void OptimizedEVMCodeTransform::validateSlot(StackSlot const& _slot, Expression | ||||
| { | ||||
| 	std::visit(util::GenericVisitor{ | ||||
| 		[&](yul::Literal const& _literal) { | ||||
| 			auto* literalSlot = get_if<LiteralSlot>(&_slot); | ||||
| 			auto* literalSlot = std::get_if<LiteralSlot>(&_slot); | ||||
| 			yulAssert(literalSlot && valueOfLiteral(_literal) == literalSlot->value, ""); | ||||
| 		}, | ||||
| 		[&](yul::Identifier const& _identifier) { | ||||
| 			auto* variableSlot = get_if<VariableSlot>(&_slot); | ||||
| 			auto* variableSlot = std::get_if<VariableSlot>(&_slot); | ||||
| 			yulAssert(variableSlot && variableSlot->variable.get().name == _identifier.name, ""); | ||||
| 		}, | ||||
| 		[&](yul::FunctionCall const& _call) { | ||||
| 			auto* temporarySlot = get_if<TemporarySlot>(&_slot); | ||||
| 			auto* temporarySlot = std::get_if<TemporarySlot>(&_slot); | ||||
| 			yulAssert(temporarySlot && &temporarySlot->call.get() == &_call && temporarySlot->index == 0, ""); | ||||
| 		} | ||||
| 	}, _expression); | ||||
| @ -267,10 +266,10 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons | ||||
| 				StackSlot const& deepSlot = m_stack.at(m_stack.size() - _i - 1); | ||||
| 				YulString varNameDeep = slotVariableName(deepSlot); | ||||
| 				YulString varNameTop = slotVariableName(m_stack.back()); | ||||
| 				string msg = | ||||
| 				std::string msg = | ||||
| 					"Cannot swap " + (varNameDeep.empty() ? "Slot " + stackSlotToString(deepSlot) : "Variable " + varNameDeep.str()) + | ||||
| 					" with " + (varNameTop.empty() ? "Slot " + stackSlotToString(m_stack.back()) : "Variable " + varNameTop.str()) + | ||||
| 					": too deep in the stack by " + to_string(deficit) + " slots in " + stackToString(m_stack); | ||||
| 					": too deep in the stack by " + std::to_string(deficit) + " slots in " + stackToString(m_stack); | ||||
| 				m_stackErrors.emplace_back(StackTooDeepError( | ||||
| 					m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{}, | ||||
| 					varNameDeep.empty() ? varNameTop : varNameDeep, | ||||
| @ -297,9 +296,9 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons | ||||
| 				{ | ||||
| 					int deficit = static_cast<int>(*depth - 15); | ||||
| 					YulString varName = slotVariableName(_slot); | ||||
| 					string msg = | ||||
| 					std::string msg = | ||||
| 						(varName.empty() ? "Slot " + stackSlotToString(_slot) : "Variable " + varName.str()) | ||||
| 						+ " is " + to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack); | ||||
| 						+ " is " + std::to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack); | ||||
| 					m_stackErrors.emplace_back(StackTooDeepError( | ||||
| 						m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{}, | ||||
| 						varName, | ||||
| @ -503,9 +502,9 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) | ||||
| 		[&](CFG::BasicBlock::Terminated const&) | ||||
| 		{ | ||||
| 			yulAssert(!_block.operations.empty()); | ||||
| 			if (CFG::BuiltinCall const* builtinCall = get_if<CFG::BuiltinCall>(&_block.operations.back().operation)) | ||||
| 			if (CFG::BuiltinCall const* builtinCall = std::get_if<CFG::BuiltinCall>(&_block.operations.back().operation)) | ||||
| 				yulAssert(builtinCall->builtin.get().controlFlowSideEffects.terminatesOrReverts(), ""); | ||||
| 			else if (CFG::FunctionCall const* functionCall = get_if<CFG::FunctionCall>(&_block.operations.back().operation)) | ||||
| 			else if (CFG::FunctionCall const* functionCall = std::get_if<CFG::FunctionCall>(&_block.operations.back().operation)) | ||||
| 				yulAssert(!functionCall->canContinue); | ||||
| 			else | ||||
| 				yulAssert(false); | ||||
|  | ||||
| @ -46,7 +46,6 @@ | ||||
| 
 | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace std; | ||||
| 
 | ||||
| StackLayout StackLayoutGenerator::run(CFG const& _cfg) | ||||
| { | ||||
| @ -59,9 +58,9 @@ StackLayout StackLayoutGenerator::run(CFG const& _cfg) | ||||
| 	return stackLayout; | ||||
| } | ||||
| 
 | ||||
| map<YulString, vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg) | ||||
| std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg) | ||||
| { | ||||
| 	map<YulString, vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors; | ||||
| 	std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors; | ||||
| 	stackTooDeepErrors[YulString{}] = reportStackTooDeep(_cfg, YulString{}); | ||||
| 	for (auto const& function: _cfg.functions) | ||||
| 		if (auto errors = reportStackTooDeep(_cfg, function->name); !errors.empty()) | ||||
| @ -69,7 +68,7 @@ map<YulString, vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator: | ||||
| 	return stackTooDeepErrors; | ||||
| } | ||||
| 
 | ||||
| vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName) | ||||
| std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName) | ||||
| { | ||||
| 	StackLayout stackLayout; | ||||
| 	CFG::FunctionInfo const* functionInfo = nullptr; | ||||
| @ -98,14 +97,14 @@ StackLayoutGenerator::StackLayoutGenerator(StackLayout& _layout, CFG::FunctionIn | ||||
| namespace | ||||
| { | ||||
| /// @returns all stack too deep errors that would occur when shuffling @a _source to @a _target.
 | ||||
| vector<StackLayoutGenerator::StackTooDeep> findStackTooDeep(Stack const& _source, Stack const& _target) | ||||
| std::vector<StackLayoutGenerator::StackTooDeep> findStackTooDeep(Stack const& _source, Stack const& _target) | ||||
| { | ||||
| 	Stack currentStack = _source; | ||||
| 	vector<StackLayoutGenerator::StackTooDeep> stackTooDeepErrors; | ||||
| 	std::vector<StackLayoutGenerator::StackTooDeep> stackTooDeepErrors; | ||||
| 	auto getVariableChoices = [](auto&& _range) { | ||||
| 		vector<YulString> result; | ||||
| 		std::vector<YulString> result; | ||||
| 		for (auto const& slot: _range) | ||||
| 			if (auto const* variableSlot = get_if<VariableSlot>(&slot)) | ||||
| 			if (auto const* variableSlot = std::get_if<VariableSlot>(&slot)) | ||||
| 				if (!util::contains(result, variableSlot->variable.get().name)) | ||||
| 					result.push_back(variableSlot->variable.get().name); | ||||
| 		return result; | ||||
| @ -160,7 +159,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla | ||||
| 	// PreviousSlot{0}, ..., PreviousSlot{n}, [output<0>], ..., [output<m>]
 | ||||
| 	auto layout = ranges::views::iota(0u, preOperationLayoutSize) | | ||||
| 		ranges::views::transform([](size_t _index) { return PreviousSlot{_index}; }) | | ||||
| 		ranges::to<vector<variant<PreviousSlot, StackSlot>>>; | ||||
| 		ranges::to<std::vector<std::variant<PreviousSlot, StackSlot>>>; | ||||
| 	layout += _operationOutput; | ||||
| 
 | ||||
| 	// Shortcut for trivial case.
 | ||||
| @ -171,23 +170,23 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla | ||||
| 	// that are aware of PreviousSlot's.
 | ||||
| 	struct ShuffleOperations | ||||
| 	{ | ||||
| 		vector<variant<PreviousSlot, StackSlot>>& layout; | ||||
| 		std::vector<std::variant<PreviousSlot, StackSlot>>& layout; | ||||
| 		Stack const& post; | ||||
| 		std::set<StackSlot> outputs; | ||||
| 		Multiplicity multiplicity; | ||||
| 		Callable generateSlotOnTheFly; | ||||
| 		ShuffleOperations( | ||||
| 			vector<variant<PreviousSlot, StackSlot>>& _layout, | ||||
| 			std::vector<std::variant<PreviousSlot, StackSlot>>& _layout, | ||||
| 			Stack const& _post, | ||||
| 			Callable _generateSlotOnTheFly | ||||
| 		): layout(_layout), post(_post), generateSlotOnTheFly(_generateSlotOnTheFly) | ||||
| 		{ | ||||
| 			for (auto const& layoutSlot: layout) | ||||
| 				if (StackSlot const* slot = get_if<StackSlot>(&layoutSlot)) | ||||
| 				if (StackSlot const* slot = std::get_if<StackSlot>(&layoutSlot)) | ||||
| 					outputs.insert(*slot); | ||||
| 
 | ||||
| 			for (auto const& layoutSlot: layout) | ||||
| 				if (StackSlot const* slot = get_if<StackSlot>(&layoutSlot)) | ||||
| 				if (StackSlot const* slot = std::get_if<StackSlot>(&layoutSlot)) | ||||
| 					--multiplicity[*slot]; | ||||
| 			for (auto&& slot: post) | ||||
| 				if (outputs.count(slot) || generateSlotOnTheFly(slot)) | ||||
| @ -235,7 +234,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla | ||||
| 		} | ||||
| 		void swap(size_t _i) | ||||
| 		{ | ||||
| 			yulAssert(!holds_alternative<PreviousSlot>(layout.at(layout.size() - _i - 1)) || !holds_alternative<PreviousSlot>(layout.back()), ""); | ||||
| 			yulAssert(!std::holds_alternative<PreviousSlot>(layout.at(layout.size() - _i - 1)) || !std::holds_alternative<PreviousSlot>(layout.back()), ""); | ||||
| 			std::swap(layout.at(layout.size() -  _i - 1), layout.back()); | ||||
| 		} | ||||
| 		size_t sourceSize() { return layout.size(); } | ||||
| @ -250,7 +249,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla | ||||
| 	// output in place. The resulting permutation of the PreviousSlot yields the ideal positions of slots
 | ||||
| 	// before the operation, i.e. if PreviousSlot{2} is at a position at which _post contains VariableSlot{"tmp"},
 | ||||
| 	// then we want the variable tmp in the slot at offset 2 in the layout before the operation.
 | ||||
| 	vector<optional<StackSlot>> idealLayout(_post.size(), nullopt); | ||||
| 	std::vector<std::optional<StackSlot>> idealLayout(_post.size(), std::nullopt); | ||||
| 	for (auto&& [slot, idealPosition]: ranges::zip_view(_post, layout)) | ||||
| 		if (PreviousSlot* previousSlot = std::get_if<PreviousSlot>(&idealPosition)) | ||||
| 			idealLayout.at(previousSlot->slot) = slot; | ||||
| @ -261,7 +260,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla | ||||
| 
 | ||||
| 	yulAssert(idealLayout.size() == preOperationLayoutSize, ""); | ||||
| 
 | ||||
| 	return idealLayout | ranges::views::transform([](optional<StackSlot> s) { | ||||
| 	return idealLayout | ranges::views::transform([](std::optional<StackSlot> s) { | ||||
| 		yulAssert(s, ""); | ||||
| 		return *s; | ||||
| 	}) | ranges::to<Stack>; | ||||
| @ -271,7 +270,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla | ||||
| Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation, bool _aggressiveStackCompression) | ||||
| { | ||||
| 	// Enable aggressive stack compression for recursive calls.
 | ||||
| 	if (auto const* functionCall = get_if<CFG::FunctionCall>(&_operation.operation)) | ||||
| 	if (auto const* functionCall = std::get_if<CFG::FunctionCall>(&_operation.operation)) | ||||
| 		if (functionCall->recursive) | ||||
| 			_aggressiveStackCompression = true; | ||||
| 
 | ||||
| @ -285,9 +284,9 @@ Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG | ||||
| 	Stack stack = createIdealLayout(_operation.output, _exitStack, generateSlotOnTheFly); | ||||
| 
 | ||||
| 	// Make sure the resulting previous slots do not overlap with any assignmed variables.
 | ||||
| 	if (auto const* assignment = get_if<CFG::Assignment>(&_operation.operation)) | ||||
| 	if (auto const* assignment = std::get_if<CFG::Assignment>(&_operation.operation)) | ||||
| 		for (auto& stackSlot: stack) | ||||
| 			if (auto const* varSlot = get_if<VariableSlot>(&stackSlot)) | ||||
| 			if (auto const* varSlot = std::get_if<VariableSlot>(&stackSlot)) | ||||
| 				yulAssert(!util::contains(assignment->variables, *varSlot), ""); | ||||
| 
 | ||||
| 	// Since stack+_operation.output can be easily shuffled to _exitLayout, the desired layout before the operation
 | ||||
| @ -335,11 +334,11 @@ Stack StackLayoutGenerator::propagateStackThroughBlock(Stack _exitStack, CFG::Ba | ||||
| 
 | ||||
| void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry, CFG::FunctionInfo const* _functionInfo) | ||||
| { | ||||
| 	list<CFG::BasicBlock const*> toVisit{&_entry}; | ||||
| 	set<CFG::BasicBlock const*> visited; | ||||
| 	std::list<CFG::BasicBlock const*> toVisit{&_entry}; | ||||
| 	std::set<CFG::BasicBlock const*> visited; | ||||
| 
 | ||||
| 	// TODO: check whether visiting only a subset of these in the outer iteration below is enough.
 | ||||
| 	list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps = collectBackwardsJumps(_entry); | ||||
| 	std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps = collectBackwardsJumps(_entry); | ||||
| 
 | ||||
| 	while (!toVisit.empty()) | ||||
| 	{ | ||||
| @ -407,10 +406,10 @@ void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry, CFG: | ||||
| 	fillInJunk(_entry, _functionInfo); | ||||
| } | ||||
| 
 | ||||
| optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies( | ||||
| std::optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies( | ||||
| 	CFG::BasicBlock const& _block, | ||||
| 	set<CFG::BasicBlock const*> const& _visited, | ||||
| 	list<CFG::BasicBlock const*>& _toVisit | ||||
| 	std::set<CFG::BasicBlock const*> const& _visited, | ||||
| 	std::list<CFG::BasicBlock const*>& _toVisit | ||||
| ) const | ||||
| { | ||||
| 	return std::visit(util::GenericVisitor{ | ||||
| @ -434,7 +433,7 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies( | ||||
| 				return m_layout.blockInfos.at(_jump.target).entryLayout; | ||||
| 			// Otherwise stage the jump target for visit and defer the current block.
 | ||||
| 			_toVisit.emplace_front(_jump.target); | ||||
| 			return nullopt; | ||||
| 			return std::nullopt; | ||||
| 		}, | ||||
| 		[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) -> std::optional<Stack> | ||||
| 		{ | ||||
| @ -456,7 +455,7 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies( | ||||
| 				_toVisit.emplace_front(_conditionalJump.zero); | ||||
| 			if (!nonZeroVisited) | ||||
| 				_toVisit.emplace_front(_conditionalJump.nonZero); | ||||
| 			return nullopt; | ||||
| 			return std::nullopt; | ||||
| 		}, | ||||
| 		[&](CFG::BasicBlock::FunctionReturn const& _functionReturn) -> std::optional<Stack> | ||||
| 		{ | ||||
| @ -476,9 +475,9 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies( | ||||
| 	}, _block.exit); | ||||
| } | ||||
| 
 | ||||
| list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> StackLayoutGenerator::collectBackwardsJumps(CFG::BasicBlock const& _entry) const | ||||
| std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> StackLayoutGenerator::collectBackwardsJumps(CFG::BasicBlock const& _entry) const | ||||
| { | ||||
| 	list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps; | ||||
| 	std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps; | ||||
| 	util::BreadthFirstSearch<CFG::BasicBlock const*>{{&_entry}}.run([&](CFG::BasicBlock const* _block, auto _addChild) { | ||||
| 		std::visit(util::GenericVisitor{ | ||||
| 			[&](CFG::BasicBlock::MainExit const&) {}, | ||||
| @ -576,7 +575,7 @@ Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _sta | ||||
| 		if (!util::contains(candidate, slot)) | ||||
| 			candidate.emplace_back(slot); | ||||
| 	cxx20::erase_if(candidate, [](StackSlot const& slot) { | ||||
| 		return holds_alternative<LiteralSlot>(slot) || holds_alternative<FunctionCallReturnLabelSlot>(slot); | ||||
| 		return std::holds_alternative<LiteralSlot>(slot) || std::holds_alternative<FunctionCallReturnLabelSlot>(slot); | ||||
| 	}); | ||||
| 
 | ||||
| 	auto evaluate = [&](Stack const& _candidate) -> size_t { | ||||
| @ -633,9 +632,9 @@ Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _sta | ||||
| 	return commonPrefix + bestCandidate; | ||||
| } | ||||
| 
 | ||||
| vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG::BasicBlock const& _entry) const | ||||
| std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG::BasicBlock const& _entry) const | ||||
| { | ||||
| 	vector<StackTooDeep> stackTooDeepErrors; | ||||
| 	std::vector<StackTooDeep> stackTooDeepErrors; | ||||
| 	util::BreadthFirstSearch<CFG::BasicBlock const*> breadthFirstSearch{{&_entry}}; | ||||
| 	breadthFirstSearch.run([&](CFG::BasicBlock const* _block, auto _addChild) { | ||||
| 		Stack currentStack = m_layout.blockInfos.at(_block).entryLayout; | ||||
| @ -683,7 +682,7 @@ vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooD | ||||
| 
 | ||||
| Stack StackLayoutGenerator::compressStack(Stack _stack) | ||||
| { | ||||
| 	optional<size_t> firstDupOffset; | ||||
| 	std::optional<size_t> firstDupOffset; | ||||
| 	do | ||||
| 	{ | ||||
| 		if (firstDupOffset) | ||||
| @ -768,8 +767,8 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi | ||||
| 				{ | ||||
| 					// This has to be a previously unassigned return variable.
 | ||||
| 					// We at least sanity-check that it is among the return variables at all.
 | ||||
| 					yulAssert(m_currentFunctionInfo && holds_alternative<VariableSlot>(_slot)); | ||||
| 					yulAssert(util::contains(m_currentFunctionInfo->returnVariables, get<VariableSlot>(_slot))); | ||||
| 					yulAssert(m_currentFunctionInfo && std::holds_alternative<VariableSlot>(_slot)); | ||||
| 					yulAssert(util::contains(m_currentFunctionInfo->returnVariables, std::get<VariableSlot>(_slot))); | ||||
| 					// Strictly speaking the cost of the PUSH0 depends on the targeted EVM version, but the difference
 | ||||
| 					// will not matter here.
 | ||||
| 					opGas += evmasm::GasMeter::runGas(evmasm::pushInstruction(0), langutil::EVMVersion());; | ||||
|  | ||||
| @ -25,7 +25,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/Common.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
|  | ||||
| @ -25,7 +25,6 @@ | ||||
| 
 | ||||
| #include <range/v3/view/reverse.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| 
 | ||||
| #include <functional> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -34,9 +33,9 @@ void BlockFlattener::operator()(Block& _block) | ||||
| 
 | ||||
| 	iterateReplacing( | ||||
| 		_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); | ||||
| 			else | ||||
| 				return {}; | ||||
| @ -48,9 +47,9 @@ void BlockFlattener::run(OptimiserStepContext&, Block& _ast) | ||||
| { | ||||
| 	BlockFlattener flattener; | ||||
| 	for (auto& statement: _ast.statements) | ||||
| 		if (auto* block = get_if<Block>(&statement)) | ||||
| 		if (auto* block = std::get_if<Block>(&statement)) | ||||
| 			flattener(*block); | ||||
| 		else if (auto* function = get_if<FunctionDefinition>(&statement)) | ||||
| 		else if (auto* function = std::get_if<FunctionDefinition>(&statement)) | ||||
| 			flattener(function->body); | ||||
| 		else | ||||
| 			yulAssert(false, "BlockFlattener requires the FunctionGrouper."); | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| #include <libyul/AST.h> | ||||
| #include <libyul/Utilities.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
|  | ||||
| @ -25,7 +25,6 @@ | ||||
| #include <libsolutil/CommonData.h> | ||||
| #include <stack> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -36,9 +35,9 @@ namespace | ||||
| struct CallGraphCycleFinder | ||||
| { | ||||
| 	CallGraph const& callGraph; | ||||
| 	set<YulString> containedInCycle{}; | ||||
| 	set<YulString> visited{}; | ||||
| 	vector<YulString> currentPath{}; | ||||
| 	std::set<YulString> containedInCycle{}; | ||||
| 	std::set<YulString> visited{}; | ||||
| 	std::vector<YulString> currentPath{}; | ||||
| 
 | ||||
| 	void visit(YulString _function) | ||||
| 	{ | ||||
| @ -62,7 +61,7 @@ struct CallGraphCycleFinder | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| set<YulString> CallGraph::recursiveFunctions() const | ||||
| std::set<YulString> CallGraph::recursiveFunctions() const | ||||
| { | ||||
| 	CallGraphCycleFinder cycleFinder{*this}; | ||||
| 	// Visiting the root only is not enough, since there may be disconnected recursive functions.
 | ||||
|  | ||||
| @ -24,7 +24,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/Algorithms.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast) | ||||
| @ -35,11 +34,11 @@ void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast) | ||||
| 
 | ||||
| void CircularReferencesPruner::operator()(Block& _block) | ||||
| { | ||||
| 	set<YulString> functionsToKeep = | ||||
| 	std::set<YulString> functionsToKeep = | ||||
| 		functionsCalledFromOutermostContext(CallGraphGenerator::callGraph(_block)); | ||||
| 
 | ||||
| 	for (auto&& statement: _block.statements) | ||||
| 		if (holds_alternative<FunctionDefinition>(statement)) | ||||
| 		if (std::holds_alternative<FunctionDefinition>(statement)) | ||||
| 		{ | ||||
| 			FunctionDefinition const& funDef = std::get<FunctionDefinition>(statement); | ||||
| 			if (!functionsToKeep.count(funDef.name)) | ||||
| @ -49,9 +48,9 @@ void CircularReferencesPruner::operator()(Block& _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("")); | ||||
| 
 | ||||
| 	return util::BreadthFirstSearch<YulString>{{verticesToTraverse.begin(), verticesToTraverse.end()}}.run( | ||||
|  | ||||
| @ -31,7 +31,6 @@ | ||||
| #include <libyul/Dialect.h> | ||||
| #include <libyul/Utilities.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -47,7 +46,7 @@ void CommonSubexpressionEliminator::run(OptimiserStepContext& _context, Block& _ | ||||
| 
 | ||||
| CommonSubexpressionEliminator::CommonSubexpressionEliminator( | ||||
| 	Dialect const& _dialect, | ||||
| 	map<YulString, SideEffects> _functionSideEffects | ||||
| 	std::map<YulString, SideEffects> _functionSideEffects | ||||
| ): | ||||
| 	DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore, std::move(_functionSideEffects)) | ||||
| { | ||||
| @ -69,7 +68,7 @@ void CommonSubexpressionEliminator::visit(Expression& _e) | ||||
| 	bool descend = true; | ||||
| 	// If this is a function call to a function that requires literal arguments,
 | ||||
| 	// do not try to simplify there.
 | ||||
| 	if (holds_alternative<FunctionCall>(_e)) | ||||
| 	if (std::holds_alternative<FunctionCall>(_e)) | ||||
| 	{ | ||||
| 		FunctionCall& funCall = std::get<FunctionCall>(_e); | ||||
| 
 | ||||
| @ -94,13 +93,13 @@ void CommonSubexpressionEliminator::visit(Expression& _e) | ||||
| 	if (descend) | ||||
| 		DataFlowAnalyzer::visit(_e); | ||||
| 
 | ||||
| 	if (Identifier const* identifier = get_if<Identifier>(&_e)) | ||||
| 	if (Identifier const* identifier = std::get_if<Identifier>(&_e)) | ||||
| 	{ | ||||
| 		YulString identifierName = identifier->name; | ||||
| 		if (AssignedValue const* assignedValue = variableValue(identifierName)) | ||||
| 		{ | ||||
| 			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)) | ||||
| 					_e = Identifier{debugDataOf(_e), value->name}; | ||||
| 		} | ||||
| @ -114,8 +113,8 @@ void CommonSubexpressionEliminator::visit(Expression& _e) | ||||
| 				// instead of literal zeros.
 | ||||
| 				if ( | ||||
| 					m_returnVariables.count(variable) && | ||||
| 					holds_alternative<Literal>(*value->value) && | ||||
| 					valueOfLiteral(get<Literal>(*value->value)) == 0 | ||||
| 					std::holds_alternative<Literal>(*value->value) && | ||||
| 					valueOfLiteral(std::get<Literal>(*value->value)) == 0 | ||||
| 				) | ||||
| 					continue; | ||||
| 				// We check for syntactic equality again because the value might have changed.
 | ||||
|  | ||||
| @ -22,7 +22,6 @@ | ||||
| #include <libyul/ControlFlowSideEffectsCollector.h> | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -38,7 +37,7 @@ void ConditionalSimplifier::run(OptimiserStepContext& _context, Block& _ast) | ||||
| void ConditionalSimplifier::operator()(Switch& _switch) | ||||
| { | ||||
| 	visit(*_switch.expression); | ||||
| 	if (!holds_alternative<Identifier>(*_switch.expression)) | ||||
| 	if (!std::holds_alternative<Identifier>(*_switch.expression)) | ||||
| 	{ | ||||
| 		ASTModifier::operator()(_switch); | ||||
| 		return; | ||||
| @ -53,7 +52,7 @@ void ConditionalSimplifier::operator()(Switch& _switch) | ||||
| 				Assignment{ | ||||
| 					_case.body.debugData, | ||||
| 					{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( | ||||
| 		_block.statements, | ||||
| 		[&](Statement& _s) -> std::optional<vector<Statement>> | ||||
| 		[&](Statement& _s) -> std::optional<std::vector<Statement>> | ||||
| 		{ | ||||
| 			visit(_s); | ||||
| 			if (holds_alternative<If>(_s)) | ||||
| 			if (std::holds_alternative<If>(_s)) | ||||
| 			{ | ||||
| 				If& _if = std::get<If>(_s); | ||||
| 				if ( | ||||
| 					holds_alternative<Identifier>(*_if.condition) && | ||||
| 					std::holds_alternative<Identifier>(*_if.condition) && | ||||
| 					!_if.body.statements.empty() && | ||||
| 					TerminationFinder(m_dialect, &m_functionSideEffects).controlFlowKind(_if.body.statements.back()) != | ||||
| 						TerminationFinder::ControlFlow::FlowOut | ||||
| @ -85,7 +84,7 @@ void ConditionalSimplifier::operator()(Block& _block) | ||||
| 						Assignment{ | ||||
| 							debugData, | ||||
| 							{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 <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -39,7 +38,7 @@ void ConditionalUnsimplifier::run(OptimiserStepContext& _context, Block& _ast) | ||||
| void ConditionalUnsimplifier::operator()(Switch& _switch) | ||||
| { | ||||
| 	visit(*_switch.expression); | ||||
| 	if (!holds_alternative<Identifier>(*_switch.expression)) | ||||
| 	if (!std::holds_alternative<Identifier>(*_switch.expression)) | ||||
| 	{ | ||||
| 		ASTModifier::operator()(_switch); | ||||
| 		return; | ||||
| @ -52,14 +51,14 @@ void ConditionalUnsimplifier::operator()(Switch& _switch) | ||||
| 			(*this)(*_case.value); | ||||
| 			if ( | ||||
| 				!_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()); | ||||
| 				if ( | ||||
| 					assignment.variableNames.size() == 1 && | ||||
| 					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) | ||||
| 				) | ||||
| 					_case.body.statements.erase(_case.body.statements.begin()); | ||||
| @ -74,19 +73,19 @@ void ConditionalUnsimplifier::operator()(Block& _block) | ||||
| 	walkVector(_block.statements); | ||||
| 	iterateReplacingWindow<2>( | ||||
| 		_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 ( | ||||
| 					holds_alternative<Identifier>(*_if.condition) && | ||||
| 					std::holds_alternative<Identifier>(*_if.condition) && | ||||
| 					!_if.body.statements.empty() | ||||
| 				) | ||||
| 				{ | ||||
| 					YulString condition = std::get<Identifier>(*_if.condition).name; | ||||
| 					if ( | ||||
| 						holds_alternative<Assignment>(_stmt2) && | ||||
| 						std::holds_alternative<Assignment>(_stmt2) && | ||||
| 						TerminationFinder(m_dialect, &m_functionSideEffects).controlFlowKind(_if.body.statements.back()) != | ||||
| 							TerminationFinder::ControlFlow::FlowOut | ||||
| 					) | ||||
| @ -95,7 +94,7 @@ void ConditionalUnsimplifier::operator()(Block& _block) | ||||
| 						if ( | ||||
| 							assignment.variableNames.size() == 1 && | ||||
| 							assignment.variableNames.front().name == condition && | ||||
| 							holds_alternative<Literal>(*assignment.value) && | ||||
| 							std::holds_alternative<Literal>(*assignment.value) && | ||||
| 							valueOfLiteral(std::get<Literal>(*assignment.value)) == 0 | ||||
| 						) | ||||
| 							return {make_vector<Statement>(std::move(_stmt1))}; | ||||
|  | ||||
| @ -27,12 +27,11 @@ | ||||
| 
 | ||||
| #include <range/v3/action/remove_if.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| using OptionalStatements = std::optional<vector<Statement>>; | ||||
| using OptionalStatements = std::optional<std::vector<Statement>>; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| @ -85,13 +84,13 @@ void ControlFlowSimplifier::operator()(Block& _block) | ||||
| void ControlFlowSimplifier::operator()(FunctionDefinition& _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(); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowSimplifier::visit(Statement& _st) | ||||
| { | ||||
| 	if (holds_alternative<ForLoop>(_st)) | ||||
| 	if (std::holds_alternative<ForLoop>(_st)) | ||||
| 	{ | ||||
| 		ForLoop& forLoop = std::get<ForLoop>(_st); | ||||
| 		yulAssert(forLoop.pre.statements.empty(), ""); | ||||
| @ -141,7 +140,7 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements) | ||||
| 		[&](If& _ifStmt) -> OptionalStatements { | ||||
| 			if (_ifStmt.body.statements.empty() && m_dialect.discardFunction(m_dialect.boolType)) | ||||
| 			{ | ||||
| 				OptionalStatements s = vector<Statement>{}; | ||||
| 				OptionalStatements s = std::vector<Statement>{}; | ||||
| 				s->emplace_back(makeDiscardCall( | ||||
| 					_ifStmt.debugData, | ||||
| 					*m_dialect.discardFunction(m_dialect.boolType), | ||||
| @ -197,7 +196,7 @@ OptionalStatements ControlFlowSimplifier::reduceSingleCaseSwitch(Switch& _switch | ||||
| 	yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!"); | ||||
| 
 | ||||
| 	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); | ||||
| 	if (switchCase.value) | ||||
| 	{ | ||||
| @ -205,7 +204,7 @@ OptionalStatements ControlFlowSimplifier::reduceSingleCaseSwitch(Switch& _switch | ||||
| 			return {}; | ||||
| 		return make_vector<Statement>(If{ | ||||
| 			std::move(_switchStmt.debugData), | ||||
| 			make_unique<Expression>(FunctionCall{ | ||||
| 			std::make_unique<Expression>(FunctionCall{ | ||||
| 				debugData, | ||||
| 				Identifier{debugData, m_dialect.equalityFunction(type)->name}, | ||||
| 				{std::move(*switchCase.value), std::move(*_switchStmt.expression)} | ||||
|  | ||||
| @ -38,7 +38,6 @@ | ||||
| 
 | ||||
| #include <range/v3/view/reverse.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity::yul; | ||||
| @ -46,7 +45,7 @@ using namespace solidity::yul; | ||||
| DataFlowAnalyzer::DataFlowAnalyzer( | ||||
| 	Dialect const& _dialect, | ||||
| 	MemoryAndStorage _analyzeStores, | ||||
| 	map<YulString, SideEffects> _functionSideEffects | ||||
| 	std::map<YulString, SideEffects> _functionSideEffects | ||||
| ): | ||||
| 	m_dialect(_dialect), | ||||
| 	m_functionSideEffects(std::move(_functionSideEffects)), | ||||
| @ -99,7 +98,7 @@ void DataFlowAnalyzer::operator()(ExpressionStatement& _statement) | ||||
| 
 | ||||
| void DataFlowAnalyzer::operator()(Assignment& _assignment) | ||||
| { | ||||
| 	set<YulString> names; | ||||
| 	std::set<YulString> names; | ||||
| 	for (auto const& var: _assignment.variableNames) | ||||
| 		names.emplace(var.name); | ||||
| 	assertThrow(_assignment.value, OptimizerException, ""); | ||||
| @ -110,7 +109,7 @@ void DataFlowAnalyzer::operator()(Assignment& _assignment) | ||||
| 
 | ||||
| void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl) | ||||
| { | ||||
| 	set<YulString> names; | ||||
| 	std::set<YulString> names; | ||||
| 	for (auto const& var: _varDecl.variables) | ||||
| 		names.emplace(var.name); | ||||
| 	m_variableScopes.back().variables += names; | ||||
| @ -139,14 +138,14 @@ void DataFlowAnalyzer::operator()(Switch& _switch) | ||||
| { | ||||
| 	clearKnowledgeIfInvalidated(*_switch.expression); | ||||
| 	visit(*_switch.expression); | ||||
| 	set<YulString> assignedVariables; | ||||
| 	std::set<YulString> assignedVariables; | ||||
| 	for (auto& _case: _switch.cases) | ||||
| 	{ | ||||
| 		Environment preEnvironment = m_state.environment; | ||||
| 		(*this)(_case.body); | ||||
| 		joinKnowledge(preEnvironment); | ||||
| 
 | ||||
| 		set<YulString> variables = assignedVariableNames(_case.body); | ||||
| 		std::set<YulString> variables = assignedVariableNames(_case.body); | ||||
| 		assignedVariables += variables; | ||||
| 		// This is a little too destructive, we could retain the old values.
 | ||||
| 		clearValues(variables); | ||||
| @ -192,7 +191,7 @@ void DataFlowAnalyzer::operator()(ForLoop& _for) | ||||
| 	AssignmentsSinceContinue assignmentsSinceCont; | ||||
| 	assignmentsSinceCont(_for.body); | ||||
| 
 | ||||
| 	set<YulString> assignedVariables = | ||||
| 	std::set<YulString> assignedVariables = | ||||
| 		assignedVariableNames(_for.body) + assignedVariableNames(_for.post); | ||||
| 	clearValues(assignedVariables); | ||||
| 
 | ||||
| @ -223,31 +222,31 @@ void DataFlowAnalyzer::operator()(Block& _block) | ||||
| 	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)) | ||||
| 		return *value; | ||||
| 	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)) | ||||
| 		return *value; | ||||
| 	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; | ||||
| 	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) | ||||
| 		clearValues(_variables); | ||||
| @ -321,7 +320,7 @@ void DataFlowAnalyzer::popScope() | ||||
| 	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
 | ||||
| 	// cleared, but not recursively, since only the value of the original
 | ||||
| @ -410,24 +409,24 @@ bool DataFlowAnalyzer::inScope(YulString _variableName) const | ||||
| 	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 (Literal const* literal = get_if<Literal>(value->value)) | ||||
| 		if (Literal const* literal = std::get_if<Literal>(value->value)) | ||||
| 			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, | ||||
| 	ExpressionStatement const& _statement | ||||
| ) 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 (Identifier const* key = std::get_if<Identifier>(&funCall->arguments.front())) | ||||
| 				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 {}; | ||||
| } | ||||
| 
 | ||||
| @ -436,21 +435,21 @@ std::optional<YulString> DataFlowAnalyzer::isSimpleLoad( | ||||
| 	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_loadFunctionName[static_cast<unsigned>(_location)]) | ||||
| 			if (Identifier const* key = std::get_if<Identifier>(&funCall->arguments.front())) | ||||
| 				return key->name; | ||||
| 	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 (Identifier const* start = std::get_if<Identifier>(&funCall->arguments.at(0))) | ||||
| 				if (Identifier const* length = std::get_if<Identifier>(&funCall->arguments.at(1))) | ||||
| 					return make_pair(start->name, length->name); | ||||
| 	return nullopt; | ||||
| 					return std::make_pair(start->name, length->name); | ||||
| 	return std::nullopt; | ||||
| } | ||||
| 
 | ||||
| void DataFlowAnalyzer::joinKnowledge(Environment const& _olderEnvironment) | ||||
|  | ||||
| @ -30,7 +30,6 @@ | ||||
| #include <algorithm> | ||||
| #include <limits> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity::yul; | ||||
| @ -54,7 +53,7 @@ void DeadCodeEliminator::operator()(Block& _block) | ||||
| { | ||||
| 	TerminationFinder::ControlFlow controlFlowChange; | ||||
| 	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.
 | ||||
| 	if (controlFlowChange != TerminationFinder::ControlFlow::FlowOut && index != std::numeric_limits<size_t>::max()) | ||||
| @ -62,7 +61,7 @@ void DeadCodeEliminator::operator()(Block& _block) | ||||
| 			remove_if( | ||||
| 				_block.statements.begin() + static_cast<ptrdiff_t>(index) + 1, | ||||
| 				_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() | ||||
| 		); | ||||
|  | ||||
| @ -26,7 +26,6 @@ | ||||
| #include <libyul/Exceptions.h> | ||||
| #include <libyul/Scope.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
|  | ||||
| @ -28,7 +28,6 @@ | ||||
| #include <libyul/AST.h> | ||||
| #include <libyul/Utilities.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity::evmasm; | ||||
| @ -50,17 +49,17 @@ void EqualStoreEliminator::visit(Statement& _statement) | ||||
| { | ||||
| 	// No need to consider potential changes through complex arguments since
 | ||||
| 	// 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 (optional<YulString> currentValue = storageValue(vars->first)) | ||||
| 			if (std::optional<YulString> currentValue = storageValue(vars->first)) | ||||
| 				if (*currentValue == vars->second) | ||||
| 					m_pendingRemovals.insert(&_statement); | ||||
| 		} | ||||
| 		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) | ||||
| 					m_pendingRemovals.insert(&_statement); | ||||
| 		} | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| #include <libyul/AST.h> | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
|  | ||||
| @ -25,7 +25,6 @@ | ||||
| #include <libyul/AST.h> | ||||
| #include <libyul/optimiser/Metrics.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
|  | ||||
| @ -30,7 +30,6 @@ | ||||
| 
 | ||||
| #include <libyul/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -50,14 +49,14 @@ void ExpressionInliner::operator()(FunctionDefinition& _fun) | ||||
| void ExpressionInliner::visit(Expression& _expression) | ||||
| { | ||||
| 	ASTModifier::visit(_expression); | ||||
| 	if (holds_alternative<FunctionCall>(_expression)) | ||||
| 	if (std::holds_alternative<FunctionCall>(_expression)) | ||||
| 	{ | ||||
| 		FunctionCall& funCall = std::get<FunctionCall>(_expression); | ||||
| 		if (!m_inlinableFunctions.count(funCall.functionName.name)) | ||||
| 			return; | ||||
| 		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++) | ||||
| 		{ | ||||
| 			Expression const& arg = funCall.arguments[i]; | ||||
|  | ||||
| @ -34,7 +34,6 @@ | ||||
| 
 | ||||
| #include <limits> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -66,7 +65,7 @@ void ExpressionJoiner::operator()(Block& _block) | ||||
| 
 | ||||
| void ExpressionJoiner::visit(Expression& _e) | ||||
| { | ||||
| 	if (holds_alternative<Identifier>(_e)) | ||||
| 	if (std::holds_alternative<Identifier>(_e)) | ||||
| 	{ | ||||
| 		Identifier const& identifier = std::get<Identifier>(_e); | ||||
| 		if (isLatestStatementVarDeclJoinable(identifier)) | ||||
| @ -89,7 +88,7 @@ ExpressionJoiner::ExpressionJoiner(Block& _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
 | ||||
| 	// 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) | ||||
| 	{ | ||||
| 		--i; | ||||
| 		if (!holds_alternative<Identifier>(arg) && !holds_alternative<Literal>(arg)) | ||||
| 		if (!std::holds_alternative<Identifier>(arg) && !std::holds_alternative<Literal>(arg)) | ||||
| 			break; | ||||
| 	} | ||||
| 	// i points to the last element that is neither an identifier nor a literal,
 | ||||
| @ -124,7 +123,7 @@ void ExpressionJoiner::decrementLatestStatementPointer() | ||||
| void ExpressionJoiner::resetLatestStatementPointer() | ||||
| { | ||||
| 	m_currentBlock = nullptr; | ||||
| 	m_latestStatementInBlock = numeric_limits<size_t>::max(); | ||||
| 	m_latestStatementInBlock = std::numeric_limits<size_t>::max(); | ||||
| } | ||||
| 
 | ||||
| Statement* ExpressionJoiner::latestStatement() | ||||
| @ -138,7 +137,7 @@ Statement* ExpressionJoiner::latestStatement() | ||||
| bool ExpressionJoiner::isLatestStatementVarDeclJoinable(Identifier const& _identifier) | ||||
| { | ||||
| 	Statement const* statement = latestStatement(); | ||||
| 	if (!statement || !holds_alternative<VariableDeclaration>(*statement)) | ||||
| 	if (!statement || !std::holds_alternative<VariableDeclaration>(*statement)) | ||||
| 		return false; | ||||
| 	VariableDeclaration const& varDecl = std::get<VariableDeclaration>(*statement); | ||||
| 	if (varDecl.variables.size() != 1 || !varDecl.value) | ||||
|  | ||||
| @ -29,7 +29,6 @@ | ||||
| 
 | ||||
| #include <libevmasm/SemanticInformation.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -49,8 +48,8 @@ void ExpressionSimplifier::visit(Expression& _expression) | ||||
| 	)) | ||||
| 		_expression = match->action().toExpression(debugDataOf(_expression), evmVersionFromDialect(m_dialect)); | ||||
| 
 | ||||
| 	if (auto* functionCall = get_if<FunctionCall>(&_expression)) | ||||
| 		if (optional<evmasm::Instruction> instruction = toEVMInstruction(m_dialect, functionCall->functionName.name)) | ||||
| 	if (auto* functionCall = std::get_if<FunctionCall>(&_expression)) | ||||
| 		if (std::optional<evmasm::Instruction> instruction = toEVMInstruction(m_dialect, functionCall->functionName.name)) | ||||
| 			for (auto op: evmasm::SemanticInformation::readWriteOperations(*instruction)) | ||||
| 				if (op.startParameter && op.lengthParameter) | ||||
| 				{ | ||||
| @ -59,7 +58,7 @@ void ExpressionSimplifier::visit(Expression& _expression) | ||||
| 					if ( | ||||
| 						knownToBeZero(lengthArgument) && | ||||
| 						!knownToBeZero(startArgument) && | ||||
| 						!holds_alternative<FunctionCall>(startArgument) | ||||
| 						!std::holds_alternative<FunctionCall>(startArgument) | ||||
| 					) | ||||
| 						startArgument = Literal{debugDataOf(startArgument), LiteralKind::Number, "0"_yulstring, {}}; | ||||
| 				} | ||||
| @ -67,9 +66,9 @@ void ExpressionSimplifier::visit(Expression& _expression) | ||||
| 
 | ||||
| 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; | ||||
| 	else if (auto const* identifier = get_if<Identifier>(&_expression)) | ||||
| 	else if (auto const* identifier = std::get_if<Identifier>(&_expression)) | ||||
| 		return valueOfIdentifier(identifier->name) == 0; | ||||
| 	else | ||||
| 		return false; | ||||
|  | ||||
| @ -30,7 +30,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -75,11 +74,11 @@ void ExpressionSplitter::operator()(ForLoop& _loop) | ||||
| 
 | ||||
| void ExpressionSplitter::operator()(Block& _block) | ||||
| { | ||||
| 	vector<Statement> saved; | ||||
| 	std::vector<Statement> saved; | ||||
| 	swap(saved, m_statementsToPrefix); | ||||
| 
 | ||||
| 	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>> { | ||||
| 		m_statementsToPrefix.clear(); | ||||
| 		visit(_statement); | ||||
| 		if (m_statementsToPrefix.empty()) | ||||
| @ -94,18 +93,18 @@ void ExpressionSplitter::operator()(Block& _block) | ||||
| 
 | ||||
| void ExpressionSplitter::outlineExpression(Expression& _expr) | ||||
| { | ||||
| 	if (holds_alternative<Identifier>(_expr)) | ||||
| 	if (std::holds_alternative<Identifier>(_expr)) | ||||
| 		return; | ||||
| 
 | ||||
| 	visit(_expr); | ||||
| 
 | ||||
| 	shared_ptr<DebugData const> debugData = debugDataOf(_expr); | ||||
| 	std::shared_ptr<DebugData const> debugData = debugDataOf(_expr); | ||||
| 	YulString var = m_nameDispenser.newName({}); | ||||
| 	YulString type = m_typeInfo.typeOf(_expr); | ||||
| 	m_statementsToPrefix.emplace_back(VariableDeclaration{ | ||||
| 		debugData, | ||||
| 		{{TypedName{debugData, var, type}}}, | ||||
| 		make_unique<Expression>(std::move(_expr)) | ||||
| 		std::make_unique<Expression>(std::move(_expr)) | ||||
| 	}); | ||||
| 	_expr = Identifier{debugData, var}; | ||||
| 	m_typeInfo.setVariableType(var, type); | ||||
|  | ||||
| @ -22,7 +22,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -35,17 +34,17 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop) | ||||
| { | ||||
| 	if ( | ||||
| 		m_dialect.booleanNegationFunction() && | ||||
| 		!holds_alternative<Literal>(*_forLoop.condition) && | ||||
| 		!holds_alternative<Identifier>(*_forLoop.condition) | ||||
| 		!std::holds_alternative<Literal>(*_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( | ||||
| 			begin(_forLoop.body.statements), | ||||
| 			If { | ||||
| 				debugData, | ||||
| 				make_unique<Expression>( | ||||
| 				std::make_unique<Expression>( | ||||
| 					FunctionCall { | ||||
| 						debugData, | ||||
| 						{debugData, m_dialect.booleanNegationFunction()->name}, | ||||
| @ -55,7 +54,7 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop) | ||||
| 				Block {debugData, util::make_vector<Statement>(Break{{}})} | ||||
| 			} | ||||
| 		); | ||||
| 		_forLoop.condition = make_unique<Expression>( | ||||
| 		_forLoop.condition = std::make_unique<Expression>( | ||||
| 			Literal { | ||||
| 				debugData, | ||||
| 				LiteralKind::Boolean, | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -38,32 +37,32 @@ void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop) | ||||
| 
 | ||||
| 	if ( | ||||
| 		!m_dialect.booleanNegationFunction() || | ||||
| 		!holds_alternative<Literal>(*_forLoop.condition) || | ||||
| 		!std::holds_alternative<Literal>(*_forLoop.condition) || | ||||
| 		valueOfLiteral(std::get<Literal>(*_forLoop.condition)) == u256(0) || | ||||
| 		_forLoop.body.statements.empty() || | ||||
| 		!holds_alternative<If>(_forLoop.body.statements.front()) | ||||
| 		!std::holds_alternative<If>(_forLoop.body.statements.front()) | ||||
| 	) | ||||
| 		return; | ||||
| 
 | ||||
| 	If& firstStatement = std::get<If>(_forLoop.body.statements.front()); | ||||
| 	if ( | ||||
| 		firstStatement.body.statements.empty() || | ||||
| 		!holds_alternative<Break>(firstStatement.body.statements.front()) | ||||
| 		!std::holds_alternative<Break>(firstStatement.body.statements.front()) | ||||
| 	) | ||||
| 		return; | ||||
| 	if (!SideEffectsCollector(m_dialect, *firstStatement.condition).movable()) | ||||
| 		return; | ||||
| 
 | ||||
| 	YulString iszero = m_dialect.booleanNegationFunction()->name; | ||||
| 	shared_ptr<DebugData const> debugData = debugDataOf(*firstStatement.condition); | ||||
| 	std::shared_ptr<DebugData const> debugData = debugDataOf(*firstStatement.condition); | ||||
| 
 | ||||
| 	if ( | ||||
| 		holds_alternative<FunctionCall>(*firstStatement.condition) && | ||||
| 		std::holds_alternative<FunctionCall>(*firstStatement.condition) && | ||||
| 		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 | ||||
| 		_forLoop.condition = make_unique<Expression>(FunctionCall{ | ||||
| 		_forLoop.condition = std::make_unique<Expression>(FunctionCall{ | ||||
| 			debugData, | ||||
| 			Identifier{debugData, iszero}, | ||||
| 			util::make_vector<Expression>( | ||||
|  | ||||
| @ -22,7 +22,6 @@ | ||||
| 
 | ||||
| #include <functional> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -30,15 +29,15 @@ void ForLoopInitRewriter::operator()(Block& _block) | ||||
| { | ||||
| 	util::iterateReplacing( | ||||
| 		_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); | ||||
| 				(*this)(forLoop.pre); | ||||
| 				(*this)(forLoop.body); | ||||
| 				(*this)(forLoop.post); | ||||
| 				vector<Statement> rewrite; | ||||
| 				std::vector<Statement> rewrite; | ||||
| 				swap(rewrite, forLoop.pre.statements); | ||||
| 				rewrite.emplace_back(std::move(forLoop)); | ||||
| 				return { std::move(rewrite) }; | ||||
|  | ||||
| @ -41,7 +41,6 @@ | ||||
| #include <range/v3/view/reverse.hpp> | ||||
| #include <range/v3/view/zip.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -63,15 +62,15 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& | ||||
| 	SSAValueTracker tracker; | ||||
| 	tracker(m_ast); | ||||
| 	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); | ||||
| 
 | ||||
| 	// Store size of global statements.
 | ||||
| 	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) | ||||
| 	{ | ||||
| 		if (!holds_alternative<FunctionDefinition>(statement)) | ||||
| 		if (!std::holds_alternative<FunctionDefinition>(statement)) | ||||
| 			continue; | ||||
| 		FunctionDefinition& fun = std::get<FunctionDefinition>(statement); | ||||
| 		m_functions[fun.name] = &fun; | ||||
| @ -84,7 +83,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& | ||||
| 	} | ||||
| 
 | ||||
| 	// Check for memory guard.
 | ||||
| 	vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run( | ||||
| 	std::vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run( | ||||
| 		_ast, | ||||
| 		"memoryguard"_yulstring | ||||
| 	); | ||||
| @ -105,10 +104,10 @@ void FullInliner::run(Pass _pass) | ||||
| 	// function name) order.
 | ||||
| 	// We use stable_sort below to keep the inlining order of two functions
 | ||||
| 	// with the same depth.
 | ||||
| 	map<YulString, size_t> depths = callDepths(); | ||||
| 	vector<FunctionDefinition*> functions; | ||||
| 	std::map<YulString, size_t> depths = callDepths(); | ||||
| 	std::vector<FunctionDefinition*> functions; | ||||
| 	for (auto& statement: m_ast.statements) | ||||
| 		if (holds_alternative<FunctionDefinition>(statement)) | ||||
| 		if (std::holds_alternative<FunctionDefinition>(statement)) | ||||
| 			functions.emplace_back(&std::get<FunctionDefinition>(statement)); | ||||
| 	std::stable_sort(functions.begin(), functions.end(), [depths]( | ||||
| 		FunctionDefinition const* _a, | ||||
| @ -123,11 +122,11 @@ void FullInliner::run(Pass _pass) | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto& statement: m_ast.statements) | ||||
| 		if (holds_alternative<Block>(statement)) | ||||
| 		if (std::holds_alternative<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); | ||||
| 	cg.functionCalls.erase(""_yulstring); | ||||
| @ -140,12 +139,12 @@ map<YulString, size_t> FullInliner::callDepths() const | ||||
| 			else | ||||
| 				++it; | ||||
| 
 | ||||
| 	map<YulString, size_t> depths; | ||||
| 	std::map<YulString, size_t> depths; | ||||
| 	size_t currentDepth = 0; | ||||
| 
 | ||||
| 	while (true) | ||||
| 	{ | ||||
| 		vector<YulString> removed; | ||||
| 		std::vector<YulString> removed; | ||||
| 		for (auto it = cg.functionCalls.begin(); it != cg.functionCalls.end();) | ||||
| 		{ | ||||
| 			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.
 | ||||
| 	// To avoid running into this, make sure that ExpressionSplitter runs before FullInliner.
 | ||||
| 	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; | ||||
| 
 | ||||
| 	// 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.
 | ||||
| 	bool constantArg = false; | ||||
| 	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) && | ||||
| 			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 | ||||
| { | ||||
| 	map<YulString, size_t> references = ReferencesCounter::countReferences(_fun); | ||||
| 	std::map<YulString, size_t> references = ReferencesCounter::countReferences(_fun); | ||||
| 	return references[_fun.name] > 0; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 		return tryInlineStatement(_statement); | ||||
| 	}; | ||||
| 	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.
 | ||||
| 	Expression* e = std::visit(util::GenericVisitor{ | ||||
| @ -290,10 +289,10 @@ std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _ | ||||
| 	return {}; | ||||
| } | ||||
| 
 | ||||
| vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionCall& _funCall) | ||||
| std::vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionCall& _funCall) | ||||
| { | ||||
| 	vector<Statement> newStatements; | ||||
| 	map<YulString, YulString> variableReplacements; | ||||
| 	std::vector<Statement> newStatements; | ||||
| 	std::map<YulString, YulString> variableReplacements; | ||||
| 
 | ||||
| 	FunctionDefinition* function = m_driver.function(_funCall.functionName.name); | ||||
| 	assertThrow(!!function, OptimizerException, "Attempt to inline invalid function."); | ||||
| @ -307,9 +306,9 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC | ||||
| 		variableReplacements[_existingVariable.name] = newName; | ||||
| 		VariableDeclaration varDecl{_funCall.debugData, {{_funCall.debugData, newName, _existingVariable.type}}, {}}; | ||||
| 		if (_value) | ||||
| 			varDecl.value = make_unique<Expression>(std::move(*_value)); | ||||
| 			varDecl.value = std::make_unique<Expression>(std::move(*_value)); | ||||
| 		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)); | ||||
| 	}; | ||||
| 
 | ||||
| @ -329,7 +328,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC | ||||
| 				newStatements.emplace_back(Assignment{ | ||||
| 					_assignment.debugData, | ||||
| 					{_assignment.variableNames[i]}, | ||||
| 					make_unique<Expression>(Identifier{ | ||||
| 					std::make_unique<Expression>(Identifier{ | ||||
| 						_assignment.debugData, | ||||
| 						variableReplacements.at(function->returnVariables[i].name) | ||||
| 					}) | ||||
| @ -341,7 +340,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC | ||||
| 				newStatements.emplace_back(VariableDeclaration{ | ||||
| 					_varDecl.debugData, | ||||
| 					{std::move(_varDecl.variables[i])}, | ||||
| 					make_unique<Expression>(Identifier{ | ||||
| 					std::make_unique<Expression>(Identifier{ | ||||
| 						_varDecl.debugData, | ||||
| 						variableReplacements.at(function->returnVariables[i].name) | ||||
| 					}) | ||||
|  | ||||
| @ -18,11 +18,10 @@ | ||||
| #include <libyul/optimiser/FunctionCallFinder.h> | ||||
| #include <libyul/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| 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(_block); | ||||
|  | ||||
| @ -24,7 +24,6 @@ | ||||
| 
 | ||||
| #include <libyul/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -34,12 +33,12 @@ void FunctionGrouper::operator()(Block& _block) | ||||
| 	if (alreadyGrouped(_block)) | ||||
| 		return; | ||||
| 
 | ||||
| 	vector<Statement> reordered; | ||||
| 	std::vector<Statement> reordered; | ||||
| 	reordered.emplace_back(Block{_block.debugData, {}}); | ||||
| 
 | ||||
| 	for (auto&& statement: _block.statements) | ||||
| 	{ | ||||
| 		if (holds_alternative<FunctionDefinition>(statement)) | ||||
| 		if (std::holds_alternative<FunctionDefinition>(statement)) | ||||
| 			reordered.emplace_back(std::move(statement)); | ||||
| 		else | ||||
| 			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()) | ||||
| 		return false; | ||||
| 	if (!holds_alternative<Block>(_block.statements.front())) | ||||
| 	if (!std::holds_alternative<Block>(_block.statements.front())) | ||||
| 		return false; | ||||
| 	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 true; | ||||
| } | ||||
|  | ||||
| @ -27,7 +27,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -38,7 +37,7 @@ void FunctionHoister::operator()(Block& _block) | ||||
| 	for (auto&& statement: _block.statements) | ||||
| 	{ | ||||
| 		std::visit(*this, statement); | ||||
| 		if (holds_alternative<FunctionDefinition>(statement)) | ||||
| 		if (std::holds_alternative<FunctionDefinition>(statement)) | ||||
| 		{ | ||||
| 			m_functions.emplace_back(std::move(statement)); | ||||
| 			statement = Block{_block.debugData, {}}; | ||||
|  | ||||
| @ -32,7 +32,6 @@ | ||||
| 
 | ||||
| #include <variant> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -40,11 +39,11 @@ FunctionSpecializer::LiteralArguments FunctionSpecializer::specializableArgument | ||||
| 	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 nullopt; | ||||
| 		return std::nullopt; | ||||
| 	}; | ||||
| 
 | ||||
| 	return applyMap(_f.arguments, heuristic); | ||||
| @ -68,7 +67,7 @@ void FunctionSpecializer::operator()(FunctionCall& _f) | ||||
| 		YulString oldName = std::move(_f.functionName.name); | ||||
| 		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.arguments = util::filter( | ||||
| @ -86,27 +85,27 @@ FunctionDefinition FunctionSpecializer::specialize( | ||||
| { | ||||
| 	yulAssert(_arguments.size() == _f.parameters.size(), ""); | ||||
| 
 | ||||
| 	map<YulString, YulString> translatedNames = applyMap( | ||||
| 	std::map<YulString, YulString> translatedNames = applyMap( | ||||
| 		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
 | ||||
| 	// declarations.
 | ||||
| 	vector<Statement> missingVariableDeclarations; | ||||
| 	std::vector<Statement> missingVariableDeclarations; | ||||
| 	for (auto&& [index, argument]: _arguments | ranges::views::enumerate) | ||||
| 		if (argument) | ||||
| 			missingVariableDeclarations.emplace_back( | ||||
| 				VariableDeclaration{ | ||||
| 					_f.debugData, | ||||
| 					vector<TypedName>{newFunction.parameters[index]}, | ||||
| 					make_unique<Expression>(std::move(*argument)) | ||||
| 					std::vector<TypedName>{newFunction.parameters[index]}, | ||||
| 					std::make_unique<Expression>(std::move(*argument)) | ||||
| 				} | ||||
| 			); | ||||
| 
 | ||||
| @ -134,15 +133,15 @@ void FunctionSpecializer::run(OptimiserStepContext& _context, Block& _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)) | ||||
| 			{ | ||||
| 				vector<Statement> out = applyMap( | ||||
| 				std::vector<Statement> out = applyMap( | ||||
| 					f.m_oldToNewMap.at(functionDefinition.name), | ||||
| 					[&](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/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -46,7 +45,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu | ||||
| 	{ | ||||
| 		YulString retVariable = _function.returnVariables.front().name; | ||||
| 		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); | ||||
| 			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
 | ||||
| 				// function body.
 | ||||
| 				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); | ||||
| 				if (!m_foundDisallowedIdentifier) | ||||
| 					m_inlinableFunctions[_function.name] = &_function; | ||||
|  | ||||
| @ -29,36 +29,35 @@ | ||||
| 
 | ||||
| #include <variant> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| KnowledgeBase::KnowledgeBase(map<YulString, AssignedValue> const& _ssaValues): | ||||
| KnowledgeBase::KnowledgeBase(std::map<YulString, AssignedValue> const& _ssaValues): | ||||
| 	m_valuesAreSSA(true), | ||||
| 	m_variableValues([_ssaValues](YulString _var) { return util::valueOrNullptr(_ssaValues, _var); }) | ||||
| {} | ||||
| 
 | ||||
| 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 false; | ||||
| } | ||||
| 
 | ||||
| optional<u256> KnowledgeBase::differenceIfKnownConstant(YulString _a, YulString _b) | ||||
| std::optional<u256> KnowledgeBase::differenceIfKnownConstant(YulString _a, YulString _b) | ||||
| { | ||||
| 	VariableOffset offA = explore(_a); | ||||
| 	VariableOffset offB = explore(_b); | ||||
| 	if (offA.reference == offB.reference) | ||||
| 		return offA.offset - offB.offset; | ||||
| 	else | ||||
| 		return nullopt; | ||||
| 		return std::nullopt; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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 false; | ||||
| @ -69,19 +68,19 @@ bool KnowledgeBase::knownToBeZero(YulString _a) | ||||
| 	return valueIfKnownConstant(_a) == 0; | ||||
| } | ||||
| 
 | ||||
| optional<u256> KnowledgeBase::valueIfKnownConstant(YulString _a) | ||||
| std::optional<u256> KnowledgeBase::valueIfKnownConstant(YulString _a) | ||||
| { | ||||
| 	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); | ||||
| 	else if (Literal const* lit = get_if<Literal>(&_expression)) | ||||
| 	else if (Literal const* lit = std::get_if<Literal>(&_expression)) | ||||
| 		return valueOfLiteral(*lit); | ||||
| 	else | ||||
| 		return nullopt; | ||||
| 		return std::nullopt; | ||||
| } | ||||
| 
 | ||||
| KnowledgeBase::VariableOffset KnowledgeBase::explore(YulString _var) | ||||
| @ -105,24 +104,24 @@ KnowledgeBase::VariableOffset KnowledgeBase::explore(YulString _var) | ||||
| 	} | ||||
| 
 | ||||
| 	if (value) | ||||
| 		if (optional<VariableOffset> offset = explore(*value)) | ||||
| 		if (std::optional<VariableOffset> offset = explore(*value)) | ||||
| 			return setOffset(_var, *offset); | ||||
| 	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)}; | ||||
| 	else if (Identifier const* identifier = get_if<Identifier>(&_value)) | ||||
| 	else if (Identifier const* identifier = std::get_if<Identifier>(&_value)) | ||||
| 		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 (optional<VariableOffset> a = explore(f->arguments[0])) | ||||
| 				if (optional<VariableOffset> b = explore(f->arguments[1])) | ||||
| 			if (std::optional<VariableOffset> a = explore(f->arguments[0])) | ||||
| 				if (std::optional<VariableOffset> b = explore(f->arguments[1])) | ||||
| 				{ | ||||
| 					u256 offset = a->offset + b->offset; | ||||
| 					if (a->isAbsolute()) | ||||
| @ -134,8 +133,8 @@ optional<KnowledgeBase::VariableOffset> KnowledgeBase::explore(Expression const& | ||||
| 				} | ||||
| 		} | ||||
| 		else if (f->functionName.name == "sub"_yulstring) | ||||
| 			if (optional<VariableOffset> a = explore(f->arguments[0])) | ||||
| 				if (optional<VariableOffset> b = explore(f->arguments[1])) | ||||
| 			if (std::optional<VariableOffset> a = explore(f->arguments[0])) | ||||
| 				if (std::optional<VariableOffset> b = explore(f->arguments[1])) | ||||
| 				{ | ||||
| 					u256 offset = a->offset - b->offset; | ||||
| 					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) | ||||
| @ -175,7 +174,7 @@ void KnowledgeBase::reset(YulString _var) | ||||
| 			m_groupMembers[offset->reference].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.
 | ||||
| 		if (!group->empty()) | ||||
|  | ||||
| @ -36,7 +36,6 @@ | ||||
| 
 | ||||
| #include <limits> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity::evmasm; | ||||
| @ -65,8 +64,8 @@ void LoadResolver::visit(Expression& _e) | ||||
| 			tryResolve(_e, StoreLoadLocation::Storage, funCall->arguments); | ||||
| 		else if (!m_containsMSize && funCall->functionName.name == m_dialect.hashFunction({})) | ||||
| 		{ | ||||
| 			Identifier const* start = get_if<Identifier>(&funCall->arguments.at(0)); | ||||
| 			Identifier const* length = get_if<Identifier>(&funCall->arguments.at(1)); | ||||
| 			Identifier const* start = std::get_if<Identifier>(&funCall->arguments.at(0)); | ||||
| 			Identifier const* length = std::get_if<Identifier>(&funCall->arguments.at(1)); | ||||
| 			if (start && length) | ||||
| 				if (auto const& value = keccakValue(start->name, length->name)) | ||||
| 					if (inScope(*value)) | ||||
| @ -82,10 +81,10 @@ void LoadResolver::visit(Expression& _e) | ||||
| void LoadResolver::tryResolve( | ||||
| 	Expression& _e, | ||||
| 	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; | ||||
| 
 | ||||
| 	YulString key = std::get<Identifier>(_arguments.at(0)).name; | ||||
| @ -126,7 +125,7 @@ void LoadResolver::tryEvaluateKeccak( | ||||
| 			{}, | ||||
| 			LiteralKind::Number, | ||||
| 			// 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) | ||||
| 		return; | ||||
| 
 | ||||
| 	optional<YulString> value = memoryValue(memoryKey->name); | ||||
| 	std::optional<YulString> value = memoryValue(memoryKey->name); | ||||
| 	if (value && inScope(*value)) | ||||
| 	{ | ||||
| 		optional<u256> memoryContent = valueOfIdentifier(*value); | ||||
| 		optional<u256> byteLength = valueOfIdentifier(length->name); | ||||
| 		std::optional<u256> memoryContent = valueOfIdentifier(*value); | ||||
| 		std::optional<u256> byteLength = valueOfIdentifier(length->name); | ||||
| 		if (memoryContent && byteLength && *byteLength <= 32) | ||||
| 		{ | ||||
| 			bytes contentAsBytes = toBigEndian(*memoryContent); | ||||
|  | ||||
| @ -27,16 +27,15 @@ | ||||
| 
 | ||||
| #include <utility> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| void LoopInvariantCodeMotion::run(OptimiserStepContext& _context, Block& _ast) | ||||
| { | ||||
| 	map<YulString, SideEffects> functionSideEffects = | ||||
| 	std::map<YulString, SideEffects> functionSideEffects = | ||||
| 		SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_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); | ||||
| } | ||||
| 
 | ||||
| @ -44,11 +43,11 @@ void LoopInvariantCodeMotion::operator()(Block& _block) | ||||
| { | ||||
| 	util::iterateReplacing( | ||||
| 		_block.statements, | ||||
| 		[&](Statement& _s) -> optional<vector<Statement>> | ||||
| 		[&](Statement& _s) -> std::optional<std::vector<Statement>> | ||||
| 		{ | ||||
| 			visit(_s); | ||||
| 			if (holds_alternative<ForLoop>(_s)) | ||||
| 				return rewriteLoop(get<ForLoop>(_s)); | ||||
| 			if (std::holds_alternative<ForLoop>(_s)) | ||||
| 				return rewriteLoop(std::get<ForLoop>(_s)); | ||||
| 			else | ||||
| 				return {}; | ||||
| 		} | ||||
| @ -57,7 +56,7 @@ void LoopInvariantCodeMotion::operator()(Block& _block) | ||||
| 
 | ||||
| bool LoopInvariantCodeMotion::canBePromoted( | ||||
| 	VariableDeclaration const& _varDecl, | ||||
| 	set<YulString> const& _varsDefinedInCurrentScope, | ||||
| 	std::set<YulString> const& _varsDefinedInCurrentScope, | ||||
| 	SideEffects const& _forLoopSideEffects | ||||
| ) const | ||||
| { | ||||
| @ -81,29 +80,29 @@ bool LoopInvariantCodeMotion::canBePromoted( | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| optional<vector<Statement>> LoopInvariantCodeMotion::rewriteLoop(ForLoop& _for) | ||||
| std::optional<std::vector<Statement>> LoopInvariantCodeMotion::rewriteLoop(ForLoop& _for) | ||||
| { | ||||
| 	assertThrow(_for.pre.statements.empty(), OptimizerException, ""); | ||||
| 
 | ||||
| 	auto forLoopSideEffects = | ||||
| 		SideEffectsCollector{m_dialect, _for, &m_functionSideEffects}.sideEffects(); | ||||
| 
 | ||||
| 	vector<Statement> replacement; | ||||
| 	std::vector<Statement> replacement; | ||||
| 	for (Block* block: {&_for.post, &_for.body}) | ||||
| 	{ | ||||
| 		set<YulString> varsDefinedInScope; | ||||
| 		std::set<YulString> varsDefinedInScope; | ||||
| 		util::iterateReplacing( | ||||
| 			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); | ||||
| 					if (canBePromoted(varDecl, varsDefinedInScope, forLoopSideEffects)) | ||||
| 					{ | ||||
| 						replacement.emplace_back(std::move(_s)); | ||||
| 						// 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) | ||||
| 						varsDefinedInScope.insert(var.name); | ||||
|  | ||||
| @ -30,34 +30,33 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| 
 | ||||
| size_t CodeWeights::costOf(Statement const& _statement) const | ||||
| { | ||||
| 	if (holds_alternative<ExpressionStatement>(_statement)) | ||||
| 	if (std::holds_alternative<ExpressionStatement>(_statement)) | ||||
| 		return expressionStatementCost; | ||||
| 	else if (holds_alternative<Assignment>(_statement)) | ||||
| 	else if (std::holds_alternative<Assignment>(_statement)) | ||||
| 		return assignmentCost; | ||||
| 	else if (holds_alternative<VariableDeclaration>(_statement)) | ||||
| 	else if (std::holds_alternative<VariableDeclaration>(_statement)) | ||||
| 		return variableDeclarationCost; | ||||
| 	else if (holds_alternative<FunctionDefinition>(_statement)) | ||||
| 	else if (std::holds_alternative<FunctionDefinition>(_statement)) | ||||
| 		return functionDefinitionCost; | ||||
| 	else if (holds_alternative<If>(_statement)) | ||||
| 	else if (std::holds_alternative<If>(_statement)) | ||||
| 		return ifCost; | ||||
| 	else if (holds_alternative<Switch>(_statement)) | ||||
| 	else if (std::holds_alternative<Switch>(_statement)) | ||||
| 		return switchCost + caseCost * std::get<Switch>(_statement).cases.size(); | ||||
| 	else if (holds_alternative<ForLoop>(_statement)) | ||||
| 	else if (std::holds_alternative<ForLoop>(_statement)) | ||||
| 		return forLoopCost; | ||||
| 	else if (holds_alternative<Break>(_statement)) | ||||
| 	else if (std::holds_alternative<Break>(_statement)) | ||||
| 		return breakCost; | ||||
| 	else if (holds_alternative<Continue>(_statement)) | ||||
| 	else if (std::holds_alternative<Continue>(_statement)) | ||||
| 		return continueCost; | ||||
| 	else if (holds_alternative<Leave>(_statement)) | ||||
| 	else if (std::holds_alternative<Leave>(_statement)) | ||||
| 		return leaveCost; | ||||
| 	else if (holds_alternative<Block>(_statement)) | ||||
| 	else if (std::holds_alternative<Block>(_statement)) | ||||
| 		return blockCost; | ||||
| 	else | ||||
| 		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 | ||||
| { | ||||
| 	if (holds_alternative<FunctionCall>(_expression)) | ||||
| 	if (std::holds_alternative<FunctionCall>(_expression)) | ||||
| 		return functionCallCost; | ||||
| 	else if (holds_alternative<Identifier>(_expression)) | ||||
| 	else if (std::holds_alternative<Identifier>(_expression)) | ||||
| 		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.
 | ||||
| 		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) | ||||
| { | ||||
| 	if (holds_alternative<FunctionDefinition>(_statement) && m_ignoreFunctions) | ||||
| 	if (std::holds_alternative<FunctionDefinition>(_statement) && m_ignoreFunctions) | ||||
| 		return; | ||||
| 
 | ||||
| 	m_size += m_weights.costOf(_statement); | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| 
 | ||||
| #include <libyul/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| @ -60,21 +59,21 @@ void ReferencesCounter::operator()(FunctionCall const& _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; | ||||
| 	counter(_block); | ||||
| 	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; | ||||
| 	counter(_function); | ||||
| 	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; | ||||
| 	counter.visit(_expression); | ||||
| @ -86,28 +85,28 @@ void VariableReferencesCounter::operator()(Identifier const& _identifier) | ||||
| 	++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; | ||||
| 	counter(_block); | ||||
| 	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; | ||||
| 	counter(_function); | ||||
| 	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; | ||||
| 	counter.visit(_expression); | ||||
| 	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; | ||||
| 	counter.visit(_statement); | ||||
| @ -149,7 +148,7 @@ std::set<YulString> solidity::yul::assignedVariableNames(Block const& _code) | ||||
| 	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; | ||||
| 	forEach<FunctionDefinition const>(_block, [&](FunctionDefinition const& _function) { | ||||
|  | ||||
| @ -29,18 +29,17 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 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) | ||||
| { | ||||
| 	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_usedNames(std::move(_usedNames)) | ||||
| { | ||||
| @ -52,7 +51,7 @@ YulString NameDispenser::newName(YulString _nameHint) | ||||
| 	while (illegalName(name)) | ||||
| 	{ | ||||
| 		m_counter++; | ||||
| 		name = YulString(_nameHint.str() + "_" + to_string(m_counter)); | ||||
| 		name = YulString(_nameHint.str() + "_" + std::to_string(m_counter)); | ||||
| 	} | ||||
| 	m_usedNames.emplace(name); | ||||
| 	return name; | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| 
 | ||||
| #include <libyul/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -64,7 +63,7 @@ void NameDisplacer::operator()(Block& _block) | ||||
| 	// First replace all the names of function definitions
 | ||||
| 	// because of scoping.
 | ||||
| 	for (auto& st: _block.statements) | ||||
| 		if (holds_alternative<FunctionDefinition>(st)) | ||||
| 		if (std::holds_alternative<FunctionDefinition>(st)) | ||||
| 			checkAndReplaceNew(std::get<FunctionDefinition>(st).name); | ||||
| 
 | ||||
| 	ASTModifier::operator()(_block); | ||||
|  | ||||
| @ -28,7 +28,6 @@ | ||||
| #include <regex> | ||||
| 
 | ||||
| using namespace solidity::yul; | ||||
| using namespace std; | ||||
| 
 | ||||
| NameSimplifier::NameSimplifier(OptimiserStepContext& _context, Block const& _ast): | ||||
| 	m_context(_context) | ||||
| @ -54,7 +53,7 @@ void NameSimplifier::operator()(VariableDeclaration& _varDecl) | ||||
| 	ASTModifier::operator()(_varDecl); | ||||
| } | ||||
| 
 | ||||
| void NameSimplifier::renameVariables(vector<TypedName>& _variables) | ||||
| void NameSimplifier::renameVariables(std::vector<TypedName>& _variables) | ||||
| { | ||||
| 	for (TypedName& typedName: _variables) | ||||
| 		translate(typedName.name); | ||||
| @ -78,31 +77,31 @@ void NameSimplifier::findSimplification(YulString const& _name) | ||||
| 	if (m_translations.count(_name)) | ||||
| 		return; | ||||
| 
 | ||||
| 	string name = _name.str(); | ||||
| 	std::string name = _name.str(); | ||||
| 
 | ||||
| 	static auto replacements = vector<pair<regex, string>>{ | ||||
| 		{regex("_\\$|\\$_"), "_"}, // remove type mangling delimiters
 | ||||
| 		{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.
 | ||||
| 		{regex("_t_"), "_"}, // remove type prefixes
 | ||||
| 		{regex("__"), "_"}, | ||||
| 		{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
 | ||||
| 		{regex("tuple_"), ""}, | ||||
| 		{regex("_memory_ptr"), ""}, | ||||
| 		{regex("_calldata_ptr"), "_calldata"}, | ||||
| 		{regex("_fromStack"), ""}, | ||||
| 		{regex("_storage_storage"), "_storage"}, | ||||
| 		{regex("(storage.*)_?storage"), "$1"}, | ||||
| 		{regex("_memory_memory"), "_memory"}, | ||||
| 		{regex("_contract\\$_([^_]*)_?"), "$1_"}, | ||||
| 		{regex("index_access_(t_)?array"), "index_access"}, | ||||
| 		{regex("[0-9]*_$"), ""} | ||||
| 	static auto replacements = std::vector<std::pair<std::regex, std::string>>{ | ||||
| 		{std::regex("_\\$|\\$_"), "_"}, // remove type mangling delimiters
 | ||||
| 		{std::regex("_[0-9]+([^0-9a-fA-Fx])"), "$1"}, // removes AST IDs that are not hex.
 | ||||
| 		{std::regex("_[0-9]+$"), ""}, // removes AST IDs that are not hex.
 | ||||
| 		{std::regex("_t_"), "_"}, // remove type prefixes
 | ||||
| 		{std::regex("__"), "_"}, | ||||
| 		{std::regex("(abi_..code.*)_to_.*"), "$1"}, // removes _to... for abi functions
 | ||||
| 		{std::regex("(stringliteral_?[0-9a-f][0-9a-f][0-9a-f][0-9a-f])[0-9a-f]*"), "$1"}, // shorten string literal
 | ||||
| 		{std::regex("tuple_"), ""}, | ||||
| 		{std::regex("_memory_ptr"), ""}, | ||||
| 		{std::regex("_calldata_ptr"), "_calldata"}, | ||||
| 		{std::regex("_fromStack"), ""}, | ||||
| 		{std::regex("_storage_storage"), "_storage"}, | ||||
| 		{std::regex("(storage.*)_?storage"), "$1"}, | ||||
| 		{std::regex("_memory_memory"), "_memory"}, | ||||
| 		{std::regex("_contract\\$_([^_]*)_?"), "$1_"}, | ||||
| 		{std::regex("index_access_(t_)?array"), "index_access"}, | ||||
| 		{std::regex("[0-9]*_$"), ""} | ||||
| 	}; | ||||
| 
 | ||||
| 	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))) | ||||
| 			name = candidate; | ||||
| 	} | ||||
|  | ||||
| @ -31,7 +31,6 @@ | ||||
| 
 | ||||
| #include <range/v3/action/remove_if.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::langutil; | ||||
| using namespace solidity::util; | ||||
| @ -40,7 +39,7 @@ using namespace solidity::yul; | ||||
| void yul::removeEmptyBlocks(Block& _block) | ||||
| { | ||||
| 	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); | ||||
| } | ||||
| @ -50,12 +49,12 @@ bool yul::isRestrictedIdentifier(Dialect const& _dialect, YulString const& _iden | ||||
| 	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 (BuiltinFunctionForEVM const* builtin = dialect->builtin(_name)) | ||||
| 			return builtin->instruction; | ||||
| 	return nullopt; | ||||
| 	return std::nullopt; | ||||
| } | ||||
| 
 | ||||
| langutil::EVMVersion const yul::evmVersionFromDialect(Dialect const& _dialect) | ||||
| @ -69,12 +68,12 @@ void StatementRemover::operator()(Block& _block) | ||||
| { | ||||
| 	util::iterateReplacing( | ||||
| 		_block.statements, | ||||
| 		[&](Statement& _statement) -> std::optional<vector<Statement>> | ||||
| 		[&](Statement& _statement) -> std::optional<std::vector<Statement>> | ||||
| 		{ | ||||
| 			if (m_toRemove.count(&_statement)) | ||||
| 				return {vector<Statement>{}}; | ||||
| 				return {std::vector<Statement>{}}; | ||||
| 			else | ||||
| 				return nullopt; | ||||
| 				return std::nullopt; | ||||
| 		} | ||||
| 	); | ||||
| 	ASTModifier::operator()(_block); | ||||
|  | ||||
| @ -28,11 +28,10 @@ | ||||
| 
 | ||||
| #include <range/v3/algorithm/all_of.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| 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); | ||||
| } | ||||
| @ -40,7 +39,7 @@ void Rematerialiser::run(Dialect const& _dialect, Block& _ast, set<YulString> _v | ||||
| Rematerialiser::Rematerialiser( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block& _ast, | ||||
| 	set<YulString> _varsToAlwaysRematerialize, | ||||
| 	std::set<YulString> _varsToAlwaysRematerialize, | ||||
| 	bool _onlySelectedVariables | ||||
| ): | ||||
| 	DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore), | ||||
| @ -52,7 +51,7 @@ Rematerialiser::Rematerialiser( | ||||
| 
 | ||||
| void Rematerialiser::visit(Expression& _e) | ||||
| { | ||||
| 	if (holds_alternative<Identifier>(_e)) | ||||
| 	if (std::holds_alternative<Identifier>(_e)) | ||||
| 	{ | ||||
| 		Identifier& identifier = std::get<Identifier>(_e); | ||||
| 		YulString name = identifier.name; | ||||
| @ -91,14 +90,14 @@ void Rematerialiser::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); | ||||
| 		YulString name = identifier.name; | ||||
| 		if (AssignedValue const* value = variableValue(name)) | ||||
| 		{ | ||||
| 			assertThrow(value->value, OptimizerException, ""); | ||||
| 			if (holds_alternative<Literal>(*value->value)) | ||||
| 			if (std::holds_alternative<Literal>(*value->value)) | ||||
| 				_e = *value->value; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -22,7 +22,6 @@ | ||||
| 
 | ||||
| #include <variant> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -38,7 +37,7 @@ void SSAReverser::operator()(Block& _block) | ||||
| 	walkVector(_block.statements); | ||||
| 	util::iterateReplacingWindow<2>( | ||||
| 		_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); | ||||
| 
 | ||||
|  | ||||
| @ -30,7 +30,6 @@ | ||||
| 
 | ||||
| #include <libyul/optimiser/TypeInfo.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::langutil; | ||||
| @ -47,7 +46,7 @@ class IntroduceSSA: public ASTModifier | ||||
| public: | ||||
| 	explicit IntroduceSSA( | ||||
| 		NameDispenser& _nameDispenser, | ||||
| 		set<YulString> const& _variablesToReplace, | ||||
| 		std::set<YulString> const& _variablesToReplace, | ||||
| 		TypeInfo& _typeInfo | ||||
| 	): | ||||
| 		m_nameDispenser(_nameDispenser), | ||||
| @ -59,7 +58,7 @@ public: | ||||
| 
 | ||||
| private: | ||||
| 	NameDispenser& m_nameDispenser; | ||||
| 	set<YulString> const& m_variablesToReplace; | ||||
| 	std::set<YulString> const& m_variablesToReplace; | ||||
| 	TypeInfo const& m_typeInfo; | ||||
| }; | ||||
| 
 | ||||
| @ -68,9 +67,9 @@ void IntroduceSSA::operator()(Block& _block) | ||||
| { | ||||
| 	util::iterateReplacing( | ||||
| 		_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); | ||||
| 				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, b := v" by "let a_1, b_1 := v  let a := a_1 let b := b_2"
 | ||||
| 				shared_ptr<DebugData const> debugData = varDecl.debugData; | ||||
| 				vector<Statement> statements; | ||||
| 				std::shared_ptr<DebugData const> debugData = varDecl.debugData; | ||||
| 				std::vector<Statement> statements; | ||||
| 				statements.emplace_back(VariableDeclaration{debugData, {}, std::move(varDecl.value)}); | ||||
| 				TypedNameList newVariables; | ||||
| 				for (auto const& var: varDecl.variables) | ||||
| @ -97,13 +96,13 @@ void IntroduceSSA::operator()(Block& _block) | ||||
| 					statements.emplace_back(VariableDeclaration{ | ||||
| 						debugData, | ||||
| 						{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); | ||||
| 				return { std::move(statements) }; | ||||
| 			} | ||||
| 			else if (holds_alternative<Assignment>(_s)) | ||||
| 			else if (std::holds_alternative<Assignment>(_s)) | ||||
| 			{ | ||||
| 				Assignment& assignment = std::get<Assignment>(_s); | ||||
| 				visit(*assignment.value); | ||||
| @ -113,7 +112,7 @@ void IntroduceSSA::operator()(Block& _block) | ||||
| 				// 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"
 | ||||
| 				std::shared_ptr<DebugData const> debugData = assignment.debugData; | ||||
| 				vector<Statement> statements; | ||||
| 				std::vector<Statement> statements; | ||||
| 				statements.emplace_back(VariableDeclaration{debugData, {}, std::move(assignment.value)}); | ||||
| 				TypedNameList newVariables; | ||||
| 				for (auto const& var: assignment.variableNames) | ||||
| @ -127,7 +126,7 @@ void IntroduceSSA::operator()(Block& _block) | ||||
| 					statements.emplace_back(Assignment{ | ||||
| 						debugData, | ||||
| 						{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); | ||||
| @ -149,7 +148,7 @@ class IntroduceControlFlowSSA: public ASTModifier | ||||
| public: | ||||
| 	explicit IntroduceControlFlowSSA( | ||||
| 		NameDispenser& _nameDispenser, | ||||
| 		set<YulString> const& _variablesToReplace, | ||||
| 		std::set<YulString> const& _variablesToReplace, | ||||
| 		TypeInfo const& _typeInfo | ||||
| 	): | ||||
| 		m_nameDispenser(_nameDispenser), | ||||
| @ -164,19 +163,19 @@ public: | ||||
| 
 | ||||
| private: | ||||
| 	NameDispenser& m_nameDispenser; | ||||
| 	set<YulString> const& m_variablesToReplace; | ||||
| 	std::set<YulString> const& m_variablesToReplace; | ||||
| 	/// 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<YulString> m_variablesToReassign; | ||||
| 	std::set<YulString> m_variablesToReassign; | ||||
| 	TypeInfo const& m_typeInfo; | ||||
| }; | ||||
| 
 | ||||
| void IntroduceControlFlowSSA::operator()(FunctionDefinition& _function) | ||||
| { | ||||
| 	set<YulString> varsInScope; | ||||
| 	std::set<YulString> varsInScope; | ||||
| 	std::swap(varsInScope, m_variablesInScope); | ||||
| 	set<YulString> toReassign; | ||||
| 	std::set<YulString> toReassign; | ||||
| 	std::swap(toReassign, m_variablesToReassign); | ||||
| 
 | ||||
| 	for (auto const& param: _function.parameters) | ||||
| @ -208,7 +207,7 @@ void IntroduceControlFlowSSA::operator()(Switch& _switch) | ||||
| { | ||||
| 	yulAssert(m_variablesToReassign.empty(), ""); | ||||
| 
 | ||||
| 	set<YulString> toReassign; | ||||
| 	std::set<YulString> toReassign; | ||||
| 	for (auto& c: _switch.cases) | ||||
| 	{ | ||||
| 		(*this)(c.body); | ||||
| @ -220,27 +219,27 @@ void IntroduceControlFlowSSA::operator()(Switch& _switch) | ||||
| 
 | ||||
| void IntroduceControlFlowSSA::operator()(Block& _block) | ||||
| { | ||||
| 	set<YulString> variablesDeclaredHere; | ||||
| 	set<YulString> assignedVariables; | ||||
| 	std::set<YulString> variablesDeclaredHere; | ||||
| 	std::set<YulString> assignedVariables; | ||||
| 
 | ||||
| 	util::iterateReplacing( | ||||
| 		_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) | ||||
| 			{ | ||||
| 				YulString newName = m_nameDispenser.newName(toReassign); | ||||
| 				toPrepend.emplace_back(VariableDeclaration{ | ||||
| 					debugDataOf(_s), | ||||
| 					{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); | ||||
| 			} | ||||
| 			m_variablesToReassign.clear(); | ||||
| 
 | ||||
| 			if (holds_alternative<VariableDeclaration>(_s)) | ||||
| 			if (std::holds_alternative<VariableDeclaration>(_s)) | ||||
| 			{ | ||||
| 				VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s); | ||||
| 				for (auto const& var: varDecl.variables) | ||||
| @ -250,7 +249,7 @@ void IntroduceControlFlowSSA::operator()(Block& _block) | ||||
| 						m_variablesInScope.insert(var.name); | ||||
| 					} | ||||
| 			} | ||||
| 			else if (holds_alternative<Assignment>(_s)) | ||||
| 			else if (std::holds_alternative<Assignment>(_s)) | ||||
| 			{ | ||||
| 				Assignment& assignment = std::get<Assignment>(_s); | ||||
| 				for (auto const& var: assignment.variableNames) | ||||
| @ -281,7 +280,7 @@ void IntroduceControlFlowSSA::operator()(Block& _block) | ||||
| class PropagateValues: public ASTModifier | ||||
| { | ||||
| public: | ||||
| 	explicit PropagateValues(set<YulString> const& _variablesToReplace): | ||||
| 	explicit PropagateValues(std::set<YulString> const& _variablesToReplace): | ||||
| 		m_variablesToReplace(_variablesToReplace) | ||||
| 	{ } | ||||
| 
 | ||||
| @ -294,9 +293,9 @@ public: | ||||
| private: | ||||
| 	/// 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.
 | ||||
| 	set<YulString> const& m_variablesToReplace; | ||||
| 	map<YulString, YulString> m_currentVariableValues; | ||||
| 	set<YulString> m_clearAtEndOfBlock; | ||||
| 	std::set<YulString> const& m_variablesToReplace; | ||||
| 	std::map<YulString, YulString> m_currentVariableValues; | ||||
| 	std::set<YulString> m_clearAtEndOfBlock; | ||||
| }; | ||||
| 
 | ||||
| void PropagateValues::operator()(Identifier& _identifier) | ||||
| @ -316,11 +315,11 @@ void PropagateValues::operator()(VariableDeclaration& _varDecl) | ||||
| 	if (m_variablesToReplace.count(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_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.
 | ||||
| 		YulString value = std::get<Identifier>(*_varDecl.value).name; | ||||
| @ -345,7 +344,7 @@ void PropagateValues::operator()(Assignment& _assignment) | ||||
| 	if (!m_variablesToReplace.count(name)) | ||||
| 		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_clearAtEndOfBlock.insert(name); | ||||
| } | ||||
| @ -364,7 +363,7 @@ void PropagateValues::operator()(ForLoop& _for) | ||||
| 
 | ||||
| void PropagateValues::operator()(Block& _block) | ||||
| { | ||||
| 	set<YulString> clearAtParentBlock = std::move(m_clearAtEndOfBlock); | ||||
| 	std::set<YulString> clearAtParentBlock = std::move(m_clearAtEndOfBlock); | ||||
| 	m_clearAtEndOfBlock.clear(); | ||||
| 
 | ||||
| 	ASTModifier::operator()(_block); | ||||
| @ -380,7 +379,7 @@ void PropagateValues::operator()(Block& _block) | ||||
| void SSATransform::run(OptimiserStepContext& _context, Block& _ast) | ||||
| { | ||||
| 	TypeInfo typeInfo(_context.dialect, _ast); | ||||
| 	set<YulString> assignedVariables = assignedVariableNames(_ast); | ||||
| 	std::set<YulString> assignedVariables = assignedVariableNames(_ast); | ||||
| 	IntroduceSSA{_context.dispenser, assignedVariables, typeInfo}(_ast); | ||||
| 	IntroduceControlFlowSSA{_context.dispenser, assignedVariables, typeInfo}(_ast); | ||||
| 	PropagateValues{assignedVariables}(_ast); | ||||
|  | ||||
| @ -24,7 +24,6 @@ | ||||
| 
 | ||||
| #include <libyul/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -50,11 +49,11 @@ void SSAValueTracker::operator()(VariableDeclaration const& _varDecl) | ||||
| 		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; | ||||
| 	t(_ast); | ||||
| 	set<YulString> ssaVars; | ||||
| 	std::set<YulString> ssaVars; | ||||
| 	for (auto const& value: t.values()) | ||||
| 		ssaVars.insert(value.first); | ||||
| 	return ssaVars; | ||||
|  | ||||
| @ -33,7 +33,6 @@ | ||||
| 
 | ||||
| #include <limits> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -41,7 +40,7 @@ using namespace solidity::yul; | ||||
| SideEffectsCollector::SideEffectsCollector( | ||||
| 		Dialect const& _dialect, | ||||
| 		Expression const& _expression, | ||||
| 		map<YulString, SideEffects> const* _functionSideEffects | ||||
| 		std::map<YulString, SideEffects> const* _functionSideEffects | ||||
| ): | ||||
| 	SideEffectsCollector(_dialect, _functionSideEffects) | ||||
| { | ||||
| @ -57,7 +56,7 @@ SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Statement co | ||||
| SideEffectsCollector::SideEffectsCollector( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block const& _ast, | ||||
| 	map<YulString, SideEffects> const* _functionSideEffects | ||||
| 	std::map<YulString, SideEffects> const* _functionSideEffects | ||||
| ): | ||||
| 	SideEffectsCollector(_dialect, _functionSideEffects) | ||||
| { | ||||
| @ -67,7 +66,7 @@ SideEffectsCollector::SideEffectsCollector( | ||||
| SideEffectsCollector::SideEffectsCollector( | ||||
| 	Dialect const& _dialect, | ||||
| 	ForLoop const& _ast, | ||||
| 	map<YulString, SideEffects> const* _functionSideEffects | ||||
| 	std::map<YulString, SideEffects> const* _functionSideEffects | ||||
| ): | ||||
| 	SideEffectsCollector(_dialect, _functionSideEffects) | ||||
| { | ||||
| @ -99,7 +98,7 @@ bool MSizeFinder::containsMSize(Dialect const& _dialect, Object const& _object) | ||||
| 	if (containsMSize(_dialect, *_object.code)) | ||||
| 		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 (containsMSize(_dialect, *object)) | ||||
| 				return true; | ||||
| @ -116,7 +115,7 @@ void MSizeFinder::operator()(FunctionCall const& _functionCall) | ||||
| 			m_msizeFound = true; | ||||
| } | ||||
| 
 | ||||
| map<YulString, SideEffects> SideEffectsPropagator::sideEffects( | ||||
| std::map<YulString, SideEffects> SideEffectsPropagator::sideEffects( | ||||
| 	Dialect const& _dialect, | ||||
| 	CallGraph const& _directCallGraph | ||||
| ) | ||||
| @ -127,7 +126,7 @@ map<YulString, SideEffects> SideEffectsPropagator::sideEffects( | ||||
| 	// In the future, we should refine that, because the property
 | ||||
| 	// 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()) | ||||
| 	{ | ||||
| 		ret[function].movable = false; | ||||
| @ -179,8 +178,8 @@ void MovableChecker::visit(Statement const&) | ||||
| 	assertThrow(false, OptimizerException, "Movability for statement requested."); | ||||
| } | ||||
| 
 | ||||
| pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUnconditionalControlFlowChange( | ||||
| 	vector<Statement> const& _statements | ||||
| std::pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUnconditionalControlFlowChange( | ||||
| 	std::vector<Statement> const& _statements | ||||
| ) | ||||
| { | ||||
| 	for (size_t i = 0; i < _statements.size(); ++i) | ||||
| @ -189,32 +188,32 @@ pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUncondition | ||||
| 		if (controlFlow != ControlFlow::FlowOut) | ||||
| 			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) | ||||
| { | ||||
| 	if ( | ||||
| 		holds_alternative<VariableDeclaration>(_statement) && | ||||
| 		std::holds_alternative<VariableDeclaration>(_statement) && | ||||
| 		std::get<VariableDeclaration>(_statement).value && | ||||
| 		containsNonContinuingFunctionCall(*std::get<VariableDeclaration>(_statement).value) | ||||
| 	) | ||||
| 		return ControlFlow::Terminate; | ||||
| 	else if ( | ||||
| 		holds_alternative<Assignment>(_statement) && | ||||
| 		std::holds_alternative<Assignment>(_statement) && | ||||
| 		containsNonContinuingFunctionCall(*std::get<Assignment>(_statement).value) | ||||
| 	) | ||||
| 		return ControlFlow::Terminate; | ||||
| 	else if ( | ||||
| 		holds_alternative<ExpressionStatement>(_statement) && | ||||
| 		std::holds_alternative<ExpressionStatement>(_statement) && | ||||
| 		containsNonContinuingFunctionCall(std::get<ExpressionStatement>(_statement).expression) | ||||
| 	) | ||||
| 		return ControlFlow::Terminate; | ||||
| 	else if (holds_alternative<Break>(_statement)) | ||||
| 	else if (std::holds_alternative<Break>(_statement)) | ||||
| 		return ControlFlow::Break; | ||||
| 	else if (holds_alternative<Continue>(_statement)) | ||||
| 	else if (std::holds_alternative<Continue>(_statement)) | ||||
| 		return ControlFlow::Continue; | ||||
| 	else if (holds_alternative<Leave>(_statement)) | ||||
| 	else if (std::holds_alternative<Leave>(_statement)) | ||||
| 		return ControlFlow::Leave; | ||||
| 	else | ||||
| 		return ControlFlow::FlowOut; | ||||
|  | ||||
| @ -32,7 +32,6 @@ | ||||
| #include <libevmasm/RuleList.h> | ||||
| #include <libsolutil/StringUtils.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::evmasm; | ||||
| using namespace solidity::langutil; | ||||
| @ -41,7 +40,7 @@ using namespace solidity::yul; | ||||
| SimplificationRules::Rule const* SimplificationRules::findFirstMatch( | ||||
| 	Expression const& _expr, | ||||
| 	Dialect const& _dialect, | ||||
| 	function<AssignedValue const*(YulString)> const& _ssaValues | ||||
| 	std::function<AssignedValue const*(YulString)> const& _ssaValues | ||||
| ) | ||||
| { | ||||
| 	auto instruction = instructionAndArguments(_dialect, _expr); | ||||
| @ -75,14 +74,14 @@ bool SimplificationRules::isInitialized() const | ||||
| 	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) | ||||
| { | ||||
| 	if (holds_alternative<FunctionCall>(_expr)) | ||||
| 	if (std::holds_alternative<FunctionCall>(_expr)) | ||||
| 		if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect)) | ||||
| 			if (auto const* builtin = dialect->builtin(std::get<FunctionCall>(_expr).functionName.name)) | ||||
| 				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 {}; | ||||
| } | ||||
| @ -122,14 +121,14 @@ SimplificationRules::SimplificationRules(std::optional<langutil::EVMVersion> _ev | ||||
| 	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_instruction(_instruction), | ||||
| 	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_matchGroups = &_matchGroups; | ||||
| @ -138,14 +137,14 @@ void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _ | ||||
| bool Pattern::matches( | ||||
| 	Expression const& _expr, | ||||
| 	Dialect const& _dialect, | ||||
| 	function<AssignedValue const*(YulString)> const& _ssaValues | ||||
| 	std::function<AssignedValue const*(YulString)> const& _ssaValues | ||||
| ) const | ||||
| { | ||||
| 	Expression const* expr = &_expr; | ||||
| 
 | ||||
| 	// Resolve the variable if possible.
 | ||||
| 	// 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; | ||||
| 		if (AssignedValue const* value = _ssaValues(varName)) | ||||
| @ -156,7 +155,7 @@ bool Pattern::matches( | ||||
| 
 | ||||
| 	if (m_kind == PatternKind::Constant) | ||||
| 	{ | ||||
| 		if (!holds_alternative<Literal>(*expr)) | ||||
| 		if (!std::holds_alternative<Literal>(*expr)) | ||||
| 			return false; | ||||
| 		Literal const& literal = std::get<Literal>(*expr); | ||||
| 		if (literal.kind != LiteralKind::Number) | ||||
| @ -178,7 +177,7 @@ bool Pattern::matches( | ||||
| 			// we reject the match because side-effects could prevent us from
 | ||||
| 			// arbitrarily modifying the code.
 | ||||
| 			if ( | ||||
| 				holds_alternative<FunctionCall>(arg) || | ||||
| 				std::holds_alternative<FunctionCall>(arg) || | ||||
| 				!m_arguments[i].matches(arg, _dialect, _ssaValues) | ||||
| 			) | ||||
| 				return false; | ||||
| @ -187,7 +186,7 @@ bool Pattern::matches( | ||||
| 	else | ||||
| 	{ | ||||
| 		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) | ||||
| @ -209,8 +208,8 @@ bool Pattern::matches( | ||||
| 			Expression const* firstMatch = (*m_matchGroups)[m_matchGroup]; | ||||
| 			assertThrow(firstMatch, OptimizerException, "Match set but to null."); | ||||
| 			assertThrow( | ||||
| 				!holds_alternative<FunctionCall>(_expr) && | ||||
| 				!holds_alternative<FunctionCall>(*firstMatch), | ||||
| 				!std::holds_alternative<FunctionCall>(_expr) && | ||||
| 				!std::holds_alternative<FunctionCall>(*firstMatch), | ||||
| 				OptimizerException, | ||||
| 				"Group matches have to be literals or variables." | ||||
| 			); | ||||
| @ -235,7 +234,7 @@ evmasm::Instruction Pattern::instruction() const | ||||
| 	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()) | ||||
| 		return ASTCopier().translate(matchGroupValue()); | ||||
| @ -246,11 +245,11 @@ Expression Pattern::toExpression(shared_ptr<DebugData const> const& _debugData, | ||||
| 	} | ||||
| 	else if (m_kind == PatternKind::Operation) | ||||
| 	{ | ||||
| 		vector<Expression> arguments; | ||||
| 		std::vector<Expression> arguments; | ||||
| 		for (auto const& arg: m_arguments) | ||||
| 			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, | ||||
| 			Identifier{_debugData, YulString{name}}, | ||||
|  | ||||
| @ -40,7 +40,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| 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
 | ||||
| 	/// and variables that occur in their expression.
 | ||||
| 	/// 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) | ||||
| 		{ | ||||
| 			if (size_t const* cost = util::valueOrNullptr(m_expressionCodeCost, candidate)) | ||||
| @ -110,7 +109,7 @@ public: | ||||
| 	// get called on left-hand-sides of assignments.
 | ||||
| 	void visit(Expression& _e) override | ||||
| 	{ | ||||
| 		if (holds_alternative<Identifier>(_e)) | ||||
| 		if (std::holds_alternative<Identifier>(_e)) | ||||
| 		{ | ||||
| 			YulString name = std::get<Identifier>(_e).name; | ||||
| 			if (m_expressionCodeCost.count(name)) | ||||
| @ -134,20 +133,20 @@ public: | ||||
| 	YulString m_currentFunctionName = {}; | ||||
| 
 | ||||
| 	/// 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.
 | ||||
| 	map<YulString, size_t> m_expressionCodeCost; | ||||
| 	std::map<YulString, size_t> m_expressionCodeCost; | ||||
| 	/// 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.
 | ||||
| set<YulString> chooseVarsToEliminate( | ||||
| 	map<size_t, vector<YulString>> const& _candidates, | ||||
| std::set<YulString> chooseVarsToEliminate( | ||||
| 	std::map<size_t, std::vector<YulString>> const& _candidates, | ||||
| 	size_t _numVariables | ||||
| ) | ||||
| { | ||||
| 	set<YulString> varsToEliminate; | ||||
| 	std::set<YulString> varsToEliminate; | ||||
| 	for (auto&& [cost, candidates]: _candidates) | ||||
| 		for (auto&& candidate: candidates) | ||||
| 		{ | ||||
| @ -161,15 +160,15 @@ set<YulString> chooseVarsToEliminate( | ||||
| void eliminateVariables( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block& _ast, | ||||
| 	map<YulString, int> const& _numVariables, | ||||
| 	std::map<YulString, int> const& _numVariables, | ||||
| 	bool _allowMSizeOptimization | ||||
| ) | ||||
| { | ||||
| 	RematCandidateSelector selector{_dialect}; | ||||
| 	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) | ||||
| 	{ | ||||
| 		yulAssert(numVariables > 0); | ||||
| @ -178,14 +177,14 @@ void eliminateVariables( | ||||
| 
 | ||||
| 	Rematerialiser::run(_dialect, _ast, std::move(varsToEliminate)); | ||||
| 	// 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); | ||||
| } | ||||
| 
 | ||||
| void eliminateVariablesOptimizedCodegen( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block& _ast, | ||||
| 	map<YulString, vector<StackLayoutGenerator::StackTooDeep>> const& _unreachables, | ||||
| 	std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> const& _unreachables, | ||||
| 	bool _allowMSizeOptimization | ||||
| ) | ||||
| { | ||||
| @ -195,19 +194,19 @@ void eliminateVariablesOptimizedCodegen( | ||||
| 	RematCandidateSelector selector{_dialect}; | ||||
| 	selector(_ast); | ||||
| 
 | ||||
| 	map<YulString, size_t> candidates; | ||||
| 	std::map<YulString, size_t> candidates; | ||||
| 	for (auto const& [functionName, candidatesInFunction]: selector.candidates()) | ||||
| 		for (auto [cost, candidatesWithCost]: candidatesInFunction) | ||||
| 			for (auto candidate: candidatesWithCost) | ||||
| 				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.
 | ||||
| 	for (auto const& [functionName, unreachables]: _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; | ||||
| 			for (auto varName: unreachable.variableChoices) | ||||
| 			{ | ||||
| @ -230,7 +229,7 @@ void eliminateVariablesOptimizedCodegen( | ||||
| 		} | ||||
| 	Rematerialiser::run(_dialect, _ast, std::move(varsToEliminate), true); | ||||
| 	// 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); | ||||
| } | ||||
| 
 | ||||
| @ -245,7 +244,7 @@ bool StackCompressor::run( | ||||
| { | ||||
| 	yulAssert( | ||||
| 		_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." | ||||
| 	); | ||||
| 	bool usesOptimizedCodeGenerator = false; | ||||
| @ -258,7 +257,7 @@ bool StackCompressor::run( | ||||
| 	if (usesOptimizedCodeGenerator) | ||||
| 	{ | ||||
| 		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( | ||||
| 			_dialect, | ||||
| 			*_object.code, | ||||
| @ -269,7 +268,7 @@ bool StackCompressor::run( | ||||
| 	else | ||||
| 		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()) | ||||
| 				return true; | ||||
| 			eliminateVariables( | ||||
|  | ||||
| @ -36,7 +36,6 @@ | ||||
| #include <range/v3/view/concat.hpp> | ||||
| #include <range/v3/view/take.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -97,16 +96,16 @@ struct MemoryOffsetAllocator | ||||
| 
 | ||||
| 	/// 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.
 | ||||
| 	map<YulString, vector<YulString>> const& unreachableVariables; | ||||
| 	std::map<YulString, std::vector<YulString>> const& unreachableVariables; | ||||
| 	/// 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.
 | ||||
| 	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.
 | ||||
| 	map<YulString, uint64_t> slotAllocations{}; | ||||
| 	std::map<YulString, uint64_t> slotAllocations{}; | ||||
| 	/// 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) | ||||
| @ -131,7 +130,7 @@ void StackLimitEvader::run( | ||||
| 	if (evmDialect && evmDialect->evmVersion().canOverchargeGasForCall()) | ||||
| 	{ | ||||
| 		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)); | ||||
| 	} | ||||
| 	else | ||||
| @ -146,10 +145,10 @@ void StackLimitEvader::run( | ||||
| void StackLimitEvader::run( | ||||
| 	OptimiserStepContext& _context, | ||||
| 	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) | ||||
| 	{ | ||||
| 		auto& unreachables = unreachableVariables[function]; | ||||
| @ -165,7 +164,7 @@ void StackLimitEvader::run( | ||||
| void StackLimitEvader::run( | ||||
| 	OptimiserStepContext& _context, | ||||
| 	Object& _object, | ||||
| 	map<YulString, vector<YulString>> const& _unreachableVariables | ||||
| 	std::map<YulString, std::vector<YulString>> const& _unreachableVariables | ||||
| ) | ||||
| { | ||||
| 	yulAssert(_object.code, ""); | ||||
| @ -175,7 +174,7 @@ void StackLimitEvader::run( | ||||
| 		"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, | ||||
| 		"memoryguard"_yulstring | ||||
| 	); | ||||
| @ -198,7 +197,7 @@ void StackLimitEvader::run( | ||||
| 		if (_unreachableVariables.count(function)) | ||||
| 			return; | ||||
| 
 | ||||
| 	map<YulString, FunctionDefinition const*> functionDefinitions = allFunctionDefinitions(*_object.code); | ||||
| 	std::map<YulString, FunctionDefinition const*> functionDefinitions = allFunctionDefinitions(*_object.code); | ||||
| 
 | ||||
| 	MemoryOffsetAllocator memoryOffsetAllocator{_unreachableVariables, callGraph.functionCalls, functionDefinitions}; | ||||
| 	uint64_t requiredSlots = memoryOffsetAllocator.run(); | ||||
|  | ||||
| @ -29,22 +29,21 @@ | ||||
| #include <range/v3/view/zip.hpp> | ||||
| #include <range/v3/range/conversion.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| vector<Statement> generateMemoryStore( | ||||
| std::vector<Statement> generateMemoryStore( | ||||
| 	Dialect const& _dialect, | ||||
| 	shared_ptr<DebugData const> const& _debugData, | ||||
| 	std::shared_ptr<DebugData const> const& _debugData, | ||||
| 	YulString _mpos, | ||||
| 	Expression _value | ||||
| ) | ||||
| { | ||||
| 	BuiltinFunction const* memoryStoreFunction = _dialect.memoryStoreFunction(_dialect.defaultType); | ||||
| 	yulAssert(memoryStoreFunction, ""); | ||||
| 	vector<Statement> result; | ||||
| 	std::vector<Statement> result; | ||||
| 	result.emplace_back(ExpressionStatement{_debugData, FunctionCall{ | ||||
| 		_debugData, | ||||
| 		Identifier{_debugData, memoryStoreFunction->name}, | ||||
| @ -77,7 +76,7 @@ FunctionCall generateMemoryLoad(Dialect const& _dialect, std::shared_ptr<DebugDa | ||||
| void StackToMemoryMover::run( | ||||
| 	OptimiserStepContext& _context, | ||||
| 	u256 _reservedMemory, | ||||
| 	map<YulString, uint64_t> const& _memorySlots, | ||||
| 	std::map<YulString, uint64_t> const& _memorySlots, | ||||
| 	uint64_t _numRequiredSlots, | ||||
| 	Block& _block | ||||
| ) | ||||
| @ -91,7 +90,7 @@ void StackToMemoryMover::run( | ||||
| 			util::mapTuple([](YulString _name, FunctionDefinition const* _funDef) { | ||||
| 				return make_pair(_name, _funDef->returnVariables); | ||||
| 			}), | ||||
| 			map<YulString, TypedNameList>{} | ||||
| 			std::map<YulString, TypedNameList>{} | ||||
| 		) | ||||
| 	); | ||||
| 	stackToMemoryMover(_block); | ||||
| @ -101,7 +100,7 @@ void StackToMemoryMover::run( | ||||
| StackToMemoryMover::StackToMemoryMover( | ||||
| 	OptimiserStepContext& _context, | ||||
| 	VariableMemoryOffsetTracker const& _memoryOffsetTracker, | ||||
| 	map<YulString, TypedNameList> _functionReturnVariables | ||||
| 	std::map<YulString, TypedNameList> _functionReturnVariables | ||||
| ): | ||||
| m_context(_context), | ||||
| m_memoryOffsetTracker(_memoryOffsetTracker), | ||||
| @ -121,7 +120,7 @@ void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition) | ||||
| 	// variable arguments we might generate below.
 | ||||
| 	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.
 | ||||
| 	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)) | ||||
| 	{ | ||||
| 		TypedNameList stackParameters = _functionDefinition.parameters | ranges::views::filter( | ||||
| 			not_fn(m_memoryOffsetTracker) | ||||
| 			std::not_fn(m_memoryOffsetTracker) | ||||
| 		) | ranges::to<TypedNameList>; | ||||
| 		// Generate new function without return variable and with only the non-moved parameters.
 | ||||
| 		YulString newFunctionName = m_context.dispenser.newName(_functionDefinition.name); | ||||
| @ -173,13 +172,13 @@ void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition) | ||||
| 				Identifier{_functionDefinition.debugData, newFunctionName}, | ||||
| 				stackParameters | ranges::views::transform([&](TypedName const& _arg) { | ||||
| 					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.debugData, | ||||
| 			{Identifier{_functionDefinition.debugData, _functionDefinition.returnVariables.front().name}}, | ||||
| 			make_unique<Expression>(generateMemoryLoad( | ||||
| 			std::make_unique<Expression>(generateMemoryLoad( | ||||
| 				m_context.dialect, | ||||
| 				_functionDefinition.debugData, | ||||
| 				*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.returnVariables = _functionDefinition.returnVariables | ranges::views::filter( | ||||
| 		not_fn(m_memoryOffsetTracker) | ||||
| 		std::not_fn(m_memoryOffsetTracker) | ||||
| 	) | ranges::to<TypedNameList>; | ||||
| } | ||||
| 
 | ||||
| void StackToMemoryMover::operator()(Block& _block) | ||||
| { | ||||
| 	using OptionalStatements = optional<vector<Statement>>; | ||||
| 	using OptionalStatements = std::optional<std::vector<Statement>>; | ||||
| 
 | ||||
| 	auto rewriteAssignmentOrVariableDeclarationLeftHandSide = [this]( | ||||
| 		auto& _stmt, | ||||
| 		auto& _lhsVars | ||||
| 	) -> OptionalStatements { | ||||
| 		using StatementType = decay_t<decltype(_stmt)>; | ||||
| 		using StatementType = std::decay_t<decltype(_stmt)>; | ||||
| 
 | ||||
| 		auto debugData = _stmt.debugData; | ||||
| 		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( | ||||
| 					m_context.dialect, | ||||
| 					debugData, | ||||
| @ -219,48 +218,48 @@ void StackToMemoryMover::operator()(Block& _block) | ||||
| 			else | ||||
| 				return {}; | ||||
| 		} | ||||
| 		vector<optional<YulString>> rhsMemorySlots; | ||||
| 		std::vector<std::optional<YulString>> rhsMemorySlots; | ||||
| 		if (_stmt.value) | ||||
| 		{ | ||||
| 			FunctionCall const* functionCall = get_if<FunctionCall>(_stmt.value.get()); | ||||
| 			FunctionCall const* functionCall = std::get_if<FunctionCall>(_stmt.value.get()); | ||||
| 			yulAssert(functionCall, ""); | ||||
| 			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 | ||||
| 				rhsMemorySlots = | ||||
| 					m_functionReturnVariables.at(functionCall->functionName.name) | | ||||
| 					ranges::views::transform(m_memoryOffsetTracker) | | ||||
| 					ranges::to<vector<optional<YulString>>>; | ||||
| 					ranges::to<std::vector<std::optional<YulString>>>; | ||||
| 		} | ||||
| 		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
 | ||||
| 		// none of the variables in the left-hand-side are moved.
 | ||||
| 		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) | ||||
| 		) | ||||
| 			return {}; | ||||
| 
 | ||||
| 		vector<Statement> memoryAssignments; | ||||
| 		vector<Statement> variableAssignments; | ||||
| 		std::vector<Statement> memoryAssignments; | ||||
| 		std::vector<Statement> variableAssignments; | ||||
| 		VariableDeclaration tempDecl{debugData, {}, std::move(_stmt.value)}; | ||||
| 
 | ||||
| 		yulAssert(rhsMemorySlots.size() == _lhsVars.size(), ""); | ||||
| 		for (auto&& [lhsVar, rhsSlot]: ranges::views::zip(_lhsVars, rhsMemorySlots)) | ||||
| 		{ | ||||
| 			unique_ptr<Expression> rhs; | ||||
| 			std::unique_ptr<Expression> rhs; | ||||
| 			if (rhsSlot) | ||||
| 				rhs = make_unique<Expression>(generateMemoryLoad(m_context.dialect, debugData, *rhsSlot)); | ||||
| 				rhs = std::make_unique<Expression>(generateMemoryLoad(m_context.dialect, debugData, *rhsSlot)); | ||||
| 			else | ||||
| 			{ | ||||
| 				YulString tempVarName = m_nameDispenser.newName(lhsVar.name); | ||||
| 				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( | ||||
| 					m_context.dialect, | ||||
| 					_stmt.debugData, | ||||
| @ -275,7 +274,7 @@ void StackToMemoryMover::operator()(Block& _block) | ||||
| 				}); | ||||
| 		} | ||||
| 
 | ||||
| 		vector<Statement> result; | ||||
| 		std::vector<Statement> result; | ||||
| 		if (tempDecl.variables.empty()) | ||||
| 			result.emplace_back(ExpressionStatement{debugData, *std::move(tempDecl.value)}); | ||||
| 		else | ||||
| @ -292,9 +291,9 @@ void StackToMemoryMover::operator()(Block& _block) | ||||
| 		[&](Statement& _statement) -> OptionalStatements | ||||
| 		{ | ||||
| 			visit(_statement); | ||||
| 			if (auto* assignment = get_if<Assignment>(&_statement)) | ||||
| 			if (auto* assignment = std::get_if<Assignment>(&_statement)) | ||||
| 				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 {}; | ||||
| 		} | ||||
| @ -304,12 +303,12 @@ void StackToMemoryMover::operator()(Block& _block) | ||||
| void StackToMemoryMover::visit(Expression& _expression) | ||||
| { | ||||
| 	ASTModifier::visit(_expression); | ||||
| 	if (Identifier* identifier = get_if<Identifier>(&_expression)) | ||||
| 		if (optional<YulString> offset = m_memoryOffsetTracker(identifier->name)) | ||||
| 	if (Identifier* identifier = std::get_if<Identifier>(&_expression)) | ||||
| 		if (std::optional<YulString> offset = m_memoryOffsetTracker(identifier->name)) | ||||
| 			_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)) | ||||
| 	{ | ||||
| @ -318,15 +317,15 @@ optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()( | ||||
| 		return YulString{toCompactHexWithPrefix(m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1))}; | ||||
| 	} | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(Identifier const& _variable) const | ||||
| std::optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(Identifier const& _variable) const | ||||
| { | ||||
| 	return (*this)(_variable.name); | ||||
| } | ||||
|  | ||||
| @ -21,11 +21,10 @@ | ||||
| #include <libsolutil/CommonData.h> | ||||
| #include <libsolutil/Visitor.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| using OptionalStatements = std::optional<vector<Statement>>; | ||||
| using OptionalStatements = std::optional<std::vector<Statement>>; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| @ -52,12 +51,12 @@ OptionalStatements replaceConstArgSwitch(Switch& _switchStmt, u256 const& _const | ||||
| 	if (matchingCaseBlock) | ||||
| 		return util::make_vector<Statement>(std::move(*matchingCaseBlock)); | ||||
| 	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)); | ||||
| 	else | ||||
| 		return std::optional<u256>(); | ||||
| @ -99,7 +98,7 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements) | ||||
| 			if (expressionAlwaysTrue(*_ifStmt.condition)) | ||||
| 				return {std::move(_ifStmt.body.statements)}; | ||||
| 			else if (expressionAlwaysFalse(*_ifStmt.condition)) | ||||
| 				return {vector<Statement>{}}; | ||||
| 				return {std::vector<Statement>{}}; | ||||
| 			return {}; | ||||
| 		}, | ||||
| 		[&](Switch& _switchStmt) -> OptionalStatements { | ||||
|  | ||||
| @ -23,13 +23,12 @@ | ||||
| 
 | ||||
| #include <libyul/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| Expression Substitution::translate(Expression const& _expression) | ||||
| { | ||||
| 	if (holds_alternative<Identifier>(_expression)) | ||||
| 	if (std::holds_alternative<Identifier>(_expression)) | ||||
| 	{ | ||||
| 		YulString name = std::get<Identifier>(_expression).name; | ||||
| 		if (m_substitutions.count(name)) | ||||
|  | ||||
| @ -86,12 +86,12 @@ | ||||
| #include <fmt/format.h> | ||||
| #endif | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| #ifdef PROFILE_OPTIMIZER_STEPS | ||||
| using namespace std::chrono; | ||||
| #endif | ||||
| using namespace std::string_literals; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| @ -136,10 +136,10 @@ void OptimiserSuite::run( | ||||
| 	GasMeter const* _meter, | ||||
| 	Object& _object, | ||||
| 	bool _optimizeStackAllocation, | ||||
| 	string_view _optimisationSequence, | ||||
| 	string_view _optimisationCleanupSequence, | ||||
| 	optional<size_t> _expectedExecutionsPerDeployment, | ||||
| 	set<YulString> const& _externallyUsedIdentifiers | ||||
| 	std::string_view _optimisationSequence, | ||||
| 	std::string_view _optimisationCleanupSequence, | ||||
| 	std::optional<size_t> _expectedExecutionsPerDeployment, | ||||
| 	std::set<YulString> const& _externallyUsedIdentifiers | ||||
| ) | ||||
| { | ||||
| 	EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect); | ||||
| @ -148,7 +148,7 @@ void OptimiserSuite::run( | ||||
| 		evmDialect && | ||||
| 		evmDialect->evmVersion().canOverchargeGasForCall() && | ||||
| 		evmDialect->providesObjectAccess(); | ||||
| 	set<YulString> reservedIdentifiers = _externallyUsedIdentifiers; | ||||
| 	std::set<YulString> reservedIdentifiers = _externallyUsedIdentifiers; | ||||
| 	reservedIdentifiers += _dialect.fixedFunctionNames(); | ||||
| 
 | ||||
| 	*_object.code = std::get<Block>(Disambiguator( | ||||
| @ -226,11 +226,11 @@ namespace | ||||
| { | ||||
| 
 | ||||
| template <class... Step> | ||||
| map<string, unique_ptr<OptimiserStep>> optimiserStepCollection() | ||||
| std::map<std::string, std::unique_ptr<OptimiserStep>> optimiserStepCollection() | ||||
| { | ||||
| 	map<string, unique_ptr<OptimiserStep>> ret; | ||||
| 	for (unique_ptr<OptimiserStep>& s: util::make_vector<unique_ptr<OptimiserStep>>( | ||||
| 		(make_unique<OptimiserStepInstance<Step>>())... | ||||
| 	std::map<std::string, std::unique_ptr<OptimiserStep>> ret; | ||||
| 	for (std::unique_ptr<OptimiserStep>& s: util::make_vector<std::unique_ptr<OptimiserStep>>( | ||||
| 		(std::make_unique<OptimiserStepInstance<Step>>())... | ||||
| 	)) | ||||
| 	{ | ||||
| 		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()) | ||||
| 		instance = optimiserStepCollection< | ||||
| 			BlockFlattener, | ||||
| @ -284,9 +284,9 @@ map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps() | ||||
| 	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'}, | ||||
| 		{CircularReferencesPruner::name,      'l'}, | ||||
| 		{CommonSubexpressionEliminator::name, 'c'}, | ||||
| @ -322,23 +322,23 @@ map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap() | ||||
| 	}; | ||||
| 	yulAssert(lookupTable.size() == allSteps().size(), ""); | ||||
| 	yulAssert(( | ||||
| 			util::convertContainer<set<char>>(string(NonStepAbbreviations)) - | ||||
| 			util::convertContainer<set<char>>(lookupTable | ranges::views::values) | ||||
| 		).size() == string(NonStepAbbreviations).size(), | ||||
| 			util::convertContainer<std::set<char>>(std::string(NonStepAbbreviations)) - | ||||
| 			util::convertContainer<std::set<char>>(lookupTable | ranges::views::values) | ||||
| 		).size() == std::string(NonStepAbbreviations).size(), | ||||
| 		"Step abbreviation conflicts with a character reserved for another syntactic element" | ||||
| 	); | ||||
| 
 | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| void OptimiserSuite::validateSequence(string_view _stepAbbreviations) | ||||
| void OptimiserSuite::validateSequence(std::string_view _stepAbbreviations) | ||||
| { | ||||
| 	int8_t nestingLevel = 0; | ||||
| 	int8_t colonDelimiters = 0; | ||||
| @ -349,7 +349,7 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations) | ||||
| 		case '\n': | ||||
| 			break; | ||||
| 		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++; | ||||
| 			break; | ||||
| 		case ']': | ||||
| @ -364,7 +364,7 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations) | ||||
| 		default: | ||||
| 		{ | ||||
| 			yulAssert( | ||||
| 				string(NonStepAbbreviations).find(abbreviation) == string::npos, | ||||
| 				std::string(NonStepAbbreviations).find(abbreviation) == std::string::npos, | ||||
| 				"Unhandled syntactic element in the abbreviation sequence" | ||||
| 			); | ||||
| 			assertThrow( | ||||
| @ -372,7 +372,7 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations) | ||||
| 				OptimizerException, | ||||
| 				"'"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( | ||||
| 				!invalid.has_value(), | ||||
| 				OptimizerException, | ||||
| @ -383,12 +383,12 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations) | ||||
| 	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); | ||||
| 
 | ||||
| 	// 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) | ||||
| 		{ | ||||
| @ -400,7 +400,7 @@ void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bo | ||||
| 	}; | ||||
| 
 | ||||
| 	// 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] == '['); | ||||
| 
 | ||||
| @ -410,7 +410,7 @@ void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bo | ||||
| 		{ | ||||
| 			if (abbreviation == '[') | ||||
| 			{ | ||||
| 				yulAssert(nestingLevel < numeric_limits<int8_t>::max()); | ||||
| 				yulAssert(nestingLevel < std::numeric_limits<int8_t>::max()); | ||||
| 				++nestingLevel; | ||||
| 			} | ||||
| 			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)}; | ||||
| 	}; | ||||
| 
 | ||||
| 	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) | ||||
| 			if (abbreviation != ' ' && abbreviation != '\n') | ||||
| 				steps.emplace_back(stepAbbreviationToNameMap().at(abbreviation)); | ||||
| 		return steps; | ||||
| 	}; | ||||
| 
 | ||||
| 	vector<tuple<string_view, bool>> subsequences; | ||||
| 	string_view tail = _stepAbbreviations; | ||||
| 	std::vector<std::tuple<std::string_view, bool>> subsequences; | ||||
| 	std::string_view tail = _stepAbbreviations; | ||||
| 	while (!tail.empty()) | ||||
| 	{ | ||||
| 		string_view subsequence; | ||||
| 		std::string_view subsequence; | ||||
| 		tie(subsequence, tail) = extractNonNestedPrefix(tail); | ||||
| 		if (subsequence.size() > 0) | ||||
| 			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) | ||||
| 		copy = make_unique<Block>(std::get<Block>(ASTCopier{}(_ast))); | ||||
| 	for (string const& step: _steps) | ||||
| 		copy = std::make_unique<Block>(std::get<Block>(ASTCopier{}(_ast))); | ||||
| 	for (std::string const& step: _steps) | ||||
| 	{ | ||||
| 		if (m_debug == Debug::PrintStep) | ||||
| 			cout << "Running " << step << endl; | ||||
| 			std::cout << "Running " << step << std::endl; | ||||
| #ifdef PROFILE_OPTIMIZER_STEPS | ||||
| 		steady_clock::time_point startTime = steady_clock::now(); | ||||
| #endif | ||||
| @ -495,12 +495,12 @@ void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast) | ||||
| 		{ | ||||
| 			// TODO should add switch to also compare variable names!
 | ||||
| 			if (SyntacticallyEqual{}.statementEqual(_ast, *copy)) | ||||
| 				cout << "== Running " << step << " did not cause changes." << endl; | ||||
| 				std::cout << "== Running " << step << " did not cause changes." << std::endl; | ||||
| 			else | ||||
| 			{ | ||||
| 				cout << "== Running " << step << " changed the AST." << endl; | ||||
| 				cout << AsmPrinter{}(_ast) << endl; | ||||
| 				copy = make_unique<Block>(std::get<Block>(ASTCopier{}(_ast))); | ||||
| 				std::cout << "== Running " << step << " changed the AST." << std::endl; | ||||
| 				std::cout << AsmPrinter{}(_ast) << std::endl; | ||||
| 				copy = std::make_unique<Block>(std::get<Block>(ASTCopier{}(_ast))); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -25,7 +25,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
|  | ||||
| @ -28,7 +28,6 @@ | ||||
| 
 | ||||
| #include <libsolutil/Visitor.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::util; | ||||
| 
 | ||||
| @ -81,7 +80,7 @@ YulString TypeInfo::typeOf(Expression const& _expression) const | ||||
| 	return std::visit(GenericVisitor{ | ||||
| 		[&](FunctionCall const& _funCall) { | ||||
| 			YulString name = _funCall.functionName.name; | ||||
| 			vector<YulString> const* retTypes = nullptr; | ||||
| 			std::vector<YulString> const* retTypes = nullptr; | ||||
| 			if (BuiltinFunction const* fun = m_dialect.builtin(name)) | ||||
| 				retTypes = &fun->returns; | ||||
| 			else | ||||
|  | ||||
| @ -34,7 +34,6 @@ | ||||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -48,7 +47,7 @@ void UnusedAssignEliminator::run(OptimiserStepContext& _context, Block& _ast) | ||||
| 
 | ||||
| 	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}; | ||||
| 	remover(_ast); | ||||
| } | ||||
| @ -103,7 +102,7 @@ void UnusedAssignEliminator::operator()(Block const& _block) | ||||
| 	UnusedStoreBase::operator()(_block); | ||||
| 
 | ||||
| 	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) | ||||
| 				m_activeStores.erase(var.name); | ||||
| } | ||||
| @ -112,7 +111,7 @@ void UnusedAssignEliminator::visit(Statement const& _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,
 | ||||
| 		// but clear the active stores to the assigned variables in any case.
 | ||||
|  | ||||
| @ -36,14 +36,13 @@ | ||||
| #include <optional> | ||||
| #include <variant> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::yul::unusedFunctionsCommon; | ||||
| 
 | ||||
| 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); }; | ||||
| 
 | ||||
| 	// 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
 | ||||
| 	// return parameter at index `i` in `FunctionDefinition::returnVariables` is unused inside
 | ||||
| 	// 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
 | ||||
| 	// return-parameters) are not used in its body.
 | ||||
| 	for (auto const& statement: _ast.statements) | ||||
| 		if (holds_alternative<FunctionDefinition>(statement)) | ||||
| 		if (std::holds_alternative<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
 | ||||
| 	// 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
 | ||||
| 	// 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() }`.
 | ||||
| 	iterateReplacing(_ast.statements, [&](Statement& _s) -> optional<vector<Statement>> { | ||||
| 		if (holds_alternative<FunctionDefinition>(_s)) | ||||
| 	iterateReplacing(_ast.statements, [&](Statement& _s) -> std::optional<std::vector<Statement>> { | ||||
| 		if (std::holds_alternative<FunctionDefinition>(_s)) | ||||
| 		{ | ||||
| 			// 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)) | ||||
| 			{ | ||||
| 
 | ||||
| 				YulString linkingFunctionName = originalFunction.name; | ||||
| 				YulString originalFunctionName = newToOriginalNames.at(linkingFunctionName); | ||||
| 				pair<vector<bool>, vector<bool>> used = | ||||
| 				std::pair<std::vector<bool>, std::vector<bool>> used = | ||||
| 					usedParametersAndReturnVariables.at(originalFunctionName); | ||||
| 
 | ||||
| 				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/SideEffects.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -44,8 +43,8 @@ UnusedPruner::UnusedPruner( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block& _ast, | ||||
| 	bool _allowMSizeOptimization, | ||||
| 	map<YulString, SideEffects> const* _functionSideEffects, | ||||
| 	set<YulString> const& _externallyUsedFunctions | ||||
| 	std::map<YulString, SideEffects> const* _functionSideEffects, | ||||
| 	std::set<YulString> const& _externallyUsedFunctions | ||||
| ): | ||||
| 	m_dialect(_dialect), | ||||
| 	m_allowMSizeOptimization(_allowMSizeOptimization), | ||||
| @ -60,7 +59,7 @@ UnusedPruner::UnusedPruner( | ||||
| 	Dialect const& _dialect, | ||||
| 	FunctionDefinition& _function, | ||||
| 	bool _allowMSizeOptimization, | ||||
| 	set<YulString> const& _externallyUsedFunctions | ||||
| 	std::set<YulString> const& _externallyUsedFunctions | ||||
| ): | ||||
| 	m_dialect(_dialect), | ||||
| 	m_allowMSizeOptimization(_allowMSizeOptimization) | ||||
| @ -73,7 +72,7 @@ UnusedPruner::UnusedPruner( | ||||
| void UnusedPruner::operator()(Block& _block) | ||||
| { | ||||
| 	for (auto&& statement: _block.statements) | ||||
| 		if (holds_alternative<FunctionDefinition>(statement)) | ||||
| 		if (std::holds_alternative<FunctionDefinition>(statement)) | ||||
| 		{ | ||||
| 			FunctionDefinition& funDef = std::get<FunctionDefinition>(statement); | ||||
| 			if (!used(funDef.name)) | ||||
| @ -82,7 +81,7 @@ void UnusedPruner::operator()(Block& _block) | ||||
| 				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); | ||||
| 			// 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); | ||||
| 			if ( | ||||
| @ -136,8 +135,8 @@ void UnusedPruner::runUntilStabilised( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block& _ast, | ||||
| 	bool _allowMSizeOptimization, | ||||
| 	map<YulString, SideEffects> const* _functionSideEffects, | ||||
| 	set<YulString> const& _externallyUsedFunctions | ||||
| 	std::map<YulString, SideEffects> const* _functionSideEffects, | ||||
| 	std::set<YulString> const& _externallyUsedFunctions | ||||
| ) | ||||
| { | ||||
| 	while (true) | ||||
| @ -154,10 +153,10 @@ void UnusedPruner::runUntilStabilised( | ||||
| void UnusedPruner::runUntilStabilisedOnFullAST( | ||||
| 	Dialect const& _dialect, | ||||
| 	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)); | ||||
| 	bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, _ast); | ||||
| 	runUntilStabilised(_dialect, _ast, allowMSizeOptimization, &functionSideEffects, _externallyUsedFunctions); | ||||
| @ -167,7 +166,7 @@ void UnusedPruner::runUntilStabilised( | ||||
| 	Dialect const& _dialect, | ||||
| 	FunctionDefinition& _function, | ||||
| 	bool _allowMSizeOptimization, | ||||
| 	set<YulString> const& _externallyUsedFunctions | ||||
| 	std::set<YulString> const& _externallyUsedFunctions | ||||
| ) | ||||
| { | ||||
| 	while (true) | ||||
| @ -184,7 +183,7 @@ bool UnusedPruner::used(YulString _name) const | ||||
| 	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) | ||||
| 	{ | ||||
|  | ||||
| @ -29,7 +29,6 @@ | ||||
| 
 | ||||
| #include <range/v3/action/remove_if.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -50,7 +49,7 @@ void UnusedStoreBase::operator()(Switch const& _switch) | ||||
| 	ActiveStores const preState{m_activeStores}; | ||||
| 
 | ||||
| 	bool hasDefault = false; | ||||
| 	vector<ActiveStores> branches; | ||||
| 	std::vector<ActiveStores> branches; | ||||
| 	for (auto const& c: _switch.cases) | ||||
| 	{ | ||||
| 		if (!c.value) | ||||
| @ -146,15 +145,15 @@ void UnusedStoreBase::operator()(Continue const&) | ||||
| void UnusedStoreBase::merge(ActiveStores& _target, ActiveStores&& _other) | ||||
| { | ||||
| 	util::joinMap(_target, std::move(_other), []( | ||||
| 		set<Statement const*>& _storesHere, | ||||
| 		set<Statement const*>&& _storesThere | ||||
| 		std::set<Statement const*>& _storesHere, | ||||
| 		std::set<Statement const*>&& _storesThere | ||||
| 	) | ||||
| 	{ | ||||
| 		_storesHere += _storesThere; | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| void UnusedStoreBase::merge(ActiveStores& _target, vector<ActiveStores>&& _source) | ||||
| void UnusedStoreBase::merge(ActiveStores& _target, std::vector<ActiveStores>&& _source) | ||||
| { | ||||
| 	for (ActiveStores& ts: _source) | ||||
| 		merge(_target, std::move(ts)); | ||||
|  | ||||
| @ -40,26 +40,25 @@ | ||||
| 
 | ||||
| #include <range/v3/algorithm/all_of.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| /// Variable names for special constants that can never appear in actual Yul code.
 | ||||
| static string const zero{"@ 0"}; | ||||
| static string const one{"@ 1"}; | ||||
| static string const thirtyTwo{"@ 32"}; | ||||
| static std::string const zero{"@ 0"}; | ||||
| static std::string const one{"@ 1"}; | ||||
| static std::string const thirtyTwo{"@ 32"}; | ||||
| 
 | ||||
| 
 | ||||
| void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast) | ||||
| { | ||||
| 	map<YulString, SideEffects> functionSideEffects = SideEffectsPropagator::sideEffects( | ||||
| 	std::map<YulString, SideEffects> functionSideEffects = SideEffectsPropagator::sideEffects( | ||||
| 		_context.dialect, | ||||
| 		CallGraphGenerator::callGraph(_ast) | ||||
| 	); | ||||
| 
 | ||||
| 	SSAValueTracker ssaValues; | ||||
| 	ssaValues(_ast); | ||||
| 	map<YulString, AssignedValue> values; | ||||
| 	std::map<YulString, AssignedValue> values; | ||||
| 	for (auto const& [name, expression]: ssaValues.values()) | ||||
| 		values[name] = AssignedValue{expression, {}}; | ||||
| 	Expression const zeroLiteral{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}}; | ||||
| @ -87,16 +86,16 @@ void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast) | ||||
| 	rse.markActiveAsUsed(Location::Storage); | ||||
| 	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}; | ||||
| 	remover(_ast); | ||||
| } | ||||
| 
 | ||||
| UnusedStoreEliminator::UnusedStoreEliminator( | ||||
| 	Dialect const& _dialect, | ||||
| 	map<YulString, SideEffects> const& _functionSideEffects, | ||||
| 	map<YulString, ControlFlowSideEffects> _controlFlowSideEffects, | ||||
| 	map<YulString, AssignedValue> const& _ssaValues, | ||||
| 	std::map<YulString, SideEffects> const& _functionSideEffects, | ||||
| 	std::map<YulString, ControlFlowSideEffects> _controlFlowSideEffects, | ||||
| 	std::map<YulString, AssignedValue> const& _ssaValues, | ||||
| 	bool _ignoreMemory | ||||
| ): | ||||
| 	UnusedStoreBase(_dialect), | ||||
| @ -148,18 +147,18 @@ void UnusedStoreEliminator::visit(Statement const& _statement) | ||||
| 
 | ||||
| 	UnusedStoreBase::visit(_statement); | ||||
| 
 | ||||
| 	auto const* exprStatement = get_if<ExpressionStatement>(&_statement); | ||||
| 	auto const* exprStatement = std::get_if<ExpressionStatement>(&_statement); | ||||
| 	if (!exprStatement) | ||||
| 		return; | ||||
| 
 | ||||
| 	FunctionCall const* funCall = get_if<FunctionCall>(&exprStatement->expression); | ||||
| 	FunctionCall const* funCall = std::get_if<FunctionCall>(&exprStatement->expression); | ||||
| 	yulAssert(funCall); | ||||
| 	optional<Instruction> instruction = toEVMInstruction(m_dialect, funCall->functionName.name); | ||||
| 	std::optional<Instruction> instruction = toEVMInstruction(m_dialect, funCall->functionName.name); | ||||
| 	if (!instruction) | ||||
| 		return; | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| @ -195,7 +194,7 @@ void UnusedStoreEliminator::visit(Statement const& _statement) | ||||
| 			auto length = identifierNameIfSSA(funCall->arguments.at(2)); | ||||
| 			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 ( | ||||
| 					m_knowledgeBase.knownToBeZero(*startOffset) && | ||||
| 					lengthCall && | ||||
| @ -207,7 +206,7 @@ void UnusedStoreEliminator::visit(Statement const& _statement) | ||||
| 				return; | ||||
| 		} | ||||
| 		m_allStores.insert(&_statement); | ||||
| 		vector<Operation> operations = operationsFromFunctionCall(*funCall); | ||||
| 		std::vector<Operation> operations = operationsFromFunctionCall(*funCall); | ||||
| 		yulAssert(operations.size() == 1, ""); | ||||
| 		if (operations.front().location == Location::Storage) | ||||
| 			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 | ||||
| ) const | ||||
| { | ||||
| @ -230,10 +229,10 @@ vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFu | ||||
| 	else | ||||
| 		sideEffects = m_functionSideEffects.at(functionName); | ||||
| 
 | ||||
| 	optional<Instruction> instruction = toEVMInstruction(m_dialect, functionName); | ||||
| 	std::optional<Instruction> instruction = toEVMInstruction(m_dialect, functionName); | ||||
| 	if (!instruction) | ||||
| 	{ | ||||
| 		vector<Operation> result; | ||||
| 		std::vector<Operation> result; | ||||
| 		// Unknown read is worse than unknown write.
 | ||||
| 		if (sideEffects.memory != SideEffects::Effect::None) | ||||
| 			result.emplace_back(Operation{Location::Memory, Effect::Read, {}, {}}); | ||||
| @ -269,7 +268,7 @@ vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFu | ||||
| 
 | ||||
| void UnusedStoreEliminator::applyOperation(UnusedStoreEliminator::Operation const& _operation) | ||||
| { | ||||
| 	set<Statement const*>& active = | ||||
| 	std::set<Statement const*>& active = | ||||
| 		_operation.location == Location::Storage ? | ||||
| 		activeStorageStores() : | ||||
| 		activeMemoryStores(); | ||||
| @ -324,9 +323,9 @@ bool UnusedStoreEliminator::knownUnrelated( | ||||
| 
 | ||||
| 		if (_op1.start && _op1.length && _op2.start) | ||||
| 		{ | ||||
| 			optional<u256> length1 = m_knowledgeBase.valueIfKnownConstant(*_op1.length); | ||||
| 			optional<u256> start1 = m_knowledgeBase.valueIfKnownConstant(*_op1.start); | ||||
| 			optional<u256> start2 = m_knowledgeBase.valueIfKnownConstant(*_op2.start); | ||||
| 			std::optional<u256> length1 = m_knowledgeBase.valueIfKnownConstant(*_op1.length); | ||||
| 			std::optional<u256> start1 = m_knowledgeBase.valueIfKnownConstant(*_op1.start); | ||||
| 			std::optional<u256> start2 = m_knowledgeBase.valueIfKnownConstant(*_op2.start); | ||||
| 			if ( | ||||
| 				(length1 && start1 && start2) && | ||||
| 				*start1 + *length1 >= *start1 && // no overflow
 | ||||
| @ -336,9 +335,9 @@ bool UnusedStoreEliminator::knownUnrelated( | ||||
| 		} | ||||
| 		if (_op2.start && _op2.length && _op1.start) | ||||
| 		{ | ||||
| 			optional<u256> length2 = m_knowledgeBase.valueIfKnownConstant(*_op2.length); | ||||
| 			optional<u256> start2 = m_knowledgeBase.valueIfKnownConstant(*_op2.start); | ||||
| 			optional<u256> start1 = m_knowledgeBase.valueIfKnownConstant(*_op1.start); | ||||
| 			std::optional<u256> length2 = m_knowledgeBase.valueIfKnownConstant(*_op2.length); | ||||
| 			std::optional<u256> start2 = m_knowledgeBase.valueIfKnownConstant(*_op2.start); | ||||
| 			std::optional<u256> start1 = m_knowledgeBase.valueIfKnownConstant(*_op1.start); | ||||
| 			if ( | ||||
| 				(length2 && start2 && start1) && | ||||
| 				*start2 + *length2 >= *start2 && // no overflow
 | ||||
| @ -349,8 +348,8 @@ bool UnusedStoreEliminator::knownUnrelated( | ||||
| 
 | ||||
| 		if (_op1.start && _op1.length && _op2.start && _op2.length) | ||||
| 		{ | ||||
| 			optional<u256> length1 = m_knowledgeBase.valueIfKnownConstant(*_op1.length); | ||||
| 			optional<u256> length2 = m_knowledgeBase.valueIfKnownConstant(*_op2.length); | ||||
| 			std::optional<u256> length1 = m_knowledgeBase.valueIfKnownConstant(*_op1.length); | ||||
| 			std::optional<u256> length2 = m_knowledgeBase.valueIfKnownConstant(*_op2.length); | ||||
| 			if ( | ||||
| 				(length1 && *length1 <= 32) && | ||||
| 				(length2 && *length2 <= 32) && | ||||
| @ -384,13 +383,13 @@ bool UnusedStoreEliminator::knownCovered( | ||||
| 		// i.start <= e.start && e.start + e.length <= i.start + i.length
 | ||||
| 		if (!_covered.start || !_covering.start || !_covered.length || !_covering.length) | ||||
| 			return false; | ||||
| 		optional<u256> coveredLength = m_knowledgeBase.valueIfKnownConstant(*_covered.length); | ||||
| 		optional<u256> coveringLength = m_knowledgeBase.valueIfKnownConstant(*_covering.length); | ||||
| 		std::optional<u256> coveredLength = m_knowledgeBase.valueIfKnownConstant(*_covered.length); | ||||
| 		std::optional<u256> coveringLength = m_knowledgeBase.valueIfKnownConstant(*_covering.length); | ||||
| 		if (*_covered.start == *_covering.start) | ||||
| 			if (coveredLength && coveringLength && *coveredLength <= *coveringLength) | ||||
| 				return true; | ||||
| 		optional<u256> coveredStart = m_knowledgeBase.valueIfKnownConstant(*_covered.start); | ||||
| 		optional<u256> coveringStart = m_knowledgeBase.valueIfKnownConstant(*_covering.start); | ||||
| 		std::optional<u256> coveredStart = m_knowledgeBase.valueIfKnownConstant(*_covered.start); | ||||
| 		std::optional<u256> coveringStart = m_knowledgeBase.valueIfKnownConstant(*_covering.start); | ||||
| 		if (coveredStart && coveringStart && coveredLength && coveringLength) | ||||
| 			if ( | ||||
| 				*coveringStart <= *coveredStart && | ||||
| @ -408,32 +407,32 @@ bool UnusedStoreEliminator::knownCovered( | ||||
| } | ||||
| 
 | ||||
| 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()) | ||||
| 			m_usedStores.insert(statement); | ||||
| 	if (_onlyLocation == nullopt || _onlyLocation == Location::Storage) | ||||
| 	if (_onlyLocation == std::nullopt || _onlyLocation == Location::Storage) | ||||
| 		for (Statement const* statement: activeStorageStores()) | ||||
| 			m_usedStores.insert(statement); | ||||
| 	clearActive(_onlyLocation); | ||||
| } | ||||
| 
 | ||||
| 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() = {}; | ||||
| 	if (_onlyLocation == nullopt || _onlyLocation == Location::Storage) | ||||
| 	if (_onlyLocation == std::nullopt || _onlyLocation == Location::Storage) | ||||
| 		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)) | ||||
| 			return {identifier->name}; | ||||
| 	return nullopt; | ||||
| 	return std::nullopt; | ||||
| } | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| #include <libsolutil/Visitor.h> | ||||
| #include <libyul/Dialect.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| @ -31,7 +30,7 @@ void VarDeclInitializer::operator()(Block& _block) | ||||
| { | ||||
| 	ASTModifier::operator()(_block); | ||||
| 
 | ||||
| 	using OptionalStatements = std::optional<vector<Statement>>; | ||||
| 	using OptionalStatements = std::optional<std::vector<Statement>>; | ||||
| 	util::GenericVisitor visitor{ | ||||
| 		util::VisitorFallback<OptionalStatements>{}, | ||||
| 		[this](VariableDeclaration& _varDecl) -> OptionalStatements | ||||
| @ -41,15 +40,15 @@ void VarDeclInitializer::operator()(Block& _block) | ||||
| 
 | ||||
| 			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 {}; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				OptionalStatements ret{vector<Statement>{}}; | ||||
| 				OptionalStatements ret{std::vector<Statement>{}}; | ||||
| 				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)}); | ||||
| 				} | ||||
| 				return ret; | ||||
|  | ||||
| @ -29,20 +29,19 @@ | ||||
| #include <regex> | ||||
| #include <limits> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| VarNameCleaner::VarNameCleaner( | ||||
| 	Block const& _ast, | ||||
| 	Dialect const& _dialect, | ||||
| 	set<YulString> _namesToKeep | ||||
| 	std::set<YulString> _namesToKeep | ||||
| ): | ||||
| 	m_dialect{_dialect}, | ||||
| 	m_namesToKeep{std::move(_namesToKeep)}, | ||||
| 	m_translatedNames{} | ||||
| { | ||||
| 	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_usedNames = m_namesToKeep; | ||||
| } | ||||
| @ -52,9 +51,9 @@ void VarNameCleaner::operator()(FunctionDefinition& _funDef) | ||||
| 	yulAssert(!m_insideFunction, ""); | ||||
| 	m_insideFunction = true; | ||||
| 
 | ||||
| 	set<YulString> globalUsedNames = std::move(m_usedNames); | ||||
| 	std::set<YulString> globalUsedNames = std::move(m_usedNames); | ||||
| 	m_usedNames = m_namesToKeep; | ||||
| 	map<YulString, YulString> globalTranslatedNames; | ||||
| 	std::map<YulString, YulString> globalTranslatedNames; | ||||
| 	swap(globalTranslatedNames, m_translatedNames); | ||||
| 
 | ||||
| 	renameVariables(_funDef.parameters); | ||||
| @ -73,7 +72,7 @@ void VarNameCleaner::operator()(VariableDeclaration& _varDecl) | ||||
| 	ASTModifier::operator()(_varDecl); | ||||
| } | ||||
| 
 | ||||
| void VarNameCleaner::renameVariables(vector<TypedName>& _variables) | ||||
| void VarNameCleaner::renameVariables(std::vector<TypedName>& _variables) | ||||
| { | ||||
| 	for (TypedName& typedName: _variables) | ||||
| 	{ | ||||
| @ -101,9 +100,9 @@ YulString VarNameCleaner::findCleanName(YulString const& _name) const | ||||
| 		return newName; | ||||
| 
 | ||||
| 	// 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)) | ||||
| 			return newNameSuffixed; | ||||
| 	} | ||||
| @ -117,9 +116,9 @@ bool VarNameCleaner::isUsedName(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)) | ||||
| 		return {YulString{suffixMatch.prefix().str()}}; | ||||
| 	return _name; | ||||
|  | ||||
| @ -34,6 +34,8 @@ NAMESPACE_STD_FREE_FILES=( | ||||
|     libsolidity/lsp/* | ||||
|     libsolidity/parsing/* | ||||
|     libsolutil/* | ||||
|     libyul/backends/evm/* | ||||
|     libyul/optimiser/* | ||||
|     solc/* | ||||
| ) | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user