Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
Language Features:
* General: Add a builtin that computes the base slot of a storage namespace using the `erc7201` formula from ERC-7201.

Important Bugfixes:
* Yul Optimizer: Fix `UnusedStoreEliminator` incorrectly removing `returndatacopy` operations when the length comes from a stale `returndatasize()` call that was invalidated by subsequent call opcodes.

Compiler Features:
* Commandline Interface: Disallow selecting the deprecated assembly input mode that was only accessible via `--assemble` instead of treating it as equivalent to `--strict-assembly`.
* Commandline Interface: Introduce `--experimental` flag required for enabling the experimental mode.
Expand All @@ -15,6 +18,7 @@ Compiler Features:
* Standard JSON Interface: Introduce `settings.experimental` setting required for enabling the experimental mode.
* Standard JSON Interface: Replace the top-level ``ethdebug`` output with ``ethdebug.resources`` and ``ethdebug.compilation``. Decouple ethdebug outputs from binary compilation so that global ethdebug outputs can be produced without generating bytecode.
* Yul Optimizer: Improve performance of control flow side effects collector and function references resolver.
* Yul Optimizer: Remove optimization that eliminated `returndatacopy` operations.

Bugfixes:
* Yul: Fix incorrect serialization of Yul object names containing double quotes and escape sequences, producing output that could not be parsed as valid Yul.
Expand Down
14 changes: 14 additions & 0 deletions docs/bugs.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
[
{
"uid": "SOL-2026-2",
"name": "UnusedStoreEliminatorStaleReturnDataSize",
"summary": "The Yul optimizer's ``UnusedStoreEliminator`` may incorrectly remove ``returndatacopy(...)`` operations when using a stale value from ``returndatasize()`` that was invalidated by subsequent call operations.",
"description": "The ``UnusedStoreEliminator`` is a Yul optimizer step that removes redundant memory and storage writes. One of the operations eligible for removal is ``returndatacopy(...)``. This particular operation has a quirk - unlike any other instruction for bulk memory copying it reverts on out-of-bounds access. A revert is one of the side-effects that the optimizer guarantees to preserve so the operation can only be removed when it is certain that it cannot revert. This is the case when the entire return data buffer is copied to memory, i.e. when the start offset is zero and the length equals ``returndatasize()``. The optimizer was special-cased to detect and optimize only this specific pattern, since it matches the code produced by the code generator for external calls. However, the check did not account for the possibility of ``returndatasize()`` values becoming stale. The size of the return data buffer is updated by ``call()``, ``staticcall()``, ``delegatecall()``, and ``callcode()``. If a ``returndatasize()`` value is stored in a variable before such an operation and then used in a subsequent ``returndatacopy(...)``, the stored size may no longer reflect the actual return data buffer size. Despite this, the optimizer would consider it safe to remove, bypassing the revert and allowing the code to continue, possibly leading to unexpected behavior. Since the code generator never produces code that interleaves multiple calls and access to their return data, the bug only affected inline assembly or handwritten Yul code. The necessary condition is the use of an optimizer sequence including the ``UnusedStoreEliminator`` step (which is the default).",
"link": "https://blog.soliditylang.org/2026/04/21/unusedstore-eliminator-stale-returndatasize-bug/",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The release is currently planned for the 29th.

Suggested change
"link": "https://blog.soliditylang.org/2026/04/21/unusedstore-eliminator-stale-returndatasize-bug/",
"link": "https://blog.soliditylang.org/2026/04/29/unusedstore-eliminator-stale-returndatasize-bug/",

This should be corrected in the blog post as well.

"introduced": "0.8.13",
"fixed": "0.8.35",
"severity": "very low",
"conditions": {
"yulOptimizer": true,
"evmVersion": ">=byzantium"
}
Comment thread
cameel marked this conversation as resolved.
},
{
"uid": "SOL-2026-1",
"name": "TransientStorageClearingHelperCollision",
Expand Down
25 changes: 24 additions & 1 deletion docs/bugs_by_version.json
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,7 @@
},
"0.8.13": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
Expand All @@ -1884,6 +1885,7 @@
},
"0.8.14": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
Expand All @@ -1897,6 +1899,7 @@
},
"0.8.15": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
Expand All @@ -1908,6 +1911,7 @@
},
"0.8.16": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
Expand All @@ -1918,6 +1922,7 @@
},
"0.8.17": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
Expand All @@ -1927,6 +1932,7 @@
},
"0.8.18": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
Expand All @@ -1936,6 +1942,7 @@
},
"0.8.19": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
Expand All @@ -1960,6 +1967,7 @@
},
"0.8.20": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
Expand All @@ -1969,57 +1977,66 @@
},
"0.8.21": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication"
],
"released": "2023-07-19"
},
"0.8.22": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication"
],
"released": "2023-10-25"
},
"0.8.23": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2023-11-08"
},
"0.8.24": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-01-25"
},
"0.8.25": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-03-14"
},
"0.8.26": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-05-21"
},
"0.8.27": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-09-04"
},
"0.8.28": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"TransientStorageClearingHelperCollision",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-10-09"
},
"0.8.29": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"TransientStorageClearingHelperCollision",
"LostStorageArrayWriteOnSlotOverflow"
],
Expand All @@ -2041,32 +2058,38 @@
},
"0.8.30": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"TransientStorageClearingHelperCollision",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2025-05-07"
},
"0.8.31": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"TransientStorageClearingHelperCollision",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2025-12-03"
},
"0.8.32": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"TransientStorageClearingHelperCollision"
],
"released": "2025-12-18"
},
"0.8.33": {
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize",
"TransientStorageClearingHelperCollision"
],
"released": "2025-12-18"
},
"0.8.34": {
"bugs": [],
"bugs": [
"UnusedStoreEliminatorStaleReturnDataSize"
],
"released": "2026-02-18"
},
"0.8.4": {
Expand Down
48 changes: 16 additions & 32 deletions libyul/optimiser/UnusedStoreEliminator.cpp
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like removing this did not affect gas in any of our semantic tests?

Please check gas benchmarks from external tests though.

Copy link
Copy Markdown
Contributor Author

@rodiazet rodiazet Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relative

ir-no-optimize

project bytecode_size deployment_gas method_gas
brink 0%
colony 0%
elementfi 0%
ens 0%
euler
gnosis
gp2 0%
pool-together 0%
uniswap 0% +0% +0%
yield_liquidator 0% +0% +0%
zeppelin

ir-optimize-evm+yul

project bytecode_size deployment_gas method_gas
brink 0%
colony 0%
elementfi 0%
ens 0% 0% 0%
euler 0% -0% +0%
gnosis
gp2 0%
pool-together 0%
uniswap 0% +0% -0%
yield_liquidator 0% -0% 0%
zeppelin 0% -0% +0%

ir-optimize-evm-only

project bytecode_size deployment_gas method_gas
brink 0%
colony 0%
elementfi 0%
ens 0% 0% 0%
euler
gnosis
gp2 0%
pool-together 0%
uniswap 0% 0% +0%
yield_liquidator 0% 0% 0%
zeppelin 0%

legacy-no-optimize

project bytecode_size deployment_gas method_gas
brink 0%
colony 0%
elementfi 0%
ens 0%
euler 0% +0% -0%
gnosis 0%
gp2 0%
pool-together 0%
uniswap 0% +0% +0%
yield_liquidator 0% -0% 0%
zeppelin

legacy-optimize-evm+yul

project bytecode_size deployment_gas method_gas
brink 0%
colony 0%
elementfi 0%
ens 0% 0% 0%
euler 0% -0% -0%
gnosis 0%
gp2 0%
pool-together 0%
uniswap 0% +0% -0%
yield_liquidator 0% -0% 0%
zeppelin 0% +0% +0%

legacy-optimize-evm-only

project bytecode_size deployment_gas method_gas
brink 0%
colony 0%
elementfi 0%
ens 0% 0% 0%
euler 0% +0% -0%
gnosis 0%
gp2 0%
pool-together 0%
uniswap 0% -0% +0%
yield_liquidator 0% 0% 0%
zeppelin

!V = version mismatch
!B = no value in the "before" version
!A = no value in the "after" version
!T = one or both values were not numeric and could not be compared
-0 = very small negative value rounded to zero
+0 = very small positive value rounded to zero

absolute

ir-no-optimize

project bytecode_size deployment_gas method_gas
brink 0
colony 0
elementfi 0
ens 0
euler
gnosis
gp2 0
pool-together 0
uniswap 0 36 82
yield_liquidator 0 12 72
zeppelin

ir-optimize-evm+yul

project bytecode_size deployment_gas method_gas
brink 0
colony 0
elementfi 0
ens 0 0 0
euler 0 -24 5972
gnosis
gp2 0
pool-together 0
uniswap 0 48 -103
yield_liquidator 0 -36 0
zeppelin 0 -24 121

ir-optimize-evm-only

project bytecode_size deployment_gas method_gas
brink 0
colony 0
elementfi 0
ens 0 0 0
euler
gnosis
gp2 0
pool-together 0
uniswap 0 0 3955
yield_liquidator 0 0 0
zeppelin 0

legacy-no-optimize

project bytecode_size deployment_gas method_gas
brink 0
colony 0
elementfi 0
ens 0
euler 0 12 -12110
gnosis 0
gp2 0
pool-together 0
uniswap 0 36 380
yield_liquidator 0 -12 0
zeppelin

legacy-optimize-evm+yul

project bytecode_size deployment_gas method_gas
brink 0
colony 0
elementfi 0
ens 0 0 0
euler 0 -48 -18878
gnosis 0
gp2 0
pool-together 0
uniswap 0 48 -1614
yield_liquidator 0 -12 0
zeppelin 0 100 1426

legacy-optimize-evm-only

project bytecode_size deployment_gas method_gas
brink 0
colony 0
elementfi 0
ens 0 0 0
euler 0 24 -10010
gnosis 0
gp2 0
pool-together 0
uniswap 0 -12 882
yield_liquidator 0 0 0
zeppelin

!V = version mismatch
!B = no value in the "before" version
!A = no value in the "after" version
!T = one or both values were not numeric and could not be compared
-0 = very small negative value rounded to zero
+0 = very small positive value rounded to zero

Original file line number Diff line number Diff line change
Expand Up @@ -158,48 +158,32 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
// both by querying a combination of semantic information and by listing the instructions.
// This way the assert below should be triggered on any change.
using evmasm::SemanticInformation;
bool isStorageWrite = (*instruction == Instruction::SSTORE);
bool isMemoryWrite =
bool const isStorageOnlyWrite = (*instruction == Instruction::SSTORE);
bool const isMemoryOnlyWrite =
*instruction == Instruction::EXTCODECOPY ||
*instruction == Instruction::CODECOPY ||
*instruction == Instruction::CALLDATACOPY ||
*instruction == Instruction::RETURNDATACOPY ||
// TODO: Removing MCOPY is complicated because it's not just a store but also a load.
//*instruction == Instruction::MCOPY ||
*instruction == Instruction::MSTORE ||
*instruction == Instruction::MSTORE8;
bool isCandidateForRemoval =
*instruction != Instruction::MCOPY &&
*instruction == Instruction::MSTORE8 ||
*instruction == Instruction::MCOPY ||
*instruction == Instruction::RETURNDATACOPY;
bool const isBlacklisted =
// TODO: Removing MCOPY is complicated because it's not just a store but also a load.
*instruction == Instruction::MCOPY ||
// The optimization that eliminated `returndatacopy` operations
// was intentionally removed because it is very rarely used and complicates the implementation
// of UnusedStoreEliminator. I.e. a variable which is initialized to `returndatasize()` becomes
// stale when a call changing the size is used in between the variable initialization and `returndatacopy`.
*instruction == Instruction::RETURNDATACOPY;
bool const isCandidateForRemoval =
!isBlacklisted &&
SemanticInformation::otherState(*instruction) != SemanticInformation::Write && (
SemanticInformation::storage(*instruction) == SemanticInformation::Write ||
(!m_ignoreMemory && SemanticInformation::memory(*instruction) == SemanticInformation::Write)
);
yulAssert(isCandidateForRemoval == (isStorageWrite || (!m_ignoreMemory && isMemoryWrite)));
yulAssert(isCandidateForRemoval == (isStorageOnlyWrite || (!m_ignoreMemory && isMemoryOnlyWrite && !isBlacklisted)));
if (isCandidateForRemoval)
{
if (*instruction == Instruction::RETURNDATACOPY)
{
// Out-of-bounds access to the returndata buffer results in a revert,
// so we are careful not to remove a potentially reverting call to a builtin.
// The only way the Solidity compiler uses `returndatacopy` is
// `returndatacopy(X, 0, returndatasize())`, so we only allow to remove this pattern
// (which is guaranteed to never cause an out-of-bounds revert).
bool allowReturndatacopyToBeRemoved = false;
auto startOffset = identifierNameIfSSA(funCall->arguments.at(1));
auto length = identifierNameIfSSA(funCall->arguments.at(2));
if (length && startOffset)
{
FunctionCall const* lengthCall = std::get_if<FunctionCall>(m_ssaValues.at(*length).value);
if (
m_knowledgeBase.knownToBeZero(*startOffset) &&
lengthCall &&
toEVMInstruction(m_dialect, lengthCall->functionName) == Instruction::RETURNDATASIZE
)
allowReturndatacopyToBeRemoved = true;
}
if (!allowReturndatacopyToBeRemoved)
return;
}
m_allStores.insert(&_statement);
std::vector<Operation> operations = operationsFromFunctionCall(*funCall);
yulAssert(operations.size() == 1, "");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--ir-optimized --optimize --debug-info none --no-cbor-metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't hard-code versions in these.

Suggested change
pragma solidity >=0.8.0;
pragma solidity *;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I'd group it with the other Yul optimizer tests: unusedStoreEliminator_returndatacopy_returndatasize/ -> yul_optimizer_unused_store_eliminator_unused_returndatasize_removal/

And the comment should also say that returndatasize() used to be removed but now the expectation is that now it is not. This is not obvious without context and the name does not make it clear either.


contract C {
function f() public pure {
assembly {
// Destination offset 96 is chosen to make the written memory region [96, 96+returndatasize())
// provably disjoint from the ABI encoder's mload(64) (which reads [64, 96)).
returndatacopy(96, 0, returndatasize())
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This verifies that the returndatacopy removal in inline assembly as possible and is no longer the case. Which is fine to have as a test, but not what I meant in #16508 (comment).

I expected something like the repro from the report. Which I guess would be this:

contract C {
    function f() public view {
        assembly {
            let s := returndatasize()
            pop(staticcall(gas(), 0x01, 0, 0, 0, 0))
            returndatacopy(0, 0, s)
        }
    }
}

I see that this does not reproduce the error though. Not even with the sequence we use in Yul tests for UnusedStoreEliminator (oxaSVj). Note also that this repro does not even compile - I had to remove the last argument from staticcall() to make it compile.

This puts into question if the bug can even be triggered. A buggy path definitely exists, but if there's no input that can exercise it, I would not classify it as an important bug.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the repro does work in pure Yul:

{
    let s := returndatasize()
    pop(staticcall(gas(), 0x01, 0, 0, 0, 0))
    returndatacopy(0, 0, s)
}

So the bug is real after all. But the question still remains if it's reproducible in inline assembly. If it's not then I'd still consider demoting it.

We also still need a non-Yul version of the test to prove that affects evmasm as well (otherwise buglist entry needs viaIR: true).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I'd put the repro under yul_optimizer_unused_store_eliminator_stale_returndatasize_bug/ (Solidity version) and strict_asm_yul_optimizer_unused_store_eliminator_stale_returndatasize_bug/ (Yul version).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added semantic test which triggers the bug.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will move it to cmdLineTests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think we should create the tests as you mentioned but the semantic test should stay too. It checks that the call reverts. cmdLineTest only verifies that the returndataload is not removed by the optimizer step.

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Optimized IR:
/// @use-src 0:"input.sol"
object "C_7" {
code {
{
let _1 := memoryguard(0x80)
mstore(64, _1)
if callvalue() { revert(0, 0) }
let _2 := datasize("C_7_deployed")
codecopy(_1, dataoffset("C_7_deployed"), _2)
return(_1, _2)
}
}
/// @use-src 0:"input.sol"
object "C_7_deployed" {
code {
{
mstore(64, 128)
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) }
returndatacopy(96, 0, returndatasize())
return(0, 0)
}
}
revert(0, 0)
}
}
data ".metadata" hex""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
contract C {
function e1() external returns(uint256) {
return 1;
}

function e() external {}

// This test verifies that UnusedStoreEliminator does not incorrectly eliminate
// a returndatacopy whose size argument is a stale snapshot of returndatasize()
// taken before a subsequent call that resets the return data buffer.
//
// The test only detects the bug when run with --optimize.
//
// The destination offset 96 is chosen so that the written region [96, 128)
// is provably disjoint from the ABI encoder's mload(64) at [64, 96).
function f() public {
assembly {
mstore(0x00, shl(0xe0, 0xa2c2d666)) // bytes4(keccak256("e1()"))
pop(staticcall(gas(), address(), 0x00, 0x04, 0x00, 0x00))
let rds := returndatasize() // rds == 32 (return value of e1())
mstore(0x00, shl(0xe0, 0xffae15ba)) // bytes4(keccak256("e()"))
pop(staticcall(gas(), address(), 0x00, 0x04, 0x00, 0x00))
// After e(), returndatasize() == 0, but rds is stale (== 32).
// The out-of-bounds access reverts.
returndatacopy(96, 0x00, rds)
}
}
}
// ----
// f() -> FAILURE
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// This optimisation step is removed and `returndatacopy` is never removed by `unusedStoreEliminator`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"optimisation step" sounds like you're talking about the whole UnusedStoreEliminator. I'd explain it like this:

Suggested change
// This optimisation step is removed and `returndatacopy` is never removed by `unusedStoreEliminator`.
// Unused `returndatacopy()` is not supposed be optimized out in this case.
// In fact, it's never optimized out now that we removed this optimization from UnusedStoreEliminator.

It would fit the other test where you have this comment as well.

{
returndatacopy(0,0,32)
}
Expand Down
Comment thread
cameel marked this conversation as resolved.
Comment thread
cameel marked this conversation as resolved.
Comment thread
cameel marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// This test ensures that `returndatacopy` is NOT optimized away.
{
returndatacopy(0,0,returndatasize())
}
Expand All @@ -8,8 +9,6 @@
//
// {
// {
// let _1 := returndatasize()
// let _2 := 0
// let _3 := 0
// returndatacopy(0, 0, returndatasize())
// }
// }
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// This optimisation step is removed and `returndatacopy` is never removed by `unusedStoreEliminator`.
{
returndatacopy(0,1,returndatasize())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// This test ensures that `returndatacopy` is NOT optimized away.
{
let s := returndatasize()
returndatacopy(0,0,s)
Expand All @@ -9,8 +10,6 @@
//
// {
// {
// let s := returndatasize()
// let _1 := 0
// let _2 := 0
// returndatacopy(0, 0, returndatasize())
// }
// }