@@ -94,7 +94,6 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> {
94
94
header,
95
95
debug_string_source : & mut module. debug_string_source ,
96
96
annotations : & mut module. annotations ,
97
- types_global_values : & mut module. types_global_values ,
98
97
99
98
legal_globals,
100
99
@@ -493,7 +492,6 @@ struct Inliner<'a, 'b> {
493
492
header : & ' b mut ModuleHeader ,
494
493
debug_string_source : & ' b mut Vec < Instruction > ,
495
494
annotations : & ' b mut Vec < Instruction > ,
496
- types_global_values : & ' b mut Vec < Instruction > ,
497
495
498
496
legal_globals : FxHashMap < Word , LegalGlobal > ,
499
497
functions_that_may_abort : FxHashSet < Word > ,
@@ -523,29 +521,6 @@ impl Inliner<'_, '_> {
523
521
}
524
522
}
525
523
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
-
549
524
fn inline_fn (
550
525
& mut self ,
551
526
function : & mut Function ,
@@ -622,15 +597,19 @@ impl Inliner<'_, '_> {
622
597
. insert ( caller. def_id ( ) . unwrap ( ) ) ;
623
598
}
624
599
625
- let call_result_type = {
600
+ let mut maybe_call_result_phi = {
626
601
let ty = call_inst. result_type . unwrap ( ) ;
627
602
if ty == self . op_type_void_id {
628
603
None
629
604
} else {
630
- Some ( ty)
605
+ Some ( Instruction :: new (
606
+ Op :: Phi ,
607
+ Some ( ty) ,
608
+ Some ( call_inst. result_id . unwrap ( ) ) ,
609
+ vec ! [ ] ,
610
+ ) )
631
611
}
632
612
} ;
633
- let call_result_id = call_inst. result_id . unwrap ( ) ;
634
613
635
614
// Get the debug "source location" instruction that applies to the call.
636
615
let custom_ext_inst_set_import = self . custom_ext_inst_set_import ;
@@ -667,17 +646,12 @@ impl Inliner<'_, '_> {
667
646
} ) ;
668
647
let mut rewrite_rules = callee_parameters. zip ( call_arguments) . collect ( ) ;
669
648
670
- let return_variable = if call_result_type. is_some ( ) {
671
- Some ( self . id ( ) )
672
- } else {
673
- None
674
- } ;
675
649
let return_jump = self . id ( ) ;
676
650
// Rewrite OpReturns of the callee.
677
651
let mut inlined_callee_blocks = self . get_inlined_blocks (
678
652
callee,
679
653
call_debug_src_loc_inst,
680
- return_variable ,
654
+ maybe_call_result_phi . as_mut ( ) ,
681
655
return_jump,
682
656
) ;
683
657
// Clone the IDs of the callee, because otherwise they'd be defined multiple times if the
@@ -686,6 +660,55 @@ impl Inliner<'_, '_> {
686
660
apply_rewrite_rules ( & rewrite_rules, & mut inlined_callee_blocks) ;
687
661
self . apply_rewrite_for_decorations ( & rewrite_rules) ;
688
662
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
+
689
712
// Split the block containing the `OpFunctionCall` into pre-call vs post-call.
690
713
let pre_call_block_idx = block_idx;
691
714
#[ expect( unused) ]
@@ -701,18 +724,6 @@ impl Inliner<'_, '_> {
701
724
. unwrap ( ) ;
702
725
assert ! ( call. class. opcode == Op :: FunctionCall ) ;
703
726
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
-
716
727
// Insert non-entry inlined callee blocks just after the pre-call block.
717
728
let non_entry_inlined_callee_blocks = inlined_callee_blocks. drain ( 1 ..) ;
718
729
let num_non_entry_inlined_callee_blocks = non_entry_inlined_callee_blocks. len ( ) ;
@@ -721,18 +732,9 @@ impl Inliner<'_, '_> {
721
732
non_entry_inlined_callee_blocks,
722
733
) ;
723
734
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) ;
736
738
}
737
739
738
740
// Insert the post-call block, after all the inlined callee blocks.
@@ -899,7 +901,7 @@ impl Inliner<'_, '_> {
899
901
& mut self ,
900
902
callee : & Function ,
901
903
call_debug_src_loc_inst : Option < & Instruction > ,
902
- return_variable : Option < Word > ,
904
+ mut maybe_call_result_phi : Option < & mut Instruction > ,
903
905
return_jump : Word ,
904
906
) -> Vec < Block > {
905
907
let Self {
@@ -997,17 +999,13 @@ impl Inliner<'_, '_> {
997
999
if let Op :: Return | Op :: ReturnValue = terminator. class . opcode {
998
1000
if Op :: ReturnValue == terminator. class . opcode {
999
1001
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
+ ] ) ;
1009
1007
} else {
1010
- assert ! ( return_variable . is_none( ) ) ;
1008
+ assert ! ( maybe_call_result_phi . is_none( ) ) ;
1011
1009
}
1012
1010
terminator =
1013
1011
Instruction :: new ( Op :: Branch , None , None , vec ! [ Operand :: IdRef ( return_jump) ] ) ;
0 commit comments