From c2ccb85c4b6cd32f0f42c8d3715ee8a2ad07ea6d Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Tue, 12 Mar 2024 15:48:14 +0100 Subject: [PATCH] [ethdebug] Transport debug data through common subexpression eliminator. --- .../CommonSubexpressionEliminator.cpp | 19 ++++++ test/libyul/YulOptimizerAssemblyTest.cpp | 29 ++++++++ test/libyul/YulOptimizerAssemblyTest.h | 9 +++ .../commonSubexpressionEliminator/basic.yul | 24 +++++++ .../function.yul | 66 +++++++++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 test/libyul/yulOptimizerAssemblyTests/commonSubexpressionEliminator/basic.yul create mode 100644 test/libyul/yulOptimizerAssemblyTests/commonSubexpressionEliminator/function.yul diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp index 1c7879056d61..8900303db416 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.cpp +++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp @@ -120,6 +120,25 @@ void CommonSubexpressionEliminator::visit(Expression& _e) // We check for syntactic equality again because the value might have changed. if (inScope(variable) && SyntacticallyEqual{}(_e, *value->value)) { + if (debugDataOf(*value->value)) + { + langutil::DebugData::Attributes mergedDebugAttributes; + if (debugDataOf(*value->value)->attributes.has_value()) + mergedDebugAttributes = debugDataOf(*value->value)->attributes; + if (debugDataOf(_e) && mergedDebugAttributes.has_value()) + { + for (auto const& i: debugDataOf(_e)->attributes.value()) + mergedDebugAttributes->emplace_back(i); + _e = Identifier{ + langutil::DebugData::create( + debugDataOf(_e)->nativeLocation, + debugDataOf(_e)->originLocation, + debugDataOf(_e)->astID, + mergedDebugAttributes), + variable}; + break; + } + } _e = Identifier{debugDataOf(_e), variable}; break; } diff --git a/test/libyul/YulOptimizerAssemblyTest.cpp b/test/libyul/YulOptimizerAssemblyTest.cpp index 2e600c3d4dd3..98d539d9cc3c 100644 --- a/test/libyul/YulOptimizerAssemblyTest.cpp +++ b/test/libyul/YulOptimizerAssemblyTest.cpp @@ -19,12 +19,14 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -60,6 +62,10 @@ YulOptimizerAssemblyTest::YulOptimizerAssemblyTest(std::string const& _filename) m_optimizerStep = std::prev(std::prev(path.end()))->string(); m_source = m_reader.source(); + + auto dialectName = m_reader.stringSetting("dialect", "evm"); + m_dialect = &dialect(dialectName, solidity::test::CommonOptions::get().evmVersion()); + m_expectation = m_reader.simpleExpectations(); } @@ -104,3 +110,26 @@ TestCase::TestResult YulOptimizerAssemblyTest::run(std::ostream& _stream, std::s return checkResult(_stream, _linePrefix, _formatted); } + +std::pair, std::shared_ptr> YulOptimizerAssemblyTest::parse( + std::ostream& _stream, + std::string const& _linePrefix, + bool const _formatted, + std::string const& _source +) +{ + ErrorList errors; + soltestAssert(m_dialect, ""); + std::shared_ptr object; + std::shared_ptr analysisInfo; + std::tie(object, analysisInfo) = yul::test::parse(_source, *m_dialect, errors); + if (!object || !analysisInfo || Error::containsErrors(errors)) + { + AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; + CharStream charStream(_source, ""); + SourceReferenceFormatter{_stream, SingletonCharStreamProvider(charStream), true, false} + .printErrorInformation(errors); + return {}; + } + return {std::move(object), std::move(analysisInfo)}; +} diff --git a/test/libyul/YulOptimizerAssemblyTest.h b/test/libyul/YulOptimizerAssemblyTest.h index eeae052458fd..35fd09569db5 100644 --- a/test/libyul/YulOptimizerAssemblyTest.h +++ b/test/libyul/YulOptimizerAssemblyTest.h @@ -48,7 +48,16 @@ class YulOptimizerAssemblyTest: public solidity::frontend::test::EVMVersionRestr TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; private: + std::pair, std::shared_ptr> parse( + std::ostream& _stream, std::string const& _linePrefix, bool const _formatted, std::string const& _source + ); + std::string m_optimizerStep; + + Dialect const* m_dialect = nullptr; + + std::shared_ptr m_object; + std::shared_ptr m_analysisInfo; }; } diff --git a/test/libyul/yulOptimizerAssemblyTests/commonSubexpressionEliminator/basic.yul b/test/libyul/yulOptimizerAssemblyTests/commonSubexpressionEliminator/basic.yul new file mode 100644 index 000000000000..8740156eb59b --- /dev/null +++ b/test/libyul/yulOptimizerAssemblyTests/commonSubexpressionEliminator/basic.yul @@ -0,0 +1,24 @@ +{ + let a := /** @debug.set {"assignment":"a"} */ mul(1, codesize()) /** @debug.set {} */ + let b := /** @debug.set {"assignment":"b"} */ mul(1, codesize()) /** @debug.set {} */ +} +// ---- +// step: commonSubexpressionEliminator +// +// { +// let a := /** @debug.set {"assignment":"a"} */ mul(1, codesize()) +// let b := a +// } +// +// Assembly: +// /* "":59:69 */ +// codesize // @debug.set {"assignment":"a"} +// /* "":56:57 */ +// 0x01 // @debug.set {"assignment":"a"} +// /* "":52:70 */ +// mul // @debug.set {"assignment":"a"} +// /* "":142:160 */ +// dup1 // @debug.set [{"assignment":"a"},{"assignment":"b"}] +// /* "":0:183 */ +// pop +// pop diff --git a/test/libyul/yulOptimizerAssemblyTests/commonSubexpressionEliminator/function.yul b/test/libyul/yulOptimizerAssemblyTests/commonSubexpressionEliminator/function.yul new file mode 100644 index 000000000000..903733b44cc8 --- /dev/null +++ b/test/libyul/yulOptimizerAssemblyTests/commonSubexpressionEliminator/function.yul @@ -0,0 +1,66 @@ +{ + function f(a, b) + { + } + let x := /** @debug.set {"id": 0} */ 42 /** @debug.set {} */ + let y := /** @debug.set {"id":" 1"} */ add(sload(42), calldataload(0)) /** @debug.set {} */ + let z := /** @debug.set {"id":"2"} */ 42 /** @debug.set {} */ + f(/** @debug.set {"f": 0} */ 42, /** @debug.set {"f": 1} */add(sload(42), /** @debug.set {"f": 2} */calldataload(0))) /** @debug.set {} */ +} +// ---- +// step: commonSubexpressionEliminator +// +// { +// let x := /** @debug.set {"id":0} */ 42 +// let y := /** @debug.set {"id":" 1"} */ add(sload(x), /** @debug.set {"id":" 1"} */ calldataload(0)) +// let z := x +// f(x, /** @debug.set {"f":1} */ add(sload(x), /** @debug.set {"f":2} */ calldataload(0))) +// function f(a, b) +// { } +// } +// +// Assembly: +// /* "":76:78 */ +// 0x2a // @debug.set {"id":0} +// /* "":171:172 */ +// 0x00 // @debug.set {"id":" 1"} +// /* "":158:173 */ +// calldataload // @debug.set {"id":" 1"} +// /* "":153:155 */ +// dup2 // @debug.set [{"id":0},{"id":" 1"}] +// /* "":147:156 */ +// sload // @debug.set {"id":" 1"} +// /* "":143:174 */ +// add // @debug.set {"id":" 1"} +// /* "":238:240 */ +// dup2 // @debug.set [{"id":0},{"id":"2"}] +// /* "":266:383 */ +// tag_2 +// /* "":379:380 */ +// 0x00 // @debug.set {"f":2} +// /* "":366:381 */ +// calldataload // @debug.set {"f":2} +// /* "":335:337 */ +// dup5 // @debug.set [{"id":0},{"f":1}] +// /* "":329:338 */ +// sload // @debug.set {"f":1} +// /* "":325:382 */ +// add // @debug.set {"f":1} +// /* "":295:297 */ +// dup5 // @debug.set [{"id":0},{"f":0}] +// /* "":266:383 */ +// tag_1 +// jump // in +// tag_2: +// /* "":6:34 */ +// jump(tag_3) +// tag_1: +// pop +// pop +// tag_4: +// jump // out +// tag_3: +// /* "":0:406 */ +// pop +// pop +// pop