diff --git a/Changelog.md b/Changelog.md index 2e857a89f..28a1eff05 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Compiler Features: Bugfixes: + * Optimizer: Keep side-effects of ``x`` in ``byte(a, shr(b, x))`` even if the constants ``a`` and ``b`` would make the expression zero unconditionally. This optimizer rule is very hard if not impossible to trigger in a way that it can result in invalid code, though. * SMTChecker: Fix internal error on fixed bytes index access. diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h index 93ccdcaf9..1e3fd7800 100644 --- a/libevmasm/RuleList.h +++ b/libevmasm/RuleList.h @@ -581,9 +581,20 @@ std::vector> simplificationRuleListPart7( rules.push_back({ Builtins::BYTE(A, Builtins::SHR(B, X)), - [=]() -> Pattern { return A.d() < B.d() / 8 ? Word(0) : Builtins::BYTE(A.d() - B.d() / 8, X); }, + [=]() -> Pattern { return Word(0); }, + true, + [=] { + return B.d() % 8 == 0 && A.d() < Pattern::WordSize / 8 && B.d() <= Pattern::WordSize && A.d() < B.d() / 8; + } + }); + + rules.push_back({ + Builtins::BYTE(A, Builtins::SHR(B, X)), + [=]() -> Pattern { return Builtins::BYTE(A.d() - B.d() / 8, X); }, false, - [=] { return B.d() % 8 == 0 && A.d() < Pattern::WordSize / 8 && B.d() <= Pattern::WordSize; } + [=] { + return B.d() % 8 == 0 && A.d() < Pattern::WordSize / 8 && B.d() <= Pattern::WordSize && A.d() >= B.d() / 8; + } }); return rules; diff --git a/test/libyul/yulInterpreterTests/pop_byte_shr_call.yul b/test/libyul/yulInterpreterTests/pop_byte_shr_call.yul new file mode 100644 index 000000000..4e431a6b1 --- /dev/null +++ b/test/libyul/yulInterpreterTests/pop_byte_shr_call.yul @@ -0,0 +1,10 @@ +{ + pop(byte(0, shr(0x8, call(0, 0, 0, 0, 0, 0, 0)))) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Trace: +// CALL(0, 0, 0, 0, 0, 0, 0) +// Memory dump: +// Storage dump: diff --git a/test/libyul/yulInterpreterTests/pop_byte_shr_func.yul b/test/libyul/yulInterpreterTests/pop_byte_shr_func.yul new file mode 100644 index 000000000..b520b9181 --- /dev/null +++ b/test/libyul/yulInterpreterTests/pop_byte_shr_func.yul @@ -0,0 +1,11 @@ +{ + function f() -> x { mstore(0, 0x1337) } + pop(byte(0, shr(0x8, f()))) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Trace: +// Memory dump: +// 0: 0000000000000000000000000000000000000000000000000000000000001337 +// Storage dump: diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_call.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_call.yul new file mode 100644 index 000000000..e30a0418c --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_call.yul @@ -0,0 +1,11 @@ +{ + pop(byte(0, shr(0x8, call(0, 0, 0, 0, 0, 0, 0)))) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// step: expressionSimplifier +// +// { +// pop(byte(0, shr(0x8, call(0, 0, 0, 0, 0, 0, 0)))) +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func.yul new file mode 100644 index 000000000..f24add1dd --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func.yul @@ -0,0 +1,14 @@ +{ + function f() -> x { mstore(0, 1337) } + pop(byte(0, shr(0x8, f()))) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// step: expressionSimplifier +// +// { +// function f() -> x +// { mstore(0, 1337) } +// pop(byte(0, shr(0x8, f()))) +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func_trivial.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func_trivial.yul new file mode 100644 index 000000000..3fc5ee558 --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func_trivial.yul @@ -0,0 +1,14 @@ +{ + function f() -> x {} + pop(byte(0, shr(0x8, f()))) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// step: expressionSimplifier +// +// { +// function f() -> x +// { } +// pop(byte(0, shr(0x8, f()))) +// }