From 1832fbd732f387b6e0be72bf96f0bd082acb9515 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Mon, 22 Jul 2024 19:15:14 +0200 Subject: [PATCH 1/2] Enable ethdebug debug info and output selection. --- libevmasm/AbstractAssemblyStack.h | 4 + libevmasm/Assembly.cpp | 2 +- libevmasm/EVMAssemblyStack.cpp | 19 + libevmasm/EVMAssemblyStack.h | 6 + liblangutil/DebugInfoSelection.cpp | 12 +- liblangutil/DebugInfoSelection.h | 15 +- libsolidity/codegen/ir/IRGenerator.cpp | 3 +- libsolidity/interface/CompilerStack.cpp | 33 ++ libsolidity/interface/CompilerStack.h | 17 + libsolidity/interface/StandardCompiler.cpp | 88 ++- libyul/YulStack.cpp | 14 +- libyul/YulStack.h | 4 + solc/CommandLineInterface.cpp | 64 +++ solc/CommandLineInterface.h | 2 + solc/CommandLineParser.cpp | 84 ++- solc/CommandLineParser.h | 4 + test/cmdlineTests/ethdebug/args | 1 + test/cmdlineTests/ethdebug/input.sol | 7 + test/cmdlineTests/ethdebug/output | 42 ++ .../ethdebug_and_ethdebug_runtime/args | 1 + .../ethdebug_and_ethdebug_runtime/input.sol | 7 + .../ethdebug_and_ethdebug_runtime/output | 44 ++ test/cmdlineTests/ethdebug_runtime/args | 1 + test/cmdlineTests/ethdebug_runtime/input.sol | 7 + test/cmdlineTests/ethdebug_runtime/output | 42 ++ .../input.json | 24 + .../output.json | 214 ++++++++ .../input.json | 24 + .../output.json | 226 ++++++++ .../input.json | 24 + .../output.json | 214 ++++++++ .../standard_yul_ethdebug_bytecode/args | 1 + .../standard_yul_ethdebug_bytecode/in.yul | 17 + .../standard_yul_ethdebug_bytecode/input.json | 14 + .../output.json | 31 ++ .../args | 1 + .../in.yul | 17 + .../input.json | 11 + .../output.json | 11 + test/cmdlineTests/yul_ethdebug/args | 1 + test/cmdlineTests/yul_ethdebug/input.yul | 18 + test/cmdlineTests/yul_ethdebug/output | 18 + test/cmdlineTests/yul_ethdebug_runtime/args | 1 + test/cmdlineTests/yul_ethdebug_runtime/err | 1 + test/cmdlineTests/yul_ethdebug_runtime/exit | 1 + .../yul_ethdebug_runtime/input.yul | 18 + test/libsolidity/StandardCompiler.cpp | 511 ++++++++++++++++++ test/libyul/Common.cpp | 2 +- test/libyul/EVMCodeTransformTest.cpp | 2 +- test/libyul/ObjectParser.cpp | 2 +- test/solc/CommandLineInterface.cpp | 350 ++++++++++++ test/solc/CommandLineParser.cpp | 43 ++ .../ossfuzz/strictasm_assembly_ossfuzz.cpp | 2 +- test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp | 2 +- test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp | 2 +- 55 files changed, 2308 insertions(+), 18 deletions(-) create mode 100644 test/cmdlineTests/ethdebug/args create mode 100644 test/cmdlineTests/ethdebug/input.sol create mode 100644 test/cmdlineTests/ethdebug/output create mode 100644 test/cmdlineTests/ethdebug_and_ethdebug_runtime/args create mode 100644 test/cmdlineTests/ethdebug_and_ethdebug_runtime/input.sol create mode 100644 test/cmdlineTests/ethdebug_and_ethdebug_runtime/output create mode 100644 test/cmdlineTests/ethdebug_runtime/args create mode 100644 test/cmdlineTests/ethdebug_runtime/input.sol create mode 100644 test/cmdlineTests/ethdebug_runtime/output create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json create mode 100644 test/cmdlineTests/standard_yul_ethdebug_bytecode/args create mode 100644 test/cmdlineTests/standard_yul_ethdebug_bytecode/in.yul create mode 100644 test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json create mode 100644 test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json create mode 100644 test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/args create mode 100644 test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/in.yul create mode 100644 test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/input.json create mode 100644 test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/output.json create mode 100644 test/cmdlineTests/yul_ethdebug/args create mode 100644 test/cmdlineTests/yul_ethdebug/input.yul create mode 100644 test/cmdlineTests/yul_ethdebug/output create mode 100644 test/cmdlineTests/yul_ethdebug_runtime/args create mode 100644 test/cmdlineTests/yul_ethdebug_runtime/err create mode 100644 test/cmdlineTests/yul_ethdebug_runtime/exit create mode 100644 test/cmdlineTests/yul_ethdebug_runtime/input.yul diff --git a/libevmasm/AbstractAssemblyStack.h b/libevmasm/AbstractAssemblyStack.h index 278edf5c273b..c4eb804eea41 100644 --- a/libevmasm/AbstractAssemblyStack.h +++ b/libevmasm/AbstractAssemblyStack.h @@ -40,6 +40,10 @@ class AbstractAssemblyStack virtual std::string const* sourceMapping(std::string const& _contractName) const = 0; virtual std::string const* runtimeSourceMapping(std::string const& _contractName) const = 0; + virtual Json ethdebug(std::string const& _contractName) const = 0; + virtual Json ethdebugRuntime(std::string const& _contractName) const = 0; + virtual Json ethdebug() const = 0; + virtual Json assemblyJSON(std::string const& _contractName) const = 0; virtual std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const = 0; diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 22bff5415333..ac9f14b15498 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -444,7 +444,7 @@ std::string Assembly::assemblyString( { std::ostringstream tmp; assemblyStream(tmp, _debugInfoSelection, "", _sourceCodes); - return tmp.str(); + return (_debugInfoSelection.ethdebug ? "/// ethdebug: enabled\n" : "") + tmp.str(); } Json Assembly::assemblyJSON(std::map const& _sourceIndices, bool _includeSourceList) const diff --git a/libevmasm/EVMAssemblyStack.cpp b/libevmasm/EVMAssemblyStack.cpp index df4517fc522b..f8b8b4b54d0e 100644 --- a/libevmasm/EVMAssemblyStack.cpp +++ b/libevmasm/EVMAssemblyStack.cpp @@ -103,6 +103,25 @@ std::string const* EVMAssemblyStack::runtimeSourceMapping(std::string const& _co return &m_runtimeSourceMapping; } +Json EVMAssemblyStack::ethdebug(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + solAssert(m_ethdebug != nullptr); + return *m_ethdebug; +} + +Json EVMAssemblyStack::ethdebugRuntime(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + solAssert(m_ethdebugRuntime != nullptr); + return *m_ethdebugRuntime; +} + +Json EVMAssemblyStack::ethdebug() const +{ + return {}; +} + Json EVMAssemblyStack::assemblyJSON(std::string const& _contractName) const { solAssert(_contractName == m_name); diff --git a/libevmasm/EVMAssemblyStack.h b/libevmasm/EVMAssemblyStack.h index 55c9fd684ecc..e3888afadc3e 100644 --- a/libevmasm/EVMAssemblyStack.h +++ b/libevmasm/EVMAssemblyStack.h @@ -59,6 +59,10 @@ class EVMAssemblyStack: public AbstractAssemblyStack std::string const* sourceMapping(std::string const& _contractName) const override; std::string const* runtimeSourceMapping(std::string const& _contractName) const override; + Json ethdebug(std::string const& _contractName) const override; + Json ethdebugRuntime(std::string const& _contractName) const override; + Json ethdebug() const override; + Json assemblyJSON(std::string const& _contractName) const override; std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const override; @@ -87,6 +91,8 @@ class EVMAssemblyStack: public AbstractAssemblyStack langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default(); std::string m_sourceMapping; std::string m_runtimeSourceMapping; + std::unique_ptr m_ethdebug; + std::unique_ptr m_ethdebugRuntime; }; } // namespace solidity::evmasm diff --git a/liblangutil/DebugInfoSelection.cpp b/liblangutil/DebugInfoSelection.cpp index ad0b615c1c1e..dfd623646e3a 100644 --- a/liblangutil/DebugInfoSelection.cpp +++ b/liblangutil/DebugInfoSelection.cpp @@ -49,6 +49,14 @@ DebugInfoSelection const DebugInfoSelection::Only(bool DebugInfoSelection::* _me return result; } +DebugInfoSelection const DebugInfoSelection::AllExcept(std::vector const& _members) noexcept +{ + DebugInfoSelection result = All(); + for (bool DebugInfoSelection::* member: _members) + result.*member = false; + return result; +} + std::optional DebugInfoSelection::fromString(std::string_view _input) { // TODO: Make more stuff constexpr and make it a static_assert(). @@ -56,7 +64,7 @@ std::optional DebugInfoSelection::fromString(std::string_vie solAssert(componentMap().count("none") == 0, ""); if (_input == "all") - return All(); + return AllExceptExperimental(); if (_input == "none") return None(); @@ -74,7 +82,7 @@ std::optional DebugInfoSelection::fromComponents( for (auto const& component: _componentNames) { if (component == "*") - return (_acceptWildcards ? std::make_optional(DebugInfoSelection::All()) : std::nullopt); + return (_acceptWildcards ? std::make_optional(AllExceptExperimental()) : std::nullopt); if (!selection.enable(component)) return std::nullopt; diff --git a/liblangutil/DebugInfoSelection.h b/liblangutil/DebugInfoSelection.h index 3a9432de6d02..daf4b950f2e9 100644 --- a/liblangutil/DebugInfoSelection.h +++ b/liblangutil/DebugInfoSelection.h @@ -42,7 +42,9 @@ struct DebugInfoSelection static DebugInfoSelection const All(bool _value = true) noexcept; static DebugInfoSelection const None() noexcept { return All(false); } static DebugInfoSelection const Only(bool DebugInfoSelection::* _member) noexcept; - static DebugInfoSelection const Default() noexcept { return All(); } + static DebugInfoSelection const Default() noexcept { return AllExceptExperimental(); } + static DebugInfoSelection const AllExcept(std::vector const& _members) noexcept; + static DebugInfoSelection const AllExceptExperimental() noexcept { return AllExcept({&DebugInfoSelection::ethdebug}); } static std::optional fromString(std::string_view _input); static std::optional fromComponents( @@ -72,13 +74,24 @@ struct DebugInfoSelection {"location", &DebugInfoSelection::location}, {"snippet", &DebugInfoSelection::snippet}, {"ast-id", &DebugInfoSelection::astID}, + {"ethdebug", &DebugInfoSelection::ethdebug}, }; return components; } + std::vector selectedNames() const + { + std::vector result; + for (auto const& component: componentMap()) + if (this->*(component.second)) + result.push_back(component.first); + return result; + } + bool location = false; ///< Include source location. E.g. `@src 3:50:100` bool snippet = false; ///< Include source code snippet next to location. E.g. `@src 3:50:100 "contract C {..."` bool astID = false; ///< Include ID of the Solidity AST node. E.g. `@ast-id 15` + bool ethdebug = false; ///< Include ethdebug related debug information. }; std::ostream& operator<<(std::ostream& _stream, DebugInfoSelection const& _selection); diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index ae2a12c71c32..dd6503ca1fbf 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -120,7 +120,7 @@ std::string IRGenerator::generate( ); }; - Whiskers t(R"( + Whiskers t(R"(/// ethdebug: enabled /// @use-src object "" { code { @@ -164,6 +164,7 @@ std::string IRGenerator::generate( for (VariableDeclaration const* var: ContractType(_contract).immutableVariables()) m_context.registerImmutableVariable(*var); + t("isEthdebugEnabled", m_context.debugInfoSelection().ethdebug); t("CreationObject", IRNames::creationObject(_contract)); t("sourceLocationCommentCreation", dispenseLocationComment(_contract)); t("library", _contract.isLibrary()); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 2a859ea24517..1791ad45a9d5 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1181,6 +1181,39 @@ Json CompilerStack::interfaceSymbols(std::string const& _contractName) const return interfaceSymbols; } +Json CompilerStack::ethdebug() const +{ + solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful."); + solAssert(!m_contracts.empty()); + Json result = Json::object(); + result["sources"] = sourceNames(); + return result; +} + +Json CompilerStack::ethdebug(std::string const& _contractName) const +{ + return ethdebug(contract(_contractName), /* runtime */ false); +} + +Json CompilerStack::ethdebugRuntime(std::string const& _contractName) const +{ + return ethdebug(contract(_contractName), /* runtime */ true); +} + +Json CompilerStack::ethdebug(Contract const& _contract, bool _runtime) const +{ + solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful."); + solAssert(_contract.contract); + solUnimplementedAssert(!isExperimentalSolidity()); + if (_runtime) + { + Json result = Json::object(); + return result; + } + Json result = Json::object(); + return result; +} + bytes CompilerStack::cborMetadata(std::string const& _contractName, bool _forIR) const { solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful."); diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index f36eedde0611..2731787a4b88 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -391,6 +391,18 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac /// @returns a JSON object with the three members ``methods``, ``events``, ``errors``. Each is a map, mapping identifiers (hashes) to function names. Json interfaceSymbols(std::string const& _contractName) const; + /// @returns a JSON representing the ethdebug data of the specified contract. + /// Prerequisite: Successful call to parse or compile. + Json ethdebug(std::string const& _contractName) const override; + + /// @returns a JSON representing the ethdebug data of the specified contract. + /// Prerequisite: Successful call to parse or compile. + Json ethdebugRuntime(std::string const& _contractName) const override; + + /// @returns a JSON representing the top-level ethdebug data (types, etc.). + /// Prerequisite: Successful call to parse or compile. + Json ethdebug() const override; + /// @returns the Contract Metadata matching the pipeline selected using the viaIR setting. std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); } @@ -571,6 +583,11 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac /// This will generate the metadata and store it in the Contract object if it is not present yet. std::string const& metadata(Contract const& _contract) const; + /// @returns the Contract ethdebug data. + /// This will generate the JSON object and store it in the Contract object if it is not present yet. + /// Prerequisite: Successful call to parse or compile. + Json ethdebug(Contract const& _contract, bool _runtime) const; + /// @returns the offset of the entry point of the given function into the list of assembly items /// or zero if it is not found or does not exist. size_t functionEntryPoint( diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 9357310c07e4..bcdb2901d053 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -165,7 +165,7 @@ bool hashMatchesContent(std::string const& _hash, std::string const& _content) bool isArtifactRequested(Json const& _outputSelection, std::string const& _artifact, bool _wildcardMatchesExperimental) { - static std::set experimental{"ir", "irAst", "irOptimized", "irOptimizedAst", "yulCFGJson"}; + static std::set experimental{"ir", "irAst", "irOptimized", "irOptimizedAst", "yulCFGJson", "ethdebug"}; for (auto const& selectedArtifactJson: _outputSelection) { std::string const& selectedArtifact = selectedArtifactJson.get(); @@ -173,12 +173,20 @@ bool isArtifactRequested(Json const& _outputSelection, std::string const& _artif _artifact == selectedArtifact || boost::algorithm::starts_with(_artifact, selectedArtifact + ".") ) + { + if (_artifact.find("ethdebug") != std::string::npos) + // only accept exact matches for ethdebug, e.g. evm.bytecode.ethdebug + return selectedArtifact == _artifact; return true; + } else if (selectedArtifact == "*") { // TODO: yulCFGJson is only experimental now, so it should not be matched by "*". if (_artifact == "yulCFGJson") return false; + // TODO: everything ethdebug related is only experimental for now, so it should not be matched by "*". + if (_artifact.find("ethdebug") != std::string::npos) + return false; // "ir", "irOptimized" can only be matched by "*" if activated. if (experimental.count(_artifact) == 0 || _wildcardMatchesExperimental) return true; @@ -237,7 +245,7 @@ bool isArtifactRequested(Json const& _outputSelection, std::string const& _file, std::vector evmObjectComponents(std::string const& _objectKind) { solAssert(_objectKind == "bytecode" || _objectKind == "deployedBytecode", ""); - std::vector components{"", ".object", ".opcodes", ".sourceMap", ".functionDebugData", ".generatedSources", ".linkReferences"}; + std::vector components{"", ".object", ".opcodes", ".sourceMap", ".functionDebugData", ".generatedSources", ".linkReferences", ".ethdebug"}; if (_objectKind == "deployedBytecode") components.push_back(".immutableReferences"); return util::applyMap(components, [&](auto const& _s) { return "evm." + _objectKind + _s; }); @@ -253,7 +261,7 @@ bool isBinaryRequested(Json const& _outputSelection) static std::vector const outputsThatRequireBinaries = std::vector{ "*", "ir", "irAst", "irOptimized", "irOptimizedAst", "yulCFGJson", - "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly" + "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly", "ethdebug" } + evmObjectComponents("bytecode") + evmObjectComponents("deployedBytecode"); for (auto const& fileRequests: _outputSelection) @@ -283,6 +291,21 @@ bool isEvmBytecodeRequested(Json const& _outputSelection) return false; } +/// @returns true if ethdebug was requested. +bool isEthdebugRequested(Json const& _outputSelection) +{ + if (!_outputSelection.is_object()) + return false; + + for (auto const& fileRequests: _outputSelection) + for (auto const& requests: fileRequests) + for (auto const& request: requests) + if (request == "evm.bytecode.ethdebug" || request == "evm.deployedBytecode.ethdebug") + return true; + + return false; +} + /// @returns The set of selected contracts, along with their compiler pipeline configuration, based /// on outputs requested in the JSON. Translates wildcards to the ones understood by CompilerStack. /// Note that as an exception, '*' does not yet match "ir", "irAst", "irOptimized" or "irOptimizedAst". @@ -1152,6 +1175,35 @@ std::variant StandardCompiler::parseI ret.modelCheckerSettings.timeout = modelCheckerSettings["timeout"].get(); } + if ((ret.debugInfoSelection.has_value() && ret.debugInfoSelection->ethdebug) || isEthdebugRequested(ret.outputSelection)) + { + if (ret.language != "Solidity" && ret.language != "Yul") + return formatFatalError(Error::Type::FatalError, "'settings.debug.debugInfo' 'ethdebug' is only supported for languages 'Solidity' and 'Yul'."); + } + + if (isEthdebugRequested(ret.outputSelection)) + { + if (ret.language == "Solidity" && !ret.viaIR) + return formatFatalError(Error::Type::FatalError, "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set."); + + if (!ret.debugInfoSelection.has_value()) + { + ret.debugInfoSelection = DebugInfoSelection::Default(); + ret.debugInfoSelection->enable("ethdebug"); + } + else + { + if (!ret.debugInfoSelection->ethdebug && ret.language == "Solidity") + return formatFatalError(Error::Type::FatalError, "'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output."); + } + } + + if ( + ret.debugInfoSelection.has_value() && ret.debugInfoSelection->ethdebug && ret.language == "Solidity" && + !pipelineConfig(ret.outputSelection)[""][""].irCodegen && !isEthdebugRequested(ret.outputSelection) + ) + return formatFatalError(Error::Type::FatalError, "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected."); + return {std::move(ret)}; } @@ -1235,6 +1287,8 @@ Json StandardCompiler::importEVMAssembly(StandardCompiler::InputsAndSettings _in creationJSON["functionDebugData"] = formatFunctionDebugData(stack.object(sourceName).functionDebugData); if (evmCreationArtifactRequested("linkReferences")) creationJSON["linkReferences"] = formatLinkReferences(stack.object(sourceName).linkReferences); + if (evmCreationArtifactRequested("ethdebug")) + creationJSON["ethdebug"] = stack.ethdebug(sourceName); evmData["bytecode"] = creationJSON; } @@ -1263,6 +1317,8 @@ Json StandardCompiler::importEVMAssembly(StandardCompiler::InputsAndSettings _in deployedJSON["linkReferences"] = formatLinkReferences(stack.runtimeObject(sourceName).linkReferences); if (evmDeployedArtifactRequested("immutableReferences")) deployedJSON["immutableReferences"] = formatImmutableReferences(stack.runtimeObject(sourceName).immutableReferences); + if (evmDeployedArtifactRequested("ethdebug")) + deployedJSON["ethdebug"] = stack.ethdebugRuntime(sourceName); evmData["deployedBytecode"] = deployedJSON; } @@ -1503,6 +1559,8 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu creationJSON["linkReferences"] = formatLinkReferences(compilerStack.object(contractName).linkReferences); if (evmCreationArtifactRequested("generatedSources")) creationJSON["generatedSources"] = compilerStack.generatedSources(contractName, /* _runtime */ false); + if (evmCreationArtifactRequested("ethdebug")) + creationJSON["ethdebug"] = compilerStack.ethdebug(contractName); evmData["bytecode"] = creationJSON; } @@ -1533,6 +1591,8 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu deployedJSON["immutableReferences"] = formatImmutableReferences(compilerStack.runtimeObject(contractName).immutableReferences); if (evmDeployedArtifactRequested("generatedSources")) deployedJSON["generatedSources"] = compilerStack.generatedSources(contractName, /* _runtime */ true); + if (evmDeployedArtifactRequested("ethdebug")) + deployedJSON["ethdebug"] = compilerStack.ethdebugRuntime(contractName); evmData["deployedBytecode"] = deployedJSON; } @@ -1546,6 +1606,10 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu contractsOutput[file][name] = contractData; } } + + if (isEthdebugRequested(_inputsAndSettings.outputSelection)) + output["ethdebug"] = compilerStack.ethdebug(); + if (!contractsOutput.empty()) output["contracts"] = contractsOutput; @@ -1597,6 +1661,19 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) return output; } + for (auto const& fileRequests: _inputsAndSettings.outputSelection) + for (auto const& requests: fileRequests) + for (auto const& request: requests) + if (request == "evm.deployedBytecode.ethdebug") + { + output["errors"].emplace_back(formatError( + Error::Type::JSONError, + "general", + "\"evm.deployedBytecode.ethdebug\" cannot be used for Yul." + )); + return output; + } + YulStack stack( _inputsAndSettings.evmVersion, _inputsAndSettings.eofVersion, @@ -1687,6 +1764,8 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) bytecodeJSON["functionDebugData"] = formatFunctionDebugData(selectedObject.bytecode->functionDebugData); if (evmArtifactRequested(kind, "linkReferences")) bytecodeJSON["linkReferences"] = formatLinkReferences(selectedObject.bytecode->linkReferences); + if (evmArtifactRequested(kind, "ethdebug")) + bytecodeJSON["ethdebug"] = selectedObject.ethdebug; if (isDeployed && evmArtifactRequested(kind, "immutableReferences")) bytecodeJSON["immutableReferences"] = formatImmutableReferences(selectedObject.bytecode->immutableReferences); output["contracts"][sourceName][contractName]["evm"][kind] = bytecodeJSON; @@ -1700,6 +1779,9 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "yulCFGJson", wildcardMatchesExperimental)) output["contracts"][sourceName][contractName]["yulCFGJson"] = stack.cfgJson(); + if (isEthdebugRequested(_inputsAndSettings.outputSelection)) + output["ethdebug"] = stack.ethdebug(); + return output; } diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index aa8a328204d2..f58705e9cb9d 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -273,6 +273,7 @@ YulStack::assembleWithDeployed(std::optional _deployName) {{m_charStream->name(), 0}} ); } + creationObject.ethdebug["not yet implemented @ MachineAssemblyObject::ethdebug"] = true; if (deployedAssembly) { @@ -368,7 +369,7 @@ std::string YulStack::print() const yulAssert(m_stackState >= Parsed); yulAssert(m_parserResult, ""); yulAssert(m_parserResult->hasCode(), ""); - return m_parserResult->toString( + return (m_debugInfoSelection.ethdebug ? "/// ethdebug: enabled\n" : "") + m_parserResult->toString( m_debugInfoSelection, m_soliditySourceProvider ) + "\n"; @@ -382,6 +383,17 @@ Json YulStack::astJson() const return m_parserResult->toJson(); } +Json YulStack::ethdebug() const +{ + yulAssert(m_parserResult, ""); + yulAssert(m_parserResult->hasCode(), ""); + yulAssert(m_parserResult->analysisInfo, ""); + + Json result = Json::object(); + result["sources"] = Json::array({m_charStream->name()}); + return result; +} + Json YulStack::cfgJson() const { yulAssert(m_parserResult, ""); diff --git a/libyul/YulStack.h b/libyul/YulStack.h index 94688fddcaaf..b745f1b80538 100644 --- a/libyul/YulStack.h +++ b/libyul/YulStack.h @@ -60,6 +60,7 @@ struct MachineAssemblyObject std::shared_ptr bytecode; std::shared_ptr assembly; std::unique_ptr sourceMappings; + Json ethdebug = Json::object(); }; /* @@ -148,6 +149,9 @@ class YulStack: public langutil::CharStreamProvider // return the JSON representation of the YuL CFG (experimental) Json cfgJson() const; + /// @returns a JSON representing the top-level ethdebug data (types, etc.). + Json ethdebug() const; + /// Return the parsed and analyzed object. std::shared_ptr parserResult() const; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index f2bb4af107bb..d97e56638947 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -151,6 +151,8 @@ static bool needsHumanTargetedStdout(CommandLineOptions const& _options) _options.compiler.outputs.yulCFGJson || _options.compiler.outputs.binary || _options.compiler.outputs.binaryRuntime || + _options.compiler.outputs.ethdebug || + _options.compiler.outputs.ethdebugRuntime || _options.compiler.outputs.metadata || _options.compiler.outputs.natspecUser || _options.compiler.outputs.natspecDev || @@ -551,6 +553,44 @@ void CommandLineInterface::handleGasEstimation(std::string const& _contract) } } +void CommandLineInterface::handleEthdebug() +{ + if (m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) + { + std::string ethdebug{jsonPrint(removeNullMembers(m_compiler->ethdebug()), m_options.formatting.json)}; + if (!m_options.output.dir.empty()) + createFile("ethdebug.json", ethdebug); + else + sout() << "======= Debug Data (ethdebug/format/info/resources) =======" << std::endl << ethdebug << std::endl; + } +} + +void CommandLineInterface::handleEthdebug(std::string const& _contract) +{ + solAssert(CompilerInputModes.count(m_options.input.mode) == 1); + + if (!(m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime)) + return; + + if (m_options.compiler.outputs.ethdebug) + { + std::string ethdebug{jsonPrint(removeNullMembers(m_compiler->ethdebug(_contract)), m_options.formatting.json)}; + if (!m_options.output.dir.empty()) + createFile(m_compiler->filesystemFriendlyName(_contract) + "_ethdebug.json", ethdebug); + else + sout() << "Debug Data (ethdebug/format/program):" << std::endl << ethdebug << std::endl; + } + + if (m_options.compiler.outputs.ethdebugRuntime) + { + std::string ethdebugRuntime{jsonPrint(removeNullMembers(m_compiler->ethdebugRuntime(_contract)), m_options.formatting.json)}; + if (!m_options.output.dir.empty()) + createFile(m_compiler->filesystemFriendlyName(_contract) + "_ethdebug-runtime.json", ethdebugRuntime); + else + sout() << "Debug Data of the runtime part (ethdebug/format/program):" << std::endl << ethdebugRuntime << std::endl; + } +} + void CommandLineInterface::readInputFiles() { solAssert(!m_standardJsonInput.has_value()); @@ -912,6 +952,8 @@ void CommandLineInterface::compile() m_options.compiler.outputs.opcodes || m_options.compiler.outputs.binary || m_options.compiler.outputs.binaryRuntime || + m_options.compiler.outputs.ethdebug || + m_options.compiler.outputs.ethdebugRuntime || (m_options.compiler.combinedJsonRequests && ( m_options.compiler.combinedJsonRequests->binary || m_options.compiler.combinedJsonRequests->binaryRuntime || @@ -1290,6 +1332,17 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y solThrow(CommandLineExecutionError, ""); } + if (m_options.compiler.outputs.ethdebug) + { + Json ethdebugObject = Json::object(); + ethdebugObject["sources"] = m_fileReader.sourceUnits() | ranges::views::keys; + sout() << "======= Debug Data (ethdebug/format/info/resources) =======" << std::endl; + sout() << util::jsonPrint( + ethdebugObject, + m_options.formatting.json + ) << std::endl; + } + for (auto const& [sourceUnitName, yulSource]: m_fileReader.sourceUnits()) { solAssert(_targetMachine == yul::YulStack::Machine::EVM); @@ -1345,6 +1398,14 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y m_options.formatting.json ) << std::endl; } + if (m_options.compiler.outputs.ethdebug) + { + sout() << std::endl << "Debug Data (ethdebug/format/program):" << std::endl; + sout() << util::jsonPrint( + object.ethdebug, + m_options.formatting.json + ) << std::endl; + } } } @@ -1357,6 +1418,8 @@ void CommandLineInterface::outputCompilationResults() // do we need AST output? handleAst(); + handleEthdebug(); + CompilerOutputs astOutputSelection; astOutputSelection.astCompactJson = true; if (m_options.compiler.outputs != CompilerOutputs() && m_options.compiler.outputs != astOutputSelection) @@ -1388,6 +1451,7 @@ void CommandLineInterface::outputCompilationResults() handleTransientStorageLayout(contract); handleNatspec(true, contract); handleNatspec(false, contract); + handleEthdebug(contract); } // end of contracts iteration } diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index ce30a4d71db7..b8a10c372db2 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -101,6 +101,7 @@ class CommandLineInterface void handleCombinedJSON(); void handleAst(); + void handleEthdebug(); void handleEVMAssembly(std::string const& _contract); void handleBinary(std::string const& _contract); void handleOpcode(std::string const& _contract); @@ -117,6 +118,7 @@ class CommandLineInterface void handleGasEstimation(std::string const& _contract); void handleStorageLayout(std::string const& _contract); void handleTransientStorageLayout(std::string const& _contract); + void handleEthdebug(std::string const& _contract); /// Tries to read @ m_sourceCodes as a JSONs holding ASTs /// such that they can be imported into the compiler (importASTs()) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 5929144049a2..f62abb3c6043 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -474,6 +474,7 @@ void CommandLineParser::parseOutputSelection() CompilerOutputs::componentName(&CompilerOutputs::astCompactJson), CompilerOutputs::componentName(&CompilerOutputs::asmJson), CompilerOutputs::componentName(&CompilerOutputs::yulCFGJson), + CompilerOutputs::componentName(&CompilerOutputs::ethdebug), }; static std::set const evmAssemblyJsonImportModeOutputs = { CompilerOutputs::componentName(&CompilerOutputs::asm_), @@ -651,7 +652,7 @@ General Information)").c_str(), po::value()->default_value(util::toString(DebugInfoSelection::Default())), ("Debug info components to be included in the produced EVM assembly and Yul code. " "Value can be all, none or a comma-separated list containing one or more of the " - "following components: " + util::joinHumanReadable(DebugInfoSelection::componentMap() | ranges::views::keys) + ".").c_str() + "following components: " + util::joinHumanReadable(DebugInfoSelection::Default().selectedNames()) + ".").c_str() ) ( g_strStopAfter.c_str(), @@ -773,9 +774,23 @@ General Information)").c_str(), (CompilerOutputs::componentName(&CompilerOutputs::transientStorageLayout).c_str(), "Slots, offsets and types of the contract's state variables located in transient storage.") ; if (!_forHelp) // Note: We intentionally keep this undocumented for now. + { outputComponents.add_options() - (CompilerOutputs::componentName(&CompilerOutputs::yulCFGJson).c_str(), "Control Flow Graph (CFG) of Yul code in JSON format.") - ; + ( + CompilerOutputs::componentName(&CompilerOutputs::yulCFGJson).c_str(), + "Control Flow Graph (CFG) of Yul code in JSON format." + ); + outputComponents.add_options() + ( + CompilerOutputs::componentName(&CompilerOutputs::ethdebug).c_str(), + "Ethdebug output of all contracts." + ); + outputComponents.add_options() + ( + CompilerOutputs::componentName(&CompilerOutputs::ethdebugRuntime).c_str(), + "Ethdebug output of the runtime part of all contracts." + ); + } desc.add(outputComponents); po::options_description extraOutput("Extra Output"); @@ -1321,6 +1336,14 @@ void CommandLineParser::processArgs() CommandLineValidationError, "Optimizer can only be used for strict assembly. Use --" + g_strStrictAssembly + "." ); + + if (m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) + if (!m_options.output.debugInfoSelection.has_value()) + { + m_options.output.debugInfoSelection = DebugInfoSelection::Default(); + m_options.output.debugInfoSelection->enable("ethdebug"); + } + return; } else if (countEnabledOptions({g_strYulDialect, g_strMachine}) >= 1) @@ -1460,6 +1483,61 @@ void CommandLineParser::processArgs() m_options.input.mode == InputMode::CompilerWithASTImport || m_options.input.mode == InputMode::EVMAssemblerJSON ); + + bool incompatibleEthdebugOutputs = + m_options.compiler.outputs.asmJson || m_options.compiler.outputs.irAstJson || m_options.compiler.outputs.irOptimizedAstJson; + + bool incompatibleEthdebugInputs = m_options.input.mode != InputMode::Compiler; + + static std::string enableEthdebugMessage = + "--" + CompilerOutputs::componentName(&CompilerOutputs::ethdebug) + " / --" + CompilerOutputs::componentName(&CompilerOutputs::ethdebugRuntime); + + static std::string enableIrMessage = + "--" + CompilerOutputs::componentName(&CompilerOutputs::ir) + " / --" + CompilerOutputs::componentName(&CompilerOutputs::irOptimized); + + if (m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) + { + if (!m_options.output.viaIR) + solThrow( + CommandLineValidationError, + enableEthdebugMessage + " output can only be selected, if --via-ir was specified." + ); + + if (incompatibleEthdebugOutputs) + solThrow( + CommandLineValidationError, + enableEthdebugMessage + " output can only be used with " + enableIrMessage + "." + ); + + if (!m_options.output.debugInfoSelection.has_value()) + { + m_options.output.debugInfoSelection = DebugInfoSelection::Default(); + m_options.output.debugInfoSelection->enable("ethdebug"); + } + else + { + if (!m_options.output.debugInfoSelection->ethdebug) + solThrow( + CommandLineValidationError, + "--debug-info must contain ethdebug, when compiling with " + enableEthdebugMessage + "." + ); + } + } + + if ( + m_options.output.debugInfoSelection.has_value() && m_options.output.debugInfoSelection->ethdebug && + (!(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized || m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) || incompatibleEthdebugOutputs) + ) + solThrow( + CommandLineValidationError, + "--debug-info ethdebug can only be used with " + enableIrMessage + " and/or " + enableEthdebugMessage + "." + ); + + if (m_options.output.debugInfoSelection.has_value() && m_options.output.debugInfoSelection->ethdebug && incompatibleEthdebugInputs) + solThrow( + CommandLineValidationError, + "Invalid input mode for --debug-info ethdebug / --ethdebug / --ethdebug-runtime." + ); } void CommandLineParser::parseCombinedJsonOption() diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 3d187694e2e0..d8141cb4fcf0 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -88,6 +88,8 @@ struct CompilerOutputs {"storage-layout", &CompilerOutputs::storageLayout}, {"transient-storage-layout", &CompilerOutputs::transientStorageLayout}, {"yul-cfg-json", &CompilerOutputs::yulCFGJson}, + {"ethdebug", &CompilerOutputs::ethdebug}, + {"ethdebug-runtime", &CompilerOutputs::ethdebugRuntime}, }; return components; } @@ -110,6 +112,8 @@ struct CompilerOutputs bool metadata = false; bool storageLayout = false; bool transientStorageLayout = false; + bool ethdebug = false; + bool ethdebugRuntime = false; }; struct CombinedJsonRequests diff --git a/test/cmdlineTests/ethdebug/args b/test/cmdlineTests/ethdebug/args new file mode 100644 index 000000000000..6edc3b560136 --- /dev/null +++ b/test/cmdlineTests/ethdebug/args @@ -0,0 +1 @@ +--ethdebug --via-ir --optimize --ir-optimized \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug/input.sol b/test/cmdlineTests/ethdebug/input.sol new file mode 100644 index 000000000000..25b9640ca565 --- /dev/null +++ b/test/cmdlineTests/ethdebug/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} + diff --git a/test/cmdlineTests/ethdebug/output b/test/cmdlineTests/ethdebug/output new file mode 100644 index 000000000000..41f243d9c488 --- /dev/null +++ b/test/cmdlineTests/ethdebug/output @@ -0,0 +1,42 @@ +======= Debug Data (ethdebug/format/info/resources) ======= +{"sources":["ethdebug/input.sol"]} + +======= ethdebug/input.sol:C ======= +Optimized IR: +/// ethdebug: enabled +/// @use-src 0:"ethdebug/input.sol" +object "C_6" { + code { + { + /// @src 0:60:101 "contract C {..." + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize("C_6_deployed") + codecopy(_1, dataoffset("C_6_deployed"), _2) + return(_1, _2) + } + } + /// @use-src 0:"ethdebug/input.sol" + object "C_6_deployed" { + code { + { + /// @src 0:60:101 "contract C {..." + if iszero(lt(calldatasize(), 4)) + { + if eq(0x26121ff0, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + return(0, 0) + } + } + revert(0, 0) + } + } + data ".metadata" hex"" + } +} + +Debug Data (ethdebug/format/program): +{} diff --git a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args new file mode 100644 index 000000000000..809fb09884d8 --- /dev/null +++ b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args @@ -0,0 +1 @@ +--ethdebug-runtime --ethdebug --via-ir --optimize --ir-optimized \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/input.sol b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/input.sol new file mode 100644 index 000000000000..25b9640ca565 --- /dev/null +++ b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} + diff --git a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output new file mode 100644 index 000000000000..3566824b9b03 --- /dev/null +++ b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output @@ -0,0 +1,44 @@ +======= Debug Data (ethdebug/format/info/resources) ======= +{"sources":["ethdebug_and_ethdebug_runtime/input.sol"]} + +======= ethdebug_and_ethdebug_runtime/input.sol:C ======= +Optimized IR: +/// ethdebug: enabled +/// @use-src 0:"ethdebug_and_ethdebug_runtime/input.sol" +object "C_6" { + code { + { + /// @src 0:60:101 "contract C {..." + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize("C_6_deployed") + codecopy(_1, dataoffset("C_6_deployed"), _2) + return(_1, _2) + } + } + /// @use-src 0:"ethdebug_and_ethdebug_runtime/input.sol" + object "C_6_deployed" { + code { + { + /// @src 0:60:101 "contract C {..." + if iszero(lt(calldatasize(), 4)) + { + if eq(0x26121ff0, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + return(0, 0) + } + } + revert(0, 0) + } + } + data ".metadata" hex"" + } +} + +Debug Data (ethdebug/format/program): +{} +Debug Data of the runtime part (ethdebug/format/program): +{} diff --git a/test/cmdlineTests/ethdebug_runtime/args b/test/cmdlineTests/ethdebug_runtime/args new file mode 100644 index 000000000000..dfc6038785a5 --- /dev/null +++ b/test/cmdlineTests/ethdebug_runtime/args @@ -0,0 +1 @@ +--ethdebug-runtime --via-ir --optimize --ir-optimized \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug_runtime/input.sol b/test/cmdlineTests/ethdebug_runtime/input.sol new file mode 100644 index 000000000000..25b9640ca565 --- /dev/null +++ b/test/cmdlineTests/ethdebug_runtime/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} + diff --git a/test/cmdlineTests/ethdebug_runtime/output b/test/cmdlineTests/ethdebug_runtime/output new file mode 100644 index 000000000000..8af39f64ef3c --- /dev/null +++ b/test/cmdlineTests/ethdebug_runtime/output @@ -0,0 +1,42 @@ +======= Debug Data (ethdebug/format/info/resources) ======= +{"sources":["ethdebug_runtime/input.sol"]} + +======= ethdebug_runtime/input.sol:C ======= +Optimized IR: +/// ethdebug: enabled +/// @use-src 0:"ethdebug_runtime/input.sol" +object "C_6" { + code { + { + /// @src 0:60:101 "contract C {..." + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize("C_6_deployed") + codecopy(_1, dataoffset("C_6_deployed"), _2) + return(_1, _2) + } + } + /// @use-src 0:"ethdebug_runtime/input.sol" + object "C_6_deployed" { + code { + { + /// @src 0:60:101 "contract C {..." + if iszero(lt(calldatasize(), 4)) + { + if eq(0x26121ff0, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + return(0, 0) + } + } + revert(0, 0) + } + } + data ".metadata" hex"" + } +} + +Debug Data of the runtime part (ethdebug/format/program): +{} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json new file mode 100644 index 000000000000..e7173abed3e1 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "irOptimized" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json new file mode 100644 index 000000000000..da701aec60f5 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json @@ -0,0 +1,214 @@ +{ + "contracts": { + "a.sol": { + "A1": { + "evm": { + "bytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A1_14\" { + code { + { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A1_14_deployed\") + codecopy(_1, dataoffset(\"A1_14_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 0:\"a.sol\" + object \"A1_14_deployed\" { + code { + { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xf0fdf834, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 0:112:117 \"x > 0\" */ iszero(/** @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + }, + "A2": { + "evm": { + "bytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A2_27\" { + code { + { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A2_27_deployed\") + codecopy(_1, dataoffset(\"A2_27_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 0:\"a.sol\" + object \"A2_27_deployed\" { + code { + { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xf0fdf834, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 0:178:183 \"x > 0\" */ iszero(/** @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + }, + "b.sol": { + "A1": { + "evm": { + "bytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"A1_42\" { + code { + { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A1_42_deployed\") + codecopy(_1, dataoffset(\"A1_42_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 1:\"b.sol\" + object \"A1_42_deployed\" { + code { + { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xcd580ff3, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 1:112:117 \"x > 0\" */ iszero(/** @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + }, + "B2": { + "evm": { + "bytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"B2_55\" { + code { + { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"B2_55_deployed\") + codecopy(_1, dataoffset(\"B2_55_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 1:\"b.sol\" + object \"B2_55_deployed\" { + code { + { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xcd580ff3, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 1:178:183 \"x > 0\" */ iszero(/** @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + } + }, + "ethdebug": { + "sources": [ + "a.sol", + "b.sol" + ] + }, + "sources": { + "a.sol": { + "id": 0 + }, + "b.sol": { + "id": 1 + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json new file mode 100644 index 000000000000..e45f27f3caa8 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "irOptimized" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json new file mode 100644 index 000000000000..4e41e41c385b --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json @@ -0,0 +1,226 @@ +{ + "contracts": { + "a.sol": { + "A1": { + "evm": { + "bytecode": { + "ethdebug": {} + }, + "deployedBytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A1_14\" { + code { + { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A1_14_deployed\") + codecopy(_1, dataoffset(\"A1_14_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 0:\"a.sol\" + object \"A1_14_deployed\" { + code { + { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xf0fdf834, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 0:112:117 \"x > 0\" */ iszero(/** @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + }, + "A2": { + "evm": { + "bytecode": { + "ethdebug": {} + }, + "deployedBytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A2_27\" { + code { + { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A2_27_deployed\") + codecopy(_1, dataoffset(\"A2_27_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 0:\"a.sol\" + object \"A2_27_deployed\" { + code { + { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xf0fdf834, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 0:178:183 \"x > 0\" */ iszero(/** @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + }, + "b.sol": { + "A1": { + "evm": { + "bytecode": { + "ethdebug": {} + }, + "deployedBytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"A1_42\" { + code { + { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A1_42_deployed\") + codecopy(_1, dataoffset(\"A1_42_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 1:\"b.sol\" + object \"A1_42_deployed\" { + code { + { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xcd580ff3, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 1:112:117 \"x > 0\" */ iszero(/** @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + }, + "B2": { + "evm": { + "bytecode": { + "ethdebug": {} + }, + "deployedBytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"B2_55\" { + code { + { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"B2_55_deployed\") + codecopy(_1, dataoffset(\"B2_55_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 1:\"b.sol\" + object \"B2_55_deployed\" { + code { + { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xcd580ff3, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 1:178:183 \"x > 0\" */ iszero(/** @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + } + }, + "ethdebug": { + "sources": [ + "a.sol", + "b.sol" + ] + }, + "sources": { + "a.sol": { + "id": 0 + }, + "b.sol": { + "id": 1 + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json new file mode 100644 index 000000000000..9e104dc177cc --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": { + "*": [ + "evm.deployedBytecode.ethdebug", "irOptimized" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json new file mode 100644 index 000000000000..3ad7350a9fe8 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json @@ -0,0 +1,214 @@ +{ + "contracts": { + "a.sol": { + "A1": { + "evm": { + "deployedBytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A1_14\" { + code { + { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A1_14_deployed\") + codecopy(_1, dataoffset(\"A1_14_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 0:\"a.sol\" + object \"A1_14_deployed\" { + code { + { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xf0fdf834, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 0:112:117 \"x > 0\" */ iszero(/** @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + }, + "A2": { + "evm": { + "deployedBytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A2_27\" { + code { + { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A2_27_deployed\") + codecopy(_1, dataoffset(\"A2_27_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 0:\"a.sol\" + object \"A2_27_deployed\" { + code { + { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xf0fdf834, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 0:178:183 \"x > 0\" */ iszero(/** @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + }, + "b.sol": { + "A1": { + "evm": { + "deployedBytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"A1_42\" { + code { + { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"A1_42_deployed\") + codecopy(_1, dataoffset(\"A1_42_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 1:\"b.sol\" + object \"A1_42_deployed\" { + code { + { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xcd580ff3, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 1:112:117 \"x > 0\" */ iszero(/** @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + }, + "B2": { + "evm": { + "deployedBytecode": { + "ethdebug": {} + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"B2_55\" { + code { + { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize(\"B2_55_deployed\") + codecopy(_1, dataoffset(\"B2_55_deployed\"), _2) + return(_1, _2) + } + } + /// @use-src 1:\"b.sol\" + object \"B2_55_deployed\" { + code { + { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + if iszero(lt(calldatasize(), 4)) + { + if eq(0xcd580ff3, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } + if /** @src 1:178:183 \"x > 0\" */ iszero(/** @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 1) + revert(0, 0x24) + } + return(0, 0) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + } + }, + "ethdebug": { + "sources": [ + "a.sol", + "b.sol" + ] + }, + "sources": { + "a.sol": { + "id": 0 + }, + "b.sol": { + "id": 1 + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/args b/test/cmdlineTests/standard_yul_ethdebug_bytecode/args new file mode 100644 index 000000000000..18532c5a6d3f --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/args @@ -0,0 +1 @@ +--allow-paths . diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/in.yul b/test/cmdlineTests/standard_yul_ethdebug_bytecode/in.yul new file mode 100644 index 000000000000..920aef8e9dc2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/in.yul @@ -0,0 +1,17 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + sstore(0, 42) + } + /// @src 0:60:101 "contract C {..." + } +} + diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json b/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json new file mode 100644 index 000000000000..86761f23659c --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json @@ -0,0 +1,14 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": {"*": ["evm.bytecode.ethdebug", "irOptimized"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json b/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json new file mode 100644 index 000000000000..0e93c5b77f30 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json @@ -0,0 +1,31 @@ +{ + "contracts": { + "C": { + "C_6_deployed": { + "evm": { + "bytecode": { + "ethdebug": { + "not yet implemented @ MachineAssemblyObject::ethdebug": true + } + } + }, + "irOptimized": "/// ethdebug: enabled +/// @use-src 0:\"input.sol\" +object \"C_6_deployed\" { + code { + { + /// @src 0:77:99 + sstore(0, 42) + } + } +} +" + } + } + }, + "ethdebug": { + "sources": [ + "C" + ] + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/args b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/args new file mode 100644 index 000000000000..18532c5a6d3f --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/args @@ -0,0 +1 @@ +--allow-paths . diff --git a/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/in.yul b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/in.yul new file mode 100644 index 000000000000..920aef8e9dc2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/in.yul @@ -0,0 +1,17 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + sstore(0, 42) + } + /// @src 0:60:101 "contract C {..." + } +} + diff --git a/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/input.json b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/input.json new file mode 100644 index 000000000000..e132c654f042 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/input.json @@ -0,0 +1,11 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "outputSelection": { + "*": {"*": ["evm.deployedBytecode.ethdebug"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/output.json b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/output.json new file mode 100644 index 000000000000..1380c31d7c10 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "\"evm.deployedBytecode.ethdebug\" cannot be used for Yul.", + "message": "\"evm.deployedBytecode.ethdebug\" cannot be used for Yul.", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/yul_ethdebug/args b/test/cmdlineTests/yul_ethdebug/args new file mode 100644 index 000000000000..715f3fb4848b --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug/args @@ -0,0 +1 @@ +--ethdebug --strict-assembly --optimize --ir-optimized \ No newline at end of file diff --git a/test/cmdlineTests/yul_ethdebug/input.yul b/test/cmdlineTests/yul_ethdebug/input.yul new file mode 100644 index 000000000000..acd0b45f5335 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug/input.yul @@ -0,0 +1,18 @@ +object "object" { + code { + let a + let b + { + function z() -> y + { y := calldataload(0) } + a := z() + } + { + function z() -> y + { y := calldataload(0x20) } + b := z() + } + sstore(a, b) + } +} + diff --git a/test/cmdlineTests/yul_ethdebug/output b/test/cmdlineTests/yul_ethdebug/output new file mode 100644 index 000000000000..702fe057d532 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug/output @@ -0,0 +1,18 @@ +======= Debug Data (ethdebug/format/info/resources) ======= +{"sources":["yul_ethdebug/input.yul"]} + +======= yul_ethdebug/input.yul (EVM) ======= + +Pretty printed source: +/// ethdebug: enabled +object "object" { + code { + { + sstore(calldataload(0), calldataload(0x20)) + } + } +} + + +Debug Data (ethdebug/format/program): +{"not yet implemented @ MachineAssemblyObject::ethdebug":true} diff --git a/test/cmdlineTests/yul_ethdebug_runtime/args b/test/cmdlineTests/yul_ethdebug_runtime/args new file mode 100644 index 000000000000..3bedf2d9e437 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug_runtime/args @@ -0,0 +1 @@ +--ethdebug-runtime --strict-assembly \ No newline at end of file diff --git a/test/cmdlineTests/yul_ethdebug_runtime/err b/test/cmdlineTests/yul_ethdebug_runtime/err new file mode 100644 index 000000000000..ed5894632c43 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug_runtime/err @@ -0,0 +1 @@ +Error: The following outputs are not supported in assembler mode: --ethdebug-runtime. diff --git a/test/cmdlineTests/yul_ethdebug_runtime/exit b/test/cmdlineTests/yul_ethdebug_runtime/exit new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug_runtime/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/yul_ethdebug_runtime/input.yul b/test/cmdlineTests/yul_ethdebug_runtime/input.yul new file mode 100644 index 000000000000..acd0b45f5335 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug_runtime/input.yul @@ -0,0 +1,18 @@ +object "object" { + code { + let a + let b + { + function z() -> y + { y := calldataload(0) } + a := z() + } + { + function z() -> y + { y := calldataload(0x20) } + b := z() + } + sstore(a, b) + } +} + diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 4cb0b3c93068..80cba338202d 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -33,6 +33,7 @@ #include #include +#include using namespace solidity::evmasm; using namespace std::string_literals; @@ -152,6 +153,147 @@ Json compile(std::string _input) return ret; } +Json createLanguageAndSourcesSection(std::string const& _language, std::map const& _sources, bool _contentNode = true) +{ + Json result = Json::object(); + result["language"] = _language; + result["sources"] = Json::object(); + for (auto const& source: _sources) + { + result["sources"][source.first] = Json::object(); + if (_contentNode) + result["sources"][source.first]["content"] = source.second; + else + result["sources"][source.first] = source.second; + } + return result; +} + +class Code +{ +public: + virtual ~Code() = default; + explicit Code(std::map _code = {}) : m_code(std::move(_code)) {} + [[nodiscard]] virtual Json json() const = 0; +protected: + std::map m_code; +}; + +class SolidityCode: public Code +{ +public: + explicit SolidityCode(std::map _code = { + {"fileA", "pragma solidity >=0.0; contract C { function f() public pure {} }"} + }) : Code(std::move(_code)) {} + [[nodiscard]] Json json() const override + { + return createLanguageAndSourcesSection("Solidity", m_code); + } +}; + +class YulCode: public Code +{ +public: + explicit YulCode(std::map _code = { + {"fileA", "{}"} + }) : Code(std::move(_code)) {} + [[nodiscard]] Json json() const override + { + return createLanguageAndSourcesSection("Yul", m_code); + } +}; + +class EvmAssemblyCode: public Code +{ +public: + explicit EvmAssemblyCode(std::map _code = { + {"fileA", Json::parse(R"( + { + "assemblyJson": { + ".code": [ + { + "begin": 36, + "end": 51, + "name": "PUSH", + "source": 0, + "value": "0" + } + ], + "sourceList": [ + "" + ] + } + } + )")} + }) : Code(std::move(_code)) {} + [[nodiscard]] Json json() const override + { + return createLanguageAndSourcesSection("EVMAssembly", m_code, false); + } +}; + +class SolidityAstCode: public Code +{ +public: + explicit SolidityAstCode(std::map _code = { + {"fileA", Json::parse(R"( + { + "ast": { + "absolutePath": "empty_contract.sol", + "exportedSymbols": { + "test": [ + 1 + ] + }, + "id": 2, + "nodeType": "SourceUnit", + "nodes": [ + { + "abstract": false, + "baseContracts": [], + "canonicalName": "test", + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 1, + "linearizedBaseContracts": [ + 1 + ], + "name": "test", + "nameLocation": "9:4:0", + "nodeType": "ContractDefinition", + "nodes": [], + "scope": 2, + "src": "0:17:0", + "usedErrors": [] + } + ], + "src": "0:124:0" + }, + "id": 0 + } + )")} + }) : Code(std::move(_code)) {} + [[nodiscard]] Json json() const override + { + return createLanguageAndSourcesSection("SolidityAST", m_code); + } +}; + +Json generateStandardJson(bool _viaIr, Json const& _debugInfoSelection, Json const& _outputSelection, Code const& _code = SolidityCode(), bool _advancedOutputSelection = false) +{ + Json result = _code.json(); + result["settings"] = Json::object(); + result["settings"]["viaIR"] = _viaIr; + if (!_debugInfoSelection.empty()) + result["settings"]["debug"]["debugInfo"] = _debugInfoSelection; + if (_advancedOutputSelection) + result["settings"]["outputSelection"] = _outputSelection; + else + result["settings"]["outputSelection"]["*"]["*"] = _outputSelection; + return result; +} + } // end anonymous namespace BOOST_AUTO_TEST_SUITE(StandardCompiler) @@ -1782,6 +1924,375 @@ BOOST_AUTO_TEST_CASE(source_location_of_bare_block) BOOST_REQUIRE(sourceMap.find(sourceRef) != std::string::npos); } +BOOST_AUTO_TEST_CASE(ethdebug_excluded_from_wildcards) +{ + frontend::StandardCompiler compiler; + // excluded from output selection wildcard + Json result = compiler.compile(generateStandardJson(true, {}, Json::array({"*"}))); + BOOST_REQUIRE(result.dump().find("ethdebug") == std::string::npos); + // excluded from debug info selection wildcard + result = compiler.compile(generateStandardJson(true, {"*"}, Json::array({"ir"}))); + BOOST_REQUIRE(result.dump().find("ethdebug") == std::string::npos); + // excluded from both - just in case ;) + result = compiler.compile(generateStandardJson(true, {"*"}, Json::array({"*"}))); + BOOST_REQUIRE(result.dump().find("ethdebug") == std::string::npos); +} + +BOOST_AUTO_TEST_CASE(ethdebug_debug_info_ethdebug) +{ + static std::vector>>> tests{ + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"*"})), + "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected.", + std::nullopt, + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"*"})), + "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected.", + std::nullopt, + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt, + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt, + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt, + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"irOptimized"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.bytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"irOptimized", "evm.bytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"irOptimized", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"irOptimized", "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"ir"}), YulCode()), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"irOptimized"}), YulCode()), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, Json::array({"ethdebugs"}), Json::array({"irOptimized"}), YulCode()), + "Invalid value in settings.debug.debugInfo.", + {} + }, + { + generateStandardJson( + true, Json::array({"ethdebug"}), { + {"fileA", {{"contractA", Json::array({"evm.deployedBytecode.bin"})}}}, + {"fileB", {{"contractB", Json::array({"evm.bytecode.bin"})}}} + }, + SolidityCode({ + {"fileA", "pragma solidity >=0.0; contract contractA { function f() public pure {} }"}, + {"fileB", "pragma solidity >=0.0; contract contractB { function f() public pure {} }"} + }), true + ), + "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected.", + std::nullopt, + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"*"}), EvmAssemblyCode()), + "'settings.debug.debugInfo' 'ethdebug' is only supported for languages 'Solidity' and 'Yul'.", + std::nullopt, + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"*"}), SolidityAstCode()), + "'settings.debug.debugInfo' 'ethdebug' is only supported for languages 'Solidity' and 'Yul'.", + std::nullopt, + }, + }; + frontend::StandardCompiler compiler; + for (auto const& test: tests) + { + Json result = compiler.compile(std::get<0>(test)); + BOOST_REQUIRE(!std::get<1>(test).empty() ? result.contains("errors") : result.contains("contracts")); + if (!std::get<1>(test).empty()) + for (auto const& e: result["errors"]) + BOOST_REQUIRE(e["message"] == std::get<1>(test)); + if (std::get<2>(test).has_value()) + BOOST_REQUIRE((*std::get<2>(test))(result)); + } +} + +BOOST_AUTO_TEST_CASE(ethdebug_ethdebug_output) +{ + static std::vector>>> tests{ + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, {}, Json::array({"evm.bytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, {}, Json::array({"evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, {}, Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(true, Json::array({"location"}), Json::array({"evm.bytecode.ethdebug"})), + "'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output.", + std::nullopt + }, + { + generateStandardJson(true, Json::array({"location"}), Json::array({"evm.deployedBytecode.ethdebug"})), + "'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output.", + std::nullopt + }, + { + generateStandardJson(true, Json::array({"location"}), Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + "'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output.", + std::nullopt + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug") && + result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug") && + result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos && result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode.ethdebug", "ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos && result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebugs"})), + {}, + [](const Json& result) + { + return !result.contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode.ethdebugs"})), + {}, + [](const Json& result) + { + return !result.contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos && result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug") && + result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "ir"}), YulCode()), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos && result["contracts"]["fileA"]["object"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode.ethdebug", "ir"}), YulCode()), + {"\"evm.deployedBytecode.ethdebug\" cannot be used for Yul."}, + std::nullopt + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "ir"}), YulCode()), + {"\"evm.deployedBytecode.ethdebug\" cannot be used for Yul."}, + std::nullopt + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode"})), + {}, + [](const Json& result) + { + return result.dump().find("ethdebug") == std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode"})), + {}, + [](const Json& result) + { + return result.dump().find("ethdebug") == std::string::npos; + } + }, + { + generateStandardJson( + true, {}, { + {"fileA", {{"contractA", Json::array({"evm.deployedBytecode.ethdebug"})}}}, + {"fileB", {{"contractB", Json::array({"evm.bytecode.ethdebug"})}}} + }, + SolidityCode({ + {"fileA", "pragma solidity >=0.0; contract contractA { function f() public pure {} }"}, + {"fileB", "pragma solidity >=0.0; contract contractB { function f() public pure {} }"} + }), true + ), + {}, + [](const Json& result) + { + return result["contracts"]["fileA"]["contractA"]["evm"]["deployedBytecode"].contains("ethdebug") && + result["contracts"]["fileB"]["contractB"]["evm"]["bytecode"].contains("ethdebug") && result.contains("ethdebug"); + } + } + }; + frontend::StandardCompiler compiler; + for (auto const& test: tests) + { + Json result = compiler.compile(std::get<0>(test)); + if (!std::get<1>(test).empty()) + for (auto const& e: result["errors"]) + BOOST_REQUIRE(e["message"] == std::get<1>(test)); + if (std::get<2>(test).has_value()) + BOOST_REQUIRE((*std::get<2>(test))(result)); + } +} + BOOST_AUTO_TEST_SUITE_END() } // end namespaces diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index e64558bd48a9..a9f4c59a74ac 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -63,7 +63,7 @@ YulStack yul::test::parseYul( _optimiserSettings.has_value() ? *_optimiserSettings : (CommonOptions::get().optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal()), - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); bool successful = yulStack.parseAndAnalyze(_sourceUnitName, _source); if (!successful) diff --git a/test/libyul/EVMCodeTransformTest.cpp b/test/libyul/EVMCodeTransformTest.cpp index 624a44c3e538..4fff5a22e70d 100644 --- a/test/libyul/EVMCodeTransformTest.cpp +++ b/test/libyul/EVMCodeTransformTest.cpp @@ -58,7 +58,7 @@ TestCase::TestResult EVMCodeTransformTest::run(std::ostream& _stream, std::strin CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, settings, - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); yulStack.parseAndAnalyze("", m_source); if (yulStack.hasErrors()) diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp index 23d8aaa57f8e..446348fa0ba3 100644 --- a/test/libyul/ObjectParser.cpp +++ b/test/libyul/ObjectParser.cpp @@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(to_string) solidity::test::CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::none(), - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); BOOST_REQUIRE(asmStack.parseAndAnalyze("source", code)); BOOST_CHECK_EQUAL(asmStack.print(), expectation); diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 6d19df01b3f8..8dfcedac8548 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -1412,6 +1412,356 @@ BOOST_AUTO_TEST_CASE(cli_include_paths_ambiguous_import) BOOST_REQUIRE(!result.success); } +BOOST_AUTO_TEST_CASE(cli_ethdebug_no_ethdebug_in_help) +{ + OptionsReaderAndMessages result = runCLI({"solc", "--help"}); + BOOST_REQUIRE(result.stdoutContent.find("ethdebug") == std::string::npos); + // just in case + BOOST_REQUIRE(result.stderrContent.find("ethdebug") == std::string::npos); +} + +BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_outputs) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + createFilesWithParentDirs({tempDir.path() / "input.sol"}); + static std::vector, std::string>> tests{ + { + {"solc", "--ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + }, + { + {"solc", "--ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --ethdebug is not supported with --import-asm-json.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + }, + { + {"solc", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n" + }, + { + {"solc", "--via-ir", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + }, + { + {"solc", "--via-ir", "--ethdebug-runtime", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + }, + { + {"solc", "--via-ir", "--ethdebug-runtime", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + }, + { + {"solc", "--ethdebug-runtime", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --ethdebug-runtime is not supported with --import-asm-json.\n" + }, + { + {"solc", "--via-ir", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --debug-info is not supported with --import-asm-json.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --debug-info is not supported with --import-asm-json.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.json"}, + "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + } + }; + for (auto const& test: tests) + { + OptionsReaderAndMessages result = runCLI(test.first, ""); + BOOST_REQUIRE(!result.success); + BOOST_CHECK_EQUAL(result.stderrContent, test.second); + } +} + +BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_input_modes) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + createFilesWithParentDirs({tempDir.path() / "input.json"}); + static std::vector, std::string>> tests{ + { + {"solc", "--ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --ethdebug is not supported with --import-asm-json.\n" + }, + { + {"solc", "--ethdebug", "--via-ir", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: The following options are not supported in the current input mode: --via-ir\n" + }, + { + {"solc", "--ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --ethdebug is not supported with --import-asm-json.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --debug-info is not supported with --import-asm-json.\n" + }, + { + {"solc", "--ethdebug", "--import-ast", tempDir.path().string() + "/input.json"}, + "Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n" + }, + { + {"solc", "--ethdebug", "--via-ir", "--import-ast", tempDir.path().string() + "/input.json"}, + "Error: Invalid input mode for --debug-info ethdebug / --ethdebug / --ethdebug-runtime.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--ir", "--import-ast", tempDir.path().string() + "/input.json"}, + "Error: Invalid input mode for --debug-info ethdebug / --ethdebug / --ethdebug-runtime.\n" + } + }; + for (auto const& test: tests) + { + OptionsReaderAndMessages result = runCLI(test.first, ""); + BOOST_REQUIRE(!result.success); + BOOST_CHECK_EQUAL(result.stderrContent, test.second); + } +} + +BOOST_AUTO_TEST_CASE(cli_ethdebug_debug_info_ethdebug) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + createFilesWithParentDirs({tempDir.path() / "input.sol"}, "pragma solidity >=0.0; contract C { function f() public pure {} }"); + createFilesWithParentDirs({tempDir.path() / "input.yul"}, "{}"); + static std::vector, std::vector, std::vector>> tests{ + { + {"solc", "--debug-info", "ethdebug", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ir", tempDir.path().string() + "/input.sol"}, + {}, + {"/// ethdebug: enabled"}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {}, + {"/// ethdebug: enabled"}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program):"}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program):"}, + }, + { + {"solc", "--debug-info", "ethdebug", "--strict-assembly", tempDir.path().string() + "/input.yul"}, + {}, + {"/// ethdebug: enabled", "Pretty printed source", "Binary representation", "Text representation"}, + }, + { + {"solc", "--ethdebug", "--strict-assembly", tempDir.path().string() + "/input.yul"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program):"}, + }, + { + {"solc", "--ethdebug-runtime", "--strict-assembly", tempDir.path().string() + "/input.yul"}, + {"Error: The following outputs are not supported in assembler mode: --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--strict-assembly", tempDir.path().string() + "/input.yul"}, + {"Error: The following outputs are not supported in assembler mode: --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug-runtime", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", "--ethdebug-runtime", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program):", "Debug Data of the runtime part (ethdebug/format/program):"}, + }, + { + {"solc", "--debug-info", "location", "--ethdebug", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "location", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "location", "--ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "all", "--ethdebug", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "all", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "all", "--ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + }; + for (auto const& test: tests) + { + OptionsReaderAndMessages result{runCLI(std::get<0>(test), "")}; + BOOST_REQUIRE(!std::get<1>(test).empty() ? !result.success : result.success); + for (auto const& error : std::get<1>(test)) + BOOST_REQUIRE(result.stderrContent == error); + for (auto const& output : std::get<2>(test)) + BOOST_REQUIRE(result.stdoutContent.find(output) != std::string::npos); + } +} + +BOOST_AUTO_TEST_CASE(cli_ethdebug_ethdebug_output) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + createFilesWithParentDirs({tempDir.path() / "input.sol"}, "pragma solidity >=0.0; contract C { function f() public pure {} }"); + static std::vector, std::vector, std::vector>> tests{ + { + {"solc", "--ethdebug", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--ethdebug-runtime", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)"}, + }, + { + {"solc", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program)"}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "Debug Data of the runtime part (ethdebug/format/program)"}, + }, + { + {"solc", "--ethdebug", "--via-ir", "--ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug-runtime", "--via-ir", "--ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", "--ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug-runtime", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug-runtime", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + }; + for (auto const& test: tests) + { + OptionsReaderAndMessages result{runCLI(std::get<0>(test), "")}; + BOOST_REQUIRE(!std::get<1>(test).empty() ? !result.success : result.success); + for (auto const& error : std::get<1>(test)) + BOOST_REQUIRE(result.stderrContent == error); + for (auto const& output : std::get<2>(test)) + BOOST_REQUIRE(result.stdoutContent.find(output) != std::string::npos); + } +} + BOOST_AUTO_TEST_SUITE_END() } // namespace solidity::frontend::test diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 227b1b9213d8..be3e25d3302c 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -628,6 +628,49 @@ BOOST_AUTO_TEST_CASE(invalid_optimizer_sequence_without_optimize) } } +BOOST_AUTO_TEST_CASE(ethdebug) +{ + CommandLineOptions commandLineOptions = parseCommandLine({"solc", "contract.sol", "--debug-info", "ethdebug", "--ethdebug", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, true); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, false); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--debug-info", "ethdebug", "--ethdebug-runtime", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--ethdebug", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, true); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, false); + // debug-info "ethdebug" selected implicitly, + // if compiled with --ethdebug or --ethdebug-runtime and no debug-info was selected. + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--ethdebug-runtime", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--ethdebug", "--ethdebug-runtime", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, true); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--debug-info", "ethdebug", "--ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ir, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--debug-info", "ethdebug", "--ir-optimized"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.irOptimized, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace solidity::frontend::test diff --git a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp index 595aecdca3f4..5a9192bc3a05 100644 --- a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp @@ -41,7 +41,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) std::nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::minimal(), - langutil::DebugInfoSelection::All() + langutil::DebugInfoSelection::AllExceptExperimental() ); if (!stack.parseAndAnalyze("source", input)) diff --git a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp index ffeb14702183..a4515b30957a 100644 --- a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp @@ -65,7 +65,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) std::nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); try { diff --git a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp index 7553c81c0f44..4543804926ee 100644 --- a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp @@ -42,7 +42,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) std::nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); if (!stack.parseAndAnalyze("source", input)) From 7ea985d54daa79ca623623b719eb4aa9d26f0411 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Thu, 16 Jan 2025 15:24:13 +0100 Subject: [PATCH 2/2] Error when ethdebug is used with optimization. --- libsolidity/interface/StandardCompiler.cpp | 3 + solc/CommandLineParser.cpp | 15 +- test/cmdlineTests/ethdebug/args | 2 +- test/cmdlineTests/ethdebug/output | 111 ++- .../ethdebug_and_ethdebug_runtime/args | 2 +- .../ethdebug_and_ethdebug_runtime/output | 111 ++- .../ethdebug_enabled_optimization/args | 1 + .../ethdebug_enabled_optimization/err | 1 + .../ethdebug_enabled_optimization/exit | 1 + .../ethdebug_enabled_optimization/input.sol | 7 + test/cmdlineTests/ethdebug_runtime/args | 2 +- test/cmdlineTests/ethdebug_runtime/output | 111 ++- .../input.json | 4 +- .../output.json | 692 +++++++++++++++--- .../input.json | 4 +- .../output.json | 692 +++++++++++++++--- .../input.json | 24 + .../output.json | 11 + .../input.json | 4 +- .../output.json | 692 +++++++++++++++--- .../input.json | 21 + .../output.json | 11 + .../input.json | 24 + .../output.json | 11 + .../standard_yul_ethdebug_bytecode/input.json | 5 +- .../output.json | 12 +- .../standard_yul_ethdebug_irOptimized/args | 1 + .../standard_yul_ethdebug_irOptimized/in.yul | 17 + .../input.json | 11 + .../output.json | 11 + .../standard_yul_ethdebug_optimize/args | 1 + .../standard_yul_ethdebug_optimize/in.yul | 17 + .../standard_yul_ethdebug_optimize/input.json | 14 + .../output.json | 11 + test/libsolidity/StandardCompiler.cpp | 17 +- test/solc/CommandLineInterface.cpp | 55 +- test/solc/CommandLineParser.cpp | 6 - 37 files changed, 2362 insertions(+), 373 deletions(-) create mode 100644 test/cmdlineTests/ethdebug_enabled_optimization/args create mode 100644 test/cmdlineTests/ethdebug_enabled_optimization/err create mode 100644 test/cmdlineTests/ethdebug_enabled_optimization/exit create mode 100644 test/cmdlineTests/ethdebug_enabled_optimization/input.sol create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/input.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/output.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/input.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/output.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_optimize/input.json create mode 100644 test/cmdlineTests/standard_output_selection_ethdebug_optimize/output.json create mode 100644 test/cmdlineTests/standard_yul_ethdebug_irOptimized/args create mode 100644 test/cmdlineTests/standard_yul_ethdebug_irOptimized/in.yul create mode 100644 test/cmdlineTests/standard_yul_ethdebug_irOptimized/input.json create mode 100644 test/cmdlineTests/standard_yul_ethdebug_irOptimized/output.json create mode 100644 test/cmdlineTests/standard_yul_ethdebug_optimize/args create mode 100644 test/cmdlineTests/standard_yul_ethdebug_optimize/in.yul create mode 100644 test/cmdlineTests/standard_yul_ethdebug_optimize/input.json create mode 100644 test/cmdlineTests/standard_yul_ethdebug_optimize/output.json diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index bcdb2901d053..520f4d5f1c8f 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -1204,6 +1204,9 @@ std::variant StandardCompiler::parseI ) return formatFatalError(Error::Type::FatalError, "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected."); + if (isEthdebugRequested(ret.outputSelection) && (ret.optimiserSettings.runYulOptimiser || isArtifactRequested(ret.outputSelection, "*", "*", "irOptimized", false))) + return formatFatalError(Error::Type::FatalError, "Optimization is not yet supported with ethdebug."); + return {std::move(ret)}; } diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index f62abb3c6043..56be4195dcc8 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -1485,15 +1485,18 @@ void CommandLineParser::processArgs() ); bool incompatibleEthdebugOutputs = - m_options.compiler.outputs.asmJson || m_options.compiler.outputs.irAstJson || m_options.compiler.outputs.irOptimizedAstJson; + m_options.compiler.outputs.asmJson || m_options.compiler.outputs.irAstJson || m_options.compiler.outputs.irOptimizedAstJson || + m_options.compiler.outputs.irOptimized || m_options.optimizer.optimizeYul || m_options.optimizer.optimizeEvmasm; bool incompatibleEthdebugInputs = m_options.input.mode != InputMode::Compiler; static std::string enableEthdebugMessage = "--" + CompilerOutputs::componentName(&CompilerOutputs::ethdebug) + " / --" + CompilerOutputs::componentName(&CompilerOutputs::ethdebugRuntime); - static std::string enableIrMessage = - "--" + CompilerOutputs::componentName(&CompilerOutputs::ir) + " / --" + CompilerOutputs::componentName(&CompilerOutputs::irOptimized); + static std::string incompatibleEthdebugOptimizerMessage = + "--" + g_strOptimize + " / --" + CompilerOutputs::componentName(&CompilerOutputs::irOptimized); + + static std::string enableIrMessage = "--" + CompilerOutputs::componentName(&CompilerOutputs::ir); if (m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) { @@ -1506,7 +1509,7 @@ void CommandLineParser::processArgs() if (incompatibleEthdebugOutputs) solThrow( CommandLineValidationError, - enableEthdebugMessage + " output can only be used with " + enableIrMessage + "." + enableEthdebugMessage + " output can only be used with " + enableIrMessage + ". Optimization is not yet supported with ethdebug, e.g. no support for " + incompatibleEthdebugOptimizerMessage + " yet." ); if (!m_options.output.debugInfoSelection.has_value()) @@ -1526,11 +1529,11 @@ void CommandLineParser::processArgs() if ( m_options.output.debugInfoSelection.has_value() && m_options.output.debugInfoSelection->ethdebug && - (!(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized || m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) || incompatibleEthdebugOutputs) + (!(m_options.compiler.outputs.ir || m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) || incompatibleEthdebugOutputs) ) solThrow( CommandLineValidationError, - "--debug-info ethdebug can only be used with " + enableIrMessage + " and/or " + enableEthdebugMessage + "." + "--debug-info ethdebug can only be used with " + enableIrMessage + " and/or " + enableEthdebugMessage + ". Optimization is not yet supported with ethdebug, e.g. no support for " + incompatibleEthdebugOptimizerMessage + " yet." ); if (m_options.output.debugInfoSelection.has_value() && m_options.output.debugInfoSelection->ethdebug && incompatibleEthdebugInputs) diff --git a/test/cmdlineTests/ethdebug/args b/test/cmdlineTests/ethdebug/args index 6edc3b560136..ac83894b301f 100644 --- a/test/cmdlineTests/ethdebug/args +++ b/test/cmdlineTests/ethdebug/args @@ -1 +1 @@ ---ethdebug --via-ir --optimize --ir-optimized \ No newline at end of file +--ethdebug --via-ir --ir \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug/output b/test/cmdlineTests/ethdebug/output index 41f243d9c488..375c5cf900af 100644 --- a/test/cmdlineTests/ethdebug/output +++ b/test/cmdlineTests/ethdebug/output @@ -2,41 +2,120 @@ {"sources":["ethdebug/input.sol"]} ======= ethdebug/input.sol:C ======= -Optimized IR: +IR: /// ethdebug: enabled /// @use-src 0:"ethdebug/input.sol" object "C_6" { code { - { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 "contract C {..." + function constructor_C_6() { + /// @src 0:60:101 "contract C {..." - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize("C_6_deployed") - codecopy(_1, dataoffset("C_6_deployed"), _2) - return(_1, _2) + } + /// @src 0:60:101 "contract C {..." + } /// @use-src 0:"ethdebug/input.sol" object "C_6_deployed" { code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:60:101 "contract C {..." - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 { - if eq(0x26121ff0, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } - return(0, 0) - } + // f() + + external_fun_f_5() } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @ast-id 5 + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + + } + /// @src 0:60:101 "contract C {..." + } + data ".metadata" hex"" } + } + Debug Data (ethdebug/format/program): {} diff --git a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args index 809fb09884d8..18053bcdac95 100644 --- a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args +++ b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args @@ -1 +1 @@ ---ethdebug-runtime --ethdebug --via-ir --optimize --ir-optimized \ No newline at end of file +--ethdebug-runtime --ethdebug --via-ir --ir \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output index 3566824b9b03..000f29c4df1a 100644 --- a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output +++ b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output @@ -2,42 +2,121 @@ {"sources":["ethdebug_and_ethdebug_runtime/input.sol"]} ======= ethdebug_and_ethdebug_runtime/input.sol:C ======= -Optimized IR: +IR: /// ethdebug: enabled /// @use-src 0:"ethdebug_and_ethdebug_runtime/input.sol" object "C_6" { code { - { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 "contract C {..." + function constructor_C_6() { + /// @src 0:60:101 "contract C {..." - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize("C_6_deployed") - codecopy(_1, dataoffset("C_6_deployed"), _2) - return(_1, _2) + } + /// @src 0:60:101 "contract C {..." + } /// @use-src 0:"ethdebug_and_ethdebug_runtime/input.sol" object "C_6_deployed" { code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:60:101 "contract C {..." - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 { - if eq(0x26121ff0, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } - return(0, 0) - } + // f() + + external_fun_f_5() } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @ast-id 5 + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + + } + /// @src 0:60:101 "contract C {..." + } + data ".metadata" hex"" } + } + Debug Data (ethdebug/format/program): {} Debug Data of the runtime part (ethdebug/format/program): diff --git a/test/cmdlineTests/ethdebug_enabled_optimization/args b/test/cmdlineTests/ethdebug_enabled_optimization/args new file mode 100644 index 000000000000..6edc3b560136 --- /dev/null +++ b/test/cmdlineTests/ethdebug_enabled_optimization/args @@ -0,0 +1 @@ +--ethdebug --via-ir --optimize --ir-optimized \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug_enabled_optimization/err b/test/cmdlineTests/ethdebug_enabled_optimization/err new file mode 100644 index 000000000000..082f6feee994 --- /dev/null +++ b/test/cmdlineTests/ethdebug_enabled_optimization/err @@ -0,0 +1 @@ +Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet. diff --git a/test/cmdlineTests/ethdebug_enabled_optimization/exit b/test/cmdlineTests/ethdebug_enabled_optimization/exit new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/test/cmdlineTests/ethdebug_enabled_optimization/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/ethdebug_enabled_optimization/input.sol b/test/cmdlineTests/ethdebug_enabled_optimization/input.sol new file mode 100644 index 000000000000..25b9640ca565 --- /dev/null +++ b/test/cmdlineTests/ethdebug_enabled_optimization/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} + diff --git a/test/cmdlineTests/ethdebug_runtime/args b/test/cmdlineTests/ethdebug_runtime/args index dfc6038785a5..a2193034c8db 100644 --- a/test/cmdlineTests/ethdebug_runtime/args +++ b/test/cmdlineTests/ethdebug_runtime/args @@ -1 +1 @@ ---ethdebug-runtime --via-ir --optimize --ir-optimized \ No newline at end of file +--ethdebug-runtime --via-ir --ir \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug_runtime/output b/test/cmdlineTests/ethdebug_runtime/output index 8af39f64ef3c..8670e379d4e3 100644 --- a/test/cmdlineTests/ethdebug_runtime/output +++ b/test/cmdlineTests/ethdebug_runtime/output @@ -2,41 +2,120 @@ {"sources":["ethdebug_runtime/input.sol"]} ======= ethdebug_runtime/input.sol:C ======= -Optimized IR: +IR: /// ethdebug: enabled /// @use-src 0:"ethdebug_runtime/input.sol" object "C_6" { code { - { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 "contract C {..." + function constructor_C_6() { + /// @src 0:60:101 "contract C {..." - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize("C_6_deployed") - codecopy(_1, dataoffset("C_6_deployed"), _2) - return(_1, _2) + } + /// @src 0:60:101 "contract C {..." + } /// @use-src 0:"ethdebug_runtime/input.sol" object "C_6_deployed" { code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:60:101 "contract C {..." - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 { - if eq(0x26121ff0, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } - return(0, 0) - } + // f() + + external_fun_f_5() } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @ast-id 5 + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + + } + /// @src 0:60:101 "contract C {..." + } + data ".metadata" hex"" } + } + Debug Data of the runtime part (ethdebug/format/program): {} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json index e7173abed3e1..6ac2691c2085 100644 --- a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json @@ -11,12 +11,12 @@ "settings": { "viaIR": true, "optimizer": { - "enabled": true + "enabled": false }, "outputSelection": { "*": { "*": [ - "evm.bytecode.ethdebug", "irOptimized" + "evm.bytecode.ethdebug", "ir" ] } } diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json index da701aec60f5..fabb25ee6720 100644 --- a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json @@ -7,46 +7,175 @@ "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 0:\"a.sol\" object \"A1_14\" { code { - { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_14() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_14_deployed\"), datasize(\"A1_14_deployed\")) + + return(_1, datasize(\"A1_14_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_14() { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A1_14_deployed\") - codecopy(_1, dataoffset(\"A1_14_deployed\"), _2) - return(_1, _2) + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 0:\"a.sol\" object \"A1_14_deployed\" { code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 { - if eq(0xf0fdf834, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 0:112:117 \"x > 0\" */ iszero(/** @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // a(uint256) + + external_fun_a_13() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_13() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_13(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 13 + /// @src 0:72:121 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_13(var_x_3) { + + /// @src 0:112:113 \"x\" + let _1 := var_x_3 + let expr_7 := _1 + /// @src 0:116:117 \"0\" + let expr_8 := 0x00 + /// @src 0:112:117 \"x > 0\" + let expr_9 := gt(cleanup_t_uint256(expr_7), convert_t_rational_0_by_1_to_t_uint256(expr_8)) + /// @src 0:105:118 \"assert(x > 0)\" + assert_helper(expr_9) + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " }, "A2": { @@ -55,46 +184,175 @@ object \"A1_14\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 0:\"a.sol\" object \"A2_27\" { code { - { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A2_27() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A2_27_deployed\"), datasize(\"A2_27_deployed\")) + + return(_1, datasize(\"A2_27_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A2_27() { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A2_27_deployed\") - codecopy(_1, dataoffset(\"A2_27_deployed\"), _2) - return(_1, _2) + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 0:\"a.sol\" object \"A2_27_deployed\" { code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 { - if eq(0xf0fdf834, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 0:178:183 \"x > 0\" */ iszero(/** @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // a(uint256) + + external_fun_a_26() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_26() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_26(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 26 + /// @src 0:138:187 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_26(var_x_16) { + + /// @src 0:178:179 \"x\" + let _1 := var_x_16 + let expr_20 := _1 + /// @src 0:182:183 \"0\" + let expr_21 := 0x00 + /// @src 0:178:183 \"x > 0\" + let expr_22 := gt(cleanup_t_uint256(expr_20), convert_t_rational_0_by_1_to_t_uint256(expr_21)) + /// @src 0:171:184 \"assert(x > 0)\" + assert_helper(expr_22) + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " } }, @@ -105,46 +363,175 @@ object \"A2_27\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 1:\"b.sol\" object \"A1_42\" { code { - { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_42() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_42_deployed\"), datasize(\"A1_42_deployed\")) + + return(_1, datasize(\"A1_42_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_42() { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A1_42_deployed\") - codecopy(_1, dataoffset(\"A1_42_deployed\"), _2) - return(_1, _2) + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 1:\"b.sol\" object \"A1_42_deployed\" { code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 { - if eq(0xcd580ff3, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 1:112:117 \"x > 0\" */ iszero(/** @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // b(uint256) + + external_fun_b_41() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_41() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_41(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 41 + /// @src 1:72:121 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_41(var_x_31) { + + /// @src 1:112:113 \"x\" + let _1 := var_x_31 + let expr_35 := _1 + /// @src 1:116:117 \"0\" + let expr_36 := 0x00 + /// @src 1:112:117 \"x > 0\" + let expr_37 := gt(cleanup_t_uint256(expr_35), convert_t_rational_0_by_1_to_t_uint256(expr_36)) + /// @src 1:105:118 \"assert(x > 0)\" + assert_helper(expr_37) + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " }, "B2": { @@ -153,46 +540,175 @@ object \"A1_42\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 1:\"b.sol\" object \"B2_55\" { code { - { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_B2_55() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"B2_55_deployed\"), datasize(\"B2_55_deployed\")) + + return(_1, datasize(\"B2_55_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_B2_55() { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"B2_55_deployed\") - codecopy(_1, dataoffset(\"B2_55_deployed\"), _2) - return(_1, _2) + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 1:\"b.sol\" object \"B2_55_deployed\" { code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 { - if eq(0xcd580ff3, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 1:178:183 \"x > 0\" */ iszero(/** @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // b(uint256) + + external_fun_b_54() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_54() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_54(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 54 + /// @src 1:138:187 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_54(var_x_44) { + + /// @src 1:178:179 \"x\" + let _1 := var_x_44 + let expr_48 := _1 + /// @src 1:182:183 \"0\" + let expr_49 := 0x00 + /// @src 1:178:183 \"x > 0\" + let expr_50 := gt(cleanup_t_uint256(expr_48), convert_t_rational_0_by_1_to_t_uint256(expr_49)) + /// @src 1:171:184 \"assert(x > 0)\" + assert_helper(expr_50) + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " } } diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json index e45f27f3caa8..bb93f57a8256 100644 --- a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json @@ -11,12 +11,12 @@ "settings": { "viaIR": true, "optimizer": { - "enabled": true + "enabled": false }, "outputSelection": { "*": { "*": [ - "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "irOptimized" + "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "ir" ] } } diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json index 4e41e41c385b..f8fb2ce274d0 100644 --- a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json @@ -10,46 +10,175 @@ "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 0:\"a.sol\" object \"A1_14\" { code { - { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_14() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_14_deployed\"), datasize(\"A1_14_deployed\")) + + return(_1, datasize(\"A1_14_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_14() { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A1_14_deployed\") - codecopy(_1, dataoffset(\"A1_14_deployed\"), _2) - return(_1, _2) + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 0:\"a.sol\" object \"A1_14_deployed\" { code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 { - if eq(0xf0fdf834, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 0:112:117 \"x > 0\" */ iszero(/** @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // a(uint256) + + external_fun_a_13() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_13() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_13(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 13 + /// @src 0:72:121 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_13(var_x_3) { + + /// @src 0:112:113 \"x\" + let _1 := var_x_3 + let expr_7 := _1 + /// @src 0:116:117 \"0\" + let expr_8 := 0x00 + /// @src 0:112:117 \"x > 0\" + let expr_9 := gt(cleanup_t_uint256(expr_7), convert_t_rational_0_by_1_to_t_uint256(expr_8)) + /// @src 0:105:118 \"assert(x > 0)\" + assert_helper(expr_9) + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " }, "A2": { @@ -61,46 +190,175 @@ object \"A1_14\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 0:\"a.sol\" object \"A2_27\" { code { - { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A2_27() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A2_27_deployed\"), datasize(\"A2_27_deployed\")) + + return(_1, datasize(\"A2_27_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A2_27() { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A2_27_deployed\") - codecopy(_1, dataoffset(\"A2_27_deployed\"), _2) - return(_1, _2) + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 0:\"a.sol\" object \"A2_27_deployed\" { code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 { - if eq(0xf0fdf834, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 0:178:183 \"x > 0\" */ iszero(/** @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // a(uint256) + + external_fun_a_26() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_26() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_26(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 26 + /// @src 0:138:187 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_26(var_x_16) { + + /// @src 0:178:179 \"x\" + let _1 := var_x_16 + let expr_20 := _1 + /// @src 0:182:183 \"0\" + let expr_21 := 0x00 + /// @src 0:178:183 \"x > 0\" + let expr_22 := gt(cleanup_t_uint256(expr_20), convert_t_rational_0_by_1_to_t_uint256(expr_21)) + /// @src 0:171:184 \"assert(x > 0)\" + assert_helper(expr_22) + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " } }, @@ -114,46 +372,175 @@ object \"A2_27\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 1:\"b.sol\" object \"A1_42\" { code { - { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_42() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_42_deployed\"), datasize(\"A1_42_deployed\")) + + return(_1, datasize(\"A1_42_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_42() { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A1_42_deployed\") - codecopy(_1, dataoffset(\"A1_42_deployed\"), _2) - return(_1, _2) + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 1:\"b.sol\" object \"A1_42_deployed\" { code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 { - if eq(0xcd580ff3, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 1:112:117 \"x > 0\" */ iszero(/** @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // b(uint256) + + external_fun_b_41() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_41() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_41(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 41 + /// @src 1:72:121 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_41(var_x_31) { + + /// @src 1:112:113 \"x\" + let _1 := var_x_31 + let expr_35 := _1 + /// @src 1:116:117 \"0\" + let expr_36 := 0x00 + /// @src 1:112:117 \"x > 0\" + let expr_37 := gt(cleanup_t_uint256(expr_35), convert_t_rational_0_by_1_to_t_uint256(expr_36)) + /// @src 1:105:118 \"assert(x > 0)\" + assert_helper(expr_37) + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " }, "B2": { @@ -165,46 +552,175 @@ object \"A1_42\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 1:\"b.sol\" object \"B2_55\" { code { - { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_B2_55() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"B2_55_deployed\"), datasize(\"B2_55_deployed\")) + + return(_1, datasize(\"B2_55_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_B2_55() { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"B2_55_deployed\") - codecopy(_1, dataoffset(\"B2_55_deployed\"), _2) - return(_1, _2) + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 1:\"b.sol\" object \"B2_55_deployed\" { code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 { - if eq(0xcd580ff3, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 1:178:183 \"x > 0\" */ iszero(/** @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // b(uint256) + + external_fun_b_54() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_54() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_54(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 54 + /// @src 1:138:187 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_54(var_x_44) { + + /// @src 1:178:179 \"x\" + let _1 := var_x_44 + let expr_48 := _1 + /// @src 1:182:183 \"0\" + let expr_49 := 0x00 + /// @src 1:178:183 \"x > 0\" + let expr_50 := gt(cleanup_t_uint256(expr_48), convert_t_rational_0_by_1_to_t_uint256(expr_49)) + /// @src 1:171:184 \"assert(x > 0)\" + assert_helper(expr_50) + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " } } diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/input.json new file mode 100644 index 000000000000..e45f27f3caa8 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "irOptimized" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json index 9e104dc177cc..f8e3ee312e6b 100644 --- a/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json +++ b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json @@ -11,12 +11,12 @@ "settings": { "viaIR": true, "optimizer": { - "enabled": true + "enabled": false }, "outputSelection": { "*": { "*": [ - "evm.deployedBytecode.ethdebug", "irOptimized" + "evm.deployedBytecode.ethdebug", "ir" ] } } diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json index 3ad7350a9fe8..4c7b4ed67197 100644 --- a/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json +++ b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json @@ -7,46 +7,175 @@ "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 0:\"a.sol\" object \"A1_14\" { code { - { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_14() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_14_deployed\"), datasize(\"A1_14_deployed\")) + + return(_1, datasize(\"A1_14_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_14() { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A1_14_deployed\") - codecopy(_1, dataoffset(\"A1_14_deployed\"), _2) - return(_1, _2) + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 0:\"a.sol\" object \"A1_14_deployed\" { code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 { - if eq(0xf0fdf834, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 0:112:117 \"x > 0\" */ iszero(/** @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // a(uint256) + + external_fun_a_13() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_13() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_13(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 13 + /// @src 0:72:121 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_13(var_x_3) { + + /// @src 0:112:113 \"x\" + let _1 := var_x_3 + let expr_7 := _1 + /// @src 0:116:117 \"0\" + let expr_8 := 0x00 + /// @src 0:112:117 \"x > 0\" + let expr_9 := gt(cleanup_t_uint256(expr_7), convert_t_rational_0_by_1_to_t_uint256(expr_8)) + /// @src 0:105:118 \"assert(x > 0)\" + assert_helper(expr_9) + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " }, "A2": { @@ -55,46 +184,175 @@ object \"A1_14\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 0:\"a.sol\" object \"A2_27\" { code { - { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A2_27() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A2_27_deployed\"), datasize(\"A2_27_deployed\")) + + return(_1, datasize(\"A2_27_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A2_27() { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A2_27_deployed\") - codecopy(_1, dataoffset(\"A2_27_deployed\"), _2) - return(_1, _2) + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 0:\"a.sol\" object \"A2_27_deployed\" { code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 { - if eq(0xf0fdf834, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 0:178:183 \"x > 0\" */ iszero(/** @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // a(uint256) + + external_fun_a_26() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_26() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_26(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 26 + /// @src 0:138:187 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_26(var_x_16) { + + /// @src 0:178:179 \"x\" + let _1 := var_x_16 + let expr_20 := _1 + /// @src 0:182:183 \"0\" + let expr_21 := 0x00 + /// @src 0:178:183 \"x > 0\" + let expr_22 := gt(cleanup_t_uint256(expr_20), convert_t_rational_0_by_1_to_t_uint256(expr_21)) + /// @src 0:171:184 \"assert(x > 0)\" + assert_helper(expr_22) + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " } }, @@ -105,46 +363,175 @@ object \"A2_27\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 1:\"b.sol\" object \"A1_42\" { code { - { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_42() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_42_deployed\"), datasize(\"A1_42_deployed\")) + + return(_1, datasize(\"A1_42_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_42() { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"A1_42_deployed\") - codecopy(_1, dataoffset(\"A1_42_deployed\"), _2) - return(_1, _2) + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 1:\"b.sol\" object \"A1_42_deployed\" { code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 { - if eq(0xcd580ff3, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 1:112:117 \"x > 0\" */ iszero(/** @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // b(uint256) + + external_fun_b_41() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_41() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_41(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 41 + /// @src 1:72:121 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_41(var_x_31) { + + /// @src 1:112:113 \"x\" + let _1 := var_x_31 + let expr_35 := _1 + /// @src 1:116:117 \"0\" + let expr_36 := 0x00 + /// @src 1:112:117 \"x > 0\" + let expr_37 := gt(cleanup_t_uint256(expr_35), convert_t_rational_0_by_1_to_t_uint256(expr_36)) + /// @src 1:105:118 \"assert(x > 0)\" + assert_helper(expr_37) + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " }, "B2": { @@ -153,46 +540,175 @@ object \"A1_42\" { "ethdebug": {} } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 1:\"b.sol\" object \"B2_55\" { code { - { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_B2_55() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"B2_55_deployed\"), datasize(\"B2_55_deployed\")) + + return(_1, datasize(\"B2_55_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_B2_55() { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" - let _1 := memoryguard(0x80) - mstore(64, _1) - if callvalue() { revert(0, 0) } - let _2 := datasize(\"B2_55_deployed\") - codecopy(_1, dataoffset(\"B2_55_deployed\"), _2) - return(_1, _2) + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + } /// @use-src 1:\"b.sol\" object \"B2_55_deployed\" { code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) { - /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" - if iszero(lt(calldatasize(), 4)) + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 { - if eq(0xcd580ff3, shr(224, calldataload(0))) - { - if callvalue() { revert(0, 0) } - if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) } - if /** @src 1:178:183 \"x > 0\" */ iszero(/** @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" */ calldataload(4)) - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 1) - revert(0, 0x24) - } - return(0, 0) - } + // b(uint256) + + external_fun_b_54() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_54() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_54(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 54 + /// @src 1:138:187 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_54(var_x_44) { + + /// @src 1:178:179 \"x\" + let _1 := var_x_44 + let expr_48 := _1 + /// @src 1:182:183 \"0\" + let expr_49 := 0x00 + /// @src 1:178:183 \"x > 0\" + let expr_50 := gt(cleanup_t_uint256(expr_48), convert_t_rational_0_by_1_to_t_uint256(expr_49)) + /// @src 1:171:184 \"assert(x > 0)\" + assert_helper(expr_50) + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + } + data \".metadata\" hex\"\" } + } + " } } diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/input.json new file mode 100644 index 000000000000..ab13b27ea6ea --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/input.json @@ -0,0 +1,21 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "irOptimized" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_optimize/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_optimize/input.json new file mode 100644 index 000000000000..a8a5cff05d0b --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_optimize/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "ir" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_optimize/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_optimize/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_optimize/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json b/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json index 86761f23659c..f3346fdd10e3 100644 --- a/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json @@ -4,11 +4,8 @@ "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} }, "settings": { - "optimizer": { - "enabled": true - }, "outputSelection": { - "*": {"*": ["evm.bytecode.ethdebug", "irOptimized"]} + "*": {"*": ["evm.bytecode.ethdebug", "ir"]} } } } diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json b/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json index 0e93c5b77f30..c9ab1d8f5e73 100644 --- a/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json @@ -9,14 +9,16 @@ } } }, - "irOptimized": "/// ethdebug: enabled + "ir": "/// ethdebug: enabled /// @use-src 0:\"input.sol\" object \"C_6_deployed\" { code { - { - /// @src 0:77:99 - sstore(0, 42) - } + /// @src 0:60:101 + mstore(64, 128) + fun_f_5() + /// @src 0:77:99 + function fun_f_5() + { sstore(0, 42) } } } " diff --git a/test/cmdlineTests/standard_yul_ethdebug_irOptimized/args b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/args new file mode 100644 index 000000000000..18532c5a6d3f --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/args @@ -0,0 +1 @@ +--allow-paths . diff --git a/test/cmdlineTests/standard_yul_ethdebug_irOptimized/in.yul b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/in.yul new file mode 100644 index 000000000000..920aef8e9dc2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/in.yul @@ -0,0 +1,17 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + sstore(0, 42) + } + /// @src 0:60:101 "contract C {..." + } +} + diff --git a/test/cmdlineTests/standard_yul_ethdebug_irOptimized/input.json b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/input.json new file mode 100644 index 000000000000..89994857f418 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/input.json @@ -0,0 +1,11 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "outputSelection": { + "*": {"*": ["evm.bytecode.ethdebug", "irOptimized"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_irOptimized/output.json b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_optimize/args b/test/cmdlineTests/standard_yul_ethdebug_optimize/args new file mode 100644 index 000000000000..18532c5a6d3f --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_optimize/args @@ -0,0 +1 @@ +--allow-paths . diff --git a/test/cmdlineTests/standard_yul_ethdebug_optimize/in.yul b/test/cmdlineTests/standard_yul_ethdebug_optimize/in.yul new file mode 100644 index 000000000000..920aef8e9dc2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_optimize/in.yul @@ -0,0 +1,17 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + sstore(0, 42) + } + /// @src 0:60:101 "contract C {..." + } +} + diff --git a/test/cmdlineTests/standard_yul_ethdebug_optimize/input.json b/test/cmdlineTests/standard_yul_ethdebug_optimize/input.json new file mode 100644 index 000000000000..fb232f23a1fb --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_optimize/input.json @@ -0,0 +1,14 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": {"*": ["evm.bytecode.ethdebug", "ir"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_optimize/output.json b/test/cmdlineTests/standard_yul_ethdebug_optimize/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_optimize/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 80cba338202d..3161eba2a868 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -1975,7 +1975,7 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_info_ethdebug) } }, { - generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"irOptimized"})), + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"ir"})), {}, [](const Json& result) { @@ -2007,7 +2007,7 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_info_ethdebug) } }, { - generateStandardJson(true, {}, Json::array({"irOptimized", "evm.bytecode.ethdebug"})), + generateStandardJson(true, {}, Json::array({"ir", "evm.bytecode.ethdebug"})), {}, [](const Json& result) { @@ -2015,7 +2015,7 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_info_ethdebug) } }, { - generateStandardJson(true, {}, Json::array({"irOptimized", "evm.deployedBytecode.ethdebug"})), + generateStandardJson(true, {}, Json::array({"ir", "evm.deployedBytecode.ethdebug"})), {}, [](const Json& result) { @@ -2023,7 +2023,7 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_info_ethdebug) } }, { - generateStandardJson(true, {}, Json::array({"irOptimized", "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + generateStandardJson(true, {}, Json::array({"ir", "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), {}, [](const Json& result) { @@ -2040,14 +2040,11 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_info_ethdebug) }, { generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"irOptimized"}), YulCode()), - {}, - [](const Json& result) - { - return result.dump().find("/// ethdebug: enabled") != std::string::npos; - } + "Optimization is not yet supported with ethdebug.", + {} }, { - generateStandardJson(true, Json::array({"ethdebugs"}), Json::array({"irOptimized"}), YulCode()), + generateStandardJson(true, Json::array({"ethdebugs"}), Json::array({"ir"}), YulCode()), "Invalid value in settings.debug.debugInfo.", {} }, diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 8dfcedac8548..17166268a656 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -1431,15 +1431,23 @@ BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_outputs) }, { {"solc", "--via-ir", "--ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, - "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--optimize", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--via-ir", "--ethdebug", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, - "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--via-ir", "--ethdebug", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, - "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, @@ -1447,7 +1455,7 @@ BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_outputs) }, { {"solc", "--via-ir", "--ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, - "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, @@ -1455,15 +1463,15 @@ BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_outputs) }, { {"solc", "--via-ir", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, - "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--via-ir", "--ethdebug-runtime", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, - "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--via-ir", "--ethdebug-runtime", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, - "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--ethdebug-runtime", "--import-asm-json", tempDir.path().string() + "/input.json"}, @@ -1471,23 +1479,23 @@ BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_outputs) }, { {"solc", "--via-ir", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, - "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir / --ir-optimized.\n" + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, - "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, - "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--debug-info", "ethdebug", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, - "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--debug-info", "ethdebug", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, - "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" }, { {"solc", "--debug-info", "ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, @@ -1499,7 +1507,7 @@ BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_outputs) }, { {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.json"}, - "Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n" + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" } }; for (auto const& test: tests) @@ -1560,7 +1568,7 @@ BOOST_AUTO_TEST_CASE(cli_ethdebug_debug_info_ethdebug) static std::vector, std::vector, std::vector>> tests{ { {"solc", "--debug-info", "ethdebug", tempDir.path().string() + "/input.sol"}, - {"Error: --debug-info ethdebug can only be used with --ir / --ir-optimized and/or --ethdebug / --ethdebug-runtime.\n"}, + {"Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, {}, }, { @@ -1570,8 +1578,13 @@ BOOST_AUTO_TEST_CASE(cli_ethdebug_debug_info_ethdebug) }, { {"solc", "--debug-info", "ethdebug", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--optimize", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, {}, - {"/// ethdebug: enabled"}, }, { {"solc", "--debug-info", "ethdebug", "--ethdebug", tempDir.path().string() + "/input.sol"}, @@ -1722,33 +1735,33 @@ BOOST_AUTO_TEST_CASE(cli_ethdebug_ethdebug_output) }, { {"solc", "--ethdebug", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, {}, - {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "/// ethdebug: enabled"}, }, { {"solc", "--ethdebug-runtime", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, {}, - {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, }, { {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, {}, - {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, }, { {"solc", "--ethdebug", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, {}, - {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "/// ethdebug: enabled"}, }, { {"solc", "--ethdebug-runtime", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, {}, - {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, }, { {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, {}, - {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, }, }; for (auto const& test: tests) diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index be3e25d3302c..85eeaebe31a8 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -663,12 +663,6 @@ BOOST_AUTO_TEST_CASE(ethdebug) BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ir, true); BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); - commandLineOptions = parseCommandLine({"solc", "contract.sol", "--debug-info", "ethdebug", "--ir-optimized"}); - BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, false); - BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, false); - BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.irOptimized, true); - BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); - BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); } BOOST_AUTO_TEST_SUITE_END()