Skip to content
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

Bytecode size difference when calling storage try_read().unwrap() instead of read() #5982

Open
ironcev opened this issue May 9, 2024 · 0 comments
Labels
compiler: ir IRgen and sway-ir including optimization passes compiler General compiler. Should eventually become more specific as the issue is triaged

Comments

@ironcev
Copy link
Member

ironcev commented May 9, 2024

StorageKey::read() is internally storage_api::read().unwrap() while StorageKey::try_read() is just storage_api::read(). Thus, one would expect calling storage.x.read() and storage.x.try_read().unwrap() to produce the same resulting bytecode.

This is indeed the case for a single call. But when having multiple calls, try_read().unwrap() chains produce noticeable bigger bytecode size. unwrap() doesn't get inlined and we end up in additional calls to unwrap().

Even in the simple example below, the bytecode size of calling multiple_reads() is ~1700, and when calling multiple_try_reads() ~2000.

contract;

storage {
    x: u64 = 0,
}

abi Abi {
    #[storage(read)]
    fn main();
}

impl Abi for Contract {
    #[storage(read)]
    fn main() {
        let x = multiple_reads();
        poke(x);
        let x = multiple_try_reads();
        poke(x);
    }
}

// #[inline(never)]
// #[storage(read)]
fn multiple_reads() -> u64 {
    let mut x = 0;
    x += storage.x.read();
    x += storage.x.read();
    x += storage.x.read();
    x += storage.x.read();
    x
}

#[inline(never)]
#[storage(read)]
fn multiple_try_reads() -> u64 {
    let mut x = 0;
    x += storage.x.try_read().unwrap();
    x += storage.x.try_read().unwrap();
    x += storage.x.try_read().unwrap();
    x += storage.x.try_read().unwrap();
    x
}

#[inline(never)]
fn poke<T>(_x: T) { }

In this case, since logically in this case anyhow read() should be called, I don't see this as a pressing issue. But it's a good example to take a look at when improving our inlining. Essentially, recognizing chains like try_read().unwrap() and inlining them.

@ironcev ironcev added compiler General compiler. Should eventually become more specific as the issue is triaged compiler: ir IRgen and sway-ir including optimization passes labels May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler: ir IRgen and sway-ir including optimization passes compiler General compiler. Should eventually become more specific as the issue is triaged
Projects
None yet
Development

No branches or pull requests

1 participant