mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #5925 from ethereum/stackCompressor
Stack compressor
This commit is contained in:
		
						commit
						18c7ad08a0
					
				| @ -134,7 +134,7 @@ void AssemblyStack::optimize(yul::Object& _object) | ||||
| 	for (auto& subNode: _object.subObjects) | ||||
| 		if (auto subObject = dynamic_cast<yul::Object*>(subNode.get())) | ||||
| 			optimize(*subObject); | ||||
| 	yul::OptimiserSuite::run(*languageToDialect(m_language), *_object.code, *_object.analysisInfo); | ||||
| 	yul::OptimiserSuite::run(languageToDialect(m_language), *_object.code, *_object.analysisInfo); | ||||
| } | ||||
| 
 | ||||
| MachineAssemblyObject AssemblyStack::assemble(Machine _machine, bool _optimize) const | ||||
|  | ||||
| @ -94,6 +94,8 @@ add_library(yul | ||||
| 	optimiser/Semantics.h | ||||
| 	optimiser/SimplificationRules.cpp | ||||
| 	optimiser/SimplificationRules.h | ||||
| 	optimiser/StackCompressor.cpp | ||||
| 	optimiser/StackCompressor.h | ||||
| 	optimiser/StructuralSimplifier.cpp | ||||
| 	optimiser/StructuralSimplifier.h | ||||
| 	optimiser/Substitution.cpp | ||||
|  | ||||
| @ -60,6 +60,13 @@ map<YulString, size_t> ReferencesCounter::countReferences(Block const& _block) | ||||
| 	return counter.references(); | ||||
| } | ||||
| 
 | ||||
| map<YulString, size_t> ReferencesCounter::countReferences(FunctionDefinition const& _function) | ||||
| { | ||||
| 	ReferencesCounter counter; | ||||
| 	counter(_function); | ||||
| 	return counter.references(); | ||||
| } | ||||
| 
 | ||||
| map<YulString, size_t> ReferencesCounter::countReferences(Expression const& _expression) | ||||
| { | ||||
| 	ReferencesCounter counter; | ||||
|  | ||||
| @ -59,6 +59,7 @@ public: | ||||
| 	virtual void operator()(FunctionCall const& _funCall); | ||||
| 
 | ||||
| 	static std::map<YulString, size_t> countReferences(Block const& _block); | ||||
| 	static std::map<YulString, size_t> countReferences(FunctionDefinition const& _function); | ||||
| 	static std::map<YulString, size_t> countReferences(Expression const& _expression); | ||||
| 
 | ||||
| 	std::map<YulString, size_t> const& references() const { return m_references; } | ||||
|  | ||||
| @ -30,14 +30,39 @@ using namespace std; | ||||
| using namespace dev; | ||||
| using namespace yul; | ||||
| 
 | ||||
| void Rematerialiser::run(Dialect const& _dialect, Block& _ast) | ||||
| void Rematerialiser::run(Dialect const& _dialect, Block& _ast, set<YulString> _varsToAlwaysRematerialize) | ||||
| { | ||||
| 	Rematerialiser{_dialect, _ast}(_ast); | ||||
| 	Rematerialiser{_dialect, _ast, std::move(_varsToAlwaysRematerialize)}(_ast); | ||||
| } | ||||
| 
 | ||||
| Rematerialiser::Rematerialiser(Dialect const& _dialect, Block& _ast): | ||||
| void Rematerialiser::run( | ||||
| 	Dialect const& _dialect, | ||||
| 	FunctionDefinition& _function, | ||||
| 	set<YulString> _varsToAlwaysRematerialize | ||||
| ) | ||||
| { | ||||
| 	Rematerialiser{_dialect, _function, std::move(_varsToAlwaysRematerialize)}(_function); | ||||
| } | ||||
| 
 | ||||
| Rematerialiser::Rematerialiser( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block& _ast, | ||||
| 	set<YulString> _varsToAlwaysRematerialize | ||||
| ): | ||||
| 	DataFlowAnalyzer(_dialect), | ||||
| 	m_referenceCounts(ReferencesCounter::countReferences(_ast)) | ||||
| 	m_referenceCounts(ReferencesCounter::countReferences(_ast)), | ||||
| 	m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Rematerialiser::Rematerialiser( | ||||
| 	Dialect const& _dialect, | ||||
| 	FunctionDefinition& _function, | ||||
| 	set<YulString> _varsToAlwaysRematerialize | ||||
| ): | ||||
| 	DataFlowAnalyzer(_dialect), | ||||
| 	m_referenceCounts(ReferencesCounter::countReferences(_function)), | ||||
| 	m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| @ -53,7 +78,7 @@ void Rematerialiser::visit(Expression& _e) | ||||
| 			auto const& value = *m_value.at(name); | ||||
| 			size_t refs = m_referenceCounts[name]; | ||||
| 			size_t cost = CodeCost::codeCost(value); | ||||
| 			if (refs <= 1 || cost == 0 || (refs <= 5 && cost <= 1)) | ||||
| 			if (refs <= 1 || cost == 0 || (refs <= 5 && cost <= 1) || m_varsToAlwaysRematerialize.count(name)) | ||||
| 			{ | ||||
| 				assertThrow(m_referenceCounts[name] > 0, OptimizerException, ""); | ||||
| 				for (auto const& ref: m_references[name]) | ||||
|  | ||||
| @ -38,15 +38,34 @@ namespace yul | ||||
| class Rematerialiser: public DataFlowAnalyzer | ||||
| { | ||||
| public: | ||||
| 	static void run(Dialect const& _dialect, Block& _ast); | ||||
| 	static void run( | ||||
| 		Dialect const& _dialect, | ||||
| 		Block& _ast, | ||||
| 		std::set<YulString> _varsToAlwaysRematerialize = {} | ||||
| 	); | ||||
| 	static void run( | ||||
| 		Dialect const& _dialect, | ||||
| 		FunctionDefinition& _function, | ||||
| 		std::set<YulString> _varsToAlwaysRematerialize = {} | ||||
| 	); | ||||
| 
 | ||||
| protected: | ||||
| 	Rematerialiser(Dialect const& _dialect, Block& _ast); | ||||
| 	Rematerialiser( | ||||
| 		Dialect const& _dialect, | ||||
| 		Block& _ast, | ||||
| 		std::set<YulString> _varsToAlwaysRematerialize = {} | ||||
| 	); | ||||
| 	Rematerialiser( | ||||
| 		Dialect const& _dialect, | ||||
| 		FunctionDefinition& _function, | ||||
| 		std::set<YulString> _varsToAlwaysRematerialize = {} | ||||
| 	); | ||||
| 
 | ||||
| 	using ASTModifier::visit; | ||||
| 	void visit(Expression& _e) override; | ||||
| 
 | ||||
| 	std::map<YulString, size_t> m_referenceCounts; | ||||
| 	std::set<YulString> m_varsToAlwaysRematerialize; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
							
								
								
									
										107
									
								
								libyul/optimiser/StackCompressor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								libyul/optimiser/StackCompressor.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | ||||
| /*(
 | ||||
| 	This file is part of solidity. | ||||
| 
 | ||||
| 	solidity is free software: you can redistribute it and/or modify | ||||
| 	it under the terms of the GNU General Public License as published by | ||||
| 	the Free Software Foundation, either version 3 of the License, or | ||||
| 	(at your option) any later version. | ||||
| 
 | ||||
| 	solidity is distributed in the hope that it will be useful, | ||||
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| 	GNU General Public License for more details. | ||||
| 
 | ||||
| 	You should have received a copy of the GNU General Public License | ||||
| 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| /**
 | ||||
|  * Optimisation stage that aggressively rematerializes certain variables ina a function to free | ||||
|  * space on the stack until it is compilable. | ||||
|  */ | ||||
| 
 | ||||
| #include <libyul/optimiser/StackCompressor.h> | ||||
| 
 | ||||
| #include <libyul/optimiser/SSAValueTracker.h> | ||||
| #include <libyul/optimiser/NameCollector.h> | ||||
| #include <libyul/optimiser/Rematerialiser.h> | ||||
| #include <libyul/optimiser/UnusedPruner.h> | ||||
| #include <libyul/optimiser/Metrics.h> | ||||
| #include <libyul/optimiser/Semantics.h> | ||||
| 
 | ||||
| #include <libyul/CompilabilityChecker.h> | ||||
| 
 | ||||
| #include <libyul/AsmData.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| using namespace yul; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| 
 | ||||
| template <typename ASTNode> | ||||
| void eliminateVariables(shared_ptr<Dialect> const& _dialect, ASTNode& _node, size_t _numVariables) | ||||
| { | ||||
| 	SSAValueTracker ssaValues; | ||||
| 	ssaValues(_node); | ||||
| 
 | ||||
| 	map<YulString, size_t> references = ReferencesCounter::countReferences(_node); | ||||
| 
 | ||||
| 	set<pair<size_t, YulString>> rematCosts; | ||||
| 	for (auto const& ssa: ssaValues.values()) | ||||
| 	{ | ||||
| 		if (!MovableChecker{*_dialect, *ssa.second}.movable()) | ||||
| 			continue; | ||||
| 		size_t numRef = references[ssa.first]; | ||||
| 		size_t cost = 0; | ||||
| 		if (numRef > 1) | ||||
| 			cost = CodeCost::codeCost(*ssa.second) * (numRef - 1); | ||||
| 		rematCosts.insert(make_pair(cost, ssa.first)); | ||||
| 	} | ||||
| 
 | ||||
| 	// Select at most _numVariables
 | ||||
| 	set<YulString> varsToEliminate; | ||||
| 	for (auto const& costs: rematCosts) | ||||
| 	{ | ||||
| 		if (varsToEliminate.size() >= _numVariables) | ||||
| 			break; | ||||
| 		varsToEliminate.insert(costs.second); | ||||
| 	} | ||||
| 
 | ||||
| 	Rematerialiser::run(*_dialect, _node, std::move(varsToEliminate)); | ||||
| 	UnusedPruner::runUntilStabilised(*_dialect, _node); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool StackCompressor::run(shared_ptr<Dialect> const& _dialect, Block& _ast) | ||||
| { | ||||
| 	yulAssert( | ||||
| 		_ast.statements.size() > 0 && _ast.statements.at(0).type() == typeid(Block), | ||||
| 		"Need to run the function grouper before the stack compressor." | ||||
| 	); | ||||
| 	for (size_t iterations = 0; iterations < 4; iterations++) | ||||
| 	{ | ||||
| 		map<YulString, int> stackSurplus = CompilabilityChecker::run(_dialect, _ast); | ||||
| 		if (stackSurplus.empty()) | ||||
| 			return true; | ||||
| 
 | ||||
| 		if (stackSurplus.count(YulString{})) | ||||
| 		{ | ||||
| 			yulAssert(stackSurplus.at({}) > 0, "Invalid surplus value."); | ||||
| 			eliminateVariables(_dialect, boost::get<Block>(_ast.statements.at(0)), stackSurplus.at({})); | ||||
| 		} | ||||
| 
 | ||||
| 		for (size_t i = 1; i < _ast.statements.size(); ++i) | ||||
| 		{ | ||||
| 			FunctionDefinition& fun = boost::get<FunctionDefinition>(_ast.statements[i]); | ||||
| 			if (!stackSurplus.count(fun.name)) | ||||
| 				continue; | ||||
| 
 | ||||
| 			yulAssert(stackSurplus.at(fun.name) > 0, "Invalid surplus value."); | ||||
| 			eliminateVariables(_dialect, fun, stackSurplus.at(fun.name)); | ||||
| 		} | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										47
									
								
								libyul/optimiser/StackCompressor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								libyul/optimiser/StackCompressor.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| /*
 | ||||
| 	This file is part of solidity. | ||||
| 
 | ||||
| 	solidity is free software: you can redistribute it and/or modify | ||||
| 	it under the terms of the GNU General Public License as published by | ||||
| 	the Free Software Foundation, either version 3 of the License, or | ||||
| 	(at your option) any later version. | ||||
| 
 | ||||
| 	solidity is distributed in the hope that it will be useful, | ||||
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| 	GNU General Public License for more details. | ||||
| 
 | ||||
| 	You should have received a copy of the GNU General Public License | ||||
| 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| /**
 | ||||
|  * Optimisation stage that aggressively rematerializes certain variables ina a function to free | ||||
|  * space on the stack until it is compilable. | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace yul | ||||
| { | ||||
| 
 | ||||
| struct Dialect; | ||||
| struct Block; | ||||
| struct FunctionDefinition; | ||||
| 
 | ||||
| /**
 | ||||
|  * Optimisation stage that aggressively rematerializes certain variables in a function to free | ||||
|  * space on the stack until it is compilable. | ||||
|  * | ||||
|  * Prerequisite: Disambiguator, Function Grouper | ||||
|  */ | ||||
| class StackCompressor | ||||
| { | ||||
| public: | ||||
| 	/// Try to remove local variables until the AST is compilable.
 | ||||
| 	/// @returns true if it was successful.
 | ||||
| 	static bool run(std::shared_ptr<Dialect> const& _dialect, Block& _ast); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| @ -37,6 +37,7 @@ | ||||
| #include <libyul/optimiser/CommonSubexpressionEliminator.h> | ||||
| #include <libyul/optimiser/SSAReverser.h> | ||||
| #include <libyul/optimiser/SSATransform.h> | ||||
| #include <libyul/optimiser/StackCompressor.h> | ||||
| #include <libyul/optimiser/StructuralSimplifier.h> | ||||
| #include <libyul/optimiser/RedundantAssignEliminator.h> | ||||
| #include <libyul/AsmAnalysisInfo.h> | ||||
| @ -50,7 +51,7 @@ using namespace dev; | ||||
| using namespace yul; | ||||
| 
 | ||||
| void OptimiserSuite::run( | ||||
| 	Dialect const& _dialect, | ||||
| 	shared_ptr<Dialect> const& _dialect, | ||||
| 	Block& _ast, | ||||
| 	AsmAnalysisInfo const& _analysisInfo, | ||||
| 	set<YulString> const& _externallyUsedIdentifiers | ||||
| @ -58,86 +59,121 @@ void OptimiserSuite::run( | ||||
| { | ||||
| 	set<YulString> reservedIdentifiers = _externallyUsedIdentifiers; | ||||
| 
 | ||||
| 	Block ast = boost::get<Block>(Disambiguator(_dialect, _analysisInfo, reservedIdentifiers)(_ast)); | ||||
| 	Block ast = boost::get<Block>(Disambiguator(*_dialect, _analysisInfo, reservedIdentifiers)(_ast)); | ||||
| 
 | ||||
| 	(VarDeclInitializer{})(ast); | ||||
| 	(FunctionHoister{})(ast); | ||||
| 	(BlockFlattener{})(ast); | ||||
| 	(FunctionGrouper{})(ast); | ||||
| 	EquivalentFunctionCombiner::run(ast); | ||||
| 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 	(ForLoopInitRewriter{})(ast); | ||||
| 	(BlockFlattener{})(ast); | ||||
| 	StructuralSimplifier{_dialect}(ast); | ||||
| 	StructuralSimplifier{*_dialect}(ast); | ||||
| 	(BlockFlattener{})(ast); | ||||
| 
 | ||||
| 	NameDispenser dispenser{_dialect, ast}; | ||||
| 	// None of the above can make stack problems worse.
 | ||||
| 
 | ||||
| 	NameDispenser dispenser{*_dialect, ast}; | ||||
| 
 | ||||
| 	for (size_t i = 0; i < 4; i++) | ||||
| 	{ | ||||
| 		ExpressionSplitter{_dialect, dispenser}(ast); | ||||
| 		SSATransform::run(ast, dispenser); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		{ | ||||
| 			// Turn into SSA and simplify
 | ||||
| 			ExpressionSplitter{*_dialect, dispenser}(ast); | ||||
| 			SSATransform::run(ast, dispenser); | ||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | ||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | ||||
| 
 | ||||
| 		ExpressionSimplifier::run(_dialect, ast); | ||||
| 		CommonSubexpressionEliminator{_dialect}(ast); | ||||
| 		StructuralSimplifier{_dialect}(ast); | ||||
| 		(BlockFlattener{})(ast); | ||||
| 		SSATransform::run(ast, dispenser); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 		CommonSubexpressionEliminator{_dialect}(ast); | ||||
| 		UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 			ExpressionSimplifier::run(*_dialect, ast); | ||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | ||||
| 		} | ||||
| 
 | ||||
| 		SSAReverser::run(ast); | ||||
| 		CommonSubexpressionEliminator{_dialect}(ast); | ||||
| 		UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 		{ | ||||
| 			// still in SSA, perform structural simplification
 | ||||
| 			StructuralSimplifier{*_dialect}(ast); | ||||
| 			(BlockFlattener{})(ast); | ||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 		} | ||||
| 		{ | ||||
| 			// simplify again
 | ||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | ||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 		} | ||||
| 
 | ||||
| 		ExpressionJoiner::run(ast); | ||||
| 		ExpressionJoiner::run(ast); | ||||
| 		ExpressionInliner(_dialect, ast).run(); | ||||
| 		UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 		{ | ||||
| 			// reverse SSA
 | ||||
| 			SSAReverser::run(ast); | ||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | ||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 
 | ||||
| 		ExpressionSplitter{_dialect, dispenser}(ast); | ||||
| 		SSATransform::run(ast, dispenser); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		CommonSubexpressionEliminator{_dialect}(ast); | ||||
| 			ExpressionJoiner::run(ast); | ||||
| 			ExpressionJoiner::run(ast); | ||||
| 		} | ||||
| 
 | ||||
| 		(FunctionGrouper{})(ast); | ||||
| 		EquivalentFunctionCombiner::run(ast); | ||||
| 		FullInliner{ast, dispenser}.run(); | ||||
| 		(BlockFlattener{})(ast); | ||||
| 		// should have good "compilability" property here.
 | ||||
| 
 | ||||
| 		SSATransform::run(ast, dispenser); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		ExpressionSimplifier::run(_dialect, ast); | ||||
| 		StructuralSimplifier{_dialect}(ast); | ||||
| 		(BlockFlattener{})(ast); | ||||
| 		CommonSubexpressionEliminator{_dialect}(ast); | ||||
| 		SSATransform::run(ast, dispenser); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		RedundantAssignEliminator::run(_dialect, ast); | ||||
| 		UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 		CommonSubexpressionEliminator{_dialect}(ast); | ||||
| 		{ | ||||
| 			// run functional expression inliner
 | ||||
| 			ExpressionInliner(*_dialect, ast).run(); | ||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			// Turn into SSA again and simplify
 | ||||
| 			ExpressionSplitter{*_dialect, dispenser}(ast); | ||||
| 			SSATransform::run(ast, dispenser); | ||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | ||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | ||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			// run full inliner
 | ||||
| 			(FunctionGrouper{})(ast); | ||||
| 			EquivalentFunctionCombiner::run(ast); | ||||
| 			FullInliner{ast, dispenser}.run(); | ||||
| 			(BlockFlattener{})(ast); | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			// SSA plus simplify
 | ||||
| 			SSATransform::run(ast, dispenser); | ||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | ||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | ||||
| 			ExpressionSimplifier::run(*_dialect, ast); | ||||
| 			StructuralSimplifier{*_dialect}(ast); | ||||
| 			(BlockFlattener{})(ast); | ||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | ||||
| 			SSATransform::run(ast, dispenser); | ||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | ||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | ||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Make source short and pretty.
 | ||||
| 
 | ||||
| 	ExpressionJoiner::run(ast); | ||||
| 	Rematerialiser::run(_dialect, ast); | ||||
| 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 	Rematerialiser::run(*_dialect, ast); | ||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 	ExpressionJoiner::run(ast); | ||||
| 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 	ExpressionJoiner::run(ast); | ||||
| 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 
 | ||||
| 	SSAReverser::run(ast); | ||||
| 	CommonSubexpressionEliminator{_dialect}(ast); | ||||
| 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 	CommonSubexpressionEliminator{*_dialect}(ast); | ||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 
 | ||||
| 	ExpressionJoiner::run(ast); | ||||
| 	Rematerialiser::run(_dialect, ast); | ||||
| 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||
| 	Rematerialiser::run(*_dialect, ast); | ||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | ||||
| 
 | ||||
| 	(FunctionGrouper{})(ast); | ||||
| 	StackCompressor::run(_dialect, ast); | ||||
| 	(BlockFlattener{})(ast); | ||||
| 
 | ||||
| 	_ast = std::move(ast); | ||||
| } | ||||
|  | ||||
| @ -38,7 +38,7 @@ class OptimiserSuite | ||||
| { | ||||
| public: | ||||
| 	static void run( | ||||
| 		Dialect const& _dialect, | ||||
| 		std::shared_ptr<Dialect> const& _dialect, | ||||
| 		Block& _ast, | ||||
| 		AsmAnalysisInfo const& _analysisInfo, | ||||
| 		std::set<YulString> const& _externallyUsedIdentifiers = {} | ||||
|  | ||||
| @ -35,10 +35,15 @@ using namespace yul; | ||||
| UnusedPruner::UnusedPruner(Dialect const& _dialect, Block& _ast, set<YulString> const& _externallyUsedFunctions): | ||||
| 	m_dialect(_dialect) | ||||
| { | ||||
| 	ReferencesCounter counter; | ||||
| 	counter(_ast); | ||||
| 	m_references = ReferencesCounter::countReferences(_ast); | ||||
| 	for (auto const& f: _externallyUsedFunctions) | ||||
| 		++m_references[f]; | ||||
| } | ||||
| 
 | ||||
| 	m_references = counter.references(); | ||||
| UnusedPruner::UnusedPruner(Dialect const& _dialect, FunctionDefinition& _function, set<YulString> const& _externallyUsedFunctions): | ||||
| 	m_dialect(_dialect) | ||||
| { | ||||
| 	m_references = ReferencesCounter::countReferences(_function); | ||||
| 	for (auto const& f: _externallyUsedFunctions) | ||||
| 		++m_references[f]; | ||||
| } | ||||
| @ -116,6 +121,21 @@ void UnusedPruner::runUntilStabilised( | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void UnusedPruner::runUntilStabilised( | ||||
| 	Dialect const& _dialect, | ||||
| 	FunctionDefinition& _function, | ||||
| 	set<YulString> const& _externallyUsedFunctions | ||||
| ) | ||||
| { | ||||
| 	while (true) | ||||
| 	{ | ||||
| 		UnusedPruner pruner(_dialect, _function, _externallyUsedFunctions); | ||||
| 		pruner(_function); | ||||
| 		if (!pruner.shouldRunAgain()) | ||||
| 			return; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool UnusedPruner::used(YulString _name) const | ||||
| { | ||||
| 	return m_references.count(_name) && m_references.at(_name) > 0; | ||||
|  | ||||
| @ -46,6 +46,11 @@ public: | ||||
| 		Block& _ast, | ||||
| 		std::set<YulString> const& _externallyUsedFunctions = {} | ||||
| 	); | ||||
| 	UnusedPruner( | ||||
| 		Dialect const& _dialect, | ||||
| 		FunctionDefinition& _function, | ||||
| 		std::set<YulString> const& _externallyUsedFunctions = {} | ||||
| 	); | ||||
| 
 | ||||
| 	using ASTModifier::operator(); | ||||
| 	void operator()(Block& _block) override; | ||||
| @ -60,6 +65,14 @@ public: | ||||
| 		std::set<YulString> const& _externallyUsedFunctions = {} | ||||
| 	); | ||||
| 
 | ||||
| 	// Run the pruner until the code does not change anymore.
 | ||||
| 	// Only run on the given function.
 | ||||
| 	static void runUntilStabilised( | ||||
| 		Dialect const& _dialect, | ||||
| 		FunctionDefinition& _functionDefinition, | ||||
| 		std::set<YulString> const& _externallyUsedFunctions = {} | ||||
| 	); | ||||
| 
 | ||||
| private: | ||||
| 	bool used(YulString _name) const; | ||||
| 	void subtractReferences(std::map<YulString, size_t> const& _subtrahend); | ||||
|  | ||||
| @ -42,6 +42,7 @@ | ||||
| #include <libyul/optimiser/SSATransform.h> | ||||
| #include <libyul/optimiser/RedundantAssignEliminator.h> | ||||
| #include <libyul/optimiser/StructuralSimplifier.h> | ||||
| #include <libyul/optimiser/StackCompressor.h> | ||||
| #include <libyul/optimiser/Suite.h> | ||||
| #include <libyul/backends/evm/EVMDialect.h> | ||||
| #include <libyul/AsmPrinter.h> | ||||
| @ -241,8 +242,15 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con | ||||
| 		CommonSubexpressionEliminator{*m_dialect}(*m_ast); | ||||
| 		UnusedPruner::runUntilStabilised(*m_dialect, *m_ast); | ||||
| 	} | ||||
| 	else if (m_optimizerStep == "stackCompressor") | ||||
| 	{ | ||||
| 		disambiguate(); | ||||
| 		(FunctionGrouper{})(*m_ast); | ||||
| 		StackCompressor::run(m_dialect, *m_ast); | ||||
| 		(BlockFlattener{})(*m_ast); | ||||
| 	} | ||||
| 	else if (m_optimizerStep == "fullSuite") | ||||
| 		OptimiserSuite::run(*m_dialect, *m_ast, *m_analysisInfo); | ||||
| 		OptimiserSuite::run(m_dialect, *m_ast, *m_analysisInfo); | ||||
| 	else | ||||
| 	{ | ||||
| 		FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Invalid optimizer step: " << m_optimizerStep << endl; | ||||
|  | ||||
| @ -1073,12 +1073,12 @@ | ||||
| // fullSuite | ||||
| // { | ||||
| //     let _2 := mload(1) | ||||
| //     let _153 := mload(0) | ||||
| //     if slt(sub(_2, _153), 64) | ||||
| //     let _134 := mload(0) | ||||
| //     if slt(sub(_2, _134), 64) | ||||
| //     { | ||||
| //         revert(0, 0) | ||||
| //     } | ||||
| //     sstore(0, and(calldataload(_153), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) | ||||
| //     sstore(0, and(calldataload(_134), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) | ||||
| //     let x0, x1, x2, x3, x4 := abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(mload(7), mload(8)) | ||||
| //     sstore(x1, x0) | ||||
| //     sstore(x3, x2) | ||||
| @ -1093,40 +1093,40 @@ | ||||
| //         value0_57 := and(calldataload(headStart_55), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ||||
| //         value1_58 := calldataload(add(headStart_55, 32)) | ||||
| //         let offset_62 := calldataload(add(headStart_55, 64)) | ||||
| //         let _200 := 0xffffffffffffffff | ||||
| //         if gt(offset_62, _200) | ||||
| //         let _181 := 0xffffffffffffffff | ||||
| //         if gt(offset_62, _181) | ||||
| //         { | ||||
| //             revert(value4, value4) | ||||
| //         } | ||||
| //         let _202 := add(headStart_55, offset_62) | ||||
| //         if iszero(slt(add(_202, 0x1f), dataEnd_56)) | ||||
| //         let _183 := add(headStart_55, offset_62) | ||||
| //         if iszero(slt(add(_183, 0x1f), dataEnd_56)) | ||||
| //         { | ||||
| //             revert(value4, value4) | ||||
| //         } | ||||
| //         let abi_decode_length_15_244 := calldataload(_202) | ||||
| //         if gt(abi_decode_length_15_244, _200) | ||||
| //         let abi_decode_length_15_225 := calldataload(_183) | ||||
| //         if gt(abi_decode_length_15_225, _181) | ||||
| //         { | ||||
| //             revert(value4, value4) | ||||
| //         } | ||||
| //         if gt(add(add(_202, abi_decode_length_15_244), 32), dataEnd_56) | ||||
| //         if gt(add(add(_183, abi_decode_length_15_225), 32), dataEnd_56) | ||||
| //         { | ||||
| //             revert(value4, value4) | ||||
| //         } | ||||
| //         value2_59 := add(_202, 32) | ||||
| //         value3 := abi_decode_length_15_244 | ||||
| //         let _205 := calldataload(add(headStart_55, 96)) | ||||
| //         if iszero(lt(_205, 3)) | ||||
| //         value2_59 := add(_183, 32) | ||||
| //         value3 := abi_decode_length_15_225 | ||||
| //         let _186 := calldataload(add(headStart_55, 96)) | ||||
| //         if iszero(lt(_186, 3)) | ||||
| //         { | ||||
| //             revert(value4, value4) | ||||
| //         } | ||||
| //         value4 := _205 | ||||
| //         value4 := _186 | ||||
| //     } | ||||
| //     function abi_encode_tuple_t_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_$1949_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256__to_t_bytes32_t_address_t_uint256_t_bytes32_t_uint8_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256_(headStart_252, value10_253, value9_254, value8_255, value7_256, value6_257, value5_258, value4_259, value3_260, value2_261, value1_262, value0_263) -> tail_264 | ||||
| //     { | ||||
| //         tail_264 := add(headStart_252, 352) | ||||
| //         mstore(headStart_252, value0_263) | ||||
| //         let _409 := 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF | ||||
| //         mstore(add(headStart_252, 32), and(value1_262, _409)) | ||||
| //         let _382 := 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF | ||||
| //         mstore(add(headStart_252, 32), and(value1_262, _382)) | ||||
| //         mstore(add(headStart_252, 64), value2_261) | ||||
| //         mstore(add(headStart_252, 96), value3_260) | ||||
| //         if iszero(lt(value4_259, 3)) | ||||
| @ -1137,8 +1137,8 @@ | ||||
| //         mstore(add(headStart_252, 160), value5_258) | ||||
| //         mstore(add(headStart_252, 192), value6_257) | ||||
| //         mstore(add(headStart_252, 224), value7_256) | ||||
| //         mstore(add(headStart_252, 256), and(value8_255, _409)) | ||||
| //         mstore(add(headStart_252, 288), and(value9_254, _409)) | ||||
| //         mstore(add(headStart_252, 256), and(value8_255, _382)) | ||||
| //         mstore(add(headStart_252, 288), and(value9_254, _382)) | ||||
| //         mstore(add(headStart_252, 320), value10_253) | ||||
| //     } | ||||
| // } | ||||
|  | ||||
| @ -460,12 +460,12 @@ | ||||
| // { | ||||
| //     let _1 := 0x20 | ||||
| //     let _2 := 0 | ||||
| //     let _218 := mload(_2) | ||||
| //     let _168 := mload(_2) | ||||
| //     let abi_encode_pos := _1 | ||||
| //     let abi_encode_length_68 := mload(_218) | ||||
| //     let abi_encode_length_68 := mload(_168) | ||||
| //     mstore(_1, abi_encode_length_68) | ||||
| //     abi_encode_pos := 64 | ||||
| //     let abi_encode_srcPtr := add(_218, _1) | ||||
| //     let abi_encode_srcPtr := add(_168, _1) | ||||
| //     let abi_encode_i_69 := _2 | ||||
| //     for { | ||||
| //     } | ||||
| @ -474,45 +474,45 @@ | ||||
| //         abi_encode_i_69 := add(abi_encode_i_69, 1) | ||||
| //     } | ||||
| //     { | ||||
| //         let _579 := mload(abi_encode_srcPtr) | ||||
| //         let abi_encode_pos_71_671 := abi_encode_pos | ||||
| //         let abi_encode_srcPtr_73_673 := _579 | ||||
| //         let abi_encode_i_74_674 := _2 | ||||
| //         let _491 := mload(abi_encode_srcPtr) | ||||
| //         let abi_encode_pos_71_583 := abi_encode_pos | ||||
| //         let abi_encode_srcPtr_73_585 := _491 | ||||
| //         let abi_encode_i_74_586 := _2 | ||||
| //         for { | ||||
| //         } | ||||
| //         lt(abi_encode_i_74_674, 0x3) | ||||
| //         lt(abi_encode_i_74_586, 0x3) | ||||
| //         { | ||||
| //             abi_encode_i_74_674 := add(abi_encode_i_74_674, 1) | ||||
| //             abi_encode_i_74_586 := add(abi_encode_i_74_586, 1) | ||||
| //         } | ||||
| //         { | ||||
| //             mstore(abi_encode_pos_71_671, and(mload(abi_encode_srcPtr_73_673), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) | ||||
| //             abi_encode_srcPtr_73_673 := add(abi_encode_srcPtr_73_673, _1) | ||||
| //             abi_encode_pos_71_671 := add(abi_encode_pos_71_671, _1) | ||||
| //             mstore(abi_encode_pos_71_583, and(mload(abi_encode_srcPtr_73_585), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) | ||||
| //             abi_encode_srcPtr_73_585 := add(abi_encode_srcPtr_73_585, _1) | ||||
| //             abi_encode_pos_71_583 := add(abi_encode_pos_71_583, _1) | ||||
| //         } | ||||
| //         abi_encode_srcPtr := add(abi_encode_srcPtr, _1) | ||||
| //         abi_encode_pos := add(abi_encode_pos, 0x60) | ||||
| //     } | ||||
| //     let _220 := mload(64) | ||||
| //     let _221 := mload(_1) | ||||
| //     if slt(sub(_220, _221), 128) | ||||
| //     let _170 := mload(64) | ||||
| //     let _171 := mload(_1) | ||||
| //     if slt(sub(_170, _171), 128) | ||||
| //     { | ||||
| //         revert(_2, _2) | ||||
| //     } | ||||
| //     let abi_decode_offset_64 := calldataload(add(_221, 64)) | ||||
| //     let abi_decode_offset_64 := calldataload(add(_171, 64)) | ||||
| //     let abi_decode__74 := 0xffffffffffffffff | ||||
| //     if gt(abi_decode_offset_64, abi_decode__74) | ||||
| //     { | ||||
| //         revert(_2, _2) | ||||
| //     } | ||||
| //     let abi_decode_value2_314 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_221, abi_decode_offset_64), _220) | ||||
| //     let abi_decode_offset_65 := calldataload(add(_221, 96)) | ||||
| //     let abi_decode_value2_264 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_171, abi_decode_offset_64), _170) | ||||
| //     let abi_decode_offset_65 := calldataload(add(_171, 96)) | ||||
| //     if gt(abi_decode_offset_65, abi_decode__74) | ||||
| //     { | ||||
| //         revert(_2, _2) | ||||
| //     } | ||||
| //     let abi_decode_value3_315 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_221, abi_decode_offset_65), _220) | ||||
| //     sstore(calldataload(_221), calldataload(add(_221, _1))) | ||||
| //     sstore(abi_decode_value2_314, abi_decode_value3_315) | ||||
| //     let abi_decode_value3_265 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_171, abi_decode_offset_65), _170) | ||||
| //     sstore(calldataload(_171), calldataload(add(_171, _1))) | ||||
| //     sstore(abi_decode_value2_264, abi_decode_value3_265) | ||||
| //     sstore(_2, abi_encode_pos) | ||||
| //     function abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(offset_3, end_4) -> array_5 | ||||
| //     { | ||||
| @ -544,10 +544,10 @@ | ||||
| //                 revert(0, 0) | ||||
| //             } | ||||
| //             let abi_decode_dst_15 := allocateMemory(array_allocation_size_t_array$_t_uint256_$2_memory(0x2)) | ||||
| //             let abi_decode_dst_15_1154 := abi_decode_dst_15 | ||||
| //             let abi_decode_dst_15_990 := abi_decode_dst_15 | ||||
| //             let abi_decode_src_16 := src_8 | ||||
| //             let abi_decode__238 := add(src_8, 0x40) | ||||
| //             if gt(abi_decode__238, end_4) | ||||
| //             let abi_decode__188 := add(src_8, 0x40) | ||||
| //             if gt(abi_decode__188, end_4) | ||||
| //             { | ||||
| //                 revert(0, 0) | ||||
| //             } | ||||
| @ -563,9 +563,9 @@ | ||||
| //                 abi_decode_dst_15 := add(abi_decode_dst_15, _16) | ||||
| //                 abi_decode_src_16 := add(abi_decode_src_16, _16) | ||||
| //             } | ||||
| //             mstore(dst_7, abi_decode_dst_15_1154) | ||||
| //             mstore(dst_7, abi_decode_dst_15_990) | ||||
| //             dst_7 := add(dst_7, _16) | ||||
| //             src_8 := abi_decode__238 | ||||
| //             src_8 := abi_decode__188 | ||||
| //         } | ||||
| //     } | ||||
| //     function abi_decode_t_array$_t_uint256_$dyn_memory_ptr(offset_27, end_28) -> array_29 | ||||
|  | ||||
| @ -234,10 +234,8 @@ | ||||
| //     let validateJo__6 := 0x80 | ||||
| //     mstore(validateJo__6, 7673901602397024137095011250362199966051872585513276903826533215767972925880) | ||||
| //     mstore(0xa0, 8489654445897228341090914135473290831551238522473825886865492707826370766375) | ||||
| //     let validateJo__10 := calldataload(0x04) | ||||
| //     let validateJo_notes := add(0x04, validateJo__10) | ||||
| //     let validateJo_m := calldataload(0x24) | ||||
| //     let validateJo_n := calldataload(validateJo_notes) | ||||
| //     let validateJo_n := calldataload(add(0x04, calldataload(0x04))) | ||||
| //     let validateJo_gen_order := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 | ||||
| //     let validateJo_challenge := mod(calldataload(0x44), validateJo_gen_order) | ||||
| //     if gt(validateJo_m, validateJo_n) | ||||
| @ -246,15 +244,14 @@ | ||||
| //         revert(0x00, 0x20) | ||||
| //     } | ||||
| //     let validateJo_kn := calldataload(add(calldatasize(), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40)) | ||||
| //     let validateJo__24 := 0x2a0 | ||||
| //     mstore(validateJo__24, caller()) | ||||
| //     mstore(0x2a0, caller()) | ||||
| //     mstore(0x2c0, validateJo_kn) | ||||
| //     mstore(0x2e0, validateJo_m) | ||||
| //     validateJo_kn := mulmod(sub(validateJo_gen_order, validateJo_kn), validateJo_challenge, validateJo_gen_order) | ||||
| //     hashCommitments(validateJo_notes, validateJo_n) | ||||
| //     hashCommitments(add(0x04, calldataload(0x04)), validateJo_n) | ||||
| //     let validateJo_b := add(0x300, mul(validateJo_n, validateJo__6)) | ||||
| //     let validateJo_i := 0 | ||||
| //     let validateJo_i_1306 := validateJo_i | ||||
| //     let validateJo_i_1218 := validateJo_i | ||||
| //     for { | ||||
| //     } | ||||
| //     lt(validateJo_i, validateJo_n) | ||||
| @ -262,14 +259,11 @@ | ||||
| //         validateJo_i := add(validateJo_i, 0x01) | ||||
| //     } | ||||
| //     { | ||||
| //         let validateJo__34 := 0x20 | ||||
| //         let validateJo__351 := add(validateJo__10, mul(validateJo_i, 0xc0)) | ||||
| //         let validateJo_noteIndex := add(validateJo__351, 0x24) | ||||
| //         let validateJo_k := validateJo_i_1306 | ||||
| //         let validateJo_a := calldataload(add(validateJo__351, 0x44)) | ||||
| //         let validateJo__329 := add(calldataload(0x04), mul(validateJo_i, 0xc0)) | ||||
| //         let validateJo_k := validateJo_i_1218 | ||||
| //         let validateJo_a := calldataload(add(validateJo__329, 0x44)) | ||||
| //         let validateJo_c := validateJo_challenge | ||||
| //         let validateJo__39 := add(validateJo_i, 0x01) | ||||
| //         switch eq(validateJo__39, validateJo_n) | ||||
| //         switch eq(add(validateJo_i, 0x01), validateJo_n) | ||||
| //         case 1 { | ||||
| //             validateJo_k := validateJo_kn | ||||
| //             if eq(validateJo_m, validateJo_n) | ||||
| @ -278,55 +272,50 @@ | ||||
| //             } | ||||
| //         } | ||||
| //         case 0 { | ||||
| //             validateJo_k := calldataload(validateJo_noteIndex) | ||||
| //             validateJo_k := calldataload(add(validateJo__329, 0x24)) | ||||
| //         } | ||||
| //         validateCommitment(validateJo_noteIndex, validateJo_k, validateJo_a) | ||||
| //         switch gt(validateJo__39, validateJo_m) | ||||
| //         validateCommitment(add(validateJo__329, 0x24), validateJo_k, validateJo_a) | ||||
| //         switch gt(add(validateJo_i, 0x01), validateJo_m) | ||||
| //         case 1 { | ||||
| //             validateJo_kn := addmod(validateJo_kn, sub(validateJo_gen_order, validateJo_k), validateJo_gen_order) | ||||
| //             let validateJo_x := mod(mload(validateJo_i_1306), validateJo_gen_order) | ||||
| //             let validateJo_x := mod(mload(validateJo_i_1218), validateJo_gen_order) | ||||
| //             validateJo_k := mulmod(validateJo_k, validateJo_x, validateJo_gen_order) | ||||
| //             validateJo_a := mulmod(validateJo_a, validateJo_x, validateJo_gen_order) | ||||
| //             validateJo_c := mulmod(validateJo_challenge, validateJo_x, validateJo_gen_order) | ||||
| //             mstore(validateJo_i_1306, keccak256(validateJo_i_1306, validateJo__34)) | ||||
| //             mstore(validateJo_i_1218, keccak256(validateJo_i_1218, 0x20)) | ||||
| //         } | ||||
| //         case 0 { | ||||
| //             validateJo_kn := addmod(validateJo_kn, validateJo_k, validateJo_gen_order) | ||||
| //         } | ||||
| //         let validateJo__52 := 0x40 | ||||
| //         calldatacopy(0xe0, add(validateJo__351, 164), validateJo__52) | ||||
| //         calldatacopy(validateJo__34, add(validateJo__351, 100), validateJo__52) | ||||
| //         let validateJo__61 := 0x120 | ||||
| //         mstore(validateJo__61, sub(validateJo_gen_order, validateJo_c)) | ||||
| //         let validateJo__62 := 0x60 | ||||
| //         mstore(validateJo__62, validateJo_k) | ||||
| //         calldatacopy(0xe0, add(validateJo__329, 164), validateJo__52) | ||||
| //         calldatacopy(0x20, add(validateJo__329, 100), validateJo__52) | ||||
| //         mstore(0x120, sub(validateJo_gen_order, validateJo_c)) | ||||
| //         mstore(0x60, validateJo_k) | ||||
| //         mstore(0xc0, validateJo_a) | ||||
| //         let validateJo__65 := 0x1a0 | ||||
| //         let validateJo_result := call(gas(), 7, validateJo_i_1306, 0xe0, validateJo__62, validateJo__65, validateJo__52) | ||||
| //         let validateJo_result_303 := and(validateJo_result, call(gas(), 7, validateJo_i_1306, validateJo__34, validateJo__62, validateJo__61, validateJo__52)) | ||||
| //         let validateJo__80 := 0x160 | ||||
| //         let validateJo_result_304 := and(validateJo_result_303, call(gas(), 7, validateJo_i_1306, validateJo__6, validateJo__62, validateJo__80, validateJo__52)) | ||||
| //         let validateJo_result_305 := and(validateJo_result_304, call(gas(), 6, validateJo_i_1306, validateJo__61, validateJo__6, validateJo__80, validateJo__52)) | ||||
| //         validateJo_result := and(validateJo_result_305, call(gas(), 6, validateJo_i_1306, validateJo__80, validateJo__6, validateJo_b, validateJo__52)) | ||||
| //         let validateJo_result := call(gas(), 7, validateJo_i_1218, 0xe0, 0x60, 0x1a0, validateJo__52) | ||||
| //         let validateJo_result_303 := and(validateJo_result, call(gas(), 7, validateJo_i_1218, 0x20, 0x60, 0x120, validateJo__52)) | ||||
| //         let validateJo_result_304 := and(validateJo_result_303, call(gas(), 7, validateJo_i_1218, validateJo__6, 0x60, 0x160, validateJo__52)) | ||||
| //         let validateJo_result_305 := and(validateJo_result_304, call(gas(), 6, validateJo_i_1218, 0x120, validateJo__6, 0x160, validateJo__52)) | ||||
| //         validateJo_result := and(validateJo_result_305, call(gas(), 6, validateJo_i_1218, 0x160, validateJo__6, validateJo_b, validateJo__52)) | ||||
| //         if eq(validateJo_i, validateJo_m) | ||||
| //         { | ||||
| //             mstore(0x260, mload(validateJo__34)) | ||||
| //             mstore(0x260, mload(0x20)) | ||||
| //             mstore(0x280, mload(validateJo__52)) | ||||
| //             mstore(0x1e0, mload(0xe0)) | ||||
| //             mstore(0x200, sub(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47, mload(0x100))) | ||||
| //         } | ||||
| //         if gt(validateJo_i, validateJo_m) | ||||
| //         { | ||||
| //             mstore(validateJo__62, validateJo_c) | ||||
| //             let validateJo__120 := 0x220 | ||||
| //             let validateJo_result_307 := and(validateJo_result, call(gas(), 7, validateJo_i_1306, validateJo__34, validateJo__62, validateJo__120, validateJo__52)) | ||||
| //             let validateJo_result_308 := and(validateJo_result_307, call(gas(), 6, validateJo_i_1306, validateJo__120, validateJo__6, 0x260, validateJo__52)) | ||||
| //             validateJo_result := and(validateJo_result_308, call(gas(), 6, validateJo_i_1306, validateJo__65, validateJo__6, 0x1e0, validateJo__52)) | ||||
| //             mstore(0x60, validateJo_c) | ||||
| //             let validateJo_result_307 := and(validateJo_result, call(gas(), 7, validateJo_i_1218, 0x20, 0x60, 0x220, validateJo__52)) | ||||
| //             let validateJo_result_308 := and(validateJo_result_307, call(gas(), 6, validateJo_i_1218, 0x220, validateJo__6, 0x260, validateJo__52)) | ||||
| //             validateJo_result := and(validateJo_result_308, call(gas(), 6, validateJo_i_1218, 0x1a0, validateJo__6, 0x1e0, validateJo__52)) | ||||
| //         } | ||||
| //         if iszero(validateJo_result) | ||||
| //         { | ||||
| //             mstore(validateJo_i_1306, 400) | ||||
| //             revert(validateJo_i_1306, validateJo__34) | ||||
| //             mstore(validateJo_i_1218, 400) | ||||
| //             revert(validateJo_i_1218, 0x20) | ||||
| //         } | ||||
| //         validateJo_b := add(validateJo_b, validateJo__52) | ||||
| //     } | ||||
| @ -334,15 +323,15 @@ | ||||
| //     { | ||||
| //         validatePairing(0x64) | ||||
| //     } | ||||
| //     if iszero(eq(mod(keccak256(validateJo__24, add(validateJo_b, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd60)), validateJo_gen_order), validateJo_challenge)) | ||||
| //     if iszero(eq(mod(keccak256(0x2a0, add(validateJo_b, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd60)), validateJo_gen_order), validateJo_challenge)) | ||||
| //     { | ||||
| //         mstore(validateJo_i_1306, 404) | ||||
| //         revert(validateJo_i_1306, 0x20) | ||||
| //         mstore(validateJo_i_1218, 404) | ||||
| //         revert(validateJo_i_1218, 0x20) | ||||
| //     } | ||||
| //     mstore(validateJo_i_1306, 0x01) | ||||
| //     return(validateJo_i_1306, 0x20) | ||||
| //     mstore(validateJo_i_1306, 404) | ||||
| //     revert(validateJo_i_1306, 0x20) | ||||
| //     mstore(validateJo_i_1218, 0x01) | ||||
| //     return(validateJo_i_1218, 0x20) | ||||
| //     mstore(validateJo_i_1218, 404) | ||||
| //     revert(validateJo_i_1218, 0x20) | ||||
| //     function validatePairing(t2) | ||||
| //     { | ||||
| //         let t2_x_1 := calldataload(t2) | ||||
|  | ||||
| @ -21,8 +21,8 @@ | ||||
| // { | ||||
| //     let allocate__19 := 0x40 | ||||
| //     mstore(allocate__19, add(mload(allocate__19), 0x20)) | ||||
| //     let allocate_p_35_39 := mload(allocate__19) | ||||
| //     mstore(allocate__19, add(allocate_p_35_39, allocate__19)) | ||||
| //     mstore(add(allocate_p_35_39, 96), 2) | ||||
| //     let allocate_p_33_37 := mload(allocate__19) | ||||
| //     mstore(allocate__19, add(allocate_p_33_37, allocate__19)) | ||||
| //     mstore(add(allocate_p_33_37, 96), 2) | ||||
| //     mstore(allocate__19, 0x20) | ||||
| // } | ||||
|  | ||||
| @ -0,0 +1,10 @@ | ||||
| { | ||||
|   let x := 8 | ||||
|   let y := calldataload(calldataload(9)) | ||||
|   mstore(y, add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(y, 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) | ||||
| } | ||||
| // ---- | ||||
| // stackCompressor | ||||
| // { | ||||
| //     mstore(calldataload(calldataload(9)), add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(calldataload(calldataload(9)), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) | ||||
| // } | ||||
| @ -0,0 +1,16 @@ | ||||
| { | ||||
|   let x := 8 | ||||
|   function f() { | ||||
|     let y := calldataload(calldataload(9)) | ||||
|     mstore(y, add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(y, 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) | ||||
|   } | ||||
| } | ||||
| // ---- | ||||
| // stackCompressor | ||||
| // { | ||||
| //     let x := 8 | ||||
| //     function f() | ||||
| //     { | ||||
| //         mstore(calldataload(calldataload(9)), add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(calldataload(calldataload(9)), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) | ||||
| //     } | ||||
| // } | ||||
							
								
								
									
										13
									
								
								test/libyul/yulOptimizerTests/stackCompressor/noInline.yul
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								test/libyul/yulOptimizerTests/stackCompressor/noInline.yul
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| { | ||||
|   let x := 8 | ||||
|   function f() { let y := 9 } | ||||
| } | ||||
| // ---- | ||||
| // stackCompressor | ||||
| // { | ||||
| //     let x := 8 | ||||
| //     function f() | ||||
| //     { | ||||
| //         let y := 9 | ||||
| //     } | ||||
| // } | ||||
| @ -48,6 +48,7 @@ | ||||
| #include <libyul/optimiser/RedundantAssignEliminator.h> | ||||
| #include <libyul/optimiser/SSAReverser.h> | ||||
| #include <libyul/optimiser/SSATransform.h> | ||||
| #include <libyul/optimiser/StackCompressor.h> | ||||
| #include <libyul/optimiser/StructuralSimplifier.h> | ||||
| #include <libyul/optimiser/VarDeclInitializer.h> | ||||
| 
 | ||||
| @ -130,7 +131,8 @@ public: | ||||
| 			cout << "(q)quit/(f)flatten/(c)se/initialize var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl; | ||||
| 			cout << "  (e)xpr inline/(i)nline/(s)implify/(u)nusedprune/ss(a) transform/" << endl; | ||||
| 			cout << "  (r)edundant assign elim./re(m)aterializer/f(o)r-loop-pre-rewriter/" << endl; | ||||
| 			cout << "  s(t)ructural simplifier/equi(v)alent function combiner/ssa re(V)erser? " << endl; | ||||
| 			cout << "  s(t)ructural simplifier/equi(v)alent function combiner/ssa re(V)erser/? " << endl; | ||||
| 			cout << "  stack com(p)ressor? " << endl; | ||||
| 			cout.flush(); | ||||
| 			int option = readStandardInputChar(); | ||||
| 			cout << ' ' << char(option) << endl; | ||||
| @ -192,6 +194,9 @@ public: | ||||
| 			case 'V': | ||||
| 				SSAReverser::run(*m_ast); | ||||
| 				break; | ||||
| 			case 'p': | ||||
| 				StackCompressor::run(m_dialect, *m_ast); | ||||
| 				break; | ||||
| 			default: | ||||
| 				cout << "Unknown option." << endl; | ||||
| 			} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user