diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 3bc638f82..1902880a7 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -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, diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index a9d199279..db669d148 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -34,6 +34,8 @@ #include #include +#include + #include #include @@ -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(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(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(assembly.finalize()); /// TODO: fill out text representation return object; diff --git a/libyul/AssemblyStack.h b/libyul/AssemblyStack.h index 8a30ebfcb..fb6686c39 100644 --- a/libyul/AssemblyStack.h +++ b/libyul/AssemblyStack.h @@ -27,6 +27,8 @@ #include #include +#include + #include #include @@ -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 m_scanner; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index c461d4f5e..9de8b70b8 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -1239,12 +1239,16 @@ bool CommandLineInterface::assemble( map 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) { diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 149f7679c..0479be2f3 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -61,14 +61,13 @@ boost::optional 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); diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index 770b4a791..e4ee599c4 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -65,7 +65,10 @@ pair, shared_ptr> 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."); diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index 66b0d0545..0363cc298 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -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; diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp index fc05a3e7a..c54cee762 100644 --- a/test/libyul/ObjectParser.cpp +++ b/test/libyul/ObjectParser.cpp @@ -25,6 +25,8 @@ #include +#include + #include #include @@ -48,7 +50,8 @@ std::pair 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); diff --git a/test/libyul/StackReuseCodegen.cpp b/test/libyul/StackReuseCodegen.cpp index d4c82b2e4..d386c83f8 100644 --- a/test/libyul/StackReuseCodegen.cpp +++ b/test/libyul/StackReuseCodegen.cpp @@ -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); } } diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index 4a699ca90..125fb70de 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -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; diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 7d05ea9f5..c96857c73 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -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()) { diff --git a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp index 11b60638b..fe9f9609e 100644 --- a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp @@ -28,14 +28,18 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) return 0; string input(reinterpret_cast(_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&) diff --git a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp index 6aadbfa4f..588644841 100644 --- a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp @@ -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&) diff --git a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp index 05e70e8ab..28e1984b2 100644 --- a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp @@ -27,7 +27,11 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) return 0; string input(reinterpret_cast(_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; diff --git a/test/tools/ossfuzz/yulProtoFuzzer.cpp b/test/tools/ossfuzz/yulProtoFuzzer.cpp index a44e8aacf..c7b34872d 100644 --- a/test/tools/ossfuzz/yulProtoFuzzer.cpp +++ b/test/tools/ossfuzz/yulProtoFuzzer.cpp @@ -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)) diff --git a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp index e4628f9fb..72e33d848 100644 --- a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp @@ -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 { diff --git a/test/tools/yulrun.cpp b/test/tools/yulrun.cpp index 6dffb9ec2..acb198c74 100644 --- a/test/tools/yulrun.cpp +++ b/test/tools/yulrun.cpp @@ -63,7 +63,11 @@ void printErrors(ErrorList const& _errors) pair, shared_ptr> 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.");