Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mask generator optimizations #15935

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Language Features:


Compiler Features:

* Constant Optimizer: Compute masks using shifts when optimizing for size.

Bugfixes:
* SMTChecker: Fix incorrect analysis when only a subset of contracts is selected with `--model-checker-contracts`.
Expand Down
20 changes: 19 additions & 1 deletion libevmasm/ConstantOptimiser.cpp
Copy link
Member

@cameel cameel Mar 15, 2025

Choose a reason for hiding this comment

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

@ekpyron Not strictly related to the PR, but while looking at it I noticed that ConstantOptimisationMethod::simpleRunGas() does not account for the new AssemblyItem types we introduced for EOF.

Especially DUPN and SWAPN. Though fortunately it should not have any real consequences because we are not using them in constant optimizer yet (heads up @rodiazet).

Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,25 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
if (_value < 0x10000)
// Very small value, not worth computing
return AssemblyItems{_value};
else if (numberEncodingSize(~_value) < numberEncodingSize(_value))

// check for masks first
unsigned lowZeros = 0;
unsigned highOnes = 0;
for (; ((_value >> lowZeros) & 1) == 0 && lowZeros < 256; lowZeros++) {}
for (; ((_value >> (lowZeros + highOnes)) & 1) == 1 && highOnes < 256; highOnes++) {}
if (m_params.evmVersion.hasBitwiseShifting() && highOnes > 32 &&
((_value >> (lowZeros + highOnes)) == 0) &&
((lowZeros + highOnes < 256) || lowZeros > 16))
{
// this is a big enough mask to use zero negation
AssemblyItems newRoutine = AssemblyItems{u256(0), Instruction::NOT};
if ((highOnes + lowZeros) != 256)
newRoutine += AssemblyItems{u256(256 - highOnes), Instruction::SHR};
if (lowZeros > 0)
newRoutine += AssemblyItems{u256(lowZeros), Instruction::SHL};
return newRoutine;
}
if (numberEncodingSize(~_value) < numberEncodingSize(_value))
// Negated is shorter to represent
return findRepresentation(~_value) + AssemblyItems{Instruction::NOT};
else
Expand Down
4 changes: 2 additions & 2 deletions test/cmdlineTests/optimizer_BlockDeDuplicator/output
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ EVM assembly:
0x00
dup1
sload
not(sub(shl(0x40, 0x01), 0x01))
shl(0x40, not(0x00))
and
/* "optimizer_BlockDeDuplicator/input.sol":201:206 fun_x */
or(tag_0_7, shl(0x20, tag_2))
sub(shl(0x40, 0x01), 0x01)
shr(0xc0, not(0x00))
/* "optimizer_BlockDeDuplicator/input.sol":179:210 function() r = true ? fun_x : f */
and
or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ sub_0: assembly {
/* "optimizer_inliner_dynamic_reference/input.sol":147:152 x = f */
dup1
sload
not(0xffffffffffffffff)
shl(0x40, not(0x00))
and
/* "optimizer_inliner_dynamic_reference/input.sol":151:152 f */
tag_17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ tag_1:
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":93:98 x = f */
dup1
sload
not(sub(shl(0x40, 0x01), 0x01))
shl(0x40, not(0x00))
and
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":97:98 f */
or(tag_0_12, shl(0x20, tag_4))
sub(shl(0x40, 0x01), 0x01)
shr(0xc0, not(0x00))
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":93:98 x = f */
and
or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
dup4
add
swap2
sub(shl(0x40, 0x01), 0x01)
shr(0xc0, not(0x00))
dup4
gt
dup5
Expand Down Expand Up @@ -104,7 +104,7 @@ sub_0: assembly {
jumpi(tag_26, callvalue)
jumpi(tag_26, slt(add(not(0x03), calldatasize), 0x00))
sload(0x00)
sub(shl(0xff, 0x01), 0x01)
shr(0x01, not(0x00))
dup2
eq
tag_14
Expand Down Expand Up @@ -350,7 +350,7 @@ sub_0: assembly {
dup4
add
swap2
sub(shl(0x40, 0x01), 0x01)
shr(0xc0, not(0x00))
dup4
gt
dup5
Expand Down Expand Up @@ -450,7 +450,7 @@ sub_0: assembly {
jumpi(tag_26, callvalue)
jumpi(tag_26, slt(add(not(0x03), calldatasize), 0x00))
sload(0x00)
sub(shl(0xff, 0x01), 0x01)
shr(0x01, not(0x00))
dup2
eq
tag_14
Expand Down
4 changes: 2 additions & 2 deletions test/cmdlineTests/viair_subobject_optimization/output
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ EVM assembly:
dup4
add
swap2
sub(shl(0x40, 0x01), 0x01)
shr(0xc0, not(0x00))
dup4
gt
dup5
Expand Down Expand Up @@ -223,7 +223,7 @@ sub_0: assembly {
dup4
add
swap2
sub(shl(0x40, 0x01), 0x01)
shr(0xc0, not(0x00))
dup4
gt
dup5
Expand Down
6 changes: 3 additions & 3 deletions test/libsolidity/gasTests/abiv2_optimised.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ contract C {
// optimize-yul: true
// ----
// creation:
// codeDepositCost: 618200
// executionCost: 649
// totalCost: 618849
// codeDepositCost: 605600
// executionCost: 636
// totalCost: 606236
// external:
// a(): 2283
// b(uint256): 4649
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ contract C {
}
// ----
// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg"
// gas irOptimized: 135499
// gas irOptimized: 135563
// gas legacy: 137095
// gas legacyOptimized: 135823
// gas legacyOptimized: 135879
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ contract C {
}
// ----
// f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb
// gas irOptimized: 203167
// gas irOptimized: 203255
// gas legacy: 206263
// gas legacyOptimized: 203172
// gas legacyOptimized: 203220
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ contract C {
// EVMVersion: >homestead
// ----
// test_bytes() ->
// gas irOptimized: 314884
// gas irOptimized: 310684
// gas legacy: 305816
// gas legacyOptimized: 253573
// gas legacyOptimized: 248777
// test_uint256() ->
// gas irOptimized: 448346
// gas irOptimized: 440498
// gas legacy: 421304
// gas legacyOptimized: 351544
// gas legacyOptimized: 343112
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ contract C {
// EVMVersion: >homestead
// ----
// test_bytes() ->
// gas irOptimized: 314884
// gas irOptimized: 310684
// gas legacy: 305816
// gas legacyOptimized: 253573
// gas legacyOptimized: 248777
// test_uint256() ->
// gas irOptimized: 448346
// gas irOptimized: 440498
// gas legacy: 421304
// gas legacyOptimized: 351544
// gas legacyOptimized: 343112
4 changes: 2 additions & 2 deletions test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ contract C {
// f2() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc"
// f3() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc"
// f4() -> 0x20, 0x160, 0x1, 0x80, 0xc0, 0x2, 0x3, "abc", 0x7, 0x40, 0x2, 0x2, 0x3
// gas irOptimized: 111816
// gas irOptimized: 111812
// gas legacy: 113890
// gas legacyOptimized: 111658
// gas legacyOptimized: 111654
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ contract C is B {
}
// ----
// test() -> 77
// gas irOptimized: 55117
// gas irOptimized code: 56800
// gas irOptimized: 55177
// gas irOptimized code: 54400
// gas legacy: 57266
// gas legacy code: 94600
// gas legacyOptimized: 55195
// gas legacyOptimized: 55191
// gas legacyOptimized code: 55000
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ contract C {
// f(uint256[][1]): 32, 32, 0 -> true
// f(uint256[][1]): 32, 32, 1, 42 -> true
// f(uint256[][1]): 32, 32, 8, 421, 422, 423, 424, 425, 426, 427, 428 -> true
// gas irOptimized: 120978
// gas irOptimized: 118550
// gas legacy: 101568
// gas legacyOptimized: 119092
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ contract C {
// f_which(uint256[],uint256[2],uint256): 0x40, 1, 2, 1, 5, 6 -> 0x20, 0x40, 5, 2
// f_which(uint256[],uint256[2],uint256): 0x40, 1, 2, 1 -> FAILURE
// f_storage(uint256[],uint256[2]): 0x20, 1, 2 -> 0x20, 0x60, 0x20, 1, 2
// gas irOptimized: 111409
// gas irOptimized: 111441
// gas legacy: 112707
// gas legacyOptimized: 111845
// gas legacyOptimized: 111861
// f_storage(uint256[],uint256[2]): 0x40, 1, 2, 5, 6 -> 0x20, 0x80, 0x20, 2, 5, 6
// f_storage(uint256[],uint256[2]): 0x40, 1, 2, 5 -> FAILURE
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ contract C {
// EVMVersion: >homestead
// ----
// h(uint256[2][]): 0x20, 3, 123, 124, 223, 224, 323, 324 -> 32, 256, 0x20, 3, 123, 124, 223, 224, 323, 324
// gas irOptimized: 180080
// gas irOptimized: 180104
// gas legacy: 184233
// gas legacyOptimized: 180856
// i(uint256[2][2]): 123, 124, 223, 224 -> 32, 128, 123, 124, 223, 224
// gas irOptimized: 112031
// gas irOptimized: 112039
// gas legacy: 115091
// gas legacyOptimized: 112657
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ contract Test {
}
// ----
// set(uint24[3][]): 0x20, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 -> 0x06
// gas irOptimized: 185216
// gas irOptimized: 185288
// gas legacy: 211054
// gas legacyOptimized: 206077
// gas legacyOptimized: 206149
// data(uint256,uint256): 0x02, 0x02 -> 0x09
// data(uint256,uint256): 0x05, 0x01 -> 0x11
// data(uint256,uint256): 0x06, 0x00 -> FAILURE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ contract c {
// test() -> 0
// gas irOptimized: 122717
// gas legacy: 147108
// gas legacyOptimized: 144200
// gas legacyOptimized: 143790
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ contract C {
}
// ----
// constructor(): 1, 2, 3 ->
// gas irOptimized: 124991
// gas irOptimized: 124887
// gas irOptimized code: 14800
// gas legacy: 134317
// gas legacy code: 46200
// gas legacyOptimized: 127166
// gas legacyOptimized: 127114
// gas legacyOptimized code: 23400
// a(uint256): 0 -> 1
// a(uint256): 1 -> 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ contract C {
}
// ----
// f() -> true
// gas irOptimized: 122541
// gas irOptimized: 122810
// gas legacy: 124643
// gas legacyOptimized: 122801
// gas legacyOptimized: 123108
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ contract c {
}
// ----
// test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x05000000000000000000000000000000000000000000000000
// gas irOptimized: 208415
// gas irOptimized: 208657
// gas legacy: 220711
// gas legacyOptimized: 220097
// gas legacyOptimized: 220354
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ contract c {
}
// ----
// test() -> 5, 4
// gas irOptimized: 205667
// gas irOptimized: 205763
// gas legacy: 213863
// gas legacyOptimized: 212901
// gas legacyOptimized: 212981
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ contract c {
}
// ----
// test() -> 3, 4
// gas irOptimized: 169669
// gas irOptimized: 169619
// gas legacy: 175415
// gas legacyOptimized: 172533
// gas legacyOptimized: 172479
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ contract c {
// ----
// setData1(uint256,uint256,uint256): 10, 5, 4 ->
// copyStorageStorage() ->
// gas irOptimized: 111350
// gas irOptimized: 111358
// gas legacy: 109272
// gas legacyOptimized: 109262
// getData2(uint256): 5 -> 10, 4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ contract c {
}
// ----
// test() -> 4, 5
// gas irOptimized: 190628
// gas irOptimized: 190621
// gas legacy: 190828
// gas legacyOptimized: 189657
// storageEmpty -> 1
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ contract c {
}
// ----
// test() -> 0xffffffff, 0x0000000000000000000000000a00090008000700060005000400030002000100, 0x0000000000000000000000000000000000000000000000000000000000000000
// gas irOptimized: 100496
// gas irOptimized: 100492
// gas legacy: 158109
// gas legacyOptimized: 141019
// gas legacyOptimized: 140891
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ contract c {
}
// ----
// test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x0
// gas irOptimized: 273543
// gas irOptimized: 273515
// gas legacy: 282601
// gas legacyOptimized: 281510
// gas legacyOptimized: 281424
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ contract c {
}
// ----
// test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x00
// gas irOptimized: 232995
// gas irOptimized: 233107
// gas legacy: 235694
// gas legacyOptimized: 235193
// gas legacyOptimized: 235102
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ contract C {
}
// ----
// from_storage() -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
// gas irOptimized: 149868
// gas irOptimized: 149940
// gas legacy: 150737
// gas legacyOptimized: 148690
// from_storage_ptr() -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ contract c {
// compileViaYul: true
// ----
// test1(uint256[][]): 0x20, 2, 0x40, 0x40, 2, 23, 42 -> 2, 65
// gas irOptimized: 181029
// gas irOptimized: 181093
// test2(uint256[][2]): 0x20, 0x40, 0x40, 2, 23, 42 -> 2, 65
// gas irOptimized: 157604
// gas irOptimized: 157660
// test3(uint256[2][]): 0x20, 2, 23, 42, 23, 42 -> 2, 65
// gas irOptimized: 134801
// gas irOptimized: 134817
// test4(uint256[2][2]): 23, 42, 23, 42 -> 65
// gas irOptimized: 111177
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ contract C {
}
// ----
// copyExternalStorageArrayOfFunctionType() -> true
// gas irOptimized: 104566
// gas irOptimized: 104654
// gas legacy: 108554
// gas legacyOptimized: 102405
// gas legacyOptimized: 102465
// copyInternalArrayOfFunctionType() -> true
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ contract C {
}
// ----
// copyExternalStorageArraysOfFunctionType() -> true
// gas irOptimized: 104238
// gas irOptimized: 104326
// gas legacy: 108295
// gas legacyOptimized: 102162
// gas legacyOptimized: 102222
// copyInternalArrayOfFunctionType() -> true
// gas legacy: 104178
Loading