mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #6396 from ethereum/optSetForAsmStack
Make optimiser settings available to assembly stack.
This commit is contained in:
		
						commit
						f9820adb5e
					
				| @ -863,7 +863,11 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) | ||||
| 
 | ||||
| 	Json::Value output = Json::objectValue; | ||||
| 
 | ||||
| 	AssemblyStack stack(_inputsAndSettings.evmVersion, AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		_inputsAndSettings.evmVersion, | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		_inputsAndSettings.optimiserSettings | ||||
| 	); | ||||
| 	string const& sourceName = _inputsAndSettings.sources.begin()->first; | ||||
| 	string const& sourceContents = _inputsAndSettings.sources.begin()->second; | ||||
| 
 | ||||
| @ -899,13 +903,9 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) | ||||
| 	if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "ir")) | ||||
| 		output["contracts"][sourceName][contractName]["ir"] = stack.print(); | ||||
| 
 | ||||
| 	if (_inputsAndSettings.optimiserSettings.runYulOptimiser) | ||||
| 		stack.optimize(); | ||||
| 	stack.optimize(); | ||||
| 
 | ||||
| 	MachineAssemblyObject object = stack.assemble( | ||||
| 		AssemblyStack::Machine::EVM, | ||||
| 		_inputsAndSettings.optimiserSettings.optimizeStackAllocation | ||||
| 	); | ||||
| 	MachineAssemblyObject object = stack.assemble(AssemblyStack::Machine::EVM); | ||||
| 
 | ||||
| 	if (isArtifactRequested( | ||||
| 		_inputsAndSettings.outputSelection, | ||||
|  | ||||
| @ -34,6 +34,8 @@ | ||||
| #include <libyul/ObjectParser.h> | ||||
| #include <libyul/optimiser/Suite.h> | ||||
| 
 | ||||
| #include <libsolidity/interface/OptimiserSettings.h> | ||||
| 
 | ||||
| #include <libevmasm/Assembly.h> | ||||
| #include <liblangutil/Scanner.h> | ||||
| 
 | ||||
| @ -83,9 +85,13 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string | ||||
| 
 | ||||
| void AssemblyStack::optimize() | ||||
| { | ||||
| 	if (!m_optimiserSettings.runYulOptimiser) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (m_language != Language::StrictAssembly) | ||||
| 		solUnimplemented("Optimizer for both loose assembly and Yul is not yet implemented"); | ||||
| 	solAssert(m_analysisSuccessful, "Analysis was not successful."); | ||||
| 
 | ||||
| 	m_analysisSuccessful = false; | ||||
| 	solAssert(m_parserResult, ""); | ||||
| 	optimize(*m_parserResult); | ||||
| @ -135,13 +141,15 @@ void AssemblyStack::optimize(Object& _object) | ||||
| 	for (auto& subNode: _object.subObjects) | ||||
| 		if (auto subObject = dynamic_cast<Object*>(subNode.get())) | ||||
| 			optimize(*subObject); | ||||
| 	// TODO: Store this as setting - it should be the same as the flag passed to
 | ||||
| 	// ::assemble(...)
 | ||||
| 	bool optimizeStackAllocation = false; | ||||
| 	OptimiserSuite::run(languageToDialect(m_language, m_evmVersion), *_object.code, *_object.analysisInfo, optimizeStackAllocation); | ||||
| 	OptimiserSuite::run( | ||||
| 		languageToDialect(m_language, m_evmVersion), | ||||
| 		*_object.code, | ||||
| 		*_object.analysisInfo, | ||||
| 		m_optimiserSettings.optimizeStackAllocation | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| MachineAssemblyObject AssemblyStack::assemble(Machine _machine, bool _optimize) const | ||||
| MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const | ||||
| { | ||||
| 	solAssert(m_analysisSuccessful, ""); | ||||
| 	solAssert(m_parserResult, ""); | ||||
| @ -155,7 +163,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine, bool _optimize) | ||||
| 		MachineAssemblyObject object; | ||||
| 		dev::eth::Assembly assembly; | ||||
| 		EthAssemblyAdapter adapter(assembly); | ||||
| 		compileEVM(adapter, false, _optimize); | ||||
| 		compileEVM(adapter, false, m_optimiserSettings.optimizeStackAllocation); | ||||
| 		object.bytecode = make_shared<dev::eth::LinkerObject>(assembly.assemble()); | ||||
| 		object.assembly = assembly.assemblyString(); | ||||
| 		return object; | ||||
| @ -164,7 +172,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine, bool _optimize) | ||||
| 	{ | ||||
| 		MachineAssemblyObject object; | ||||
| 		EVMAssembly assembly(true); | ||||
| 		compileEVM(assembly, true, _optimize); | ||||
| 		compileEVM(assembly, true, m_optimiserSettings.optimizeStackAllocation); | ||||
| 		object.bytecode = make_shared<dev::eth::LinkerObject>(assembly.finalize()); | ||||
| 		/// TODO: fill out text representation
 | ||||
| 		return object; | ||||
|  | ||||
| @ -27,6 +27,8 @@ | ||||
| #include <libyul/Object.h> | ||||
| #include <libyul/ObjectParser.h> | ||||
| 
 | ||||
| #include <libsolidity/interface/OptimiserSettings.h> | ||||
| 
 | ||||
| #include <libevmasm/LinkerObject.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| @ -58,8 +60,14 @@ public: | ||||
| 	enum class Language { Yul, Assembly, StrictAssembly }; | ||||
| 	enum class Machine { EVM, EVM15, eWasm }; | ||||
| 
 | ||||
| 	explicit AssemblyStack(langutil::EVMVersion _evmVersion = langutil::EVMVersion(), Language _language = Language::Assembly): | ||||
| 		m_language(_language), m_evmVersion(_evmVersion), m_errorReporter(m_errors) | ||||
| 	AssemblyStack(): | ||||
| 		AssemblyStack(langutil::EVMVersion{}, Language::Assembly, dev::solidity::OptimiserSettings::none()) | ||||
| 	{} | ||||
| 	AssemblyStack(langutil::EVMVersion _evmVersion, Language _language, dev::solidity::OptimiserSettings _optimiserSettings): | ||||
| 		m_language(_language), | ||||
| 		m_evmVersion(_evmVersion), | ||||
| 		m_optimiserSettings(std::move(_optimiserSettings)), | ||||
| 		m_errorReporter(m_errors) | ||||
| 	{} | ||||
| 
 | ||||
| 	/// @returns the scanner used during parsing
 | ||||
| @ -70,11 +78,11 @@ public: | ||||
| 	bool parseAndAnalyze(std::string const& _sourceName, std::string const& _source); | ||||
| 
 | ||||
| 	/// Run the optimizer suite. Can only be used with Yul or strict assembly.
 | ||||
| 	/// If the settings (see constructor) disabled the optimizer, nothing is done here.
 | ||||
| 	void optimize(); | ||||
| 
 | ||||
| 	/// Run the assembly step (should only be called after parseAndAnalyze).
 | ||||
| 	/// @param _optimize does not run the optimizer but performs optimized code generation.
 | ||||
| 	MachineAssemblyObject assemble(Machine _machine, bool _optimize) const; | ||||
| 	MachineAssemblyObject assemble(Machine _machine) const; | ||||
| 
 | ||||
| 	/// @returns the errors generated during parsing, analysis (and potentially assembly).
 | ||||
| 	langutil::ErrorList const& errors() const { return m_errors; } | ||||
| @ -95,6 +103,7 @@ private: | ||||
| 
 | ||||
| 	Language m_language = Language::Assembly; | ||||
| 	langutil::EVMVersion m_evmVersion; | ||||
| 	dev::solidity::OptimiserSettings m_optimiserSettings; | ||||
| 
 | ||||
| 	std::shared_ptr<langutil::Scanner> m_scanner; | ||||
| 
 | ||||
|  | ||||
| @ -1239,12 +1239,16 @@ bool CommandLineInterface::assemble( | ||||
| 	map<string, yul::AssemblyStack> assemblyStacks; | ||||
| 	for (auto const& src: m_sourceCodes) | ||||
| 	{ | ||||
| 		auto& stack = assemblyStacks[src.first] = yul::AssemblyStack(m_evmVersion, _language); | ||||
| 		auto& stack = assemblyStacks[src.first] = yul::AssemblyStack( | ||||
| 			m_evmVersion, | ||||
| 			_language, | ||||
| 			_optimize ? OptimiserSettings::full() : OptimiserSettings::minimal() | ||||
| 		); | ||||
| 		try | ||||
| 		{ | ||||
| 			if (!stack.parseAndAnalyze(src.first, src.second)) | ||||
| 				successful = false; | ||||
| 			else if (_optimize) | ||||
| 			else | ||||
| 				stack.optimize(); | ||||
| 		} | ||||
| 		catch (Exception const& _exception) | ||||
| @ -1298,7 +1302,7 @@ bool CommandLineInterface::assemble( | ||||
| 		yul::MachineAssemblyObject object; | ||||
| 		try | ||||
| 		{ | ||||
| 			object = stack.assemble(_targetMachine, _optimize); | ||||
| 			object = stack.assemble(_targetMachine); | ||||
| 		} | ||||
| 		catch (Exception const& _exception) | ||||
| 		{ | ||||
|  | ||||
| @ -61,14 +61,13 @@ boost::optional<Error> parseAndReturnFirstError( | ||||
| 	AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM | ||||
| ) | ||||
| { | ||||
| 	AssemblyStack stack(dev::test::Options::get().evmVersion(), _language); | ||||
| 	AssemblyStack stack(dev::test::Options::get().evmVersion(), _language, dev::solidity::OptimiserSettings::none()); | ||||
| 	bool success = false; | ||||
| 	try | ||||
| 	{ | ||||
| 		success = stack.parseAndAnalyze("", _source); | ||||
| 		bool const optimize = false; | ||||
| 		if (success && _assemble) | ||||
| 			stack.assemble(_machine, optimize); | ||||
| 			stack.assemble(_machine); | ||||
| 	} | ||||
| 	catch (FatalError const&) | ||||
| 	{ | ||||
| @ -124,7 +123,7 @@ Error expectError( | ||||
| 
 | ||||
| void parsePrintCompare(string const& _source, bool _canWarn = false) | ||||
| { | ||||
| 	AssemblyStack stack(dev::test::Options::get().evmVersion()); | ||||
| 	AssemblyStack stack(dev::test::Options::get().evmVersion(), AssemblyStack::Language::Assembly, OptimiserSettings::none()); | ||||
| 	BOOST_REQUIRE(stack.parseAndAnalyze("", _source)); | ||||
| 	if (_canWarn) | ||||
| 		BOOST_REQUIRE(Error::containsOnlyWarnings(stack.errors())); | ||||
| @ -598,7 +597,7 @@ BOOST_AUTO_TEST_CASE(print_string_literal_unicode) | ||||
| { | ||||
| 	string source = "{ let x := \"\\u1bac\" }"; | ||||
| 	string parsed = "object \"object\" {\n    code {\n        let x := \"\\xe1\\xae\\xac\"\n    }\n}\n"; | ||||
| 	AssemblyStack stack(dev::test::Options::get().evmVersion()); | ||||
| 	AssemblyStack stack(dev::test::Options::get().evmVersion(), AssemblyStack::Language::Assembly, OptimiserSettings::none()); | ||||
| 	BOOST_REQUIRE(stack.parseAndAnalyze("", source)); | ||||
| 	BOOST_REQUIRE(stack.errors().empty()); | ||||
| 	BOOST_CHECK_EQUAL(stack.print(), parsed); | ||||
|  | ||||
| @ -65,7 +65,10 @@ pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(strin | ||||
| { | ||||
| 	AssemblyStack stack( | ||||
| 		dev::test::Options::get().evmVersion(), | ||||
| 		_yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly | ||||
| 		_yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::test::Options::get().optimize ? | ||||
| 			dev::solidity::OptimiserSettings::standard() : | ||||
| 			dev::solidity::OptimiserSettings::minimal() | ||||
| 	); | ||||
| 	if (!stack.parseAndAnalyze("", _source) || !stack.errors().empty()) | ||||
| 		BOOST_FAIL("Invalid source."); | ||||
|  | ||||
| @ -64,17 +64,20 @@ ObjectCompilerTest::ObjectCompilerTest(string const& _filename) | ||||
| 
 | ||||
| bool ObjectCompilerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) | ||||
| { | ||||
| 	AssemblyStack stack(EVMVersion(), AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		EVMVersion(), | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		m_optimize ? OptimiserSettings::full() : OptimiserSettings::minimal() | ||||
| 	); | ||||
| 	if (!stack.parseAndAnalyze("source", m_source)) | ||||
| 	{ | ||||
| 		AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; | ||||
| 		printErrors(_stream, stack.errors()); | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (m_optimize) | ||||
| 		stack.optimize(); | ||||
| 	stack.optimize(); | ||||
| 
 | ||||
| 	MachineAssemblyObject obj = stack.assemble(AssemblyStack::Machine::EVM, m_optimize); | ||||
| 	MachineAssemblyObject obj = stack.assemble(AssemblyStack::Machine::EVM); | ||||
| 	solAssert(obj.bytecode, ""); | ||||
| 
 | ||||
| 	m_obtainedResult = "Assembly:\n" + obj.assembly; | ||||
|  | ||||
| @ -25,6 +25,8 @@ | ||||
| 
 | ||||
| #include <libyul/AssemblyStack.h> | ||||
| 
 | ||||
| #include <libsolidity/interface/OptimiserSettings.h> | ||||
| 
 | ||||
| #include <boost/optional.hpp> | ||||
| #include <boost/algorithm/string/replace.hpp> | ||||
| 
 | ||||
| @ -48,7 +50,8 @@ std::pair<bool, ErrorList> parse(string const& _source) | ||||
| 	{ | ||||
| 		AssemblyStack asmStack( | ||||
| 			dev::test::Options::get().evmVersion(), | ||||
| 			AssemblyStack::Language::StrictAssembly | ||||
| 			AssemblyStack::Language::StrictAssembly, | ||||
| 			dev::solidity::OptimiserSettings::none() | ||||
| 		); | ||||
| 		bool success = asmStack.parseAndAnalyze("source", _source); | ||||
| 		return {success, asmStack.errors()}; | ||||
| @ -242,7 +245,8 @@ BOOST_AUTO_TEST_CASE(to_string) | ||||
| 	expectation = boost::replace_all_copy(expectation, "\t", "    "); | ||||
| 	AssemblyStack asmStack( | ||||
| 		dev::test::Options::get().evmVersion(), | ||||
| 		AssemblyStack::Language::StrictAssembly | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::solidity::OptimiserSettings::none() | ||||
| 	); | ||||
| 	BOOST_REQUIRE(asmStack.parseAndAnalyze("source", code)); | ||||
| 	BOOST_CHECK_EQUAL(asmStack.print(), expectation); | ||||
|  | ||||
| @ -34,9 +34,12 @@ namespace | ||||
| { | ||||
| string assemble(string const& _input) | ||||
| { | ||||
| 	AssemblyStack asmStack; | ||||
| 	dev::solidity::OptimiserSettings settings = dev::solidity::OptimiserSettings::full(); | ||||
| 	settings.runYulOptimiser = false; | ||||
| 	settings.optimizeStackAllocation = true; | ||||
| 	AssemblyStack asmStack(langutil::EVMVersion{}, AssemblyStack::Language::StrictAssembly, settings); | ||||
| 	BOOST_REQUIRE_MESSAGE(asmStack.parseAndAnalyze("", _input), "Source did not parse: " + _input); | ||||
| 	return dev::eth::disassemble(asmStack.assemble(AssemblyStack::Machine::EVM, true).bytecode->bytecode); | ||||
| 	return dev::eth::disassemble(asmStack.assemble(AssemblyStack::Machine::EVM).bytecode->bytecode); | ||||
| } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -107,7 +107,11 @@ void YulInterpreterTest::printIndented(ostream& _stream, string const& _output, | ||||
| 
 | ||||
| bool YulInterpreterTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted) | ||||
| { | ||||
| 	AssemblyStack stack(dev::test::Options::get().evmVersion(), AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		dev::test::Options::get().evmVersion(), | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::solidity::OptimiserSettings::none() | ||||
| 	); | ||||
| 	if (stack.parseAndAnalyze("", m_source)) | ||||
| 	{ | ||||
| 		m_ast = stack.parserResult()->code; | ||||
|  | ||||
| @ -296,7 +296,8 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c | ||||
| { | ||||
| 	AssemblyStack stack( | ||||
| 		dev::test::Options::get().evmVersion(), | ||||
| 		m_yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly | ||||
| 		m_yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::solidity::OptimiserSettings::none() | ||||
| 	); | ||||
| 	if (!stack.parseAndAnalyze("", m_source) || !stack.errors().empty()) | ||||
| 	{ | ||||
|  | ||||
| @ -28,14 +28,18 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	string input(reinterpret_cast<char const*>(_data), _size); | ||||
| 	AssemblyStack stack(langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		langutil::EVMVersion(), | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::solidity::OptimiserSettings::full() | ||||
| 	); | ||||
| 
 | ||||
| 	if (!stack.parseAndAnalyze("source", input)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	try | ||||
| 	{ | ||||
| 		MachineAssemblyObject obj = stack.assemble(AssemblyStack::Machine::EVM, /*optimize=*/true); | ||||
| 		MachineAssemblyObject obj = stack.assemble(AssemblyStack::Machine::EVM); | ||||
| 		solAssert(obj.bytecode, ""); | ||||
| 	} | ||||
| 	catch (StackTooDeepError const&) | ||||
|  | ||||
| @ -55,11 +55,18 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) | ||||
| 	})) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	AssemblyStack stack(EVMVersion::petersburg(), AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		EVMVersion::petersburg(), | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::solidity::OptimiserSettings::full() | ||||
| 	); | ||||
| 	try | ||||
| 	{ | ||||
| 		if (!stack.parseAndAnalyze("source", input) || !stack.parserResult()->code || | ||||
| 			!stack.parserResult()->analysisInfo) | ||||
| 		if ( | ||||
| 			!stack.parseAndAnalyze("source", input) || | ||||
| 			!stack.parserResult()->code || | ||||
| 			!stack.parserResult()->analysisInfo | ||||
| 		) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	catch (Exception const&) | ||||
|  | ||||
| @ -27,7 +27,11 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	string input(reinterpret_cast<char const*>(_data), _size); | ||||
| 	AssemblyStack stack(langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		langutil::EVMVersion(), | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::solidity::OptimiserSettings::full() | ||||
| 	); | ||||
| 
 | ||||
| 	if (!stack.parseAndAnalyze("source", input)) | ||||
| 		return 0; | ||||
|  | ||||
| @ -46,7 +46,11 @@ DEFINE_PROTO_FUZZER(Function const& _input) | ||||
| 	} | ||||
| 
 | ||||
| 	// AssemblyStack entry point
 | ||||
| 	AssemblyStack stack(langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		langutil::EVMVersion(), | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::solidity::OptimiserSettings::full() | ||||
| 	); | ||||
| 
 | ||||
| 	// Parse protobuf mutated YUL code
 | ||||
| 	if (!stack.parseAndAnalyze("source", yul_source)) | ||||
|  | ||||
| @ -52,7 +52,11 @@ DEFINE_PROTO_FUZZER(Function const& _input) | ||||
| 	} | ||||
| 
 | ||||
| 	// AssemblyStack entry point
 | ||||
| 	AssemblyStack stack(langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		langutil::EVMVersion(), | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		dev::solidity::OptimiserSettings::full() | ||||
| 	); | ||||
| 
 | ||||
| 	try | ||||
| 	{ | ||||
|  | ||||
| @ -63,7 +63,11 @@ void printErrors(ErrorList const& _errors) | ||||
| 
 | ||||
| pair<shared_ptr<Block>, shared_ptr<AsmAnalysisInfo>> parse(string const& _source) | ||||
| { | ||||
| 	AssemblyStack stack(langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly); | ||||
| 	AssemblyStack stack( | ||||
| 		langutil::EVMVersion(), | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		solidity::OptimiserSettings::none() | ||||
| 	); | ||||
| 	if (stack.parseAndAnalyze("--INPUT--", _source)) | ||||
| 	{ | ||||
| 		yulAssert(stack.errors().empty(), "Parsed successfully but had errors."); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user