Open PaulRBerg opened 1 year ago
Update: this conversation on Twitter is related to this issue.
As per transmission11's reply there, it does look like in an older version of Solidity, x != 0
used to be more gas efficient than x > 0
.
Tagging @hrkrshnn in case he can illuminate us here?
I will follow up tomorrow.
Thanks @hrkrshnn, though no rush from my end.
@paulrberg The main difference is the use of via-ir
. There are rules for transforming these expressions into an equivalent cheaper expression. But these rules are more effective in the new compilation pipeline. The legacy codegen and its optimizer works across basic blocks of assembly. And sometimes these expressions get split across basic blocks. See: https://hrkrshnn.com/t/devconnect.pdf#page=4 for another example.
I think these expressions should have the same cost if viaIR=true
and the optimizer is enabled. Please don't hesitate to ping me again / open an issue in the original repo if that's not the case.
Thanks @hrkrshnn, makes sense.
What I don't understand though is that when I compiled the the code snippets above in Remix, I did not enable via-ir
.
Is it that in the latest versions of Solidity, the compiler automatically applies via-ir
to some operations, like !=
and >
?
@paulrberg via-ir is not enabled by default yet. You can expect it to be default in an upcoming breaking release. The easiest way to test would be in Foundry, by adding viaIR = true
in the toml config.
You can expect it to be default in an upcoming breaking release
Good to know!
via-ir is not enabled by default yet
This doesn't clear up the mystery yet of why the code snippets all yield the same gas cost even if --via-ir
is not enabled.
This doesn't clear up the mystery yet of why the code snippets all yield the same gas cost even if --via-ir is not enabled.
It's likely because it uses different opcodes. See https://godbolt.org/z/q8K4WGqzr
Thank you ser, will take a look.
Alleged Gas Costs
At the time of opening the issue, the Optimal Comparison Operator document makes the following claim:
And then, the following gas costs are provided:
Actual Gas Costs
In the first example below, each function execution will consume exactly 21,162 gas (with the function
compare
per se consuming exactly 98 gas).Try these on Remix with the optimizer enabled and set to 200 runs
1. Require example
```solidity pragma solidity =0.8.17; contract A { function compare() external pure { require(1 > 0); } } contract B { function compare() external pure { require(1 >= 0); } } contract C { function compare() external pure { require(1 != 0); } } ```2. If/ else example
And in this case, the reported `gasUsed` will be 7. ```solidity pragma solidity =0.8.17; contract A { function compare(uint256 x) external view returns (uint256 gasUsed) { uint256 startGas = gasleft(); if (x >= 0) { uint256 foo = 1 + 2; foo; } gasUsed = startGas - gasleft(); } } contract B { function compare(uint256 x) external view returns (uint256 gasUsed) { uint256 startGas = gasleft(); if (x > 0) { uint256 foo = 1 + 2; foo; } gasUsed = startGas - gasleft(); } } contract C { function compare(uint256 x) external view returns (uint256 gasUsed) { uint256 startGas = gasleft(); if (x != 0) { uint256 foo = 1 + 2; foo; } gasUsed = startGas - gasleft(); } } ```Possible Explanations
Let's start with this is what definitely isn't - this is not a matter of enabling the optimizer. Even with the optimizer disabled, the
> 0
and!= 0
checks cost the same in Solidity v0.8.17. That leaves with a couple of options left:Whatever the case, as discussed in https://github.com/kadenzipfel/gas-optimizations/issues/3 and https://github.com/kadenzipfel/gas-optimizations/issues/15, the best way to avoid situations like this in the future would be to document the methodology that you used to obtain the reported gas costs, so that others can repeat your process and catch mistakes more easily.