Skip to content

Conversation

@m-ou-se
Copy link
Member

@m-ou-se m-ou-se commented Nov 5, 2025

Part of #99012

Continuation of #137294

This is an experimental new implementation of fmt::Arguments. In this implementation, fmt::Arguments is only two pointers in size. (Instead of six, currently.) This makes it the same size as a &str and makes it fit in a register pair.

Additionally, this fmt::Arguments can store a &'static str without any indirection or additional storage. This means that simple cases like print_fmt(format_args!("hello")) are now just as efficient for the caller as print_str("hello"), as shown by this example:

code:

fn main() {
    println!("Hello, world!");
}

before:

main:
 sub     rsp, 56
 lea     rax, [rip + .Lanon_hello_world]
 mov     qword ptr [rsp + 8], rax
 mov     qword ptr [rsp + 16], 1
 mov     qword ptr [rsp + 24], 8
 xorps   xmm0, xmm0
 movups  xmmword ptr [rsp + 32], xmm0
 lea     rdi, [rsp + 8]
 call    qword ptr [rip + std::io::stdio::_print]
 add     rsp, 56
 ret

after:

main:
 lea     rsi, [rip + .Lanon_hello_world]
 mov     edi, 29
 jmp     qword ptr [rip + std::io::stdio::_print]

Similarly, panic!("Hello, world!"); shows the same change.

To do:

  • Performance testing
  • Figure out why things are slower to compile
  • Fix compilation performance
  • Documentation / comments

@m-ou-se m-ou-se self-assigned this Nov 5, 2025
@m-ou-se m-ou-se added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. A-fmt Area: `core::fmt` labels Nov 5, 2025
@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Nov 5, 2025
@m-ou-se
Copy link
Member Author

m-ou-se commented Nov 5, 2025

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

rust-bors bot added a commit that referenced this pull request Nov 5, 2025
Experiment: New fmt::Arguments implementation
@rust-bors

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Nov 5, 2025
@rust-log-analyzer

This comment was marked as outdated.

@rust-log-analyzer

This comment has been minimized.

@rustbot rustbot added the T-clippy Relevant to the Clippy team. label Nov 5, 2025
@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-20-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
test [mir-opt] tests/mir-opt/unusual_item_types.rs ... ok

failures:

---- [mir-opt] tests/mir-opt/sroa/lifetimes.rs stdout ----
18       let mut _18: core::fmt::rt::Argument<'_>;
19       let mut _19: &u32;
20       let mut _20: core::fmt::rt::Template<'_>;
-       let mut _21: &[core::fmt::rt::Piece; 7];
-       let _22: &[core::fmt::rt::Piece; 7];
-       let _23: [core::fmt::rt::Piece; 7];
+       let mut _21: &[core::fmt::rt::Piece; 6];
+       let _22: &[core::fmt::rt::Piece; 6];
+       let _23: [core::fmt::rt::Piece; 6];
24       let mut _24: core::fmt::rt::Piece;
25       let mut _25: core::fmt::rt::Piece;
26       let mut _26: core::fmt::rt::Piece;

27       let mut _27: core::fmt::rt::Piece;
28       let mut _28: core::fmt::rt::Piece;
29       let mut _29: core::fmt::rt::Piece;
-       let mut _30: core::fmt::rt::Piece;
-       let mut _31: &[core::fmt::rt::Argument<'_>; 2];
-       let _32: &[core::fmt::rt::Argument<'_>; 2];
-       let mut _34: &std::boxed::Box<dyn std::fmt::Display>;
-       let mut _35: &u32;
-       let mut _36: bool;
+       let mut _30: &[core::fmt::rt::Argument<'_>; 2];
+       let _31: &[core::fmt::rt::Argument<'_>; 2];
+       let mut _33: &std::boxed::Box<dyn std::fmt::Display>;
+       let mut _34: &u32;
+       let mut _35: bool;
+       let mut _36: isize;
36       let mut _37: isize;
37       let mut _38: isize;
-       let mut _39: isize;
- +     let _40: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
- +     let _41: u32;
+ +     let _39: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
+ +     let _40: u32;
41       scope 1 {
42 -         debug foo => _1;
- +         debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _40;
- +         debug ((foo: Foo<T>).1: u32) => _41;
+ +         debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _39;
+ +         debug ((foo: Foo<T>).1: u32) => _40;
45           let _5: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
46           scope 2 {
47               debug x => _5;

52                       debug x => _8;
53                       let _8: std::boxed::Box<dyn std::fmt::Display>;
54                       let _12: (&std::boxed::Box<dyn std::fmt::Display>, &u32);
- +                     let _42: &std::boxed::Box<dyn std::fmt::Display>;
- +                     let _43: &u32;
+ +                     let _41: &std::boxed::Box<dyn std::fmt::Display>;
+ +                     let _42: &u32;
57                       scope 5 {
58 -                         debug args => _12;
- +                         debug ((args: (&Box<dyn std::fmt::Display>, &u32)).0: &std::boxed::Box<dyn std::fmt::Display>) => _42;
- +                         debug ((args: (&Box<dyn std::fmt::Display>, &u32)).1: &u32) => _43;
+ +                         debug ((args: (&Box<dyn std::fmt::Display>, &u32)).0: &std::boxed::Box<dyn std::fmt::Display>) => _41;
+ +                         debug ((args: (&Box<dyn std::fmt::Display>, &u32)).1: &u32) => _42;
61                           let _15: [core::fmt::rt::Argument<'_>; 2];
62                           scope 6 {
63                               debug args => _15;

-                               let mut _33: &[core::fmt::rt::Piece; 7];
+                               let mut _32: &[core::fmt::rt::Piece; 6];
65                           }
66                       }
67                   }

70       }
---
77 +         nop;
78           StorageLive(_2);
79           StorageLive(_3);

87           _2 = Result::<Box<dyn std::fmt::Display>, <T as Err>::Err>::Ok(move _3);
88           StorageDead(_3);
89 -         _1 = Foo::<T> { x: move _2, y: const 7_u32 };
- +         _40 = move _2;
- +         _41 = const 7_u32;
+ +         _39 = move _2;
+ +         _40 = const 7_u32;
92 +         nop;
93           StorageDead(_2);
94           StorageLive(_5);

-           _36 = const true;
+           _35 = const true;
96 -         _5 = move (_1.0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>);
- +         _5 = move _40;
+ +         _5 = move _39;
98           StorageLive(_6);
99 -         _6 = copy (_1.1: u32);
- +         _6 = copy _41;
+ +         _6 = copy _40;
101           _7 = discriminant(_5);
102           switchInt(move _7) -> [0: bb2, otherwise: bb8];
103       }

109           StorageLive(_10);
110           StorageLive(_11);
111 -         StorageLive(_12);
---
115           StorageLive(_13);
116           _13 = &_8;

117           StorageLive(_14);
118           _14 = &_6;
119 -         _12 = (move _13, move _14);
- +         _42 = move _13;
- +         _43 = move _14;
+ +         _41 = move _13;
+ +         _42 = move _14;
122 +         nop;
123           StorageDead(_14);
124           StorageDead(_13);

125           StorageLive(_15);
126           StorageLive(_16);
127           StorageLive(_17);
- -         _34 = copy (_12.0: &std::boxed::Box<dyn std::fmt::Display>);
- +         _34 = copy _42;
-           _17 = &(*_34);
+ -         _33 = copy (_12.0: &std::boxed::Box<dyn std::fmt::Display>);
+ +         _33 = copy _41;
+           _17 = &(*_33);
131           _16 = core::fmt::rt::Argument::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _17) -> [return: bb3, unwind unreachable];
132       }
133   

135           StorageDead(_17);
136           StorageLive(_18);
137           StorageLive(_19);
- -         _35 = copy (_12.1: &u32);
- +         _35 = copy _43;
-           _19 = &(*_35);
+ -         _34 = copy (_12.1: &u32);
+ +         _34 = copy _42;
+           _19 = &(*_34);
141           _18 = core::fmt::rt::Argument::<'_>::new_display::<u32>(move _19) -> [return: bb4, unwind unreachable];
142       }
143   

149           StorageLive(_20);
150           StorageLive(_21);
151           StorageLive(_22);
-           _33 = const foo::<T>::promoted[0];
-           _22 = &(*_33);
+           _32 = const foo::<T>::promoted[0];
+           _22 = &(*_32);
154           _21 = &(*_22);
-           _20 = core::fmt::rt::Template::<'_>::new::<7>(move _21) -> [return: bb5, unwind unreachable];
+           _20 = core::fmt::rt::Template::<'_>::new::<6>(move _21) -> [return: bb5, unwind unreachable];
156       }
157   
158       bb5: {

159           StorageDead(_22);
160           StorageDead(_21);
+           StorageLive(_30);
161           StorageLive(_31);
-           StorageLive(_32);
-           _32 = &_15;
-           _31 = &(*_32);
-           _11 = core::fmt::rt::<impl Arguments<'_>>::new::<2>(move _20, move _31) -> [return: bb6, unwind unreachable];
+           _31 = &_15;
+           _30 = &(*_31);
+           _11 = core::fmt::rt::<impl Arguments<'_>>::new::<2>(move _20, move _30) -> [return: bb6, unwind unreachable];
166       }
167   
168       bb6: {

-           StorageDead(_32);
170           StorageDead(_31);
+           StorageDead(_30);
171           StorageDead(_20);
172           _10 = _eprint(move _11) -> [return: bb7, unwind unreachable];
173       }

176           StorageDead(_11);
177           StorageDead(_15);
178 -         StorageDead(_12);
---

198   
199       bb10: {
200           StorageDead(_6);
-           _37 = discriminant(_5);
-           switchInt(move _37) -> [0: bb11, otherwise: bb12];
+           _36 = discriminant(_5);
+           switchInt(move _36) -> [0: bb11, otherwise: bb12];
203       }
204   
205       bb11: {

-           _36 = const false;
---
212           return;
213       }


thread '[mir-opt] tests/mir-opt/sroa/lifetimes.rs' panicked at src/tools/compiletest/src/runtest/mir_opt.rs:84:21:
Actual MIR output differs from expected MIR output /checkout/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
stack backtrace:
   5: __rustc::rust_begin_unwind
             at /rustc/3b4dd9bf1410f8da6329baa36ce5e37673cbbd1f/library/std/src/panicking.rs:698:5
   6: core::panicking::panic_fmt
             at /rustc/3b4dd9bf1410f8da6329baa36ce5e37673cbbd1f/library/core/src/panicking.rs:80:14

@rust-bors
Copy link

rust-bors bot commented Nov 5, 2025

☀️ Try build successful (CI)
Build commit: 89ea077 (89ea077499c3fe06868ef1d91f2c47c8af941dce, parent: 53efb3d4f3b67d189a0c72eb475a52017d79d609)

@rust-timer
Copy link
Collaborator

Queued 89ea077 with parent 53efb3d, future comparison URL.
There are currently 3 preceding artifacts in the queue.
It will probably take at least ~4.1 hours until the benchmark run finishes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-fmt Area: `core::fmt` S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-perf Status: Waiting on a perf run to be completed. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants