mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Move AND with constant inside OR.
This commit is contained in:
parent
1d95f95635
commit
40c27ccc22
@ -4,6 +4,7 @@ Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Optimizer: Try to move ``and`` with constant inside ``or`` to improve storage writes of small types.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
@ -507,6 +507,23 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
||||
});
|
||||
}
|
||||
|
||||
// Combine alternating AND/OR/AND with constant,
|
||||
// AND(OR(AND(X, A), Y), B) -> OR(AND(X, A & B), AND(Y, B))
|
||||
// Many versions due to commutativity.
|
||||
for (auto const& inner: {Builtins::AND(X, A), Builtins::AND(A, X)})
|
||||
for (auto const& second: {Builtins::OR(inner, Y), Builtins::OR(Y, inner)})
|
||||
{
|
||||
// We might swap X and Y but this is not an issue anymore.
|
||||
rules.push_back({
|
||||
Builtins::AND(second, B),
|
||||
[=]() -> Pattern { return Builtins::OR(Builtins::AND(X, A.d() & B.d()), Builtins::AND(Y, B)); }
|
||||
});
|
||||
rules.push_back({
|
||||
Builtins::AND(B, second),
|
||||
[=]() -> Pattern { return Builtins::OR(Builtins::AND(X, A.d() & B.d()), Builtins::AND(Y, B)); }
|
||||
});
|
||||
}
|
||||
|
||||
rules.push_back({
|
||||
// MUL(X, SHL(Y, 1)) -> SHL(Y, X)
|
||||
Builtins::MUL(X, Builtins::SHL(Y, Word(1))),
|
||||
|
1
test/cmdlineTests/optimize_full_storage_write/args
Normal file
1
test/cmdlineTests/optimize_full_storage_write/args
Normal file
@ -0,0 +1 @@
|
||||
--optimize --asm --metadata-hash none
|
12
test/cmdlineTests/optimize_full_storage_write/input.sol
Normal file
12
test/cmdlineTests/optimize_full_storage_write/input.sol
Normal file
@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract OptimizeFullSlotWrite {
|
||||
uint64[4] nums;
|
||||
function f() public {
|
||||
nums[0] = 11111;
|
||||
nums[1] = 22222;
|
||||
nums[2] = 33333;
|
||||
nums[3] = 44444;
|
||||
}
|
||||
}
|
64
test/cmdlineTests/optimize_full_storage_write/output
Normal file
64
test/cmdlineTests/optimize_full_storage_write/output
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
======= optimize_full_storage_write/input.sol:OptimizeFullSlotWrite =======
|
||||
EVM assembly:
|
||||
/* "optimize_full_storage_write/input.sol":60:213 contract OptimizeFullSlotWrite {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
dataSize(sub_0)
|
||||
dup1
|
||||
dataOffset(sub_0)
|
||||
0x00
|
||||
codecopy
|
||||
0x00
|
||||
return
|
||||
stop
|
||||
|
||||
sub_0: assembly {
|
||||
/* "optimize_full_storage_write/input.sol":60:213 contract OptimizeFullSlotWrite {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
jumpi(tag_2, lt(calldatasize, 0x04))
|
||||
shr(0xe0, calldataload(0x00))
|
||||
dup1
|
||||
0x26121ff0
|
||||
eq
|
||||
tag_3
|
||||
jumpi
|
||||
tag_2:
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
/* "optimize_full_storage_write/input.sol":111:211 function f() public {... */
|
||||
tag_3:
|
||||
tag_4
|
||||
/* "optimize_full_storage_write/input.sol":192:207 nums[3] = 44444 */
|
||||
0xad9c000000000000823500000000000056ce0000000000002b67
|
||||
/* "optimize_full_storage_write/input.sol":135:139 nums */
|
||||
0x00
|
||||
/* "optimize_full_storage_write/input.sol":192:207 nums[3] = 44444 */
|
||||
sstore
|
||||
/* "optimize_full_storage_write/input.sol":111:211 function f() public {... */
|
||||
jump
|
||||
tag_4:
|
||||
stop
|
||||
|
||||
auxdata: <AUXDATA REMOVED>
|
||||
}
|
32
test/formal/move_and_inside_or.py
Normal file
32
test/formal/move_and_inside_or.py
Normal file
@ -0,0 +1,32 @@
|
||||
from rule import Rule
|
||||
from opcodes import *
|
||||
|
||||
"""
|
||||
Rule:
|
||||
AND(OR(AND(X, A), Y), B) -> OR(AND(X, A & B), AND(Y, B))
|
||||
"""
|
||||
|
||||
rule = Rule()
|
||||
|
||||
# bit width is irrelevant
|
||||
n_bits = 128
|
||||
|
||||
# Input vars
|
||||
X = BitVec('X', n_bits)
|
||||
Y = BitVec('Y', n_bits)
|
||||
A = BitVec('A', n_bits)
|
||||
B = BitVec('B', n_bits)
|
||||
|
||||
# Non optimized result, explicit form
|
||||
nonopt = AND(OR(AND(X, A), Y), B)
|
||||
|
||||
# Optimized result
|
||||
opt = OR(AND(X, A & B), AND(Y, B))
|
||||
|
||||
rule.check(nonopt, opt)
|
||||
|
||||
# Now the forms as they are constructod in the code.
|
||||
for inner in [AND(X, A), AND(A, X)]:
|
||||
for second in [OR(inner, Y), OR(Y, inner)]:
|
||||
rule.check(AND(second, B), opt)
|
||||
rule.check(AND(B, second), opt)
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
// Tests that masks that "add" up to
|
||||
// the full bit width are removed.
|
||||
let a := sload(0)
|
||||
let x := sload(a)
|
||||
let mask := 0xffffffffffffffff
|
||||
x := or(and(x, not(mask)), 0x2b67)
|
||||
mask := shl(64, mask)
|
||||
x := or(and(x, not(mask)), 0x56ce0000000000000000)
|
||||
mask := shl(64, mask)
|
||||
x := or(and(x, not(mask)), shl(0x80, 0x8235))
|
||||
mask := shl(64, mask)
|
||||
x := or(and(x, not(mask)), shl(0xc2, 0x2b67))
|
||||
sstore(a, x)
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >byzantium
|
||||
// ----
|
||||
// step: fullSuite
|
||||
//
|
||||
// {
|
||||
// {
|
||||
// sstore(sload(0), 0xad9c000000000000823500000000000056ce0000000000002b67)
|
||||
// }
|
||||
// }
|
Loading…
Reference in New Issue
Block a user