-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Yul: Constant-complexity switch statement jump table targeting enums #12964
Comments
There are multiple ways to do this. You can store the jump targets in a "code table" like you did, but we can also store them in code and use codecopy to retrieve it. Furthermore, we could use a |
I like the idea of storing the jump targets in a single word. I was able to get the execution cost down to 48 gas using the Push technique (48 gas):
The two assumptions it has to make are that (a) all offsets can be represented with two bytes and (b) the offset 0 is not a valid jump destination. I have an idea for an even stronger optimization: if we can guarantee that the jump destinations of the individual cases are always greater than the offset of the default case, we can skip the out-of-bounds check entirely and instead just store the offsets from the default case location in the "jump table". I assume this might be difficult to guarantee in practice, but if we could do it, the execution gas cost would come all the way down to 35. As an example, if the default case is at offset 0x45, and case 0 is at 0x4d, we would store 0x08 in the jump table and just add 0x45 to it. Offsets from the default case (35 gas):
|
This issue has been marked as stale due to inactivity for the last 90 days. |
As an update to this, I was told that because Ethereum's trajectory was eventually going to do away with dynamic jumps, so the team is hesitant to pursue this optimization. The implementation of the jump table in the compiler and optimizer can be found in #12978. |
This issue has been marked as stale due to inactivity for the last 90 days. |
Hi everyone! This issue has been automatically closed due to inactivity. |
Abstract
The current switch statement control graph builder, for Yul to EVM specifically, is fine when switching between only a few values. To decide which path to take, a switch statement is turned into a
(DUP + PUSH + EQ + PUSH + JUMPI)
pattern for each case, and the default case is handled at the end. This is fine when handling up to three values, but the execution gas cost increases linearly with the number of cases. With four or more cases that are handled uniformly, a jump table performs better on average, and we can create a simple jump table that works specifically with switch statements containing all cases from0...n
.This is what it looks like today for a switch statement with cases
0...4
:Motivation
For enums in particular - that is, switch statements that contain cases ranging from 0 to some number, there is a rather straightforward jump table implementation that not only makes the execution gas cost constant, but with more than five cases will also decrease the deployment cost.
Rather than checking each value individually and then branching on every check, in the enum case, we should calculate the jump table offset using the enum value itself and jump there.
It would work something like this:
jumptable + 3 * value_to_compare
As it is currently, after the case is handled, jump to the end of the switch statement.
Ultimately, any work done for this could pave the way for more robust dispatchers in the future.
Specification
In the case of a switch statement handling all cases 0...n with n >= 4, turn the current dispatch method for switch statements into a jump table, which should look something like this:
My pen-and-paper execution gas cost comparison looks like this:
Backwards Compatibility
This is a Yul to EVM optimization, so I don't anticipate any backward compatibility issues. That said, this proposal only targets switch statements with 0...n values, with n >= 4.
This could be an optional optimization to be added onto the Yul compiler.
Related: #12650
The text was updated successfully, but these errors were encountered: