diff --git a/CMakeLists.txt b/CMakeLists.txt index 30073fd08ef6..fb8c1a49c811 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ include(EthPolicy) eth_policy() # 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) include(TestBigEndian) diff --git a/Changelog.md b/Changelog.md index e8731b5fa5bf..4487b30e4a8a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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) Breaking changes: @@ -33,6 +39,7 @@ Language Features: * Allow global enums and structs. * Allow public variables to override external functions. * 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 ``push()`` for dynamic storage arrays. It returns a reference to the newly allocated element, if applicable. * 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). +### 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) Bugfixes: diff --git a/docs/bugs.json b/docs/bugs.json index 5d94131a19c8..66f1808abd79 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -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", "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.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 0fa1e1076e71..4c9a01c64544 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -742,32 +742,46 @@ }, "0.5.10": { "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers" ], "released": "2019-06-25" }, "0.5.11": { - "bugs": [], + "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue0.5" + ], "released": "2019-08-12" }, "0.5.12": { - "bugs": [], + "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue0.5" + ], "released": "2019-10-01" }, "0.5.13": { - "bugs": [], + "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue0.5" + ], "released": "2019-11-14" }, "0.5.14": { "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2LoopYulOptimizer" ], "released": "2019-12-09" }, "0.5.15": { - "bugs": [], + "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue0.5" + ], "released": "2019-12-17" }, + "0.5.16": { + "bugs": [], + "released": "2020-01-02" + }, "0.5.2": { "bugs": [ "SignedArrayStorageCopy", @@ -840,6 +854,7 @@ }, "0.5.8": { "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -849,6 +864,7 @@ }, "0.5.9": { "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement" @@ -856,7 +872,13 @@ "released": "2019-05-28" }, "0.6.0": { - "bugs": [], + "bugs": [ + "YulOptimizerRedundantAssignmentBreakContinue" + ], "released": "2019-12-17" + }, + "0.6.1": { + "bugs": [], + "released": "2020-01-02" } } \ No newline at end of file diff --git a/docs/resources.rst b/docs/resources.rst index 4335c3deb04b..3a9e3c0c2f45 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -33,7 +33,7 @@ Solidity Integrations * `Solidity IDE `_ Browser-based IDE with integrated compiler, Ganache and local file system support. - * `Solium `_ + * `Ethlint `_ Linter to identify and fix style and security issues in Solidity. * `Superblocks Lab `_ @@ -48,7 +48,7 @@ Solidity Integrations Plugin for the Atom editor that provides Solidity linting. * `Atom Solium Linter `_ - Configurable Solidty linter for Atom using Solium as a base. + Configurable Solidity linter for Atom using Solium (now Ethlint) as a base. * Eclipse: diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 21f8a5d19194..6881e14d6f0d 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -639,7 +639,7 @@ void DeclarationRegistrationHelper::endVisit(FunctionDefinition&) bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause) { - _tryCatchClause.setScope(m_currentScope); + _tryCatchClause.annotation().scope = m_currentScope; enterNewSubScope(_tryCatchClause); return true; } @@ -675,7 +675,7 @@ void DeclarationRegistrationHelper::endVisit(FunctionTypeName&) bool DeclarationRegistrationHelper::visit(Block& _block) { - _block.setScope(m_currentScope); + _block.annotation().scope = m_currentScope; enterNewSubScope(_block); return true; } @@ -687,7 +687,7 @@ void DeclarationRegistrationHelper::endVisit(Block&) bool DeclarationRegistrationHelper::visit(ForStatement& _for) { - _for.setScope(m_currentScope); + _for.annotation().scope = m_currentScope; enterNewSubScope(_for); return true; } @@ -761,7 +761,7 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter); - _declaration.setScope(m_currentScope); + _declaration.annotation().scope = m_currentScope; if (_opensScope) enterNewSubScope(_declaration); } diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index aa97ae7bbdc5..4da77ead7733 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -43,10 +43,6 @@ class AssemblyViewPureChecker m_dialect(_dialect), m_reportMutability(_reportMutability) {} - void operator()(yul::Instruction const& _instruction) - { - checkInstruction(_instruction.location, _instruction.instruction); - } void operator()(yul::Literal const&) {} void operator()(yul::Identifier const&) {} void operator()(yul::ExpressionStatement const& _expr) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 140fe7a993e0..a7d5e73cad2f 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -449,6 +449,13 @@ string Scopable::sourceUnitName() const return sourceUnit().annotation().path; } +DeclarationAnnotation& Declaration::annotation() const +{ + if (!m_annotation) + m_annotation = make_unique(); + return dynamic_cast(*m_annotation); +} + bool VariableDeclaration::isLValue() const { // Constant declared variables are Read-Only @@ -653,6 +660,27 @@ InlineAssemblyAnnotation& InlineAssembly::annotation() const return dynamic_cast(*m_annotation); } +BlockAnnotation& Block::annotation() const +{ + if (!m_annotation) + m_annotation = make_unique(); + return dynamic_cast(*m_annotation); +} + +TryCatchClauseAnnotation& TryCatchClause::annotation() const +{ + if (!m_annotation) + m_annotation = make_unique(); + return dynamic_cast(*m_annotation); +} + +ForStatementAnnotation& ForStatement::annotation() const +{ + if (!m_annotation) + m_annotation = make_unique(); + return dynamic_cast(*m_annotation); +} + ReturnAnnotation& Return::annotation() const { if (!m_annotation) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index f761fe7afcf9..f687f20c9df5 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -159,8 +159,7 @@ class Scopable virtual ~Scopable() = default; /// @returns 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() const { return m_scope; } - void setScope(ASTNode const* _scope) { m_scope = _scope; } + ASTNode const* scope() const { return annotation().scope; } /// @returns the source unit this scopable is present in. SourceUnit const& sourceUnit() const; @@ -172,8 +171,7 @@ class Scopable /// Can be combined with annotation().canonicalName (if present) to form a globally unique name. std::string sourceUnitName() const; -protected: - ASTNode const* m_scope = nullptr; + virtual ScopableAnnotation& annotation() const = 0; }; /** @@ -231,6 +229,8 @@ class Declaration: public ASTNode, public Scopable /// @returns null when it is not accessible as a function. virtual FunctionTypePointer functionType(bool /*_internal*/) const { return {}; } + DeclarationAnnotation& annotation() const override; + protected: virtual Visibility defaultVisibility() const { return Visibility::Public; } @@ -1169,6 +1169,8 @@ class Block: public Statement, public Scopable std::vector> const& statements() const { return m_statements; } + BlockAnnotation& annotation() const override; + private: std::vector> m_statements; }; @@ -1248,6 +1250,8 @@ class TryCatchClause: public ASTNode, public Scopable ParameterList const* parameters() const { return m_parameters.get(); } Block const& block() const { return *m_block; } + TryCatchClauseAnnotation& annotation() const override; + private: ASTPointer m_errorName; ASTPointer m_parameters; @@ -1357,6 +1361,8 @@ class ForStatement: public BreakableStatement, public Scopable ExpressionStatement const* loopExpression() const { return m_loopExpression.get(); } Statement const& body() const { return *m_body; } + ForStatementAnnotation& annotation() const override; + private: /// For statement's initialization expression. for (XXX; ; ). Can be empty ASTPointer m_initExpression; diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 6d3c890927ab..0f11b1c5a924 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -75,7 +75,18 @@ struct SourceUnitAnnotation: ASTAnnotation std::set 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. std::string absolutePath; @@ -83,7 +94,7 @@ struct ImportAnnotation: ASTAnnotation SourceUnit const* sourceUnit = nullptr; }; -struct TypeDeclarationAnnotation: ASTAnnotation +struct TypeDeclarationAnnotation: DeclarationAnnotation { /// The name of this type, prefixed by proper namespaces if globally accessible. std::string canonicalName; @@ -104,7 +115,7 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnota std::map baseConstructorArguments; }; -struct CallableDeclarationAnnotation: ASTAnnotation +struct CallableDeclarationAnnotation: DeclarationAnnotation { /// The set of functions/modifiers/events this callable overrides. std::set baseFunctions; @@ -124,7 +135,7 @@ struct ModifierDefinitionAnnotation: CallableDeclarationAnnotation, DocumentedAn { }; -struct VariableDeclarationAnnotation: ASTAnnotation +struct VariableDeclarationAnnotation: DeclarationAnnotation { /// Type of variable (type of identifier referencing this variable). TypePointer type = nullptr; @@ -152,6 +163,18 @@ struct InlineAssemblyAnnotation: StatementAnnotation std::shared_ptr analysisInfo; }; +struct BlockAnnotation: StatementAnnotation, ScopableAnnotation +{ +}; + +struct TryCatchClauseAnnotation: ASTAnnotation, ScopableAnnotation +{ +}; + +struct ForStatementAnnotation: StatementAnnotation, ScopableAnnotation +{ +}; + struct ReturnAnnotation: StatementAnnotation { /// Reference to the return parameters of the function. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 9d9a0a7b30d0..73824297e909 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -51,10 +51,6 @@ #include #include -#include -#include -#include -#include #include #include @@ -81,7 +77,7 @@ CompilerStack::CompilerStack(ReadCallback::Callback const& _readFile): m_readFile{_readFile}, m_enabledSMTSolvers{smt::SMTSolverChoice::All()}, m_generateIR{false}, - m_generateEWasm{false}, + m_generateEwasm{false}, m_errorList{}, m_errorReporter{m_errorList} { @@ -204,7 +200,7 @@ void CompilerStack::reset(bool _keepSettings) m_evmVersion = langutil::EVMVersion(); m_enabledSMTSolvers = smt::SMTSolverChoice::All(); m_generateIR = false; - m_generateEWasm = false; + m_generateEwasm = false; m_revertStrings = RevertStrings::Default; m_optimiserSettings = OptimiserSettings::minimal(); m_metadataLiteralSources = false; @@ -467,10 +463,10 @@ bool CompilerStack::compile() if (isRequestedContract(*contract)) { compileContract(*contract, otherCompilers); - if (m_generateIR || m_generateEWasm) + if (m_generateIR || m_generateEwasm) generateIR(*contract); - if (m_generateEWasm) - generateEWasm(*contract); + if (m_generateEwasm) + generateEwasm(*contract); } m_stackState = CompilationSuccessful; this->link(); @@ -596,20 +592,20 @@ string const& CompilerStack::yulIROptimized(string const& _contractName) const return contract(_contractName).yulIROptimized; } -string const& CompilerStack::eWasm(string const& _contractName) const +string const& CompilerStack::ewasm(string const& _contractName) const { if (m_stackState != CompilationSuccessful) 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) 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 @@ -1073,15 +1069,15 @@ void CompilerStack::generateIR(ContractDefinition const& _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, ""); 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()); solAssert(!compiledContract.yulIROptimized.empty(), ""); - if (!compiledContract.eWasm.empty()) + if (!compiledContract.ewasm.empty()) return; // Re-parse the Yul IR in EVM dialect @@ -1089,15 +1085,15 @@ void CompilerStack::generateEWasm(ContractDefinition const& _contract) stack.parseAndAnalyze("", compiledContract.yulIROptimized); stack.optimize(); - stack.translate(yul::AssemblyStack::Language::EWasm); + stack.translate(yul::AssemblyStack::Language::Ewasm); stack.optimize(); //cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl; - // Turn into eWasm text representation. - auto result = stack.assemble(yul::AssemblyStack::Machine::eWasm); - compiledContract.eWasm = std::move(result.assembly); - compiledContract.eWasmObject = std::move(*result.bytecode); + // Turn into Ewasm text representation. + auto result = stack.assemble(yul::AssemblyStack::Machine::Ewasm); + compiledContract.ewasm = std::move(result.assembly); + compiledContract.ewasmObject = std::move(*result.bytecode); } CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 3133acfe8baf..9f4f42348c98 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -178,8 +178,8 @@ class CompilerStack: boost::noncopyable /// Enable experimental generation of Yul IR code. void enableIRGeneration(bool _enable = true) { m_generateIR = _enable; } - /// Enable experimental generation of eWasm code. If enabled, IR is also generated. - void enableEWasmGeneration(bool _enable = true) { m_generateEWasm = _enable; } + /// Enable experimental generation of Ewasm code. If enabled, IR is also generated. + void enableEwasmGeneration(bool _enable = true) { m_generateEwasm = _enable; } /// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata. /// Must be set before parsing. @@ -251,11 +251,11 @@ class CompilerStack: boost::noncopyable /// @returns the optimized IR representation of a contract. std::string const& yulIROptimized(std::string const& _contractName) const; - /// @returns the eWasm text representation of a contract. - std::string const& eWasm(std::string const& _contractName) const; + /// @returns the Ewasm text representation of a contract. + std::string const& ewasm(std::string const& _contractName) const; - /// @returns the eWasm representation of a contract. - eth::LinkerObject const& eWasmObject(std::string const& _contractName) const; + /// @returns the Ewasm representation of a contract. + eth::LinkerObject const& ewasmObject(std::string const& _contractName) const; /// @returns the assembled object for a contract. eth::LinkerObject const& object(std::string const& _contractName) const; @@ -338,8 +338,8 @@ class CompilerStack: boost::noncopyable eth::LinkerObject runtimeObject; ///< Runtime object. std::string yulIR; ///< Experimental Yul IR code. std::string yulIROptimized; ///< Optimized experimental Yul IR code. - std::string eWasm; ///< Experimental eWasm text representation - eth::LinkerObject eWasmObject; ///< Experimental eWasm code + std::string ewasm; ///< Experimental Ewasm text representation + eth::LinkerObject ewasmObject; ///< Experimental Ewasm code mutable std::unique_ptr metadata; ///< The metadata json that will be hashed into the chain. mutable std::unique_ptr abi; mutable std::unique_ptr storageLayout; @@ -374,8 +374,8 @@ class CompilerStack: boost::noncopyable /// The IR is stored but otherwise unused. void generateIR(ContractDefinition const& _contract); - /// Generate eWasm representation for a single contract. - void generateEWasm(ContractDefinition const& _contract); + /// Generate Ewasm representation for a single contract. + void generateEwasm(ContractDefinition const& _contract); /// Links all the known library addresses in the available objects. Any unknown /// library will still be kept as an unlinked placeholder in the objects. @@ -436,7 +436,7 @@ class CompilerStack: boost::noncopyable smt::SMTSolverChoice m_enabledSMTSolvers; std::map> m_requestedContractNames; bool m_generateIR; - bool m_generateEWasm; + bool m_generateEwasm; std::map m_libraries; /// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum /// "context:prefix=target" diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 25f6a5199fca..a7162348caf5 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -247,9 +247,9 @@ bool isBinaryRequested(Json::Value const& _outputSelection) 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" -bool isEWasmRequested(Json::Value const& _outputSelection) +bool isEwasmRequested(Json::Value const& _outputSelection) { if (!_outputSelection.isObject()) return false; @@ -267,7 +267,7 @@ bool isEWasmRequested(Json::Value const& _outputSelection) /// yet match "ir" or "irOptimized" bool isIRRequested(Json::Value const& _outputSelection) { - if (isEWasmRequested(_outputSelection)) + if (isEwasmRequested(_outputSelection)) return true; if (!_outputSelection.isObject()) @@ -780,7 +780,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting compilerStack.enableIRGeneration(isIRRequested(_inputsAndSettings.outputSelection)); - compilerStack.enableEWasmGeneration(isEWasmRequested(_inputsAndSettings.outputSelection)); + compilerStack.enableEwasmGeneration(isEwasmRequested(_inputsAndSettings.outputSelection)); 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)) contractData["irOptimized"] = compilerStack.yulIROptimized(contractName); - // eWasm + // Ewasm 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)) - contractData["ewasm"]["wasm"] = compilerStack.eWasmObject(contractName).toHex(); + contractData["ewasm"]["wasm"] = compilerStack.ewasmObject(contractName).toHex(); // EVM Json::Value evmData(Json::objectValue); diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 64b1ad4c5e70..e03ef7cb0348 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -86,16 +86,6 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, 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) { expectValidType(_literal.type.str(), _literal.location); diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h index 2ee77f71b4b6..b16e2bfed9ac 100644 --- a/libyul/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -77,7 +77,6 @@ class AsmAnalyzer /// Asserts on failure. static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object); - bool operator()(Instruction const&); bool operator()(Literal const& _literal); bool operator()(Identifier const&); bool operator()(ExpressionStatement const&); diff --git a/libyul/AsmData.h b/libyul/AsmData.h index c80fa7cfa360..5c7a058b5bdd 100644 --- a/libyul/AsmData.h +++ b/libyul/AsmData.h @@ -25,12 +25,8 @@ #include #include -#include #include -#include - -#include #include namespace yul @@ -41,8 +37,6 @@ using Type = YulString; struct TypedName { langutil::SourceLocation location; YulString name; Type type; }; using TypedNameList = std::vector; -/// Direct EVM instruction (except PUSHi and JUMPDEST) -struct Instruction { langutil::SourceLocation location; dev::eth::Instruction instruction; }; /// Literal number or string (up to 32 bytes) enum class LiteralKind { Number, Boolean, String }; struct Literal { langutil::SourceLocation location; LiteralKind kind; YulString value; Type type; }; diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index 5438494cdd3c..0967828f3362 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -29,6 +29,8 @@ #include #include +#include + #include #include #include @@ -56,7 +58,7 @@ class Parser: public langutil::ParserBase static std::map const& instructions(); protected: - using ElementaryOperation = std::variant; + using ElementaryOperation = std::variant; /// Creates an inline assembly node with the given source location. template T createWithLocation(langutil::SourceLocation const& _loc = {}) const diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 6dc84ac81464..4b6d71692e24 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -16,7 +16,7 @@ */ /** * 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 #include #include -#include -#include +#include +#include #include #include #include @@ -59,7 +59,7 @@ Dialect const& languageToDialect(AssemblyStack::Language _language, EVMVersion _ return EVMDialect::strictAssemblyForEVMObjects(_version); case AssemblyStack::Language::Yul: return Dialect::yul(); - case AssemblyStack::Language::EWasm: + case AssemblyStack::Language::Ewasm: return WasmDialect::instance(); } yulAssert(false, ""); @@ -108,11 +108,11 @@ void AssemblyStack::translate(AssemblyStack::Language _targetLanguage) return; solAssert( - m_language == Language::StrictAssembly && _targetLanguage == Language::EWasm, + m_language == Language::StrictAssembly && _targetLanguage == Language::Ewasm, "Invalid language combination" ); - *m_parserResult = EVMToEWasmTranslator( + *m_parserResult = EVMToEwasmTranslator( languageToDialect(m_language, m_evmVersion) ).run(*parserResult()); @@ -214,13 +214,13 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const /// TODO: fill out text representation 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{}); MachineAssemblyObject object; - auto result = EWasmObjectCompiler::compile(*m_parserResult, dialect); + auto result = WasmObjectCompiler::compile(*m_parserResult, dialect); object.assembly = std::move(result.first); object.bytecode = make_shared(); object.bytecode->bytecode = std::move(result.second); diff --git a/libyul/AssemblyStack.h b/libyul/AssemblyStack.h index a6dcd0b37236..6c3549331a6e 100644 --- a/libyul/AssemblyStack.h +++ b/libyul/AssemblyStack.h @@ -16,7 +16,7 @@ */ /** * 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 @@ -52,13 +52,13 @@ struct MachineAssemblyObject /* * 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 { public: - enum class Language { Yul, Assembly, StrictAssembly, EWasm }; - enum class Machine { EVM, EVM15, eWasm }; + enum class Language { Yul, Assembly, StrictAssembly, Ewasm }; + enum class Machine { EVM, EVM15, Ewasm }; AssemblyStack(): AssemblyStack(langutil::EVMVersion{}, Language::Assembly, dev::solidity::OptimiserSettings::none()) diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 2a0577edcc1a..23aca8bb2d58 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -44,18 +44,18 @@ add_library(yul backends/evm/EVMMetrics.h backends/evm/NoOutputAssembly.h backends/evm/NoOutputAssembly.cpp - backends/wasm/EVMToEWasmTranslator.cpp - backends/wasm/EVMToEWasmTranslator.h - backends/wasm/EWasmCodeTransform.cpp - backends/wasm/EWasmCodeTransform.h - backends/wasm/EWasmObjectCompiler.cpp - backends/wasm/EWasmObjectCompiler.h + backends/wasm/EVMToEwasmTranslator.cpp + backends/wasm/EVMToEwasmTranslator.h backends/wasm/BinaryTransform.cpp backends/wasm/BinaryTransform.h backends/wasm/TextTransform.cpp backends/wasm/TextTransform.h + backends/wasm/WasmCodeTransform.cpp + backends/wasm/WasmCodeTransform.h backends/wasm/WasmDialect.cpp backends/wasm/WasmDialect.h + backends/wasm/WasmObjectCompiler.cpp + backends/wasm/WasmObjectCompiler.h backends/wasm/WordSizeTransform.cpp backends/wasm/WordSizeTransform.h optimiser/ASTCopier.cpp diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 0d9a558df313..ad4a757e2f7d 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -43,7 +43,6 @@ enum class Instruction: uint8_t; namespace yul { -struct Instruction; struct Identifier; /// diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 51b31aae5c0e..ba2561e0bf6b 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -350,16 +350,6 @@ void CodeTransform::operator()(Literal const& _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) { visitExpression(*_if.condition); diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index 6cf6bb3076fb..d0615faf111b 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -170,7 +170,6 @@ class CodeTransform void deleteVariable(Scope::Variable const& _var); public: - void operator()(Instruction const& _instruction); void operator()(Literal const& _literal); void operator()(Identifier const& _identifier); void operator()(FunctionCall const&); diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index b87ab0c1916f..1dee4daeef6b 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ /** - * EWasm to binary encoder. + * Component that transforms internal Wasm representation to binary. */ #include diff --git a/libyul/backends/wasm/BinaryTransform.h b/libyul/backends/wasm/BinaryTransform.h index b57943af197c..132f38ca24f0 100644 --- a/libyul/backends/wasm/BinaryTransform.h +++ b/libyul/backends/wasm/BinaryTransform.h @@ -15,7 +15,7 @@ along with solidity. If not, see . */ /** - * EWasm to binary encoder. + * Component that transforms internal Wasm representation to binary. */ #pragma once diff --git a/libyul/backends/wasm/EVMToEWasmTranslator.cpp b/libyul/backends/wasm/EVMToEwasmTranslator.cpp similarity index 97% rename from libyul/backends/wasm/EVMToEWasmTranslator.cpp rename to libyul/backends/wasm/EVMToEwasmTranslator.cpp index 54e80fdcd10a..20a608708334 100644 --- a/libyul/backends/wasm/EVMToEWasmTranslator.cpp +++ b/libyul/backends/wasm/EVMToEwasmTranslator.cpp @@ -15,10 +15,10 @@ along with solidity. If not, see . */ /** - * Translates Yul code from EVM dialect to eWasm dialect. + * Translates Yul code from EVM dialect to Ewasm dialect. */ -#include +#include #include #include @@ -138,6 +138,10 @@ function div(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 { // TODO implement properly 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 { // TODO implement properly 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 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 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 unreachable() } @@ -397,8 +401,7 @@ function calldatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) { // Needed? function codesize() -> z1, z2, z3, z4 { - eth.getCodeSize(0) - z1, z2, z3, z4 := mload_internal(0) + z4 := eth.getCodeSize() } function codecopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) { eth.codeCopy( @@ -698,7 +701,7 @@ function invalid() { } -Object EVMToEWasmTranslator::run(Object const& _object) +Object EVMToEwasmTranslator::run(Object const& _object) { if (!m_polyfill) parsePolyfill(); @@ -746,7 +749,7 @@ Object EVMToEWasmTranslator::run(Object const& _object) return ret; } -void EVMToEWasmTranslator::parsePolyfill() +void EVMToEwasmTranslator::parsePolyfill() { ErrorList errors; ErrorReporter errorReporter(errors); diff --git a/libyul/backends/wasm/EVMToEWasmTranslator.h b/libyul/backends/wasm/EVMToEwasmTranslator.h similarity index 85% rename from libyul/backends/wasm/EVMToEWasmTranslator.h rename to libyul/backends/wasm/EVMToEwasmTranslator.h index daefa2cce7b0..73563fc053c4 100644 --- a/libyul/backends/wasm/EVMToEWasmTranslator.h +++ b/libyul/backends/wasm/EVMToEwasmTranslator.h @@ -15,7 +15,7 @@ along with solidity. If not, see . */ /** - * Translates Yul code from EVM dialect to eWasm dialect. + * Translates Yul code from EVM dialect to Ewasm dialect. */ #pragma once @@ -28,10 +28,10 @@ namespace yul { struct Object; -class EVMToEWasmTranslator: public ASTModifier +class EVMToEwasmTranslator: public ASTModifier { public: - EVMToEWasmTranslator(Dialect const& _evmDialect): m_dialect(_evmDialect) {} + EVMToEwasmTranslator(Dialect const& _evmDialect): m_dialect(_evmDialect) {} Object run(Object const& _object); private: diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index f3589f5e904c..49e617e55d3f 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ /** - * Component that transforms interval Wasm representation to text. + * Component that transforms internal Wasm representation to text. */ #include diff --git a/libyul/backends/wasm/TextTransform.h b/libyul/backends/wasm/TextTransform.h index 602a67fe147f..2424939a8cbb 100644 --- a/libyul/backends/wasm/TextTransform.h +++ b/libyul/backends/wasm/TextTransform.h @@ -15,7 +15,7 @@ along with solidity. If not, see . */ /** - * Component that transforms interval Wasm representation to text. + * Component that transforms internal Wasm representation to text. */ #pragma once diff --git a/libyul/backends/wasm/EWasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp similarity index 83% rename from libyul/backends/wasm/EWasmCodeTransform.cpp rename to libyul/backends/wasm/WasmCodeTransform.cpp index 88fc86bf4b37..51f80af17cec 100644 --- a/libyul/backends/wasm/EWasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -15,10 +15,10 @@ along with solidity. If not, see . */ /** -* Common code generator for translating Yul / inline assembly to EWasm. +* Common code generator for translating Yul / inline assembly to Wasm. */ -#include +#include #include @@ -36,11 +36,11 @@ using namespace std; using namespace dev; 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; - EWasmCodeTransform transform(_dialect, _ast); + WasmCodeTransform transform(_dialect, _ast); for (auto const& statement: _ast.statements) { @@ -59,7 +59,7 @@ wasm::Module EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const& return module; } -wasm::Expression EWasmCodeTransform::generateMultiAssignment( +wasm::Expression WasmCodeTransform::generateMultiAssignment( vector _variableNames, unique_ptr _firstValue ) @@ -82,7 +82,7 @@ wasm::Expression EWasmCodeTransform::generateMultiAssignment( return { std::move(block) }; } -wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varDecl) +wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDecl) { vector variableNames; for (auto const& var: _varDecl.variables) @@ -97,7 +97,7 @@ wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varD return wasm::BuiltinCall{"nop", {}}; } -wasm::Expression EWasmCodeTransform::operator()(Assignment const& _assignment) +wasm::Expression WasmCodeTransform::operator()(Assignment const& _assignment) { vector 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)); } -wasm::Expression EWasmCodeTransform::operator()(ExpressionStatement const& _statement) +wasm::Expression WasmCodeTransform::operator()(ExpressionStatement const& _statement) { return visitReturnByValue(_statement.expression); } -wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call) +wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call) { bool typeConversionNeeded = false; @@ -171,19 +171,19 @@ wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call) return {std::move(funCall)}; } -wasm::Expression EWasmCodeTransform::operator()(Identifier const& _identifier) +wasm::Expression WasmCodeTransform::operator()(Identifier const& _identifier) { return wasm::LocalVariable{_identifier.name.str()}; } -wasm::Expression EWasmCodeTransform::operator()(Literal const& _literal) +wasm::Expression WasmCodeTransform::operator()(Literal const& _literal) { u256 value = valueOfLiteral(_literal); yulAssert(value <= numeric_limits::max(), "Literal too large: " + value.str()); 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. @@ -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; string condition = m_nameDispenser.newName("condition"_yulstring).str(); @@ -237,13 +237,13 @@ wasm::Expression EWasmCodeTransform::operator()(Switch const& _switch) return { std::move(block) }; } -wasm::Expression EWasmCodeTransform::operator()(FunctionDefinition const&) +wasm::Expression WasmCodeTransform::operator()(FunctionDefinition const&) { yulAssert(false, "Should not have visited here."); return {}; } -wasm::Expression EWasmCodeTransform::operator()(ForLoop const& _for) +wasm::Expression WasmCodeTransform::operator()(ForLoop const& _for) { string breakLabel = newLabel(); string continueLabel = newLabel(); @@ -262,37 +262,37 @@ wasm::Expression EWasmCodeTransform::operator()(ForLoop const& _for) return { wasm::Block{breakLabel, make_vector(move(loop))} }; } -wasm::Expression EWasmCodeTransform::operator()(Break const&) +wasm::Expression WasmCodeTransform::operator()(Break const&) { 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}}; } -wasm::Expression EWasmCodeTransform::operator()(Leave const&) +wasm::Expression WasmCodeTransform::operator()(Leave const&) { return wasm::Return{}; } -wasm::Expression EWasmCodeTransform::operator()(Block const& _block) +wasm::Expression WasmCodeTransform::operator()(Block const& _block) { return wasm::Block{{}, visit(_block.statements)}; } -unique_ptr EWasmCodeTransform::visit(yul::Expression const& _expression) +unique_ptr WasmCodeTransform::visit(yul::Expression const& _expression) { return make_unique(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); } -vector EWasmCodeTransform::visit(vector const& _expressions) +vector WasmCodeTransform::visit(vector const& _expressions) { vector ret; for (auto const& e: _expressions) @@ -300,12 +300,12 @@ vector EWasmCodeTransform::visit(vector const return ret; } -wasm::Expression EWasmCodeTransform::visit(yul::Statement const& _statement) +wasm::Expression WasmCodeTransform::visit(yul::Statement const& _statement) { return std::visit(*this, _statement); } -vector EWasmCodeTransform::visit(vector const& _statements) +vector WasmCodeTransform::visit(vector const& _statements) { vector ret; for (auto const& s: _statements) @@ -313,7 +313,7 @@ vector EWasmCodeTransform::visit(vector const& return ret; } -wasm::FunctionDefinition EWasmCodeTransform::translateFunction(yul::FunctionDefinition const& _fun) +wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefinition const& _fun) { wasm::FunctionDefinition fun; fun.name = _fun.name.str(); @@ -344,7 +344,7 @@ wasm::FunctionDefinition EWasmCodeTransform::translateFunction(yul::FunctionDefi 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}); for (size_t i = 0; i < _call.arguments.size(); ++i) @@ -361,7 +361,7 @@ wasm::Expression EWasmCodeTransform::injectTypeConversionIfNeeded(wasm::Function return {std::move(_call)}; } -vector EWasmCodeTransform::injectTypeConversionIfNeeded( +vector WasmCodeTransform::injectTypeConversionIfNeeded( vector _arguments, vector const& _parameterTypes ) const @@ -378,12 +378,12 @@ vector EWasmCodeTransform::injectTypeConversionIfNeeded( return _arguments; } -string EWasmCodeTransform::newLabel() +string WasmCodeTransform::newLabel() { return m_nameDispenser.newName("label_"_yulstring).str(); } -void EWasmCodeTransform::allocateGlobals(size_t _amount) +void WasmCodeTransform::allocateGlobals(size_t _amount) { while (m_globalVariables.size() < _amount) m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{ diff --git a/libyul/backends/wasm/EWasmCodeTransform.h b/libyul/backends/wasm/WasmCodeTransform.h similarity index 98% rename from libyul/backends/wasm/EWasmCodeTransform.h rename to libyul/backends/wasm/WasmCodeTransform.h index 35700553c63a..1a606d5ab900 100644 --- a/libyul/backends/wasm/EWasmCodeTransform.h +++ b/libyul/backends/wasm/WasmCodeTransform.h @@ -15,7 +15,7 @@ along with solidity. If not, see . */ /** - * Common code generator for translating Yul / inline assembly to EWasm. + * Common code generator for translating Yul / inline assembly to Wasm. */ #pragma once @@ -32,7 +32,7 @@ namespace yul { struct AsmAnalysisInfo; -class EWasmCodeTransform +class WasmCodeTransform { public: static wasm::Module run(Dialect const& _dialect, yul::Block const& _ast); @@ -54,7 +54,7 @@ class EWasmCodeTransform wasm::Expression operator()(yul::Block const& _block); private: - EWasmCodeTransform( + WasmCodeTransform( Dialect const& _dialect, Block const& _ast ): diff --git a/libyul/backends/wasm/WasmDialect.cpp b/libyul/backends/wasm/WasmDialect.cpp index 69ba02413db6..8e0cba8f9c0a 100644 --- a/libyul/backends/wasm/WasmDialect.cpp +++ b/libyul/backends/wasm/WasmDialect.cpp @@ -56,10 +56,16 @@ WasmDialect::WasmDialect(): addFunction("i64.eqz", 1, 1); m_functions["i64.eqz"_yulstring].returns.front() = "i32"_yulstring; + addFunction("i64.clz", 1, 1); + addFunction("i64.store", 2, 0, false); m_functions["i64.store"_yulstring].parameters.front() = "i32"_yulstring; 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); m_functions["i64.load"_yulstring].parameters.front() = "i32"_yulstring; m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false; @@ -120,7 +126,7 @@ void WasmDialect::addEthereumExternals() {"getCaller", {i32ptr}, {}}, {"getCallValue", {i32ptr}, {}}, {"codeCopy", {i32ptr, i32, i32}, {}}, - {"getCodeSize", {i32ptr}, {}}, + {"getCodeSize", {}, {i32}}, {"getBlockCoinbase", {i32ptr}, {}}, {"create", {i32ptr, i32ptr, i32, i32ptr}, {i32}}, {"getBlockDifficulty", {i32ptr}, {}}, diff --git a/libyul/backends/wasm/EWasmObjectCompiler.cpp b/libyul/backends/wasm/WasmObjectCompiler.cpp similarity index 76% rename from libyul/backends/wasm/EWasmObjectCompiler.cpp rename to libyul/backends/wasm/WasmObjectCompiler.cpp index 9f0e30f47839..b65318ae3b88 100644 --- a/libyul/backends/wasm/EWasmObjectCompiler.cpp +++ b/libyul/backends/wasm/WasmObjectCompiler.cpp @@ -18,9 +18,9 @@ * Compiler that transforms Yul Objects to Wasm text and binary representation (Ewasm flavoured). */ -#include +#include -#include +#include #include #include @@ -32,25 +32,25 @@ using namespace yul; using namespace std; -pair EWasmObjectCompiler::compile(Object& _object, Dialect const& _dialect) +pair WasmObjectCompiler::compile(Object& _object, Dialect const& _dialect) { - EWasmObjectCompiler compiler(_dialect); + WasmObjectCompiler compiler(_dialect); wasm::Module module = compiler.run(_object); 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.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) if (Object* subObject = dynamic_cast(subNode.get())) module.subModules[subObject->name.str()] = run(*subObject); else - yulAssert(false, "Data is not yet supported for EWasm."); + yulAssert(false, "Data is not yet supported for Wasm."); return module; } diff --git a/libyul/backends/wasm/EWasmObjectCompiler.h b/libyul/backends/wasm/WasmObjectCompiler.h similarity index 88% rename from libyul/backends/wasm/EWasmObjectCompiler.h rename to libyul/backends/wasm/WasmObjectCompiler.h index a4fcf1af89c5..2805f0b06094 100644 --- a/libyul/backends/wasm/EWasmObjectCompiler.h +++ b/libyul/backends/wasm/WasmObjectCompiler.h @@ -28,6 +28,7 @@ namespace dev { using bytes = std::vector; } + namespace yul { struct Object; @@ -37,13 +38,13 @@ namespace wasm struct Module; } -class EWasmObjectCompiler +class WasmObjectCompiler { 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 compile(Object& _object, Dialect const& _dialect); private: - EWasmObjectCompiler(Dialect const& _dialect): + WasmObjectCompiler(Dialect const& _dialect): m_dialect(_dialect) {} diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp index aca44d0b3ef8..38c7881a009f 100644 --- a/libyul/optimiser/RedundantAssignEliminator.cpp +++ b/libyul/optimiser/RedundantAssignEliminator.cpp @@ -280,29 +280,28 @@ void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, Redundant void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEliminator::State _finalState) { - finalize(m_assignments, _variable, _finalState); - for (auto& assignments: m_forLoopInfo.pendingBreakStmts) - finalize(assignments, _variable, _finalState); - for (auto& assignments: m_forLoopInfo.pendingContinueStmts) - finalize(assignments, _variable, _finalState); -} + std::map assignments; + joinMap(assignments, std::move(m_assignments[_variable]), State::join); + m_assignments.erase(_variable); -void RedundantAssignEliminator::finalize( - TrackedAssignments& _assignments, - YulString _variable, - RedundantAssignEliminator::State _finalState -) -{ - for (auto const& assignment: _assignments[_variable]) + for (auto& breakAssignments: m_forLoopInfo.pendingBreakStmts) + { + joinMap(assignments, std::move(breakAssignments[_variable]), State::join); + breakAssignments.erase(_variable); + } + for (auto& continueAssignments: m_forLoopInfo.pendingContinueStmts) + { + 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; 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); } - _assignments.erase(_variable); } void AssignmentRemover::operator()(Block& _block) diff --git a/libyul/optimiser/RedundantAssignEliminator.h b/libyul/optimiser/RedundantAssignEliminator.h index fec6a271448d..7849708d6351 100644 --- a/libyul/optimiser/RedundantAssignEliminator.h +++ b/libyul/optimiser/RedundantAssignEliminator.h @@ -161,8 +161,6 @@ class RedundantAssignEliminator: public ASTWalker /// assignments to the final state. In this case, this also applies to pending /// break and continue TrackedAssignments. void finalize(YulString _variable, State _finalState); - /// Helper function for the above. - void finalize(TrackedAssignments& _assignments, YulString _variable, State _finalState); Dialect const* m_dialect; std::set m_declaredVariables; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 6834e62ff188..ab6ef0840397 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -116,7 +116,7 @@ static string const g_strErrorRecovery = "error-recovery"; static string const g_strEVM = "evm"; static string const g_strEVM15 = "evm15"; 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_strHelp = "help"; 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_strIR = "ir"; static string const g_strIPFS = "ipfs"; -static string const g_strEWasm = "ewasm"; static string const g_strLicense = "license"; static string const g_strLibraries = "libraries"; 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_argYul = g_strYul; 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_argLink = g_strLink; static string const g_argMachine = g_strMachine; @@ -234,14 +233,14 @@ static set const g_machineArgs { g_strEVM, g_strEVM15, - g_streWasm + g_strEwasm }; /// Possible arguments to for --yul-dialect static set const g_yulDialectArgs { g_strEVM, - g_streWasm + g_strEwasm }; /// 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)) { - createFile(m_compiler->filesystemFriendlyName(_contractName) + ".wast", m_compiler->eWasm(_contractName)); + createFile(m_compiler->filesystemFriendlyName(_contractName) + ".wast", m_compiler->ewasm(_contractName)); createFile( m_compiler->filesystemFriendlyName(_contractName) + ".wasm", - asString(m_compiler->eWasmObject(_contractName).bytecode) + asString(m_compiler->ewasmObject(_contractName).bytecode) ); } else { - sout() << "EWasm text:" << endl; - sout() << m_compiler->eWasm(_contractName) << endl; - sout() << "EWasm binary (hex): " << m_compiler->eWasmObject(_contractName).toHex() << endl; + sout() << "Ewasm text:" << endl; + sout() << m_compiler->ewasm(_contractName) << 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_argAbi.c_str(), "ABI specification of the contracts.") (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_argNatspecUser.c_str(), "Natspec user documentation of all contracts.") (g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.") @@ -981,27 +980,27 @@ bool CommandLineInterface::processInput() targetMachine = Machine::EVM; else if (machine == g_strEVM15) targetMachine = Machine::EVM15; - else if (machine == g_streWasm) - targetMachine = Machine::eWasm; + else if (machine == g_strEwasm) + targetMachine = Machine::Ewasm; else { serr() << "Invalid option for --machine: " << machine << endl; return false; } } - if (targetMachine == Machine::eWasm && inputLanguage == Input::StrictAssembly) - inputLanguage = Input::EWasm; + if (targetMachine == Machine::Ewasm && inputLanguage == Input::StrictAssembly) + inputLanguage = Input::Ewasm; if (m_args.count(g_strYulDialect)) { string dialect = m_args[g_strYulDialect].as(); if (dialect == g_strEVM) inputLanguage = Input::StrictAssembly; - else if (dialect == g_streWasm) + else if (dialect == g_strEwasm) { - inputLanguage = Input::EWasm; - if (targetMachine != Machine::eWasm) + inputLanguage = Input::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; } } @@ -1011,7 +1010,7 @@ bool CommandLineInterface::processInput() return false; } } - if (optimize && (inputLanguage != Input::StrictAssembly && inputLanguage != Input::EWasm)) + if (optimize && (inputLanguage != Input::StrictAssembly && inputLanguage != Input::Ewasm)) { serr() << "Optimizer can only be used for strict assembly. Use --" << @@ -1074,7 +1073,7 @@ bool CommandLineInterface::processInput() // TODO: Perhaps we should not compile unless requested 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(); settings.expectedExecutionsPerDeployment = m_args[g_argOptimizeRuns].as(); @@ -1453,7 +1452,7 @@ bool CommandLineInterface::assemble( string machine = _targetMachine == yul::AssemblyStack::Machine::EVM ? "EVM" : _targetMachine == yul::AssemblyStack::Machine::EVM15 ? "EVM 1.5" : - "eWasm"; + "Ewasm"; sout() << endl << "======= " << src.first << " (" << machine << ") =======" << endl; yul::AssemblyStack& stack = assemblyStacks[src.first]; @@ -1461,9 +1460,9 @@ bool CommandLineInterface::assemble( sout() << endl << "Pretty printed source:" << 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(); sout() << endl << "==========================" << endl; @@ -1554,7 +1553,7 @@ void CommandLineInterface::outputCompilationResults() handleBytecode(contract); handleIR(contract); - handleEWasm(contract); + handleEwasm(contract); handleSignatureHashes(contract); handleMetadata(contract); handleABI(contract); diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index cca76c53f7e7..02fda03831db 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -67,7 +67,7 @@ class CommandLineInterface void handleBinary(std::string const& _contract); void handleOpcode(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 handleSignatureHashes(std::string const& _contract); void handleMetadata(std::string const& _contract); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8424e957b391..609f9f047d4e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -131,8 +131,8 @@ set(libyul_sources libyul/Common.cpp libyul/Common.h libyul/CompilabilityChecker.cpp - libyul/EWasmTranslationTest.cpp - libyul/EWasmTranslationTest.h + libyul/EwasmTranslationTest.cpp + libyul/EwasmTranslationTest.h libyul/FunctionSideEffects.cpp libyul/FunctionSideEffects.h libyul/Inliner.cpp diff --git a/test/InteractiveTests.h b/test/InteractiveTests.h index e1cb6c08fd5e..4a4c4df7cf51 100644 --- a/test/InteractiveTests.h +++ b/test/InteractiveTests.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -56,7 +56,7 @@ struct Testsuite Testsuite const g_interactiveTestsuites[] = { /* 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 Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create}, {"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create}, diff --git a/test/cmdlineTests/evm_to_wasm/output b/test/cmdlineTests/evm_to_wasm/output index 3b1e0fab7434..a85239b230df 100644 --- a/test/cmdlineTests/evm_to_wasm/output +++ b/test/cmdlineTests/evm_to_wasm/output @@ -1,5 +1,5 @@ -======= evm_to_wasm/input.sol (eWasm) ======= +======= evm_to_wasm/input.sol (Ewasm) ======= Pretty printed source: object "object" { diff --git a/test/libsolidity/GasCosts.cpp b/test/libsolidity/GasCosts.cpp index 6b6adf2e3cc9..de90c9076bf8 100644 --- a/test/libsolidity/GasCosts.cpp +++ b/test/libsolidity/GasCosts.cpp @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(string_storage) auto evmVersion = dev::test::Options::get().evmVersion(); if (evmVersion <= EVMVersion::byzantium()) - CHECK_DEPLOY_GAS(134145, 130831, evmVersion); + CHECK_DEPLOY_GAS(134209, 130895, evmVersion); // This is only correct on >=Constantinople. 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. if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(0, 123969, evmVersion); + CHECK_DEPLOY_GAS(0, 124033, evmVersion); else - CHECK_DEPLOY_GAS(0, 110969, evmVersion); + CHECK_DEPLOY_GAS(0, 110981, evmVersion); } else { if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(147771, 131687, evmVersion); + CHECK_DEPLOY_GAS(147835, 131687, evmVersion); else - CHECK_DEPLOY_GAS(131859, 117231, evmVersion); + CHECK_DEPLOY_GAS(131871, 117231, evmVersion); } } else if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(126929, 119659, evmVersion); + CHECK_DEPLOY_GAS(126993, 119723, evmVersion); else - CHECK_DEPLOY_GAS(114345, 107335, evmVersion); + CHECK_DEPLOY_GAS(114357, 107347, evmVersion); if (evmVersion >= EVMVersion::byzantium()) { diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 72772f048620..c1ed1d67e95b 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -14319,8 +14319,6 @@ BOOST_AUTO_TEST_CASE(event_wrong_abi_name) )"; compileAndRun(sourceCode, 0, "ClientReceipt", bytes()); compileAndRun(sourceCode, 0, "Test", bytes(), map{{"ClientReceipt", m_contractAddress}}); - u256 value(18); - u256 id(0x1234); callContractFunction("f()"); BOOST_REQUIRE_EQUAL(numLogs(), 1); diff --git a/test/libyul/EWasmTranslationTest.cpp b/test/libyul/EwasmTranslationTest.cpp similarity index 85% rename from test/libyul/EWasmTranslationTest.cpp rename to test/libyul/EwasmTranslationTest.cpp index dc174ff7be74..b0583537e4c7 100644 --- a/test/libyul/EWasmTranslationTest.cpp +++ b/test/libyul/EwasmTranslationTest.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -47,7 +47,7 @@ using namespace dev::solidity::test; using namespace std; -EWasmTranslationTest::EWasmTranslationTest(string const& _filename) +EwasmTranslationTest::EwasmTranslationTest(string const& _filename) { boost::filesystem::path path(_filename); @@ -60,12 +60,12 @@ EWasmTranslationTest::EWasmTranslationTest(string const& _filename) 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)) return TestResult::FatalError; - *m_object = EVMToEWasmTranslator( + *m_object = EVMToEwasmTranslator( EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion()) ).run(*m_object); @@ -89,17 +89,17 @@ TestCase::TestResult EWasmTranslationTest::run(ostream& _stream, string const& _ 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); } -void EWasmTranslationTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const +void EwasmTranslationTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const { 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); string line; @@ -107,7 +107,7 @@ void EWasmTranslationTest::printIndented(ostream& _stream, string const& _output _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( 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; state.maxTraceSize = 10000; - state.maxSteps = 10000; + state.maxSteps = 100000; WasmDialect dialect; Interpreter interpreter(state, dialect); try @@ -147,7 +147,7 @@ string EWasmTranslationTest::interpret() return result.str(); } -void EWasmTranslationTest::printErrors(ostream& _stream, ErrorList const& _errors) +void EwasmTranslationTest::printErrors(ostream& _stream, ErrorList const& _errors) { SourceReferenceFormatter formatter(_stream); diff --git a/test/libyul/EWasmTranslationTest.h b/test/libyul/EwasmTranslationTest.h similarity index 90% rename from test/libyul/EWasmTranslationTest.h rename to test/libyul/EwasmTranslationTest.h index c63c305f9966..23c00262558c 100644 --- a/test/libyul/EWasmTranslationTest.h +++ b/test/libyul/EwasmTranslationTest.h @@ -32,15 +32,15 @@ namespace yul namespace test { -class EWasmTranslationTest: public dev::solidity::test::EVMVersionRestrictedTestCase +class EwasmTranslationTest: public dev::solidity::test::EVMVersionRestrictedTestCase { public: static std::unique_ptr create(Config const& _config) { - return std::make_unique(_config.filename); + return std::make_unique(_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; diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 221f3414d48e..8b0561378014 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -98,12 +99,24 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename) file.exceptions(ios::badbit); m_source = parseSourceAndSettings(file); - if (m_settings.count("yul")) + if (m_settings.count("dialect")) { - m_yul = true; - m_validatedSettings["yul"] = "true"; - m_settings.erase("yul"); + auto dialectName = m_settings["dialect"]; + if (dialectName == "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")) { m_validatedSettings["step"] = m_settings["step"]; @@ -350,7 +363,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line 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"]) { @@ -406,7 +419,7 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c { AssemblyStack stack( 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() ); 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()); return false; } - m_dialect = m_yul ? &Dialect::yul() : &EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion()); m_ast = stack.parserResult()->code; m_analysisInfo = stack.parserResult()->analysisInfo; return true; diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index a9cc04ab1965..d74e3fc166ce 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -71,7 +71,6 @@ class YulOptimizerTest: public dev::solidity::test::EVMVersionRestrictedTestCase static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors); std::string m_source; - bool m_yul = false; std::string m_optimizerStep; std::string m_expectation; diff --git a/test/libyul/ewasmTranslationTests/arithmetic_add.yul b/test/libyul/ewasmTranslationTests/arithmetic_add.yul new file mode 100644 index 000000000000..b2203070fcf4 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_add.yul @@ -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 diff --git a/test/libyul/ewasmTranslationTests/arithmetic_addmod.yul b/test/libyul/ewasmTranslationTests/arithmetic_addmod.yul new file mode 100644 index 000000000000..c1d43a731048 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_addmod.yul @@ -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: diff --git a/test/libyul/ewasmTranslationTests/arithmetic_div.yul b/test/libyul/ewasmTranslationTests/arithmetic_div.yul new file mode 100644 index 000000000000..3d97f464cc38 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_div.yul @@ -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: diff --git a/test/libyul/ewasmTranslationTests/arithmetic_exp.yul b/test/libyul/ewasmTranslationTests/arithmetic_exp.yul new file mode 100644 index 000000000000..328ac9c3be41 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_exp.yul @@ -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: diff --git a/test/libyul/ewasmTranslationTests/arithmetic_mod.yul b/test/libyul/ewasmTranslationTests/arithmetic_mod.yul new file mode 100644 index 000000000000..4aa5c6997b45 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_mod.yul @@ -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 diff --git a/test/libyul/ewasmTranslationTests/arithmetic_mul.yul b/test/libyul/ewasmTranslationTests/arithmetic_mul.yul new file mode 100644 index 000000000000..73e1bf3d86ba --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_mul.yul @@ -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 diff --git a/test/libyul/ewasmTranslationTests/arithmetic_mulmod.yul b/test/libyul/ewasmTranslationTests/arithmetic_mulmod.yul new file mode 100644 index 000000000000..094723ae02c7 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_mulmod.yul @@ -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: diff --git a/test/libyul/ewasmTranslationTests/arithmetic_sdiv.yul b/test/libyul/ewasmTranslationTests/arithmetic_sdiv.yul new file mode 100644 index 000000000000..fd4364185328 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_sdiv.yul @@ -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: diff --git a/test/libyul/ewasmTranslationTests/arithmetic_smod.yul b/test/libyul/ewasmTranslationTests/arithmetic_smod.yul new file mode 100644 index 000000000000..97983a463c42 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_smod.yul @@ -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 diff --git a/test/libyul/ewasmTranslationTests/arithmetic_sub.yul b/test/libyul/ewasmTranslationTests/arithmetic_sub.yul new file mode 100644 index 000000000000..fefb5d682439 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/arithmetic_sub.yul @@ -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 diff --git a/test/libyul/ewasmTranslationTests/shifts.yul b/test/libyul/ewasmTranslationTests/shifts.yul index f49092a30007..c3e9b6036a44 100644 --- a/test/libyul/ewasmTranslationTests/shifts.yul +++ b/test/libyul/ewasmTranslationTests/shifts.yul @@ -4,11 +4,16 @@ let z := shr(136, y) sstore(0, y) 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 // ---- // Trace: +// INVALID() // Memory dump: // 0: 0000000000000000000000000000000000000000000000000000000000000001 // 20: 0000000000000000000000000000000000101112131415161718191a1b1c1d1e diff --git a/test/libyul/ewasmTranslationTests/signextend.yul b/test/libyul/ewasmTranslationTests/signextend.yul new file mode 100644 index 000000000000..4b54332193a4 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/signextend.yul @@ -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: diff --git a/test/libyul/ewasmTranslationTests/smoke_create.yul b/test/libyul/ewasmTranslationTests/smoke_create.yul index 6f038cdc86aa..ae6d457c4dc8 100644 --- a/test/libyul/ewasmTranslationTests/smoke_create.yul +++ b/test/libyul/ewasmTranslationTests/smoke_create.yul @@ -7,6 +7,5 @@ // Trace: // INVALID() // Memory dump: -// 0: 0000000000000000000000000000000000000000000000000000000000000014 // 40: 636f6465636f6465636f6465636f6465636f6465000000000000000000000000 // Storage dump: diff --git a/test/libyul/ewasmTranslationTests/smoke_create2.yul b/test/libyul/ewasmTranslationTests/smoke_create2.yul index 347574d6b64e..32d789ea9abb 100644 --- a/test/libyul/ewasmTranslationTests/smoke_create2.yul +++ b/test/libyul/ewasmTranslationTests/smoke_create2.yul @@ -9,6 +9,5 @@ // Trace: // INVALID() // Memory dump: -// 0: 0000000000000000000000000000000000000000000000000000000000000014 // 80: 636f6465636f6465636f6465636f6465636f6465000000000000000000000000 // Storage dump: diff --git a/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul index ae7c0e1140c9..79b372972a8f 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul @@ -8,7 +8,7 @@ } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { // { let a:u256, b:u256 } diff --git a/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul b/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul index b081ebe6f119..fe54227d35bd 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul @@ -8,7 +8,7 @@ } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul index 5dd6ac3bf59d..2dee55ae7e2f 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul @@ -7,7 +7,7 @@ } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { // { let a:u256, b:u256, c:u256 } diff --git a/test/libyul/yulOptimizerTests/disambiguator/long_names.yul b/test/libyul/yulOptimizerTests/disambiguator/long_names.yul index 2b9f3e522cb3..b5db97637adb 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/long_names.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/long_names.yul @@ -1,7 +1,7 @@ { { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul b/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul index d0702de6fc23..2ed2b9ad10f6 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul @@ -1,6 +1,6 @@ { } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { } diff --git a/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul index 497f4985c5ac..647c78fda6ea 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul @@ -9,7 +9,7 @@ } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { // { let a:u256, b:u256, c:u256 } diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables.yul b/test/libyul/yulOptimizerTests/disambiguator/variables.yul index 2d3318702970..319809706808 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables.yul @@ -1,7 +1,7 @@ { { let a:u256 } { let a:u256 } } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { // { let a:u256 } diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul b/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul index 9501b8a1c97b..9474dfc86cb8 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul @@ -1,7 +1,7 @@ { { let a:u256 let a_1:u256 } { let a:u256 } } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul b/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul index b160f032c390..66d36e43120b 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul @@ -7,7 +7,7 @@ } // ==== // step: disambiguator -// yul: true +// dialect: yul // ---- // { // { diff --git a/test/libyul/yulOptimizerTests/expressionInliner/simple.yul b/test/libyul/yulOptimizerTests/expressionInliner/simple.yul index 4302da79f67d..c1a1c147e222 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/simple.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/simple.yul @@ -4,7 +4,7 @@ } // ==== // step: expressionInliner -// yul: true +// dialect: yul // ---- // { // function f() -> x:u256 diff --git a/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul b/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul index 2bdd8ffd886b..8dd694aec5af 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul @@ -4,7 +4,7 @@ } // ==== // step: expressionInliner -// yul: true +// dialect: yul // ---- // { // function f(a:u256) -> x:u256 diff --git a/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul b/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul index 51699b7a8dbd..950118647507 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul @@ -1,7 +1,7 @@ { let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } } // ==== // step: functionGrouper -// yul: true +// dialect: yul // ---- // { // { diff --git a/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul b/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul index 73af943aad04..559452a98a19 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul @@ -6,7 +6,7 @@ } // ==== // step: functionGrouper -// yul: true +// dialect: yul // ---- // { // { diff --git a/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul b/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul index ac67a4461312..14b28fbabb8d 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul @@ -10,7 +10,7 @@ } // ==== // step: functionGrouper -// yul: true +// dialect: yul // ---- // { // { let a:u256 } diff --git a/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul b/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul index ec72697a757d..94af922877e9 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul @@ -3,7 +3,7 @@ } // ==== // step: functionGrouper -// yul: true +// dialect: yul // ---- // { // { let a:u256 } diff --git a/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul b/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul index 4d3b90d45af1..4a7c0a7a22a4 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul @@ -9,7 +9,7 @@ } // ==== // step: functionHoister -// yul: true +// dialect: yul // ---- // { // let a:u256 diff --git a/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul b/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul index 7d41d59e7401..78e4b49aba87 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul @@ -7,7 +7,7 @@ } // ==== // step: functionHoister -// yul: true +// dialect: yul // ---- // { // let a:u256 diff --git a/test/libyul/yulOptimizerTests/functionHoister/nested.yul b/test/libyul/yulOptimizerTests/functionHoister/nested.yul index 50d96290710e..8135985037a5 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/nested.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/nested.yul @@ -8,7 +8,7 @@ } // ==== // step: functionHoister -// yul: true +// dialect: yul // ---- // { // let a:u256 diff --git a/test/libyul/yulOptimizerTests/functionHoister/single.yul b/test/libyul/yulOptimizerTests/functionHoister/single.yul index 70c3ecb3db48..70ecfdb8e082 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/single.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/single.yul @@ -4,7 +4,7 @@ } // ==== // step: functionHoister -// yul: true +// dialect: yul // ---- // { // let a:u256 diff --git a/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul b/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul index efe904d89db4..09a04e1d3734 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul @@ -9,7 +9,7 @@ } // ==== // step: mainFunction -// yul: true +// dialect: yul // ---- // { // function main() diff --git a/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul b/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul index 2f4de38b6e4d..7aaab11e5a0f 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul @@ -7,7 +7,7 @@ } // ==== // step: mainFunction -// yul: true +// dialect: yul // ---- // { // function main() diff --git a/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul b/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul index 2c9d120b3c55..61cb672333a0 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul @@ -8,7 +8,7 @@ } // ==== // step: mainFunction -// yul: true +// dialect: yul // ---- // { // function main() diff --git a/test/libyul/yulOptimizerTests/mainFunction/sigle_fun.yul b/test/libyul/yulOptimizerTests/mainFunction/sigle_fun.yul index c7de4344118a..63154e8c3ffb 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/sigle_fun.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/sigle_fun.yul @@ -4,7 +4,7 @@ } // ==== // step: mainFunction -// yul: true +// dialect: yul // ---- // { // function main() diff --git a/test/libyul/yulOptimizerTests/mainFunction/smoke.yul b/test/libyul/yulOptimizerTests/mainFunction/smoke.yul index 3ae7cb5f743e..54ad2d843e7f 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/smoke.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/smoke.yul @@ -1,7 +1,7 @@ {} // ==== // step: mainFunction -// yul: true +// dialect: yul // ---- // { // function main() diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul new file mode 100644 index 000000000000..8e75d82edb7c --- /dev/null +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul @@ -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) +// } +// } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul new file mode 100644 index 000000000000..f5a29382b393 --- /dev/null +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul @@ -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) +// } +// } diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 46156c219de0..acc70c2dcfd0 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -32,7 +32,7 @@ add_executable(isoltest ../libsolidity/SMTCheckerTest.cpp ../libsolidity/SMTCheckerJSONTest.cpp ../libyul/Common.cpp - ../libyul/EWasmTranslationTest.cpp + ../libyul/EwasmTranslationTest.cpp ../libyul/FunctionSideEffects.cpp ../libyul/ObjectCompilerTest.cpp ../libyul/YulOptimizerTest.cpp diff --git a/test/tools/yulInterpreter/CMakeLists.txt b/test/tools/yulInterpreter/CMakeLists.txt index 02d53d69764b..95f4c3f3d43a 100644 --- a/test/tools/yulInterpreter/CMakeLists.txt +++ b/test/tools/yulInterpreter/CMakeLists.txt @@ -1,8 +1,8 @@ set(sources EVMInstructionInterpreter.h EVMInstructionInterpreter.cpp - EWasmBuiltinInterpreter.h - EWasmBuiltinInterpreter.cpp + EwasmBuiltinInterpreter.h + EwasmBuiltinInterpreter.cpp Interpreter.h Interpreter.cpp ) diff --git a/test/tools/yulInterpreter/EWasmBuiltinInterpreter.cpp b/test/tools/yulInterpreter/EwasmBuiltinInterpreter.cpp similarity index 82% rename from test/tools/yulInterpreter/EWasmBuiltinInterpreter.cpp rename to test/tools/yulInterpreter/EwasmBuiltinInterpreter.cpp index fe8d28f70fa6..1f1ed9e60bcd 100644 --- a/test/tools/yulInterpreter/EWasmBuiltinInterpreter.cpp +++ b/test/tools/yulInterpreter/EwasmBuiltinInterpreter.cpp @@ -15,10 +15,10 @@ along with solidity. If not, see . */ /** - * Yul interpreter module that evaluates EWasm builtins. + * Yul interpreter module that evaluates Ewasm builtins. */ -#include +#include #include @@ -49,11 +49,26 @@ void copyZeroExtended( _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>; -u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _arguments) +u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _arguments) { vector arg; for (u256 const& a: _arguments) @@ -119,6 +134,8 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a return arg[0] != arg[1] ? 1 : 0; else if (_fun == "i64.eqz"_yulstring) return arg[0] == 0 ? 1 : 0; + else if (_fun == "i64.clz"_yulstring) + return clz(arg[0]); else if (_fun == "i64.lt_u"_yulstring) return arg[0] < arg[1] ? 1 : 0; else if (_fun == "i64.gt_u"_yulstring) @@ -133,24 +150,39 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a writeMemoryWord(arg[0], arg[1]); return 0; } + else if (_fun == "i64.store8"_yulstring) + { + accessMemory(arg[0], 1); + writeMemoryByte(arg[0], static_cast(arg[1] & 0xff)); + return 0; + } else if (_fun == "i64.load"_yulstring) { accessMemory(arg[0], 8); return readMemoryWord(arg[0]); } 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) + { // TODO this does not read the address, but is consistent with // EVM interpreter implementation. // 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) { if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber) return 1; 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) { @@ -199,12 +231,21 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a return 0; } 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) + { // 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) - return writeU128(arg[0], m_state.callvalue); + { + writeU128(arg[0], m_state.callvalue); + return 0; + } else if (_fun == "eth.codeCopy"_yulstring) { if (accessMemory(arg[0], arg[2])) @@ -215,9 +256,12 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a return 0; } 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) - return writeAddress(arg[0], m_state.coinbase); + { + writeAddress(arg[0], m_state.coinbase); + return 0; + } else if (_fun == "eth.create"_yulstring) { // TODO access memory @@ -226,7 +270,10 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a return 0xcccccc + arg[1]; } 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) { // TODO use readAddress to read address. @@ -239,22 +286,32 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a return 0; } 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) return 0x99; else if (_fun == "eth.getBlockGasLimit"_yulstring) return uint64_t(m_state.gaslimit); 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) { - logTrace(eth::Instruction::LOG0, {}); + uint64_t numberOfTopics = arg[2]; + if (numberOfTopics > 4) + throw ExplicitlyTerminated(); + logTrace(eth::logInstruction(numberOfTopics), {}); return 0; } else if (_fun == "eth.getBlockNumber"_yulstring) return m_state.blockNumber; 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) { bytes data; @@ -298,7 +355,7 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a 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))) { @@ -312,7 +369,7 @@ bool EWasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _siz 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."); bytes data(size_t(_size), uint8_t(0)); @@ -321,7 +378,7 @@ bytes EWasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size) return data; } -uint64_t EWasmBuiltinInterpreter::readMemoryWord(uint64_t _offset) +uint64_t EwasmBuiltinInterpreter::readMemoryWord(uint64_t _offset) { uint64_t r = 0; for (size_t i = 0; i < 8; i++) @@ -329,13 +386,18 @@ uint64_t EWasmBuiltinInterpreter::readMemoryWord(uint64_t _offset) 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++) 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); 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); _value >>= 8; } - - return {}; } -u256 EWasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo) +u256 EwasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo) { accessMemory(_offset, _croppedTo); u256 value; @@ -357,12 +417,12 @@ u256 EWasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo) return value; } -void EWasmBuiltinInterpreter::logTrace(dev::eth::Instruction _instruction, std::vector const& _arguments, bytes const& _data) +void EwasmBuiltinInterpreter::logTrace(dev::eth::Instruction _instruction, std::vector const& _arguments, bytes const& _data) { logTrace(dev::eth::instructionInfo(_instruction).name, _arguments, _data); } -void EWasmBuiltinInterpreter::logTrace(std::string const& _pseudoInstruction, std::vector const& _arguments, bytes const& _data) +void EwasmBuiltinInterpreter::logTrace(std::string const& _pseudoInstruction, std::vector const& _arguments, bytes const& _data) { string message = _pseudoInstruction + "("; for (size_t i = 0; i < _arguments.size(); ++i) diff --git a/test/tools/yulInterpreter/EWasmBuiltinInterpreter.h b/test/tools/yulInterpreter/EwasmBuiltinInterpreter.h similarity index 84% rename from test/tools/yulInterpreter/EWasmBuiltinInterpreter.h rename to test/tools/yulInterpreter/EwasmBuiltinInterpreter.h index e96cbbae2359..a9c733f8e005 100644 --- a/test/tools/yulInterpreter/EWasmBuiltinInterpreter.h +++ b/test/tools/yulInterpreter/EwasmBuiltinInterpreter.h @@ -15,7 +15,7 @@ along with solidity. If not, see . */ /** - * Yul interpreter module that evaluates EWasm builtins. + * Yul interpreter module that evaluates Ewasm builtins. */ #pragma once @@ -45,7 +45,7 @@ namespace test 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. * * 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 * and likely to be different for non-equivalent executions. */ -class EWasmBuiltinInterpreter +class EwasmBuiltinInterpreter { public: - explicit EWasmBuiltinInterpreter(InterpreterState& _state): + explicit EwasmBuiltinInterpreter(InterpreterState& _state): m_state(_state) {} /// Evaluate builtin function @@ -86,11 +86,14 @@ class EWasmBuiltinInterpreter /// Writes a word to memory (little-endian) /// Does not adjust msize, use @a accessMemory for that 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. - dev::u256 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); } - dev::u256 writeAddress(uint64_t _offset, dev::u256 _value) { return writeU256(_offset, std::move(_value), 20); } + void writeU256(uint64_t _offset, dev::u256 _value, size_t _croppedTo = 32); + void writeU128(uint64_t _offset, dev::u256 _value) { writeU256(_offset, std::move(_value), 16); } + 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; dev::u256 readU256(uint64_t _offset, size_t _croppedTo = 32); dev::u256 readU128(uint64_t _offset) { return readU256(_offset, 16); } diff --git a/test/tools/yulInterpreter/Interpreter.cpp b/test/tools/yulInterpreter/Interpreter.cpp index d50c15b11f41..64f73803a4c3 100644 --- a/test/tools/yulInterpreter/Interpreter.cpp +++ b/test/tools/yulInterpreter/Interpreter.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -246,7 +246,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall) else if (WasmDialect const* dialect = dynamic_cast(&m_dialect)) if (dialect->builtin(_funCall.functionName.name)) { - EWasmBuiltinInterpreter interpreter(m_state); + EwasmBuiltinInterpreter interpreter(m_state); setValue(interpreter.evalBuiltin(_funCall.functionName.name, values())); return; }