ethereum / solidity

Solidity, the Smart Contract Programming Language
https://soliditylang.org
GNU General Public License v3.0
23.28k stars 5.77k forks source link

Signed int256 addition optimization #15283

Open Czar102 opened 3 months ago

Czar102 commented 3 months ago

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 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:

let overflow := xor(check0, check1)

Specification

Consider altering the following code in YulUtilFunctions.cpp#734-737:

if or(
    and(iszero(slt(x, 0)), slt(sum, y)),
    and(slt(x, 0), iszero(slt(sum, y)))
) { <panic>() }

into the following:

if xor(slt(x, 0), slt(sum, y)) { <panic>() }

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.

GAMECHANGE commented 3 months ago

IMG_2976