Skip to content

Commit bf414e8

Browse files
committed
Replace fmt::Arguments sentinel metadata with typed constructor tags
1 parent 14ba846 commit bf414e8

3 files changed

Lines changed: 78 additions & 61 deletions

File tree

crates/rustc_codegen_spirv/src/builder/format_args_decompiler.rs

Lines changed: 40 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::abi::ConvSpirvType;
22
use crate::builder::Builder;
33
use crate::builder_spirv::{SpirvConst, SpirvValue, SpirvValueExt, SpirvValueKind};
4+
use crate::codegen_cx::FmtArgsCtor;
45
use crate::custom_insts::CustomOp;
56
use either::Either;
67
use itertools::Itertools;
@@ -334,7 +335,16 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
334335
});
335336
};
336337
let fmt_args_new_call_insts = try_rev_take(fmt_args_new_call_inst_count).unwrap();
337-
let (call_args, pieces_len, rt_args_count) = match fmt_args_new_call_insts[..] {
338+
let lookup_fmt_args_ctor = |callee_id| {
339+
cx.fmt_args_new_fn_ids
340+
.borrow()
341+
.get(&callee_id)
342+
.copied()
343+
.ok_or_else(|| {
344+
FormatArgsNotRecognized("fmt::Arguments::new callee not registered".into())
345+
})
346+
};
347+
let (call_args, ctor) = match fmt_args_new_call_insts[..] {
338348
[
339349
Inst::Call(call_ret_id, callee_id, ref call_args),
340350
Inst::Store(st_dst_id, st_val_id),
@@ -345,28 +355,12 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
345355
{
346356
require_local_var(st_dst_id, "fmt::Arguments::new destination")?;
347357

348-
let Some(&(pieces_len, rt_args_count)) =
349-
cx.fmt_args_new_fn_ids.borrow().get(&callee_id)
350-
else {
351-
return Err(FormatArgsNotRecognized(
352-
"fmt::Arguments::new callee not registered".into(),
353-
));
354-
};
355-
356-
(call_args, pieces_len, rt_args_count)
358+
(call_args.as_slice(), lookup_fmt_args_ctor(callee_id)?)
357359
}
358360
[Inst::Call(call_ret_id, callee_id, ref call_args)]
359361
if call_ret_id == format_args_id =>
360362
{
361-
let Some(&(pieces_len, rt_args_count)) =
362-
cx.fmt_args_new_fn_ids.borrow().get(&callee_id)
363-
else {
364-
return Err(FormatArgsNotRecognized(
365-
"fmt::Arguments::new callee not registered".into(),
366-
));
367-
};
368-
369-
(call_args, pieces_len, rt_args_count)
363+
(call_args.as_slice(), lookup_fmt_args_ctor(callee_id)?)
370364
}
371365
[
372366
Inst::Call(call_ret_id, callee_id, ref call_args),
@@ -379,15 +373,7 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
379373
&& inserted0 == inserted0_prev
380374
&& inserted1 == format_args_id =>
381375
{
382-
let Some(&(pieces_len, rt_args_count)) =
383-
cx.fmt_args_new_fn_ids.borrow().get(&callee_id)
384-
else {
385-
return Err(FormatArgsNotRecognized(
386-
"fmt::Arguments::new callee not registered".into(),
387-
));
388-
};
389-
390-
(call_args, pieces_len, rt_args_count)
376+
(call_args.as_slice(), lookup_fmt_args_ctor(callee_id)?)
391377
}
392378
_ => {
393379
// HACK(eddyb) this gathers more context before reporting.
@@ -406,12 +392,11 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
406392
)));
407393
}
408394
};
409-
const FMT_ARGS_FROM_STR_PIECES_LEN: usize = !1;
410395
enum PiecesSource {
411396
Slice { ptr_id: Word, len: usize },
412397
DirectConstStr([Word; 2]),
413398
}
414-
let (pieces_source, (rt_args_slice_ptr_id, rt_args_count)) = match call_args[..] {
399+
let (pieces_source, (rt_args_slice_ptr_id, rt_args_count)) = match (ctor, call_args) {
415400
// `<core::fmt::Arguments>::new_v1_formatted`
416401
//
417402
// HACK(eddyb) this isn't fully supported,
@@ -420,14 +405,17 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
420405
// but the whole call still needs to be removed,
421406
// and both const str pieces and runtime args
422407
// can still be printed (even if in jankier way).
423-
[
424-
pieces_slice_ptr_id,
425-
pieces_len_id,
426-
rt_args_slice_ptr_id,
427-
rt_args_len_id,
428-
fmt_placeholders_slice_ptr_id,
429-
fmt_placeholders_len_id,
430-
] if (pieces_len, rt_args_count) == (!0, !0) => {
408+
(
409+
FmtArgsCtor::NewV1FormattedDynamic,
410+
&[
411+
pieces_slice_ptr_id,
412+
pieces_len_id,
413+
rt_args_slice_ptr_id,
414+
rt_args_len_id,
415+
fmt_placeholders_slice_ptr_id,
416+
fmt_placeholders_len_id,
417+
],
418+
) => {
431419
let [pieces_len, rt_args_len, fmt_placeholders_len] =
432420
match [pieces_len_id, rt_args_len_id, fmt_placeholders_len_id]
433421
.map(const_u32_as_usize)
@@ -479,17 +467,19 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
479467
}
480468

481469
// `<core::fmt::Arguments>::from_str`
482-
[str_ptr_id, str_len_id]
483-
if (pieces_len, rt_args_count) == (FMT_ARGS_FROM_STR_PIECES_LEN, 0) =>
484-
{
485-
(
486-
PiecesSource::DirectConstStr([str_ptr_id, str_len_id]),
487-
(None, 0),
488-
)
489-
}
470+
(FmtArgsCtor::FromStr, &[str_ptr_id, str_len_id]) => (
471+
PiecesSource::DirectConstStr([str_ptr_id, str_len_id]),
472+
(None, 0),
473+
),
490474

491475
// `<core::fmt::Arguments>::new_v1`
492-
[pieces_slice_ptr_id, rt_args_slice_ptr_id] => (
476+
(
477+
FmtArgsCtor::NewV1 {
478+
pieces_len,
479+
rt_args_count,
480+
},
481+
&[pieces_slice_ptr_id, rt_args_slice_ptr_id],
482+
) => (
493483
PiecesSource::Slice {
494484
ptr_id: pieces_slice_ptr_id,
495485
len: pieces_len,
@@ -498,17 +488,17 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
498488
),
499489

500490
// `<core::fmt::Arguments>::new_const`
501-
[pieces_slice_ptr_id] if rt_args_count == 0 => (
491+
(FmtArgsCtor::NewConst { pieces_len }, &[pieces_slice_ptr_id]) => (
502492
PiecesSource::Slice {
503493
ptr_id: pieces_slice_ptr_id,
504494
len: pieces_len,
505495
},
506-
(None, rt_args_count),
496+
(None, 0),
507497
),
508498

509499
_ => {
510500
return Err(FormatArgsNotRecognized(
511-
"fmt::Arguments::new call args".into(),
501+
"fmt::Arguments::new ctor/call-args mismatch".into(),
512502
));
513503
}
514504
};

crates/rustc_codegen_spirv/src/codegen_cx/declare.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// HACK(eddyb) avoids rewriting all of the imports (see `lib.rs` and `build.rs`).
22
use crate::maybe_pqp_cg_ssa as rustc_codegen_ssa;
33

4-
use super::CodegenCx;
4+
use super::{CodegenCx, FmtArgsCtor};
55
use crate::abi::ConvSpirvType;
66
use crate::attr::AggregatedSpirvAttributes;
77
use crate::builder_spirv::{SpirvConst, SpirvFunctionCursor, SpirvValue, SpirvValueExt};
@@ -237,9 +237,12 @@ impl<'tcx> CodegenCx<'tcx> {
237237
.strip_prefix("<core::fmt::Arguments>::new_const::<")
238238
.and_then(|s| s.strip_suffix(">"))
239239
{
240-
self.fmt_args_new_fn_ids
241-
.borrow_mut()
242-
.insert(fn_id, (pieces_len.parse().unwrap(), 0));
240+
self.fmt_args_new_fn_ids.borrow_mut().insert(
241+
fn_id,
242+
FmtArgsCtor::NewConst {
243+
pieces_len: pieces_len.parse().unwrap(),
244+
},
245+
);
243246
}
244247
if let Some(generics) = demangled_symbol_name
245248
.strip_prefix("<core::fmt::Arguments>::new_v1::<")
@@ -248,18 +251,21 @@ impl<'tcx> CodegenCx<'tcx> {
248251
let (pieces_len, rt_args_len) = generics.split_once(", ").unwrap();
249252
self.fmt_args_new_fn_ids.borrow_mut().insert(
250253
fn_id,
251-
(pieces_len.parse().unwrap(), rt_args_len.parse().unwrap()),
254+
FmtArgsCtor::NewV1 {
255+
pieces_len: pieces_len.parse().unwrap(),
256+
rt_args_count: rt_args_len.parse().unwrap(),
257+
},
252258
);
253259
}
254260
if demangled_symbol_name == "<core::fmt::Arguments>::new_v1_formatted" {
255-
// HACK(eddyb) `!0` used as a placeholder value to indicate "dynamic".
256261
self.fmt_args_new_fn_ids
257262
.borrow_mut()
258-
.insert(fn_id, (!0, !0));
263+
.insert(fn_id, FmtArgsCtor::NewV1FormattedDynamic);
259264
}
260265
if demangled_symbol_name == "<core::fmt::Arguments>::from_str" {
261-
// HACK(eddyb) `!1` distinguishes `from_str` from normal `new_*`.
262-
self.fmt_args_new_fn_ids.borrow_mut().insert(fn_id, (!1, 0));
266+
self.fmt_args_new_fn_ids
267+
.borrow_mut()
268+
.insert(fn_id, FmtArgsCtor::FromStr);
263269
}
264270

265271
// HACK(eddyb) there is no good way to identify these definitions

crates/rustc_codegen_spirv/src/codegen_cx/mod.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,26 @@ use std::path::PathBuf;
4343
use std::rc::Rc;
4444
use std::str::FromStr;
4545

46+
/// Tags the `core::fmt::Arguments` constructor behind a lowered call.
47+
///
48+
/// During panic-format decompilation we pattern-match constructor calls to
49+
/// recover `pieces` and runtime argument slices. This enum keeps that matching
50+
/// explicit and type-safe, replacing the old sentinel tuple encoding.
51+
#[derive(Clone, Copy, Debug)]
52+
pub enum FmtArgsCtor {
53+
/// `Arguments::new_const(pieces)`.
54+
NewConst { pieces_len: usize },
55+
/// `Arguments::new_v1(pieces, args)`.
56+
NewV1 {
57+
pieces_len: usize,
58+
rt_args_count: usize,
59+
},
60+
/// `Arguments::new_v1_formatted(..)` where lengths come from call operands.
61+
NewV1FormattedDynamic,
62+
/// `Arguments::from_str(s)`.
63+
FromStr,
64+
}
65+
4666
pub struct CodegenCx<'tcx> {
4767
pub tcx: TyCtxt<'tcx>,
4868
pub codegen_unit: &'tcx CodegenUnit<'tcx>,
@@ -73,8 +93,9 @@ pub struct CodegenCx<'tcx> {
7393
/// of these lang items, which we always replace with an "abort".
7494
pub panic_entry_points: RefCell<FxHashSet<DefId>>,
7595

76-
/// `core::fmt::Arguments::new_{v1,const}` instances (for Rust 2021 panics).
77-
pub fmt_args_new_fn_ids: RefCell<FxHashMap<Word, (usize, usize)>>,
96+
/// `core::fmt::Arguments::{new_const,new_v1,new_v1_formatted,from_str}`
97+
/// instances (for Rust 2021 panics).
98+
pub fmt_args_new_fn_ids: RefCell<FxHashMap<Word, FmtArgsCtor>>,
7899

79100
/// `core::fmt::rt::Argument::new_*::<T>` instances (for panics' `format_args!`),
80101
/// with their `T` type (i.e. of the value being formatted), and formatting

0 commit comments

Comments
 (0)