Merge pull request #8095 from ethereum/develop

Merge develop into release for 0.6.1
This commit is contained in:
chriseth 2020-01-03 00:35:39 +01:00 committed by GitHub
commit e6f7d5a492
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
92 changed files with 817 additions and 317 deletions

View File

@ -10,7 +10,7 @@ include(EthPolicy)
eth_policy() eth_policy()
# project name and version should be set after cmake_policy CMP0048 # project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.6.0") set(PROJECT_VERSION "0.6.1")
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)
include(TestBigEndian) include(TestBigEndian)

View File

@ -1,3 +1,9 @@
### 0.6.1 (2020-01-02)
Bugfixes:
* Yul Optimizer: Fix bug in redundant assignment remover in combination with break and continue statements.
### 0.6.0 (2019-12-17) ### 0.6.0 (2019-12-17)
Breaking changes: Breaking changes:
@ -33,6 +39,7 @@ Language Features:
* Allow global enums and structs. * Allow global enums and structs.
* Allow public variables to override external functions. * Allow public variables to override external functions.
* Allow underscores as delimiters in hex strings. * Allow underscores as delimiters in hex strings.
* Allow to react on failing external calls using ``try`` and ``catch``.
* Introduce syntax for array slices and implement them for dynamic calldata arrays. * Introduce syntax for array slices and implement them for dynamic calldata arrays.
* Introduce ``push()`` for dynamic storage arrays. It returns a reference to the newly allocated element, if applicable. * Introduce ``push()`` for dynamic storage arrays. It returns a reference to the newly allocated element, if applicable.
* Introduce ``virtual`` and ``override`` keywords. * Introduce ``virtual`` and ``override`` keywords.
@ -45,6 +52,12 @@ Compiler Features:
* ABIEncoderV2: Do not warn about enabled ABIEncoderV2 anymore (the pragma is still needed, though). * ABIEncoderV2: Do not warn about enabled ABIEncoderV2 anymore (the pragma is still needed, though).
### 0.5.16 (2020-01-02)
Backported Bugfixes:
* Yul Optimizer: Fix bug in redundant assignment remover in combination with break and continue statements.
### 0.5.15 (2019-12-17) ### 0.5.15 (2019-12-17)
Bugfixes: Bugfixes:

View File

@ -1,4 +1,26 @@
[ [
{
"name": "YulOptimizerRedundantAssignmentBreakContinue",
"summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.",
"description": "The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches. This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with ``break`` or ``continue`` even though they cannot be removed in other control-flow branches. Variables declared outside of the respective for loop are not affected.",
"introduced": "0.6.0",
"fixed": "0.6.1",
"severity": "medium",
"conditions": {
"yulOptimizer": true
}
},
{
"name": "YulOptimizerRedundantAssignmentBreakContinue0.5",
"summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.",
"description": "The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches. This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with ``break`` or ``continue`` even though they cannot be removed in other control-flow branches. Variables declared outside of the respective for loop are not affected.",
"introduced": "0.5.8",
"fixed": "0.5.16",
"severity": "low",
"conditions": {
"yulOptimizer": true
}
},
{ {
"name": "ABIEncoderV2LoopYulOptimizer", "name": "ABIEncoderV2LoopYulOptimizer",
"summary": "If both the experimental ABIEncoderV2 and the experimental Yul optimizer are activated, one component of the Yul optimizer may reuse data in memory that has been changed in the meantime.", "summary": "If both the experimental ABIEncoderV2 and the experimental Yul optimizer are activated, one component of the Yul optimizer may reuse data in memory that has been changed in the meantime.",

View File

@ -742,32 +742,46 @@
}, },
"0.5.10": { "0.5.10": {
"bugs": [ "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers" "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers"
], ],
"released": "2019-06-25" "released": "2019-06-25"
}, },
"0.5.11": { "0.5.11": {
"bugs": [], "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-08-12" "released": "2019-08-12"
}, },
"0.5.12": { "0.5.12": {
"bugs": [], "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-10-01" "released": "2019-10-01"
}, },
"0.5.13": { "0.5.13": {
"bugs": [], "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-11-14" "released": "2019-11-14"
}, },
"0.5.14": { "0.5.14": {
"bugs": [ "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2LoopYulOptimizer" "ABIEncoderV2LoopYulOptimizer"
], ],
"released": "2019-12-09" "released": "2019-12-09"
}, },
"0.5.15": { "0.5.15": {
"bugs": [], "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-12-17" "released": "2019-12-17"
}, },
"0.5.16": {
"bugs": [],
"released": "2020-01-02"
},
"0.5.2": { "0.5.2": {
"bugs": [ "bugs": [
"SignedArrayStorageCopy", "SignedArrayStorageCopy",
@ -840,6 +854,7 @@
}, },
"0.5.8": { "0.5.8": {
"bugs": [ "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"SignedArrayStorageCopy", "SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement", "ABIEncoderV2StorageArrayWithMultiSlotElement",
@ -849,6 +864,7 @@
}, },
"0.5.9": { "0.5.9": {
"bugs": [ "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"SignedArrayStorageCopy", "SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement" "ABIEncoderV2StorageArrayWithMultiSlotElement"
@ -856,7 +872,13 @@
"released": "2019-05-28" "released": "2019-05-28"
}, },
"0.6.0": { "0.6.0": {
"bugs": [], "bugs": [
"YulOptimizerRedundantAssignmentBreakContinue"
],
"released": "2019-12-17" "released": "2019-12-17"
},
"0.6.1": {
"bugs": [],
"released": "2020-01-02"
} }
} }

View File

@ -33,7 +33,7 @@ Solidity Integrations
* `Solidity IDE <https://github.com/System-Glitch/Solidity-IDE>`_ * `Solidity IDE <https://github.com/System-Glitch/Solidity-IDE>`_
Browser-based IDE with integrated compiler, Ganache and local file system support. Browser-based IDE with integrated compiler, Ganache and local file system support.
* `Solium <https://github.com/duaraghav8/Solium/>`_ * `Ethlint <https://github.com/duaraghav8/Ethlint>`_
Linter to identify and fix style and security issues in Solidity. Linter to identify and fix style and security issues in Solidity.
* `Superblocks Lab <https://lab.superblocks.com/>`_ * `Superblocks Lab <https://lab.superblocks.com/>`_
@ -48,7 +48,7 @@ Solidity Integrations
Plugin for the Atom editor that provides Solidity linting. Plugin for the Atom editor that provides Solidity linting.
* `Atom Solium Linter <https://atom.io/packages/linter-solium>`_ * `Atom Solium Linter <https://atom.io/packages/linter-solium>`_
Configurable Solidty linter for Atom using Solium as a base. Configurable Solidity linter for Atom using Solium (now Ethlint) as a base.
* Eclipse: * Eclipse:

View File

@ -639,7 +639,7 @@ void DeclarationRegistrationHelper::endVisit(FunctionDefinition&)
bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause) bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause)
{ {
_tryCatchClause.setScope(m_currentScope); _tryCatchClause.annotation().scope = m_currentScope;
enterNewSubScope(_tryCatchClause); enterNewSubScope(_tryCatchClause);
return true; return true;
} }
@ -675,7 +675,7 @@ void DeclarationRegistrationHelper::endVisit(FunctionTypeName&)
bool DeclarationRegistrationHelper::visit(Block& _block) bool DeclarationRegistrationHelper::visit(Block& _block)
{ {
_block.setScope(m_currentScope); _block.annotation().scope = m_currentScope;
enterNewSubScope(_block); enterNewSubScope(_block);
return true; return true;
} }
@ -687,7 +687,7 @@ void DeclarationRegistrationHelper::endVisit(Block&)
bool DeclarationRegistrationHelper::visit(ForStatement& _for) bool DeclarationRegistrationHelper::visit(ForStatement& _for)
{ {
_for.setScope(m_currentScope); _for.annotation().scope = m_currentScope;
enterNewSubScope(_for); enterNewSubScope(_for);
return true; return true;
} }
@ -761,7 +761,7 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter); registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter);
_declaration.setScope(m_currentScope); _declaration.annotation().scope = m_currentScope;
if (_opensScope) if (_opensScope)
enterNewSubScope(_declaration); enterNewSubScope(_declaration);
} }

View File

@ -43,10 +43,6 @@ public:
m_dialect(_dialect), m_dialect(_dialect),
m_reportMutability(_reportMutability) {} m_reportMutability(_reportMutability) {}
void operator()(yul::Instruction const& _instruction)
{
checkInstruction(_instruction.location, _instruction.instruction);
}
void operator()(yul::Literal const&) {} void operator()(yul::Literal const&) {}
void operator()(yul::Identifier const&) {} void operator()(yul::Identifier const&) {}
void operator()(yul::ExpressionStatement const& _expr) void operator()(yul::ExpressionStatement const& _expr)

View File

@ -449,6 +449,13 @@ string Scopable::sourceUnitName() const
return sourceUnit().annotation().path; return sourceUnit().annotation().path;
} }
DeclarationAnnotation& Declaration::annotation() const
{
if (!m_annotation)
m_annotation = make_unique<DeclarationAnnotation>();
return dynamic_cast<DeclarationAnnotation&>(*m_annotation);
}
bool VariableDeclaration::isLValue() const bool VariableDeclaration::isLValue() const
{ {
// Constant declared variables are Read-Only // Constant declared variables are Read-Only
@ -653,6 +660,27 @@ InlineAssemblyAnnotation& InlineAssembly::annotation() const
return dynamic_cast<InlineAssemblyAnnotation&>(*m_annotation); return dynamic_cast<InlineAssemblyAnnotation&>(*m_annotation);
} }
BlockAnnotation& Block::annotation() const
{
if (!m_annotation)
m_annotation = make_unique<BlockAnnotation>();
return dynamic_cast<BlockAnnotation&>(*m_annotation);
}
TryCatchClauseAnnotation& TryCatchClause::annotation() const
{
if (!m_annotation)
m_annotation = make_unique<TryCatchClauseAnnotation>();
return dynamic_cast<TryCatchClauseAnnotation&>(*m_annotation);
}
ForStatementAnnotation& ForStatement::annotation() const
{
if (!m_annotation)
m_annotation = make_unique<ForStatementAnnotation>();
return dynamic_cast<ForStatementAnnotation&>(*m_annotation);
}
ReturnAnnotation& Return::annotation() const ReturnAnnotation& Return::annotation() const
{ {
if (!m_annotation) if (!m_annotation)

View File

@ -159,8 +159,7 @@ public:
virtual ~Scopable() = default; virtual ~Scopable() = default;
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step. /// Available only after name and type resolution step.
ASTNode const* scope() const { return m_scope; } ASTNode const* scope() const { return annotation().scope; }
void setScope(ASTNode const* _scope) { m_scope = _scope; }
/// @returns the source unit this scopable is present in. /// @returns the source unit this scopable is present in.
SourceUnit const& sourceUnit() const; SourceUnit const& sourceUnit() const;
@ -172,8 +171,7 @@ public:
/// Can be combined with annotation().canonicalName (if present) to form a globally unique name. /// Can be combined with annotation().canonicalName (if present) to form a globally unique name.
std::string sourceUnitName() const; std::string sourceUnitName() const;
protected: virtual ScopableAnnotation& annotation() const = 0;
ASTNode const* m_scope = nullptr;
}; };
/** /**
@ -231,6 +229,8 @@ public:
/// @returns null when it is not accessible as a function. /// @returns null when it is not accessible as a function.
virtual FunctionTypePointer functionType(bool /*_internal*/) const { return {}; } virtual FunctionTypePointer functionType(bool /*_internal*/) const { return {}; }
DeclarationAnnotation& annotation() const override;
protected: protected:
virtual Visibility defaultVisibility() const { return Visibility::Public; } virtual Visibility defaultVisibility() const { return Visibility::Public; }
@ -1169,6 +1169,8 @@ public:
std::vector<ASTPointer<Statement>> const& statements() const { return m_statements; } std::vector<ASTPointer<Statement>> const& statements() const { return m_statements; }
BlockAnnotation& annotation() const override;
private: private:
std::vector<ASTPointer<Statement>> m_statements; std::vector<ASTPointer<Statement>> m_statements;
}; };
@ -1248,6 +1250,8 @@ public:
ParameterList const* parameters() const { return m_parameters.get(); } ParameterList const* parameters() const { return m_parameters.get(); }
Block const& block() const { return *m_block; } Block const& block() const { return *m_block; }
TryCatchClauseAnnotation& annotation() const override;
private: private:
ASTPointer<ASTString> m_errorName; ASTPointer<ASTString> m_errorName;
ASTPointer<ParameterList> m_parameters; ASTPointer<ParameterList> m_parameters;
@ -1357,6 +1361,8 @@ public:
ExpressionStatement const* loopExpression() const { return m_loopExpression.get(); } ExpressionStatement const* loopExpression() const { return m_loopExpression.get(); }
Statement const& body() const { return *m_body; } Statement const& body() const { return *m_body; }
ForStatementAnnotation& annotation() const override;
private: private:
/// For statement's initialization expression. for (XXX; ; ). Can be empty /// For statement's initialization expression. for (XXX; ; ). Can be empty
ASTPointer<Statement> m_initExpression; ASTPointer<Statement> m_initExpression;

View File

@ -75,7 +75,18 @@ struct SourceUnitAnnotation: ASTAnnotation
std::set<ExperimentalFeature> experimentalFeatures; std::set<ExperimentalFeature> experimentalFeatures;
}; };
struct ImportAnnotation: ASTAnnotation struct ScopableAnnotation
{
/// The scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step.
ASTNode const* scope = nullptr;
};
struct DeclarationAnnotation: ASTAnnotation, ScopableAnnotation
{
};
struct ImportAnnotation: DeclarationAnnotation
{ {
/// The absolute path of the source unit to import. /// The absolute path of the source unit to import.
std::string absolutePath; std::string absolutePath;
@ -83,7 +94,7 @@ struct ImportAnnotation: ASTAnnotation
SourceUnit const* sourceUnit = nullptr; SourceUnit const* sourceUnit = nullptr;
}; };
struct TypeDeclarationAnnotation: ASTAnnotation struct TypeDeclarationAnnotation: DeclarationAnnotation
{ {
/// The name of this type, prefixed by proper namespaces if globally accessible. /// The name of this type, prefixed by proper namespaces if globally accessible.
std::string canonicalName; std::string canonicalName;
@ -104,7 +115,7 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnota
std::map<FunctionDefinition const*, ASTNode const*> baseConstructorArguments; std::map<FunctionDefinition const*, ASTNode const*> baseConstructorArguments;
}; };
struct CallableDeclarationAnnotation: ASTAnnotation struct CallableDeclarationAnnotation: DeclarationAnnotation
{ {
/// The set of functions/modifiers/events this callable overrides. /// The set of functions/modifiers/events this callable overrides.
std::set<CallableDeclaration const*> baseFunctions; std::set<CallableDeclaration const*> baseFunctions;
@ -124,7 +135,7 @@ struct ModifierDefinitionAnnotation: CallableDeclarationAnnotation, DocumentedAn
{ {
}; };
struct VariableDeclarationAnnotation: ASTAnnotation struct VariableDeclarationAnnotation: DeclarationAnnotation
{ {
/// Type of variable (type of identifier referencing this variable). /// Type of variable (type of identifier referencing this variable).
TypePointer type = nullptr; TypePointer type = nullptr;
@ -152,6 +163,18 @@ struct InlineAssemblyAnnotation: StatementAnnotation
std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo; std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
}; };
struct BlockAnnotation: StatementAnnotation, ScopableAnnotation
{
};
struct TryCatchClauseAnnotation: ASTAnnotation, ScopableAnnotation
{
};
struct ForStatementAnnotation: StatementAnnotation, ScopableAnnotation
{
};
struct ReturnAnnotation: StatementAnnotation struct ReturnAnnotation: StatementAnnotation
{ {
/// Reference to the return parameters of the function. /// Reference to the return parameters of the function.

View File

@ -51,10 +51,6 @@
#include <libyul/YulString.h> #include <libyul/YulString.h>
#include <libyul/AsmPrinter.h> #include <libyul/AsmPrinter.h>
#include <libyul/backends/wasm/EVMToEWasmTranslator.h>
#include <libyul/backends/wasm/EWasmObjectCompiler.h>
#include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/AssemblyStack.h> #include <libyul/AssemblyStack.h>
#include <liblangutil/Scanner.h> #include <liblangutil/Scanner.h>
@ -81,7 +77,7 @@ CompilerStack::CompilerStack(ReadCallback::Callback const& _readFile):
m_readFile{_readFile}, m_readFile{_readFile},
m_enabledSMTSolvers{smt::SMTSolverChoice::All()}, m_enabledSMTSolvers{smt::SMTSolverChoice::All()},
m_generateIR{false}, m_generateIR{false},
m_generateEWasm{false}, m_generateEwasm{false},
m_errorList{}, m_errorList{},
m_errorReporter{m_errorList} m_errorReporter{m_errorList}
{ {
@ -204,7 +200,7 @@ void CompilerStack::reset(bool _keepSettings)
m_evmVersion = langutil::EVMVersion(); m_evmVersion = langutil::EVMVersion();
m_enabledSMTSolvers = smt::SMTSolverChoice::All(); m_enabledSMTSolvers = smt::SMTSolverChoice::All();
m_generateIR = false; m_generateIR = false;
m_generateEWasm = false; m_generateEwasm = false;
m_revertStrings = RevertStrings::Default; m_revertStrings = RevertStrings::Default;
m_optimiserSettings = OptimiserSettings::minimal(); m_optimiserSettings = OptimiserSettings::minimal();
m_metadataLiteralSources = false; m_metadataLiteralSources = false;
@ -467,10 +463,10 @@ bool CompilerStack::compile()
if (isRequestedContract(*contract)) if (isRequestedContract(*contract))
{ {
compileContract(*contract, otherCompilers); compileContract(*contract, otherCompilers);
if (m_generateIR || m_generateEWasm) if (m_generateIR || m_generateEwasm)
generateIR(*contract); generateIR(*contract);
if (m_generateEWasm) if (m_generateEwasm)
generateEWasm(*contract); generateEwasm(*contract);
} }
m_stackState = CompilationSuccessful; m_stackState = CompilationSuccessful;
this->link(); this->link();
@ -596,20 +592,20 @@ string const& CompilerStack::yulIROptimized(string const& _contractName) const
return contract(_contractName).yulIROptimized; return contract(_contractName).yulIROptimized;
} }
string const& CompilerStack::eWasm(string const& _contractName) const string const& CompilerStack::ewasm(string const& _contractName) const
{ {
if (m_stackState != CompilationSuccessful) if (m_stackState != CompilationSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
return contract(_contractName).eWasm; return contract(_contractName).ewasm;
} }
eth::LinkerObject const& CompilerStack::eWasmObject(string const& _contractName) const eth::LinkerObject const& CompilerStack::ewasmObject(string const& _contractName) const
{ {
if (m_stackState != CompilationSuccessful) if (m_stackState != CompilationSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
return contract(_contractName).eWasmObject; return contract(_contractName).ewasmObject;
} }
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
@ -1073,15 +1069,15 @@ void CompilerStack::generateIR(ContractDefinition const& _contract)
tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract); tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract);
} }
void CompilerStack::generateEWasm(ContractDefinition const& _contract) void CompilerStack::generateEwasm(ContractDefinition const& _contract)
{ {
solAssert(m_stackState >= AnalysisPerformed, ""); solAssert(m_stackState >= AnalysisPerformed, "");
if (m_hasError) if (m_hasError)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateEWasm with errors.")); BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateEwasm with errors."));
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
solAssert(!compiledContract.yulIROptimized.empty(), ""); solAssert(!compiledContract.yulIROptimized.empty(), "");
if (!compiledContract.eWasm.empty()) if (!compiledContract.ewasm.empty())
return; return;
// Re-parse the Yul IR in EVM dialect // Re-parse the Yul IR in EVM dialect
@ -1089,15 +1085,15 @@ void CompilerStack::generateEWasm(ContractDefinition const& _contract)
stack.parseAndAnalyze("", compiledContract.yulIROptimized); stack.parseAndAnalyze("", compiledContract.yulIROptimized);
stack.optimize(); stack.optimize();
stack.translate(yul::AssemblyStack::Language::EWasm); stack.translate(yul::AssemblyStack::Language::Ewasm);
stack.optimize(); stack.optimize();
//cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl; //cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;
// Turn into eWasm text representation. // Turn into Ewasm text representation.
auto result = stack.assemble(yul::AssemblyStack::Machine::eWasm); auto result = stack.assemble(yul::AssemblyStack::Machine::Ewasm);
compiledContract.eWasm = std::move(result.assembly); compiledContract.ewasm = std::move(result.assembly);
compiledContract.eWasmObject = std::move(*result.bytecode); compiledContract.ewasmObject = std::move(*result.bytecode);
} }
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const

View File

@ -178,8 +178,8 @@ public:
/// Enable experimental generation of Yul IR code. /// Enable experimental generation of Yul IR code.
void enableIRGeneration(bool _enable = true) { m_generateIR = _enable; } void enableIRGeneration(bool _enable = true) { m_generateIR = _enable; }
/// Enable experimental generation of eWasm code. If enabled, IR is also generated. /// Enable experimental generation of Ewasm code. If enabled, IR is also generated.
void enableEWasmGeneration(bool _enable = true) { m_generateEWasm = _enable; } void enableEwasmGeneration(bool _enable = true) { m_generateEwasm = _enable; }
/// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata. /// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata.
/// Must be set before parsing. /// Must be set before parsing.
@ -251,11 +251,11 @@ public:
/// @returns the optimized IR representation of a contract. /// @returns the optimized IR representation of a contract.
std::string const& yulIROptimized(std::string const& _contractName) const; std::string const& yulIROptimized(std::string const& _contractName) const;
/// @returns the eWasm text representation of a contract. /// @returns the Ewasm text representation of a contract.
std::string const& eWasm(std::string const& _contractName) const; std::string const& ewasm(std::string const& _contractName) const;
/// @returns the eWasm representation of a contract. /// @returns the Ewasm representation of a contract.
eth::LinkerObject const& eWasmObject(std::string const& _contractName) const; eth::LinkerObject const& ewasmObject(std::string const& _contractName) const;
/// @returns the assembled object for a contract. /// @returns the assembled object for a contract.
eth::LinkerObject const& object(std::string const& _contractName) const; eth::LinkerObject const& object(std::string const& _contractName) const;
@ -338,8 +338,8 @@ private:
eth::LinkerObject runtimeObject; ///< Runtime object. eth::LinkerObject runtimeObject; ///< Runtime object.
std::string yulIR; ///< Experimental Yul IR code. std::string yulIR; ///< Experimental Yul IR code.
std::string yulIROptimized; ///< Optimized experimental Yul IR code. std::string yulIROptimized; ///< Optimized experimental Yul IR code.
std::string eWasm; ///< Experimental eWasm text representation std::string ewasm; ///< Experimental Ewasm text representation
eth::LinkerObject eWasmObject; ///< Experimental eWasm code eth::LinkerObject ewasmObject; ///< Experimental Ewasm code
mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain. mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
mutable std::unique_ptr<Json::Value const> abi; mutable std::unique_ptr<Json::Value const> abi;
mutable std::unique_ptr<Json::Value const> storageLayout; mutable std::unique_ptr<Json::Value const> storageLayout;
@ -374,8 +374,8 @@ private:
/// The IR is stored but otherwise unused. /// The IR is stored but otherwise unused.
void generateIR(ContractDefinition const& _contract); void generateIR(ContractDefinition const& _contract);
/// Generate eWasm representation for a single contract. /// Generate Ewasm representation for a single contract.
void generateEWasm(ContractDefinition const& _contract); void generateEwasm(ContractDefinition const& _contract);
/// Links all the known library addresses in the available objects. Any unknown /// Links all the known library addresses in the available objects. Any unknown
/// library will still be kept as an unlinked placeholder in the objects. /// library will still be kept as an unlinked placeholder in the objects.
@ -436,7 +436,7 @@ private:
smt::SMTSolverChoice m_enabledSMTSolvers; smt::SMTSolverChoice m_enabledSMTSolvers;
std::map<std::string, std::set<std::string>> m_requestedContractNames; std::map<std::string, std::set<std::string>> m_requestedContractNames;
bool m_generateIR; bool m_generateIR;
bool m_generateEWasm; bool m_generateEwasm;
std::map<std::string, h160> m_libraries; std::map<std::string, h160> m_libraries;
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum /// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
/// "context:prefix=target" /// "context:prefix=target"

View File

@ -247,9 +247,9 @@ bool isBinaryRequested(Json::Value const& _outputSelection)
return false; return false;
} }
/// @returns true if any eWasm code was requested. Note that as an exception, '*' does not /// @returns true if any Ewasm code was requested. Note that as an exception, '*' does not
/// yet match "ewasm.wast" or "ewasm" /// yet match "ewasm.wast" or "ewasm"
bool isEWasmRequested(Json::Value const& _outputSelection) bool isEwasmRequested(Json::Value const& _outputSelection)
{ {
if (!_outputSelection.isObject()) if (!_outputSelection.isObject())
return false; return false;
@ -267,7 +267,7 @@ bool isEWasmRequested(Json::Value const& _outputSelection)
/// yet match "ir" or "irOptimized" /// yet match "ir" or "irOptimized"
bool isIRRequested(Json::Value const& _outputSelection) bool isIRRequested(Json::Value const& _outputSelection)
{ {
if (isEWasmRequested(_outputSelection)) if (isEwasmRequested(_outputSelection))
return true; return true;
if (!_outputSelection.isObject()) if (!_outputSelection.isObject())
@ -780,7 +780,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
compilerStack.enableIRGeneration(isIRRequested(_inputsAndSettings.outputSelection)); compilerStack.enableIRGeneration(isIRRequested(_inputsAndSettings.outputSelection));
compilerStack.enableEWasmGeneration(isEWasmRequested(_inputsAndSettings.outputSelection)); compilerStack.enableEwasmGeneration(isEwasmRequested(_inputsAndSettings.outputSelection));
Json::Value errors = std::move(_inputsAndSettings.errors); Json::Value errors = std::move(_inputsAndSettings.errors);
@ -956,11 +956,11 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "irOptimized", wildcardMatchesExperimental)) if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "irOptimized", wildcardMatchesExperimental))
contractData["irOptimized"] = compilerStack.yulIROptimized(contractName); contractData["irOptimized"] = compilerStack.yulIROptimized(contractName);
// eWasm // Ewasm
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ewasm.wast", wildcardMatchesExperimental)) if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ewasm.wast", wildcardMatchesExperimental))
contractData["ewasm"]["wast"] = compilerStack.eWasm(contractName); contractData["ewasm"]["wast"] = compilerStack.ewasm(contractName);
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ewasm.wasm", wildcardMatchesExperimental)) if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ewasm.wasm", wildcardMatchesExperimental))
contractData["ewasm"]["wasm"] = compilerStack.eWasmObject(contractName).toHex(); contractData["ewasm"]["wasm"] = compilerStack.ewasmObject(contractName).toHex();
// EVM // EVM
Json::Value evmData(Json::objectValue); Json::Value evmData(Json::objectValue);

View File

@ -86,16 +86,6 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect,
return analysisInfo; return analysisInfo;
} }
bool AsmAnalyzer::operator()(yul::Instruction const& _instruction)
{
yulAssert(false, "The use of non-functional instructions is disallowed. Please use functional notation instead.");
auto const& info = instructionInfo(_instruction.instruction);
m_stackHeight += info.ret - info.args;
m_info.stackHeightInfo[&_instruction] = m_stackHeight;
warnOnInstructions(_instruction.instruction, _instruction.location);
return true;
}
bool AsmAnalyzer::operator()(Literal const& _literal) bool AsmAnalyzer::operator()(Literal const& _literal)
{ {
expectValidType(_literal.type.str(), _literal.location); expectValidType(_literal.type.str(), _literal.location);

View File

@ -77,7 +77,6 @@ public:
/// Asserts on failure. /// Asserts on failure.
static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object); static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object);
bool operator()(Instruction const&);
bool operator()(Literal const& _literal); bool operator()(Literal const& _literal);
bool operator()(Identifier const&); bool operator()(Identifier const&);
bool operator()(ExpressionStatement const&); bool operator()(ExpressionStatement const&);

View File

@ -25,12 +25,8 @@
#include <libyul/AsmDataForward.h> #include <libyul/AsmDataForward.h>
#include <libyul/YulString.h> #include <libyul/YulString.h>
#include <libevmasm/Instruction.h>
#include <liblangutil/SourceLocation.h> #include <liblangutil/SourceLocation.h>
#include <boost/noncopyable.hpp>
#include <map>
#include <memory> #include <memory>
namespace yul namespace yul
@ -41,8 +37,6 @@ using Type = YulString;
struct TypedName { langutil::SourceLocation location; YulString name; Type type; }; struct TypedName { langutil::SourceLocation location; YulString name; Type type; };
using TypedNameList = std::vector<TypedName>; using TypedNameList = std::vector<TypedName>;
/// Direct EVM instruction (except PUSHi and JUMPDEST)
struct Instruction { langutil::SourceLocation location; dev::eth::Instruction instruction; };
/// Literal number or string (up to 32 bytes) /// Literal number or string (up to 32 bytes)
enum class LiteralKind { Number, Boolean, String }; enum class LiteralKind { Number, Boolean, String };
struct Literal { langutil::SourceLocation location; LiteralKind kind; YulString value; Type type; }; struct Literal { langutil::SourceLocation location; LiteralKind kind; YulString value; Type type; };

View File

@ -29,6 +29,8 @@
#include <liblangutil/Scanner.h> #include <liblangutil/Scanner.h>
#include <liblangutil/ParserBase.h> #include <liblangutil/ParserBase.h>
#include <libevmasm/Instruction.h>
#include <memory> #include <memory>
#include <variant> #include <variant>
#include <vector> #include <vector>
@ -56,7 +58,7 @@ public:
static std::map<std::string, dev::eth::Instruction> const& instructions(); static std::map<std::string, dev::eth::Instruction> const& instructions();
protected: protected:
using ElementaryOperation = std::variant<Instruction, Literal, Identifier, FunctionCall>; using ElementaryOperation = std::variant<Literal, Identifier, FunctionCall>;
/// Creates an inline assembly node with the given source location. /// Creates an inline assembly node with the given source location.
template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const

View File

@ -16,7 +16,7 @@
*/ */
/** /**
* Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and * Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and
* eWasm as output. * Ewasm as output.
*/ */
@ -33,8 +33,8 @@
#include <libyul/backends/evm/EVMObjectCompiler.h> #include <libyul/backends/evm/EVMObjectCompiler.h>
#include <libyul/backends/evm/EVMMetrics.h> #include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/backends/wasm/WasmDialect.h> #include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/backends/wasm/EWasmObjectCompiler.h> #include <libyul/backends/wasm/WasmObjectCompiler.h>
#include <libyul/backends/wasm/EVMToEWasmTranslator.h> #include <libyul/backends/wasm/EVMToEwasmTranslator.h>
#include <libyul/optimiser/Metrics.h> #include <libyul/optimiser/Metrics.h>
#include <libyul/ObjectParser.h> #include <libyul/ObjectParser.h>
#include <libyul/optimiser/Suite.h> #include <libyul/optimiser/Suite.h>
@ -59,7 +59,7 @@ Dialect const& languageToDialect(AssemblyStack::Language _language, EVMVersion _
return EVMDialect::strictAssemblyForEVMObjects(_version); return EVMDialect::strictAssemblyForEVMObjects(_version);
case AssemblyStack::Language::Yul: case AssemblyStack::Language::Yul:
return Dialect::yul(); return Dialect::yul();
case AssemblyStack::Language::EWasm: case AssemblyStack::Language::Ewasm:
return WasmDialect::instance(); return WasmDialect::instance();
} }
yulAssert(false, ""); yulAssert(false, "");
@ -108,11 +108,11 @@ void AssemblyStack::translate(AssemblyStack::Language _targetLanguage)
return; return;
solAssert( solAssert(
m_language == Language::StrictAssembly && _targetLanguage == Language::EWasm, m_language == Language::StrictAssembly && _targetLanguage == Language::Ewasm,
"Invalid language combination" "Invalid language combination"
); );
*m_parserResult = EVMToEWasmTranslator( *m_parserResult = EVMToEwasmTranslator(
languageToDialect(m_language, m_evmVersion) languageToDialect(m_language, m_evmVersion)
).run(*parserResult()); ).run(*parserResult());
@ -214,13 +214,13 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
/// TODO: fill out text representation /// TODO: fill out text representation
return object; return object;
} }
case Machine::eWasm: case Machine::Ewasm:
{ {
yulAssert(m_language == Language::EWasm, ""); yulAssert(m_language == Language::Ewasm, "");
Dialect const& dialect = languageToDialect(m_language, EVMVersion{}); Dialect const& dialect = languageToDialect(m_language, EVMVersion{});
MachineAssemblyObject object; MachineAssemblyObject object;
auto result = EWasmObjectCompiler::compile(*m_parserResult, dialect); auto result = WasmObjectCompiler::compile(*m_parserResult, dialect);
object.assembly = std::move(result.first); object.assembly = std::move(result.first);
object.bytecode = make_shared<dev::eth::LinkerObject>(); object.bytecode = make_shared<dev::eth::LinkerObject>();
object.bytecode->bytecode = std::move(result.second); object.bytecode->bytecode = std::move(result.second);

View File

@ -16,7 +16,7 @@
*/ */
/** /**
* Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and * Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and
* eWasm as output. * Ewasm as output.
*/ */
#pragma once #pragma once
@ -52,13 +52,13 @@ struct MachineAssemblyObject
/* /*
* Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and * Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and
* eWasm as output. * Ewasm as output.
*/ */
class AssemblyStack class AssemblyStack
{ {
public: public:
enum class Language { Yul, Assembly, StrictAssembly, EWasm }; enum class Language { Yul, Assembly, StrictAssembly, Ewasm };
enum class Machine { EVM, EVM15, eWasm }; enum class Machine { EVM, EVM15, Ewasm };
AssemblyStack(): AssemblyStack():
AssemblyStack(langutil::EVMVersion{}, Language::Assembly, dev::solidity::OptimiserSettings::none()) AssemblyStack(langutil::EVMVersion{}, Language::Assembly, dev::solidity::OptimiserSettings::none())

View File

@ -44,18 +44,18 @@ add_library(yul
backends/evm/EVMMetrics.h backends/evm/EVMMetrics.h
backends/evm/NoOutputAssembly.h backends/evm/NoOutputAssembly.h
backends/evm/NoOutputAssembly.cpp backends/evm/NoOutputAssembly.cpp
backends/wasm/EVMToEWasmTranslator.cpp backends/wasm/EVMToEwasmTranslator.cpp
backends/wasm/EVMToEWasmTranslator.h backends/wasm/EVMToEwasmTranslator.h
backends/wasm/EWasmCodeTransform.cpp
backends/wasm/EWasmCodeTransform.h
backends/wasm/EWasmObjectCompiler.cpp
backends/wasm/EWasmObjectCompiler.h
backends/wasm/BinaryTransform.cpp backends/wasm/BinaryTransform.cpp
backends/wasm/BinaryTransform.h backends/wasm/BinaryTransform.h
backends/wasm/TextTransform.cpp backends/wasm/TextTransform.cpp
backends/wasm/TextTransform.h backends/wasm/TextTransform.h
backends/wasm/WasmCodeTransform.cpp
backends/wasm/WasmCodeTransform.h
backends/wasm/WasmDialect.cpp backends/wasm/WasmDialect.cpp
backends/wasm/WasmDialect.h backends/wasm/WasmDialect.h
backends/wasm/WasmObjectCompiler.cpp
backends/wasm/WasmObjectCompiler.h
backends/wasm/WordSizeTransform.cpp backends/wasm/WordSizeTransform.cpp
backends/wasm/WordSizeTransform.h backends/wasm/WordSizeTransform.h
optimiser/ASTCopier.cpp optimiser/ASTCopier.cpp

View File

@ -43,7 +43,6 @@ enum class Instruction: uint8_t;
namespace yul namespace yul
{ {
struct Instruction;
struct Identifier; struct Identifier;
/// ///

View File

@ -350,16 +350,6 @@ void CodeTransform::operator()(Literal const& _literal)
checkStackHeight(&_literal); checkStackHeight(&_literal);
} }
void CodeTransform::operator()(yul::Instruction const& _instruction)
{
yulAssert(!m_allowStackOpt, "");
yulAssert(!m_evm15 || _instruction.instruction != dev::eth::Instruction::JUMP, "Bare JUMP instruction used for EVM1.5");
yulAssert(!m_evm15 || _instruction.instruction != dev::eth::Instruction::JUMPI, "Bare JUMPI instruction used for EVM1.5");
m_assembly.setSourceLocation(_instruction.location);
m_assembly.appendInstruction(_instruction.instruction);
checkStackHeight(&_instruction);
}
void CodeTransform::operator()(If const& _if) void CodeTransform::operator()(If const& _if)
{ {
visitExpression(*_if.condition); visitExpression(*_if.condition);

View File

@ -170,7 +170,6 @@ protected:
void deleteVariable(Scope::Variable const& _var); void deleteVariable(Scope::Variable const& _var);
public: public:
void operator()(Instruction const& _instruction);
void operator()(Literal const& _literal); void operator()(Literal const& _literal);
void operator()(Identifier const& _identifier); void operator()(Identifier const& _identifier);
void operator()(FunctionCall const&); void operator()(FunctionCall const&);

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* EWasm to binary encoder. * Component that transforms internal Wasm representation to binary.
*/ */
#include <libyul/backends/wasm/BinaryTransform.h> #include <libyul/backends/wasm/BinaryTransform.h>

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* EWasm to binary encoder. * Component that transforms internal Wasm representation to binary.
*/ */
#pragma once #pragma once

View File

@ -15,10 +15,10 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Translates Yul code from EVM dialect to eWasm dialect. * Translates Yul code from EVM dialect to Ewasm dialect.
*/ */
#include <libyul/backends/wasm/EVMToEWasmTranslator.h> #include <libyul/backends/wasm/EVMToEwasmTranslator.h>
#include <libyul/backends/wasm/WordSizeTransform.h> #include <libyul/backends/wasm/WordSizeTransform.h>
#include <libyul/backends/wasm/WasmDialect.h> #include <libyul/backends/wasm/WasmDialect.h>
@ -138,6 +138,10 @@ function div(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
// TODO implement properly // TODO implement properly
r4 := i64.div_u(x4, y4) r4 := i64.div_u(x4, y4)
} }
function sdiv(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
// TODO implement properly
unreachable()
}
function mod(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 { function mod(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
// TODO implement properly // TODO implement properly
r4 := i64.rem_u(x4, y4) r4 := i64.rem_u(x4, y4)
@ -318,11 +322,11 @@ function sar(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
// TODO implement // TODO implement
unreachable() unreachable()
} }
function addmod(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 { function addmod(x1, x2, x3, x4, y1, y2, y3, y4, m1, m2, m3, m4) -> z1, z2, z3, z4 {
// TODO implement // TODO implement
unreachable() unreachable()
} }
function mulmod(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 { function mulmod(x1, x2, x3, x4, y1, y2, y3, y4, m1, m2, m3, m4) -> z1, z2, z3, z4 {
// TODO implement // TODO implement
unreachable() unreachable()
} }
@ -397,8 +401,7 @@ function calldatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
// Needed? // Needed?
function codesize() -> z1, z2, z3, z4 { function codesize() -> z1, z2, z3, z4 {
eth.getCodeSize(0) z4 := eth.getCodeSize()
z1, z2, z3, z4 := mload_internal(0)
} }
function codecopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) { function codecopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
eth.codeCopy( eth.codeCopy(
@ -698,7 +701,7 @@ function invalid() {
} }
Object EVMToEWasmTranslator::run(Object const& _object) Object EVMToEwasmTranslator::run(Object const& _object)
{ {
if (!m_polyfill) if (!m_polyfill)
parsePolyfill(); parsePolyfill();
@ -746,7 +749,7 @@ Object EVMToEWasmTranslator::run(Object const& _object)
return ret; return ret;
} }
void EVMToEWasmTranslator::parsePolyfill() void EVMToEwasmTranslator::parsePolyfill()
{ {
ErrorList errors; ErrorList errors;
ErrorReporter errorReporter(errors); ErrorReporter errorReporter(errors);

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Translates Yul code from EVM dialect to eWasm dialect. * Translates Yul code from EVM dialect to Ewasm dialect.
*/ */
#pragma once #pragma once
@ -28,10 +28,10 @@ namespace yul
{ {
struct Object; struct Object;
class EVMToEWasmTranslator: public ASTModifier class EVMToEwasmTranslator: public ASTModifier
{ {
public: public:
EVMToEWasmTranslator(Dialect const& _evmDialect): m_dialect(_evmDialect) {} EVMToEwasmTranslator(Dialect const& _evmDialect): m_dialect(_evmDialect) {}
Object run(Object const& _object); Object run(Object const& _object);
private: private:

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Component that transforms interval Wasm representation to text. * Component that transforms internal Wasm representation to text.
*/ */
#include <libyul/backends/wasm/TextTransform.h> #include <libyul/backends/wasm/TextTransform.h>

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Component that transforms interval Wasm representation to text. * Component that transforms internal Wasm representation to text.
*/ */
#pragma once #pragma once

View File

@ -15,10 +15,10 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Common code generator for translating Yul / inline assembly to EWasm. * Common code generator for translating Yul / inline assembly to Wasm.
*/ */
#include <libyul/backends/wasm/EWasmCodeTransform.h> #include <libyul/backends/wasm/WasmCodeTransform.h>
#include <libyul/optimiser/NameCollector.h> #include <libyul/optimiser/NameCollector.h>
@ -36,11 +36,11 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace yul; using namespace yul;
wasm::Module EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const& _ast) wasm::Module WasmCodeTransform::run(Dialect const& _dialect, yul::Block const& _ast)
{ {
wasm::Module module; wasm::Module module;
EWasmCodeTransform transform(_dialect, _ast); WasmCodeTransform transform(_dialect, _ast);
for (auto const& statement: _ast.statements) for (auto const& statement: _ast.statements)
{ {
@ -59,7 +59,7 @@ wasm::Module EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const&
return module; return module;
} }
wasm::Expression EWasmCodeTransform::generateMultiAssignment( wasm::Expression WasmCodeTransform::generateMultiAssignment(
vector<string> _variableNames, vector<string> _variableNames,
unique_ptr<wasm::Expression> _firstValue unique_ptr<wasm::Expression> _firstValue
) )
@ -82,7 +82,7 @@ wasm::Expression EWasmCodeTransform::generateMultiAssignment(
return { std::move(block) }; return { std::move(block) };
} }
wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varDecl) wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDecl)
{ {
vector<string> variableNames; vector<string> variableNames;
for (auto const& var: _varDecl.variables) for (auto const& var: _varDecl.variables)
@ -97,7 +97,7 @@ wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varD
return wasm::BuiltinCall{"nop", {}}; return wasm::BuiltinCall{"nop", {}};
} }
wasm::Expression EWasmCodeTransform::operator()(Assignment const& _assignment) wasm::Expression WasmCodeTransform::operator()(Assignment const& _assignment)
{ {
vector<string> variableNames; vector<string> variableNames;
for (auto const& var: _assignment.variableNames) for (auto const& var: _assignment.variableNames)
@ -105,12 +105,12 @@ wasm::Expression EWasmCodeTransform::operator()(Assignment const& _assignment)
return generateMultiAssignment(move(variableNames), visit(*_assignment.value)); return generateMultiAssignment(move(variableNames), visit(*_assignment.value));
} }
wasm::Expression EWasmCodeTransform::operator()(ExpressionStatement const& _statement) wasm::Expression WasmCodeTransform::operator()(ExpressionStatement const& _statement)
{ {
return visitReturnByValue(_statement.expression); return visitReturnByValue(_statement.expression);
} }
wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call) wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
{ {
bool typeConversionNeeded = false; bool typeConversionNeeded = false;
@ -171,19 +171,19 @@ wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call)
return {std::move(funCall)}; return {std::move(funCall)};
} }
wasm::Expression EWasmCodeTransform::operator()(Identifier const& _identifier) wasm::Expression WasmCodeTransform::operator()(Identifier const& _identifier)
{ {
return wasm::LocalVariable{_identifier.name.str()}; return wasm::LocalVariable{_identifier.name.str()};
} }
wasm::Expression EWasmCodeTransform::operator()(Literal const& _literal) wasm::Expression WasmCodeTransform::operator()(Literal const& _literal)
{ {
u256 value = valueOfLiteral(_literal); u256 value = valueOfLiteral(_literal);
yulAssert(value <= numeric_limits<uint64_t>::max(), "Literal too large: " + value.str()); yulAssert(value <= numeric_limits<uint64_t>::max(), "Literal too large: " + value.str());
return wasm::Literal{uint64_t(value)}; return wasm::Literal{uint64_t(value)};
} }
wasm::Expression EWasmCodeTransform::operator()(If const& _if) wasm::Expression WasmCodeTransform::operator()(If const& _if)
{ {
// TODO converting i64 to i32 might not always be needed. // TODO converting i64 to i32 might not always be needed.
@ -197,7 +197,7 @@ wasm::Expression EWasmCodeTransform::operator()(If const& _if)
}; };
} }
wasm::Expression EWasmCodeTransform::operator()(Switch const& _switch) wasm::Expression WasmCodeTransform::operator()(Switch const& _switch)
{ {
wasm::Block block; wasm::Block block;
string condition = m_nameDispenser.newName("condition"_yulstring).str(); string condition = m_nameDispenser.newName("condition"_yulstring).str();
@ -237,13 +237,13 @@ wasm::Expression EWasmCodeTransform::operator()(Switch const& _switch)
return { std::move(block) }; return { std::move(block) };
} }
wasm::Expression EWasmCodeTransform::operator()(FunctionDefinition const&) wasm::Expression WasmCodeTransform::operator()(FunctionDefinition const&)
{ {
yulAssert(false, "Should not have visited here."); yulAssert(false, "Should not have visited here.");
return {}; return {};
} }
wasm::Expression EWasmCodeTransform::operator()(ForLoop const& _for) wasm::Expression WasmCodeTransform::operator()(ForLoop const& _for)
{ {
string breakLabel = newLabel(); string breakLabel = newLabel();
string continueLabel = newLabel(); string continueLabel = newLabel();
@ -262,37 +262,37 @@ wasm::Expression EWasmCodeTransform::operator()(ForLoop const& _for)
return { wasm::Block{breakLabel, make_vector<wasm::Expression>(move(loop))} }; return { wasm::Block{breakLabel, make_vector<wasm::Expression>(move(loop))} };
} }
wasm::Expression EWasmCodeTransform::operator()(Break const&) wasm::Expression WasmCodeTransform::operator()(Break const&)
{ {
return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().first}}; return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().first}};
} }
wasm::Expression EWasmCodeTransform::operator()(Continue const&) wasm::Expression WasmCodeTransform::operator()(Continue const&)
{ {
return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().second}}; return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().second}};
} }
wasm::Expression EWasmCodeTransform::operator()(Leave const&) wasm::Expression WasmCodeTransform::operator()(Leave const&)
{ {
return wasm::Return{}; return wasm::Return{};
} }
wasm::Expression EWasmCodeTransform::operator()(Block const& _block) wasm::Expression WasmCodeTransform::operator()(Block const& _block)
{ {
return wasm::Block{{}, visit(_block.statements)}; return wasm::Block{{}, visit(_block.statements)};
} }
unique_ptr<wasm::Expression> EWasmCodeTransform::visit(yul::Expression const& _expression) unique_ptr<wasm::Expression> WasmCodeTransform::visit(yul::Expression const& _expression)
{ {
return make_unique<wasm::Expression>(std::visit(*this, _expression)); return make_unique<wasm::Expression>(std::visit(*this, _expression));
} }
wasm::Expression EWasmCodeTransform::visitReturnByValue(yul::Expression const& _expression) wasm::Expression WasmCodeTransform::visitReturnByValue(yul::Expression const& _expression)
{ {
return std::visit(*this, _expression); return std::visit(*this, _expression);
} }
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const& _expressions) vector<wasm::Expression> WasmCodeTransform::visit(vector<yul::Expression> const& _expressions)
{ {
vector<wasm::Expression> ret; vector<wasm::Expression> ret;
for (auto const& e: _expressions) for (auto const& e: _expressions)
@ -300,12 +300,12 @@ vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const
return ret; return ret;
} }
wasm::Expression EWasmCodeTransform::visit(yul::Statement const& _statement) wasm::Expression WasmCodeTransform::visit(yul::Statement const& _statement)
{ {
return std::visit(*this, _statement); return std::visit(*this, _statement);
} }
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Statement> const& _statements) vector<wasm::Expression> WasmCodeTransform::visit(vector<yul::Statement> const& _statements)
{ {
vector<wasm::Expression> ret; vector<wasm::Expression> ret;
for (auto const& s: _statements) for (auto const& s: _statements)
@ -313,7 +313,7 @@ vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Statement> const&
return ret; return ret;
} }
wasm::FunctionDefinition EWasmCodeTransform::translateFunction(yul::FunctionDefinition const& _fun) wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefinition const& _fun)
{ {
wasm::FunctionDefinition fun; wasm::FunctionDefinition fun;
fun.name = _fun.name.str(); fun.name = _fun.name.str();
@ -344,7 +344,7 @@ wasm::FunctionDefinition EWasmCodeTransform::translateFunction(yul::FunctionDefi
return fun; return fun;
} }
wasm::Expression EWasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionCall _call) const wasm::Expression WasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionCall _call) const
{ {
wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName}); wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName});
for (size_t i = 0; i < _call.arguments.size(); ++i) for (size_t i = 0; i < _call.arguments.size(); ++i)
@ -361,7 +361,7 @@ wasm::Expression EWasmCodeTransform::injectTypeConversionIfNeeded(wasm::Function
return {std::move(_call)}; return {std::move(_call)};
} }
vector<wasm::Expression> EWasmCodeTransform::injectTypeConversionIfNeeded( vector<wasm::Expression> WasmCodeTransform::injectTypeConversionIfNeeded(
vector<wasm::Expression> _arguments, vector<wasm::Expression> _arguments,
vector<Type> const& _parameterTypes vector<Type> const& _parameterTypes
) const ) const
@ -378,12 +378,12 @@ vector<wasm::Expression> EWasmCodeTransform::injectTypeConversionIfNeeded(
return _arguments; return _arguments;
} }
string EWasmCodeTransform::newLabel() string WasmCodeTransform::newLabel()
{ {
return m_nameDispenser.newName("label_"_yulstring).str(); return m_nameDispenser.newName("label_"_yulstring).str();
} }
void EWasmCodeTransform::allocateGlobals(size_t _amount) void WasmCodeTransform::allocateGlobals(size_t _amount)
{ {
while (m_globalVariables.size() < _amount) while (m_globalVariables.size() < _amount)
m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{ m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Common code generator for translating Yul / inline assembly to EWasm. * Common code generator for translating Yul / inline assembly to Wasm.
*/ */
#pragma once #pragma once
@ -32,7 +32,7 @@ namespace yul
{ {
struct AsmAnalysisInfo; struct AsmAnalysisInfo;
class EWasmCodeTransform class WasmCodeTransform
{ {
public: public:
static wasm::Module run(Dialect const& _dialect, yul::Block const& _ast); static wasm::Module run(Dialect const& _dialect, yul::Block const& _ast);
@ -54,7 +54,7 @@ public:
wasm::Expression operator()(yul::Block const& _block); wasm::Expression operator()(yul::Block const& _block);
private: private:
EWasmCodeTransform( WasmCodeTransform(
Dialect const& _dialect, Dialect const& _dialect,
Block const& _ast Block const& _ast
): ):

View File

@ -56,10 +56,16 @@ WasmDialect::WasmDialect():
addFunction("i64.eqz", 1, 1); addFunction("i64.eqz", 1, 1);
m_functions["i64.eqz"_yulstring].returns.front() = "i32"_yulstring; m_functions["i64.eqz"_yulstring].returns.front() = "i32"_yulstring;
addFunction("i64.clz", 1, 1);
addFunction("i64.store", 2, 0, false); addFunction("i64.store", 2, 0, false);
m_functions["i64.store"_yulstring].parameters.front() = "i32"_yulstring; m_functions["i64.store"_yulstring].parameters.front() = "i32"_yulstring;
m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false; m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.store8", 2, 0, false);
m_functions["i64.store8"_yulstring].parameters.front() = "i32"_yulstring;
m_functions["i64.store8"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.load", 1, 1, false); addFunction("i64.load", 1, 1, false);
m_functions["i64.load"_yulstring].parameters.front() = "i32"_yulstring; m_functions["i64.load"_yulstring].parameters.front() = "i32"_yulstring;
m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false; m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false;
@ -120,7 +126,7 @@ void WasmDialect::addEthereumExternals()
{"getCaller", {i32ptr}, {}}, {"getCaller", {i32ptr}, {}},
{"getCallValue", {i32ptr}, {}}, {"getCallValue", {i32ptr}, {}},
{"codeCopy", {i32ptr, i32, i32}, {}}, {"codeCopy", {i32ptr, i32, i32}, {}},
{"getCodeSize", {i32ptr}, {}}, {"getCodeSize", {}, {i32}},
{"getBlockCoinbase", {i32ptr}, {}}, {"getBlockCoinbase", {i32ptr}, {}},
{"create", {i32ptr, i32ptr, i32, i32ptr}, {i32}}, {"create", {i32ptr, i32ptr, i32, i32ptr}, {i32}},
{"getBlockDifficulty", {i32ptr}, {}}, {"getBlockDifficulty", {i32ptr}, {}},

View File

@ -18,9 +18,9 @@
* Compiler that transforms Yul Objects to Wasm text and binary representation (Ewasm flavoured). * Compiler that transforms Yul Objects to Wasm text and binary representation (Ewasm flavoured).
*/ */
#include <libyul/backends/wasm/EWasmObjectCompiler.h> #include <libyul/backends/wasm/WasmObjectCompiler.h>
#include <libyul/backends/wasm/EWasmCodeTransform.h> #include <libyul/backends/wasm/WasmCodeTransform.h>
#include <libyul/backends/wasm/BinaryTransform.h> #include <libyul/backends/wasm/BinaryTransform.h>
#include <libyul/backends/wasm/TextTransform.h> #include <libyul/backends/wasm/TextTransform.h>
@ -32,25 +32,25 @@
using namespace yul; using namespace yul;
using namespace std; using namespace std;
pair<string, dev::bytes> EWasmObjectCompiler::compile(Object& _object, Dialect const& _dialect) pair<string, dev::bytes> WasmObjectCompiler::compile(Object& _object, Dialect const& _dialect)
{ {
EWasmObjectCompiler compiler(_dialect); WasmObjectCompiler compiler(_dialect);
wasm::Module module = compiler.run(_object); wasm::Module module = compiler.run(_object);
return {wasm::TextTransform().run(module), wasm::BinaryTransform::run(module)}; return {wasm::TextTransform().run(module), wasm::BinaryTransform::run(module)};
} }
wasm::Module EWasmObjectCompiler::run(Object& _object) wasm::Module WasmObjectCompiler::run(Object& _object)
{ {
yulAssert(_object.analysisInfo, "No analysis info."); yulAssert(_object.analysisInfo, "No analysis info.");
yulAssert(_object.code, "No code."); yulAssert(_object.code, "No code.");
wasm::Module module = EWasmCodeTransform::run(m_dialect, *_object.code); wasm::Module module = WasmCodeTransform::run(m_dialect, *_object.code);
for (auto& subNode: _object.subObjects) for (auto& subNode: _object.subObjects)
if (Object* subObject = dynamic_cast<Object*>(subNode.get())) if (Object* subObject = dynamic_cast<Object*>(subNode.get()))
module.subModules[subObject->name.str()] = run(*subObject); module.subModules[subObject->name.str()] = run(*subObject);
else else
yulAssert(false, "Data is not yet supported for EWasm."); yulAssert(false, "Data is not yet supported for Wasm.");
return module; return module;
} }

View File

@ -28,6 +28,7 @@ namespace dev
{ {
using bytes = std::vector<uint8_t>; using bytes = std::vector<uint8_t>;
} }
namespace yul namespace yul
{ {
struct Object; struct Object;
@ -37,13 +38,13 @@ namespace wasm
struct Module; struct Module;
} }
class EWasmObjectCompiler class WasmObjectCompiler
{ {
public: public:
/// Compiles the given object and returns the WAST and the binary representation. /// Compiles the given object and returns the Wasm text and binary representation.
static std::pair<std::string, dev::bytes> compile(Object& _object, Dialect const& _dialect); static std::pair<std::string, dev::bytes> compile(Object& _object, Dialect const& _dialect);
private: private:
EWasmObjectCompiler(Dialect const& _dialect): WasmObjectCompiler(Dialect const& _dialect):
m_dialect(_dialect) m_dialect(_dialect)
{} {}

View File

@ -280,29 +280,28 @@ void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, Redundant
void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEliminator::State _finalState) void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEliminator::State _finalState)
{ {
finalize(m_assignments, _variable, _finalState); std::map<Assignment const*, State> assignments;
for (auto& assignments: m_forLoopInfo.pendingBreakStmts) joinMap(assignments, std::move(m_assignments[_variable]), State::join);
finalize(assignments, _variable, _finalState); m_assignments.erase(_variable);
for (auto& assignments: m_forLoopInfo.pendingContinueStmts)
finalize(assignments, _variable, _finalState);
}
void RedundantAssignEliminator::finalize( for (auto& breakAssignments: m_forLoopInfo.pendingBreakStmts)
TrackedAssignments& _assignments, {
YulString _variable, joinMap(assignments, std::move(breakAssignments[_variable]), State::join);
RedundantAssignEliminator::State _finalState breakAssignments.erase(_variable);
) }
{ for (auto& continueAssignments: m_forLoopInfo.pendingContinueStmts)
for (auto const& assignment: _assignments[_variable]) {
joinMap(assignments, std::move(continueAssignments[_variable]), State::join);
continueAssignments.erase(_variable);
}
for (auto const& assignment: assignments)
{ {
State const state = assignment.second == State::Undecided ? _finalState : assignment.second; State const state = assignment.second == State::Undecided ? _finalState : assignment.second;
if (state == State::Unused && SideEffectsCollector{*m_dialect, *assignment.first->value}.movable()) if (state == State::Unused && SideEffectsCollector{*m_dialect, *assignment.first->value}.movable())
// TODO the only point where we actually need this
// to be a set is for the for loop
m_pendingRemovals.insert(assignment.first); m_pendingRemovals.insert(assignment.first);
} }
_assignments.erase(_variable);
} }
void AssignmentRemover::operator()(Block& _block) void AssignmentRemover::operator()(Block& _block)

View File

@ -161,8 +161,6 @@ private:
/// assignments to the final state. In this case, this also applies to pending /// assignments to the final state. In this case, this also applies to pending
/// break and continue TrackedAssignments. /// break and continue TrackedAssignments.
void finalize(YulString _variable, State _finalState); void finalize(YulString _variable, State _finalState);
/// Helper function for the above.
void finalize(TrackedAssignments& _assignments, YulString _variable, State _finalState);
Dialect const* m_dialect; Dialect const* m_dialect;
std::set<YulString> m_declaredVariables; std::set<YulString> m_declaredVariables;

View File

@ -116,7 +116,7 @@ static string const g_strErrorRecovery = "error-recovery";
static string const g_strEVM = "evm"; static string const g_strEVM = "evm";
static string const g_strEVM15 = "evm15"; static string const g_strEVM15 = "evm15";
static string const g_strEVMVersion = "evm-version"; static string const g_strEVMVersion = "evm-version";
static string const g_streWasm = "ewasm"; static string const g_strEwasm = "ewasm";
static string const g_strGas = "gas"; static string const g_strGas = "gas";
static string const g_strHelp = "help"; static string const g_strHelp = "help";
static string const g_strInputFile = "input-file"; static string const g_strInputFile = "input-file";
@ -125,7 +125,6 @@ static string const g_strYul = "yul";
static string const g_strYulDialect = "yul-dialect"; static string const g_strYulDialect = "yul-dialect";
static string const g_strIR = "ir"; static string const g_strIR = "ir";
static string const g_strIPFS = "ipfs"; static string const g_strIPFS = "ipfs";
static string const g_strEWasm = "ewasm";
static string const g_strLicense = "license"; static string const g_strLicense = "license";
static string const g_strLibraries = "libraries"; static string const g_strLibraries = "libraries";
static string const g_strLink = "link"; static string const g_strLink = "link";
@ -187,7 +186,7 @@ static string const g_argHelp = g_strHelp;
static string const g_argInputFile = g_strInputFile; static string const g_argInputFile = g_strInputFile;
static string const g_argYul = g_strYul; static string const g_argYul = g_strYul;
static string const g_argIR = g_strIR; static string const g_argIR = g_strIR;
static string const g_argEWasm = g_strEWasm; static string const g_argEwasm = g_strEwasm;
static string const g_argLibraries = g_strLibraries; static string const g_argLibraries = g_strLibraries;
static string const g_argLink = g_strLink; static string const g_argLink = g_strLink;
static string const g_argMachine = g_strMachine; static string const g_argMachine = g_strMachine;
@ -234,14 +233,14 @@ static set<string> const g_machineArgs
{ {
g_strEVM, g_strEVM,
g_strEVM15, g_strEVM15,
g_streWasm g_strEwasm
}; };
/// Possible arguments to for --yul-dialect /// Possible arguments to for --yul-dialect
static set<string> const g_yulDialectArgs static set<string> const g_yulDialectArgs
{ {
g_strEVM, g_strEVM,
g_streWasm g_strEwasm
}; };
/// Possible arguments to for --metadata-hash /// Possible arguments to for --metadata-hash
@ -345,23 +344,23 @@ void CommandLineInterface::handleIR(string const& _contractName)
} }
} }
void CommandLineInterface::handleEWasm(string const& _contractName) void CommandLineInterface::handleEwasm(string const& _contractName)
{ {
if (m_args.count(g_argEWasm)) if (m_args.count(g_argEwasm))
{ {
if (m_args.count(g_argOutputDir)) if (m_args.count(g_argOutputDir))
{ {
createFile(m_compiler->filesystemFriendlyName(_contractName) + ".wast", m_compiler->eWasm(_contractName)); createFile(m_compiler->filesystemFriendlyName(_contractName) + ".wast", m_compiler->ewasm(_contractName));
createFile( createFile(
m_compiler->filesystemFriendlyName(_contractName) + ".wasm", m_compiler->filesystemFriendlyName(_contractName) + ".wasm",
asString(m_compiler->eWasmObject(_contractName).bytecode) asString(m_compiler->ewasmObject(_contractName).bytecode)
); );
} }
else else
{ {
sout() << "EWasm text:" << endl; sout() << "Ewasm text:" << endl;
sout() << m_compiler->eWasm(_contractName) << endl; sout() << m_compiler->ewasm(_contractName) << endl;
sout() << "EWasm binary (hex): " << m_compiler->eWasmObject(_contractName).toHex() << endl; sout() << "Ewasm binary (hex): " << m_compiler->ewasmObject(_contractName).toHex() << endl;
} }
} }
} }
@ -776,7 +775,7 @@ Allowed options)",
(g_argBinaryRuntime.c_str(), "Binary of the runtime part of the contracts in hex.") (g_argBinaryRuntime.c_str(), "Binary of the runtime part of the contracts in hex.")
(g_argAbi.c_str(), "ABI specification of the contracts.") (g_argAbi.c_str(), "ABI specification of the contracts.")
(g_argIR.c_str(), "Intermediate Representation (IR) of all contracts (EXPERIMENTAL).") (g_argIR.c_str(), "Intermediate Representation (IR) of all contracts (EXPERIMENTAL).")
(g_argEWasm.c_str(), "EWasm text representation of all contracts (EXPERIMENTAL).") (g_argEwasm.c_str(), "Ewasm text representation of all contracts (EXPERIMENTAL).")
(g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.") (g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.")
(g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.") (g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.")
(g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.") (g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.")
@ -981,27 +980,27 @@ bool CommandLineInterface::processInput()
targetMachine = Machine::EVM; targetMachine = Machine::EVM;
else if (machine == g_strEVM15) else if (machine == g_strEVM15)
targetMachine = Machine::EVM15; targetMachine = Machine::EVM15;
else if (machine == g_streWasm) else if (machine == g_strEwasm)
targetMachine = Machine::eWasm; targetMachine = Machine::Ewasm;
else else
{ {
serr() << "Invalid option for --machine: " << machine << endl; serr() << "Invalid option for --machine: " << machine << endl;
return false; return false;
} }
} }
if (targetMachine == Machine::eWasm && inputLanguage == Input::StrictAssembly) if (targetMachine == Machine::Ewasm && inputLanguage == Input::StrictAssembly)
inputLanguage = Input::EWasm; inputLanguage = Input::Ewasm;
if (m_args.count(g_strYulDialect)) if (m_args.count(g_strYulDialect))
{ {
string dialect = m_args[g_strYulDialect].as<string>(); string dialect = m_args[g_strYulDialect].as<string>();
if (dialect == g_strEVM) if (dialect == g_strEVM)
inputLanguage = Input::StrictAssembly; inputLanguage = Input::StrictAssembly;
else if (dialect == g_streWasm) else if (dialect == g_strEwasm)
{ {
inputLanguage = Input::EWasm; inputLanguage = Input::Ewasm;
if (targetMachine != Machine::eWasm) if (targetMachine != Machine::Ewasm)
{ {
serr() << "If you select eWasm as --yul-dialect, --machine has to be eWasm as well." << endl; serr() << "If you select Ewasm as --yul-dialect, --machine has to be Ewasm as well." << endl;
return false; return false;
} }
} }
@ -1011,7 +1010,7 @@ bool CommandLineInterface::processInput()
return false; return false;
} }
} }
if (optimize && (inputLanguage != Input::StrictAssembly && inputLanguage != Input::EWasm)) if (optimize && (inputLanguage != Input::StrictAssembly && inputLanguage != Input::Ewasm))
{ {
serr() << serr() <<
"Optimizer can only be used for strict assembly. Use --" << "Optimizer can only be used for strict assembly. Use --" <<
@ -1074,7 +1073,7 @@ bool CommandLineInterface::processInput()
// TODO: Perhaps we should not compile unless requested // TODO: Perhaps we should not compile unless requested
m_compiler->enableIRGeneration(m_args.count(g_argIR)); m_compiler->enableIRGeneration(m_args.count(g_argIR));
m_compiler->enableEWasmGeneration(m_args.count(g_argEWasm)); m_compiler->enableEwasmGeneration(m_args.count(g_argEwasm));
OptimiserSettings settings = m_args.count(g_argOptimize) ? OptimiserSettings::standard() : OptimiserSettings::minimal(); OptimiserSettings settings = m_args.count(g_argOptimize) ? OptimiserSettings::standard() : OptimiserSettings::minimal();
settings.expectedExecutionsPerDeployment = m_args[g_argOptimizeRuns].as<unsigned>(); settings.expectedExecutionsPerDeployment = m_args[g_argOptimizeRuns].as<unsigned>();
@ -1453,7 +1452,7 @@ bool CommandLineInterface::assemble(
string machine = string machine =
_targetMachine == yul::AssemblyStack::Machine::EVM ? "EVM" : _targetMachine == yul::AssemblyStack::Machine::EVM ? "EVM" :
_targetMachine == yul::AssemblyStack::Machine::EVM15 ? "EVM 1.5" : _targetMachine == yul::AssemblyStack::Machine::EVM15 ? "EVM 1.5" :
"eWasm"; "Ewasm";
sout() << endl << "======= " << src.first << " (" << machine << ") =======" << endl; sout() << endl << "======= " << src.first << " (" << machine << ") =======" << endl;
yul::AssemblyStack& stack = assemblyStacks[src.first]; yul::AssemblyStack& stack = assemblyStacks[src.first];
@ -1461,9 +1460,9 @@ bool CommandLineInterface::assemble(
sout() << endl << "Pretty printed source:" << endl; sout() << endl << "Pretty printed source:" << endl;
sout() << stack.print() << endl; sout() << stack.print() << endl;
if (_language != yul::AssemblyStack::Language::EWasm && _targetMachine == yul::AssemblyStack::Machine::eWasm) if (_language != yul::AssemblyStack::Language::Ewasm && _targetMachine == yul::AssemblyStack::Machine::Ewasm)
{ {
stack.translate(yul::AssemblyStack::Language::EWasm); stack.translate(yul::AssemblyStack::Language::Ewasm);
stack.optimize(); stack.optimize();
sout() << endl << "==========================" << endl; sout() << endl << "==========================" << endl;
@ -1554,7 +1553,7 @@ void CommandLineInterface::outputCompilationResults()
handleBytecode(contract); handleBytecode(contract);
handleIR(contract); handleIR(contract);
handleEWasm(contract); handleEwasm(contract);
handleSignatureHashes(contract); handleSignatureHashes(contract);
handleMetadata(contract); handleMetadata(contract);
handleABI(contract); handleABI(contract);

View File

@ -67,7 +67,7 @@ private:
void handleBinary(std::string const& _contract); void handleBinary(std::string const& _contract);
void handleOpcode(std::string const& _contract); void handleOpcode(std::string const& _contract);
void handleIR(std::string const& _contract); void handleIR(std::string const& _contract);
void handleEWasm(std::string const& _contract); void handleEwasm(std::string const& _contract);
void handleBytecode(std::string const& _contract); void handleBytecode(std::string const& _contract);
void handleSignatureHashes(std::string const& _contract); void handleSignatureHashes(std::string const& _contract);
void handleMetadata(std::string const& _contract); void handleMetadata(std::string const& _contract);

View File

@ -131,8 +131,8 @@ set(libyul_sources
libyul/Common.cpp libyul/Common.cpp
libyul/Common.h libyul/Common.h
libyul/CompilabilityChecker.cpp libyul/CompilabilityChecker.cpp
libyul/EWasmTranslationTest.cpp libyul/EwasmTranslationTest.cpp
libyul/EWasmTranslationTest.h libyul/EwasmTranslationTest.h
libyul/FunctionSideEffects.cpp libyul/FunctionSideEffects.cpp
libyul/FunctionSideEffects.h libyul/FunctionSideEffects.h
libyul/Inliner.cpp libyul/Inliner.cpp

View File

@ -25,7 +25,7 @@
#include <test/libsolidity/SemanticTest.h> #include <test/libsolidity/SemanticTest.h>
#include <test/libsolidity/SMTCheckerTest.h> #include <test/libsolidity/SMTCheckerTest.h>
#include <test/libsolidity/SMTCheckerJSONTest.h> #include <test/libsolidity/SMTCheckerJSONTest.h>
#include <test/libyul/EWasmTranslationTest.h> #include <test/libyul/EwasmTranslationTest.h>
#include <test/libyul/YulOptimizerTest.h> #include <test/libyul/YulOptimizerTest.h>
#include <test/libyul/YulInterpreterTest.h> #include <test/libyul/YulInterpreterTest.h>
#include <test/libyul/ObjectCompilerTest.h> #include <test/libyul/ObjectCompilerTest.h>
@ -56,7 +56,7 @@ struct Testsuite
Testsuite const g_interactiveTestsuites[] = { Testsuite const g_interactiveTestsuites[] = {
/* /*
Title Path Subpath SMT NeedsVM Creator function */ Title Path Subpath SMT NeedsVM Creator function */
{"EWasm Translation", "libyul", "ewasmTranslationTests",false,false, &yul::test::EWasmTranslationTest::create}, {"Ewasm Translation", "libyul", "ewasmTranslationTests",false,false, &yul::test::EwasmTranslationTest::create},
{"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create}, {"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create},
{"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create}, {"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create},
{"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create}, {"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create},

View File

@ -1,5 +1,5 @@
======= evm_to_wasm/input.sol (eWasm) ======= ======= evm_to_wasm/input.sol (Ewasm) =======
Pretty printed source: Pretty printed source:
object "object" { object "object" {

View File

@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(string_storage)
auto evmVersion = dev::test::Options::get().evmVersion(); auto evmVersion = dev::test::Options::get().evmVersion();
if (evmVersion <= EVMVersion::byzantium()) if (evmVersion <= EVMVersion::byzantium())
CHECK_DEPLOY_GAS(134145, 130831, evmVersion); CHECK_DEPLOY_GAS(134209, 130895, evmVersion);
// This is only correct on >=Constantinople. // This is only correct on >=Constantinople.
else if (Options::get().useABIEncoderV2) else if (Options::get().useABIEncoderV2)
{ {
@ -107,22 +107,22 @@ BOOST_AUTO_TEST_CASE(string_storage)
{ {
// Costs with 0 are cases which cannot be triggered in tests. // Costs with 0 are cases which cannot be triggered in tests.
if (evmVersion < EVMVersion::istanbul()) if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(0, 123969, evmVersion); CHECK_DEPLOY_GAS(0, 124033, evmVersion);
else else
CHECK_DEPLOY_GAS(0, 110969, evmVersion); CHECK_DEPLOY_GAS(0, 110981, evmVersion);
} }
else else
{ {
if (evmVersion < EVMVersion::istanbul()) if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(147771, 131687, evmVersion); CHECK_DEPLOY_GAS(147835, 131687, evmVersion);
else else
CHECK_DEPLOY_GAS(131859, 117231, evmVersion); CHECK_DEPLOY_GAS(131871, 117231, evmVersion);
} }
} }
else if (evmVersion < EVMVersion::istanbul()) else if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(126929, 119659, evmVersion); CHECK_DEPLOY_GAS(126993, 119723, evmVersion);
else else
CHECK_DEPLOY_GAS(114345, 107335, evmVersion); CHECK_DEPLOY_GAS(114357, 107347, evmVersion);
if (evmVersion >= EVMVersion::byzantium()) if (evmVersion >= EVMVersion::byzantium())
{ {

View File

@ -14319,8 +14319,6 @@ BOOST_AUTO_TEST_CASE(event_wrong_abi_name)
)"; )";
compileAndRun(sourceCode, 0, "ClientReceipt", bytes()); compileAndRun(sourceCode, 0, "ClientReceipt", bytes());
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"ClientReceipt", m_contractAddress}}); compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"ClientReceipt", m_contractAddress}});
u256 value(18);
u256 id(0x1234);
callContractFunction("f()"); callContractFunction("f()");
BOOST_REQUIRE_EQUAL(numLogs(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <test/libyul/EWasmTranslationTest.h> #include <test/libyul/EwasmTranslationTest.h>
#include <test/tools/yulInterpreter/Interpreter.h> #include <test/tools/yulInterpreter/Interpreter.h>
@ -23,7 +23,7 @@
#include <libyul/backends/evm/EVMDialect.h> #include <libyul/backends/evm/EVMDialect.h>
#include <libyul/backends/wasm/WasmDialect.h> #include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/backends/wasm/EVMToEWasmTranslator.h> #include <libyul/backends/wasm/EVMToEwasmTranslator.h>
#include <libyul/AsmParser.h> #include <libyul/AsmParser.h>
#include <libyul/AssemblyStack.h> #include <libyul/AssemblyStack.h>
#include <libyul/AsmAnalysisInfo.h> #include <libyul/AsmAnalysisInfo.h>
@ -47,7 +47,7 @@ using namespace dev::solidity::test;
using namespace std; using namespace std;
EWasmTranslationTest::EWasmTranslationTest(string const& _filename) EwasmTranslationTest::EwasmTranslationTest(string const& _filename)
{ {
boost::filesystem::path path(_filename); boost::filesystem::path path(_filename);
@ -60,12 +60,12 @@ EWasmTranslationTest::EWasmTranslationTest(string const& _filename)
m_expectation = parseSimpleExpectations(file); m_expectation = parseSimpleExpectations(file);
} }
TestCase::TestResult EWasmTranslationTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
{ {
if (!parse(_stream, _linePrefix, _formatted)) if (!parse(_stream, _linePrefix, _formatted))
return TestResult::FatalError; return TestResult::FatalError;
*m_object = EVMToEWasmTranslator( *m_object = EVMToEwasmTranslator(
EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion()) EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion())
).run(*m_object); ).run(*m_object);
@ -89,17 +89,17 @@ TestCase::TestResult EWasmTranslationTest::run(ostream& _stream, string const& _
return TestResult::Success; return TestResult::Success;
} }
void EWasmTranslationTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const void EwasmTranslationTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{ {
printIndented(_stream, m_source, _linePrefix); printIndented(_stream, m_source, _linePrefix);
} }
void EWasmTranslationTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const void EwasmTranslationTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{ {
printIndented(_stream, m_obtainedResult, _linePrefix); printIndented(_stream, m_obtainedResult, _linePrefix);
} }
void EWasmTranslationTest::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const void EwasmTranslationTest::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const
{ {
stringstream output(_output); stringstream output(_output);
string line; string line;
@ -107,7 +107,7 @@ void EWasmTranslationTest::printIndented(ostream& _stream, string const& _output
_stream << _linePrefix << line << endl; _stream << _linePrefix << line << endl;
} }
bool EWasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted) bool EwasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)
{ {
AssemblyStack stack( AssemblyStack stack(
dev::test::Options::get().evmVersion(), dev::test::Options::get().evmVersion(),
@ -127,11 +127,11 @@ bool EWasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bo
} }
} }
string EWasmTranslationTest::interpret() string EwasmTranslationTest::interpret()
{ {
InterpreterState state; InterpreterState state;
state.maxTraceSize = 10000; state.maxTraceSize = 10000;
state.maxSteps = 10000; state.maxSteps = 100000;
WasmDialect dialect; WasmDialect dialect;
Interpreter interpreter(state, dialect); Interpreter interpreter(state, dialect);
try try
@ -147,7 +147,7 @@ string EWasmTranslationTest::interpret()
return result.str(); return result.str();
} }
void EWasmTranslationTest::printErrors(ostream& _stream, ErrorList const& _errors) void EwasmTranslationTest::printErrors(ostream& _stream, ErrorList const& _errors)
{ {
SourceReferenceFormatter formatter(_stream); SourceReferenceFormatter formatter(_stream);

View File

@ -32,15 +32,15 @@ namespace yul
namespace test namespace test
{ {
class EWasmTranslationTest: public dev::solidity::test::EVMVersionRestrictedTestCase class EwasmTranslationTest: public dev::solidity::test::EVMVersionRestrictedTestCase
{ {
public: public:
static std::unique_ptr<TestCase> create(Config const& _config) static std::unique_ptr<TestCase> create(Config const& _config)
{ {
return std::make_unique<EWasmTranslationTest>(_config.filename); return std::make_unique<EwasmTranslationTest>(_config.filename);
} }
explicit EWasmTranslationTest(std::string const& _filename); explicit EwasmTranslationTest(std::string const& _filename);
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;

View File

@ -60,6 +60,7 @@
#include <libyul/backends/evm/EVMDialect.h> #include <libyul/backends/evm/EVMDialect.h>
#include <libyul/backends/evm/EVMMetrics.h> #include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/backends/wasm/WordSizeTransform.h> #include <libyul/backends/wasm/WordSizeTransform.h>
#include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/AsmPrinter.h> #include <libyul/AsmPrinter.h>
#include <libyul/AsmParser.h> #include <libyul/AsmParser.h>
#include <libyul/AsmAnalysis.h> #include <libyul/AsmAnalysis.h>
@ -98,12 +99,24 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename)
file.exceptions(ios::badbit); file.exceptions(ios::badbit);
m_source = parseSourceAndSettings(file); m_source = parseSourceAndSettings(file);
if (m_settings.count("yul")) if (m_settings.count("dialect"))
{ {
m_yul = true; auto dialectName = m_settings["dialect"];
m_validatedSettings["yul"] = "true"; if (dialectName == "yul")
m_settings.erase("yul"); m_dialect = &Dialect::yul();
else if (dialectName == "ewasm")
m_dialect = &WasmDialect::instance();
else if (dialectName == "evm")
m_dialect = &EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion());
else
BOOST_THROW_EXCEPTION(runtime_error("Invalid dialect " + dialectName));
m_validatedSettings["dialect"] = dialectName;
m_settings.erase("dialect");
} }
else
m_dialect = &EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion());
if (m_settings.count("step")) if (m_settings.count("step"))
{ {
m_validatedSettings["step"] = m_settings["step"]; m_validatedSettings["step"] = m_settings["step"];
@ -350,7 +363,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
return TestResult::FatalError; return TestResult::FatalError;
} }
m_obtainedResult = AsmPrinter{m_yul}(*m_ast) + "\n"; m_obtainedResult = AsmPrinter{m_dialect->flavour == AsmFlavour::Yul}(*m_ast) + "\n";
if (m_optimizerStep != m_validatedSettings["step"]) if (m_optimizerStep != m_validatedSettings["step"])
{ {
@ -406,7 +419,7 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c
{ {
AssemblyStack stack( AssemblyStack stack(
dev::test::Options::get().evmVersion(), dev::test::Options::get().evmVersion(),
m_yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly, m_dialect->flavour == AsmFlavour::Yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly,
dev::solidity::OptimiserSettings::none() dev::solidity::OptimiserSettings::none()
); );
if (!stack.parseAndAnalyze("", m_source) || !stack.errors().empty()) if (!stack.parseAndAnalyze("", m_source) || !stack.errors().empty())
@ -415,7 +428,6 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c
printErrors(_stream, stack.errors()); printErrors(_stream, stack.errors());
return false; return false;
} }
m_dialect = m_yul ? &Dialect::yul() : &EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion());
m_ast = stack.parserResult()->code; m_ast = stack.parserResult()->code;
m_analysisInfo = stack.parserResult()->analysisInfo; m_analysisInfo = stack.parserResult()->analysisInfo;
return true; return true;

View File

@ -71,7 +71,6 @@ private:
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors); static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
std::string m_source; std::string m_source;
bool m_yul = false;
std::string m_optimizerStep; std::string m_optimizerStep;
std::string m_expectation; std::string m_expectation;

View File

@ -0,0 +1,35 @@
{
sstore(0, add(0, 1))
sstore(1, add(1, not(0)))
sstore(2, add(0, 0))
sstore(3, add(1, 2))
sstore(4, add(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1))
sstore(5, add(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, add(not(0), 1))
sstore(7, add(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, add(0xffffffffffffffff, 1))
sstore(9, add(0xffffffffffffffffffffffffffffffff0000000000000000, 1))
sstore(10, add(0xffffffffffffffffffffffffffffffffffffffffffffffff, 3))
sstore(11, add(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, add(0xffffffffffffffff, 3))
sstore(13, add(0xffffffffffffffffffffffffffffffff0000000000000000, 3))
}
// ----
// Trace:
// Memory dump:
// 0: 000000000000000000000000000000000000000000000000000000000000000d
// 20: 0000000000000000ffffffffffffffffffffffffffffffff0000000000000003
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000000000001
// 0000000000000000000000000000000000000000000000000000000000000003: 0000000000000000000000000000000000000000000000000000000000000003
// 0000000000000000000000000000000000000000000000000000000000000004: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000005: 8000000000000000000000000000000000000000000000000000000000000001
// 0000000000000000000000000000000000000000000000000000000000000007: 0000000000000000000000000000000100000000000000000000000000000000
// 0000000000000000000000000000000000000000000000000000000000000008: 0000000000000000000000000000000000000000000000010000000000000000
// 0000000000000000000000000000000000000000000000000000000000000009: 0000000000000000ffffffffffffffffffffffffffffffff0000000000000001
// 000000000000000000000000000000000000000000000000000000000000000a: 0000000000000001000000000000000000000000000000000000000000000002
// 000000000000000000000000000000000000000000000000000000000000000b: 0000000000000000000000000000000100000000000000000000000000000002
// 000000000000000000000000000000000000000000000000000000000000000c: 0000000000000000000000000000000000000000000000010000000000000002
// 000000000000000000000000000000000000000000000000000000000000000d: 0000000000000000ffffffffffffffffffffffffffffffff0000000000000003

View File

@ -0,0 +1,20 @@
{
sstore(0, addmod(0, 1, 1))
sstore(1, addmod(0, 1, 2))
sstore(2, addmod(3, 1, 2))
sstore(3, addmod(1, not(0), 5))
sstore(4, addmod(0, 0, 0))
sstore(5, addmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1, 1))
sstore(6, addmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1, 0))
sstore(7, addmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd, 1, 5))
sstore(8, addmod(
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,
5
))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -0,0 +1,23 @@
{
sstore(0, div(0, 1))
sstore(1, div(1, not(0)))
sstore(2, div(0, 0))
sstore(3, div(1, 2))
sstore(4, div(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1))
sstore(5, div(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, div(not(0), 1))
sstore(7, div(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, div(0xffffffffffffffff, 1))
sstore(9, div(0xffffffffffffffffffffffffffffffff0000000000000000, 1))
sstore(10, div(0xffffffffffffffffffffffffffffffffffffffffffffffff, 3))
sstore(11, div(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, div(0xffffffffffffffff, 3))
sstore(13, div(0xffffffffffffffffffffffffffffffff0000000000000000, 3))
}
// ----
// Trace:
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000001
// Storage dump:

View File

@ -0,0 +1,25 @@
{
sstore(0, exp(0, 1))
sstore(1, exp(1, not(0)))
sstore(2, exp(0, 0))
sstore(3, exp(1, 2))
sstore(4, exp(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1))
sstore(5, exp(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, exp(not(0), 1))
sstore(7, exp(0xffffffffffffffffffffffffffffffff, 2))
sstore(8, exp(0xffffffffffffffff, 2))
sstore(9, exp(0xffffffffffffffffffffffffffffffff0000000000000000, 2))
sstore(10, exp(0xffffffffffffffffffffffffffffffffffffffffffffffff, 3))
sstore(11, exp(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, exp(0xffffffffffffffff, 3))
sstore(13, exp(0xffffffffffffffffffffffffffffffff0000000000000000, 3))
sstore(14, exp(2, 256))
sstore(15, exp(2, 255))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -0,0 +1,25 @@
{
sstore(0, mod(0, 1))
sstore(1, mod(1, not(0)))
sstore(2, mod(0, 0))
sstore(3, mod(1, 2))
sstore(4, mod(not(0), 1))
sstore(5, mod(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, mod(not(0), 1))
sstore(7, mod(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, mod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 0xfffffffffffffffffffffffffffffffe))
sstore(9, mod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 5))
sstore(10, mod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 4))
sstore(11, mod(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, mod(0xffffffffffffffff, 3))
sstore(13, mod(0xffffffffffffffffffffffffffffffff0000000000000000, 0xffffffffffffffff43342553000))
}
// ----
// Trace:
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000001
// 20: 0000000000000000000000000000000000000000000000000000000000000001
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000001

View File

@ -0,0 +1,36 @@
{
sstore(0, mul(0, 1))
sstore(1, mul(1, not(0)))
sstore(2, mul(0, 0))
sstore(3, mul(1, 2))
sstore(4, mul(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1))
sstore(5, mul(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, mul(not(0), 1))
sstore(7, mul(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, mul(0xffffffffffffffff, 1))
sstore(9, mul(0xffffffffffffffffffffffffffffffff0000000000000000, 1))
sstore(10, mul(0xffffffffffffffffffffffffffffffffffffffffffffffff, 3))
sstore(11, mul(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, mul(0xffffffffffffffff, 3))
sstore(13, mul(0xffffffffffffffffffffffffffffffff0000000000000000, 3))
}
// ----
// Trace:
// Memory dump:
// 0: 000000000000000000000000000000000000000000000000000000000000000d
// 20: 0000000000000002fffffffffffffffffffffffffffffffd0000000000000000
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000001: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000003: 0000000000000000000000000000000000000000000000000000000000000002
// 0000000000000000000000000000000000000000000000000000000000000004: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
// 0000000000000000000000000000000000000000000000000000000000000005: 8000000000000000000000000000000000000000000000000000000000000000
// 0000000000000000000000000000000000000000000000000000000000000006: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000007: 00000000000000000000000000000000ffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000008: 000000000000000000000000000000000000000000000000ffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000009: 0000000000000000ffffffffffffffffffffffffffffffff0000000000000000
// 000000000000000000000000000000000000000000000000000000000000000a: 0000000000000002fffffffffffffffffffffffffffffffffffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000b: 00000000000000000000000000000002fffffffffffffffffffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000c: 000000000000000000000000000000000000000000000002fffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000d: 0000000000000002fffffffffffffffffffffffffffffffd0000000000000000

View File

@ -0,0 +1,22 @@
{
sstore(0, mulmod(0, 1, 2))
sstore(1, mulmod(1, not(0), 5))
sstore(2, mulmod(0, 0, 5))
sstore(3, mulmod(1, 3, 2))
sstore(4, mulmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,
1,
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff))
sstore(5, mulmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1, 1))
sstore(6, mulmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1, 0))
sstore(7, mulmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd, 1, 5))
sstore(8, mulmod(
not(0),
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,
25
))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -0,0 +1,25 @@
{
sstore(0, sdiv(0, 1))
sstore(1, sdiv(0, not(0)))
sstore(2, sdiv(0, 0))
sstore(3, sdiv(1, 2))
sstore(4, sdiv(not(0), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe))
sstore(5, sdiv(0x8000000000000000000000000000000000000000000000000000000000000000, not(0)))
sstore(6, sdiv(not(0), 0x8000000000000000000000000000000000000000000000000000000000000000))
sstore(7, sdiv(0x7000000000000000000000000000000000000000000000000000000000000000, 1))
sstore(8, sdiv(1, 0x7000000000000000000000000000000000000000000000000000000000000000))
sstore(9, sdiv(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, not(0)))
sstore(10, sdiv(not(0), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff))
sstore(11, sdiv(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 1))
sstore(12, sdiv(not(0), not(0)))
sstore(13, sdiv(
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
))
sstore(14, sdiv(0x8000000000000000000000000000000000000000000000000000000000000001, not(0)))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -0,0 +1,29 @@
{
sstore(0, smod(0, 1))
sstore(1, smod(1, not(0)))
sstore(2, smod(0, 0))
sstore(3, smod(1, 2))
sstore(4, smod(not(0), 1))
sstore(5, smod(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, smod(not(0), 1))
sstore(7, smod(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, smod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 0xfffffffffffffffffffffffffffffffe))
sstore(9, smod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 5))
sstore(10, smod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 4))
sstore(11, smod(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, smod(0xffffffffffffffff, 3))
sstore(13, smod(0xffffffffffffffffffffffffffffffff0000000000000000, 0xffffffffffffffff43342553000))
sstore(14, smod(
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd,
0xffffffffffffffff43342553000
))
}
// ----
// Trace:
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000001
// 20: 0000000000000000000000000000000000000000000000000000000000000001
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000001

View File

@ -0,0 +1,36 @@
{
sstore(0, sub(0, 1))
sstore(1, sub(1, not(0)))
sstore(2, sub(0, 0))
sstore(3, sub(1, 2))
sstore(4, sub(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 1))
sstore(5, sub(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, sub(not(0), 1))
sstore(7, sub(not(0), not(0)))
sstore(8, sub(0x1000000000000000000000000000000000000000000000000, 1))
sstore(9, sub(0x100000000000000000000000000000000, 1))
sstore(10, sub(0x10000000000000000, 1))
sstore(11, sub(0x1000000000000000000000000000000000000000000000000, 3))
sstore(12, sub(0x100000000000000000000000000000000, 3))
sstore(13, sub(0x10000000000000000, 3))
}
// ----
// Trace:
// Memory dump:
// 0: 000000000000000000000000000000000000000000000000000000000000000d
// 20: 000000000000000000000000000000000000000000000000fffffffffffffffd
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000000: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000002
// 0000000000000000000000000000000000000000000000000000000000000003: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000004: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
// 0000000000000000000000000000000000000000000000000000000000000005: 7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000006: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
// 0000000000000000000000000000000000000000000000000000000000000008: 0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000009: 00000000000000000000000000000000ffffffffffffffffffffffffffffffff
// 000000000000000000000000000000000000000000000000000000000000000a: 000000000000000000000000000000000000000000000000ffffffffffffffff
// 000000000000000000000000000000000000000000000000000000000000000b: 0000000000000000fffffffffffffffffffffffffffffffffffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000c: 00000000000000000000000000000000fffffffffffffffffffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000d: 000000000000000000000000000000000000000000000000fffffffffffffffd

View File

@ -4,11 +4,16 @@
let z := shr(136, y) let z := shr(136, y)
sstore(0, y) sstore(0, y)
sstore(1, z) sstore(1, z)
sstore(2, sar(136, 0x801112131415161718191a1b1c1d1e1f20000000000000000000000000000000))
sstore(3, sar(256, 0x801112131415161718191a1b1c1d1e1f20000000000000000000000000000000))
sstore(4, sar(136, 0x701112131415161718191a1b1c1d1e1f20000000000000000000000000000000))
sstore(5, sar(256, 0x701112131415161718191a1b1c1d1e1f20000000000000000000000000000000))
} }
// ==== // ====
// EVMVersion: >=constantinople // EVMVersion: >=constantinople
// ---- // ----
// Trace: // Trace:
// INVALID()
// Memory dump: // Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000001 // 0: 0000000000000000000000000000000000000000000000000000000000000001
// 20: 0000000000000000000000000000000000101112131415161718191a1b1c1d1e // 20: 0000000000000000000000000000000000101112131415161718191a1b1c1d1e

View File

@ -0,0 +1,11 @@
{
sstore(0, signextend(0, 0x86))
sstore(1, signextend(0, 0x76))
sstore(2, signextend(32, not(0)))
sstore(3, signextend(5, 0xff8844553322))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -7,6 +7,5 @@
// Trace: // Trace:
// INVALID() // INVALID()
// Memory dump: // Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000014
// 40: 636f6465636f6465636f6465636f6465636f6465000000000000000000000000 // 40: 636f6465636f6465636f6465636f6465636f6465000000000000000000000000
// Storage dump: // Storage dump:

View File

@ -9,6 +9,5 @@
// Trace: // Trace:
// INVALID() // INVALID()
// Memory dump: // Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000014
// 80: 636f6465636f6465636f6465636f6465636f6465000000000000000000000000 // 80: 636f6465636f6465636f6465636f6465636f6465000000000000000000000000
// Storage dump: // Storage dump:

View File

@ -8,7 +8,7 @@
} }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { // {
// { let a:u256, b:u256 } // { let a:u256, b:u256 }

View File

@ -8,7 +8,7 @@
} }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { // {
// { // {

View File

@ -7,7 +7,7 @@
} }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { // {
// { let a:u256, b:u256, c:u256 } // { let a:u256, b:u256, c:u256 }

View File

@ -1,7 +1,7 @@
{ { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } } { { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { // {
// { // {

View File

@ -1,6 +1,6 @@
{ } { }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { } // { }

View File

@ -9,7 +9,7 @@
} }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { // {
// { let a:u256, b:u256, c:u256 } // { let a:u256, b:u256, c:u256 }

View File

@ -1,7 +1,7 @@
{ { let a:u256 } { let a:u256 } } { { let a:u256 } { let a:u256 } }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { // {
// { let a:u256 } // { let a:u256 }

View File

@ -1,7 +1,7 @@
{ { let a:u256 let a_1:u256 } { let a:u256 } } { { let a:u256 let a_1:u256 } { let a:u256 } }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { // {
// { // {

View File

@ -7,7 +7,7 @@
} }
// ==== // ====
// step: disambiguator // step: disambiguator
// yul: true // dialect: yul
// ---- // ----
// { // {
// { // {

View File

@ -4,7 +4,7 @@
} }
// ==== // ====
// step: expressionInliner // step: expressionInliner
// yul: true // dialect: yul
// ---- // ----
// { // {
// function f() -> x:u256 // function f() -> x:u256

View File

@ -4,7 +4,7 @@
} }
// ==== // ====
// step: expressionInliner // step: expressionInliner
// yul: true // dialect: yul
// ---- // ----
// { // {
// function f(a:u256) -> x:u256 // function f(a:u256) -> x:u256

View File

@ -1,7 +1,7 @@
{ let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } } { let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } }
// ==== // ====
// step: functionGrouper // step: functionGrouper
// yul: true // dialect: yul
// ---- // ----
// { // {
// { // {

View File

@ -6,7 +6,7 @@
} }
// ==== // ====
// step: functionGrouper // step: functionGrouper
// yul: true // dialect: yul
// ---- // ----
// { // {
// { // {

View File

@ -10,7 +10,7 @@
} }
// ==== // ====
// step: functionGrouper // step: functionGrouper
// yul: true // dialect: yul
// ---- // ----
// { // {
// { let a:u256 } // { let a:u256 }

View File

@ -3,7 +3,7 @@
} }
// ==== // ====
// step: functionGrouper // step: functionGrouper
// yul: true // dialect: yul
// ---- // ----
// { // {
// { let a:u256 } // { let a:u256 }

View File

@ -9,7 +9,7 @@
} }
// ==== // ====
// step: functionHoister // step: functionHoister
// yul: true // dialect: yul
// ---- // ----
// { // {
// let a:u256 // let a:u256

View File

@ -7,7 +7,7 @@
} }
// ==== // ====
// step: functionHoister // step: functionHoister
// yul: true // dialect: yul
// ---- // ----
// { // {
// let a:u256 // let a:u256

View File

@ -8,7 +8,7 @@
} }
// ==== // ====
// step: functionHoister // step: functionHoister
// yul: true // dialect: yul
// ---- // ----
// { // {
// let a:u256 // let a:u256

View File

@ -4,7 +4,7 @@
} }
// ==== // ====
// step: functionHoister // step: functionHoister
// yul: true // dialect: yul
// ---- // ----
// { // {
// let a:u256 // let a:u256

View File

@ -9,7 +9,7 @@
} }
// ==== // ====
// step: mainFunction // step: mainFunction
// yul: true // dialect: yul
// ---- // ----
// { // {
// function main() // function main()

View File

@ -7,7 +7,7 @@
} }
// ==== // ====
// step: mainFunction // step: mainFunction
// yul: true // dialect: yul
// ---- // ----
// { // {
// function main() // function main()

View File

@ -8,7 +8,7 @@
} }
// ==== // ====
// step: mainFunction // step: mainFunction
// yul: true // dialect: yul
// ---- // ----
// { // {
// function main() // function main()

View File

@ -4,7 +4,7 @@
} }
// ==== // ====
// step: mainFunction // step: mainFunction
// yul: true // dialect: yul
// ---- // ----
// { // {
// function main() // function main()

View File

@ -1,7 +1,7 @@
{} {}
// ==== // ====
// step: mainFunction // step: mainFunction
// yul: true // dialect: yul
// ---- // ----
// { // {
// function main() // function main()

View File

@ -0,0 +1,26 @@
{
let i := 0
for {} lt(i, 2) { i := add(i, 1) }
{
let x
x := 1337
if lt(i,1) {
x := 42
break
}
mstore(0, x)
}
}
// ====
// step: redundantAssignEliminator
// ----
// {
// let i := 0
// for { } lt(i, 2) { i := add(i, 1) }
// {
// let x
// x := 1337
// if lt(i, 1) { break }
// mstore(0, x)
// }
// }

View File

@ -0,0 +1,27 @@
{
let i := 0
for {} lt(i, 2) { i := add(i, 1) }
{
let x
x := 1337
if lt(i,1) {
x := 42
continue
}
mstore(0, x)
}
}
// ====
// step: redundantAssignEliminator
// ----
// {
// let i := 0
// for { } lt(i, 2) { i := add(i, 1) }
// {
// let x
// x := 1337
// if lt(i, 1) { continue }
// mstore(0, x)
// }
// }

View File

@ -32,7 +32,7 @@ add_executable(isoltest
../libsolidity/SMTCheckerTest.cpp ../libsolidity/SMTCheckerTest.cpp
../libsolidity/SMTCheckerJSONTest.cpp ../libsolidity/SMTCheckerJSONTest.cpp
../libyul/Common.cpp ../libyul/Common.cpp
../libyul/EWasmTranslationTest.cpp ../libyul/EwasmTranslationTest.cpp
../libyul/FunctionSideEffects.cpp ../libyul/FunctionSideEffects.cpp
../libyul/ObjectCompilerTest.cpp ../libyul/ObjectCompilerTest.cpp
../libyul/YulOptimizerTest.cpp ../libyul/YulOptimizerTest.cpp

View File

@ -1,8 +1,8 @@
set(sources set(sources
EVMInstructionInterpreter.h EVMInstructionInterpreter.h
EVMInstructionInterpreter.cpp EVMInstructionInterpreter.cpp
EWasmBuiltinInterpreter.h EwasmBuiltinInterpreter.h
EWasmBuiltinInterpreter.cpp EwasmBuiltinInterpreter.cpp
Interpreter.h Interpreter.h
Interpreter.cpp Interpreter.cpp
) )

View File

@ -15,10 +15,10 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Yul interpreter module that evaluates EWasm builtins. * Yul interpreter module that evaluates Ewasm builtins.
*/ */
#include <test/tools/yulInterpreter/EWasmBuiltinInterpreter.h> #include <test/tools/yulInterpreter/EwasmBuiltinInterpreter.h>
#include <test/tools/yulInterpreter/Interpreter.h> #include <test/tools/yulInterpreter/Interpreter.h>
@ -49,11 +49,26 @@ void copyZeroExtended(
_target[_targetOffset + i] = _sourceOffset + i < _source.size() ? _source[_sourceOffset + i] : 0; _target[_targetOffset + i] = _sourceOffset + i < _source.size() ? _source[_sourceOffset + i] : 0;
} }
/// Count leading zeros for uint64
uint64_t clz(uint64_t _v)
{
if (_v == 0)
return 64;
uint64_t r = 0;
while (!(_v & 0x8000000000000000))
{
r += 1;
_v = _v << 1;
}
return r;
}
} }
using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _arguments) u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _arguments)
{ {
vector<uint64_t> arg; vector<uint64_t> arg;
for (u256 const& a: _arguments) for (u256 const& a: _arguments)
@ -119,6 +134,8 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return arg[0] != arg[1] ? 1 : 0; return arg[0] != arg[1] ? 1 : 0;
else if (_fun == "i64.eqz"_yulstring) else if (_fun == "i64.eqz"_yulstring)
return arg[0] == 0 ? 1 : 0; return arg[0] == 0 ? 1 : 0;
else if (_fun == "i64.clz"_yulstring)
return clz(arg[0]);
else if (_fun == "i64.lt_u"_yulstring) else if (_fun == "i64.lt_u"_yulstring)
return arg[0] < arg[1] ? 1 : 0; return arg[0] < arg[1] ? 1 : 0;
else if (_fun == "i64.gt_u"_yulstring) else if (_fun == "i64.gt_u"_yulstring)
@ -133,24 +150,39 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
writeMemoryWord(arg[0], arg[1]); writeMemoryWord(arg[0], arg[1]);
return 0; return 0;
} }
else if (_fun == "i64.store8"_yulstring)
{
accessMemory(arg[0], 1);
writeMemoryByte(arg[0], static_cast<uint8_t>(arg[1] & 0xff));
return 0;
}
else if (_fun == "i64.load"_yulstring) else if (_fun == "i64.load"_yulstring)
{ {
accessMemory(arg[0], 8); accessMemory(arg[0], 8);
return readMemoryWord(arg[0]); return readMemoryWord(arg[0]);
} }
else if (_fun == "eth.getAddress"_yulstring) else if (_fun == "eth.getAddress"_yulstring)
return writeAddress(arg[0], m_state.address); {
writeAddress(arg[0], m_state.address);
return 0;
}
else if (_fun == "eth.getExternalBalance"_yulstring) else if (_fun == "eth.getExternalBalance"_yulstring)
{
// TODO this does not read the address, but is consistent with // TODO this does not read the address, but is consistent with
// EVM interpreter implementation. // EVM interpreter implementation.
// If we take the address into account, this needs to use readAddress. // If we take the address into account, this needs to use readAddress.
return writeU128(arg[0], m_state.balance); writeU128(arg[1], m_state.balance);
return 0;
}
else if (_fun == "eth.getBlockHash"_yulstring) else if (_fun == "eth.getBlockHash"_yulstring)
{ {
if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber) if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber)
return 1; return 1;
else else
return writeU256(arg[1], 0xaaaaaaaa + u256(arg[0] - m_state.blockNumber - 256)); {
writeU256(arg[1], 0xaaaaaaaa + u256(arg[0] - m_state.blockNumber - 256));
return 0;
}
} }
else if (_fun == "eth.call"_yulstring) else if (_fun == "eth.call"_yulstring)
{ {
@ -199,12 +231,21 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0; return 0;
} }
else if (_fun == "eth.storageLoad"_yulstring) else if (_fun == "eth.storageLoad"_yulstring)
return writeU256(arg[1], m_state.storage[h256(readU256(arg[0]))]); {
writeU256(arg[1], m_state.storage[h256(readU256(arg[0]))]);
return 0;
}
else if (_fun == "eth.getCaller"_yulstring) else if (_fun == "eth.getCaller"_yulstring)
{
// TODO should this only write 20 bytes? // TODO should this only write 20 bytes?
return writeAddress(arg[0], m_state.caller); writeAddress(arg[0], m_state.caller);
return 0;
}
else if (_fun == "eth.getCallValue"_yulstring) else if (_fun == "eth.getCallValue"_yulstring)
return writeU128(arg[0], m_state.callvalue); {
writeU128(arg[0], m_state.callvalue);
return 0;
}
else if (_fun == "eth.codeCopy"_yulstring) else if (_fun == "eth.codeCopy"_yulstring)
{ {
if (accessMemory(arg[0], arg[2])) if (accessMemory(arg[0], arg[2]))
@ -215,9 +256,12 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0; return 0;
} }
else if (_fun == "eth.getCodeSize"_yulstring) else if (_fun == "eth.getCodeSize"_yulstring)
return writeU256(arg[0], m_state.code.size()); return m_state.code.size();
else if (_fun == "eth.getBlockCoinbase"_yulstring) else if (_fun == "eth.getBlockCoinbase"_yulstring)
return writeAddress(arg[0], m_state.coinbase); {
writeAddress(arg[0], m_state.coinbase);
return 0;
}
else if (_fun == "eth.create"_yulstring) else if (_fun == "eth.create"_yulstring)
{ {
// TODO access memory // TODO access memory
@ -226,7 +270,10 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0xcccccc + arg[1]; return 0xcccccc + arg[1];
} }
else if (_fun == "eth.getBlockDifficulty"_yulstring) else if (_fun == "eth.getBlockDifficulty"_yulstring)
return writeU256(arg[0], m_state.difficulty); {
writeU256(arg[0], m_state.difficulty);
return 0;
}
else if (_fun == "eth.externalCodeCopy"_yulstring) else if (_fun == "eth.externalCodeCopy"_yulstring)
{ {
// TODO use readAddress to read address. // TODO use readAddress to read address.
@ -239,22 +286,32 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0; return 0;
} }
else if (_fun == "eth.getExternalCodeSize"_yulstring) else if (_fun == "eth.getExternalCodeSize"_yulstring)
return u256(keccak256(h256(readAddress(arg[0])))) & 0xffffff; // Generate "random" code length. Make sure it fits the page size.
return u256(keccak256(h256(readAddress(arg[0])))) & 0xfff;
else if (_fun == "eth.getGasLeft"_yulstring) else if (_fun == "eth.getGasLeft"_yulstring)
return 0x99; return 0x99;
else if (_fun == "eth.getBlockGasLimit"_yulstring) else if (_fun == "eth.getBlockGasLimit"_yulstring)
return uint64_t(m_state.gaslimit); return uint64_t(m_state.gaslimit);
else if (_fun == "eth.getTxGasPrice"_yulstring) else if (_fun == "eth.getTxGasPrice"_yulstring)
return writeU128(arg[0], m_state.gasprice); {
writeU128(arg[0], m_state.gasprice);
return 0;
}
else if (_fun == "eth.log"_yulstring) else if (_fun == "eth.log"_yulstring)
{ {
logTrace(eth::Instruction::LOG0, {}); uint64_t numberOfTopics = arg[2];
if (numberOfTopics > 4)
throw ExplicitlyTerminated();
logTrace(eth::logInstruction(numberOfTopics), {});
return 0; return 0;
} }
else if (_fun == "eth.getBlockNumber"_yulstring) else if (_fun == "eth.getBlockNumber"_yulstring)
return m_state.blockNumber; return m_state.blockNumber;
else if (_fun == "eth.getTxOrigin"_yulstring) else if (_fun == "eth.getTxOrigin"_yulstring)
return writeAddress(arg[0], m_state.origin); {
writeAddress(arg[0], m_state.origin);
return 0;
}
else if (_fun == "eth.finish"_yulstring) else if (_fun == "eth.finish"_yulstring)
{ {
bytes data; bytes data;
@ -298,7 +355,7 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0; return 0;
} }
bool EWasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _size) bool EwasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _size)
{ {
if (((_offset + _size) >= _offset) && ((_offset + _size + 0x1f) >= (_offset + _size))) if (((_offset + _size) >= _offset) && ((_offset + _size + 0x1f) >= (_offset + _size)))
{ {
@ -312,7 +369,7 @@ bool EWasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _siz
return false; return false;
} }
bytes EWasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size) bytes EwasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size)
{ {
yulAssert(_size <= 0xffff, "Too large read."); yulAssert(_size <= 0xffff, "Too large read.");
bytes data(size_t(_size), uint8_t(0)); bytes data(size_t(_size), uint8_t(0));
@ -321,7 +378,7 @@ bytes EWasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size)
return data; return data;
} }
uint64_t EWasmBuiltinInterpreter::readMemoryWord(uint64_t _offset) uint64_t EwasmBuiltinInterpreter::readMemoryWord(uint64_t _offset)
{ {
uint64_t r = 0; uint64_t r = 0;
for (size_t i = 0; i < 8; i++) for (size_t i = 0; i < 8; i++)
@ -329,13 +386,18 @@ uint64_t EWasmBuiltinInterpreter::readMemoryWord(uint64_t _offset)
return r; return r;
} }
void EWasmBuiltinInterpreter::writeMemoryWord(uint64_t _offset, uint64_t _value) void EwasmBuiltinInterpreter::writeMemoryWord(uint64_t _offset, uint64_t _value)
{ {
for (size_t i = 0; i < 8; i++) for (size_t i = 0; i < 8; i++)
m_state.memory[_offset + i] = uint8_t((_value >> (i * 8)) & 0xff); m_state.memory[_offset + i] = uint8_t((_value >> (i * 8)) & 0xff);
} }
u256 EWasmBuiltinInterpreter::writeU256(uint64_t _offset, u256 _value, size_t _croppedTo) void EwasmBuiltinInterpreter::writeMemoryByte(uint64_t _offset, uint8_t _value)
{
m_state.memory[_offset] = _value;
}
void EwasmBuiltinInterpreter::writeU256(uint64_t _offset, u256 _value, size_t _croppedTo)
{ {
accessMemory(_offset, _croppedTo); accessMemory(_offset, _croppedTo);
for (size_t i = 0; i < _croppedTo; i++) for (size_t i = 0; i < _croppedTo; i++)
@ -343,11 +405,9 @@ u256 EWasmBuiltinInterpreter::writeU256(uint64_t _offset, u256 _value, size_t _c
m_state.memory[_offset + _croppedTo - 1 - i] = uint8_t(_value & 0xff); m_state.memory[_offset + _croppedTo - 1 - i] = uint8_t(_value & 0xff);
_value >>= 8; _value >>= 8;
} }
return {};
} }
u256 EWasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo) u256 EwasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo)
{ {
accessMemory(_offset, _croppedTo); accessMemory(_offset, _croppedTo);
u256 value; u256 value;
@ -357,12 +417,12 @@ u256 EWasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo)
return value; return value;
} }
void EWasmBuiltinInterpreter::logTrace(dev::eth::Instruction _instruction, std::vector<u256> const& _arguments, bytes const& _data) void EwasmBuiltinInterpreter::logTrace(dev::eth::Instruction _instruction, std::vector<u256> const& _arguments, bytes const& _data)
{ {
logTrace(dev::eth::instructionInfo(_instruction).name, _arguments, _data); logTrace(dev::eth::instructionInfo(_instruction).name, _arguments, _data);
} }
void EWasmBuiltinInterpreter::logTrace(std::string const& _pseudoInstruction, std::vector<u256> const& _arguments, bytes const& _data) void EwasmBuiltinInterpreter::logTrace(std::string const& _pseudoInstruction, std::vector<u256> const& _arguments, bytes const& _data)
{ {
string message = _pseudoInstruction + "("; string message = _pseudoInstruction + "(";
for (size_t i = 0; i < _arguments.size(); ++i) for (size_t i = 0; i < _arguments.size(); ++i)

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Yul interpreter module that evaluates EWasm builtins. * Yul interpreter module that evaluates Ewasm builtins.
*/ */
#pragma once #pragma once
@ -45,7 +45,7 @@ namespace test
struct InterpreterState; struct InterpreterState;
/** /**
* Interprets EWasm builtins based on the current state and logs instructions with * Interprets Ewasm builtins based on the current state and logs instructions with
* side-effects. * side-effects.
* *
* Since this is mainly meant to be used for differential fuzz testing, it is focused * Since this is mainly meant to be used for differential fuzz testing, it is focused
@ -63,10 +63,10 @@ struct InterpreterState;
* The main focus is that the generated execution trace is the same for equivalent executions * The main focus is that the generated execution trace is the same for equivalent executions
* and likely to be different for non-equivalent executions. * and likely to be different for non-equivalent executions.
*/ */
class EWasmBuiltinInterpreter class EwasmBuiltinInterpreter
{ {
public: public:
explicit EWasmBuiltinInterpreter(InterpreterState& _state): explicit EwasmBuiltinInterpreter(InterpreterState& _state):
m_state(_state) m_state(_state)
{} {}
/// Evaluate builtin function /// Evaluate builtin function
@ -86,11 +86,14 @@ private:
/// Writes a word to memory (little-endian) /// Writes a word to memory (little-endian)
/// Does not adjust msize, use @a accessMemory for that /// Does not adjust msize, use @a accessMemory for that
void writeMemoryWord(uint64_t _offset, uint64_t _value); void writeMemoryWord(uint64_t _offset, uint64_t _value);
/// Writes a byte to memory
/// Does not adjust msize, use @a accessMemory for that
void writeMemoryByte(uint64_t _offset, uint8_t _value);
/// Helper for eth.* builtins. Writes to memory (big-endian) and always returns zero. /// Helper for eth.* builtins. Writes to memory (big-endian) and always returns zero.
dev::u256 writeU256(uint64_t _offset, dev::u256 _value, size_t _croppedTo = 32); void writeU256(uint64_t _offset, dev::u256 _value, size_t _croppedTo = 32);
dev::u256 writeU128(uint64_t _offset, dev::u256 _value) { return writeU256(_offset, std::move(_value), 16); } void writeU128(uint64_t _offset, dev::u256 _value) { writeU256(_offset, std::move(_value), 16); }
dev::u256 writeAddress(uint64_t _offset, dev::u256 _value) { return writeU256(_offset, std::move(_value), 20); } void writeAddress(uint64_t _offset, dev::u256 _value) { writeU256(_offset, std::move(_value), 20); }
/// Helper for eth.* builtins. Reads from memory (big-endian) and returns the value; /// Helper for eth.* builtins. Reads from memory (big-endian) and returns the value;
dev::u256 readU256(uint64_t _offset, size_t _croppedTo = 32); dev::u256 readU256(uint64_t _offset, size_t _croppedTo = 32);
dev::u256 readU128(uint64_t _offset) { return readU256(_offset, 16); } dev::u256 readU128(uint64_t _offset) { return readU256(_offset, 16); }

View File

@ -21,7 +21,7 @@
#include <test/tools/yulInterpreter/Interpreter.h> #include <test/tools/yulInterpreter/Interpreter.h>
#include <test/tools/yulInterpreter/EVMInstructionInterpreter.h> #include <test/tools/yulInterpreter/EVMInstructionInterpreter.h>
#include <test/tools/yulInterpreter/EWasmBuiltinInterpreter.h> #include <test/tools/yulInterpreter/EwasmBuiltinInterpreter.h>
#include <libyul/AsmData.h> #include <libyul/AsmData.h>
#include <libyul/Dialect.h> #include <libyul/Dialect.h>
@ -246,7 +246,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall)
else if (WasmDialect const* dialect = dynamic_cast<WasmDialect const*>(&m_dialect)) else if (WasmDialect const* dialect = dynamic_cast<WasmDialect const*>(&m_dialect))
if (dialect->builtin(_funCall.functionName.name)) if (dialect->builtin(_funCall.functionName.name))
{ {
EWasmBuiltinInterpreter interpreter(m_state); EwasmBuiltinInterpreter interpreter(m_state);
setValue(interpreter.evalBuiltin(_funCall.functionName.name, values())); setValue(interpreter.evalBuiltin(_funCall.functionName.name, values()));
return; return;
} }