Poor optimization of `call` and `staticcall` with `--via-ir`
- Dominant language
- C++
- Stars
- 25.7k
- Forks
- 6.2k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 29
Description
## Description
I came across that calls are rather poorly optimized with `--via-ir`, although everything else is much better with this flag.
## Environment
- Compiler version: 0.8.26+commit.8a97fa7a.Linux.g++
- Target EVM version (as per compiler settings): cancun
- Framework/IDE (e.g. Truffle or Remix): none
- EVM execution environment / backend / blockchain client: none
- Operating system: Linux
## Steps to Reproduce
`MyContract.sol`
```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;
contract MyContract {
function sendViaCall(address payable to) public payable {
(bool sent,) = to.call{value: msg.value}("");
require(sent);
}
}
```
```
$ solc --optimize --via-ir --no-cbor-metadata --bin-runtime MyContract.sol
======= MyContract.sol:MyContract =======
Binary of the runtime part:
608060405260043610156010575f80fd5b5f3560e01c63830c29ae146022575f80fd5b60203660031901126097576004356001600160a01b038116908190036097575f8080809334905af13d1560af573d67ffffffffffffffff8111609b5760405190601f8101601f19908116603f0116820167ffffffffffffffff811183821017609b5760405281525f60203d92013e5b15609757005b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b609156
```
Then I use decompiler like https://app.dedaub.com to look at the Yul pseudo code. I don't understand why check is made to ensure that the free memory pointer does not exceed `0xffffffffffffffff`. This makes no sense since `retOffset` and
`retSize` have been set to `0`.
```yul
function func_sendViaCall() {
let _3 := slt(add(not(0x3), calldatasize()), 0x20)
require(_3)
let _4 := calldataload(0x4)
let _5 := and(_4, sub(shl(0xa0, 0x1), 0x1))
let _6 := sub(_4, _5)
require(_6)
let _7 := call(gas(), _5, callvalue(), 0x0, 0x0, 0x0, 0x0)
let _8 := iszero(returndatasize())
if not(_8){
let _9 := returndatasize()
let _10 := gt(_9, 0xffffffffffffffff)
if _10{
mstore(0x0, shl(0xe0, 0x4e487b71))
mstore(0x4, 0x41)
revert(0x0, 0x24)
}
if not(_10){
let _11 := mload(0x40)
let _12 := not(0x1f)
let _13 := add(_11, and(add(0x3f, and(_12, add(_9, 0x1f))), _12))
let _14 := or(lt(_13, _11), gt(_13, 0xffffffffffffffff))
if _14{
mstore(0x0, shl(0xe0, 0x4e487b71))
mstore(0x4, 0x41)
revert(0x0, 0x24)
}
if not(_14){
mstore(0x40, _13)
mstore(_11, _9)
returndatacopy(add(_11, 0x20), 0x0, returndatasize())
}
}
}
let _15 := iszero(_7)
require(_15)
stop()
}
```
Contributor guide
Research direction
Start by compiling MyContract.sol with solc 0.8.26 using --optimize --via-ir --no-cbor-metadata --bin-runtime, then inspect the generated Yul around call and returndatacopy. Trace the via-IR compiler entry points responsible for lowering call and staticcall and compare the bounds checks with the zero return-data case. Done means the redundant checks are removed where valid and regression coverage confirms the optimized output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, solidity
- Domain
- blockchain, compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100