diff --git a/Changelog.md b/Changelog.md index 442c4e34f3e8..0004c3b15967 100644 --- a/Changelog.md +++ b/Changelog.md @@ -17,6 +17,7 @@ Bugfixes: * SMTChecker: Fix formatting of unary minus expressions in invariants. * SMTChecker: Fix internal compiler error when reporting proved targets for BMC engine. * TypeChecker: Fix segfault when assigning nested tuple to tuple. + * Yul AST: Fix ``nativeSrc`` attributes in optimized IR AST referring to locations in unoptimized IR. * Yul Optimizer: Name simplification could lead to forbidden identifiers with a leading and/or trailing dot, e.g., ``x._`` would get simplified into ``x.``. diff --git a/libsolidity/codegen/ir/IRGeneratorOutput.cpp b/libsolidity/codegen/ir/IRGeneratorOutput.cpp index 2427f1f50110..07f026db61e8 100644 --- a/libsolidity/codegen/ir/IRGeneratorOutput.cpp +++ b/libsolidity/codegen/ir/IRGeneratorOutput.cpp @@ -33,6 +33,53 @@ using namespace solidity::frontend; using namespace solidity::util; using namespace solidity::yul; +namespace +{ + +std::set qualifiedDataNamesForObject( + std::string const& _name, + std::set const& _dependencies, + IRGeneratorOutput::DependencyResolver const& _dependencyResolver +) +{ + // NOTE: The implementation here should be kept in sync with Object::qualifiedDataNames() + + // ASSUMPTION: Codegen never creates Data objects other than metadata. + // ASSUMPTION: Codegen never uses reserved identifiers to name objects generated from contracts. + solAssert(!contains(_name, '.')); + solAssert(!_name.empty()); + std::set qualifiedNames{{_name}}; + + for (IRGeneratorOutput const& subOutput: _dependencies | ranges::views::transform(_dependencyResolver)) + { + solAssert(!contains(subOutput.creation.name, '.')); + auto [_, subInserted] = qualifiedNames.insert(subOutput.creation.name); + solAssert(subInserted); + + for (std::string subSubDataName: subOutput.qualifiedDataNames(_dependencyResolver)) + if (subSubDataName != subOutput.creation.name) + { + auto [_, subSubInserted] = qualifiedNames.insert(subOutput.creation.name + "." + subSubDataName); + solAssert(subSubInserted); + } + } + + solAssert(!contains(qualifiedNames, "")); + return qualifiedNames; +} + +} + +std::set IRGeneratorOutput::Deployed::qualifiedDataNames(DependencyResolver const& _dependencyResolver) const +{ + // ASSUMPTION: metadata name is a reserved identifier (i.e. should not be accessible as data). + // If this ever changes, the implementation here will need to be updated. + if (metadata) + solAssert(contains(metadata->name.str(), '.')); + + return qualifiedDataNamesForObject(name, dependencies, _dependencyResolver); +} + bool IRGeneratorOutput::isValid() const { static auto const isNull = [](ContractDefinition const* _contract) -> bool { return !_contract; }; @@ -53,6 +100,23 @@ std::string IRGeneratorOutput::toPrettyString(DependencyResolver const& _depende return yul::reindent(toString(_dependencyResolver)); } +std::set IRGeneratorOutput::qualifiedDataNames(DependencyResolver const& _dependencyResolver) const +{ + using ranges::views::transform; + + solAssert(isValid()); + + auto const prefixWithCreationName = [this](std::string const& _dataName) { + return creation.name + '.' + _dataName; + }; + + std::set deployedNames = deployed.qualifiedDataNames(_dependencyResolver); + return + qualifiedDataNamesForObject(creation.name, creation.dependencies, _dependencyResolver) + + std::set{deployed.name} + + (deployedNames | transform(prefixWithCreationName)); +} + std::string IRGeneratorOutput::toString(DependencyResolver const& _dependencyResolver) const { solAssert(isValid()); diff --git a/libsolidity/codegen/ir/IRGeneratorOutput.h b/libsolidity/codegen/ir/IRGeneratorOutput.h index 9da39695c0a0..9e354e2f94b7 100644 --- a/libsolidity/codegen/ir/IRGeneratorOutput.h +++ b/libsolidity/codegen/ir/IRGeneratorOutput.h @@ -51,6 +51,9 @@ struct IRGeneratorOutput std::shared_ptr debugData; std::set dependencies; std::shared_ptr metadata; + + // TMP: docstring + std::set qualifiedDataNames(DependencyResolver const& _dependencyResolver) const; } deployed; bool isValid() const; @@ -63,6 +66,12 @@ struct IRGeneratorOutput /// (recursively) in the @a IRGeneratorOutput instances returned by the function. std::string toPrettyString(DependencyResolver const& _dependencyResolver) const; + // TMP: docstring + /// @returns the set of names of data objects accessible from within the code of + /// this object, including the name of object itself + /// Handles all names containing dots as reserved identifiers, not accessible as data. + std::set qualifiedDataNames(DependencyResolver const& _dependencyResolver) const; + private: /// Implementation detail of @a toPrettyString(). The only difference is that the output is not /// properly indented. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 345080dd6a71..2463e3fdde2b 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -67,6 +67,7 @@ #include #include +#include #include #include #include @@ -88,8 +89,10 @@ #include #include +#include #include #include +#include #include @@ -1285,6 +1288,157 @@ void CompilerStack::annotateInternalFunctionIDs() } } +namespace +{ + +// TMP: better name? +std::shared_ptr parseAndAnalyzeYulSourceWithoutDependencies( + std::string const& _name, + std::string const& _sourceCode, + std::shared_ptr _debugData, + std::set _fullyQualifiedDataNames, + EVMVersion const& _evmVersion +) +{ + ErrorList errors; + ErrorReporter errorReporter(errors); + Dialect const& dialect = EVMDialect::strictAssemblyForEVMObjects(_evmVersion); + CharStream charStream(_sourceCode, ""); // TMP: source name + auto const scanner = std::make_shared(charStream); + + auto const debugMessageWithSourceAndErrors = [&]() { + return fmt::format( + "Invalid IR generated:\n{}\n\n" + "Errors reported during parsing and analysis of IR object {}:\n{}\n", + _sourceCode, + _name, + langutil::SourceReferenceFormatter::formatErrorInformation( + errorReporter.errors(), + SingletonCharStreamProvider(charStream) + ) + ); + }; + + ObjectParser objectParser(errorReporter, dialect); + std::shared_ptr object = objectParser.parse(scanner, false /* _reuseScanner */, _debugData->sourceNames); + solAssert(object && errorReporter.errors().empty(), debugMessageWithSourceAndErrors()); + // TMP: other asserts? + + solAssert(object->debugData->sourceNames == _debugData->sourceNames); + solAssert(object->name == "object"_yulstring); + object->debugData = std::move(_debugData); + object->name = YulString{_name}; + + object->analysisInfo = std::make_shared(); + AsmAnalyzer asmAnalyzer( + *object->analysisInfo, + errorReporter, + dialect, + {}, // _resolver + std::move(_fullyQualifiedDataNames) + ); + + bool analysisSuccessful = asmAnalyzer.analyze(*object->code); + solAssert(analysisSuccessful, debugMessageWithSourceAndErrors()); + + return object; +} + +} + +void CompilerStack::parseAndAnalyzeYul(ContractDefinition const& _contract) +{ + solAssert(m_stackState >= AnalysisSuccessful); + + Contract& contractInfo = m_contracts.at(_contract.fullyQualifiedName()); + solAssert(contractInfo.yulIRGeneratorOutput.has_value()); + solAssert(contractInfo.yulIRGeneratorOutput->isValid()); + IRGeneratorOutput::Creation creation = contractInfo.yulIRGeneratorOutput->creation; + IRGeneratorOutput::Deployed deployed = contractInfo.yulIRGeneratorOutput->deployed; + + auto const resolveContract = [this](ContractDefinition const* _contractToResolve) -> IRGeneratorOutput const& { + Contract const& contractInfoToResolve = m_contracts.at(_contractToResolve->fullyQualifiedName()); + solAssert(contractInfoToResolve.yulIRGeneratorOutput.has_value()); + return *contractInfoToResolve.yulIRGeneratorOutput; + }; + + static auto const toString = [](std::string _string) { return YulString{_string}; }; + + std::set creationDataNames = contractInfo.yulIRGeneratorOutput->qualifiedDataNames(resolveContract); + std::set deployedDataNames = deployed.qualifiedDataNames(resolveContract); + + std::shared_ptr creationObject = parseAndAnalyzeYulSourceWithoutDependencies( + creation.name, + creation.code, + creation.debugData, + creationDataNames | ranges::views::transform(toString) | ranges::to, + m_evmVersion + ); + std::shared_ptr deployedObject = parseAndAnalyzeYulSourceWithoutDependencies( + deployed.name, + deployed.code, + deployed.debugData, + deployedDataNames | ranges::views::transform(toString) | ranges::to, + m_evmVersion + ); + solAssert(creationObject && creationObject->subObjects.empty()); + solAssert(deployedObject && deployedObject->subObjects.empty()); + + creationObject->addSubNode(deployedObject); + if (deployed.metadata) + deployedObject->addSubNode(deployed.metadata); + + contractInfo.yulIRObjectWithoutDependencies = std::move(creationObject); +} + +void CompilerStack::optimizeYul(ContractDefinition const& _contract) +{ + solAssert(m_stackState >= AnalysisSuccessful); + + Contract& contractInfo = m_contracts.at(_contract.fullyQualifiedName()); + solAssert(contractInfo.yulIRObjectWithoutDependencies); + + YulStack::optimize( + // TMP: Do not do it in place? + *contractInfo.yulIRObjectWithoutDependencies, + true, // _isCreation + EVMDialect::strictAssemblyForEVMObjects(m_evmVersion), + m_optimiserSettings + ); +} + +std::shared_ptr CompilerStack::linkIRObject(ContractDefinition const& _contract) const +{ + Contract const& contractInfo = contract(_contract.fullyQualifiedName()); + solAssert(contractInfo.yulIRGeneratorOutput.has_value()); + solAssert(contractInfo.yulIRObjectWithoutDependencies); + + std::shared_ptr fullCreationObject = contractInfo.yulIRObjectWithoutDependencies->structuralClone(); + solAssert(fullCreationObject->name.str() == contractInfo.yulIRGeneratorOutput->creation.name); + solAssert(fullCreationObject->subObjects.size() == 1); + solAssert(fullCreationObject->subObjects[0]); + for (ContractDefinition const* dependency: contractInfo.yulIRGeneratorOutput->creation.dependencies) + fullCreationObject->addSubNode(linkIRObject(*dependency)); + + auto* fullDeployedObject = dynamic_cast(fullCreationObject->subObjects[0].get()); + solAssert(fullDeployedObject->name.str() == contractInfo.yulIRGeneratorOutput->deployed.name); + solAssert(fullDeployedObject->subObjects.size() <= 1); + + bool hasMetadata = (fullDeployedObject->subObjects.size() != 0); + if (hasMetadata) + solAssert(fullDeployedObject->subObjects[0] == contractInfo.yulIRGeneratorOutput->deployed.metadata); + fullDeployedObject->subObjects.clear(); + fullDeployedObject->subIndexByName.clear(); + + for (ContractDefinition const* dependency: contractInfo.yulIRGeneratorOutput->deployed.dependencies) + fullDeployedObject->addSubNode(linkIRObject(*dependency)); + + if (hasMetadata) + fullDeployedObject->addSubNode(contractInfo.yulIRGeneratorOutput->deployed.metadata); + + return fullCreationObject; +} + namespace { bool onlySafeExperimentalFeaturesActivated(std::set const& features) @@ -1461,26 +1615,49 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) ); } compiledContract.yulIR = linkIR(compiledContract); + // TMP: + solAssert(!compiledContract.yulIRObjectWithoutDependencies); + parseAndAnalyzeYul(*compiledContract.contract); - yul::YulStack stack( - m_evmVersion, - m_eofVersion, - yul::YulStack::Language::StrictAssembly, - m_optimiserSettings, - m_debugInfoSelection - ); - bool yulAnalysisSuccessful = stack.parseAndAnalyze("", compiledContract.yulIR); - solAssert( - yulAnalysisSuccessful, - compiledContract.yulIR + "\n\n" - "Invalid IR generated:\n" + - langutil::SourceReferenceFormatter::formatErrorInformation(stack.errors(), stack) + "\n" - ); + std::shared_ptr irObject = linkIRObject(*compiledContract.contract); + + optimizeYul(*compiledContract.contract); + std::shared_ptr optimizedIRObject = linkIRObject(*compiledContract.contract); + + compiledContract.yulIROptimized = optimizedIRObject->toString( + &EVMDialect::strictAssemblyForEVMObjects(m_evmVersion), + m_debugInfoSelection, + this // _soliditySourceProvider // TMP: + ) + "\n"; + + auto const reparseYul = [&](std::string const& _irSource) { + YulStack stack( + m_evmVersion, + m_eofVersion, + YulStack::Language::StrictAssembly, + m_optimiserSettings, + m_debugInfoSelection + ); + bool yulAnalysisSuccessful = stack.parseAndAnalyze("", _irSource); + solAssert( + yulAnalysisSuccessful, + _irSource + "\n\n" + "Invalid IR generated:\n" + + langutil::SourceReferenceFormatter::formatErrorInformation(stack.errors(), stack) + "\n" + ); + return stack; + }; - compiledContract.yulIRAst = stack.astJson(); - stack.optimize(); - compiledContract.yulIROptimized = stack.print(this); - compiledContract.yulIROptimizedAst = stack.astJson(); + { + YulStack stack = reparseYul(compiledContract.yulIR); + compiledContract.yulIRAst = stack.astJson(); + } + { + // Optimizer does not maintain correct native source locations in the AST. + // We can work around it by regenerating the AST from scratch from optimized IR. + YulStack stack = reparseYul(compiledContract.yulIROptimized); + compiledContract.yulIROptimizedAst = stack.astJson(); + } } void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract) diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index df021455c32c..d2441ed78485 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -389,6 +389,7 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac evmasm::LinkerObject object; ///< Deployment object (includes the runtime sub-object). evmasm::LinkerObject runtimeObject; ///< Runtime object. std::optional yulIRGeneratorOutput; ///< Yul IR code of the current contract only (without dependencies). + std::shared_ptr yulIRObjectWithoutDependencies; // TMP: docstring // TMP: It may be optimized std::string yulIR; ///< Yul IR code. std::string yulIROptimized; ///< Optimized Yul IR code. Json yulIRAst; ///< JSON AST of Yul IR code. @@ -434,6 +435,16 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac /// @returns false on error. bool analyzeExperimental(); + // TMP: docstring + void parseAndAnalyzeYul(ContractDefinition const& _contract); + + // TMP: docstring + void optimizeYul(ContractDefinition const& _contract); + + // TMP: docstring, name, argument + // TMP: Can't even guarantee it's really optimized + std::shared_ptr linkIRObject(ContractDefinition const& _contract) const; + /// Assembles the contract. /// This function should only be internally called by compileContract and generateEVMFromIR. void assembleYul( diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index ac97f988d47d..858abe70e5fa 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -84,7 +84,7 @@ bool AsmAnalyzer::analyze(Block const& _block) return watcher.ok(); } -AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object) +AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object, bool _ignoreMissingData) { ErrorList errorList; langutil::ErrorReporter errors(errorList); @@ -94,7 +94,8 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, errors, _dialect, {}, - _object.qualifiedDataNames() + _object.qualifiedDataNames(), + _ignoreMissingData ).analyze(*_object.code); yulAssert(success && !errors.hasErrors(), "Invalid assembly/yul code."); return analysisInfo; @@ -428,7 +429,7 @@ std::vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (functionName == "datasize" || functionName == "dataoffset") { auto const& argumentAsLiteral = std::get(arg); - if (!m_dataNames.count(YulString(formatLiteral(argumentAsLiteral)))) + if (!m_ignoreMissingData && !m_dataNames.count(YulString(formatLiteral(argumentAsLiteral)))) m_errorReporter.typeError( 3517_error, nativeLocationOf(arg), diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h index c49e6855914d..6d2f35a7ddb2 100644 --- a/libyul/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -61,13 +61,16 @@ class AsmAnalyzer langutil::ErrorReporter& _errorReporter, Dialect const& _dialect, ExternalIdentifierAccess::Resolver _resolver = ExternalIdentifierAccess::Resolver(), - std::set _dataNames = {} + std::set _dataNames = {}, + // TMP: Should I instead store unlinked references in the object? + bool _ignoreMissingData = false ): m_resolver(std::move(_resolver)), m_info(_analysisInfo), m_errorReporter(_errorReporter), m_dialect(_dialect), - m_dataNames(std::move(_dataNames)) + m_dataNames(std::move(_dataNames)), + m_ignoreMissingData(_ignoreMissingData) { if (EVMDialect const* evmDialect = dynamic_cast(&m_dialect)) m_evmVersion = evmDialect->evmVersion(); @@ -77,7 +80,7 @@ class AsmAnalyzer /// Performs analysis on the outermost code of the given object and returns the analysis info. /// Asserts on failure. - static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object); + static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object, bool _ignoreMissingData = false); std::vector operator()(Literal const& _literal); std::vector operator()(Identifier const&); @@ -132,6 +135,7 @@ class AsmAnalyzer ForLoop const* m_currentForLoop = nullptr; /// Worst side effects encountered during analysis (including within defined functions). SideEffects m_sideEffects; + bool m_ignoreMissingData{}; }; } diff --git a/libyul/Object.cpp b/libyul/Object.cpp index d9dbdd284301..e1c4c92d501f 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -92,6 +92,43 @@ std::string ObjectDebugData::formatUseSrcComment() const return "/// @use-src " + serializedSourceNames + "\n"; } +std::shared_ptr Object::structuralClone() const +{ + std::vector> clonedSubObjects; + for (std::shared_ptr subNode: subObjects) + if (auto const* subObject = dynamic_cast(subNode.get())) + clonedSubObjects.push_back(subObject->structuralClone()); + else + clonedSubObjects.push_back(subNode); + + // TMP: Add constructors? + auto clonedObject = std::make_shared(); + clonedObject->name = name; + clonedObject->code = code; + clonedObject->subId = subId; + clonedObject->subObjects = std::move(clonedSubObjects); + clonedObject->subIndexByName = subIndexByName; + clonedObject->analysisInfo = analysisInfo; + clonedObject->debugData = debugData; + return clonedObject; +} + +void Object::addSubNode(std::shared_ptr _subNode) +{ + yulAssert(_subNode); + + size_t index = subObjects.size(); + subIndexByName[_subNode->name] = index; + + if (auto* subObject = dynamic_cast(_subNode.get())) + { + yulAssert(subObject->subId == std::numeric_limits::max()); + subObject->subId = index; + } + + subObjects.push_back(std::move(_subNode)); +} + Json Object::toJson() const { yulAssert(code, "No code"); @@ -114,6 +151,8 @@ Json Object::toJson() const std::set Object::qualifiedDataNames() const { + // NOTE: The implementation here should be kept in sync with IRGeneratorOutput::qualifiedDataNames() + std::set qualifiedNames = name.empty() || util::contains(name.str(), '.') ? std::set{} : diff --git a/libyul/Object.h b/libyul/Object.h index 3bca307c5e47..cc14e5d00b1c 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -99,8 +99,16 @@ struct Object: public ObjectNode langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(), langutil::CharStreamProvider const* _soliditySourceProvider = nullptr ) const override; + + // TMP: docstring + // TMP: make it clear that code remains shared + std::shared_ptr structuralClone() const; + + void addSubNode(std::shared_ptr _subNode); + /// @returns a compact JSON representation of the AST. Json toJson() const override; + /// @returns the set of names of data objects accessible from within the code of /// this object, including the name of object itself /// Handles all names containing dots as reserved identifiers, not accessible as data. diff --git a/libyul/ObjectParser.cpp b/libyul/ObjectParser.cpp index a02b9660b978..3596743d3d80 100644 --- a/libyul/ObjectParser.cpp +++ b/libyul/ObjectParser.cpp @@ -38,7 +38,11 @@ using namespace solidity::yul; using namespace solidity::util; using namespace solidity::langutil; -std::shared_ptr ObjectParser::parse(std::shared_ptr const& _scanner, bool _reuseScanner) +std::shared_ptr ObjectParser::parse( + std::shared_ptr const& _scanner, + bool _reuseScanner, + std::optional _sourceNames +) { m_recursionDepth = 0; try @@ -51,9 +55,10 @@ std::shared_ptr ObjectParser::parse(std::shared_ptr const& _sca // Special case: Code-only form. object = std::make_shared(); object->name = "object"_yulstring; - auto sourceNameMapping = tryParseSourceNameMapping(); - object->debugData = std::make_shared(ObjectDebugData{sourceNameMapping}); - object->code = parseBlock(sourceNameMapping); + object->debugData = _sourceNames.has_value() ? + std::make_shared(ObjectDebugData{std::move(_sourceNames)}) : + std::make_shared(ObjectDebugData{tryParseSourceNameMapping()}); + object->code = parseBlock(object->debugData->sourceNames); if (!object->code) return nullptr; } @@ -70,14 +75,15 @@ std::shared_ptr ObjectParser::parse(std::shared_ptr const& _sca return nullptr; } -std::shared_ptr ObjectParser::parseObject(Object* _containingObject) +std::shared_ptr ObjectParser::parseObject(Object* _containingObject, std::optional _sourceNames) { RecursionGuard guard(*this); std::shared_ptr ret = std::make_shared(); - auto sourceNameMapping = tryParseSourceNameMapping(); - ret->debugData = std::make_shared(ObjectDebugData{sourceNameMapping}); + ret->debugData = _sourceNames.has_value() ? + std::make_shared(ObjectDebugData{std::move(_sourceNames)}) : + std::make_shared(ObjectDebugData{tryParseSourceNameMapping()}); if (currentToken() != Token::Identifier || currentLiteral() != "object") fatalParserError(4294_error, "Expected keyword \"object\"."); @@ -87,7 +93,7 @@ std::shared_ptr ObjectParser::parseObject(Object* _containingObject) expectToken(Token::LBrace); - ret->code = parseCode(std::move(sourceNameMapping)); + ret->code = parseCode(ret->debugData->sourceNames); while (currentToken() != Token::RBrace) { diff --git a/libyul/ObjectParser.h b/libyul/ObjectParser.h index 716a191ea878..98a2d1d27526 100644 --- a/libyul/ObjectParser.h +++ b/libyul/ObjectParser.h @@ -49,15 +49,23 @@ class ObjectParser: public langutil::ParserBase explicit ObjectParser(langutil::ErrorReporter& _errorReporter, Dialect const& _dialect): ParserBase(_errorReporter), m_dialect(_dialect) {} + // TMP: update docstring /// Parses a Yul object. /// Falls back to code-only parsing if the source starts with `{`. /// @param _reuseScanner if true, do check for end of input after the last `}`. /// @returns an empty shared pointer on error. - std::shared_ptr parse(std::shared_ptr const& _scanner, bool _reuseScanner); + std::shared_ptr parse( + std::shared_ptr const& _scanner, + bool _reuseScanner, + std::optional _sourceNames = std::nullopt + ); private: std::optional tryParseSourceNameMapping() const; - std::shared_ptr parseObject(Object* _containingObject = nullptr); + std::shared_ptr parseObject( + Object* _containingObject = nullptr, + std::optional _sourceNames = std::nullopt + ); std::shared_ptr parseCode(std::optional _sourceNames); std::shared_ptr parseBlock(std::optional _sourceNames); void parseData(Object& _containingObject); diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index 94e9ad7a8d55..f8df7295143f 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -120,7 +120,12 @@ void YulStack::optimize() return; m_stackState = Parsed; - optimize(*m_parserResult, true); + optimize( + *m_parserResult, + true, // _isCreation + languageToDialect(m_language, m_evmVersion), + m_optimiserSettings + ); yulAssert(analyzeParsed(), "Invalid source code after optimization."); } catch (UnimplementedFeatureError const& _error) @@ -191,7 +196,12 @@ void YulStack::compileEVM(AbstractAssembly& _assembly, bool _optimize) const EVMObjectCompiler::compile(*m_parserResult, _assembly, *dialect, _optimize, m_eofVersion); } -void YulStack::optimize(Object& _object, bool _isCreation) +void YulStack::optimize( + Object& _object, + bool _isCreation, + Dialect const& _dialect, + OptimiserSettings const& _optimiserSettings +) { yulAssert(_object.code, ""); yulAssert(_object.analysisInfo, ""); @@ -199,48 +209,47 @@ void YulStack::optimize(Object& _object, bool _isCreation) if (auto subObject = dynamic_cast(subNode.get())) { bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed"); - optimize(*subObject, isCreation); + optimize(*subObject, isCreation, _dialect, _optimiserSettings); } - Dialect const& dialect = languageToDialect(m_language, m_evmVersion); std::unique_ptr meter; - if (EVMDialect const* evmDialect = dynamic_cast(&dialect)) - meter = std::make_unique(*evmDialect, _isCreation, m_optimiserSettings.expectedExecutionsPerDeployment); + if (EVMDialect const* evmDialect = dynamic_cast(&_dialect)) + meter = std::make_unique(*evmDialect, _isCreation, _optimiserSettings.expectedExecutionsPerDeployment); auto [optimizeStackAllocation, yulOptimiserSteps, yulOptimiserCleanupSteps] = [&]() -> std::tuple { - if (!m_optimiserSettings.runYulOptimiser) + if (!_optimiserSettings.runYulOptimiser) { // Yul optimizer disabled, but empty sequence (:) explicitly provided - if (OptimiserSuite::isEmptyOptimizerSequence(m_optimiserSettings.yulOptimiserSteps + ":" + m_optimiserSettings.yulOptimiserCleanupSteps)) + if (OptimiserSuite::isEmptyOptimizerSequence(_optimiserSettings.yulOptimiserSteps + ":" + _optimiserSettings.yulOptimiserCleanupSteps)) return std::make_tuple(true, "", ""); // Yul optimizer disabled, and no sequence explicitly provided (assumes default sequence) else { yulAssert( - m_optimiserSettings.yulOptimiserSteps == OptimiserSettings::DefaultYulOptimiserSteps && - m_optimiserSettings.yulOptimiserCleanupSteps == OptimiserSettings::DefaultYulOptimiserCleanupSteps + _optimiserSettings.yulOptimiserSteps == OptimiserSettings::DefaultYulOptimiserSteps && + _optimiserSettings.yulOptimiserCleanupSteps == OptimiserSettings::DefaultYulOptimiserCleanupSteps ); return std::make_tuple(true, "u", ""); } } return std::make_tuple( - m_optimiserSettings.optimizeStackAllocation, - m_optimiserSettings.yulOptimiserSteps, - m_optimiserSettings.yulOptimiserCleanupSteps + _optimiserSettings.optimizeStackAllocation, + _optimiserSettings.yulOptimiserSteps, + _optimiserSettings.yulOptimiserCleanupSteps ); }(); OptimiserSuite::run( - dialect, + _dialect, meter.get(), _object, // Defaults are the minimum necessary to avoid running into "Stack too deep" constantly. optimizeStackAllocation, yulOptimiserSteps, yulOptimiserCleanupSteps, - _isCreation ? std::nullopt : std::make_optional(m_optimiserSettings.expectedExecutionsPerDeployment), + _isCreation ? std::nullopt : std::make_optional(_optimiserSettings.expectedExecutionsPerDeployment), {} ); } diff --git a/libyul/YulStack.h b/libyul/YulStack.h index d75ff200f5ce..518edab91e57 100644 --- a/libyul/YulStack.h +++ b/libyul/YulStack.h @@ -109,6 +109,13 @@ class YulStack: public langutil::CharStreamProvider /// If the settings (see constructor) disabled the optimizer, nothing is done here. void optimize(); + static void optimize( + Object& _object, + bool _isCreation, + Dialect const& _dialect, + frontend::OptimiserSettings const& _optimiserSettings + ); + /// Run the assembly step (should only be called after parseAndAnalyze). MachineAssemblyObject assemble(Machine _machine); @@ -147,8 +154,6 @@ class YulStack: public langutil::CharStreamProvider void compileEVM(yul::AbstractAssembly& _assembly, bool _optimize) const; - void optimize(yul::Object& _object, bool _isCreation); - void reportUnimplementedFeatureError(langutil::UnimplementedFeatureError const& _error); Language m_language = Language::Assembly; diff --git a/libyul/optimiser/StackCompressor.cpp b/libyul/optimiser/StackCompressor.cpp index 58552147a608..552d46d630de 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -256,7 +256,7 @@ bool StackCompressor::run( bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, *_object.code); if (usesOptimizedCodeGenerator) { - yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object); + yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object, true /* _ignoreMissingData */); std::unique_ptr cfg = ControlFlowGraphBuilder::build(analysisInfo, _dialect, *_object.code); eliminateVariablesOptimizedCodegen( _dialect, diff --git a/libyul/optimiser/StackLimitEvader.cpp b/libyul/optimiser/StackLimitEvader.cpp index 904ee77e00f9..eefa7ee5d9c0 100644 --- a/libyul/optimiser/StackLimitEvader.cpp +++ b/libyul/optimiser/StackLimitEvader.cpp @@ -129,7 +129,7 @@ void StackLimitEvader::run( ); if (evmDialect && evmDialect->evmVersion().canOverchargeGasForCall()) { - yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(*evmDialect, _object); + yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(*evmDialect, _object, true /* _ignoreMissingData */); std::unique_ptr cfg = ControlFlowGraphBuilder::build(analysisInfo, *evmDialect, *_object.code); run(_context, _object, StackLayoutGenerator::reportStackTooDeep(*cfg)); } diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 83bc0370092b..4bae7f2c4fee 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -221,7 +221,7 @@ void OptimiserSuite::run( outputPerformanceMetrics(suite.m_durationPerStepInMicroseconds); #endif - *_object.analysisInfo = AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object); + *_object.analysisInfo = AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object, true /* _ignoreMissingData */); } namespace diff --git a/test/cmdlineTests/ast_ir/output b/test/cmdlineTests/ast_ir/output index c68c77872969..76f111990870 100644 --- a/test/cmdlineTests/ast_ir/output +++ b/test/cmdlineTests/ast_ir/output @@ -637,24 +637,24 @@ Optimized IR AST: { "code": { "block": { - "nativeSrc": "59:790:0", + "nativeSrc": "58:315:0", "nodeType": "YulBlock", "src": "-1:-1:0", "statements": [ { - "nativeSrc": "59:790:0", + "nativeSrc": "68:299:0", "nodeType": "YulBlock", "src": "-1:-1:0", "statements": [ { - "nativeSrc": "122:16:0", + "nativeSrc": "128:27:0", "nodeType": "YulVariableDeclaration", "src": "60:13:0", "value": { "arguments": [ { "kind": "number", - "nativeSrc": "134:3:0", + "nativeSrc": "150:4:0", "nodeType": "YulLiteral", "src": "60:13:0", "type": "", @@ -663,18 +663,18 @@ Optimized IR AST: ], "functionName": { "name": "memoryguard", - "nativeSrc": "122:11:0", + "nativeSrc": "138:11:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "122:16:0", + "nativeSrc": "138:17:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, "variables": [ { "name": "_1", - "nativeSrc": "122:16:0", + "nativeSrc": "132:2:0", "nodeType": "YulTypedName", "src": "60:13:0", "type": "" @@ -686,7 +686,7 @@ Optimized IR AST: "arguments": [ { "kind": "number", - "nativeSrc": "118:2:0", + "nativeSrc": "175:2:0", "nodeType": "YulLiteral", "src": "60:13:0", "type": "", @@ -694,28 +694,28 @@ Optimized IR AST: }, { "name": "_1", - "nativeSrc": "122:16:0", + "nativeSrc": "179:2:0", "nodeType": "YulIdentifier", "src": "60:13:0" } ], "functionName": { "name": "mstore", - "nativeSrc": "111:6:0", + "nativeSrc": "168:6:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "111:28:0", + "nativeSrc": "168:14:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, - "nativeSrc": "111:28:0", + "nativeSrc": "168:14:0", "nodeType": "YulExpressionStatement", "src": "60:13:0" }, { "body": { - "nativeSrc": "163:83:0", + "nativeSrc": "210:16:0", "nodeType": "YulBlock", "src": "60:13:0", "statements": [ @@ -724,7 +724,7 @@ Optimized IR AST: "arguments": [ { "kind": "number", - "nativeSrc": "650:1:0", + "nativeSrc": "219:1:0", "nodeType": "YulLiteral", "src": "60:13:0", "type": "", @@ -732,7 +732,7 @@ Optimized IR AST: }, { "kind": "number", - "nativeSrc": "650:1:0", + "nativeSrc": "222:1:0", "nodeType": "YulLiteral", "src": "60:13:0", "type": "", @@ -741,15 +741,15 @@ Optimized IR AST: ], "functionName": { "name": "revert", - "nativeSrc": "640:6:0", + "nativeSrc": "212:6:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "640:12:0", + "nativeSrc": "212:12:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, - "nativeSrc": "640:12:0", + "nativeSrc": "212:12:0", "nodeType": "YulExpressionStatement", "src": "60:13:0" } @@ -759,20 +759,20 @@ Optimized IR AST: "arguments": [], "functionName": { "name": "callvalue", - "nativeSrc": "151:9:0", + "nativeSrc": "198:9:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "151:11:0", + "nativeSrc": "198:11:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, - "nativeSrc": "148:98:0", + "nativeSrc": "195:31:0", "nodeType": "YulIf", "src": "60:13:0" }, { - "nativeSrc": "363:24:0", + "nativeSrc": "239:34:0", "nodeType": "YulVariableDeclaration", "src": "60:13:0", "value": { @@ -780,7 +780,7 @@ Optimized IR AST: { "hexValue": "435f325f6465706c6f796564", "kind": "string", - "nativeSrc": "372:14:0", + "nativeSrc": "258:14:0", "nodeType": "YulLiteral", "src": "60:13:0", "type": "", @@ -789,18 +789,18 @@ Optimized IR AST: ], "functionName": { "name": "datasize", - "nativeSrc": "363:8:0", + "nativeSrc": "249:8:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "363:24:0", + "nativeSrc": "249:24:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, "variables": [ { "name": "_2", - "nativeSrc": "363:24:0", + "nativeSrc": "243:2:0", "nodeType": "YulTypedName", "src": "60:13:0", "type": "" @@ -812,7 +812,7 @@ Optimized IR AST: "arguments": [ { "name": "_1", - "nativeSrc": "331:2:0", + "nativeSrc": "295:2:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, @@ -821,7 +821,7 @@ Optimized IR AST: { "hexValue": "435f325f6465706c6f796564", "kind": "string", - "nativeSrc": "346:14:0", + "nativeSrc": "310:14:0", "nodeType": "YulLiteral", "src": "60:13:0", "type": "", @@ -830,32 +830,32 @@ Optimized IR AST: ], "functionName": { "name": "dataoffset", - "nativeSrc": "335:10:0", + "nativeSrc": "299:10:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "335:26:0", + "nativeSrc": "299:26:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, { "name": "_2", - "nativeSrc": "363:24:0", + "nativeSrc": "327:2:0", "nodeType": "YulIdentifier", "src": "60:13:0" } ], "functionName": { "name": "codecopy", - "nativeSrc": "322:8:0", + "nativeSrc": "286:8:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "322:66:0", + "nativeSrc": "286:44:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, - "nativeSrc": "322:66:0", + "nativeSrc": "286:44:0", "nodeType": "YulExpressionStatement", "src": "60:13:0" }, @@ -864,28 +864,28 @@ Optimized IR AST: "arguments": [ { "name": "_1", - "nativeSrc": "405:2:0", + "nativeSrc": "350:2:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, { "name": "_2", - "nativeSrc": "409:24:0", + "nativeSrc": "354:2:0", "nodeType": "YulIdentifier", "src": "60:13:0" } ], "functionName": { "name": "return", - "nativeSrc": "398:6:0", + "nativeSrc": "343:6:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "398:36:0", + "nativeSrc": "343:14:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, - "nativeSrc": "398:36:0", + "nativeSrc": "343:14:0", "nodeType": "YulExpressionStatement", "src": "60:13:0" } @@ -901,12 +901,12 @@ Optimized IR AST: { "code": { "block": { - "nativeSrc": "929:588:0", + "nativeSrc": "453:118:0", "nodeType": "YulBlock", "src": "-1:-1:0", "statements": [ { - "nativeSrc": "929:588:0", + "nativeSrc": "467:94:0", "nodeType": "YulBlock", "src": "-1:-1:0", "statements": [ @@ -915,7 +915,7 @@ Optimized IR AST: "arguments": [ { "kind": "number", - "nativeSrc": "1490:1:0", + "nativeSrc": "542:1:0", "nodeType": "YulLiteral", "src": "60:13:0", "type": "", @@ -923,7 +923,7 @@ Optimized IR AST: }, { "kind": "number", - "nativeSrc": "1490:1:0", + "nativeSrc": "545:1:0", "nodeType": "YulLiteral", "src": "60:13:0", "type": "", @@ -932,15 +932,15 @@ Optimized IR AST: ], "functionName": { "name": "revert", - "nativeSrc": "1480:6:0", + "nativeSrc": "535:6:0", "nodeType": "YulIdentifier", "src": "60:13:0" }, - "nativeSrc": "1480:12:0", + "nativeSrc": "535:12:0", "nodeType": "YulFunctionCall", "src": "60:13:0" }, - "nativeSrc": "1480:12:0", + "nativeSrc": "535:12:0", "nodeType": "YulExpressionStatement", "src": "60:13:0" } diff --git a/test/cmdlineTests/standard_irOptimized_ast_requested/output.json b/test/cmdlineTests/standard_irOptimized_ast_requested/output.json index 91d0e87f3619..5c6762ac9907 100644 --- a/test/cmdlineTests/standard_irOptimized_ast_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_ast_requested/output.json @@ -5,12 +5,12 @@ "irOptimizedAst": { "code": { "block": { - "nativeSrc": "44:790:0", + "nativeSrc": "43:639:0", "nodeType": "YulBlock", "src": "-1:-1:0", "statements": [ { - "nativeSrc": "44:790:0", + "nativeSrc": "53:421:0", "nodeType": "YulBlock", "src": "-1:-1:0", "statements": [ @@ -19,7 +19,7 @@ "arguments": [ { "kind": "number", - "nativeSrc": "103:2:0", + "nativeSrc": "120:2:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -29,7 +29,7 @@ "arguments": [ { "kind": "number", - "nativeSrc": "119:3:0", + "nativeSrc": "136:4:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -38,32 +38,32 @@ ], "functionName": { "name": "memoryguard", - "nativeSrc": "107:11:0", + "nativeSrc": "124:11:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "107:16:0", + "nativeSrc": "124:17:0", "nodeType": "YulFunctionCall", "src": "56:13:0" } ], "functionName": { "name": "mstore", - "nativeSrc": "96:6:0", + "nativeSrc": "113:6:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "96:28:0", + "nativeSrc": "113:29:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "96:28:0", + "nativeSrc": "113:29:0", "nodeType": "YulExpressionStatement", "src": "56:13:0" }, { "body": { - "nativeSrc": "148:83:0", + "nativeSrc": "182:111:0", "nodeType": "YulBlock", "src": "56:13:0", "statements": [ @@ -72,15 +72,15 @@ "arguments": [], "functionName": { "name": "revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb", - "nativeSrc": "150:77:0", + "nativeSrc": "200:77:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "150:79:0", + "nativeSrc": "200:79:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "150:79:0", + "nativeSrc": "200:79:0", "nodeType": "YulExpressionStatement", "src": "56:13:0" } @@ -90,38 +90,38 @@ "arguments": [], "functionName": { "name": "callvalue", - "nativeSrc": "136:9:0", + "nativeSrc": "158:9:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "136:11:0", + "nativeSrc": "158:11:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "133:98:0", + "nativeSrc": "155:138:0", "nodeType": "YulIf", "src": "56:13:0" }, { - "nativeSrc": "268:30:0", + "nativeSrc": "306:30:0", "nodeType": "YulVariableDeclaration", "src": "56:13:0", "value": { "arguments": [], "functionName": { "name": "allocate_unbounded", - "nativeSrc": "278:18:0", + "nativeSrc": "316:18:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "278:20:0", + "nativeSrc": "316:20:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, "variables": [ { "name": "_1", - "nativeSrc": "272:2:0", + "nativeSrc": "310:2:0", "nodeType": "YulTypedName", "src": "56:13:0", "type": "" @@ -133,7 +133,7 @@ "arguments": [ { "name": "_1", - "nativeSrc": "316:2:0", + "nativeSrc": "358:2:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, @@ -142,7 +142,7 @@ { "hexValue": "435f325f6465706c6f796564", "kind": "string", - "nativeSrc": "331:14:0", + "nativeSrc": "373:14:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -151,11 +151,11 @@ ], "functionName": { "name": "dataoffset", - "nativeSrc": "320:10:0", + "nativeSrc": "362:10:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "320:26:0", + "nativeSrc": "362:26:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, @@ -164,7 +164,7 @@ { "hexValue": "435f325f6465706c6f796564", "kind": "string", - "nativeSrc": "357:14:0", + "nativeSrc": "399:14:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -173,26 +173,26 @@ ], "functionName": { "name": "datasize", - "nativeSrc": "348:8:0", + "nativeSrc": "390:8:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "348:24:0", + "nativeSrc": "390:24:0", "nodeType": "YulFunctionCall", "src": "56:13:0" } ], "functionName": { "name": "codecopy", - "nativeSrc": "307:8:0", + "nativeSrc": "349:8:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "307:66:0", + "nativeSrc": "349:66:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "307:66:0", + "nativeSrc": "349:66:0", "nodeType": "YulExpressionStatement", "src": "56:13:0" }, @@ -201,7 +201,7 @@ "arguments": [ { "name": "_1", - "nativeSrc": "390:2:0", + "nativeSrc": "435:2:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, @@ -210,7 +210,7 @@ { "hexValue": "435f325f6465706c6f796564", "kind": "string", - "nativeSrc": "403:14:0", + "nativeSrc": "448:14:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -219,26 +219,26 @@ ], "functionName": { "name": "datasize", - "nativeSrc": "394:8:0", + "nativeSrc": "439:8:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "394:24:0", + "nativeSrc": "439:24:0", "nodeType": "YulFunctionCall", "src": "56:13:0" } ], "functionName": { "name": "return", - "nativeSrc": "383:6:0", + "nativeSrc": "428:6:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "383:36:0", + "nativeSrc": "428:36:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "383:36:0", + "nativeSrc": "428:36:0", "nodeType": "YulExpressionStatement", "src": "56:13:0" } @@ -246,19 +246,19 @@ }, { "body": { - "nativeSrc": "469:43:0", + "nativeSrc": "531:23:0", "nodeType": "YulBlock", "src": "56:13:0", "statements": [ { - "nativeSrc": "483:19:0", + "nativeSrc": "533:19:0", "nodeType": "YulAssignment", "src": "56:13:0", "value": { "arguments": [ { "kind": "number", - "nativeSrc": "499:2:0", + "nativeSrc": "549:2:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -267,18 +267,18 @@ ], "functionName": { "name": "mload", - "nativeSrc": "493:5:0", + "nativeSrc": "543:5:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "493:9:0", + "nativeSrc": "543:9:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, "variableNames": [ { "name": "memPtr", - "nativeSrc": "483:6:0", + "nativeSrc": "533:6:0", "nodeType": "YulIdentifier", "src": "56:13:0" } @@ -287,12 +287,12 @@ ] }, "name": "allocate_unbounded", - "nativeSrc": "429:83:0", + "nativeSrc": "483:71:0", "nodeType": "YulFunctionDefinition", "returnVariables": [ { "name": "memPtr", - "nativeSrc": "462:6:0", + "nativeSrc": "516:6:0", "nodeType": "YulTypedName", "src": "56:13:0", "type": "" @@ -302,7 +302,7 @@ }, { "body": { - "nativeSrc": "611:36:0", + "nativeSrc": "660:16:0", "nodeType": "YulBlock", "src": "56:13:0", "statements": [ @@ -311,7 +311,7 @@ "arguments": [ { "kind": "number", - "nativeSrc": "632:1:0", + "nativeSrc": "669:1:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -319,7 +319,7 @@ }, { "kind": "number", - "nativeSrc": "635:1:0", + "nativeSrc": "672:1:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -328,22 +328,22 @@ ], "functionName": { "name": "revert", - "nativeSrc": "625:6:0", + "nativeSrc": "662:6:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "625:12:0", + "nativeSrc": "662:12:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "625:12:0", + "nativeSrc": "662:12:0", "nodeType": "YulExpressionStatement", "src": "56:13:0" } ] }, "name": "revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb", - "nativeSrc": "522:125:0", + "nativeSrc": "563:113:0", "nodeType": "YulFunctionDefinition", "src": "56:13:0" } @@ -357,12 +357,12 @@ { "code": { "block": { - "nativeSrc": "899:588:0", + "nativeSrc": "747:361:0", "nodeType": "YulBlock", "src": "-1:-1:0", "statements": [ { - "nativeSrc": "899:588:0", + "nativeSrc": "761:207:0", "nodeType": "YulBlock", "src": "-1:-1:0", "statements": [ @@ -371,7 +371,7 @@ "arguments": [ { "kind": "number", - "nativeSrc": "966:2:0", + "nativeSrc": "836:2:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -381,7 +381,7 @@ "arguments": [ { "kind": "number", - "nativeSrc": "982:3:0", + "nativeSrc": "852:4:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -390,26 +390,26 @@ ], "functionName": { "name": "memoryguard", - "nativeSrc": "970:11:0", + "nativeSrc": "840:11:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "970:16:0", + "nativeSrc": "840:17:0", "nodeType": "YulFunctionCall", "src": "56:13:0" } ], "functionName": { "name": "mstore", - "nativeSrc": "959:6:0", + "nativeSrc": "829:6:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "959:28:0", + "nativeSrc": "829:29:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "959:28:0", + "nativeSrc": "829:29:0", "nodeType": "YulExpressionStatement", "src": "56:13:0" }, @@ -418,15 +418,15 @@ "arguments": [], "functionName": { "name": "revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74", - "nativeSrc": "1001:77:0", + "nativeSrc": "875:77:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "1001:79:0", + "nativeSrc": "875:79:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "1001:79:0", + "nativeSrc": "875:79:0", "nodeType": "YulExpressionStatement", "src": "56:13:0" } @@ -434,7 +434,7 @@ }, { "body": { - "nativeSrc": "1432:44:0", + "nativeSrc": "1082:16:0", "nodeType": "YulBlock", "src": "56:13:0", "statements": [ @@ -443,7 +443,7 @@ "arguments": [ { "kind": "number", - "nativeSrc": "1457:1:0", + "nativeSrc": "1091:1:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -451,7 +451,7 @@ }, { "kind": "number", - "nativeSrc": "1460:1:0", + "nativeSrc": "1094:1:0", "nodeType": "YulLiteral", "src": "56:13:0", "type": "", @@ -460,22 +460,22 @@ ], "functionName": { "name": "revert", - "nativeSrc": "1450:6:0", + "nativeSrc": "1084:6:0", "nodeType": "YulIdentifier", "src": "56:13:0" }, - "nativeSrc": "1450:12:0", + "nativeSrc": "1084:12:0", "nodeType": "YulFunctionCall", "src": "56:13:0" }, - "nativeSrc": "1450:12:0", + "nativeSrc": "1084:12:0", "nodeType": "YulExpressionStatement", "src": "56:13:0" } ] }, "name": "revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74", - "nativeSrc": "1343:133:0", + "nativeSrc": "981:117:0", "nodeType": "YulFunctionDefinition", "src": "56:13:0" } diff --git a/test/cmdlineTests/viair_msize_without_optimizer/output b/test/cmdlineTests/viair_msize_without_optimizer/output index b54f8a3f5647..e2ee84586087 100644 --- a/test/cmdlineTests/viair_msize_without_optimizer/output +++ b/test/cmdlineTests/viair_msize_without_optimizer/output @@ -2,86 +2,57 @@ ======= viair_msize_without_optimizer/input.sol:C ======= EVM assembly: mstore(0x40, 0x80) - jumpi(tag_4, iszero(callvalue)) + jumpi(tag_3, callvalue) tag_5 - tag_2 - jump // in -tag_5: -tag_4: - tag_6 - tag_3 - jump // in -tag_6: - tag_7 tag_1 jump // in -tag_7: +tag_5: dataSize(sub_0) dataOffset(sub_0) dup3 codecopy dataSize(sub_0) - dup2 + swap1 return +tag_3: + tag_2 + jump // in tag_1: - 0x00 mload(0x40) swap1 - pop - swap1 jump // out tag_2: 0x00 dup1 revert -tag_3: - jump // out stop sub_0: assembly { mstore(0x40, 0x80) - jumpi(tag_10, lt(calldatasize, 0x04)) - tag_11 + jumpi(tag_11, iszero(lt(calldatasize, 0x04))) + tag_12: + tag_8 + jump // in + tag_11: + tag_13 calldataload(0x00) tag_1 jump // in - tag_11: - dup1 + tag_13: 0x26121ff0 - dup2 sub tag_12 jumpi - tag_14 tag_7 jump // in - tag_14: - tag_12: - pop - pop - tag_10: - tag_15 - tag_8 - jump // in - tag_15: - jump(tag_16) tag_1: - 0x00 - dup2 0xe0 shr swap1 - pop - swap2 - swap1 - pop jump // out tag_2: - 0x00 mload(0x40) swap1 - pop - swap1 jump // out tag_3: 0x00 @@ -93,90 +64,64 @@ sub_0: assembly { revert tag_5: 0x00 - dup2 - dup4 + swap2 sub slt - iszero - tag_22 + tag_16 jumpi - tag_23 + jump // out + tag_16: tag_4 jump // in - tag_23: - tag_22: - pop - pop - jump // out tag_6: 0x00 - dup1 - dup3 add swap1 - pop - swap2 - swap1 - pop jump // out tag_7: - jumpi(tag_26, iszero(callvalue)) - tag_27 - tag_3 - jump // in - tag_27: - tag_26: - tag_28 + jumpi(tag_18, callvalue) + tag_20 calldatasize 0x04 tag_5 jump // in - tag_28: - tag_29 - tag_9 + tag_20: + tag_21 + tag_10 jump // in - tag_29: - tag_30 + tag_21: + tag_22 tag_2 jump // in - tag_30: - tag_31 + tag_22: + dup1 + tag_23 dup2 tag_6 jump // in - tag_31: - dup2 - dup2 + tag_23: sub - dup3 + swap1 return + tag_18: + tag_3 + jump // in tag_8: 0x00 dup1 revert tag_9: - jump(tag_35) - tag_34: - 0x00 - dup1 - mload - swap1 - pop + mload(0x00) swap1 jump // out - tag_35: - 0x00 - dup1 - tag_37 - tag_34 + tag_10: + tag_24 + tag_9 jump // in - tag_37: + tag_24: 0x00 mstore - pop - pop jump // out - tag_16: auxdata: } @@ -185,35 +130,36 @@ Optimized IR: /// @use-src 0:"viair_msize_without_optimizer/input.sol" object "C_7" { code { - mstore(64, memoryguard(128)) - if callvalue() { - revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + mstore(64, memoryguard(0x80)) + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_7_deployed"), datasize("C_7_deployed")) + return(_1, datasize("C_7_deployed")) } - constructor_C_7() - let _1 := allocate_unbounded() - codecopy(_1, dataoffset("C_7_deployed"), datasize("C_7_deployed")) - return(_1, datasize("C_7_deployed")) function allocate_unbounded() -> memPtr { memPtr := mload(64) } function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } - function constructor_C_7() - { } } /// @use-src 0:"viair_msize_without_optimizer/input.sol" object "C_7_deployed" { code { - mstore(64, memoryguard(128)) - if iszero(lt(calldatasize(), 4)) { - let selector := shift_right_224_unsigned(calldataload(0)) - switch selector - case 0x26121ff0 { external_fun_f_6() } - default { } + mstore(64, memoryguard(0x80)) + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_unsigned(calldataload(0)) + switch selector + case 0x26121ff0 { external_fun_f() } + default { } + } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() } - revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - function shift_right_224_unsigned(value) -> newValue + function shift_right_unsigned(value) -> newValue { newValue := shr(224, value) } function allocate_unbounded() -> memPtr { memPtr := mload(64) } @@ -221,40 +167,33 @@ object "C_7" { { revert(0, 0) } function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { revert(0, 0) } - function abi_decode_tuple_(headStart, dataEnd) + function abi_decode(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } } - function abi_encode_tuple__to__fromStack(headStart) -> tail + function abi_encode_tuple(headStart) -> tail { tail := add(headStart, 0) } - function external_fun_f_6() + function external_fun_f() { if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_6() + abi_decode(4, calldatasize()) + fun_f() let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos) + let memEnd := abi_encode_tuple(memPos) return(memPos, sub(memEnd, memPos)) } function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } - function fun_f_6() - { - { - function usr$f() -> usr$x - { usr$x := mload(0) } - pop(msize()) - let usr$x := 0 - let usr$y := usr$x - mstore(0, usr$f()) - } - } + function usr$f() -> usr$x + { usr$x := mload(0) } + function fun_f() + { mstore(0, usr$f()) } } data ".metadata" hex"" }