@@ -200,12 +200,10 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
200200 SpirvValue {
201201 kind : SpirvValueKind :: Def ( a_id) ,
202202 ty : a_ty,
203- ..
204203 } ,
205204 SpirvValue {
206205 kind : SpirvValueKind :: Def ( b_id) ,
207206 ty : b_ty,
208- ..
209207 } ,
210208 ref other_args @ ..,
211209 ] = args[ ..]
@@ -238,12 +236,10 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
238236 SpirvValue {
239237 kind : SpirvValueKind :: Def ( template_id) ,
240238 ty : template_ty_id,
241- ..
242239 } ,
243240 SpirvValue {
244241 kind : SpirvValueKind :: Def ( rt_args_or_tagged_len_id) ,
245242 ty : rt_args_or_tagged_len_ty_id,
246- ..
247243 } ,
248244 ref trailing @ ..,
249245 ] if trailing. len ( ) <= 2
@@ -462,165 +458,98 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
462458 FormatArgsNotRecognized ( "fmt::Arguments::new callee not registered" . into ( ) )
463459 } )
464460 } ;
465- let ( ctor, call_args_storage) = if let Some ( (
466- template_id,
467- template_ty_id,
468- rt_args_ptr_id,
469- rt_args_ptr_ty_id,
470- ) ) = split_fmt_args
471- {
472- let ctor = if let ( Some ( template_len) , Some ( rt_args_count) ) = (
473- const_ptr_to_composite_len ( template_id)
474- . or_else ( || array_len_from_ptr_type ( template_ty_id) ) ,
475- const_ptr_to_composite_len ( rt_args_ptr_id)
476- . or_else ( || array_len_from_ptr_type ( rt_args_ptr_ty_id) ) ,
477- ) {
478- FmtArgsCtor :: NewTemplate {
479- template_len,
480- rt_args_count,
481- }
482- } else if let Some ( & [ Inst :: Call ( _, callee_id, ref call_args) ] ) =
483- try_rev_take ( -1 ) . as_deref ( )
484- && call_args. len ( ) == 2
485- && [ call_args[ 0 ] , call_args[ 1 ] ] == [ template_id, rt_args_ptr_id]
486- {
487- // Consume the matched call instruction.
488- try_rev_take ( 1 ) . unwrap ( ) ;
489- lookup_fmt_args_ctor ( callee_id) ?
490- } else {
491- // We failed to recover constructor metadata for an already-split
492- // `fmt::Arguments` value. Keep panic lowering sound by falling
493- // back to an unknown panic message, without requiring decompilation.
494- return Ok ( decoded_format_args) ;
495- } ;
496-
497- (
498- ctor,
499- SmallVec :: < [ Word ; 8 ] > :: from_slice ( & [ template_id, rt_args_ptr_id] ) ,
500- )
501- } else {
502- // Newer rustc can pass the `fmt::Arguments::new_*` result directly to
503- // panic entry points (single trailing call), while older versions go
504- // through a local temporary (`Call -> Store -> Load`).
505- let fmt_args_new_call_inst_count = if matches ! (
506- try_rev_take( -3 ) . as_deref( ) ,
507- Some ( & [ Inst :: Call ( _, _, _) , Inst :: Store ( _, _) , Inst :: Load ( _, _) ] )
508- ) {
509- 3
510- } else if let Some ( & [ Inst :: Call ( call_ret_id, callee_id, _) ] ) =
511- try_rev_take ( -1 ) . as_deref ( )
461+ let ( ctor, call_args_storage) =
462+ if let Some ( ( template_id, template_ty_id, rt_args_ptr_id, rt_args_ptr_ty_id) ) =
463+ split_fmt_args
512464 {
513- if call_ret_id == format_args_id
514- || cx. fmt_args_new_fn_ids . borrow ( ) . contains_key ( & callee_id)
465+ let ctor = if let ( Some ( template_len) , Some ( rt_args_count) ) = (
466+ const_ptr_to_composite_len ( template_id)
467+ . or_else ( || array_len_from_ptr_type ( template_ty_id) ) ,
468+ const_ptr_to_composite_len ( rt_args_ptr_id)
469+ . or_else ( || array_len_from_ptr_type ( rt_args_ptr_ty_id) ) ,
470+ ) {
471+ FmtArgsCtor :: NewTemplate {
472+ template_len,
473+ rt_args_count,
474+ }
475+ } else if let Some ( & [ Inst :: Call ( _, callee_id, ref call_args) ] ) =
476+ try_rev_take ( -1 ) . as_deref ( )
477+ && call_args. len ( ) == 2
478+ && [ call_args[ 0 ] , call_args[ 1 ] ] == [ template_id, rt_args_ptr_id]
515479 {
516- 1
480+ // Consume the matched call instruction.
481+ try_rev_take ( 1 ) . unwrap ( ) ;
482+ lookup_fmt_args_ctor ( callee_id) ?
517483 } else {
518- 0
519- }
520- } else if matches ! (
521- try_rev_take( -5 ) . as_deref( ) ,
522- Some ( & [
523- Inst :: Call ( call_ret_id, _, _) ,
524- Inst :: CompositeExtract ( extracted0, from0, 0 ) ,
525- Inst :: CompositeExtract ( extracted1, from1, 1 ) ,
526- Inst :: CompositeInsert ( inserted0, value0, _, 0 ) ,
527- Inst :: CompositeInsert ( inserted1, value1, inserted0_prev, 1 ) ,
528- ] ) if [ from0, from1] == [ call_ret_id; 2 ]
529- && [ value0, value1] == [ extracted0, extracted1]
530- && inserted0 == inserted0_prev
531- && inserted1 == format_args_id
532- ) {
533- 5
534- } else if try_rev_take ( -1 ) . is_some ( ) {
535- 0
536- } else {
537- // HACK(eddyb) gather context for new call patterns before bailing.
538- let mut insts = SmallVec :: < [ Inst < Word > ; 32 ] > :: new ( ) ;
539- while let Some ( extra_inst) = try_rev_take ( 1 ) {
540- insts. extend ( extra_inst) ;
541- if insts. len ( ) >= 32 {
542- break ;
543- }
544- }
545- insts. reverse ( ) ;
546-
547- if insts. is_empty ( ) {
548- return Ok ( decoded_format_args) ;
549- }
550- if !insts. iter ( ) . any ( |inst| matches ! ( inst, Inst :: Call ( _, _, _) ) ) {
484+ // We failed to recover constructor metadata for an already-split
485+ // `fmt::Arguments` value. Keep panic lowering sound by falling
486+ // back to an unknown panic message, without requiring decompilation.
551487 return Ok ( decoded_format_args) ;
552- }
553- return Err ( FormatArgsNotRecognized ( format ! (
554- "fmt::Arguments::new call sequence ({insts:?})" ,
555- ) ) ) ;
556- } ;
557- if fmt_args_new_call_inst_count == 0 {
558- // HACK(eddyb) gather context for new call patterns before bailing.
559- let mut insts = SmallVec :: < [ Inst < Word > ; 32 ] > :: new ( ) ;
560- while let Some ( extra_inst) = try_rev_take ( 1 ) {
561- insts. extend ( extra_inst) ;
562- if insts. len ( ) >= 32 {
563- break ;
564- }
565- }
566- insts. reverse ( ) ;
488+ } ;
567489
568- if insts. is_empty ( ) {
569- return Ok ( decoded_format_args) ;
570- }
571- if !insts. iter ( ) . any ( |inst| matches ! ( inst, Inst :: Call ( _, _, _) ) ) {
572- return Ok ( decoded_format_args) ;
573- }
574- return Err ( FormatArgsNotRecognized ( format ! (
575- "fmt::Arguments::new call sequence ({insts:?})" ,
576- ) ) ) ;
577- }
578- let fmt_args_new_call_insts = try_rev_take ( fmt_args_new_call_inst_count) . unwrap ( ) ;
579- match fmt_args_new_call_insts[ ..] {
580- [
581- Inst :: Call ( call_ret_id, callee_id, ref call_args) ,
582- Inst :: Store ( st_dst_id, st_val_id) ,
583- Inst :: Load ( ld_val_id, ld_src_id) ,
584- ] if call_ret_id == st_val_id
585- && st_dst_id == ld_src_id
586- && ld_val_id == format_args_id =>
490+ (
491+ ctor,
492+ SmallVec :: < [ Word ; 8 ] > :: from_slice ( & [ template_id, rt_args_ptr_id] ) ,
493+ )
494+ } else {
495+ // Newer rustc can pass the `fmt::Arguments::new_*` result directly to
496+ // panic entry points (single trailing call), while older versions go
497+ // through a local temporary (`Call -> Store -> Load`).
498+ let fmt_args_new_call_inst_count = if matches ! (
499+ try_rev_take( -3 ) . as_deref( ) ,
500+ Some ( & [ Inst :: Call ( _, _, _) , Inst :: Store ( _, _) , Inst :: Load ( _, _) ] )
501+ ) {
502+ 3
503+ } else if let Some ( & [ Inst :: Call ( call_ret_id, callee_id, _) ] ) =
504+ try_rev_take ( -1 ) . as_deref ( )
587505 {
588- require_local_var ( st_dst_id, "fmt::Arguments::new destination" ) ?;
589-
590- (
591- lookup_fmt_args_ctor ( callee_id) ?,
592- call_args. iter ( ) . copied ( ) . collect ( ) ,
593- )
594- }
595- [ Inst :: Call ( call_ret_id, callee_id, ref call_args) ]
596506 if call_ret_id == format_args_id
597- || cx. fmt_args_new_fn_ids . borrow ( ) . contains_key ( & callee_id) =>
598- {
599- (
600- lookup_fmt_args_ctor ( callee_id) ?,
601- call_args. iter ( ) . copied ( ) . collect ( ) ,
602- )
603- }
604- [
605- Inst :: Call ( call_ret_id, callee_id, ref call_args) ,
606- Inst :: CompositeExtract ( extracted0, from0, 0 ) ,
607- Inst :: CompositeExtract ( extracted1, from1, 1 ) ,
608- Inst :: CompositeInsert ( inserted0, value0, _, 0 ) ,
609- Inst :: CompositeInsert ( inserted1, value1, inserted0_prev, 1 ) ,
610- ] if [ from0, from1] == [ call_ret_id; 2 ]
611- && [ value0, value1] == [ extracted0, extracted1]
612- && inserted0 == inserted0_prev
613- && inserted1 == format_args_id =>
614- {
615- (
616- lookup_fmt_args_ctor ( callee_id) ?,
617- call_args. iter ( ) . copied ( ) . collect ( ) ,
618- )
619- }
620- _ => {
621- // HACK(eddyb) this gathers more context before reporting.
622- let mut insts = fmt_args_new_call_insts;
507+ || cx. fmt_args_new_fn_ids . borrow ( ) . contains_key ( & callee_id)
508+ {
509+ 1
510+ } else {
511+ 0
512+ }
513+ } else if matches ! (
514+ try_rev_take( -5 ) . as_deref( ) ,
515+ Some ( & [
516+ Inst :: Call ( call_ret_id, _, _) ,
517+ Inst :: CompositeExtract ( extracted0, from0, 0 ) ,
518+ Inst :: CompositeExtract ( extracted1, from1, 1 ) ,
519+ Inst :: CompositeInsert ( inserted0, value0, _, 0 ) ,
520+ Inst :: CompositeInsert ( inserted1, value1, inserted0_prev, 1 ) ,
521+ ] ) if [ from0, from1] == [ call_ret_id; 2 ]
522+ && [ value0, value1] == [ extracted0, extracted1]
523+ && inserted0 == inserted0_prev
524+ && inserted1 == format_args_id
525+ ) {
526+ 5
527+ } else if try_rev_take ( -1 ) . is_some ( ) {
528+ 0
529+ } else {
530+ // HACK(eddyb) gather context for new call patterns before bailing.
531+ let mut insts = SmallVec :: < [ Inst < Word > ; 32 ] > :: new ( ) ;
532+ while let Some ( extra_inst) = try_rev_take ( 1 ) {
533+ insts. extend ( extra_inst) ;
534+ if insts. len ( ) >= 32 {
535+ break ;
536+ }
537+ }
623538 insts. reverse ( ) ;
539+
540+ if insts. is_empty ( ) {
541+ return Ok ( decoded_format_args) ;
542+ }
543+ if !insts. iter ( ) . any ( |inst| matches ! ( inst, Inst :: Call ( _, _, _) ) ) {
544+ return Ok ( decoded_format_args) ;
545+ }
546+ return Err ( FormatArgsNotRecognized ( format ! (
547+ "fmt::Arguments::new call sequence ({insts:?})" ,
548+ ) ) ) ;
549+ } ;
550+ if fmt_args_new_call_inst_count == 0 {
551+ // HACK(eddyb) gather context for new call patterns before bailing.
552+ let mut insts = SmallVec :: < [ Inst < Word > ; 32 ] > :: new ( ) ;
624553 while let Some ( extra_inst) = try_rev_take ( 1 ) {
625554 insts. extend ( extra_inst) ;
626555 if insts. len ( ) >= 32 {
@@ -629,12 +558,76 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
629558 }
630559 insts. reverse ( ) ;
631560
561+ if insts. is_empty ( ) {
562+ return Ok ( decoded_format_args) ;
563+ }
564+ if !insts. iter ( ) . any ( |inst| matches ! ( inst, Inst :: Call ( _, _, _) ) ) {
565+ return Ok ( decoded_format_args) ;
566+ }
632567 return Err ( FormatArgsNotRecognized ( format ! (
633568 "fmt::Arguments::new call sequence ({insts:?})" ,
634569 ) ) ) ;
635570 }
636- }
637- } ;
571+ let fmt_args_new_call_insts = try_rev_take ( fmt_args_new_call_inst_count) . unwrap ( ) ;
572+ match fmt_args_new_call_insts[ ..] {
573+ [
574+ Inst :: Call ( call_ret_id, callee_id, ref call_args) ,
575+ Inst :: Store ( st_dst_id, st_val_id) ,
576+ Inst :: Load ( ld_val_id, ld_src_id) ,
577+ ] if call_ret_id == st_val_id
578+ && st_dst_id == ld_src_id
579+ && ld_val_id == format_args_id =>
580+ {
581+ require_local_var ( st_dst_id, "fmt::Arguments::new destination" ) ?;
582+
583+ (
584+ lookup_fmt_args_ctor ( callee_id) ?,
585+ call_args. iter ( ) . copied ( ) . collect ( ) ,
586+ )
587+ }
588+ [ Inst :: Call ( call_ret_id, callee_id, ref call_args) ]
589+ if call_ret_id == format_args_id
590+ || cx. fmt_args_new_fn_ids . borrow ( ) . contains_key ( & callee_id) =>
591+ {
592+ (
593+ lookup_fmt_args_ctor ( callee_id) ?,
594+ call_args. iter ( ) . copied ( ) . collect ( ) ,
595+ )
596+ }
597+ [
598+ Inst :: Call ( call_ret_id, callee_id, ref call_args) ,
599+ Inst :: CompositeExtract ( extracted0, from0, 0 ) ,
600+ Inst :: CompositeExtract ( extracted1, from1, 1 ) ,
601+ Inst :: CompositeInsert ( inserted0, value0, _, 0 ) ,
602+ Inst :: CompositeInsert ( inserted1, value1, inserted0_prev, 1 ) ,
603+ ] if [ from0, from1] == [ call_ret_id; 2 ]
604+ && [ value0, value1] == [ extracted0, extracted1]
605+ && inserted0 == inserted0_prev
606+ && inserted1 == format_args_id =>
607+ {
608+ (
609+ lookup_fmt_args_ctor ( callee_id) ?,
610+ call_args. iter ( ) . copied ( ) . collect ( ) ,
611+ )
612+ }
613+ _ => {
614+ // HACK(eddyb) this gathers more context before reporting.
615+ let mut insts = fmt_args_new_call_insts;
616+ insts. reverse ( ) ;
617+ while let Some ( extra_inst) = try_rev_take ( 1 ) {
618+ insts. extend ( extra_inst) ;
619+ if insts. len ( ) >= 32 {
620+ break ;
621+ }
622+ }
623+ insts. reverse ( ) ;
624+
625+ return Err ( FormatArgsNotRecognized ( format ! (
626+ "fmt::Arguments::new call sequence ({insts:?})" ,
627+ ) ) ) ;
628+ }
629+ }
630+ } ;
638631 let call_args = call_args_storage. as_slice ( ) ;
639632 enum PiecesSource {
640633 Slice { ptr_id : Word , len : usize } ,
0 commit comments