Coder Social home page Coder Social logo

Comments (2)

cameel avatar cameel commented on May 29, 2024

I can confirm this. I see that in the optimized Yul code the loop is identical in both cases and the difference is only visible in assembly. This means that it must be the effect of the optimized Yul->EVM transform. We fall back to the legacy transform if the assembly blocks are not memory-safe.

Honestly, I'm not sure if this is something we'll be able to fix. I think it's likely to not be a result of a bug that can be simply "fixed", but rather a trade-off that might affect other cases. We're generally working on improving the transform, so this may also improve as a result of the upcoming changes and might not make sense to target specifically. Need @ekpyron's opinion here.

Details

The stack shuffling issue is specific to the two staticcalls to the SHA-256 precompile that follow. In particular, if you remove any of them, the problem is no longer observed and you get the expected behaviour of code with memory-safe assembly tags being slightly more performant than potentially memory unsafe assembly.

Interesting. I expected that this would be caused by stuff being optimized out without the calls, but no. When I comment out the staticcalls the loop is still there, and still the same in both cases, just processed differently by the transform.

(Also on an unrelated note, I noticed that it is compiling sub(shift, 6) as add(shift, 0xffff...ffa which is 31 more code bytes and also seems like a minor bug...)

Maybe we should reconsider #6765 after all. I think it happens because Yul optimizer always converts sub() to add() and in this form this leaves the constant optimizer only the choice between add(shift, not(5)) (which is more space-efficient and chosen for lower runs values) and add(shift, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa) (which is cheaper to execute). Converting it back to sub(shift, 6) would be a much better alternative, since it's both cheaper and more space-efficient.

Workaround

I would not necessarily recommend it as a general solution, but as of 0.8.25 we still support the stackAllocation option in Standard JSON, which lets you select the old Yul->EVM transform. Keep in mind though that we're going to deprecate it eventually.

Repro

CLI repro using Foundry. Assumes that the contract from the issue description is in a file called base64-safe.sol.

export seed="grace crime cat remove spice bean concert lawsuit render horse collect vocal"
anvil --mnemonic "$seed"
export key=0x60b139825a56a987d58b20f0145e05dc45bed12df72cb92812b5ea988383c987

function benchmark_contract {
    solc "$1".sol --via-ir --optimize --optimize-runs 100000 --bin |
        sed -e '/^=======.*=======$/d' -e '/^Binary:$/d' -e '/^\s*$/d' > "$1".bin
    local address
    address=$(
        cast send --json --private-key "$key" --create "$(cat "$1".bin)" |
            jq --raw-output .contractAddress
    )
    gas=$(
        cast send --json --private-key "$key" "$address" "bench()" |
            jq --raw-output .gasUsed
    )
    echo "$((gas - 21000))"
}

benchmark_contract base64-safe

sed -e 's/("memory-safe")//g' base64-safe.sol > base64-unsafe.sol
benchmark_contract base64-unsafe
5104
4486

from solidity.

nlordell avatar nlordell commented on May 29, 2024

Thanks for the detailed response.

Another possible work around would be to split the code into separate functions, one with the loop and another with the static calls, and force the loop to not be optimized somehow (we can achieve this by having an additional external function that calls the loop function). I verified it with the above code and it had the desired effect.

Is there a better way to tell the Yul optimizer "please don't inline this function" without changing the ABI of the contract?

from solidity.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.