@@ -89,7 +89,6 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> {
8989 header,
9090 debug_string_source : & mut module. debug_string_source ,
9191 annotations : & mut module. annotations ,
92- types_global_values : & mut module. types_global_values ,
9392
9493 legal_globals,
9594
@@ -488,7 +487,6 @@ struct Inliner<'a, 'b> {
488487 header : & ' b mut ModuleHeader ,
489488 debug_string_source : & ' b mut Vec < Instruction > ,
490489 annotations : & ' b mut Vec < Instruction > ,
491- types_global_values : & ' b mut Vec < Instruction > ,
492490
493491 legal_globals : FxHashMap < Word , LegalGlobal > ,
494492 functions_that_may_abort : FxHashSet < Word > ,
@@ -518,29 +516,6 @@ impl Inliner<'_, '_> {
518516 }
519517 }
520518
521- fn ptr_ty ( & mut self , pointee : Word ) -> Word {
522- // TODO: This is horribly slow, fix this
523- let existing = self . types_global_values . iter ( ) . find ( |inst| {
524- inst. class . opcode == Op :: TypePointer
525- && inst. operands [ 0 ] . unwrap_storage_class ( ) == StorageClass :: Function
526- && inst. operands [ 1 ] . unwrap_id_ref ( ) == pointee
527- } ) ;
528- if let Some ( existing) = existing {
529- return existing. result_id . unwrap ( ) ;
530- }
531- let inst_id = self . id ( ) ;
532- self . types_global_values . push ( Instruction :: new (
533- Op :: TypePointer ,
534- None ,
535- Some ( inst_id) ,
536- vec ! [
537- Operand :: StorageClass ( StorageClass :: Function ) ,
538- Operand :: IdRef ( pointee) ,
539- ] ,
540- ) ) ;
541- inst_id
542- }
543-
544519 fn inline_fn (
545520 & mut self ,
546521 function : & mut Function ,
@@ -617,15 +592,19 @@ impl Inliner<'_, '_> {
617592 . insert ( caller. def_id ( ) . unwrap ( ) ) ;
618593 }
619594
620- let call_result_type = {
595+ let mut maybe_call_result_phi = {
621596 let ty = call_inst. result_type . unwrap ( ) ;
622597 if ty == self . op_type_void_id {
623598 None
624599 } else {
625- Some ( ty)
600+ Some ( Instruction :: new (
601+ Op :: Phi ,
602+ Some ( ty) ,
603+ Some ( call_inst. result_id . unwrap ( ) ) ,
604+ vec ! [ ] ,
605+ ) )
626606 }
627607 } ;
628- let call_result_id = call_inst. result_id . unwrap ( ) ;
629608
630609 // Get the debug "source location" instruction that applies to the call.
631610 let custom_ext_inst_set_import = self . custom_ext_inst_set_import ;
@@ -662,17 +641,12 @@ impl Inliner<'_, '_> {
662641 } ) ;
663642 let mut rewrite_rules = callee_parameters. zip ( call_arguments) . collect ( ) ;
664643
665- let return_variable = if call_result_type. is_some ( ) {
666- Some ( self . id ( ) )
667- } else {
668- None
669- } ;
670644 let return_jump = self . id ( ) ;
671645 // Rewrite OpReturns of the callee.
672646 let mut inlined_callee_blocks = self . get_inlined_blocks (
673647 callee,
674648 call_debug_src_loc_inst,
675- return_variable ,
649+ maybe_call_result_phi . as_mut ( ) ,
676650 return_jump,
677651 ) ;
678652 // Clone the IDs of the callee, because otherwise they'd be defined multiple times if the
@@ -681,6 +655,55 @@ impl Inliner<'_, '_> {
681655 apply_rewrite_rules ( & rewrite_rules, & mut inlined_callee_blocks) ;
682656 self . apply_rewrite_for_decorations ( & rewrite_rules) ;
683657
658+ if let Some ( call_result_phi) = & mut maybe_call_result_phi {
659+ // HACK(eddyb) new IDs should be generated earlier, to avoid pushing
660+ // callee IDs to `call_result_phi.operands` only to rewrite them here.
661+ for op in & mut call_result_phi. operands {
662+ if let Some ( id) = op. id_ref_any_mut ( ) {
663+ if let Some ( & rewrite) = rewrite_rules. get ( id) {
664+ * id = rewrite;
665+ }
666+ }
667+ }
668+
669+ // HACK(eddyb) this special-casing of the single-return case is
670+ // really necessary for passes like `mem2reg` which are not capable
671+ // of skipping through the extraneous `OpPhi`s on their own.
672+ if let [ returned_value, _return_block] = & call_result_phi. operands [ ..] {
673+ let call_result_id = call_result_phi. result_id . unwrap ( ) ;
674+ let returned_value_id = returned_value. unwrap_id_ref ( ) ;
675+
676+ maybe_call_result_phi = None ;
677+
678+ // HACK(eddyb) this is a conservative approximation of all the
679+ // instructions that could potentially reference the call result.
680+ let reaching_insts = {
681+ let ( pre_call_blocks, call_and_post_call_blocks) =
682+ caller. blocks . split_at_mut ( block_idx) ;
683+ ( pre_call_blocks. iter_mut ( ) . flat_map ( |block| {
684+ block
685+ . instructions
686+ . iter_mut ( )
687+ . take_while ( |inst| inst. class . opcode == Op :: Phi )
688+ } ) )
689+ . chain (
690+ call_and_post_call_blocks
691+ . iter_mut ( )
692+ . flat_map ( |block| & mut block. instructions ) ,
693+ )
694+ } ;
695+ for reaching_inst in reaching_insts {
696+ for op in & mut reaching_inst. operands {
697+ if let Some ( id) = op. id_ref_any_mut ( ) {
698+ if * id == call_result_id {
699+ * id = returned_value_id;
700+ }
701+ }
702+ }
703+ }
704+ }
705+ }
706+
684707 // Split the block containing the `OpFunctionCall` into pre-call vs post-call.
685708 let pre_call_block_idx = block_idx;
686709 #[ expect( unused) ]
@@ -696,18 +719,6 @@ impl Inliner<'_, '_> {
696719 . unwrap ( ) ;
697720 assert ! ( call. class. opcode == Op :: FunctionCall ) ;
698721
699- if let Some ( call_result_type) = call_result_type {
700- // Generate the storage space for the return value: Do this *after* the split above,
701- // because if block_idx=0, inserting a variable here shifts call_index.
702- let ret_var_inst = Instruction :: new (
703- Op :: Variable ,
704- Some ( self . ptr_ty ( call_result_type) ) ,
705- Some ( return_variable. unwrap ( ) ) ,
706- vec ! [ Operand :: StorageClass ( StorageClass :: Function ) ] ,
707- ) ;
708- self . insert_opvariables ( & mut caller. blocks [ 0 ] , [ ret_var_inst] ) ;
709- }
710-
711722 // Insert non-entry inlined callee blocks just after the pre-call block.
712723 let non_entry_inlined_callee_blocks = inlined_callee_blocks. drain ( 1 ..) ;
713724 let num_non_entry_inlined_callee_blocks = non_entry_inlined_callee_blocks. len ( ) ;
@@ -716,18 +727,9 @@ impl Inliner<'_, '_> {
716727 non_entry_inlined_callee_blocks,
717728 ) ;
718729
719- if let Some ( call_result_type) = call_result_type {
720- // Add the load of the result value after the inlined function. Note there's guaranteed no
721- // OpPhi instructions since we just split this block.
722- post_call_block_insts. insert (
723- 0 ,
724- Instruction :: new (
725- Op :: Load ,
726- Some ( call_result_type) ,
727- Some ( call_result_id) ,
728- vec ! [ Operand :: IdRef ( return_variable. unwrap( ) ) ] ,
729- ) ,
730- ) ;
730+ if let Some ( call_result_phi) = maybe_call_result_phi {
731+ // Add the `OpPhi` for the call result value, after the inlined function.
732+ post_call_block_insts. insert ( 0 , call_result_phi) ;
731733 }
732734
733735 // Insert the post-call block, after all the inlined callee blocks.
@@ -894,7 +896,7 @@ impl Inliner<'_, '_> {
894896 & mut self ,
895897 callee : & Function ,
896898 call_debug_src_loc_inst : Option < & Instruction > ,
897- return_variable : Option < Word > ,
899+ mut maybe_call_result_phi : Option < & mut Instruction > ,
898900 return_jump : Word ,
899901 ) -> Vec < Block > {
900902 let Self {
@@ -990,14 +992,13 @@ impl Inliner<'_, '_> {
990992 if let Op :: Return | Op :: ReturnValue = terminator. class . opcode {
991993 if Op :: ReturnValue == terminator. class . opcode {
992994 let return_value = terminator. operands [ 0 ] . id_ref_any ( ) . unwrap ( ) ;
993- block
994- . instructions
995- . push ( Instruction :: new ( Op :: Store , None , None , vec ! [
996- Operand :: IdRef ( return_variable. unwrap( ) ) ,
997- Operand :: IdRef ( return_value) ,
998- ] ) ) ;
995+ let call_result_phi = maybe_call_result_phi. as_deref_mut ( ) . unwrap ( ) ;
996+ call_result_phi. operands . extend ( [
997+ Operand :: IdRef ( return_value) ,
998+ Operand :: IdRef ( block. label_id ( ) . unwrap ( ) ) ,
999+ ] ) ;
9991000 } else {
1000- assert ! ( return_variable . is_none( ) ) ;
1001+ assert ! ( maybe_call_result_phi . is_none( ) ) ;
10011002 }
10021003 terminator =
10031004 Instruction :: new ( Op :: Branch , None , None , vec ! [ Operand :: IdRef ( return_jump) ] ) ;
0 commit comments