diff --git a/libyul/ObjectParser.cpp b/libyul/ObjectParser.cpp index a02b9660b978..fc1e71dd1152 100644 --- a/libyul/ObjectParser.cpp +++ b/libyul/ObjectParser.cpp @@ -171,7 +171,7 @@ std::optional ObjectParser::tryParseSourceNameMapping() const std::shared_ptr ObjectParser::parseBlock(std::optional _sourceNames) { - Parser parser(m_errorReporter, m_dialect, std::move(_sourceNames)); + Parser parser(m_errorReporter, m_dialect, std::move(_sourceNames), m_debugAttributeCache); std::shared_ptr block = parser.parseInline(m_scanner); yulAssert(block || m_errorReporter.hasErrors(), "Invalid block but no error!"); return block; diff --git a/libyul/ObjectParser.h b/libyul/ObjectParser.h index 716a191ea878..7a7cc100dba7 100644 --- a/libyul/ObjectParser.h +++ b/libyul/ObjectParser.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ #include #include +#include namespace solidity::langutil { @@ -46,8 +48,8 @@ namespace solidity::yul class ObjectParser: public langutil::ParserBase { public: - explicit ObjectParser(langutil::ErrorReporter& _errorReporter, Dialect const& _dialect): - ParserBase(_errorReporter), m_dialect(_dialect) {} + explicit ObjectParser(langutil::ErrorReporter& _errorReporter, Dialect const& _dialect, Parser::DebugAttributeCache::Ptr _debugAttributeCache = {}): + ParserBase(_errorReporter), m_dialect(_dialect), m_debugAttributeCache(std::move(_debugAttributeCache)) {} /// Parses a Yul object. /// Falls back to code-only parsing if the source starts with `{`. @@ -67,6 +69,7 @@ class ObjectParser: public langutil::ParserBase void addNamedSubObject(Object& _container, YulString _name, std::shared_ptr _subObject); Dialect const& m_dialect; + Parser::DebugAttributeCache::Ptr m_debugAttributeCache; }; } diff --git a/libyul/optimiser/FunctionGrouper.h b/libyul/optimiser/FunctionGrouper.h index 57ea80cac9f7..be8102b311e2 100644 --- a/libyul/optimiser/FunctionGrouper.h +++ b/libyul/optimiser/FunctionGrouper.h @@ -23,6 +23,9 @@ #pragma once #include +#include + +#include namespace solidity::yul { @@ -41,14 +44,22 @@ class FunctionGrouper { public: static constexpr char const* name{"FunctionGrouper"}; - static void run(OptimiserStepContext&, Block& _ast) { FunctionGrouper{}(_ast); } + static void run(OptimiserStepContext&, Block& _ast, Parser::DebugAttributeCache::Ptr _debugAttributeCache = {}) + { + FunctionGrouper{std::move(_debugAttributeCache)}(_ast); + } void operator()(Block& _block); private: - FunctionGrouper() = default; + explicit FunctionGrouper(Parser::DebugAttributeCache::Ptr _debugAttributeCache) + : m_debugAttributeCache(std::move(_debugAttributeCache)) + { + } bool alreadyGrouped(Block const& _block); + + Parser::DebugAttributeCache::Ptr m_debugAttributeCache; }; } diff --git a/libyul/optimiser/NameDisplacer.h b/libyul/optimiser/NameDisplacer.h index 336dd04e42de..476140f26fd7 100644 --- a/libyul/optimiser/NameDisplacer.h +++ b/libyul/optimiser/NameDisplacer.h @@ -21,11 +21,14 @@ #pragma once +#include #include #include + #include #include +#include namespace solidity::yul { @@ -44,10 +47,12 @@ class NameDisplacer: public ASTModifier public: explicit NameDisplacer( NameDispenser& _dispenser, - std::set const& _namesToFree + std::set const& _namesToFree, + Parser::DebugAttributeCache::Ptr _debugAttributeCache = {} ): m_nameDispenser(_dispenser), - m_namesToFree(_namesToFree) + m_namesToFree(_namesToFree), + m_debugAttributeCache(std::move(_debugAttributeCache)) { for (YulString n: _namesToFree) m_nameDispenser.markUsed(n); @@ -71,6 +76,7 @@ class NameDisplacer: public ASTModifier NameDispenser& m_nameDispenser; std::set const& m_namesToFree; std::map m_translations; + Parser::DebugAttributeCache::Ptr m_debugAttributeCache; }; } diff --git a/libyul/optimiser/OptimiserStep.h b/libyul/optimiser/OptimiserStep.h index e3e5fe4c605d..674a7940c81c 100644 --- a/libyul/optimiser/OptimiserStep.h +++ b/libyul/optimiser/OptimiserStep.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include #include @@ -39,6 +40,7 @@ struct OptimiserStepContext std::set const& reservedIdentifiers; /// The value nullopt represents creation code std::optional expectedExecutionsPerDeployment; + Parser::DebugAttributeCache::Ptr debugAttributeCache; }; diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 83bc0370092b..e8bea10d9545 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -141,7 +141,8 @@ void OptimiserSuite::run( std::string_view _optimisationSequence, std::string_view _optimisationCleanupSequence, std::optional _expectedExecutionsPerDeployment, - std::set const& _externallyUsedIdentifiers + std::set const& _externallyUsedIdentifiers, + Parser::DebugAttributeCache::Ptr _debugAttributeCache ) { EVMDialect const* evmDialect = dynamic_cast(&_dialect); @@ -161,7 +162,7 @@ void OptimiserSuite::run( Block& ast = *_object.code; NameDispenser dispenser{_dialect, ast, reservedIdentifiers}; - OptimiserStepContext context{_dialect, dispenser, reservedIdentifiers, _expectedExecutionsPerDeployment}; + OptimiserStepContext context{_dialect, dispenser, reservedIdentifiers, _expectedExecutionsPerDeployment, _debugAttributeCache}; OptimiserSuite suite(context, Debug::None); diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h index 6e3886da3b2d..9d2e7c6436ee 100644 --- a/libyul/optimiser/Suite.h +++ b/libyul/optimiser/Suite.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -70,7 +71,8 @@ class OptimiserSuite std::string_view _optimisationSequence, std::string_view _optimisationCleanupSequence, std::optional _expectedExecutionsPerDeployment, - std::set const& _externallyUsedIdentifiers = {} + std::set const& _externallyUsedIdentifiers = {}, + Parser::DebugAttributeCache::Ptr _debugAttributeCache = {} ); /// Ensures that specified sequence of step abbreviations is well-formed and can be executed. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a264ef0c1160..62da68b288dd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -159,6 +159,8 @@ set(libyul_sources libyul/SyntaxTest.cpp libyul/YulInterpreterTest.cpp libyul/YulInterpreterTest.h + libyul/YulOptimizerAssemblyTest.cpp + libyul/YulOptimizerAssemblyTest.h libyul/YulOptimizerTest.cpp libyul/YulOptimizerTest.h libyul/YulOptimizerTestCommon.cpp diff --git a/test/InteractiveTests.h b/test/InteractiveTests.h index 42e20d7e3919..9e44a5ba3bf5 100644 --- a/test/InteractiveTests.h +++ b/test/InteractiveTests.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ Testsuite const g_interactiveTestsuites[] = { /* Title Path Subpath SMT NeedsVM Creator function */ {"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create}, + {"Yul Optimizer with Assembly", "libyul", "yulOptimizerAssemblyTests", false, false, &yul::test::YulOptimizerAssemblyTest::create}, {"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create}, {"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create}, {"Yul Control Flow Graph", "libyul", "yulControlFlowGraph", false, false, &yul::test::ControlFlowGraphTest::create}, diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index 10d7d12adddd..2bcf388ec563 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -33,9 +33,13 @@ #include #include #include +#include + +#include #include +#include #include using namespace solidity; @@ -69,13 +73,14 @@ std::pair, std::shared_ptr> yul::te std::pair, std::shared_ptr> yul::test::parse( std::string const& _source, Dialect const& _dialect, - ErrorList& _errors + ErrorList& _errors, + Parser::DebugAttributeCache::Ptr _debugAttributeCache ) { ErrorReporter errorReporter(_errors); CharStream stream(_source, ""); std::shared_ptr scanner = std::make_shared(stream); - std::shared_ptr parserResult = yul::ObjectParser(errorReporter, _dialect).parse(scanner, false); + std::shared_ptr parserResult = yul::ObjectParser(errorReporter, _dialect, std::move(_debugAttributeCache)).parse(scanner, false); if (!parserResult) return {}; if (!parserResult->code || errorReporter.hasErrors()) @@ -88,6 +93,30 @@ std::pair, std::shared_ptr> yul::t return {std::move(parserResult), std::move(analysisInfo)}; } +std::pair, std::shared_ptr> yul::test::parse( + std::ostream& _stream, + std::string const& _linePrefix, + bool const _formatted, + std::string const& _source, + Dialect const& _dialect, + Parser::DebugAttributeCache::Ptr _debugAttributeCache +) +{ + ErrorList errors; + std::shared_ptr object; + std::shared_ptr analysisInfo; + std::tie(object, analysisInfo) = yul::test::parse(_source, _dialect, errors, _debugAttributeCache); + if (!object || !analysisInfo || Error::containsErrors(errors)) + { + util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; + CharStream charStream(_source, ""); + SourceReferenceFormatter{_stream, SingletonCharStreamProvider(charStream), true, false} + .printErrorInformation(errors); + return {}; + } + return {std::move(object), std::move(analysisInfo)}; +} + yul::Block yul::test::disambiguate(std::string const& _source, bool _yul) { auto result = parse(_source, _yul); diff --git a/test/libyul/Common.h b/test/libyul/Common.h index f6c63feb9bb2..45b3bdc0fd73 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -27,6 +27,8 @@ #include #include +#include + namespace solidity::langutil { class Error; @@ -48,7 +50,16 @@ std::pair, std::shared_ptr> parse(std::string const& _source, bool _yul = true); std::pair, std::shared_ptr> -parse(std::string const& _source, Dialect const& _dialect, langutil::ErrorList& _errors); +parse(std::string const& _source, Dialect const& _dialect, langutil::ErrorList& _errors, Parser::DebugAttributeCache::Ptr _debugAttributeCache = {}); + +std::pair, std::shared_ptr> parse( + std::ostream& _stream, + std::string const& _linePrefix, + bool const _formatted, + std::string const& _source, + Dialect const& _dialect, + Parser::DebugAttributeCache::Ptr _debugAttributeCache = {} +); Block disambiguate(std::string const& _source, bool _yul = true); std::string format(std::string const& _source, bool _yul = true); diff --git a/test/libyul/KnowledgeBaseTest.cpp b/test/libyul/KnowledgeBaseTest.cpp index b1dd0e6d19c5..7af0407097d5 100644 --- a/test/libyul/KnowledgeBaseTest.cpp +++ b/test/libyul/KnowledgeBaseTest.cpp @@ -50,7 +50,7 @@ class KnowledgeBaseTest NameDispenser dispenser(m_dialect, *m_object->code); std::set reserved; - OptimiserStepContext context{m_dialect, dispenser, reserved, 0}; + OptimiserStepContext context{m_dialect, dispenser, reserved, 0, {}}; CommonSubexpressionEliminator::run(context, *m_object->code); m_ssaValues(*m_object->code); diff --git a/test/libyul/YulOptimizerAssemblyTest.cpp b/test/libyul/YulOptimizerAssemblyTest.cpp new file mode 100644 index 000000000000..2e600c3d4dd3 --- /dev/null +++ b/test/libyul/YulOptimizerAssemblyTest.cpp @@ -0,0 +1,106 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace solidity; +using namespace solidity::util; +using namespace solidity::langutil; +using namespace solidity::yul; +using namespace solidity::yul::test; +using namespace solidity::frontend; +using namespace solidity::frontend::test; + +YulOptimizerAssemblyTest::YulOptimizerAssemblyTest(std::string const& _filename): + EVMVersionRestrictedTestCase(_filename) +{ + boost::filesystem::path path(_filename); + + if (path.empty() || std::next(path.begin()) == path.end() || std::next(std::next(path.begin())) == path.end()) + BOOST_THROW_EXCEPTION(std::runtime_error("Filename path has to contain a directory: \"" + _filename + "\".")); + m_optimizerStep = std::prev(std::prev(path.end()))->string(); + + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); +} + +TestCase::TestResult YulOptimizerAssemblyTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) +{ + std::shared_ptr object; + std::shared_ptr analysisInfo; + Parser::DebugAttributeCache::Ptr debugAttributeCache = std::make_shared(); + + Dialect const& dialect = test::dialect("evm", solidity::test::CommonOptions::get().evmVersion()); + std::tie(object, analysisInfo) = test::parse(_stream, _linePrefix, _formatted, m_source, dialect, debugAttributeCache); + if (!object) + return TestResult::FatalError; + + object->analysisInfo = analysisInfo; + YulOptimizerTestCommon tester(object, dialect); + tester.setStep(m_optimizerStep); + + if (!tester.runStep()) + { + AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Invalid optimizer step: " << m_optimizerStep << std::endl; + return TestResult::FatalError; + } + + auto const printed = (object->subObjects.empty() ? AsmPrinter{ dialect }(*object->code) : object->toString(&dialect)); + + m_obtainedResult = "step: " + m_optimizerStep + "\n\n" + printed + "\n"; + + *object->analysisInfo = AsmAnalyzer::analyzeStrictAssertCorrect(dialect, *object); + + evmasm::Assembly assembly{solidity::test::CommonOptions::get().evmVersion(), false, {}}; + EthAssemblyAdapter adapter(assembly); + EVMObjectCompiler::compile( + *object, + adapter, + EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion()), + false, // optimize - don't run any other optimization + solidity::test::CommonOptions::get().eofVersion() + ); + + m_obtainedResult += "\nAssembly:\n" + toString(assembly); + + return checkResult(_stream, _linePrefix, _formatted); +} diff --git a/test/libyul/YulOptimizerAssemblyTest.h b/test/libyul/YulOptimizerAssemblyTest.h new file mode 100644 index 000000000000..eeae052458fd --- /dev/null +++ b/test/libyul/YulOptimizerAssemblyTest.h @@ -0,0 +1,54 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +namespace solidity::langutil +{ +class Error; +using ErrorList = std::vector>; +} + +namespace solidity::yul +{ +struct AsmAnalysisInfo; +struct Object; +struct Dialect; +} + +namespace solidity::yul::test +{ + +class YulOptimizerAssemblyTest: public solidity::frontend::test::EVMVersionRestrictedTestCase +{ +public: + static std::unique_ptr create(Config const& _config) + { + return std::make_unique(_config.filename); + } + + explicit YulOptimizerAssemblyTest(std::string const& _filename); + + TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; +private: + std::string m_optimizerStep; +}; + +} diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 82e2549809e2..daa1393d0a19 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -26,9 +26,8 @@ #include #include -#include -#include #include +#include #include #include @@ -62,11 +61,11 @@ YulOptimizerTest::YulOptimizerTest(std::string const& _filename): TestCase::TestResult YulOptimizerTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) { - std::tie(m_object, m_analysisInfo) = parse(_stream, _linePrefix, _formatted, m_source); + soltestAssert(m_dialect, "Dialect not set."); + std::tie(m_object, m_analysisInfo) = parse(_stream, _linePrefix, _formatted, m_source, *m_dialect); if (!m_object) return TestResult::FatalError; - soltestAssert(m_dialect, "Dialect not set."); m_object->analysisInfo = m_analysisInfo; YulOptimizerTestCommon tester(m_object, *m_dialect); @@ -81,7 +80,7 @@ TestCase::TestResult YulOptimizerTest::run(std::ostream& _stream, std::string co auto const printed = (m_object->subObjects.empty() ? AsmPrinter{ *m_dialect }(*m_object->code) : m_object->toString(m_dialect)); // Re-parse new code for compilability - if (!std::get<0>(parse(_stream, _linePrefix, _formatted, printed))) + if (!std::get<0>(parse(_stream, _linePrefix, _formatted, printed, *m_dialect))) { util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN}) << _linePrefix << "Result after the optimiser:" << std::endl; @@ -94,25 +93,3 @@ TestCase::TestResult YulOptimizerTest::run(std::ostream& _stream, std::string co return checkResult(_stream, _linePrefix, _formatted); } -std::pair, std::shared_ptr> YulOptimizerTest::parse( - std::ostream& _stream, - std::string const& _linePrefix, - bool const _formatted, - std::string const& _source -) -{ - ErrorList errors; - soltestAssert(m_dialect, ""); - std::shared_ptr object; - std::shared_ptr analysisInfo; - std::tie(object, analysisInfo) = yul::test::parse(_source, *m_dialect, errors); - if (!object || !analysisInfo || Error::containsErrors(errors)) - { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; - CharStream charStream(_source, ""); - SourceReferenceFormatter{_stream, SingletonCharStreamProvider(charStream), true, false} - .printErrorInformation(errors); - return {}; - } - return {std::move(object), std::move(analysisInfo)}; -} diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index 832b5dfb8f7c..161114384a84 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -48,10 +48,6 @@ class YulOptimizerTest: public solidity::frontend::test::EVMVersionRestrictedTes TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; private: - std::pair, std::shared_ptr> parse( - std::ostream& _stream, std::string const& _linePrefix, bool const _formatted, std::string const& _source - ); - std::string m_optimizerStep; Dialect const* m_dialect = nullptr; diff --git a/test/libyul/YulOptimizerTestCommon.cpp b/test/libyul/YulOptimizerTestCommon.cpp index 091a9a0b6cff..a3d5f887682b 100644 --- a/test/libyul/YulOptimizerTestCommon.cpp +++ b/test/libyul/YulOptimizerTestCommon.cpp @@ -75,13 +75,16 @@ using namespace solidity::frontend; YulOptimizerTestCommon::YulOptimizerTestCommon( std::shared_ptr _obj, - Dialect const& _dialect + Dialect const& _dialect, + Parser::DebugAttributeCache::Ptr _debugAttributeCache ) { m_object = _obj; m_ast = m_object->code; m_analysisInfo = m_object->analysisInfo; m_dialect = &_dialect; + if (_debugAttributeCache != nullptr) + m_context->debugAttributeCache = std::move(_debugAttributeCache); m_namedSteps = { {"disambiguator", [&]() { disambiguate(); }}, @@ -442,7 +445,7 @@ std::shared_ptr YulOptimizerTestCommon::run() void YulOptimizerTestCommon::disambiguate() { - *m_object->code = std::get(Disambiguator(*m_dialect, *m_analysisInfo)(*m_object->code)); + *m_object->code = std::get(Disambiguator(*m_dialect, *m_analysisInfo, {})(*m_object->code)); m_analysisInfo.reset(); updateContext(); } @@ -454,6 +457,7 @@ void YulOptimizerTestCommon::updateContext() *m_dialect, *m_nameDispenser, m_reservedIdentifiers, - frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment + frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment, + m_debugAttributeCache }); } diff --git a/test/libyul/YulOptimizerTestCommon.h b/test/libyul/YulOptimizerTestCommon.h index 3dce998c56cc..a78291cdd7f7 100644 --- a/test/libyul/YulOptimizerTestCommon.h +++ b/test/libyul/YulOptimizerTestCommon.h @@ -18,6 +18,7 @@ #pragma once +#include #include #include @@ -40,7 +41,8 @@ class YulOptimizerTestCommon public: explicit YulOptimizerTestCommon( std::shared_ptr _obj, - Dialect const& _dialect + Dialect const& _dialect, + Parser::DebugAttributeCache::Ptr _debugAttributeCache = {} ); /// Sets optimiser step to be run to @param /// _optimiserStep. @@ -71,6 +73,8 @@ class YulOptimizerTestCommon std::shared_ptr m_ast; std::shared_ptr m_analysisInfo; std::map> m_namedSteps; + + Parser::DebugAttributeCache::Ptr m_debugAttributeCache; }; } diff --git a/test/libyul/yulOptimizerAssemblyTests/blockFlattener/basic.yul b/test/libyul/yulOptimizerAssemblyTests/blockFlattener/basic.yul new file mode 100644 index 000000000000..ff388bc0f07e --- /dev/null +++ b/test/libyul/yulOptimizerAssemblyTests/blockFlattener/basic.yul @@ -0,0 +1,70 @@ +/// @debug.set {"block": 0} +{ + /// @debug.set {"block": 1} + { + let _1 := mload(0) + let f_a := mload(1) + let f_r + /// @debug.set {"block": 2} + { + f_a := mload(f_a) + f_r := add(f_a, calldatasize()) + } + /// @debug.set {"block": 3} + let z := mload(/** @debug.set {"block": 4} **/2/** @debug.set {"block": 5} **/) + } +} +// ---- +// step: blockFlattener +// +// /// @debug.set {"block":0} +// { +// /// @debug.set {"block":1} +// { +// let _1 := mload(0) +// let f_a := mload(1) +// let f_r +// /// @debug.set {"block":2} +// f_a := mload(f_a) +// f_r := add(f_a, calldatasize()) +// /// @debug.set {"block":3} +// let z := mload(/** @debug.set {"block":4} */ 2) +// } +// } +// +// Assembly: +// /* "":92:93 */ +// 0x00 // @debug.set {"block":1} +// /* "":86:94 */ +// mload // @debug.set {"block":1} +// /* "":120:121 */ +// 0x01 // @debug.set {"block":1} +// /* "":114:122 */ +// mload // @debug.set {"block":1} +// /* "":131:138 */ +// 0x00 // @debug.set {"block":1} +// /* "":210:213 */ +// dup2 // @debug.set {"block":2} +// /* "":204:214 */ +// mload // @debug.set {"block":2} +// /* "":197:214 */ +// swap2 // @debug.set {"block":2} +// pop // @debug.set {"block":2} +// /* "":243:257 */ +// calldatasize // @debug.set {"block":2} +// /* "":238:241 */ +// dup3 // @debug.set {"block":2} +// /* "":234:258 */ +// add // @debug.set {"block":2} +// /* "":227:258 */ +// swap1 // @debug.set {"block":2} +// pop // @debug.set {"block":2} +// /* "":359:360 */ +// 0x02 // @debug.set {"block":4} +// /* "":322:392 */ +// mload // @debug.set {"block":3} +// /* "":66:398 */ +// pop // @debug.set {"block":1} +// pop // @debug.set {"block":1} +// pop // @debug.set {"block":1} +// pop // @debug.set {"block":1} diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 532a08d9fc55..0512b474c76c 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -46,6 +46,7 @@ add_executable(isoltest ../libyul/StackShufflingTest.cpp ../libyul/StackLayoutGeneratorTest.cpp ../libyul/YulOptimizerTest.cpp + ../libyul/YulOptimizerAssemblyTest.cpp ../libyul/YulOptimizerTestCommon.cpp ../libyul/YulInterpreterTest.cpp ) diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index d16b1da1969b..a8432c718131 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -251,7 +251,8 @@ class YulOpti m_dialect, m_nameDispenser, m_reservedIdentifiers, - solidity::frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment + solidity::frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment, + {} }; }; diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index 00abcc8e5c31..2f4632fe3073 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -195,7 +195,8 @@ std::unique_ptr Program::applyOptimisationSteps( _dialect, _nameDispenser, externallyUsedIdentifiers, - frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment + frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment, + {} }; for (std::string const& step: _optimisationSteps)