Skip to content

Commit 503dce3

Browse files
committed
Auto merge of #148789 - m-ou-se:new-fmt-args-alt, r=wafflelapkin,jdonszelmann
New format_args!() and fmt::Arguments implementation Part of #99012 This is a new implementation of `format_args!()` and `fmt::Arguments`. With this implementation, `fmt::Arguments` is only two pointers in size. (Instead of six, before.) This makes it the same size as a `&str` and makes it fit in a register pair. --- 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: > ```rust > fn main() { > println!("Hello, world!"); > } > ``` > > before: > ```asm > 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: > ```asm > main: > lea rsi, [rip + .Lanon_hello_world] > mov edi, 29 > jmp qword ptr [rip + std::io::stdio::_print] > ``` (`panic!("Hello, world!");` shows a similar change.) --- This implementation stores all static information as just a single (byte) string, without any indirection: > code: > ```rust > format_args!("Hello, {name:-^20}!") > ``` > > lowering before: > ```rust > fmt::Arguments::new_v1_formatted( > &["Hello, ", "!\n"], > &args, > &[ > Placeholder { > position: 0usize, > flags: 3355443245u32, > precision: format_count::Implied, > width: format_count::Is(20u16), > }, > ], > ) > ``` > > lowering after: > ```rust > fmt::Arguments::new( > b"\x07Hello, \xc3-\x00\x00\xc8\x14\x00\x02!\n\x00", > &args, > ) > ``` This saves a ton of pointers and simplifies the expansion significantly, but does mean that individual pieces (e.g. `"Hello, "` and `"!\n"`) cannot be reused. (Those pieces are often smaller than a pointer to them, though, in which case reusing them is useless.) --- The details of the new representation are documented in [library/core/src/fmt/mod.rs](https://github.com/m-ou-se/rust/blob/new-fmt-args-alt/library/core/src/fmt/mod.rs#L609-L712).
2 parents 0186755 + cfbdc2c commit 503dce3

File tree

58 files changed

+886
-989
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+886
-989
lines changed

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_middle::span_bug;
1313
use rustc_middle::ty::TyCtxt;
1414
use rustc_session::errors::report_lit_error;
1515
use rustc_span::source_map::{Spanned, respan};
16-
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
16+
use rustc_span::{ByteSymbol, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
1717
use thin_vec::{ThinVec, thin_vec};
1818
use visit::{Visitor, walk_expr};
1919

@@ -924,7 +924,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
924924
arena_vec![self; new_unchecked, get_context],
925925
),
926926
};
927-
self.arena.alloc(self.expr_unsafe(call))
927+
self.arena.alloc(self.expr_unsafe(span, call))
928928
};
929929

930930
// `::std::task::Poll::Ready(result) => break result`
@@ -1832,7 +1832,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
18321832
arena_vec![self; iter],
18331833
));
18341834
// `unsafe { ... }`
1835-
let iter = self.arena.alloc(self.expr_unsafe(iter));
1835+
let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));
18361836
let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);
18371837
self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })
18381838
}
@@ -1887,7 +1887,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
18871887
arena_vec![self; iter],
18881888
));
18891889
// `unsafe { ... }`
1890-
let iter = self.arena.alloc(self.expr_unsafe(iter));
1890+
let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));
18911891
let inner_match_expr = self.arena.alloc(self.expr_match(
18921892
for_span,
18931893
iter,
@@ -2103,30 +2103,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
21032103
self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
21042104
}
21052105

2106-
fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> {
2106+
pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
21072107
let lit = hir::Lit {
21082108
span: self.lower_span(sp),
2109-
node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)),
2109+
node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
21102110
};
21112111
self.expr(sp, hir::ExprKind::Lit(lit))
21122112
}
21132113

2114-
pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
2115-
self.expr_uint(sp, ast::UintTy::Usize, value as u128)
2116-
}
2117-
2118-
pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
2119-
self.expr_uint(sp, ast::UintTy::U32, value as u128)
2120-
}
2121-
2122-
pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> {
2123-
self.expr_uint(sp, ast::UintTy::U16, value as u128)
2124-
}
2125-
2126-
pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
2114+
pub(super) fn expr_byte_str(&mut self, sp: Span, value: ByteSymbol) -> hir::Expr<'hir> {
21272115
let lit = hir::Lit {
21282116
span: self.lower_span(sp),
2129-
node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
2117+
node: ast::LitKind::ByteStr(value, ast::StrStyle::Cooked),
21302118
};
21312119
self.expr(sp, hir::ExprKind::Lit(lit))
21322120
}
@@ -2262,9 +2250,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
22622250
self.expr(span, expr_path)
22632251
}
22642252

2265-
fn expr_unsafe(&mut self, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
2253+
pub(super) fn expr_unsafe(
2254+
&mut self,
2255+
span: Span,
2256+
expr: &'hir hir::Expr<'hir>,
2257+
) -> hir::Expr<'hir> {
22662258
let hir_id = self.next_id();
2267-
let span = expr.span;
22682259
self.expr(
22692260
span,
22702261
hir::ExprKind::Block(
@@ -2302,15 +2293,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
23022293
self.arena.alloc(self.expr_block(b))
23032294
}
23042295

2305-
pub(super) fn expr_array_ref(
2306-
&mut self,
2307-
span: Span,
2308-
elements: &'hir [hir::Expr<'hir>],
2309-
) -> hir::Expr<'hir> {
2310-
let array = self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements)));
2311-
self.expr_ref(span, array)
2312-
}
2313-
23142296
pub(super) fn expr_ref(&mut self, span: Span, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
23152297
self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr))
23162298
}

0 commit comments

Comments
 (0)