Skip to content

Commit

Permalink
Auto merge of #136974 - m-ou-se:fmt-options-64-bit, r=<try>
Browse files Browse the repository at this point in the history
Reduce FormattingOptions to 64 bits

This reduces FormattingOptions from 6-7 machine words (384 bits on 64-bit platforms, 224 bits on 32-bit platforms) to just 64 bits (a single register on 64-bit platforms).

This PR includes #136932, which reduces the width and precision options to 16 bits, to make it all fit.

Before:

```rust
pub struct FormattingOptions {
    flags: u32, // only 6 bits used
    fill: char,
    align: Option<Alignment>,
    width: Option<usize>,
    precision: Option<usize>,
}
```

After:

```rust
pub struct FormattingOptions {
    /// Bits:
    ///  - 0: `+` flag [rt::Flag::SignPlus]
    ///  - 1: `-` flag [rt::Flag::SignMinus]
    ///  - 2: `#` flag [rt::Flag::Alternate]
    ///  - 3: `0` flag [rt::Flag::SignAwareZeroPad]
    ///  - 4: `x?` flag [rt::Flag::DebugLowerHex]
    ///  - 5: `X?` flag [rt::Flag::DebugUpperHex]
    ///  - 6-7: Alignment (0: Left, 1: Right, 2: Center, 3: Unknown)
    ///  - 8: Width flag (if set, the width field below is used)
    ///  - 9: Precision flag (if set, the precision field below is used)
    ///  - 10: unused
    ///  - 11-31: fill character (21 bits, a full `char`)
    flags: u32,
    /// Width if width flag above is set. Otherwise, always 0.
    width: u16,
    /// Precision if precision flag above is set. Otherwise, always 0.
    precision: u16,
}
```
  • Loading branch information
bors committed Feb 13, 2025
2 parents 54cdc75 + c059377 commit 47853a6
Show file tree
Hide file tree
Showing 17 changed files with 736 additions and 271 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ pub enum FormatAlignment {
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
pub enum FormatCount {
/// `{:5}` or `{:.5}`
Literal(usize),
Literal(u16),
/// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
Argument(FormatArgPosition),
}
10 changes: 8 additions & 2 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2151,8 +2151,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.expr(sp, hir::ExprKind::Lit(lit))
}

pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> {
let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Char(value) });
pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> {
let lit = self.arena.alloc(hir::Lit {
span: sp,
node: ast::LitKind::Int(
u128::from(value).into(),
ast::LitIntType::Unsigned(ast::UintTy::U16),
),
});
self.expr(sp, hir::ExprKind::Lit(lit))
}

Expand Down
31 changes: 16 additions & 15 deletions compiler/rustc_ast_lowering/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ fn make_count<'hir>(
hir::LangItem::FormatCount,
sym::Is,
));
let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]);
let value = ctx.arena.alloc_from_iter([ctx.expr_u16(sp, *n)]);
ctx.expr_call_mut(sp, count_is, value)
}
Some(FormatCount::Argument(arg)) => {
Expand Down Expand Up @@ -361,24 +361,25 @@ fn make_format_spec<'hir>(
zero_pad,
debug_hex,
} = &placeholder.format_options;
let fill = ctx.expr_char(sp, fill.unwrap_or(' '));
let align = ctx.expr_lang_item_type_relative(
sp,
hir::LangItem::FormatAlignment,
match alignment {
Some(FormatAlignment::Left) => sym::Left,
Some(FormatAlignment::Right) => sym::Right,
Some(FormatAlignment::Center) => sym::Center,
None => sym::Unknown,
},
);
// This needs to match `Flag` in library/core/src/fmt/rt.rs.
let fill = fill.unwrap_or(' ');
// These need to match the constants in library/core/src/fmt/rt.rs.
let align = match alignment {
Some(FormatAlignment::Left) => 0,
Some(FormatAlignment::Right) => 1,
Some(FormatAlignment::Center) => 2,
None => 3,
};
// This needs to match the constants in library/core/src/fmt/rt.rs.
let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
| ((sign == Some(FormatSign::Minus)) as u32) << 1
| (alternate as u32) << 2
| (zero_pad as u32) << 3
| ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4
| ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5;
| ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5
| align << 6
| (width.is_some() as u32) << 8
| (precision.is_some() as u32) << 9
| (fill as u32) << 11;
let flags = ctx.expr_u32(sp, flags);
let precision = make_count(ctx, sp, precision, argmap);
let width = make_count(ctx, sp, width, argmap);
Expand All @@ -387,7 +388,7 @@ fn make_format_spec<'hir>(
hir::LangItem::FormatPlaceholder,
sym::new,
));
let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]);
let args = ctx.arena.alloc_from_iter([position, flags, precision, width]);
ctx.expr_call_mut(sp, format_placeholder_new, args)
}

Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ language_item_table! {
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;

// Lang items needed for `format_args!()`.
FormatAlignment, sym::format_alignment, format_alignment, Target::Enum, GenericRequirement::None;
FormatArgument, sym::format_argument, format_argument, Target::Struct, GenericRequirement::None;
FormatArguments, sym::format_arguments, format_arguments, Target::Struct, GenericRequirement::None;
FormatCount, sym::format_count, format_count, Target::Enum, GenericRequirement::None;
Expand Down
18 changes: 9 additions & 9 deletions compiler/rustc_parse_format/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ pub enum DebugHex {
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Count<'a> {
/// The count is specified explicitly.
CountIs(usize),
CountIs(u16),
/// The count is specified by the argument with the given name.
CountIsName(&'a str, InnerSpan),
/// The count is specified by the argument at the given index.
Expand Down Expand Up @@ -565,7 +565,7 @@ impl<'a> Parser<'a> {
/// consuming a macro argument, `None` if it's the case.
fn position(&mut self) -> Option<Position<'a>> {
if let Some(i) = self.integer() {
Some(ArgumentIs(i))
Some(ArgumentIs(i.into()))
} else {
match self.cur.peek() {
Some(&(lo, c)) if rustc_lexer::is_id_start(c) => {
Expand Down Expand Up @@ -771,7 +771,7 @@ impl<'a> Parser<'a> {
/// width.
fn count(&mut self, start: usize) -> Count<'a> {
if let Some(i) = self.integer() {
if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) }
} else {
let tmp = self.cur.clone();
let word = self.word();
Expand Down Expand Up @@ -822,15 +822,15 @@ impl<'a> Parser<'a> {
word
}

fn integer(&mut self) -> Option<usize> {
let mut cur: usize = 0;
fn integer(&mut self) -> Option<u16> {
let mut cur: u16 = 0;
let mut found = false;
let mut overflow = false;
let start = self.current_pos();
while let Some(&(_, c)) = self.cur.peek() {
if let Some(i) = c.to_digit(10) {
let (tmp, mul_overflow) = cur.overflowing_mul(10);
let (tmp, add_overflow) = tmp.overflowing_add(i as usize);
let (tmp, add_overflow) = tmp.overflowing_add(i as u16);
if mul_overflow || add_overflow {
overflow = true;
}
Expand All @@ -847,11 +847,11 @@ impl<'a> Parser<'a> {
let overflowed_int = &self.input[start..end];
self.err(
format!(
"integer `{}` does not fit into the type `usize` whose range is `0..={}`",
"integer `{}` does not fit into the type `u16` whose range is `0..={}`",
overflowed_int,
usize::MAX
u16::MAX
),
"integer out of range for `usize`",
"integer out of range for `u16`",
self.span(start, end),
);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,6 @@ symbols! {
forbid,
forget,
format,
format_alignment,
format_args,
format_args_capture,
format_args_macro,
Expand All @@ -1003,6 +1002,7 @@ symbols! {
from_residual,
from_size_align_unchecked,
from_str_method,
from_u16,
from_usize,
from_yeet,
fs_create_dir,
Expand Down
18 changes: 9 additions & 9 deletions library/core/src/fmt/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn float_to_decimal_common_exact<T>(
fmt: &mut Formatter<'_>,
num: &T,
sign: flt2dec::Sign,
precision: usize,
precision: u16,
) -> Result
where
T: flt2dec::DecodableFloat,
Expand All @@ -40,7 +40,7 @@ where
flt2dec::strategy::grisu::format_exact,
*num,
sign,
precision,
precision.into(),
&mut buf,
&mut parts,
);
Expand All @@ -55,7 +55,7 @@ fn float_to_decimal_common_shortest<T>(
fmt: &mut Formatter<'_>,
num: &T,
sign: flt2dec::Sign,
precision: usize,
precision: u16,
) -> Result
where
T: flt2dec::DecodableFloat,
Expand All @@ -68,7 +68,7 @@ where
flt2dec::strategy::grisu::format_shortest,
*num,
sign,
precision,
precision.into(),
&mut buf,
&mut parts,
);
Expand All @@ -86,7 +86,7 @@ where
true => flt2dec::Sign::MinusPlus,
};

if let Some(precision) = fmt.options.precision {
if let Some(precision) = fmt.options.get_precision() {
float_to_decimal_common_exact(fmt, num, sign, precision)
} else {
let min_precision = 0;
Expand All @@ -101,7 +101,7 @@ fn float_to_exponential_common_exact<T>(
fmt: &mut Formatter<'_>,
num: &T,
sign: flt2dec::Sign,
precision: usize,
precision: u16,
upper: bool,
) -> Result
where
Expand All @@ -113,7 +113,7 @@ where
flt2dec::strategy::grisu::format_exact,
*num,
sign,
precision,
precision.into(),
upper,
&mut buf,
&mut parts,
Expand Down Expand Up @@ -162,7 +162,7 @@ where
true => flt2dec::Sign::MinusPlus,
};

if let Some(precision) = fmt.options.precision {
if let Some(precision) = fmt.options.get_precision() {
// 1 integral digit + `precision` fractional digits = `precision + 1` total digits
float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
} else {
Expand All @@ -180,7 +180,7 @@ where
true => flt2dec::Sign::MinusPlus,
};

if let Some(precision) = fmt.options.precision {
if let Some(precision) = fmt.options.get_precision() {
// this behavior of {:.PREC?} predates exponential formatting for {:?}
float_to_decimal_common_exact(fmt, num, sign, precision)
} else {
Expand Down
Loading

0 comments on commit 47853a6

Please sign in to comment.