Open molly-ting opened 1 month ago
Another similar case is the external call.
function extcall(uint256 a) public returns(uint256) {
uint256 res = 0;
try l.lib(a) returns (uint256 tmp) {
res=tmp*2;
} catch {
res = 1;
}
return res;
}
The above function will generate the following opcode.
DUP1 ISZERO PUSH2 0xF5 JUMPI POP PUSH1 0x40 MLOAD ... JUMP JUMPDEST PUSH1 0x1 JUMPDEST PUSH2 0x102 JUMPI PUSH1 0x1 SWAP1 POP
The corresponding assembly code is:
...
tag_11:
...
gas
call
swap3
pop
pop
pop
dup1
iszero
tag_12
jumpi
pop
mload(0x40)
…
jump // in
tag_13:
0x01
tag_12:
/* "extcall.sol":481:589 try l.lib(a) returns (uint256 tmp) {... */
tag_15
jumpi
/* "extcall.sol":577:578 1 */
0x01
/* "extcall.sol":571:578 res = 1 */
swap1
pop
/* "extcall.sol":481:589 try l.lib(a) returns (uint256 tmp) {... */
jump(tag_19)
...
In tag_11, there is a 'POP' just after 'JUMPI', which means the original value of the DUP is not used. Although this value is used in the other branch(tag_12), this can also be optimized.
Specifically, moving tag_12 after tag_15 jumpi
would achieve this optimization. The resulting assembly code is as follows:
...
tag_11:
...
gas
call
swap3
pop
pop
pop
iszero
tag_12
jumpi
mload(0x40)
…
jump // in
tag_13:
0x01
/* "extcall.sol":481:589 try l.lib(a) returns (uint256 tmp) {... */
tag_15
jumpi
tag_12:
/* "extcall.sol":577:578 1 */
0x01
/* "extcall.sol":571:578 res = 1 */
swap1
pop
/* "extcall.sol":481:589 try l.lib(a) returns (uint256 tmp) {... */
jump(tag_19)
...
https://github.com/ethereum/solidity/blob/b849b327781cb71478709b28c4d0d372492cbdc1/libsolidity/codegen/ExpressionCompiler.cpp#L2854-L2859 https://github.com/ethereum/solidity/blob/b849b327781cb71478709b28c4d0d372492cbdc1/libsolidity/codegen/ExpressionCompiler.cpp#L2923-L2928 In this function, endTag is tag_12 in this example. https://github.com/ethereum/solidity/blob/b849b327781cb71478709b28c4d0d372492cbdc1/libsolidity/codegen/ContractCompiler.cpp#L965-L977 In this function, successTag is tag_15 in this example. Is it possible to move the conditionalJump in this function to the front of the endTag in the function appendExternalFunctionCall so that we can save one duplication and pop?
Could someone take a look at this? I believe it could reduce gas consumption
Description
The above function will generate the following opcode.
The corresponding assembly code is:
In tag_7, there is a 'POP' just after 'JUMPI', which means the original value of the DUP is not used. Although this value is used in the other branch(tag_11), this can also be optimized.
Optimization
Specifically, moving tag_11 after
iszero tag_12 jumpi
would achieve this optimization. The resulting assembly code is as follows:In this way, for a>b, it will execute
PUSH1 DUP2 DUP4 GT PUSH2 JUMPI JUMPDEST DUP2 DUP4
instead ofPUSH1 DUP2 DUP4 GT DUP1 PUSH2 JUMPI JUMPDEST ISZERO PUSH2 JUMPI DUP2 DUP4
. For a<=b and a>100, it will executePUSH1 DUP2 DUP4 GT PUSH2 JUMPI PUSH1 DUP4 GT ISZERO PUSH2 JUMPI JUMPDEST DUP2 DUP4
instead ofPUSH1 DUP2 DUP4 GT DUP1 PUSH2 JUMPI POP PUSH1 DUP4 GT JUMPDEST ISZERO PUSH2 JUMPI DUP2 DUP4
. https://github.com/ethereum/solidity/blob/b849b327781cb71478709b28c4d0d372492cbdc1/libsolidity/codegen/ExpressionCompiler.cpp#L2367-L2380 In this function, the endLabel is tag_11 in this example. https://github.com/ethereum/solidity/blob/b849b327781cb71478709b28c4d0d372492cbdc1/libsolidity/codegen/ContractCompiler.cpp#L1153-L1172 Is it possible to move the Instruction::ISZERO and conditionalJump in this function to the front of the endLabel in the function appendAndOrOperatorCode?