diff --git a/Changelog.md b/Changelog.md index f00234d8b..5a53a4d50 100644 --- a/Changelog.md +++ b/Changelog.md @@ -15,6 +15,7 @@ Compiler Features: * SMTChecker: Properties that are proved safe are now reported explicitly at the end of the analysis. By default, only the number of safe properties is shown. The CLI option ``--model-checker-show-proved-safe`` and the JSON option ``settings.modelChecker.showProvedSafe`` can be enabled to show the full list of safe properties. * SMTChecker: Group all messages about unsupported language features in a single warning. The CLI option ``--model-checker-show-unsupported`` and the JSON option ``settings.modelChecker.showUnsupported`` can be enabled to show the full list. * Yul EVM Code Transform: If available, use ``push0`` instead of ``codesize`` to produce an arbitrary value on stack in order to create equal stack heights between branches. + * Yul IR Code Generation: Cheaper code for reverting with errors of a static small encoding size. Bugfixes: diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 509cc28c7..4612bb981 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -47,6 +47,7 @@ #include #include +#include #include using namespace std; @@ -58,6 +59,18 @@ using namespace std::string_literals; namespace { +optional staticEncodingSize(vector const& _parameterTypes) +{ + size_t encodedSize = 0; + for (auto const* type: _parameterTypes) + { + if (type->isDynamicallyEncoded()) + return nullopt; + encodedSize += type->calldataHeadSize(); + } + return encodedSize; +} + struct CopyTranslate: public yul::ASTCopier { using ExternalRefsMap = std::map; @@ -3363,8 +3376,16 @@ void IRGeneratorForStatements::revertWithError( vector> const& _errorArguments ) { + bool needsAllocation = true; + if (optional size = staticEncodingSize(_parameterTypes)) + if (ranges::all_of(_parameterTypes, [](auto const* type) { return type && type->isValueType(); })) + needsAllocation = *size + 4 > CompilerUtils::generalPurposeMemoryStart; Whiskers templ(R"({ + let := () + + let := 0 + mstore(, ) let := (add(, 4) ) revert(, sub(, )) @@ -3372,7 +3393,9 @@ void IRGeneratorForStatements::revertWithError( templ("pos", m_context.newYulVariable()); templ("end", m_context.newYulVariable()); templ("hash", util::selectorFromSignatureU256(_signature).str()); - templ("allocateUnbounded", m_utils.allocateUnboundedFunction()); + templ("needsAllocation", needsAllocation); + if (needsAllocation) + templ("allocateUnbounded", m_utils.allocateUnboundedFunction()); vector errorArgumentVars; vector errorArgumentTypes; diff --git a/test/libsolidity/semanticTests/errors/small_error_optimization.sol b/test/libsolidity/semanticTests/errors/small_error_optimization.sol index 79f6f563f..cb05d308f 100644 --- a/test/libsolidity/semanticTests/errors/small_error_optimization.sol +++ b/test/libsolidity/semanticTests/errors/small_error_optimization.sol @@ -14,6 +14,6 @@ contract B { } // ---- // f() -> FAILURE, hex"92bbf6e8" -// gas irOptimized: 274265 +// gas irOptimized: 270934 // gas legacy: 310592 // gas legacyOptimized: 273662