I think the current implementation of int256 addition overflow check is quite suboptimal. The optimizer seems not to be able to catch this possible optimization, probably because it's unaware of the bounds of the inputs.
Motivation
The compiler seems to be outputting the following Yul equivalent when intending to add two signed integers a and b (thanks to Dedaub for the decompiler):
let res := add(b, a)
let check0 := slt(res, a)
let check1 := slt(b, 0x0)
let overflow := or(and(iszero(check1), check0), and(check1, iszero(check0)))
if overflow {
mstore(0x0, 0x4e487b7100000000000000000000000000000000000000000000000000000000)
mstore(0x4, 0x11)
revert(0x0, 0x24)
}
This is quite inefficient. Since slt returns 0 or 1, we can use xor instead of an or, two ands and two iszeros:
This is just a bytecode generation improvement. Should be fully backward compatible.
PS. I don't know the structure of the codebase very well, so I'm not comfortable writing a PR for this – this is why I'm raising this as an issue. Sorry for any additional effort needed due to this.
Abstract
I think the current implementation of int256 addition overflow check is quite suboptimal. The optimizer seems not to be able to catch this possible optimization, probably because it's unaware of the bounds of the inputs.
Motivation
The compiler seems to be outputting the following Yul equivalent when intending to add two signed integers
a
andb
(thanks to Dedaub for the decompiler):This is quite inefficient. Since
slt
returns 0 or 1, we can usexor
instead of anor
, twoand
s and twoiszero
s:Specification
Consider altering the following code in
YulUtilFunctions.cpp#734-737
:into the following:
Backwards Compatibility
This is just a bytecode generation improvement. Should be fully backward compatible.
PS. I don't know the structure of the codebase very well, so I'm not comfortable writing a PR for this – this is why I'm raising this as an issue. Sorry for any additional effort needed due to this.