-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Trivially encoded types #7488
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
Trivially encoded types #7488
Conversation
CodSpeed Performance ReportMerging #7488 will not alter performanceComparing Summary
|
d8b0301 to
b5bed35
Compare
9c8145a to
7e43c6a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is being reviewed by Cursor Bugbot
Details
Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
…7501) ## Description Continuation of #7488. This PR introduces the option for each type to control its own `is_trivial`. Primitive data types have direct implementation (only decoding bool is false, as we need to guarantee its value is zero or one). Structs, tuples, arrays etc... are trivial if their runtime representation and "inner types" allow for trivial encoding or decoding. Enums are more complicated as we need to control that the enum tag is valid; they are not trivial. String arrays are not trivially encoded/decoded for backwards compatibility with "encoding v0" that needs padding in some cases. Some tests are showing a small regression (6 gas), which comes from the introduced "if" not being optimised away. I want to solve this in another PR, where the "if" condition will come from a const, and IR generation will guarantee that only one branch will ever be emitted. ## Snapshot "echo" Small QOL of snapshot was introduced with the "echo" command. It just prints the message directly, wrapping on 80 chars. The idea is to explain what the snapshot is trying to test. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [ ] I have requested a review from the relevant team or maintainers. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Add per-type trivial encode/decode flags and use raw_ptr fast paths in ABI (encode/decode) with supporting changes to codec, String/Vec, and tests. > > - **std/codec**: > - Introduce `AbiEncode::is_encode_trivial` and `AbiDecode::is_decode_trivial`; add helpers `is_encode_trivial/is_decode_trivial`. > - Switch `encode`/`abi_decode` to branch on triviality; add `decode_from_raw_ptr` and raw-ptr-based `decode_*` helpers. > - Make `BufferReader` parameter accessors return `raw_ptr`; minor refactors to use raw ptr copies. > - Implement triviality for primitives, arrays/tuples (conditional), `str[strN]` non-trivial, enums non-trivial. > - **std/string & std/vec**: implement trivial encode/decode markers (non-trivial) and adapt codec impls. > - **Tests/fixtures**: > - Update snapshots (IR/ASM/bytecode/gas), JSON ABI offsets, contract/predicate IDs, and logging expectations to match new encoding paths. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit dddd944. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
Description
This PR will slice #7419 into multiple PRS, being the first one.
To start optimising encoding/decoding we will introduce the concept of "trivially encoded/decoded types". A type is trivially encoded or decoded if the encoding memory representation is the same as the runtime memory representation.
PR #7419 introduced an intrinsic that would return a
boolif both representations match. For this PR I decided to expose these memory representations directly. For that we have two new intrinsics:__runtime_mem_idand__encoding_mem_id.I am not 100% sure if they are going to be useful in other scenarios, but given that the optimiser is able to optimise them away, I think exposing them like this is better than what #7419 does.
These
idsare opaque numbers that do not convey anything about the type or their representation. They can only be compared for equality, and when a type does not have an encoding representation the intrinsic returns zero.With this in mind, the
encodefunction now checks if a type is "trivially encoded" or not. If it is, we just allocate and memcopy its bytes. As this function should not return an aliased pointer.On top of that, we also have an
encode_and_returnfunction that avoids creating tuples and other stuff, given that the optimiser still generates somemem_copys in these cases.A simple example of the benefit is the test
main_args_empty, where the binary size went from 96 bytes to 64 bytes.Before
After
Next PR will introduce this concept into the
AbiEncodetrait, allowing the type itself to control if it wants to be trivially encoded or not.Missing optimizations
If we look at the test
main_args_various_types, after themainis called we see that IR is still not optimal.Ideally, IR would be
Gas Usage Diff
Checklist
Breaking*orNew Featurelabels where relevant.Note
Introduce
__runtime_mem_id/__encoding_mem_idintrinsics and use them to trivially encode/return values, updating ABI entry tonever, improving gas/binary size, and adjusting docs, IR, and tests.__runtime_mem_id<T>() -> u64and__encoding_mem_id<T>() -> u64(AST, semantic, IR gen, const-eval).get_memory_representation,get_memory_id,get_encoding_representation/id).neverand use directretd.never.codec.sw):encode<T>: detect trivially-encodable types (matching IDs) andmemcpybytes; otherwise fallback to normal encoding.encode_and_return<T>() -> !using__contract_retfor fast returns.__transmute,__runtime_mem_id, and__encoding_mem_idin the Sway book; include constraints/semantics.main_args_emptyshrinks (e.g., 96→64 B) and many gas wins.Written by Cursor Bugbot for commit 2caf44c. This will update automatically on new commits. Configure here.