diff options
author | chriseth <chris@ethereum.org> | 2018-12-20 01:06:13 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-20 01:06:13 +0800 |
commit | 1df8f40cd2fd7b47698d847907b8ca7b47eb488d (patch) | |
tree | 5ed5816fe2d1a8a207e750d39884aca7957c8289 /test/libyul | |
parent | c8a2cb62832afb2dc09ccee6fd42c1516dfdb981 (diff) | |
parent | ddf54b21d1d002903624f61173ab4af197f50053 (diff) | |
download | dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.tar.gz dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.tar.zst dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.zip |
Merge pull request #5697 from ethereum/develop
Merge develop into release for 0.5.2
Diffstat (limited to 'test/libyul')
70 files changed, 1575 insertions, 306 deletions
diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index a247a169..a337fa8d 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -29,6 +29,7 @@ #include <libyul/AsmParser.h> #include <libyul/AsmAnalysis.h> #include <libyul/AsmPrinter.h> +#include <libyul/backends/evm/EVMDialect.h> #include <liblangutil/Scanner.h> #include <liblangutil/ErrorReporter.h> @@ -40,9 +41,9 @@ using namespace langutil; using namespace yul; using namespace dev::solidity; -void yul::test::printErrors(ErrorList const& _errors, Scanner const& _scanner) +void yul::test::printErrors(ErrorList const& _errors) { - SourceReferenceFormatter formatter(cout, [&](std::string const&) -> Scanner const& { return _scanner; }); + SourceReferenceFormatter formatter(cout); for (auto const& error: _errors) formatter.printExceptionInformation( @@ -54,11 +55,11 @@ void yul::test::printErrors(ErrorList const& _errors, Scanner const& _scanner) pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(string const& _source, bool _yul) { - auto flavour = _yul ? yul::AsmFlavour::Yul : yul::AsmFlavour::Strict; + shared_ptr<Dialect> dialect = _yul ? yul::Dialect::yul() : yul::EVMDialect::strictAssemblyForEVM(); ErrorList errors; ErrorReporter errorReporter(errors); auto scanner = make_shared<Scanner>(CharStream(_source, "")); - auto parserResult = yul::Parser(errorReporter, flavour).parse(scanner, false); + auto parserResult = yul::Parser(errorReporter, dialect).parse(scanner, false); if (parserResult) { BOOST_REQUIRE(errorReporter.errors().empty()); @@ -68,7 +69,7 @@ pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(strin errorReporter, dev::test::Options::get().evmVersion(), boost::none, - flavour + dialect ); if (analyzer.analyze(*parserResult)) { @@ -76,7 +77,7 @@ pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(strin return make_pair(parserResult, analysisInfo); } } - printErrors(errors, *scanner); + printErrors(errors); BOOST_FAIL("Invalid source."); // Unreachable. diff --git a/test/libyul/Common.h b/test/libyul/Common.h index a1c64ca5..01fc416a 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -29,7 +29,6 @@ namespace langutil { -class Scanner; class Error; using ErrorList = std::vector<std::shared_ptr<Error const>>; } @@ -44,7 +43,7 @@ namespace yul namespace test { -void printErrors(langutil::ErrorList const& _errors, langutil::Scanner const& _scanner); +void printErrors(langutil::ErrorList const& _errors); std::pair<std::shared_ptr<Block>, std::shared_ptr<AsmAnalysisInfo>> parse(std::string const& _source, bool _yul = true); Block disambiguate(std::string const& _source, bool _yul = true); diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp new file mode 100644 index 00000000..e60f718d --- /dev/null +++ b/test/libyul/ObjectCompilerTest.cpp @@ -0,0 +1,134 @@ +/* + 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/>. +*/ + +#include <test/libyul/ObjectCompilerTest.h> + +#include <test/libsolidity/FormattedScope.h> + +#include <libsolidity/interface/AssemblyStack.h> + +#include <libevmasm/Instruction.h> + +#include <liblangutil/SourceReferenceFormatter.h> + +#include <boost/algorithm/string.hpp> + +#include <fstream> + +using namespace dev; +using namespace langutil; +using namespace yul; +using namespace yul::test; +using namespace dev::solidity; +using namespace dev::solidity::test; +using namespace std; + +ObjectCompilerTest::ObjectCompilerTest(string const& _filename) +{ + boost::filesystem::path path(_filename); + + ifstream file(_filename); + if (!file) + BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\".")); + file.exceptions(ios::badbit); + + string line; + while (getline(file, line)) + { + if (boost::algorithm::starts_with(line, "// ----")) + break; + if (m_source.empty() && boost::algorithm::starts_with(line, "// optimize")) + m_optimize = true; + m_source += line + "\n"; + } + while (getline(file, line)) + if (boost::algorithm::starts_with(line, "//")) + m_expectation += line.substr((line.size() >= 3 && line[2] == ' ') ? 3 : 2) + "\n"; + else + m_expectation += line + "\n"; +} + +bool ObjectCompilerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) +{ + AssemblyStack stack(EVMVersion(), AssemblyStack::Language::StrictAssembly); + if (!stack.parseAndAnalyze("source", m_source)) + { + FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; + printErrors(_stream, stack.errors()); + return false; + } + if (m_optimize) + stack.optimize(); + + MachineAssemblyObject obj = stack.assemble(AssemblyStack::Machine::EVM); + solAssert(obj.bytecode, ""); + + m_obtainedResult = "Assembly:\n" + obj.assembly; + if (obj.bytecode->bytecode.empty()) + m_obtainedResult += "-- empty bytecode --\n"; + else + m_obtainedResult += + "Bytecode: " + + toHex(obj.bytecode->bytecode) + + "\nOpcodes: " + + boost::trim_copy(solidity::disassemble(obj.bytecode->bytecode)) + + "\n"; + + if (m_expectation != m_obtainedResult) + { + string nextIndentLevel = _linePrefix + " "; + FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Expected result:" << endl; + printIndented(_stream, m_expectation, nextIndentLevel); + FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Obtained result:" << endl; + printIndented(_stream, m_obtainedResult, nextIndentLevel); + return false; + } + return true; +} + +void ObjectCompilerTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const +{ + printIndented(_stream, m_source, _linePrefix); +} + +void ObjectCompilerTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const +{ + printIndented(_stream, m_obtainedResult, _linePrefix); +} + +void ObjectCompilerTest::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const +{ + stringstream output(_output); + string line; + while (getline(output, line)) + if (line.empty()) + // Avoid trailing spaces. + _stream << boost::trim_right_copy(_linePrefix) << endl; + else + _stream << _linePrefix << line << endl; +} + +void ObjectCompilerTest::printErrors(ostream& _stream, ErrorList const& _errors) +{ + SourceReferenceFormatter formatter(_stream); + + for (auto const& error: _errors) + formatter.printExceptionInformation( + *error, + (error->type() == Error::Type::Warning) ? "Warning" : "Error" + ); +} diff --git a/test/libyul/ObjectCompilerTest.h b/test/libyul/ObjectCompilerTest.h new file mode 100644 index 00000000..a5f8d777 --- /dev/null +++ b/test/libyul/ObjectCompilerTest.h @@ -0,0 +1,69 @@ +/* + 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/>. +*/ + +#pragma once + +#include <test/TestCase.h> + +namespace langutil +{ +class Scanner; +class Error; +using ErrorList = std::vector<std::shared_ptr<Error const>>; +} + +namespace yul +{ +struct AsmAnalysisInfo; +struct Block; +} + +namespace yul +{ +namespace test +{ + +class ObjectCompilerTest: public dev::solidity::test::TestCase +{ +public: + static std::unique_ptr<TestCase> create(std::string const& _filename) + { + return std::unique_ptr<TestCase>(new ObjectCompilerTest(_filename)); + } + + explicit ObjectCompilerTest(std::string const& _filename); + + bool run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; + + void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool const _formatted = false) const override; + void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override; + +private: + void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const; + bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted); + void disambiguate(); + + static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors); + + std::string m_source; + bool m_optimize = false; + std::string m_expectation; + std::string m_obtainedResult; +}; + +} +} diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index caaf2719..df7e32a1 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -22,10 +22,12 @@ #include <test/Options.h> #include <test/libsolidity/ErrorCheck.h> +#include <test/libyul/Common.h> #include <libyul/AsmParser.h> #include <libyul/AsmAnalysis.h> #include <libyul/AsmAnalysisInfo.h> +#include <libyul/Dialect.h> #include <liblangutil/Scanner.h> #include <liblangutil/ErrorReporter.h> @@ -47,12 +49,12 @@ namespace test namespace { -bool parse(string const& _source, ErrorReporter& errorReporter) +bool parse(string const& _source, std::shared_ptr<Dialect> _dialect, ErrorReporter& errorReporter) { try { auto scanner = make_shared<Scanner>(CharStream(_source, "")); - auto parserResult = yul::Parser(errorReporter, yul::AsmFlavour::Yul).parse(scanner, false); + auto parserResult = yul::Parser(errorReporter, _dialect).parse(scanner, false); if (parserResult) { yul::AsmAnalysisInfo analysisInfo; @@ -61,7 +63,7 @@ bool parse(string const& _source, ErrorReporter& errorReporter) errorReporter, dev::test::Options::get().evmVersion(), boost::none, - yul::AsmFlavour::Yul + _dialect )).analyze(*parserResult); } } @@ -72,13 +74,14 @@ bool parse(string const& _source, ErrorReporter& errorReporter) return false; } -boost::optional<Error> parseAndReturnFirstError(string const& _source, bool _allowWarnings = true) +boost::optional<Error> parseAndReturnFirstError(string const& _source, shared_ptr<Dialect> _dialect, bool _allowWarnings = true) { ErrorList errors; ErrorReporter errorReporter(errors); - if (!parse(_source, errorReporter)) + if (!parse(_source, _dialect, errorReporter)) { - BOOST_REQUIRE_EQUAL(errors.size(), 1); + BOOST_REQUIRE(!errors.empty()); + BOOST_CHECK_EQUAL(errors.size(), 1); return *errors.front(); } else @@ -96,29 +99,31 @@ boost::optional<Error> parseAndReturnFirstError(string const& _source, bool _all return {}; } -bool successParse(std::string const& _source, bool _allowWarnings = true) +bool successParse(std::string const& _source, shared_ptr<Dialect> _dialect = Dialect::yul(), bool _allowWarnings = true) { - return !parseAndReturnFirstError(_source, _allowWarnings); + return !parseAndReturnFirstError(_source, _dialect, _allowWarnings); } -Error expectError(std::string const& _source, bool _allowWarnings = false) +Error expectError(std::string const& _source, shared_ptr<Dialect> _dialect = Dialect::yul(), bool _allowWarnings = false) { - auto error = parseAndReturnFirstError(_source, _allowWarnings); + auto error = parseAndReturnFirstError(_source, _dialect, _allowWarnings); BOOST_REQUIRE(error); return *error; } } -#define CHECK_ERROR(text, typ, substring) \ +#define CHECK_ERROR_DIALECT(text, typ, substring, dialect) \ do \ { \ - Error err = expectError((text), false); \ + Error err = expectError((text), dialect, false); \ BOOST_CHECK(err.type() == (Error::Type::typ)); \ BOOST_CHECK(dev::solidity::searchErrorMessage(err, (substring))); \ } while(0) +#define CHECK_ERROR(text, typ, substring) CHECK_ERROR_DIALECT(text, typ, substring, Dialect::yul()) + BOOST_AUTO_TEST_SUITE(YulParser) BOOST_AUTO_TEST_CASE(smoke_test) @@ -299,6 +304,42 @@ BOOST_AUTO_TEST_CASE(if_statement_invalid) BOOST_CHECK(successParse("{ if 42:u256 { } }")); } +BOOST_AUTO_TEST_CASE(builtins_parser) +{ + struct SimpleDialect: public Dialect + { + SimpleDialect(): Dialect(AsmFlavour::Strict) {} + BuiltinFunction const* builtin(YulString _name) const override + { + return _name == "builtin"_yulstring ? &f : nullptr; + } + BuiltinFunction f; + }; + + shared_ptr<Dialect> dialect = make_shared<SimpleDialect>(); + CHECK_ERROR_DIALECT("{ let builtin := 6 }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); + CHECK_ERROR_DIALECT("{ function builtin() {} }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); + CHECK_ERROR_DIALECT("{ builtin := 6 }", ParserError, "Cannot assign to builtin function \"builtin\".", dialect); +} + +BOOST_AUTO_TEST_CASE(builtins_analysis) +{ + struct SimpleDialect: public Dialect + { + SimpleDialect(): Dialect(AsmFlavour::Strict) {} + BuiltinFunction const* builtin(YulString _name) const override + { + return _name == "builtin"_yulstring ? &f : nullptr; + } + BuiltinFunction f{"builtin"_yulstring, vector<Type>(2), vector<Type>(3), false}; + }; + + shared_ptr<Dialect> dialect = make_shared<SimpleDialect>(); + BOOST_CHECK(successParse("{ let a, b, c := builtin(1, 2) }", dialect)); + CHECK_ERROR_DIALECT("{ let a, b, c := builtin(1) }", TypeError, "Function expects 2 arguments but got 1", dialect); + CHECK_ERROR_DIALECT("{ let a, b := builtin(1, 2) }", DeclarationError, "Variable count mismatch: 2 variables and 3 values.", dialect); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libyul/StackReuseCodegen.cpp b/test/libyul/StackReuseCodegen.cpp new file mode 100644 index 00000000..97be11d3 --- /dev/null +++ b/test/libyul/StackReuseCodegen.cpp @@ -0,0 +1,353 @@ +/* + 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/>. +*/ +/** + * Unit tests for stack-reusing code generator. + */ + +#include <test/Options.h> + +#include <libsolidity/interface/AssemblyStack.h> +#include <libevmasm/Instruction.h> + +using namespace std; + +namespace dev +{ +namespace yul +{ +namespace test +{ + +namespace +{ +string assemble(string const& _input) +{ + solidity::AssemblyStack asmStack; + BOOST_REQUIRE_MESSAGE(asmStack.parseAndAnalyze("", _input), "Source did not parse: " + _input); + return solidity::disassemble(asmStack.assemble(solidity::AssemblyStack::Machine::EVM, true).bytecode->bytecode); +} +} + +BOOST_AUTO_TEST_SUITE(StackReuseCodegen) + +BOOST_AUTO_TEST_CASE(smoke_test) +{ + string out = assemble("{}"); + BOOST_CHECK_EQUAL(out, ""); +} + +BOOST_AUTO_TEST_CASE(single_var) +{ + string out = assemble("{ let x }"); + BOOST_CHECK_EQUAL(out, "PUSH1 0x0 POP "); +} + +BOOST_AUTO_TEST_CASE(single_var_assigned) +{ + string out = assemble("{ let x := 1 }"); + BOOST_CHECK_EQUAL(out, "PUSH1 0x1 POP "); +} + +BOOST_AUTO_TEST_CASE(single_var_assigned_plus_code) +{ + string out = assemble("{ let x := 1 mstore(3, 4) }"); + BOOST_CHECK_EQUAL(out, "PUSH1 0x1 POP PUSH1 0x4 PUSH1 0x3 MSTORE "); +} + +BOOST_AUTO_TEST_CASE(single_var_assigned_plus_code_and_reused) +{ + string out = assemble("{ let x := 1 mstore(3, 4) pop(mload(x)) }"); + BOOST_CHECK_EQUAL(out, "PUSH1 0x1 PUSH1 0x4 PUSH1 0x3 MSTORE DUP1 MLOAD POP POP "); +} + +BOOST_AUTO_TEST_CASE(multi_reuse_single_slot) +{ + string out = assemble("{ let x := 1 x := 6 let y := 2 y := 4 }"); + BOOST_CHECK_EQUAL(out, "PUSH1 0x1 PUSH1 0x6 SWAP1 POP POP PUSH1 0x2 PUSH1 0x4 SWAP1 POP POP "); +} + +BOOST_AUTO_TEST_CASE(multi_reuse_single_slot_nested) +{ + string out = assemble("{ let x := 1 x := 6 { let y := 2 y := 4 } }"); + BOOST_CHECK_EQUAL(out, "PUSH1 0x1 PUSH1 0x6 SWAP1 POP POP PUSH1 0x2 PUSH1 0x4 SWAP1 POP POP "); +} + +BOOST_AUTO_TEST_CASE(multi_reuse_same_variable_name) +{ + string out = assemble("{ let z := mload(0) { let x := 1 x := 6 z := x } { let x := 2 z := x x := 4 } }"); + BOOST_CHECK_EQUAL(out, + "PUSH1 0x0 MLOAD " + "PUSH1 0x1 PUSH1 0x6 SWAP1 POP DUP1 SWAP2 POP POP " + "PUSH1 0x2 DUP1 SWAP2 POP PUSH1 0x4 SWAP1 POP POP " + "POP " + ); +} + +BOOST_AUTO_TEST_CASE(last_use_in_nested_block) +{ + string out = assemble("{ let z := 0 { pop(z) } let x := 1 }"); + BOOST_CHECK_EQUAL(out, "PUSH1 0x0 DUP1 POP POP PUSH1 0x1 POP "); +} + +BOOST_AUTO_TEST_CASE(if_) +{ + // z is only removed after the if (after the jumpdest) + string out = assemble("{ let z := mload(0) if z { let x := z } let t := 3 }"); + BOOST_CHECK_EQUAL(out, "PUSH1 0x0 MLOAD DUP1 ISZERO PUSH1 0xA JUMPI DUP1 POP JUMPDEST POP PUSH1 0x3 POP "); +} + +BOOST_AUTO_TEST_CASE(switch_) +{ + string out = assemble("{ let z := 0 switch z case 0 { let x := 2 let y := 3 } default { z := 3 } let t := 9 }"); + BOOST_CHECK_EQUAL(out, + "PUSH1 0x0 DUP1 " + "PUSH1 0x0 DUP2 EQ PUSH1 0x11 JUMPI " + "PUSH1 0x3 SWAP2 POP PUSH1 0x18 JUMP " + "JUMPDEST PUSH1 0x2 POP PUSH1 0x3 POP " + "JUMPDEST POP POP " // This is where z and its copy (switch condition) can be removed. + "PUSH1 0x9 POP " + ); +} + +BOOST_AUTO_TEST_CASE(reuse_slots) +{ + // x and y should reuse the slots of b and d + string out = assemble("{ let a, b, c, d let x := 2 let y := 3 mstore(x, a) mstore(y, c) }"); + BOOST_CHECK_EQUAL(out, + "PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 " + "POP " // d is removed right away + "PUSH1 0x2 SWAP2 POP " // x is stored at b's slot + "PUSH1 0x3 DUP4 DUP4 MSTORE " + "DUP2 DUP2 MSTORE " + "POP POP POP POP " + ); +} + +BOOST_AUTO_TEST_CASE(for_1) +{ + // Special scoping rules, but can remove z early + string out = assemble("{ for { let z := 0 } 1 { } { let x := 3 } let t := 2 }"); + BOOST_CHECK_EQUAL(out, + "PUSH1 0x0 POP " + "JUMPDEST PUSH1 0x1 ISZERO PUSH1 0x11 JUMPI " + "PUSH1 0x3 POP JUMPDEST PUSH1 0x3 JUMP " + "JUMPDEST PUSH1 0x2 POP " + ); +} + +BOOST_AUTO_TEST_CASE(for_2) +{ + // Special scoping rules, cannot remove z until after the loop! + string out = assemble("{ for { let z := 0 } 1 { } { z := 8 let x := 3 } let t := 2 }"); + BOOST_CHECK_EQUAL(out, + "PUSH1 0x0 " + "JUMPDEST PUSH1 0x1 ISZERO PUSH1 0x14 JUMPI " + "PUSH1 0x8 SWAP1 POP " + "PUSH1 0x3 POP " + "JUMPDEST PUSH1 0x2 JUMP " + "JUMPDEST POP " // z is removed + "PUSH1 0x2 POP " + ); +} + +BOOST_AUTO_TEST_CASE(function_trivial) +{ + string in = R"({ + function f() { } + })"; + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0x5 JUMP JUMPDEST JUMP JUMPDEST " + ); +} + +BOOST_AUTO_TEST_CASE(function_retparam) +{ + string in = R"({ + function f() -> x, y { } + })"; + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0xB JUMP " + "JUMPDEST PUSH1 0x0 PUSH1 0x0 SWAP1 SWAP2 JUMP " + "JUMPDEST " + ); +} + +BOOST_AUTO_TEST_CASE(function_params) +{ + string in = R"({ + function f(a, b) { } + })"; + BOOST_CHECK_EQUAL(assemble(in), "PUSH1 0x7 JUMP JUMPDEST POP POP JUMP JUMPDEST "); +} + +BOOST_AUTO_TEST_CASE(function_params_and_retparams) +{ + string in = R"({ + function f(a, b, c, d) -> x, y { } + })"; + // This does not re-use the parameters for the return parameters + // We do not expect parameters to be fully unused, so the stack + // layout for a function is still fixed, even though parameters + // can be re-used. + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0x10 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x0 SWAP5 POP SWAP5 SWAP3 POP POP POP JUMP JUMPDEST " + ); +} + +BOOST_AUTO_TEST_CASE(function_params_and_retparams_partly_unused) +{ + string in = R"({ + function f(a, b, c, d) -> x, y { b := 3 let s := 9 y := 2 mstore(s, y) } + })"; + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0x1E JUMP " + "JUMPDEST PUSH1 0x0 PUSH1 0x0 " + "PUSH1 0x3 SWAP4 POP " + "PUSH1 0x9 PUSH1 0x2 SWAP2 POP " + "DUP2 DUP2 MSTORE " + "POP SWAP5 POP SWAP5 SWAP3 POP POP POP JUMP " + "JUMPDEST " + ); +} + +BOOST_AUTO_TEST_CASE(function_with_body_embedded) +{ + string in = R"({ + let b := 3 + function f(a, r) -> t { + // r could be removed right away, but a cannot - this is not implemented, though + let x := a a := 3 t := a + } + b := 7 + })"; + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0x3 PUSH1 " + "0x16 JUMP " + "JUMPDEST PUSH1 0x0 " // start of f, initialize t + "DUP2 POP " // let x := a + "PUSH1 0x3 SWAP2 POP " + "DUP2 SWAP1 POP " + "SWAP3 SWAP2 POP POP JUMP " + "JUMPDEST PUSH1 0x7 SWAP1 " + "POP POP " + ); +} + +BOOST_AUTO_TEST_CASE(function_call) +{ + string in = R"({ + let b := f(1, 2) + function f(a, r) -> t { } + b := f(3, 4) + })"; + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0x9 PUSH1 0x2 PUSH1 0x1 PUSH1 0xD JUMP " + "JUMPDEST PUSH1 0x15 JUMP " // jump over f + "JUMPDEST PUSH1 0x0 SWAP3 SWAP2 POP POP JUMP " // f + "JUMPDEST PUSH1 0x1F PUSH1 0x4 PUSH1 0x3 PUSH1 0xD JUMP " + "JUMPDEST SWAP1 POP POP " + ); +} + + +BOOST_AUTO_TEST_CASE(functions_multi_return) +{ + string in = R"({ + function f(a, b) -> t { } + function g() -> r, s { } + let x := f(1, 2) + x := f(3, 4) + let y, z := g() + y, z := g() + let unused := 7 + })"; + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0xB JUMP " + "JUMPDEST PUSH1 0x0 SWAP3 SWAP2 POP POP JUMP " // f + "JUMPDEST PUSH1 0x17 JUMP " + "JUMPDEST PUSH1 0x0 PUSH1 0x0 SWAP1 SWAP2 JUMP " // g + "JUMPDEST PUSH1 0x21 PUSH1 0x2 PUSH1 0x1 PUSH1 0x3 JUMP " // f(1, 2) + "JUMPDEST PUSH1 0x2B PUSH1 0x4 PUSH1 0x3 PUSH1 0x3 JUMP " // f(3, 4) + "JUMPDEST SWAP1 POP " // assignment to x + "POP " // remove x + "PUSH1 0x34 PUSH1 0xF JUMP " // g() + "JUMPDEST PUSH1 0x3A PUSH1 0xF JUMP " // g() + "JUMPDEST SWAP2 POP SWAP2 POP " // assignments + "POP POP " // removal of y and z + "PUSH1 0x7 POP " + ); +} + +BOOST_AUTO_TEST_CASE(reuse_slots_function) +{ + string in = R"({ + function f() -> x, y, z, t {} + let a, b, c, d := f() let x1 := 2 let y1 := 3 mstore(x1, a) mstore(y1, c) + })"; + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0x11 JUMP " + "JUMPDEST PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 SWAP1 SWAP2 SWAP3 SWAP4 JUMP " + "JUMPDEST PUSH1 0x17 PUSH1 0x3 JUMP " + // Stack: a b c d + "JUMPDEST POP " // d is unused + // Stack: a b c + "PUSH1 0x2 SWAP2 POP " // x1 reuses b's slot + "PUSH1 0x3 " + // Stack: a x1 c y1 + "DUP4 DUP4 MSTORE " + "DUP2 DUP2 MSTORE " + "POP POP POP POP " + ); +} + +BOOST_AUTO_TEST_CASE(reuse_slots_function_with_gaps) +{ + string in = R"({ + // Only x3 is actually used, the slots of + // x1 and x2 will be reused right away. + let x1 := 5 let x2 := 6 let x3 := 7 + mstore(x1, x2) + function f() -> x, y, z, t {} + let a, b, c, d := f() mstore(x3, a) mstore(c, d) + })"; + BOOST_CHECK_EQUAL(assemble(in), + "PUSH1 0x5 PUSH1 0x6 PUSH1 0x7 " + "DUP2 DUP4 MSTORE " + "PUSH1 0x1A JUMP " // jump across function + "JUMPDEST PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 SWAP1 SWAP2 SWAP3 SWAP4 JUMP " + "JUMPDEST PUSH1 0x20 PUSH1 0xC JUMP " + // stack: x1 x2 x3 a b c d + "JUMPDEST SWAP6 POP " // move d into x1 + // stack: d x2 x3 a b c + "SWAP4 POP " + // stack: d c x3 a b + "POP " + // stack: d c x3 a + "DUP1 DUP3 MSTORE " + "POP POP " + // stack: d c + "DUP2 DUP2 MSTORE " + "POP POP " + ); +} + + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 15d70faa..9643a1e9 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -22,7 +22,7 @@ #include <test/Options.h> #include <libyul/optimiser/BlockFlattener.h> -#include <libyul/optimiser/VarDeclPropagator.h> +#include <libyul/optimiser/VarDeclInitializer.h> #include <libyul/optimiser/Disambiguator.h> #include <libyul/optimiser/CommonSubexpressionEliminator.h> #include <libyul/optimiser/NameCollector.h> @@ -39,7 +39,9 @@ #include <libyul/optimiser/ExpressionJoiner.h> #include <libyul/optimiser/SSATransform.h> #include <libyul/optimiser/RedundantAssignEliminator.h> +#include <libyul/optimiser/StructuralSimplifier.h> #include <libyul/optimiser/Suite.h> +#include <libyul/backends/evm/EVMDialect.h> #include <libyul/AsmPrinter.h> #include <libyul/AsmParser.h> #include <libyul/AsmAnalysis.h> @@ -105,11 +107,8 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con disambiguate(); BlockFlattener{}(*m_ast); } - else if (m_optimizerStep == "varDeclPropagator") - { - disambiguate(); - VarDeclPropagator{}(*m_ast); - } + else if (m_optimizerStep == "varDeclInitializer") + VarDeclInitializer{}(*m_ast); else if (m_optimizerStep == "forLoopInitRewriter") { disambiguate(); @@ -213,6 +212,11 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con SSATransform::run(*m_ast, nameDispenser); RedundantAssignEliminator::run(*m_ast); } + else if (m_optimizerStep == "structuralSimplifier") + { + disambiguate(); + StructuralSimplifier{}(*m_ast); + } else if (m_optimizerStep == "fullSuite") OptimiserSuite::run(*m_ast, *m_analysisInfo); else @@ -256,15 +260,15 @@ void YulOptimizerTest::printIndented(ostream& _stream, string const& _output, st bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted) { - yul::AsmFlavour flavour = m_yul ? yul::AsmFlavour::Yul : yul::AsmFlavour::Strict; + shared_ptr<yul::Dialect> dialect = m_yul ? yul::Dialect::yul() : yul::EVMDialect::strictAssemblyForEVM(); ErrorList errors; ErrorReporter errorReporter(errors); shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(m_source, "")); - m_ast = yul::Parser(errorReporter, flavour).parse(scanner, false); + m_ast = yul::Parser(errorReporter, dialect).parse(scanner, false); if (!m_ast || !errorReporter.errors().empty()) { FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; - printErrors(_stream, errorReporter.errors(), *scanner); + printErrors(_stream, errorReporter.errors()); return false; } m_analysisInfo = make_shared<yul::AsmAnalysisInfo>(); @@ -273,12 +277,12 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c errorReporter, dev::test::Options::get().evmVersion(), boost::none, - flavour + dialect ); if (!analyzer.analyze(*m_ast) || !errorReporter.errors().empty()) { FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error analyzing source." << endl; - printErrors(_stream, errorReporter.errors(), *scanner); + printErrors(_stream, errorReporter.errors()); return false; } return true; @@ -290,9 +294,9 @@ void YulOptimizerTest::disambiguate() m_analysisInfo.reset(); } -void YulOptimizerTest::printErrors(ostream& _stream, ErrorList const& _errors, Scanner const& _scanner) +void YulOptimizerTest::printErrors(ostream& _stream, ErrorList const& _errors) { - SourceReferenceFormatter formatter(_stream, [&](string const&) -> Scanner const& { return _scanner; }); + SourceReferenceFormatter formatter(_stream); for (auto const& error: _errors) formatter.printExceptionInformation( diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index 90026e24..5648e995 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -57,7 +57,7 @@ private: bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted); void disambiguate(); - static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors, langutil::Scanner const& _scanner); + static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors); std::string m_source; bool m_yul = false; diff --git a/test/libyul/objectCompiler/data.yul b/test/libyul/objectCompiler/data.yul new file mode 100644 index 00000000..daa22d21 --- /dev/null +++ b/test/libyul/objectCompiler/data.yul @@ -0,0 +1,11 @@ +object "a" { + code {} + // Unreferenced data is not added to the assembled bytecode. + data "str" "Hello, World!" +} +// ---- +// Assembly: +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// Bytecode: fe +// Opcodes: INVALID diff --git a/test/libyul/objectCompiler/datacopy.yul b/test/libyul/objectCompiler/datacopy.yul new file mode 100644 index 00000000..2259e5dc --- /dev/null +++ b/test/libyul/objectCompiler/datacopy.yul @@ -0,0 +1,48 @@ +object "a" { + code { + datacopy(0, dataoffset("sub"), datasize("sub")) + return(0, datasize("sub")) + } + object "sub" { + code { + sstore(0, dataoffset("sub")) + mstore(0, datasize("data1")) + } + data "data1" "Hello, World!" + } +} +// ---- +// Assembly: +// /* "source":26:73 */ +// dataSize(sub_0) +// dataOffset(sub_0) +// /* "source":35:36 */ +// 0x00 +// /* "source":26:73 */ +// codecopy +// /* "source":78:104 */ +// dataSize(sub_0) +// /* "source":85:86 */ +// 0x00 +// /* "source":78:104 */ +// return +// stop +// +// sub_0: assembly { +// /* "source":143:171 */ +// 0x00 +// /* "source":150:151 */ +// 0x00 +// /* "source":143:171 */ +// sstore +// /* "source":178:206 */ +// 0x0d +// /* "source":185:186 */ +// 0x00 +// /* "source":178:206 */ +// mstore +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// } +// Bytecode: 600b600d600039600b6000f3fe6000600055600d600052fe +// Opcodes: PUSH1 0xB PUSH1 0xD PUSH1 0x0 CODECOPY PUSH1 0xB PUSH1 0x0 RETURN INVALID PUSH1 0x0 PUSH1 0x0 SSTORE PUSH1 0xD PUSH1 0x0 MSTORE INVALID diff --git a/test/libyul/objectCompiler/dataoffset_code.yul b/test/libyul/objectCompiler/dataoffset_code.yul new file mode 100644 index 00000000..725267f2 --- /dev/null +++ b/test/libyul/objectCompiler/dataoffset_code.yul @@ -0,0 +1,29 @@ +object "a" { + code { sstore(0, dataoffset("sub")) } + object "sub" { + code { sstore(0, 8) } + data "data1" "Hello, World!" + } +} +// ---- +// Assembly: +// /* "source":22:50 */ +// dataOffset(sub_0) +// /* "source":29:30 */ +// 0x00 +// /* "source":22:50 */ +// sstore +// stop +// +// sub_0: assembly { +// /* "source":91:92 */ +// 0x08 +// /* "source":88:89 */ +// 0x00 +// /* "source":81:93 */ +// sstore +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// } +// Bytecode: 6006600055fe6008600055fe +// Opcodes: PUSH1 0x6 PUSH1 0x0 SSTORE INVALID PUSH1 0x8 PUSH1 0x0 SSTORE INVALID diff --git a/test/libyul/objectCompiler/dataoffset_data.yul b/test/libyul/objectCompiler/dataoffset_data.yul new file mode 100644 index 00000000..9a0a461d --- /dev/null +++ b/test/libyul/objectCompiler/dataoffset_data.yul @@ -0,0 +1,16 @@ +object "a" { + code { sstore(0, dataoffset("data1")) } + data "data1" "Hello, World!" +} +// ---- +// Assembly: +// /* "source":22:52 */ +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f +// /* "source":29:30 */ +// 0x00 +// /* "source":22:52 */ +// sstore +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// Bytecode: 6006600055fe48656c6c6f2c20576f726c6421 +// Opcodes: PUSH1 0x6 PUSH1 0x0 SSTORE INVALID 0x48 PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000 diff --git a/test/libyul/objectCompiler/dataoffset_self.yul b/test/libyul/objectCompiler/dataoffset_self.yul new file mode 100644 index 00000000..b7740735 --- /dev/null +++ b/test/libyul/objectCompiler/dataoffset_self.yul @@ -0,0 +1,16 @@ +object "a" { + code { sstore(0, dataoffset("a")) } + data "data1" "Hello, World!" +} +// ---- +// Assembly: +// /* "source":22:48 */ +// 0x00 +// /* "source":29:30 */ +// 0x00 +// /* "source":22:48 */ +// sstore +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// Bytecode: 6000600055fe +// Opcodes: PUSH1 0x0 PUSH1 0x0 SSTORE INVALID diff --git a/test/libyul/objectCompiler/datasize_code.yul b/test/libyul/objectCompiler/datasize_code.yul new file mode 100644 index 00000000..cff68515 --- /dev/null +++ b/test/libyul/objectCompiler/datasize_code.yul @@ -0,0 +1,29 @@ +object "a" { + code { sstore(0, datasize("sub")) } + object "sub" { + code { sstore(0, 8) } + data "data1" "Hello, World!" + } +} +// ---- +// Assembly: +// /* "source":22:48 */ +// dataSize(sub_0) +// /* "source":29:30 */ +// 0x00 +// /* "source":22:48 */ +// sstore +// stop +// +// sub_0: assembly { +// /* "source":89:90 */ +// 0x08 +// /* "source":86:87 */ +// 0x00 +// /* "source":79:91 */ +// sstore +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// } +// Bytecode: 6006600055fe +// Opcodes: PUSH1 0x6 PUSH1 0x0 SSTORE INVALID diff --git a/test/libyul/objectCompiler/datasize_data.yul b/test/libyul/objectCompiler/datasize_data.yul new file mode 100644 index 00000000..f8341469 --- /dev/null +++ b/test/libyul/objectCompiler/datasize_data.yul @@ -0,0 +1,16 @@ +object "a" { + code { sstore(0, datasize("data1")) } + data "data1" "Hello, World!" +} +// ---- +// Assembly: +// /* "source":22:50 */ +// 0x0d +// /* "source":29:30 */ +// 0x00 +// /* "source":22:50 */ +// sstore +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// Bytecode: 600d600055fe +// Opcodes: PUSH1 0xD PUSH1 0x0 SSTORE INVALID diff --git a/test/libyul/objectCompiler/datasize_self.yul b/test/libyul/objectCompiler/datasize_self.yul new file mode 100644 index 00000000..4579fe67 --- /dev/null +++ b/test/libyul/objectCompiler/datasize_self.yul @@ -0,0 +1,16 @@ +object "a" { + code { sstore(0, datasize("a")) } + data "data1" "Hello, World!" +} +// ---- +// Assembly: +// /* "source":22:46 */ +// bytecodeSize +// /* "source":29:30 */ +// 0x00 +// /* "source":22:46 */ +// sstore +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// Bytecode: 6006600055fe +// Opcodes: PUSH1 0x6 PUSH1 0x0 SSTORE INVALID diff --git a/test/libyul/objectCompiler/namedObject.yul b/test/libyul/objectCompiler/namedObject.yul new file mode 100644 index 00000000..940160fd --- /dev/null +++ b/test/libyul/objectCompiler/namedObject.yul @@ -0,0 +1,6 @@ +object "a" { + code {} +} +// ---- +// Assembly: +// -- empty bytecode -- diff --git a/test/libyul/objectCompiler/namedObjectCode.yul b/test/libyul/objectCompiler/namedObjectCode.yul new file mode 100644 index 00000000..4fc6891c --- /dev/null +++ b/test/libyul/objectCompiler/namedObjectCode.yul @@ -0,0 +1,13 @@ +object "a" { + code { sstore(0, 1) } +} +// ---- +// Assembly: +// /* "source":32:33 */ +// 0x01 +// /* "source":29:30 */ +// 0x00 +// /* "source":22:34 */ +// sstore +// Bytecode: 6001600055 +// Opcodes: PUSH1 0x1 PUSH1 0x0 SSTORE diff --git a/test/libyul/objectCompiler/nested_optimizer.yul b/test/libyul/objectCompiler/nested_optimizer.yul new file mode 100644 index 00000000..7739ce61 --- /dev/null +++ b/test/libyul/objectCompiler/nested_optimizer.yul @@ -0,0 +1,49 @@ +// optimize +object "a" { + code { + let x := calldataload(0) + let y := calldataload(0) + let z := sub(y, x) + sstore(add(x, 0), z) + } + object "sub" { + code { + let x := calldataload(0) + let y := calldataload(0) + let z := sub(y, x) + sstore(add(x, 0), z) + } + } +} +// ---- +// Assembly: +// /* "source":60:61 */ +// 0x00 +// /* "source":137:138 */ +// dup1 +// /* "source":60:61 */ +// dup2 +// /* "source":47:62 */ +// calldataload +// /* "source":119:139 */ +// sstore +// /* "source":32:143 */ +// pop +// stop +// +// sub_0: assembly { +// /* "source":200:201 */ +// 0x00 +// /* "source":283:284 */ +// dup1 +// /* "source":200:201 */ +// dup2 +// /* "source":187:202 */ +// calldataload +// /* "source":265:285 */ +// sstore +// /* "source":170:291 */ +// pop +// } +// Bytecode: 60008081355550fe +// Opcodes: PUSH1 0x0 DUP1 DUP2 CALLDATALOAD SSTORE POP INVALID diff --git a/test/libyul/objectCompiler/simple.yul b/test/libyul/objectCompiler/simple.yul new file mode 100644 index 00000000..d41b527c --- /dev/null +++ b/test/libyul/objectCompiler/simple.yul @@ -0,0 +1,13 @@ +{ + sstore(0, 1) +} +// ---- +// Assembly: +// /* "source":14:15 */ +// 0x01 +// /* "source":11:12 */ +// 0x00 +// /* "source":4:16 */ +// sstore +// Bytecode: 6001600055 +// Opcodes: PUSH1 0x1 PUSH1 0x0 SSTORE diff --git a/test/libyul/objectCompiler/simple_optimizer.yul b/test/libyul/objectCompiler/simple_optimizer.yul new file mode 100644 index 00000000..43b33553 --- /dev/null +++ b/test/libyul/objectCompiler/simple_optimizer.yul @@ -0,0 +1,23 @@ +// optimize +{ + let x := calldataload(0) + let y := calldataload(0) + let z := sub(y, x) + sstore(add(x, 0), z) +} +// ---- +// Assembly: +// /* "source":38:39 */ +// 0x00 +// /* "source":109:110 */ +// dup1 +// /* "source":38:39 */ +// dup2 +// /* "source":25:40 */ +// calldataload +// /* "source":91:111 */ +// sstore +// /* "source":12:113 */ +// pop +// Bytecode: 60008081355550 +// Opcodes: PUSH1 0x0 DUP1 DUP2 CALLDATALOAD SSTORE POP diff --git a/test/libyul/objectCompiler/smoke.yul b/test/libyul/objectCompiler/smoke.yul new file mode 100644 index 00000000..b2e44d4d --- /dev/null +++ b/test/libyul/objectCompiler/smoke.yul @@ -0,0 +1,5 @@ +{ +} +// ---- +// Assembly: +// -- empty bytecode -- diff --git a/test/libyul/objectCompiler/subObject.yul b/test/libyul/objectCompiler/subObject.yul new file mode 100644 index 00000000..98ea4d07 --- /dev/null +++ b/test/libyul/objectCompiler/subObject.yul @@ -0,0 +1,21 @@ +object "a" { + code {} + // Unreferenced data is not added to the assembled bytecode. + data "str" "Hello, World!" + object "sub" { code { sstore(0, 1) } } +} +// ---- +// Assembly: +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// +// sub_0: assembly { +// /* "source":149:150 */ +// 0x01 +// /* "source":146:147 */ +// 0x00 +// /* "source":139:151 */ +// sstore +// } +// Bytecode: fe +// Opcodes: INVALID diff --git a/test/libyul/objectCompiler/subSubObject.yul b/test/libyul/objectCompiler/subSubObject.yul new file mode 100644 index 00000000..5e01f6dd --- /dev/null +++ b/test/libyul/objectCompiler/subSubObject.yul @@ -0,0 +1,39 @@ +object "a" { + code {} + // Unreferenced data is not added to the assembled bytecode. + data "str" "Hello, World!" + object "sub" { + code { sstore(0, 1) } + object "subsub" { + code { sstore(2, 3) } + data "str" hex"123456" + } + } +} +// ---- +// Assembly: +// stop +// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421 +// +// sub_0: assembly { +// /* "source":153:154 */ +// 0x01 +// /* "source":150:151 */ +// 0x00 +// /* "source":143:155 */ +// sstore +// stop +// +// sub_0: assembly { +// /* "source":203:204 */ +// 0x03 +// /* "source":200:201 */ +// 0x02 +// /* "source":193:205 */ +// sstore +// stop +// data_6adf031833174bbe4c85eafe59ddb54e6584648c2c962c6f94791ab49caa0ad4 123456 +// } +// } +// Bytecode: fe +// Opcodes: INVALID diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul new file mode 100644 index 00000000..5283ef9a --- /dev/null +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul @@ -0,0 +1,23 @@ +{ + function f() -> x { + // can re-use x + let y := 0 + mstore(y, 7) + } + let a + // can re-use a + let b := 0 + sstore(a, b) +} +// ---- +// commonSubexpressionEliminator +// { +// function f() -> x +// { +// let y := x +// mstore(x, 7) +// } +// let a +// let b := a +// sstore(a, a) +// } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul new file mode 100644 index 00000000..a790ca65 --- /dev/null +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul @@ -0,0 +1,14 @@ +{ + // This does not replace b by a because there is no + // explicit assignment, even though both hold the same value. + let a + let b + mstore(sub(a, b), 7) +} +// ---- +// commonSubexpressionEliminator +// { +// let a +// let b +// mstore(sub(a, b), 7) +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul new file mode 100644 index 00000000..51f5df40 --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul @@ -0,0 +1,14 @@ +{ + function f() -> x, z {} + let c, d := f() + let y := add(d, add(c, 7)) +} +// ---- +// expressionSimplifier +// { +// function f() -> x, z +// { +// } +// let c, d := f() +// let y := add(add(d, c), 7) +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul new file mode 100644 index 00000000..46f9bc40 --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul @@ -0,0 +1,14 @@ +// return variables are assumed to be zero initially. +{ + function f() -> c, d { + let y := add(d, add(c, 7)) + } +} +// ---- +// expressionSimplifier +// { +// function f() -> c, d +// { +// let y := 7 +// } +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul new file mode 100644 index 00000000..f260db0b --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul @@ -0,0 +1,11 @@ +// Unassigned variables are assumed to be zero. +{ + let c, d + let y := add(d, add(c, 7)) +} +// ---- +// expressionSimplifier +// { +// let c, d +// let y := 7 +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul new file mode 100644 index 00000000..7b1430f3 --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul @@ -0,0 +1,13 @@ +// Unassigned variables are assumed to be zero. +{ + let c + let d + let y := add(d, add(c, 7)) +} +// ---- +// expressionSimplifier +// { +// let c +// let d +// let y := 7 +// } diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul new file mode 100644 index 00000000..3f7aa089 --- /dev/null +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul @@ -0,0 +1,48 @@ +{ + let random := 42 + for { + for { let a := 1} iszero(eq(a,10)) {} { + a := add(a, 1) + } + let b := 1 + } iszero(eq(b, 10)) { + for { let c := 1 } iszero(eq(c,2)) { c := add(c, 1) } { + b := add(b, 1) + } + } { + mstore(b,b) + } +} +// ---- +// forLoopInitRewriter +// { +// let random := 42 +// let a := 1 +// for { +// } +// iszero(eq(a, 10)) +// { +// } +// { +// a := add(a, 1) +// } +// let b := 1 +// for { +// } +// iszero(eq(b, 10)) +// { +// let c := 1 +// for { +// } +// iszero(eq(c, 2)) +// { +// c := add(c, 1) +// } +// { +// b := add(b, 1) +// } +// } +// { +// mstore(b, b) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul b/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul index ee7f5bf5..b3f51593 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul @@ -9,14 +9,14 @@ // { // { // let f_a := calldataload(0) -// let f_b -// let f_c +// let f_b := 0 +// let f_c := 0 // f_b := sload(mload(f_a)) // f_c := 3 // let b3 := f_b // let f_a_2 := f_c -// let f_b_3 -// let f_c_4 +// let f_b_3 := 0 +// let f_c_4 := 0 // f_b_3 := sload(mload(f_a_2)) // f_c_4 := 3 // let b4 := f_b_3 diff --git a/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul b/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul index 00bb6577..9e6c4e76 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul @@ -14,7 +14,7 @@ // { // let _2 := mload(0) // let f_a := mload(1) -// let f_r +// let f_r := 0 // f_a := mload(f_a) // f_r := add(f_a, calldatasize()) // if gt(f_r, _2) diff --git a/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul b/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul index 0972ac56..c00b1163 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul @@ -2,8 +2,6 @@ function f(a) -> b { let x := mload(a) b := sload(x) - let c := 3 - mstore(mul(a, b), mload(x)) let y := add(a, x) sstore(y, 10) } @@ -13,6 +11,9 @@ let r := f(a) // This should be inlined because it is a constant let t := f(a2) + let a3 + // This should be inlined because it is a constant as well (zero) + let s := f(a3) } // ---- // fullInliner @@ -22,21 +23,25 @@ // let a2 := 2 // let r := f(a_1) // let f_a := a2 -// let f_b +// let f_b := 0 // let f_x := mload(f_a) // f_b := sload(f_x) -// let f_c := 3 -// mstore(mul(f_a, f_b), mload(f_x)) // let f_y := add(f_a, f_x) // sstore(f_y, 10) // let t := f_b +// let a3 +// let f_a_3 := a3 +// let f_b_4 := 0 +// let f_x_5 := mload(f_a_3) +// f_b_4 := sload(f_x_5) +// let f_y_6 := add(f_a_3, f_x_5) +// sstore(f_y_6, 10) +// let s := f_b_4 // } // function f(a) -> b // { // let x := mload(a) // b := sload(x) -// let c := 3 -// mstore(mul(a, b), mload(x)) // let y := add(a, x) // sstore(y, 10) // } diff --git a/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul b/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul index 3302a35c..72beb8b1 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul @@ -15,7 +15,7 @@ // { // { // let f_a := mload(1) -// let f_b +// let f_b := 0 // let f_x := mload(f_a) // f_b := sload(f_x) // let f_c := 3 diff --git a/test/libyul/yulOptimizerTests/fullInliner/long_names.yul b/test/libyul/yulOptimizerTests/fullInliner/long_names.yul index 644e9126..869abbc9 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/long_names.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/long_names.yul @@ -13,7 +13,7 @@ // { // let verylongvariablename2_1 := 3 // let verylongfu_verylongvariablename := verylongvariablename2_1 -// let verylongfu_verylongvariablename2 +// let verylongfu_verylongvariablename2 := 0 // verylongfu_verylongvariablename2 := add(verylongfu_verylongvariablename, verylongfu_verylongvariablename) // mstore(0, verylongfu_verylongvariablename2) // mstore(1, verylongvariablename2_1) diff --git a/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul b/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul index f3d0b286..0b46a3c6 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul @@ -15,7 +15,7 @@ // let f_a := mload(2) // let f_b := _6 // let f_c := _4 -// let f_x +// let f_x := 0 // f_x := add(f_a, f_b) // f_x := mul(f_x, f_c) // let _10 := add(f_x, _2) diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul index 8bc6ec58..5d658e96 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul @@ -9,11 +9,11 @@ // { // let _1 := 7 // let f_a := 3 -// let f_x +// let f_x := 0 // f_x := add(f_a, f_a) // let g_b := f_x // let g_c := _1 -// let g_y +// let g_y := 0 // g_y := mul(mload(g_c), f(g_b)) // let y_1 := g_y // } @@ -24,7 +24,7 @@ // function g(b, c) -> y // { // let f_a_6 := b -// let f_x_7 +// let f_x_7 := 0 // f_x_7 := add(f_a_6, f_a_6) // y := mul(mload(c), f_x_7) // } diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul index 19ac945e..6e4acb97 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul @@ -37,7 +37,7 @@ // function f(x) // { // mstore(0, x) -// let h_t +// let h_t := 0 // h_t := 2 // mstore(7, h_t) // let g_x_1 := 10 diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul index eebdec38..a4cbbef0 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul @@ -11,8 +11,8 @@ // { // { // let f_a := mload(0) -// let f_x -// let f_y +// let f_x := 0 +// let f_y := 0 // f_x := mul(f_a, f_a) // f_y := add(f_a, f_x) // let r := f_x diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul new file mode 100644 index 00000000..f59e2c11 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul @@ -0,0 +1,44 @@ +{ + function f(a) -> b { + let x := mload(a) + b := sload(x) + } + // This will stop inlining at some point because + // the function gets too big. + function g() -> x { + x := f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(2))))))))))))))))))) + } +} +// ---- +// fullInliner +// { +// function f(a) -> b +// { +// b := sload(mload(a)) +// } +// function g() -> x_1 +// { +// let f_a := 2 +// let f_b := 0 +// f_b := sload(mload(f_a)) +// let f_a_20 := f_b +// let f_b_21 := 0 +// f_b_21 := sload(mload(f_a_20)) +// let f_a_23 := f_b_21 +// let f_b_24 := 0 +// f_b_24 := sload(mload(f_a_23)) +// let f_a_26 := f_b_24 +// let f_b_27 := 0 +// f_b_27 := sload(mload(f_a_26)) +// let f_a_29 := f_b_27 +// let f_b_30 := 0 +// f_b_30 := sload(mload(f_a_29)) +// let f_a_32 := f_b_30 +// let f_b_33 := 0 +// f_b_33 := sload(mload(f_a_32)) +// let f_a_35 := f_b_33 +// let f_b_36 := 0 +// f_b_36 := sload(mload(f_a_35)) +// x_1 := f(f(f(f(f(f(f(f(f(f(f(f(f_b_36)))))))))))) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul new file mode 100644 index 00000000..f20b7221 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul @@ -0,0 +1,41 @@ +{ + function f(a) -> b { + let x := mload(a) + b := sload(x) + } + // This will stop inlining at some point because + // the global context gets too big. + let x := f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(2))))))))))))))))))) +} +// ---- +// fullInliner +// { +// { +// let f_a := 2 +// let f_b := 0 +// f_b := sload(mload(f_a)) +// let f_a_20 := f_b +// let f_b_21 := 0 +// f_b_21 := sload(mload(f_a_20)) +// let f_a_23 := f_b_21 +// let f_b_24 := 0 +// f_b_24 := sload(mload(f_a_23)) +// let f_a_26 := f_b_24 +// let f_b_27 := 0 +// f_b_27 := sload(mload(f_a_26)) +// let f_a_29 := f_b_27 +// let f_b_30 := 0 +// f_b_30 := sload(mload(f_a_29)) +// let f_a_32 := f_b_30 +// let f_b_33 := 0 +// f_b_33 := sload(mload(f_a_32)) +// let f_a_35 := f_b_33 +// let f_b_36 := 0 +// f_b_36 := sload(mload(f_a_35)) +// let x_1 := f(f(f(f(f(f(f(f(f(f(f(f(f_b_36)))))))))))) +// } +// function f(a) -> b +// { +// b := sload(mload(a)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul b/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul index 9644e6c1..96d806bd 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul @@ -14,7 +14,7 @@ // { // for { // let f_a := 0 -// let f_r +// let f_r := 0 // sstore(f_a, 0) // f_r := f_a // let x := f_r @@ -22,14 +22,14 @@ // f(x) // { // let f_a_3 := x -// let f_r_4 +// let f_r_4 := 0 // sstore(f_a_3, 0) // f_r_4 := f_a_3 // x := f_r_4 // } // { // let f_a_6 := x -// let f_r_7 +// let f_r_7 := 0 // sstore(f_a_6, 0) // f_r_7 := f_a_6 // let t := f_r_7 diff --git a/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul b/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul index cd9e2746..c1bed208 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul @@ -14,7 +14,7 @@ // { // let _1 := 2 // let f_a := 7 -// let f_x +// let f_x := 0 // let f_r := mul(f_a, f_a) // f_x := add(f_r, f_r) // pop(add(f_x, _1)) diff --git a/test/libyul/yulOptimizerTests/fullInliner/simple.yul b/test/libyul/yulOptimizerTests/fullInliner/simple.yul index fcdf453b..1ada8f53 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/simple.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/simple.yul @@ -11,7 +11,7 @@ // { // let _2 := mload(7) // let f_a := sload(mload(2)) -// let f_x +// let f_x := 0 // let f_r := mul(f_a, f_a) // f_x := add(f_r, f_r) // let y := add(f_x, _2) diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul index a34da198..efb846f2 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul @@ -465,178 +465,166 @@ // let abi_encode_pos := _1 // let abi_encode_length_68 := mload(_485) // mstore(_1, abi_encode_length_68) -// let abi_encode_pos_590 := 64 -// abi_encode_pos := abi_encode_pos_590 +// abi_encode_pos := 64 // let abi_encode_srcPtr := add(_485, _1) +// let abi_encode_i_69 := _2 // for { -// let abi_encode_i_69 := _2 // } // lt(abi_encode_i_69, abi_encode_length_68) // { // abi_encode_i_69 := add(abi_encode_i_69, 1) // } // { -// let _931 := mload(abi_encode_srcPtr) -// let abi_encode_pos_71_1037 := abi_encode_pos -// let abi_encode_length_72_1038 := 0x3 -// let abi_encode_srcPtr_73_1039 := _931 +// let _863 := mload(abi_encode_srcPtr) +// let abi_encode_pos_71_971 := abi_encode_pos +// let abi_encode_length_72_972 := 0x3 +// let abi_encode_srcPtr_73_973 := _863 +// let abi_encode_i_74_974 := _2 // for { -// let abi_encode_i_74_1040 := _2 // } -// lt(abi_encode_i_74_1040, abi_encode_length_72_1038) +// lt(abi_encode_i_74_974, abi_encode_length_72_972) // { -// abi_encode_i_74_1040 := add(abi_encode_i_74_1040, 1) +// abi_encode_i_74_974 := add(abi_encode_i_74_974, 1) // } // { -// mstore(abi_encode_pos_71_1037, and(mload(abi_encode_srcPtr_73_1039), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) -// abi_encode_srcPtr_73_1039 := add(abi_encode_srcPtr_73_1039, _1) -// abi_encode_pos_71_1037 := add(abi_encode_pos_71_1037, _1) +// mstore(abi_encode_pos_71_971, and(mload(abi_encode_srcPtr_73_973), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) +// abi_encode_srcPtr_73_973 := add(abi_encode_srcPtr_73_973, _1) +// abi_encode_pos_71_971 := add(abi_encode_pos_71_971, _1) // } // abi_encode_srcPtr := add(abi_encode_srcPtr, _1) // abi_encode_pos := add(abi_encode_pos, 0x60) // } -// let _933 := 0x40 -// let _487 := mload(_933) -// let _488 := mload(_1) -// let abi_decode_value0_60_618 -// let abi_decode_value0_60 := abi_decode_value0_60_618 -// let abi_decode_value1_61_619 -// let abi_decode_value1_61 := abi_decode_value1_61_619 -// let abi_decode_value2_620 -// let abi_decode_value2 := abi_decode_value2_620 -// let abi_decode_value3_621 -// let abi_decode_value3 := abi_decode_value3_621 -// if slt(sub(_487, _488), 128) +// let a, b, c, d := abi_decode_tuple_t_uint256t_uint256t_array$_t_uint256_$dyn_memory_ptrt_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(mload(_1), mload(0x40)) +// sstore(a, b) +// sstore(c, d) +// 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 +// { +// if iszero(slt(add(offset_3, 0x1f), end_4)) // { -// revert(_2, _2) +// revert(array_5, array_5) // } +// let length_6 := calldataload(offset_3) +// let array_5_254 := allocateMemory(array_allocation_size_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(length_6)) +// array_5 := array_5_254 +// let dst_7 := array_5_254 +// mstore(array_5_254, length_6) +// let _36 := 0x20 +// let offset_3_256 := add(offset_3, _36) +// dst_7 := add(array_5_254, _36) +// let src_8 := offset_3_256 +// let _38 := 0x40 +// if gt(add(add(offset_3, mul(length_6, _38)), _36), end_4) // { -// abi_decode_value0_60 := calldataload(_488) +// let _42 := 0 +// revert(_42, _42) +// } +// let i_9 := 0 +// for { // } +// lt(i_9, length_6) // { -// abi_decode_value1_61 := calldataload(add(_488, 32)) +// i_9 := add(i_9, 1) // } // { -// let abi_decode_offset_64 := calldataload(add(_488, abi_encode_pos_590)) -// let _940 := 0xffffffffffffffff -// if gt(abi_decode_offset_64, _940) -// { -// revert(_2, _2) -// } -// let _942 := add(_488, abi_decode_offset_64) -// if iszero(slt(add(_942, 0x1f), _487)) -// { -// revert(_2, _2) -// } -// let abi_decode_length_30_1046 := calldataload(_942) -// if gt(abi_decode_length_30_1046, _940) -// { -// revert(_2, _2) -// } -// let abi_decode_array_allo__561 := mul(abi_decode_length_30_1046, _1) -// let abi_decode_array_29_279_1047 := allocateMemory(add(abi_decode_array_allo__561, _1)) -// let abi_decode_dst_31_1048 := abi_decode_array_29_279_1047 -// mstore(abi_decode_array_29_279_1047, abi_decode_length_30_1046) -// let abi_decode_offset_27_281_1049 := add(_942, _1) -// abi_decode_dst_31_1048 := add(abi_decode_array_29_279_1047, _1) -// let abi_decode_src_32_1050 := abi_decode_offset_27_281_1049 -// if gt(add(add(_942, abi_decode_array_allo__561), _1), _487) -// { -// revert(_2, _2) -// } -// for { -// let abi_decode_i_33_1052 := _2 -// } -// lt(abi_decode_i_33_1052, abi_decode_length_30_1046) -// { -// abi_decode_i_33_1052 := add(abi_decode_i_33_1052, 1) -// } -// { -// mstore(abi_decode_dst_31_1048, calldataload(abi_decode_src_32_1050)) -// abi_decode_dst_31_1048 := add(abi_decode_dst_31_1048, _1) -// abi_decode_src_32_1050 := add(abi_decode_src_32_1050, _1) -// } -// abi_decode_value2 := abi_decode_array_29_279_1047 +// mstore(dst_7, abi_decode_t_array$_t_uint256_$2_memory(src_8, end_4)) +// dst_7 := add(dst_7, _36) +// src_8 := add(src_8, _38) // } +// } +// function abi_decode_t_array$_t_uint256_$2_memory(offset_11, end_12) -> array_13 +// { +// if iszero(slt(add(offset_11, 0x1f), end_12)) // { -// let abi_decode_offset_65 := calldataload(add(_488, 96)) -// let _945 := 0xffffffffffffffff -// if gt(abi_decode_offset_65, _945) -// { -// revert(_2, _2) -// } -// let _947 := add(_488, abi_decode_offset_65) -// let abi_decode__489_1056 := 0x1f -// if iszero(slt(add(_947, abi_decode__489_1056), _487)) -// { -// revert(_2, _2) -// } -// let abi_decode_length_6_1058 := calldataload(_947) -// if gt(abi_decode_length_6_1058, _945) -// { -// revert(_2, _2) -// } -// let abi_decode_array_5_254_1061 := allocateMemory(add(mul(abi_decode_length_6_1058, _1), _1)) -// let abi_decode_dst_7_1062 := abi_decode_array_5_254_1061 -// mstore(abi_decode_array_5_254_1061, abi_decode_length_6_1058) -// let abi_decode_offset_3_256_1063 := add(_947, _1) -// abi_decode_dst_7_1062 := add(abi_decode_array_5_254_1061, _1) -// let abi_decode_src_8_1064 := abi_decode_offset_3_256_1063 -// if gt(add(add(_947, mul(abi_decode_length_6_1058, _933)), _1), _487) -// { -// revert(_2, _2) -// } -// for { -// let abi_decode_i_9_1068 := _2 -// } -// lt(abi_decode_i_9_1068, abi_decode_length_6_1058) +// revert(array_13, array_13) +// } +// let length_14 := 0x2 +// let array_allo__559 := 0x20 +// let array_allo_size_95_605 := 64 +// let array_13_263 := allocateMemory(array_allo_size_95_605) +// array_13 := array_13_263 +// let dst_15 := array_13_263 +// let src_16 := offset_11 +// if gt(add(offset_11, array_allo_size_95_605), end_12) +// { +// let _59 := 0 +// revert(_59, _59) +// } +// let i_17 := 0 +// for { +// } +// lt(i_17, length_14) +// { +// i_17 := add(i_17, 1) +// } +// { +// mstore(dst_15, calldataload(src_16)) +// dst_15 := add(dst_15, array_allo__559) +// src_16 := add(src_16, array_allo__559) +// } +// } +// function abi_decode_t_array$_t_uint256_$dyn_memory_ptr(offset_27, end_28) -> array_29 +// { +// if iszero(slt(add(offset_27, 0x1f), end_28)) +// { +// revert(array_29, array_29) +// } +// let length_30 := calldataload(offset_27) +// let array_29_279 := allocateMemory(array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length_30)) +// array_29 := array_29_279 +// let dst_31 := array_29_279 +// mstore(array_29_279, length_30) +// let _91 := 0x20 +// let offset_27_281 := add(offset_27, _91) +// dst_31 := add(array_29_279, _91) +// let src_32 := offset_27_281 +// if gt(add(add(offset_27, mul(length_30, _91)), _91), end_28) +// { +// let _97 := 0 +// revert(_97, _97) +// } +// let i_33 := 0 +// for { +// } +// lt(i_33, length_30) +// { +// i_33 := add(i_33, 1) +// } +// { +// mstore(dst_31, calldataload(src_32)) +// dst_31 := add(dst_31, _91) +// src_32 := add(src_32, _91) +// } +// } +// function abi_decode_tuple_t_uint256t_uint256t_array$_t_uint256_$dyn_memory_ptrt_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(headStart_58, dataEnd_59) -> value0_60, value1_61, value2, value3 +// { +// if slt(sub(dataEnd_59, headStart_58), 128) +// { +// revert(value2, value2) +// } +// { +// value0_60 := calldataload(add(headStart_58, value2)) +// } +// { +// value1_61 := calldataload(add(headStart_58, 32)) +// } +// { +// let offset_64 := calldataload(add(headStart_58, 64)) +// if gt(offset_64, 0xffffffffffffffff) // { -// abi_decode_i_9_1068 := add(abi_decode_i_9_1068, 1) +// revert(value2, value2) // } +// value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(headStart_58, offset_64), dataEnd_59) +// } +// { +// let offset_65 := calldataload(add(headStart_58, 96)) +// if gt(offset_65, 0xffffffffffffffff) // { -// if iszero(slt(add(abi_decode_src_8_1064, abi_decode__489_1056), _487)) -// { -// revert(_2, _2) -// } -// let abi_decode_abi_decode_length_14_1069 := 0x2 -// if _2 -// { -// revert(_2, _2) -// } -// let allocateMe_memPtr_315 := mload(abi_encode_pos_590) -// let allocateMe_newFreePtr := add(allocateMe_memPtr_315, abi_encode_pos_590) -// if or(gt(allocateMe_newFreePtr, _945), lt(allocateMe_newFreePtr, allocateMe_memPtr_315)) -// { -// revert(_2, _2) -// } -// mstore(abi_encode_pos_590, allocateMe_newFreePtr) -// let abi_decode_abi_decode_dst_15_1071 := allocateMe_memPtr_315 -// let abi_decode_abi_decode_src_16_1072 := abi_decode_src_8_1064 -// if gt(add(abi_decode_src_8_1064, abi_encode_pos_590), _487) -// { -// revert(_2, _2) -// } -// for { -// let abi_decode_abi_decode_i_17_1073 := _2 -// } -// lt(abi_decode_abi_decode_i_17_1073, abi_decode_abi_decode_length_14_1069) -// { -// abi_decode_abi_decode_i_17_1073 := add(abi_decode_abi_decode_i_17_1073, 1) -// } -// { -// mstore(abi_decode_abi_decode_dst_15_1071, calldataload(abi_decode_abi_decode_src_16_1072)) -// abi_decode_abi_decode_dst_15_1071 := add(abi_decode_abi_decode_dst_15_1071, _1) -// abi_decode_abi_decode_src_16_1072 := add(abi_decode_abi_decode_src_16_1072, _1) -// } -// mstore(abi_decode_dst_7_1062, allocateMe_memPtr_315) -// abi_decode_dst_7_1062 := add(abi_decode_dst_7_1062, _1) -// abi_decode_src_8_1064 := add(abi_decode_src_8_1064, _933) +// revert(value3, value3) // } -// abi_decode_value3 := abi_decode_array_5_254_1061 +// value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(headStart_58, offset_65), dataEnd_59) // } -// sstore(abi_decode_value0_60, abi_decode_value1_61) -// sstore(abi_decode_value2, abi_decode_value3) -// sstore(_2, abi_encode_pos) // } // function allocateMemory(size) -> memPtr // { @@ -651,4 +639,22 @@ // } // mstore(_199, newFreePtr) // } +// function array_allocation_size_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(length_92) -> size_93 +// { +// if gt(length_92, 0xffffffffffffffff) +// { +// revert(size_93, size_93) +// } +// let _217 := 0x20 +// size_93 := add(mul(length_92, _217), _217) +// } +// function array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length_98) -> size_99 +// { +// if gt(length_98, 0xffffffffffffffff) +// { +// revert(size_99, size_99) +// } +// let _234 := 0x20 +// size_99 := add(mul(length_98, _234), _234) +// } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul index deb02068..fbe243d4 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/medium.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul @@ -9,16 +9,23 @@ pop(allocate(0x20)) let x := allocate(0x40) mstore(array_index_access(x, 3), 2) + if 0 { + mstore(0x40, 0x20) + } + if sub(2,1) { + for { switch mul(1,2) case 2 { mstore(0x40, 0x20) } } sub(1,1) {} { mstore(0x80, 0x40) } + } } // ---- // fullSuite // { // { -// let _18 := 0x20 -// let allocate__7 := 0x40 -// mstore(allocate__7, add(mload(allocate__7), _18)) -// let allocate_p_12_31 := mload(allocate__7) -// mstore(allocate__7, add(allocate_p_12_31, allocate__7)) -// mstore(add(allocate_p_12_31, 96), 2) +// let _1 := 0x20 +// let allocate__19 := 0x40 +// mstore(allocate__19, add(mload(allocate__19), _1)) +// let allocate_p_24_41 := mload(allocate__19) +// mstore(allocate__19, add(allocate_p_24_41, allocate__19)) +// mstore(add(allocate_p_24_41, 96), 2) +// mstore(allocate__19, _1) // } // } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/empty_if_movable_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/empty_if_movable_condition.yul new file mode 100644 index 00000000..ee1975e7 --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/empty_if_movable_condition.yul @@ -0,0 +1,7 @@ +{ let a := mload(0) if a {} } +// ---- +// structuralSimplifier +// { +// let a := mload(0) +// pop(a) +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/empty_if_non_movable_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/empty_if_non_movable_condition.yul new file mode 100644 index 00000000..5977297b --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/empty_if_non_movable_condition.yul @@ -0,0 +1,6 @@ +{ if mload(0) {} } +// ---- +// structuralSimplifier +// { +// pop(mload(0)) +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol b/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol new file mode 100644 index 00000000..b881a0a3 --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol @@ -0,0 +1,10 @@ +{ + for { let a := 42 } 0 { a := a } { + let b := a + } +} +// ---- +// structuralSimplifier +// { +// let a := 42 +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul new file mode 100644 index 00000000..0895b1bb --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul @@ -0,0 +1,5 @@ +{ if 0 { mstore(0, 0) } } +// ---- +// structuralSimplifier +// { +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul new file mode 100644 index 00000000..0ece5dbd --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul @@ -0,0 +1,10 @@ +{ + let x, y + if x { mstore(0, 0) } + if y { mstore(0, 0) } +} +// ---- +// structuralSimplifier +// { +// let x, y +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul new file mode 100644 index 00000000..ca9cba06 --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul @@ -0,0 +1,6 @@ +{ if 1 { mstore(0, 0) } } +// ---- +// structuralSimplifier +// { +// mstore(0, 0) +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul new file mode 100644 index 00000000..a327a882 --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul @@ -0,0 +1,9 @@ +{ + let x + if x { mstore(0, 0) } +} +// ---- +// structuralSimplifier +// { +// let x +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul new file mode 100644 index 00000000..169a84d1 --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul @@ -0,0 +1,6 @@ +{ if 1 { if 1 { for { mstore(0, 0) } 0 {} { mstore(2, 3) } if 0 { mstore(1, 2) } } } } +// ---- +// structuralSimplifier +// { +// mstore(0, 0) +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_only_default.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_only_default.yul new file mode 100644 index 00000000..7ca815a7 --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_only_default.yul @@ -0,0 +1,11 @@ +{ + switch mload(0) default { mstore(1, 2) } +} +// ---- +// structuralSimplifier +// { +// pop(mload(0)) +// { +// mstore(1, 2) +// } +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_to_if.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_to_if.yul new file mode 100644 index 00000000..a741ac2f --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_to_if.yul @@ -0,0 +1,11 @@ +{ + switch 1 case 2 { mstore(0, 0) } +} +// ---- +// structuralSimplifier +// { +// if eq(2, 1) +// { +// mstore(0, 0) +// } +// } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul new file mode 100644 index 00000000..5e2d60c2 --- /dev/null +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul @@ -0,0 +1,29 @@ +{ + // This component does not need the disambiguator + function f() -> x, y { + let a, b + mstore(a, b) + let d + d := 2 + } + let a + a := 4 + let b := 2 + let x, y := f() +} +// ---- +// varDeclInitializer +// { +// function f() -> x, y +// { +// let a := 0 +// let b := 0 +// mstore(a, b) +// let d := 0 +// d := 2 +// } +// let a := 0 +// a := 4 +// let b := 2 +// let x, y := f() +// } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul new file mode 100644 index 00000000..16428d7e --- /dev/null +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul @@ -0,0 +1,24 @@ +{ + function f() -> x, y { + let a, b + mstore(a, b) + let d + d := 2 + } + let r + r := 4 +} +// ---- +// varDeclInitializer +// { +// function f() -> x, y +// { +// let a := 0 +// let b := 0 +// mstore(a, b) +// let d := 0 +// d := 2 +// } +// let r := 0 +// r := 4 +// } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul new file mode 100644 index 00000000..02d731af --- /dev/null +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul @@ -0,0 +1,14 @@ +{ + let x, y, z + let a + let b +} +// ---- +// varDeclInitializer +// { +// let x := 0 +// let y := 0 +// let z := 0 +// let a := 0 +// let b := 0 +// } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul new file mode 100644 index 00000000..2e14fe70 --- /dev/null +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul @@ -0,0 +1,21 @@ +{ + function f() -> x, y { + let a, b := f() + let u + } + let r + let s := 3 + let t +} +// ---- +// varDeclInitializer +// { +// function f() -> x, y +// { +// let a, b := f() +// let u := 0 +// } +// let r := 0 +// let s := 3 +// let t := 0 +// } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul new file mode 100644 index 00000000..2a9bbe42 --- /dev/null +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul @@ -0,0 +1,8 @@ +{ + let a +} +// ---- +// varDeclInitializer +// { +// let a := 0 +// } diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/init_assignment_inside_if.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/init_assignment_inside_if.yul deleted file mode 100644 index 54fea2fb..00000000 --- a/test/libyul/yulOptimizerTests/varDeclPropagator/init_assignment_inside_if.yul +++ /dev/null @@ -1,17 +0,0 @@ -{ - let a := 4 - let x - if a { - x := 2 - } -} -// ---- -// varDeclPropagator -// { -// let a := 4 -// let x -// if a -// { -// x := 2 -// } -// } diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul deleted file mode 100644 index ed8d33b4..00000000 --- a/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul +++ /dev/null @@ -1,13 +0,0 @@ -{ - function f() -> a, b, c {} - let x, y, z - z, x, y := f() -} -// ---- -// varDeclPropagator -// { -// function f() -> a, b, c -// { -// } -// let z, x, y := f() -// } diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/overwrite.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/overwrite.yul deleted file mode 100644 index ca921500..00000000 --- a/test/libyul/yulOptimizerTests/varDeclPropagator/overwrite.yul +++ /dev/null @@ -1,11 +0,0 @@ -{ - let a - a := 4 - a := 5 -} -// ---- -// varDeclPropagator -// { -// let a := 4 -// a := 5 -// } diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/rewrite_removes_unused_var.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/rewrite_removes_unused_var.yul deleted file mode 100644 index 3affcac6..00000000 --- a/test/libyul/yulOptimizerTests/varDeclPropagator/rewrite_removes_unused_var.yul +++ /dev/null @@ -1,10 +0,0 @@ -{ - let a, b - a := mload(0) -} -// ---- -// varDeclPropagator -// { -// let b -// let a := mload(0) -// } diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul deleted file mode 100644 index d8959040..00000000 --- a/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul +++ /dev/null @@ -1,9 +0,0 @@ -{ - let f - f := mload(0) -} -// ---- -// varDeclPropagator -// { -// let f := mload(0) -// } diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/split_assign_splits_vardecl.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/split_assign_splits_vardecl.yul deleted file mode 100644 index e8c91e10..00000000 --- a/test/libyul/yulOptimizerTests/varDeclPropagator/split_assign_splits_vardecl.yul +++ /dev/null @@ -1,11 +0,0 @@ -{ - let a, b - a := mload(0) - b := mload(1) -} -// ---- -// varDeclPropagator -// { -// let a := mload(0) -// let b := mload(1) -// } diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/use_before_init.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/use_before_init.yul deleted file mode 100644 index 5312112a..00000000 --- a/test/libyul/yulOptimizerTests/varDeclPropagator/use_before_init.yul +++ /dev/null @@ -1,12 +0,0 @@ -{ - let b - let a := b - b := 1 -} -// ---- -// varDeclPropagator -// { -// let b -// let a := b -// b := 1 -// } diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/use_doesnt_rewrite.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/use_doesnt_rewrite.yul deleted file mode 100644 index e27785dd..00000000 --- a/test/libyul/yulOptimizerTests/varDeclPropagator/use_doesnt_rewrite.yul +++ /dev/null @@ -1,16 +0,0 @@ -{ - function f(x) {} - let a - f(a) - a := 4 -} -// ---- -// varDeclPropagator -// { -// function f(x) -// { -// } -// let a -// f(a) -// a := 4 -// } |