Skip to content

Commit 797057a

Browse files
author
Mohammad Rezaei
committed
Mask generator optimizations
1 parent 33e14df commit 797057a

File tree

144 files changed

+717
-675
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+717
-675
lines changed

Changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Language Features:
66
Compiler Features:
77
* NatSpec: Capture Natspec documentation of `enum` values in the AST.
88

9+
* Constant Optimizer: Compute masks using shifts when optimizing for size; use an ``--optimizer-runs`` value less than 200 for maximum size reduction.
910

1011
Bugfixes:
1112
* SMTChecker: Do not consider loop conditions as constant-condition verification target as this could cause incorrect reports and internal compiler errors.

libevmasm/ConstantOptimiser.cpp

+41-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,47 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
253253
if (_value < 0x10000)
254254
// Very small value, not worth computing
255255
return AssemblyItems{_value};
256-
else if (numberEncodingSize(~_value) < numberEncodingSize(_value))
256+
257+
// check for masks first
258+
unsigned lowZeros = 0;
259+
unsigned highOnes = 0;
260+
for (; ((_value >> lowZeros) & 1) == 0 && lowZeros < 256; lowZeros++) {}
261+
for (; ((_value >> (lowZeros + highOnes)) & 1) == 1 && highOnes < 256; highOnes++) {}
262+
if (m_params.evmVersion.hasBitwiseShifting() && highOnes > 32 &&
263+
((_value >> (lowZeros + highOnes)) == 0) &&
264+
((lowZeros + highOnes < 256) || lowZeros > 16))
265+
{
266+
// this is a big enough mask to use zero negation
267+
AssemblyItems newRoutine = AssemblyItems{u256(0), Instruction::NOT};
268+
if ((highOnes + lowZeros) != 256)
269+
newRoutine += AssemblyItems{u256(256 - highOnes), Instruction::SHR};
270+
if (lowZeros > 0)
271+
newRoutine += AssemblyItems{u256(lowZeros), Instruction::SHL};
272+
return newRoutine;
273+
}
274+
// check powers of 10
275+
u256 divBy10 = _value;
276+
unsigned pow10 = 0;
277+
while (divBy10 > 0 && divBy10 % 10 == 0)
278+
{
279+
divBy10 = divBy10 / 10;
280+
pow10++;
281+
}
282+
// 10^9 = 0x3b9aca00; requires 5 bytes with PUSH4; also 5 bytes with PUSH 5 PUSH 10 EXP
283+
if (pow10 > 9 && divBy10 == 1)
284+
{
285+
// pure power of 10
286+
return AssemblyItems{u256(pow10), u256(10), Instruction::EXP};
287+
}
288+
// 10^x * y can be encoded as: push x push 10 exp push y mul. That's about 7 bytes more than plain push
289+
if (pow10 > 12)
290+
{
291+
AssemblyItems newRoutine = findRepresentation(divBy10);
292+
newRoutine += AssemblyItems{u256(pow10), u256(10), Instruction::EXP, Instruction::MUL};
293+
return newRoutine;
294+
}
295+
if (numberEncodingSize(~_value) < numberEncodingSize(_value) &&
296+
(lowZeros+highOnes < 256 || highOnes > 16))
257297
// Negated is shorter to represent
258298
return findRepresentation(~_value) + AssemblyItems{Instruction::NOT};
259299
else

test/cmdlineTests/optimizer_BlockDeDuplicator/output

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ EVM assembly:
77
0x00
88
dup1
99
sload
10-
not(sub(shl(0x40, 0x01), 0x01))
10+
shl(0x40, not(0x00))
1111
and
1212
/* "input.sol":201:206 fun_x */
1313
or(tag_0_7, shl(0x20, tag_2))
14-
sub(shl(0x40, 0x01), 0x01)
14+
shr(0xc0, not(0x00))
1515
/* "input.sol":179:210 function() r = true ? fun_x : f */
1616
and
1717
or

test/cmdlineTests/optimizer_inliner_dynamic_reference/output

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ sub_0: assembly {
8484
/* "input.sol":147:152 x = f */
8585
dup1
8686
sload
87-
not(0xffffffffffffffff)
87+
shl(0x40, not(0x00))
8888
and
8989
/* "input.sol":151:152 f */
9090
tag_17

test/cmdlineTests/optimizer_inliner_dynamic_reference_constructor/output

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ tag_1:
1717
/* "input.sol":93:98 x = f */
1818
dup1
1919
sload
20-
not(sub(shl(0x40, 0x01), 0x01))
20+
shl(0x40, not(0x00))
2121
and
2222
/* "input.sol":97:98 f */
2323
or(tag_0_12, shl(0x20, tag_4))
24-
sub(shl(0x40, 0x01), 0x01)
24+
shr(0xc0, not(0x00))
2525
/* "input.sol":93:98 x = f */
2626
and
2727
or

test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
dup4
2121
add
2222
swap2
23-
sub(shl(0x40, 0x01), 0x01)
23+
shr(0xc0, not(0x00))
2424
dup4
2525
gt
2626
dup5
@@ -104,7 +104,7 @@ sub_0: assembly {
104104
jumpi(tag_26, callvalue)
105105
jumpi(tag_26, slt(add(not(0x03), calldatasize), 0x00))
106106
sload(0x00)
107-
sub(shl(0xff, 0x01), 0x01)
107+
shr(0x01, not(0x00))
108108
dup2
109109
eq
110110
tag_14
@@ -350,7 +350,7 @@ sub_0: assembly {
350350
dup4
351351
add
352352
swap2
353-
sub(shl(0x40, 0x01), 0x01)
353+
shr(0xc0, not(0x00))
354354
dup4
355355
gt
356356
dup5
@@ -450,7 +450,7 @@ sub_0: assembly {
450450
jumpi(tag_26, callvalue)
451451
jumpi(tag_26, slt(add(not(0x03), calldatasize), 0x00))
452452
sload(0x00)
453-
sub(shl(0xff, 0x01), 0x01)
453+
shr(0x01, not(0x00))
454454
dup2
455455
eq
456456
tag_14

test/cmdlineTests/viair_subobject_optimization/output

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ EVM assembly:
1818
dup4
1919
add
2020
swap2
21-
sub(shl(0x40, 0x01), 0x01)
21+
shr(0xc0, not(0x00))
2222
dup4
2323
gt
2424
dup5
@@ -223,7 +223,7 @@ sub_0: assembly {
223223
dup4
224224
add
225225
swap2
226-
sub(shl(0x40, 0x01), 0x01)
226+
shr(0xc0, not(0x00))
227227
dup4
228228
gt
229229
dup5

0 commit comments

Comments
 (0)