diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/boostTest.cpp | 7 | ||||
-rw-r--r-- | test/libyul/ObjectCompilerTest.cpp | 134 | ||||
-rw-r--r-- | test/libyul/ObjectCompilerTest.h | 69 | ||||
-rw-r--r-- | test/libyul/objectCompiler/data.yul | 11 | ||||
-rw-r--r-- | test/libyul/objectCompiler/namedObject.yul | 6 | ||||
-rw-r--r-- | test/libyul/objectCompiler/namedObjectCode.yul | 13 | ||||
-rw-r--r-- | test/libyul/objectCompiler/nested_optimizer.yul | 49 | ||||
-rw-r--r-- | test/libyul/objectCompiler/simple.yul | 13 | ||||
-rw-r--r-- | test/libyul/objectCompiler/simple_optimizer.yul | 23 | ||||
-rw-r--r-- | test/libyul/objectCompiler/smoke.yul | 5 | ||||
-rw-r--r-- | test/libyul/objectCompiler/subObject.yul | 21 | ||||
-rw-r--r-- | test/libyul/objectCompiler/subSubObject.yul | 39 | ||||
-rw-r--r-- | test/tools/CMakeLists.txt | 18 | ||||
-rw-r--r-- | test/tools/isoltest.cpp | 12 |
14 files changed, 417 insertions, 3 deletions
diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 7cb0c143..ff443d11 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -40,6 +40,7 @@ #include <test/libsolidity/SyntaxTest.h> #include <test/libsolidity/SMTCheckerJSONTest.h> #include <test/libyul/YulOptimizerTest.h> +#include <test/libyul/ObjectCompilerTest.h> #include <boost/algorithm/string.hpp> #include <boost/algorithm/string/predicate.hpp> @@ -146,6 +147,12 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) "yulOptimizerTests", yul::test::YulOptimizerTest::create ) > 0, "no Yul Optimizer tests found"); + solAssert(registerTests( + master, + dev::test::Options::get().testPath / "libyul", + "objectCompiler", + yul::test::ObjectCompilerTest::create + ) > 0, "no Yul Object compiler tests found"); if (!dev::test::Options::get().disableSMT) { solAssert(registerTests( 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/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/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/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 736212fc..da8e0b39 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -4,7 +4,19 @@ target_link_libraries(solfuzzer PRIVATE libsolc evmasm ${Boost_PROGRAM_OPTIONS_L add_executable(yulopti yulopti.cpp) target_link_libraries(yulopti PRIVATE solidity ${Boost_PROGRAM_OPTIONS_LIBRARIES} ${Boost_SYSTEM_LIBRARIES}) -add_executable(isoltest isoltest.cpp ../Options.cpp ../Common.cpp ../TestCase.cpp ../libsolidity/SyntaxTest.cpp - ../libsolidity/AnalysisFramework.cpp ../libsolidity/SolidityExecutionFramework.cpp ../ExecutionFramework.cpp - ../RPCSession.cpp ../libsolidity/ASTJSONTest.cpp ../libsolidity/SMTCheckerJSONTest.cpp ../libyul/YulOptimizerTest.cpp) +add_executable(isoltest + isoltest.cpp + ../Options.cpp + ../Common.cpp + ../TestCase.cpp + ../libsolidity/SyntaxTest.cpp + ../libsolidity/AnalysisFramework.cpp + ../libsolidity/SolidityExecutionFramework.cpp + ../ExecutionFramework.cpp + ../RPCSession.cpp + ../libsolidity/ASTJSONTest.cpp + ../libsolidity/SMTCheckerJSONTest.cpp + ../libyul/ObjectCompilerTest.cpp + ../libyul/YulOptimizerTest.cpp +) target_link_libraries(isoltest PRIVATE libsolc solidity evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index f8e2dc58..13585887 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -23,6 +23,7 @@ #include <test/libsolidity/ASTJSONTest.h> #include <test/libsolidity/SMTCheckerJSONTest.h> #include <test/libyul/YulOptimizerTest.h> +#include <test/libyul/ObjectCompilerTest.h> #include <boost/algorithm/string.hpp> #include <boost/algorithm/string/replace.hpp> @@ -401,6 +402,17 @@ Allowed options)", else return 1; + if (auto stats = runTestSuite( + "Yul Object Compiler", + testPath / "libyul", + "objectCompiler", + yul::test::ObjectCompilerTest::create, + formatted + )) + global_stats += *stats; + else + return 1; + if (!disableSMT) { if (auto stats = runTestSuite( |