Description
Consider the following contract:
contract C {
bytes x = "0123";
}
The creation code of C
has to initialize the state variable x
. However, in order to do so, it first reads the length field from storage, resulting in --ir-optimized --optimize
of above contract to produce:
object "C_4" {
code {
{
let _1 := memoryguard(0x80)
mstore(64, _1)
if callvalue() { revert(0, 0) }
let _2 := 0x00
let _3 := sload( _2) // We can assume ``sload(_2)`` to return 0!
let length := _2
... rest of creation code....
}
object "C_4_deployed" {
code {
{
revert(0, 0)
}
}
}
}
Since at creation time, all storage slots are zero, we can resolve sload(_2)
in this snippet to plain 0
.
This optimization should be done in the LoadResolver
optimizer step, by enriching it with the knowledge that all storage is zero at creation time. To that end, LoadResolver
will need to determine whether it is run on creation code - this can for example be done by checking if it is run on a Yul object with a name that is not suffixed with _deployed
.
Similarly, in a separate step, we can extend the LoadResolver
to also assume that all memory is zero at the begin of each transaction. Note that this should be done separately, so there's two sub-tasks here:
- Amend the optimizer to assume zero-valued storage at the beginning of creation code.
- Amend the optimizer to assume zero-valued memory at the beginning of each transaction.