diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 9a3f41b68..0f52bdaa2 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index d8bd02842..77d09706a 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -49,10 +49,12 @@ add_library(yul Utilities.h YulString.h backends/evm/AbstractAssembly.h - backends/evm/AsmCodeGen.h backends/evm/AsmCodeGen.cpp + backends/evm/AsmCodeGen.h backends/evm/ConstantOptimiser.cpp backends/evm/ConstantOptimiser.h + backends/evm/EthAssemblyAdapter.cpp + backends/evm/EthAssemblyAdapter.h backends/evm/EVMAssembly.cpp backends/evm/EVMAssembly.h backends/evm/EVMCodeTransform.cpp diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index fa9122fdc..bda3ad9e7 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -16,27 +16,15 @@ */ // SPDX-License-Identifier: GPL-3.0 /** - * Adaptor between the abstract assembly and eth assembly. + * Helper to compile Yul code using libevmasm. */ #include -#include -#include - -#include +#include #include - -#include -#include -#include - -#include - -#include - -#include -#include +#include +#include using namespace std; using namespace solidity; @@ -44,169 +32,6 @@ using namespace solidity::yul; using namespace solidity::util; using namespace solidity::langutil; -EthAssemblyAdapter::EthAssemblyAdapter(evmasm::Assembly& _assembly): - m_assembly(_assembly) -{ -} - -void EthAssemblyAdapter::setSourceLocation(SourceLocation const& _location) -{ - m_assembly.setSourceLocation(_location); -} - -int EthAssemblyAdapter::stackHeight() const -{ - return m_assembly.deposit(); -} - -void EthAssemblyAdapter::setStackHeight(int height) -{ - m_assembly.setDeposit(height); -} - -void EthAssemblyAdapter::appendInstruction(evmasm::Instruction _instruction) -{ - m_assembly.append(_instruction); -} - -void EthAssemblyAdapter::appendConstant(u256 const& _constant) -{ - m_assembly.append(_constant); -} - -void EthAssemblyAdapter::appendLabel(LabelID _labelId) -{ - m_assembly.append(evmasm::AssemblyItem(evmasm::Tag, _labelId)); -} - -void EthAssemblyAdapter::appendLabelReference(LabelID _labelId) -{ - m_assembly.append(evmasm::AssemblyItem(evmasm::PushTag, _labelId)); -} - -size_t EthAssemblyAdapter::newLabelId() -{ - return assemblyTagToIdentifier(m_assembly.newTag()); -} - -size_t EthAssemblyAdapter::namedLabel(std::string const& _name) -{ - return assemblyTagToIdentifier(m_assembly.namedTag(_name)); -} - -void EthAssemblyAdapter::appendLinkerSymbol(std::string const& _linkerSymbol) -{ - m_assembly.appendLibraryAddress(_linkerSymbol); -} - -void EthAssemblyAdapter::appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) -{ - m_assembly.appendVerbatim(move(_data), _arguments, _returnVariables); -} - -void EthAssemblyAdapter::appendJump(int _stackDiffAfter, JumpType _jumpType) -{ - appendJumpInstruction(evmasm::Instruction::JUMP, _jumpType); - m_assembly.adjustDeposit(_stackDiffAfter); -} - -void EthAssemblyAdapter::appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) -{ - appendLabelReference(_labelId); - appendJump(_stackDiffAfter, _jumpType); -} - -void EthAssemblyAdapter::appendJumpToIf(LabelID _labelId, JumpType _jumpType) -{ - appendLabelReference(_labelId); - appendJumpInstruction(evmasm::Instruction::JUMPI, _jumpType); -} - -void EthAssemblyAdapter::appendAssemblySize() -{ - m_assembly.appendProgramSize(); -} - -pair, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name) -{ - shared_ptr assembly{make_shared(std::move(_name))}; - auto sub = m_assembly.newSub(assembly); - return {make_shared(*assembly), static_cast(sub.data())}; -} - -void EthAssemblyAdapter::appendDataOffset(vector const& _subPath) -{ - if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end()) - { - yulAssert(_subPath.size() == 1, ""); - m_assembly << evmasm::AssemblyItem(evmasm::PushData, it->second); - return; - } - - m_assembly.pushSubroutineOffset(m_assembly.encodeSubPath(_subPath)); -} - -void EthAssemblyAdapter::appendDataSize(vector const& _subPath) -{ - if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end()) - { - yulAssert(_subPath.size() == 1, ""); - m_assembly << u256(m_assembly.data(h256(it->second)).size()); - return; - } - - m_assembly.pushSubroutineSize(m_assembly.encodeSubPath(_subPath)); -} - -AbstractAssembly::SubID EthAssemblyAdapter::appendData(bytes const& _data) -{ - evmasm::AssemblyItem pushData = m_assembly.newData(_data); - SubID subID = m_nextDataCounter++; - m_dataHashBySubId[subID] = pushData.data(); - return subID; -} - -void EthAssemblyAdapter::appendImmutable(std::string const& _identifier) -{ - m_assembly.appendImmutable(_identifier); -} - -void EthAssemblyAdapter::appendImmutableAssignment(std::string const& _identifier) -{ - m_assembly.appendImmutableAssignment(_identifier); -} - -void EthAssemblyAdapter::markAsInvalid() -{ - m_assembly.markAsInvalid(); -} - -EthAssemblyAdapter::LabelID EthAssemblyAdapter::assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag) -{ - u256 id = _tag.data(); - yulAssert(id <= std::numeric_limits::max(), "Tag id too large."); - return LabelID(id); -} - -void EthAssemblyAdapter::appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType) -{ - yulAssert(_instruction == evmasm::Instruction::JUMP || _instruction == evmasm::Instruction::JUMPI, ""); - evmasm::AssemblyItem jump(_instruction); - switch (_jumpType) - { - case JumpType::Ordinary: - yulAssert(jump.getJumpType() == evmasm::AssemblyItem::JumpType::Ordinary, ""); - break; - case JumpType::IntoFunction: - jump.setJumpType(evmasm::AssemblyItem::JumpType::IntoFunction); - break; - case JumpType::OutOfFunction: - jump.setJumpType(evmasm::AssemblyItem::JumpType::OutOfFunction); - break; - } - m_assembly.append(std::move(jump)); -} - void CodeGenerator::assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, diff --git a/libyul/backends/evm/AsmCodeGen.h b/libyul/backends/evm/AsmCodeGen.h index cab2c4003..35db4e7a0 100644 --- a/libyul/backends/evm/AsmCodeGen.h +++ b/libyul/backends/evm/AsmCodeGen.h @@ -16,63 +16,24 @@ */ // SPDX-License-Identifier: GPL-3.0 /** - * Adaptor between the abstract assembly and eth assembly. + * Helper to compile Yul code using libevmasm. */ #pragma once #include #include -#include -#include +#include namespace solidity::evmasm { class Assembly; -class AssemblyItem; } namespace solidity::yul { struct Block; - -class EthAssemblyAdapter: public AbstractAssembly -{ -public: - explicit EthAssemblyAdapter(evmasm::Assembly& _assembly); - void setSourceLocation(langutil::SourceLocation const& _location) override; - int stackHeight() const override; - void setStackHeight(int height) override; - void appendInstruction(evmasm::Instruction _instruction) override; - void appendConstant(u256 const& _constant) override; - void appendLabel(LabelID _labelId) override; - void appendLabelReference(LabelID _labelId) override; - size_t newLabelId() override; - size_t namedLabel(std::string const& _name) override; - void appendLinkerSymbol(std::string const& _linkerSymbol) override; - void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override; - void appendJump(int _stackDiffAfter, JumpType _jumpType) override; - void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override; - void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; - void appendAssemblySize() override; - std::pair, SubID> createSubAssembly(std::string _name = {}) override; - void appendDataOffset(std::vector const& _subPath) override; - void appendDataSize(std::vector const& _subPath) override; - SubID appendData(bytes const& _data) override; - - void appendImmutable(std::string const& _identifier) override; - void appendImmutableAssignment(std::string const& _identifier) override; - - void markAsInvalid() override; - -private: - static LabelID assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag); - void appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType); - - evmasm::Assembly& m_assembly; - std::map m_dataHashBySubId; - size_t m_nextDataCounter = std::numeric_limits::max() / 2; -}; +struct AsmAnalysisInfo; class CodeGenerator { @@ -88,5 +49,4 @@ public: bool _optimizeStackAllocation = false ); }; - } diff --git a/libyul/backends/evm/EthAssemblyAdapter.cpp b/libyul/backends/evm/EthAssemblyAdapter.cpp new file mode 100644 index 000000000..ed2c81777 --- /dev/null +++ b/libyul/backends/evm/EthAssemblyAdapter.cpp @@ -0,0 +1,203 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Adaptor between AbstractAssembly and libevmasm. + */ + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::yul; +using namespace solidity::util; +using namespace solidity::langutil; + +EthAssemblyAdapter::EthAssemblyAdapter(evmasm::Assembly& _assembly): + m_assembly(_assembly) +{ +} + +void EthAssemblyAdapter::setSourceLocation(SourceLocation const& _location) +{ + m_assembly.setSourceLocation(_location); +} + +int EthAssemblyAdapter::stackHeight() const +{ + return m_assembly.deposit(); +} + +void EthAssemblyAdapter::setStackHeight(int height) +{ + m_assembly.setDeposit(height); +} + +void EthAssemblyAdapter::appendInstruction(evmasm::Instruction _instruction) +{ + m_assembly.append(_instruction); +} + +void EthAssemblyAdapter::appendConstant(u256 const& _constant) +{ + m_assembly.append(_constant); +} + +void EthAssemblyAdapter::appendLabel(LabelID _labelId) +{ + m_assembly.append(evmasm::AssemblyItem(evmasm::Tag, _labelId)); +} + +void EthAssemblyAdapter::appendLabelReference(LabelID _labelId) +{ + m_assembly.append(evmasm::AssemblyItem(evmasm::PushTag, _labelId)); +} + +size_t EthAssemblyAdapter::newLabelId() +{ + return assemblyTagToIdentifier(m_assembly.newTag()); +} + +size_t EthAssemblyAdapter::namedLabel(std::string const& _name) +{ + return assemblyTagToIdentifier(m_assembly.namedTag(_name)); +} + +void EthAssemblyAdapter::appendLinkerSymbol(std::string const& _linkerSymbol) +{ + m_assembly.appendLibraryAddress(_linkerSymbol); +} + +void EthAssemblyAdapter::appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) +{ + m_assembly.appendVerbatim(move(_data), _arguments, _returnVariables); +} + +void EthAssemblyAdapter::appendJump(int _stackDiffAfter, JumpType _jumpType) +{ + appendJumpInstruction(evmasm::Instruction::JUMP, _jumpType); + m_assembly.adjustDeposit(_stackDiffAfter); +} + +void EthAssemblyAdapter::appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) +{ + appendLabelReference(_labelId); + appendJump(_stackDiffAfter, _jumpType); +} + +void EthAssemblyAdapter::appendJumpToIf(LabelID _labelId, JumpType _jumpType) +{ + appendLabelReference(_labelId); + appendJumpInstruction(evmasm::Instruction::JUMPI, _jumpType); +} + +void EthAssemblyAdapter::appendAssemblySize() +{ + m_assembly.appendProgramSize(); +} + +pair, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name) +{ + shared_ptr assembly{make_shared(std::move(_name))}; + auto sub = m_assembly.newSub(assembly); + return {make_shared(*assembly), static_cast(sub.data())}; +} + +void EthAssemblyAdapter::appendDataOffset(vector const& _subPath) +{ + if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end()) + { + yulAssert(_subPath.size() == 1, ""); + m_assembly << evmasm::AssemblyItem(evmasm::PushData, it->second); + return; + } + + m_assembly.pushSubroutineOffset(m_assembly.encodeSubPath(_subPath)); +} + +void EthAssemblyAdapter::appendDataSize(vector const& _subPath) +{ + if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end()) + { + yulAssert(_subPath.size() == 1, ""); + m_assembly << u256(m_assembly.data(h256(it->second)).size()); + return; + } + + m_assembly.pushSubroutineSize(m_assembly.encodeSubPath(_subPath)); +} + +AbstractAssembly::SubID EthAssemblyAdapter::appendData(bytes const& _data) +{ + evmasm::AssemblyItem pushData = m_assembly.newData(_data); + SubID subID = m_nextDataCounter++; + m_dataHashBySubId[subID] = pushData.data(); + return subID; +} + +void EthAssemblyAdapter::appendImmutable(std::string const& _identifier) +{ + m_assembly.appendImmutable(_identifier); +} + +void EthAssemblyAdapter::appendImmutableAssignment(std::string const& _identifier) +{ + m_assembly.appendImmutableAssignment(_identifier); +} + +void EthAssemblyAdapter::markAsInvalid() +{ + m_assembly.markAsInvalid(); +} + +EthAssemblyAdapter::LabelID EthAssemblyAdapter::assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag) +{ + u256 id = _tag.data(); + yulAssert(id <= std::numeric_limits::max(), "Tag id too large."); + return LabelID(id); +} + +void EthAssemblyAdapter::appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType) +{ + yulAssert(_instruction == evmasm::Instruction::JUMP || _instruction == evmasm::Instruction::JUMPI, ""); + evmasm::AssemblyItem jump(_instruction); + switch (_jumpType) + { + case JumpType::Ordinary: + yulAssert(jump.getJumpType() == evmasm::AssemblyItem::JumpType::Ordinary, ""); + break; + case JumpType::IntoFunction: + jump.setJumpType(evmasm::AssemblyItem::JumpType::IntoFunction); + break; + case JumpType::OutOfFunction: + jump.setJumpType(evmasm::AssemblyItem::JumpType::OutOfFunction); + break; + } + m_assembly.append(std::move(jump)); +} diff --git a/libyul/backends/evm/EthAssemblyAdapter.h b/libyul/backends/evm/EthAssemblyAdapter.h new file mode 100644 index 000000000..26c256d5b --- /dev/null +++ b/libyul/backends/evm/EthAssemblyAdapter.h @@ -0,0 +1,74 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Adaptor between AbstractAssembly and libevmasm. + */ + +#pragma once + +#include +#include +#include +#include + +namespace solidity::evmasm +{ +class Assembly; +class AssemblyItem; +} + +namespace solidity::yul +{ +class EthAssemblyAdapter: public AbstractAssembly +{ +public: + explicit EthAssemblyAdapter(evmasm::Assembly& _assembly); + void setSourceLocation(langutil::SourceLocation const& _location) override; + int stackHeight() const override; + void setStackHeight(int height) override; + void appendInstruction(evmasm::Instruction _instruction) override; + void appendConstant(u256 const& _constant) override; + void appendLabel(LabelID _labelId) override; + void appendLabelReference(LabelID _labelId) override; + size_t newLabelId() override; + size_t namedLabel(std::string const& _name) override; + void appendLinkerSymbol(std::string const& _linkerSymbol) override; + void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override; + void appendJump(int _stackDiffAfter, JumpType _jumpType) override; + void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override; + void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; + void appendAssemblySize() override; + std::pair, SubID> createSubAssembly(std::string _name = {}) override; + void appendDataOffset(std::vector const& _subPath) override; + void appendDataSize(std::vector const& _subPath) override; + SubID appendData(bytes const& _data) override; + + void appendImmutable(std::string const& _identifier) override; + void appendImmutableAssignment(std::string const& _identifier) override; + + void markAsInvalid() override; + +private: + static LabelID assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag); + void appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType); + + evmasm::Assembly& m_assembly; + std::map m_dataHashBySubId; + size_t m_nextDataCounter = std::numeric_limits::max() / 2; +}; +}