@@ -94,7 +94,6 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> {
9494 header,
9595 debug_string_source : & mut module. debug_string_source ,
9696 annotations : & mut module. annotations ,
97- types_global_values : & mut module. types_global_values ,
9897
9998 legal_globals,
10099
@@ -493,7 +492,6 @@ struct Inliner<'a, 'b> {
493492 header : & ' b mut ModuleHeader ,
494493 debug_string_source : & ' b mut Vec < Instruction > ,
495494 annotations : & ' b mut Vec < Instruction > ,
496- types_global_values : & ' b mut Vec < Instruction > ,
497495
498496 legal_globals : FxHashMap < Word , LegalGlobal > ,
499497 functions_that_may_abort : FxHashSet < Word > ,
@@ -523,29 +521,6 @@ impl Inliner<'_, '_> {
523521 }
524522 }
525523
526- fn ptr_ty ( & mut self , pointee : Word ) -> Word {
527- // TODO: This is horribly slow, fix this
528- let existing = self . types_global_values . iter ( ) . find ( |inst| {
529- inst. class . opcode == Op :: TypePointer
530- && inst. operands [ 0 ] . unwrap_storage_class ( ) == StorageClass :: Function
531- && inst. operands [ 1 ] . unwrap_id_ref ( ) == pointee
532- } ) ;
533- if let Some ( existing) = existing {
534- return existing. result_id . unwrap ( ) ;
535- }
536- let inst_id = self . id ( ) ;
537- self . types_global_values . push ( Instruction :: new (
538- Op :: TypePointer ,
539- None ,
540- Some ( inst_id) ,
541- vec ! [
542- Operand :: StorageClass ( StorageClass :: Function ) ,
543- Operand :: IdRef ( pointee) ,
544- ] ,
545- ) ) ;
546- inst_id
547- }
548-
549524 fn inline_fn (
550525 & mut self ,
551526 function : & mut Function ,
@@ -622,15 +597,19 @@ impl Inliner<'_, '_> {
622597 . insert ( caller. def_id ( ) . unwrap ( ) ) ;
623598 }
624599
625- let call_result_type = {
600+ let mut maybe_call_result_phi = {
626601 let ty = call_inst. result_type . unwrap ( ) ;
627602 if ty == self . op_type_void_id {
628603 None
629604 } else {
630- Some ( ty)
605+ Some ( Instruction :: new (
606+ Op :: Phi ,
607+ Some ( ty) ,
608+ Some ( call_inst. result_id . unwrap ( ) ) ,
609+ vec ! [ ] ,
610+ ) )
631611 }
632612 } ;
633- let call_result_id = call_inst. result_id . unwrap ( ) ;
634613
635614 // Get the debug "source location" instruction that applies to the call.
636615 let custom_ext_inst_set_import = self . custom_ext_inst_set_import ;
@@ -667,17 +646,12 @@ impl Inliner<'_, '_> {
667646 } ) ;
668647 let mut rewrite_rules = callee_parameters. zip ( call_arguments) . collect ( ) ;
669648
670- let return_variable = if call_result_type. is_some ( ) {
671- Some ( self . id ( ) )
672- } else {
673- None
674- } ;
675649 let return_jump = self . id ( ) ;
676650 // Rewrite OpReturns of the callee.
677651 let mut inlined_callee_blocks = self . get_inlined_blocks (
678652 callee,
679653 call_debug_src_loc_inst,
680- return_variable ,
654+ maybe_call_result_phi . as_mut ( ) ,
681655 return_jump,
682656 ) ;
683657 // Clone the IDs of the callee, because otherwise they'd be defined multiple times if the
@@ -686,6 +660,55 @@ impl Inliner<'_, '_> {
686660 apply_rewrite_rules ( & rewrite_rules, & mut inlined_callee_blocks) ;
687661 self . apply_rewrite_for_decorations ( & rewrite_rules) ;
688662
663+ if let Some ( call_result_phi) = & mut maybe_call_result_phi {
664+ // HACK(eddyb) new IDs should be generated earlier, to avoid pushing
665+ // callee IDs to `call_result_phi.operands` only to rewrite them here.
666+ for op in & mut call_result_phi. operands {
667+ if let Some ( id) = op. id_ref_any_mut ( ) {
668+ if let Some ( & rewrite) = rewrite_rules. get ( id) {
669+ * id = rewrite;
670+ }
671+ }
672+ }
673+
674+ // HACK(eddyb) this special-casing of the single-return case is
675+ // really necessary for passes like `mem2reg` which are not capable
676+ // of skipping through the extraneous `OpPhi`s on their own.
677+ if let [ returned_value, _return_block] = & call_result_phi. operands [ ..] {
678+ let call_result_id = call_result_phi. result_id . unwrap ( ) ;
679+ let returned_value_id = returned_value. unwrap_id_ref ( ) ;
680+
681+ maybe_call_result_phi = None ;
682+
683+ // HACK(eddyb) this is a conservative approximation of all the
684+ // instructions that could potentially reference the call result.
685+ let reaching_insts = {
686+ let ( pre_call_blocks, call_and_post_call_blocks) =
687+ caller. blocks . split_at_mut ( block_idx) ;
688+ ( pre_call_blocks. iter_mut ( ) . flat_map ( |block| {
689+ block
690+ . instructions
691+ . iter_mut ( )
692+ . take_while ( |inst| inst. class . opcode == Op :: Phi )
693+ } ) )
694+ . chain (
695+ call_and_post_call_blocks
696+ . iter_mut ( )
697+ . flat_map ( |block| & mut block. instructions ) ,
698+ )
699+ } ;
700+ for reaching_inst in reaching_insts {
701+ for op in & mut reaching_inst. operands {
702+ if let Some ( id) = op. id_ref_any_mut ( ) {
703+ if * id == call_result_id {
704+ * id = returned_value_id;
705+ }
706+ }
707+ }
708+ }
709+ }
710+ }
711+
689712 // Split the block containing the `OpFunctionCall` into pre-call vs post-call.
690713 let pre_call_block_idx = block_idx;
691714 #[ expect( unused) ]
@@ -701,18 +724,6 @@ impl Inliner<'_, '_> {
701724 . unwrap ( ) ;
702725 assert ! ( call. class. opcode == Op :: FunctionCall ) ;
703726
704- if let Some ( call_result_type) = call_result_type {
705- // Generate the storage space for the return value: Do this *after* the split above,
706- // because if block_idx=0, inserting a variable here shifts call_index.
707- let ret_var_inst = Instruction :: new (
708- Op :: Variable ,
709- Some ( self . ptr_ty ( call_result_type) ) ,
710- Some ( return_variable. unwrap ( ) ) ,
711- vec ! [ Operand :: StorageClass ( StorageClass :: Function ) ] ,
712- ) ;
713- self . insert_opvariables ( & mut caller. blocks [ 0 ] , [ ret_var_inst] ) ;
714- }
715-
716727 // Insert non-entry inlined callee blocks just after the pre-call block.
717728 let non_entry_inlined_callee_blocks = inlined_callee_blocks. drain ( 1 ..) ;
718729 let num_non_entry_inlined_callee_blocks = non_entry_inlined_callee_blocks. len ( ) ;
@@ -721,18 +732,9 @@ impl Inliner<'_, '_> {
721732 non_entry_inlined_callee_blocks,
722733 ) ;
723734
724- if let Some ( call_result_type) = call_result_type {
725- // Add the load of the result value after the inlined function. Note there's guaranteed no
726- // OpPhi instructions since we just split this block.
727- post_call_block_insts. insert (
728- 0 ,
729- Instruction :: new (
730- Op :: Load ,
731- Some ( call_result_type) ,
732- Some ( call_result_id) ,
733- vec ! [ Operand :: IdRef ( return_variable. unwrap( ) ) ] ,
734- ) ,
735- ) ;
735+ if let Some ( call_result_phi) = maybe_call_result_phi {
736+ // Add the `OpPhi` for the call result value, after the inlined function.
737+ post_call_block_insts. insert ( 0 , call_result_phi) ;
736738 }
737739
738740 // Insert the post-call block, after all the inlined callee blocks.
@@ -899,7 +901,7 @@ impl Inliner<'_, '_> {
899901 & mut self ,
900902 callee : & Function ,
901903 call_debug_src_loc_inst : Option < & Instruction > ,
902- return_variable : Option < Word > ,
904+ mut maybe_call_result_phi : Option < & mut Instruction > ,
903905 return_jump : Word ,
904906 ) -> Vec < Block > {
905907 let Self {
@@ -997,17 +999,13 @@ impl Inliner<'_, '_> {
997999 if let Op :: Return | Op :: ReturnValue = terminator. class . opcode {
9981000 if Op :: ReturnValue == terminator. class . opcode {
9991001 let return_value = terminator. operands [ 0 ] . id_ref_any ( ) . unwrap ( ) ;
1000- block. instructions . push ( Instruction :: new (
1001- Op :: Store ,
1002- None ,
1003- None ,
1004- vec ! [
1005- Operand :: IdRef ( return_variable. unwrap( ) ) ,
1006- Operand :: IdRef ( return_value) ,
1007- ] ,
1008- ) ) ;
1002+ let call_result_phi = maybe_call_result_phi. as_deref_mut ( ) . unwrap ( ) ;
1003+ call_result_phi. operands . extend ( [
1004+ Operand :: IdRef ( return_value) ,
1005+ Operand :: IdRef ( block. label_id ( ) . unwrap ( ) ) ,
1006+ ] ) ;
10091007 } else {
1010- assert ! ( return_variable . is_none( ) ) ;
1008+ assert ! ( maybe_call_result_phi . is_none( ) ) ;
10111009 }
10121010 terminator =
10131011 Instruction :: new ( Op :: Branch , None , None , vec ! [ Operand :: IdRef ( return_jump) ] ) ;
0 commit comments