aboutsummaryrefslogtreecommitdiffstats
path: root/libyul
diff options
context:
space:
mode:
Diffstat (limited to 'libyul')
-rw-r--r--libyul/AsmAnalysis.cpp4
-rw-r--r--libyul/AsmCodeGen.cpp163
-rw-r--r--libyul/CMakeLists.txt2
-rw-r--r--libyul/backends/evm/AbstractAssembly.h10
-rw-r--r--libyul/backends/evm/EVMAssembly.cpp21
-rw-r--r--libyul/backends/evm/EVMAssembly.h4
-rw-r--r--libyul/backends/evm/EVMObjectCompiler.cpp55
-rw-r--r--libyul/backends/evm/EVMObjectCompiler.h (renamed from libyul/AsmCodeGen.h)41
-rw-r--r--libyul/optimiser/FullInliner.cpp24
-rw-r--r--libyul/optimiser/FullInliner.h12
-rw-r--r--libyul/optimiser/SSAValueTracker.cpp2
-rw-r--r--libyul/optimiser/SSAValueTracker.h2
-rw-r--r--libyul/optimiser/SimplificationRules.cpp3
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, "");