Skip to content

Optimize type casting by using __transmute instead of asm blocks#7675

Merged
ironcev merged 2 commits into
masterfrom
ironcev/std-optimize-type-casting-transmute
Jul 7, 2026
Merged

Optimize type casting by using __transmute instead of asm blocks#7675
ironcev merged 2 commits into
masterfrom
ironcev/std-optimize-type-casting-transmute

Conversation

@ironcev

@ironcev ironcev commented Jul 3, 2026

Copy link
Copy Markdown
Member

Description

This PR improves gas costs and bytecode sizes by consistently replacing asm-based conversions of reference types in std with __transmute.

Note that copy-types are still converted using asm blocks, because currently we didn't extend __transmute to handle copy-types without demoting transmuted values to stack and actually casting pointers. This gives a performance penalty when transmuting copy-types which we don't want to have.

As expected, removing asm blocks unlocked existing IR performance optimizations and resulted in performance improvements given in the comment below.

Note that we might think of temporarily forbidding using __transmute with copy-types until it is properly supported. But we have code in ops.sw where __transmute must be used to convert between copy-types, because the operator trait methods must be const-evaluable and if they use asm for conversion, they cannot be. Historically, making them const-evaluable was the reason for adding __transmute in the first place.

Note that in the future, we plan to improve IR optimizations by letting them be aware of "safe asm blocks". Pure conversion blocks will be considered safe. That improvement would likely bring the same performance benefits as rolling out __transmute, but:

  • it will take some time before we get it implemented,
  • regardless, __transmute is the expected way to convert types and we should use it consistentlty across the codebase.

EDIT: The issue of silent sway-ir snapshots is addressed in #7676.
Note that the PR changes snapshot files in the sway-ir tests. These changes are not related to this PR, but likely to the snapshots not being updated because of the insta checks being silent. For more info see #7666 (review).

Checklist

  • I have linked to any relevant issues.
  • 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).
  • 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.
  • I have done my best to ensure that my PR adheres to the Fuel Labs Code Review Standards.
  • I have requested a review from the relevant team or maintainers.

@ironcev ironcev temporarily deployed to fuel-sway-bot July 3, 2026 22:16 — with GitHub Actions Inactive
@cursor

cursor Bot commented Jul 3, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Wide changes to std conversion and ABI/string/slice plumbing; behavior should be identical but any __transmute mismatch would affect every contract using std. Copy-type asm paths were intentionally preserved.

Overview
Replaces asm-based reinterpret casts across sway-lib-std with __transmute for reference types (e.g. b256/u256(u64, u64, u64, u64), (raw_ptr, u64)raw_slice/str, slice pointer/length unpacking, crypto B512[u8; 64], and similar paths in codec, hash, math, debug, storage, and primitive conversions).

Copy-type conversions that still need asm (e.g. narrow integer narrowing in TryFrom) are left unchanged on purpose.

E2E snapshots reflect smaller bytecode and lower gas on affected programs (e.g. array_repeat release size 1952 → 1944 B) from IR optimizations that __transmute enables.

Reviewed by Cursor Bugbot for commit 73c6b17. Bugbot is set up for automated code reviews on this repo. Configure here.

@ironcev ironcev self-assigned this Jul 3, 2026
@ironcev ironcev added lib: std Standard library performance Everything related to performance, speed wise or memory wise. labels Jul 3, 2026
@ironcev

ironcev commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

Performance improvements

E2E Gas Usage

Improvements Regressions
Count 1383 9
Average 0.96% -1.05%
Median 0.63% -1.01%
Max 17.71% -1.55%
Min 0.01% -0.05%

E2E Bytecode Size

Improvements Regressions
Count 64 1
Average 4.89% -3.03%
Median 1.98% -3.03%
Max 20.83% -3.03%
Min 0.08% -3.03%

In-language Gas Usage

Improvements Regressions
Count 222 3
Average 6.14% -1.39%
Median 2.93% -1.10%
Max 26.11% -2.94%
Min 0.06% -0.13%

In-language Bytecode Size

Improvements Regressions
Count 31
Average 1.46%
Median 0.95%
Max 8.96%
Min 0.01%

@ironcev

ironcev commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

👍

@ironcev ironcev marked this pull request as ready for review July 3, 2026 22:30
@ironcev ironcev requested review from a team as code owners July 3, 2026 22:30
@ironcev ironcev enabled auto-merge (squash) July 3, 2026 22:30
@ironcev ironcev requested review from xgreenx and xunilrj July 3, 2026 22:32
Comment thread sway-lib-std/src/array_conversions/u256.sw
@xunilrj

xunilrj commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

I am seeing some transmute-by-copy, like below. And some transmute of self.

let input = (0u64, 0u64, 0u64, self.as_u64());
__transmute::<(u64, u64, u64, u64), u256>(input)

I would expect we would be doing something like:

let input = (0u64, 0u64, 0u64, self.as_u64());
*__transmute::<&(u64, u64, u64, u64), &u256>(&input)

@ironcev

ironcev commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

I am seeing some transmute-by-copy

Currently all the transmute are "by-value" or better to say, they look like they convert values, but in the background it's just cast_ptr. There reason is the similar one why or IR v1.0 kind-of worked with pointers - non-copy-types are seen as pointers in IR.

This is inconsistent similar to inconsistencies listed in #6351 and #6993. Should we specify __transmute that it accepts only references? IR generation doesn't change, it just that type-checking and definition becomes clear. Should we revisit all this together with the topic of introducing additional intrinsics for copy-types?

@ironcev ironcev requested a review from xunilrj July 5, 2026 15:34
@ironcev ironcev temporarily deployed to fuel-sway-bot July 6, 2026 11:28 — with GitHub Actions Inactive
@xunilrj

xunilrj commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Should we specify __transmute that it accepts only references?

Hum... I think that it makes sense that __transmute works with non-pointers. Specially because if the value is already in memory, it is zero-cost, in the sense of only being a ptr-cast.

Should we revisit all this together with the topic of introducing additional intrinsics for copy-types?

I think we can gather the benefits for now, specially on o2. But I think it makes sense to revisit if we need more intrinsics.

__bitcast?

I think that __bitcast would behave 100% like __transmute for copy-types. In this case I would prefer that we improve __transmute to be zero-cost for all types.

I was thinking more for cases like __transmute((0,0,0,1)). We know that are our tuple initialization is very verbose, so 99% of the cost will be there, where a more specific intrinsic could try to be smarter and make this really zero-cost.

@ironcev ironcev merged commit 79e92e5 into master Jul 7, 2026
41 checks passed
@ironcev ironcev deleted the ironcev/std-optimize-type-casting-transmute branch July 7, 2026 12:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lib: std Standard library performance Everything related to performance, speed wise or memory wise.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants