Skip to content
Merged
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
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Compiler Features:

Bugfixes:
* Assembler: Fix not using a fixed-width type for IDs being assigned to subassemblies nested more than one level away, resulting in inconsistent `--asm-json` output between target architectures.
* Yul Optimizer: Fix edge case in which invalid Yul code is produced by ExpressionSimplifier due to expressions being substituted that contain out-of-scope variables.

### 0.8.30 (2025-05-07)

Expand Down
15 changes: 14 additions & 1 deletion libyul/optimiser/ExpressionSimplifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <libyul/optimiser/SimplificationRules.h>
#include <libyul/optimiser/OptimiserStep.h>
#include <libyul/optimiser/OptimizerUtilities.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/AST.h>
#include <libyul/Utilities.h>

Expand All @@ -45,7 +46,19 @@ void ExpressionSimplifier::visit(Expression& _expression)
while (auto const* match = SimplificationRules::findFirstMatch(
_expression,
m_dialect,
[this](YulName _var) { return variableValue(_var); }
[this](YulName const& _var) -> AssignedValue const* {
AssignedValue const* value = variableValue(_var);
if (!value || !value->value)
return nullptr;

// check that all variables in the value expression are in current scope
MovableChecker const checker(m_dialect, *value->value);
for (YulName const& referencedVar: checker.referencedVariables())
if (!inScope(referencedVar))
return nullptr; // don't substitute if any referenced var is out of scope

return value;
}
))
{
auto const* evmDialect = dynamic_cast<EVMDialect const*>(&m_dialect);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--optimize --yul-optimizations Md[F]vtDI[jxVpjCDpTnvon]TFSI[v]:Etcns --via-ir --bin
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: GPL-3.0
// reproducing https://github.com/ethereum/solidity/issues/16155

pragma solidity ^0.8.19;

contract PlaceholderContract {
function tZhBDeXU4NnUR6(bool assert_in1) internal virtual returns (int128) {
return ((
(assert_in1 && false)
? (int128(638) - int128(932))
: (assert_in1 ? int128(923) : int128(392))
) / ((int128(517) * int128(573)) / (int128(273) % int128(605))));
}

function QtdPeAwoi7LD(
bool assert_in1,
bool assert_in2
) internal pure returns (int128) {
return ((
(assert_in2 || assert_in1)
? (int128(478) % int128(983))
: (int128(298) + int128(316))
) +
(
(assert_in1 && assert_in1)
? (int128(71) / int128(885))
: (-int128(596))
));
}

function fmMG$apfQ14W86hu_3M(
bool assert_out2
) internal virtual returns (bool) {
return assert_out2;
}

function check_entrypoint(
bool /*assert_in0*/,
bool assert_in1,
bool assert_in2,
bool /*assert_in3*/
) public {
unchecked {
bool assert_out1 = (tZhBDeXU4NnUR6(assert_in1) <
QtdPeAwoi7LD(assert_in1, assert_in2));
bool assert_out2 = ((((
false
? (int128(638) - int128(932))
: ((((
(!(!assert_in1))
? int128(923)
: ((int128(392) + (int128(0) & int128(82))) &
((int128(0) + int128(392)) & int128(392)))
) + int128(0)) - (int128(77) & int128(0))) /
(int128(1) | int128(0)))
) /
((int128(573) * int128(517)) /
(-(-(-(int128(0) + (-(int128(273) % int128(605))))))))) <
((
(true && (assert_in2 || assert_in1))
? (((int128(478) % int128(983)) - int128(76)) +
int128(76))
: (int128(298) + int128(316))
) +
(
assert_in1
? (int128(73) +
((((int128(71) - int128(94)) + int128(94)) /
int128(885)) - int128(73)))
: (-int128(596))
))) ||
((((int128(0) |
(
false
? (int128(638) - int128(932))
: ((
(!(!(!(!assert_in1))))
? int128(923)
: (int128(392) &
((int128(82) & int128(0)) +
int128(392)))
) | int128(0))
)) /
((int128(573) * int128(517)) /
((-(-(-(int128(0) - (int128(273) % int128(605)))))) +
int128(0)))) | int128(0)) <
((
(((assert_in2 || assert_in1) && true) && true)
? (int128(478) % int128(983))
: (int128(298) + int128(316))
) +
(
((true && assert_in1) && assert_in1)
? (((int128(71) - int128(94)) + int128(94)) /
int128(885))
: (-int128(596))
))));
assert((assert_out1 == fmMG$apfQ14W86hu_3M(assert_out2)));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

======= input.sol:PlaceholderContract =======
Binary:
<BYTECODE REMOVED>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// regression test for https://github.com/ethereum/solidity/issues/16155
{
function identity(value) -> ret { ret := value }

function f() -> ret
{
let id1 := identity(0x01)
let x := 0x05
{
let const_six := 0x06
let id2 := identity(0x01)
x := or(0x06, id2)
}
// check that we don't substitute `or(const_six, id2)` for `x`
ret := or(id1, x)
}

mstore(42, f())
}
// ----
// step: expressionSimplifier
//
// {
// { mstore(42, f()) }
// function identity(value) -> ret
// { ret := value }
// function f() -> ret_1
// {
// let id1 := identity(0x01)
// let x := 0x05
// { x := or(0x06, id1) }
// ret_1 := or(id1, x)
// }
// }