diff options
Diffstat (limited to 'libyul')
-rw-r--r-- | libyul/AsmAnalysis.cpp | 4 | ||||
-rw-r--r-- | libyul/AsmCodeGen.cpp | 163 | ||||
-rw-r--r-- | libyul/CMakeLists.txt | 2 | ||||
-rw-r--r-- | libyul/backends/evm/AbstractAssembly.h | 10 | ||||
-rw-r--r-- | libyul/backends/evm/EVMAssembly.cpp | 21 | ||||
-rw-r--r-- | libyul/backends/evm/EVMAssembly.h | 4 | ||||
-rw-r--r-- | libyul/backends/evm/EVMObjectCompiler.cpp | 55 | ||||
-rw-r--r-- | libyul/backends/evm/EVMObjectCompiler.h (renamed from libyul/AsmCodeGen.h) | 41 | ||||
-rw-r--r-- | libyul/optimiser/FullInliner.cpp | 24 | ||||
-rw-r--r-- | libyul/optimiser/FullInliner.h | 12 | ||||
-rw-r--r-- | libyul/optimiser/SSAValueTracker.cpp | 2 | ||||
-rw-r--r-- | libyul/optimiser/SSAValueTracker.h | 2 | ||||
-rw-r--r-- | libyul/optimiser/SimplificationRules.cpp | 3 |
13 files changed, 137 insertions, 206 deletions
diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 3cbed9c7..1be1cf1a 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -629,7 +629,9 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio if (_instr == solidity::Instruction::JUMP || _instr == solidity::Instruction::JUMPI || _instr == solidity::Instruction::JUMPDEST) { - solAssert(m_dialect.flavour == AsmFlavour::Loose, ""); + if (m_dialect.flavour != AsmFlavour::Loose) + solAssert(m_errorTypeForLoose && *m_errorTypeForLoose != Error::Type::Warning, ""); + m_errorReporter.error( m_errorTypeForLoose ? *m_errorTypeForLoose : Error::Type::Warning, _location, diff --git a/libyul/AsmCodeGen.cpp b/libyul/AsmCodeGen.cpp deleted file mode 100644 index 23bf395d..00000000 --- a/libyul/AsmCodeGen.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - 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/>. -*/ -/** - * @author Christian <c@ethdev.com> - * @date 2016 - * Code-generating part of inline assembly. - */ - -#include <libyul/AsmCodeGen.h> - -#include <libyul/AsmParser.h> -#include <libyul/AsmData.h> -#include <libyul/AsmScope.h> -#include <libyul/AsmAnalysis.h> -#include <libyul/AsmAnalysisInfo.h> - -#include <libyul/backends/evm/AbstractAssembly.h> -#include <libyul/backends/evm/EVMCodeTransform.h> - -#include <libevmasm/Assembly.h> -#include <libevmasm/Instruction.h> - -#include <liblangutil/SourceLocation.h> - -#include <libdevcore/CommonIO.h> - -#include <boost/range/adaptor/reversed.hpp> -#include <boost/range/adaptor/map.hpp> -#include <boost/range/algorithm/count_if.hpp> - -#include <memory> -#include <functional> - -using namespace std; -using namespace dev; -using namespace langutil; -using namespace yul; -using namespace dev::solidity; - -class EthAssemblyAdapter: public AbstractAssembly -{ -public: - explicit EthAssemblyAdapter(eth::Assembly& _assembly): - m_assembly(_assembly) - { - } - virtual void setSourceLocation(SourceLocation const& _location) override - { - m_assembly.setSourceLocation(_location); - } - virtual int stackHeight() const override { return m_assembly.deposit(); } - virtual void appendInstruction(solidity::Instruction _instruction) override - { - m_assembly.append(_instruction); - } - virtual void appendConstant(u256 const& _constant) override - { - m_assembly.append(_constant); - } - /// Append a label. - virtual void appendLabel(LabelID _labelId) override - { - m_assembly.append(eth::AssemblyItem(eth::Tag, _labelId)); - } - /// Append a label reference. - virtual void appendLabelReference(LabelID _labelId) override - { - m_assembly.append(eth::AssemblyItem(eth::PushTag, _labelId)); - } - virtual size_t newLabelId() override - { - return assemblyTagToIdentifier(m_assembly.newTag()); - } - virtual size_t namedLabel(std::string const& _name) override - { - return assemblyTagToIdentifier(m_assembly.namedTag(_name)); - } - virtual void appendLinkerSymbol(std::string const& _linkerSymbol) override - { - m_assembly.appendLibraryAddress(_linkerSymbol); - } - virtual void appendJump(int _stackDiffAfter) override - { - appendInstruction(solidity::Instruction::JUMP); - m_assembly.adjustDeposit(_stackDiffAfter); - } - virtual void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override - { - appendLabelReference(_labelId); - appendJump(_stackDiffAfter); - } - virtual void appendJumpToIf(LabelID _labelId) override - { - appendLabelReference(_labelId); - appendInstruction(solidity::Instruction::JUMPI); - } - virtual void appendBeginsub(LabelID, int) override - { - // TODO we could emulate that, though - solAssert(false, "BEGINSUB not implemented for EVM 1.0"); - } - /// Call a subroutine. - virtual void appendJumpsub(LabelID, int, int) override - { - // TODO we could emulate that, though - solAssert(false, "JUMPSUB not implemented for EVM 1.0"); - } - - /// Return from a subroutine. - virtual void appendReturnsub(int, int) override - { - // TODO we could emulate that, though - solAssert(false, "RETURNSUB not implemented for EVM 1.0"); - } - - virtual void appendAssemblySize() override - { - m_assembly.appendProgramSize(); - } - -private: - static LabelID assemblyTagToIdentifier(eth::AssemblyItem const& _tag) - { - u256 id = _tag.data(); - solAssert(id <= std::numeric_limits<LabelID>::max(), "Tag id too large."); - return LabelID(id); - } - - eth::Assembly& m_assembly; -}; - -void CodeGenerator::assemble( - Block const& _parsedData, - AsmAnalysisInfo& _analysisInfo, - eth::Assembly& _assembly, - ExternalIdentifierAccess const& _identifierAccess, - bool _useNamedLabelsForFunctions -) -{ - EthAssemblyAdapter assemblyAdapter(_assembly); - CodeTransform( - assemblyAdapter, - _analysisInfo, - false, - false, - _identifierAccess, - _useNamedLabelsForFunctions - )(_parsedData); -} diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index e7383e4a..4bc8200c 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -1,7 +1,6 @@ add_library(yul AsmAnalysis.cpp AsmAnalysisInfo.cpp - AsmCodeGen.cpp AsmParser.cpp AsmPrinter.cpp AsmScope.cpp @@ -11,6 +10,7 @@ add_library(yul ObjectParser.cpp backends/evm/EVMAssembly.cpp backends/evm/EVMCodeTransform.cpp + backends/evm/EVMObjectCompiler.cpp optimiser/ASTCopier.cpp optimiser/ASTWalker.cpp optimiser/BlockFlattener.cpp diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 97b1d305..1f224ded 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -26,6 +26,7 @@ #include <libdevcore/CommonData.h> #include <functional> +#include <memory> namespace langutil { @@ -52,6 +53,7 @@ class AbstractAssembly { public: using LabelID = size_t; + using SubID = size_t; virtual ~AbstractAssembly() {} @@ -98,6 +100,14 @@ public: /// Append the assembled size as a constant. virtual void appendAssemblySize() = 0; + /// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset. + virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly() = 0; + /// Appends the offset of the given sub-assembly or data. + virtual void appendDataOffset(SubID _sub) = 0; + /// Appends the size of the given sub-assembly or data. + virtual void appendDataSize(SubID _sub) = 0; + /// Appends the given data to the assembly and returns its ID. + virtual SubID appendData(dev::bytes const& _data) = 0; }; enum class IdentifierContext { LValue, RValue }; diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index 99506317..2cf9f001 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -194,6 +194,27 @@ void EVMAssembly::appendAssemblySize() m_bytecode += bytes(assemblySizeReferenceSize); } +pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EVMAssembly::createSubAssembly() +{ + solAssert(false, "Sub assemblies not implemented."); + return {}; +} + +void EVMAssembly::appendDataOffset(AbstractAssembly::SubID) +{ + solAssert(false, "Data not implemented."); +} + +void EVMAssembly::appendDataSize(AbstractAssembly::SubID) +{ + solAssert(false, "Data not implemented."); +} + +AbstractAssembly::SubID EVMAssembly::appendData(bytes const&) +{ + solAssert(false, "Data not implemented."); +} + void EVMAssembly::updateReference(size_t pos, size_t size, u256 value) { solAssert(m_bytecode.size() >= size && pos <= m_bytecode.size() - size, ""); diff --git a/libyul/backends/evm/EVMAssembly.h b/libyul/backends/evm/EVMAssembly.h index d0a437cc..cef9c19a 100644 --- a/libyul/backends/evm/EVMAssembly.h +++ b/libyul/backends/evm/EVMAssembly.h @@ -77,6 +77,10 @@ public: /// Append the assembled size as a constant. void appendAssemblySize() override; + std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly() override; + void appendDataOffset(SubID _sub) override; + void appendDataSize(SubID _sub) override; + SubID appendData(dev::bytes const& _data) override; /// Resolves references inside the bytecode and returns the linker object. dev::eth::LinkerObject finalize(); diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp new file mode 100644 index 00000000..e7e8ad99 --- /dev/null +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -0,0 +1,55 @@ +/* + 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/>. +*/ +/** + * Compiler that transforms Yul Objects to EVM bytecode objects. + */ + +#include <libyul/backends/evm/EVMObjectCompiler.h> + +#include <libyul/backends/evm/EVMCodeTransform.h> +#include <libyul/Object.h> +#include <libyul/Exceptions.h> + +using namespace yul; +using namespace std; + +void EVMObjectCompiler::compile(Object& _object, AbstractAssembly& _assembly, bool _yul, bool _evm15) +{ + EVMObjectCompiler compiler(_assembly, _yul, _evm15); + compiler.run(_object); +} + +void EVMObjectCompiler::run(Object& _object) +{ + map<YulString, AbstractAssembly::SubID> subIDs; + + for (auto& subNode: _object.subObjects) + if (Object* subObject = dynamic_cast<Object*>(subNode.get())) + { + auto subAssemblyAndID = m_assembly.createSubAssembly(); + subIDs[subObject->name] = subAssemblyAndID.second; + compile(*subObject, *subAssemblyAndID.first, m_yul, m_evm15); + } + else + { + Data const& data = dynamic_cast<Data const&>(*subNode); + subIDs[data.name] = m_assembly.appendData(data.data); + } + + yulAssert(_object.analysisInfo, "No analysis info."); + CodeTransform{m_assembly, *_object.analysisInfo, m_yul, m_evm15}(*_object.code); +} diff --git a/libyul/AsmCodeGen.h b/libyul/backends/evm/EVMObjectCompiler.h index fd5ac0a1..c7172e47 100644 --- a/libyul/AsmCodeGen.h +++ b/libyul/backends/evm/EVMObjectCompiler.h @@ -15,40 +15,29 @@ along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** - * @author Christian <c@ethdev.com> - * @date 2016 - * Code-generating part of inline assembly. + * Compiler that transforms Yul Objects to EVM bytecode objects. */ -#pragma once - -#include <libyul/AsmAnalysis.h> - -#include <functional> - -namespace dev -{ -namespace eth -{ -class Assembly; -} -} namespace yul { -struct Block; +struct Object; +class AbstractAssembly; -class CodeGenerator +class EVMObjectCompiler { public: - /// Performs code generation and appends generated to _assembly. - static void assemble( - Block const& _parsedData, - AsmAnalysisInfo& _analysisInfo, - dev::eth::Assembly& _assembly, - yul::ExternalIdentifierAccess const& _identifierAccess = yul::ExternalIdentifierAccess(), - bool _useNamedLabelsForFunctions = false - ); + static void compile(Object& _object, AbstractAssembly& _assembly, bool _yul, bool _evm15); +private: + EVMObjectCompiler(AbstractAssembly& _assembly, bool _yul, bool _evm15): + m_assembly(_assembly), m_yul(_yul), m_evm15(_evm15) + {} + + void run(Object& _object); + + AbstractAssembly& m_assembly; + bool m_yul = false; + bool m_evm15 = false; }; } diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index 8ae26fbb..f69f7cdd 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -94,8 +94,11 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) if (_funCall.functionName.name == _callSite) return false; - FunctionDefinition& calledFunction = function(_funCall.functionName.name); - if (m_alwaysInline.count(calledFunction.name)) + FunctionDefinition* calledFunction = function(_funCall.functionName.name); + if (!calledFunction) + return false; + + if (m_alwaysInline.count(calledFunction->name)) return true; // Constant arguments might provide a means for further optimization, so they cause a bonus. @@ -110,7 +113,7 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) break; } - size_t size = m_functionSizes.at(calledFunction.name); + size_t size = m_functionSizes.at(calledFunction->name); return (size < 10 || (constantArg && size < 50)); } @@ -149,12 +152,13 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC vector<Statement> newStatements; map<YulString, YulString> variableReplacements; - FunctionDefinition& function = m_driver.function(_funCall.functionName.name); + FunctionDefinition* function = m_driver.function(_funCall.functionName.name); + assertThrow(!!function, OptimizerException, "Attempt to inline invalid function."); // helper function to create a new variable that is supposed to model // an existing variable. auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) { - YulString newName = m_nameDispenser.newName(_existingVariable.name, function.name); + YulString newName = m_nameDispenser.newName(_existingVariable.name, function->name); variableReplacements[_existingVariable.name] = newName; VariableDeclaration varDecl{_funCall.location, {{_funCall.location, newName, _existingVariable.type}}, {}}; if (_value) @@ -163,11 +167,11 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC }; for (size_t i = 0; i < _funCall.arguments.size(); ++i) - newVariable(function.parameters[i], &_funCall.arguments[i]); - for (auto const& var: function.returnVariables) + newVariable(function->parameters[i], &_funCall.arguments[i]); + for (auto const& var: function->returnVariables) newVariable(var, nullptr); - Statement newBody = BodyCopier(m_nameDispenser, function.name, variableReplacements)(function.body); + Statement newBody = BodyCopier(m_nameDispenser, function->name, variableReplacements)(function->body); newStatements += std::move(boost::get<Block>(newBody).statements); boost::apply_visitor(GenericFallbackVisitor<Assignment, VariableDeclaration>{ @@ -179,7 +183,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC {_assignment.variableNames[i]}, make_shared<Expression>(Identifier{ _assignment.location, - variableReplacements.at(function.returnVariables[i].name) + variableReplacements.at(function->returnVariables[i].name) }) }); }, @@ -191,7 +195,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC {std::move(_varDecl.variables[i])}, make_shared<Expression>(Identifier{ _varDecl.location, - variableReplacements.at(function.returnVariables[i].name) + variableReplacements.at(function->returnVariables[i].name) }) }); } diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index a8fe76c6..8f6211c8 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -63,8 +63,8 @@ class NameCollector; * code of f, with replacements: a -> f_a, b -> f_b, c -> f_c * let z := f_c * - * Prerequisites: Disambiguator, Function Hoister - * More efficient if run after: Expression Splitter + * Prerequisites: Disambiguator + * More efficient if run after: Function Hoister, Expression Splitter */ class FullInliner: public ASTModifier { @@ -77,7 +77,13 @@ public: /// @param _callSite the name of the function in which the function call is located. bool shallInline(FunctionCall const& _funCall, YulString _callSite); - FunctionDefinition& function(YulString _name) { return *m_functions.at(_name); } + FunctionDefinition* function(YulString _name) + { + auto it = m_functions.find(_name); + if (it != m_functions.end()) + return it->second; + return nullptr; + } private: void updateCodeSize(FunctionDefinition& fun); diff --git a/libyul/optimiser/SSAValueTracker.cpp b/libyul/optimiser/SSAValueTracker.cpp index 35b29b04..ef96c379 100644 --- a/libyul/optimiser/SSAValueTracker.cpp +++ b/libyul/optimiser/SSAValueTracker.cpp @@ -37,7 +37,7 @@ void SSAValueTracker::operator()(VariableDeclaration const& _varDecl) { if (_varDecl.variables.size() == 1) setValue(_varDecl.variables.front().name, _varDecl.value.get()); - else + else if (!_varDecl.value) for (auto const& var: _varDecl.variables) setValue(var.name, nullptr); } diff --git a/libyul/optimiser/SSAValueTracker.h b/libyul/optimiser/SSAValueTracker.h index e182e013..efec2200 100644 --- a/libyul/optimiser/SSAValueTracker.h +++ b/libyul/optimiser/SSAValueTracker.h @@ -33,6 +33,8 @@ namespace yul * Class that walks the AST and stores the initial value of each variable * that is never assigned to. * + * Default value is represented as nullptr. + * * Prerequisite: Disambiguator */ class SSAValueTracker: public ASTWalker diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index b3190fef..8ed63fa8 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -114,7 +114,8 @@ bool Pattern::matches(Expression const& _expr, map<YulString, Expression const*> { YulString varName = boost::get<Identifier>(_expr).name; if (_ssaValues.count(varName)) - expr = _ssaValues.at(varName); + if (Expression const* new_expr = _ssaValues.at(varName)) + expr = new_expr; } assertThrow(expr, OptimizerException, ""); |