Skip to content

Commit d712946

Browse files
committed
builder: more robust format_args! "decompiling".
1 parent 425328a commit d712946

File tree

1 file changed

+55
-47
lines changed

1 file changed

+55
-47
lines changed

crates/rustc_codegen_spirv/src/builder/builder_methods.rs

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3399,15 +3399,18 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
33993399
.map(|operand| operand.id_ref_any())
34003400
.collect::<Option<SmallVec<[_; 4]>>>()?;
34013401

3402+
let const_as_u32 = |id| match self.builder.lookup_const_by_id(id)? {
3403+
SpirvConst::Scalar(x) => u32::try_from(x).ok(),
3404+
_ => None,
3405+
};
3406+
34023407
// Decode the instruction into one of our `Inst`s.
34033408
Some(
34043409
match (inst.class.opcode, inst.result_id, &id_operands[..]) {
34053410
(Op::Bitcast, Some(r), &[x]) => Inst::Bitcast(r, x),
34063411
(Op::InBoundsAccessChain, Some(r), &[p, i]) => {
3407-
if let Some(SpirvConst::Scalar(i)) =
3408-
self.builder.lookup_const_by_id(i)
3409-
{
3410-
Inst::InBoundsAccessChain(r, p, i as u32)
3412+
if let Some(i) = const_as_u32(i) {
3413+
Inst::InBoundsAccessChain(r, p, i)
34113414
} else {
34123415
Inst::Unsupported(inst.class.opcode)
34133416
}
@@ -3494,47 +3497,65 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
34943497
if rt_args_count > 0 {
34953498
let rt_args_array_ptr_id = rt_args_slice_ptr_id.unwrap();
34963499

3497-
// Each runtime argument has 4 instructions to call one of
3500+
// Each runtime argument has A instructions to call one of
34983501
// the `fmt::rt::Argument::new_*` functions (and temporarily
3499-
// store its result), and 4 instructions to copy it into
3500-
// the appropriate slot in the array. The groups of 4 and 4
3501-
// instructions, for all runtime args, are each separate.
3502-
let copies_to_rt_args_array =
3503-
try_rev_take(rt_args_count * 4).ok_or_else(|| {
3502+
// store its result), and B instructions to copy it into
3503+
// the appropriate slot in the array. The groups of A and B
3504+
// instructions, for all runtime args, are each separate,
3505+
// so the B×N later instructions are all processed first,
3506+
// before moving (backwards) to the A×N earlier instructions.
3507+
3508+
let rev_copies_to_rt_args_array_src_ptrs: SmallVec<[_; 4]> =
3509+
(0..rt_args_count).rev().map(|rt_arg_idx| {
3510+
let copy_to_rt_args_array_insts = try_rev_take(4).ok_or_else(|| {
35043511
FormatArgsNotRecognized(
3505-
"[fmt::rt::Argument; N] copies: ran out of instructions".into(),
3512+
"[fmt::rt::Argument; N] copy: ran out of instructions".into(),
35063513
)
35073514
})?;
3508-
let copies_to_rt_args_array = copies_to_rt_args_array.chunks(4);
3509-
let rt_arg_new_calls = try_rev_take(rt_args_count * 4).ok_or_else(|| {
3510-
FormatArgsNotRecognized(
3511-
"fmt::rt::Argument::new calls: ran out of instructions".into(),
3512-
)
3513-
})?;
3514-
let rt_arg_new_calls = rt_arg_new_calls.chunks(4);
3515+
match copy_to_rt_args_array_insts[..] {
3516+
[
3517+
Inst::InBoundsAccessChain(array_slot, array_base, array_idx),
3518+
Inst::InBoundsAccessChain(dst_field_ptr, dst_base_ptr, 0),
3519+
Inst::InBoundsAccessChain(src_field_ptr, src_base_ptr, 0),
3520+
Inst::CopyMemory(copy_dst, copy_src),
3521+
] if array_base == rt_args_array_ptr_id
3522+
&& array_idx as usize == rt_arg_idx
3523+
&& dst_base_ptr == array_slot
3524+
&& (copy_dst, copy_src) == (dst_field_ptr, src_field_ptr) =>
3525+
{
3526+
Ok(src_base_ptr)
3527+
}
3528+
_ => {
3529+
Err(FormatArgsNotRecognized(format!(
3530+
"[fmt::rt::Argument; N] copy sequence ({copy_to_rt_args_array_insts:?})"
3531+
)))
3532+
}
3533+
}
3534+
}).collect::<Result<_, _>>()?;
35153535

3516-
for (rt_arg_idx, (rt_arg_new_call_insts, copy_to_rt_args_array_insts)) in
3517-
rt_arg_new_calls.zip(copies_to_rt_args_array).enumerate()
3518-
{
3519-
let call_ret_slot_ptr = match rt_arg_new_call_insts[..] {
3536+
let rev_ref_arg_ids_with_ty_and_spec = (rev_copies_to_rt_args_array_src_ptrs
3537+
.into_iter())
3538+
.map(|copy_to_rt_args_array_src_ptr| {
3539+
let rt_arg_new_call_insts = try_rev_take(4).ok_or_else(|| {
3540+
FormatArgsNotRecognized(
3541+
"fmt::rt::Argument::new call: ran out of instructions".into(),
3542+
)
3543+
})?;
3544+
match rt_arg_new_call_insts[..] {
35203545
[
35213546
Inst::Call(call_ret_id, callee_id, ref call_args),
35223547
Inst::InBoundsAccessChain(tmp_slot_field_ptr, tmp_slot_ptr, 0),
35233548
Inst::CompositeExtract(field, wrapper_newtype, 0),
35243549
Inst::Store(st_dst_ptr, st_val),
35253550
] if wrapper_newtype == call_ret_id
3551+
&& tmp_slot_ptr == copy_to_rt_args_array_src_ptr
35263552
&& (st_dst_ptr, st_val) == (tmp_slot_field_ptr, field) =>
35273553
{
35283554
self.fmt_rt_arg_new_fn_ids_to_ty_and_spec
35293555
.borrow()
35303556
.get(&callee_id)
35313557
.and_then(|&(ty, spec)| match call_args[..] {
3532-
[x] => {
3533-
decoded_format_args
3534-
.ref_arg_ids_with_ty_and_spec
3535-
.push((x, ty, spec));
3536-
Some(tmp_slot_ptr)
3537-
}
3558+
[x] => Some((x, ty, spec)),
35383559
_ => None,
35393560
})
35403561
}
@@ -3544,26 +3565,13 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
35443565
FormatArgsNotRecognized(format!(
35453566
"fmt::rt::Argument::new call sequence ({rt_arg_new_call_insts:?})"
35463567
))
3547-
})?;
3568+
})
3569+
})
3570+
.collect::<Result<_, _>>()?;
35483571

3549-
match copy_to_rt_args_array_insts[..] {
3550-
[
3551-
Inst::InBoundsAccessChain(array_slot, array_base, array_idx),
3552-
Inst::InBoundsAccessChain(dst_field_ptr, dst_base_ptr, 0),
3553-
Inst::InBoundsAccessChain(src_field_ptr, src_base_ptr, 0),
3554-
Inst::CopyMemory(copy_dst, copy_src),
3555-
] if array_base == rt_args_array_ptr_id
3556-
&& array_idx as usize == rt_arg_idx
3557-
&& dst_base_ptr == array_slot
3558-
&& src_base_ptr == call_ret_slot_ptr
3559-
&& (copy_dst, copy_src) == (dst_field_ptr, src_field_ptr) => {}
3560-
_ => {
3561-
return Err(FormatArgsNotRecognized(format!(
3562-
"[fmt::rt::Argument; N] copies sequence ({copy_to_rt_args_array_insts:?})"
3563-
)));
3564-
}
3565-
}
3566-
}
3572+
decoded_format_args.ref_arg_ids_with_ty_and_spec =
3573+
rev_ref_arg_ids_with_ty_and_spec;
3574+
decoded_format_args.ref_arg_ids_with_ty_and_spec.reverse();
35673575
}
35683576

35693577
// If the `pieces: &[&str]` slice needs a bitcast, it'll be here.

0 commit comments

Comments
 (0)