@@ -15,7 +15,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1515use rustc_errors:: ErrorGuaranteed ;
1616use rustc_session:: Session ;
1717use smallvec:: SmallVec ;
18- use std:: mem;
18+ use std:: mem:: { self , take } ;
1919
2020type FunctionMap = FxHashMap < Word , Function > ;
2121
@@ -658,13 +658,15 @@ impl Inliner<'_, '_> {
658658 if let Some ( call_result_type) = call_result_type {
659659 // Generate the storage space for the return value: Do this *after* the split above,
660660 // because if block_idx=0, inserting a variable here shifts call_index.
661- let ret_var_inst = Instruction :: new (
662- Op :: Variable ,
663- Some ( self . ptr_ty ( call_result_type) ) ,
664- Some ( return_variable. unwrap ( ) ) ,
665- vec ! [ Operand :: StorageClass ( StorageClass :: Function ) ] ,
661+ insert_opvariables (
662+ & mut caller. blocks [ 0 ] ,
663+ [ Instruction :: new (
664+ Op :: Variable ,
665+ Some ( self . ptr_ty ( call_result_type) ) ,
666+ Some ( return_variable. unwrap ( ) ) ,
667+ vec ! [ Operand :: StorageClass ( StorageClass :: Function ) ] ,
668+ ) ] ,
666669 ) ;
667- self . insert_opvariables ( & mut caller. blocks [ 0 ] , [ ret_var_inst] ) ;
668670 }
669671
670672 // Insert non-entry inlined callee blocks just after the pre-call block.
@@ -710,115 +712,52 @@ impl Inliner<'_, '_> {
710712 // Fuse the inlined callee entry block into the pre-call block.
711713 // This is okay because it's illegal to branch to the first BB in a function.
712714 {
713- // NOTE(eddyb) `OpExtInst`s have a result ID, even if unused, and
714- // it has to be unique, so this allocates new IDs as-needed.
715- let instantiate_debuginfo = |this : & mut Self , inst : & Instruction | {
716- let mut inst = inst. clone ( ) ;
717- if let Some ( id) = & mut inst. result_id {
718- * id = this. id ( ) ;
719- }
720- inst
721- } ;
722-
723- let custom_inst_to_inst = |this : & mut Self , inst : CustomInst < _ > | {
724- Instruction :: new (
725- Op :: ExtInst ,
726- Some ( this. op_type_void_id ) ,
727- Some ( this. id ( ) ) ,
728- [
729- Operand :: IdRef ( this. custom_ext_inst_set_import ) ,
730- Operand :: LiteralExtInstInteger ( inst. op ( ) as u32 ) ,
731- ]
732- . into_iter ( )
733- . chain ( inst. into_operands ( ) )
734- . collect ( ) ,
735- )
736- } ;
737-
738715 // Return the subsequence of `insts` made from `OpVariable`s, and any
739716 // debuginfo instructions (which may apply to them), while removing
740717 // *only* `OpVariable`s from `insts` (and keeping debuginfo in both).
741718 let mut steal_vars = |insts : & mut Vec < Instruction > | {
742- // HACK(eddyb) this duplicates some code from `get_inlined_blocks`,
743- // but that will be removed once the inliner is refactored to be
744- // inside-out instead of outside-in (already finished in a branch).
745- let mut enclosing_inlined_frames = SmallVec :: < [ _ ; 8 ] > :: new ( ) ;
746- let mut current_debug_src_loc_inst = None ;
747- let mut vars_and_debuginfo_range = 0 ..0 ;
748- while vars_and_debuginfo_range. end < insts. len ( ) {
749- let inst = & insts[ vars_and_debuginfo_range. end ] ;
750- match inst. class . opcode {
751- Op :: Line => current_debug_src_loc_inst = Some ( inst) ,
752- Op :: NoLine => current_debug_src_loc_inst = None ,
753- Op :: ExtInst
754- if inst. operands [ 0 ] . unwrap_id_ref ( )
755- == self . custom_ext_inst_set_import =>
756- {
757- match CustomOp :: decode_from_ext_inst ( inst) {
758- CustomOp :: SetDebugSrcLoc => current_debug_src_loc_inst = Some ( inst) ,
759- CustomOp :: ClearDebugSrcLoc => current_debug_src_loc_inst = None ,
760- CustomOp :: PushInlinedCallFrame => {
761- enclosing_inlined_frames
762- . push ( ( current_debug_src_loc_inst. take ( ) , inst) ) ;
763- }
764- CustomOp :: PopInlinedCallFrame => {
765- if let Some ( ( callsite_debug_src_loc_inst, _) ) =
766- enclosing_inlined_frames. pop ( )
767- {
768- current_debug_src_loc_inst = callsite_debug_src_loc_inst;
769- }
770- }
771- CustomOp :: Abort => break ,
772- }
719+ let mut vars_and_debuginfo = vec ! [ ] ;
720+ insts. retain_mut ( |inst| {
721+ let is_debuginfo = match inst. class . opcode {
722+ Op :: Line | Op :: NoLine => true ,
723+ Op :: ExtInst => {
724+ inst. operands [ 0 ] . unwrap_id_ref ( ) == self . custom_ext_inst_set_import
725+ && CustomOp :: decode_from_ext_inst ( inst) . is_debuginfo ( )
773726 }
774- Op :: Variable => { }
775- _ => break ,
727+ _ => false ,
728+ } ;
729+ if is_debuginfo {
730+ // NOTE(eddyb) `OpExtInst`s have a result ID,
731+ // even if unused, and it has to be unique.
732+ let mut inst = inst. clone ( ) ;
733+ if let Some ( id) = & mut inst. result_id {
734+ * id = self . id ( ) ;
735+ }
736+ vars_and_debuginfo. push ( inst) ;
737+ true
738+ } else if inst. class . opcode == Op :: Variable {
739+ // HACK(eddyb) we're removing this `Instruction` from
740+ // `inst`, so it doesn't really matter what we use here.
741+ vars_and_debuginfo. push ( mem:: replace (
742+ inst,
743+ Instruction :: new ( Op :: Nop , None , None , vec ! [ ] ) ,
744+ ) ) ;
745+ false
746+ } else {
747+ true
776748 }
777- vars_and_debuginfo_range. end += 1 ;
778- }
779-
780- // `vars_and_debuginfo_range.end` indicates where `OpVariable`s
781- // end and other instructions start (module debuginfo), but to
782- // split the block in two, both sides of the "cut" need "repair":
783- // - the variables are missing "inlined call frames" pops, that
784- // may happen later in the block, and have to be synthesized
785- // - the non-variables are missing "inlined call frames" pushes,
786- // that must be recreated to avoid ending up with dangling pops
787- //
788- // FIXME(eddyb) this only collects to avoid borrow conflicts,
789- // between e.g. `enclosing_inlined_frames` and mutating `insts`,
790- // but also between different uses of `self`.
791- let all_pops_after_vars: SmallVec < [ _ ; 8 ] > = enclosing_inlined_frames
792- . iter ( )
793- . map ( |_| custom_inst_to_inst ( self , CustomInst :: PopInlinedCallFrame ) )
794- . collect ( ) ;
795- let all_repushes_before_non_vars: SmallVec < [ _ ; 8 ] > =
796- ( enclosing_inlined_frames. into_iter ( ) . flat_map (
797- |( callsite_debug_src_loc_inst, push_inlined_call_frame_inst) | {
798- ( callsite_debug_src_loc_inst. into_iter ( ) )
799- . chain ( [ push_inlined_call_frame_inst] )
800- } ,
801- ) )
802- . chain ( current_debug_src_loc_inst)
803- . map ( |inst| instantiate_debuginfo ( self , inst) )
804- . collect ( ) ;
805-
806- let vars_and_debuginfo =
807- insts. splice ( vars_and_debuginfo_range, all_repushes_before_non_vars) ;
808- let repaired_vars_and_debuginfo = vars_and_debuginfo. chain ( all_pops_after_vars) ;
809-
810- // FIXME(eddyb) collecting shouldn't be necessary but this is
811- // nested in a closure, and `splice` borrows the original `Vec`.
812- repaired_vars_and_debuginfo. collect :: < SmallVec < [ _ ; 8 ] > > ( )
749+ } ) ;
750+ vars_and_debuginfo
813751 } ;
814752
815753 let [ mut inlined_callee_entry_block] : [ _ ; 1 ] =
816754 inlined_callee_blocks. try_into ( ) . unwrap ( ) ;
817755
818756 // Move the `OpVariable`s of the callee to the caller.
819- let callee_vars_and_debuginfo =
820- steal_vars ( & mut inlined_callee_entry_block. instructions ) ;
821- self . insert_opvariables ( & mut caller. blocks [ 0 ] , callee_vars_and_debuginfo) ;
757+ insert_opvariables (
758+ & mut caller. blocks [ 0 ] ,
759+ steal_vars ( & mut inlined_callee_entry_block. instructions ) ,
760+ ) ;
822761
823762 caller. blocks [ pre_call_block_idx]
824763 . instructions
@@ -1051,52 +990,15 @@ impl Inliner<'_, '_> {
1051990 caller_restore_debuginfo_after_call,
1052991 )
1053992 }
993+ }
1054994
1055- fn insert_opvariables ( & self , block : & mut Block , insts : impl IntoIterator < Item = Instruction > ) {
1056- // HACK(eddyb) this isn't as efficient as it could be in theory, but it's
1057- // very important to make sure sure to never insert new instructions in
1058- // the middle of debuginfo (as it would be affected by it).
1059- let mut inlined_frames_depth = 0usize ;
1060- let mut outermost_has_debug_src_loc = false ;
1061- let mut last_debugless_var_insertion_point_candidate = None ;
1062- for ( i, inst) in block. instructions . iter ( ) . enumerate ( ) {
1063- last_debugless_var_insertion_point_candidate =
1064- ( inlined_frames_depth == 0 && !outermost_has_debug_src_loc) . then_some ( i) ;
1065-
1066- let changed_has_debug_src_loc = match inst. class . opcode {
1067- Op :: Line => true ,
1068- Op :: NoLine => false ,
1069- Op :: ExtInst
1070- if inst. operands [ 0 ] . unwrap_id_ref ( ) == self . custom_ext_inst_set_import =>
1071- {
1072- match CustomOp :: decode_from_ext_inst ( inst) {
1073- CustomOp :: SetDebugSrcLoc => true ,
1074- CustomOp :: ClearDebugSrcLoc => false ,
1075- CustomOp :: PushInlinedCallFrame => {
1076- inlined_frames_depth += 1 ;
1077- continue ;
1078- }
1079- CustomOp :: PopInlinedCallFrame => {
1080- inlined_frames_depth = inlined_frames_depth. saturating_sub ( 1 ) ;
1081- continue ;
1082- }
1083- CustomOp :: Abort => break ,
1084- }
1085- }
1086- Op :: Variable => continue ,
1087- _ => break ,
1088- } ;
1089-
1090- if inlined_frames_depth == 0 {
1091- outermost_has_debug_src_loc = changed_has_debug_src_loc;
1092- }
1093- }
1094-
1095- // HACK(eddyb) fallback to inserting at the start, which should be correct.
1096- // FIXME(eddyb) some level of debuginfo repair could prevent needing this.
1097- let i = last_debugless_var_insertion_point_candidate. unwrap_or ( 0 ) ;
1098- block. instructions . splice ( i..i, insts) ;
1099- }
995+ fn insert_opvariables ( block : & mut Block , insts : impl IntoIterator < Item = Instruction > ) {
996+ let first_non_variable = block
997+ . instructions
998+ . iter ( )
999+ . position ( |inst| inst. class . opcode != Op :: Variable ) ;
1000+ let i = first_non_variable. unwrap_or ( block. instructions . len ( ) ) ;
1001+ block. instructions . splice ( i..i, insts) ;
11001002}
11011003
11021004fn fuse_trivial_branches ( function : & mut Function ) {
@@ -1131,7 +1033,7 @@ fn fuse_trivial_branches(function: &mut Function) {
11311033 } ;
11321034 let pred_insts = & function. blocks [ pred] . instructions ;
11331035 if pred_insts. last ( ) . unwrap ( ) . class . opcode == Op :: Branch {
1134- let mut dest_insts = mem :: take ( & mut function. blocks [ dest_block] . instructions ) ;
1036+ let mut dest_insts = take ( & mut function. blocks [ dest_block] . instructions ) ;
11351037 let pred_insts = & mut function. blocks [ pred] . instructions ;
11361038 pred_insts. pop ( ) ; // pop the branch
11371039 pred_insts. append ( & mut dest_insts) ;
0 commit comments