@@ -89,7 +89,6 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> {
89
89
header,
90
90
debug_string_source : & mut module. debug_string_source ,
91
91
annotations : & mut module. annotations ,
92
- types_global_values : & mut module. types_global_values ,
93
92
94
93
legal_globals,
95
94
@@ -488,7 +487,6 @@ struct Inliner<'a, 'b> {
488
487
header : & ' b mut ModuleHeader ,
489
488
debug_string_source : & ' b mut Vec < Instruction > ,
490
489
annotations : & ' b mut Vec < Instruction > ,
491
- types_global_values : & ' b mut Vec < Instruction > ,
492
490
493
491
legal_globals : FxHashMap < Word , LegalGlobal > ,
494
492
functions_that_may_abort : FxHashSet < Word > ,
@@ -518,29 +516,6 @@ impl Inliner<'_, '_> {
518
516
}
519
517
}
520
518
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
-
544
519
fn inline_fn (
545
520
& mut self ,
546
521
function : & mut Function ,
@@ -617,15 +592,19 @@ impl Inliner<'_, '_> {
617
592
. insert ( caller. def_id ( ) . unwrap ( ) ) ;
618
593
}
619
594
620
- let call_result_type = {
595
+ let mut maybe_call_result_phi = {
621
596
let ty = call_inst. result_type . unwrap ( ) ;
622
597
if ty == self . op_type_void_id {
623
598
None
624
599
} else {
625
- Some ( ty)
600
+ Some ( Instruction :: new (
601
+ Op :: Phi ,
602
+ Some ( ty) ,
603
+ Some ( call_inst. result_id . unwrap ( ) ) ,
604
+ vec ! [ ] ,
605
+ ) )
626
606
}
627
607
} ;
628
- let call_result_id = call_inst. result_id . unwrap ( ) ;
629
608
630
609
// Get the debug "source location" instruction that applies to the call.
631
610
let custom_ext_inst_set_import = self . custom_ext_inst_set_import ;
@@ -662,17 +641,12 @@ impl Inliner<'_, '_> {
662
641
} ) ;
663
642
let mut rewrite_rules = callee_parameters. zip ( call_arguments) . collect ( ) ;
664
643
665
- let return_variable = if call_result_type. is_some ( ) {
666
- Some ( self . id ( ) )
667
- } else {
668
- None
669
- } ;
670
644
let return_jump = self . id ( ) ;
671
645
// Rewrite OpReturns of the callee.
672
646
let mut inlined_callee_blocks = self . get_inlined_blocks (
673
647
callee,
674
648
call_debug_src_loc_inst,
675
- return_variable ,
649
+ maybe_call_result_phi . as_mut ( ) ,
676
650
return_jump,
677
651
) ;
678
652
// Clone the IDs of the callee, because otherwise they'd be defined multiple times if the
@@ -681,6 +655,55 @@ impl Inliner<'_, '_> {
681
655
apply_rewrite_rules ( & rewrite_rules, & mut inlined_callee_blocks) ;
682
656
self . apply_rewrite_for_decorations ( & rewrite_rules) ;
683
657
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
+
684
707
// Split the block containing the `OpFunctionCall` into pre-call vs post-call.
685
708
let pre_call_block_idx = block_idx;
686
709
#[ expect( unused) ]
@@ -696,18 +719,6 @@ impl Inliner<'_, '_> {
696
719
. unwrap ( ) ;
697
720
assert ! ( call. class. opcode == Op :: FunctionCall ) ;
698
721
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
-
711
722
// Insert non-entry inlined callee blocks just after the pre-call block.
712
723
let non_entry_inlined_callee_blocks = inlined_callee_blocks. drain ( 1 ..) ;
713
724
let num_non_entry_inlined_callee_blocks = non_entry_inlined_callee_blocks. len ( ) ;
@@ -716,18 +727,9 @@ impl Inliner<'_, '_> {
716
727
non_entry_inlined_callee_blocks,
717
728
) ;
718
729
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) ;
731
733
}
732
734
733
735
// Insert the post-call block, after all the inlined callee blocks.
@@ -894,7 +896,7 @@ impl Inliner<'_, '_> {
894
896
& mut self ,
895
897
callee : & Function ,
896
898
call_debug_src_loc_inst : Option < & Instruction > ,
897
- return_variable : Option < Word > ,
899
+ mut maybe_call_result_phi : Option < & mut Instruction > ,
898
900
return_jump : Word ,
899
901
) -> Vec < Block > {
900
902
let Self {
@@ -990,14 +992,13 @@ impl Inliner<'_, '_> {
990
992
if let Op :: Return | Op :: ReturnValue = terminator. class . opcode {
991
993
if Op :: ReturnValue == terminator. class . opcode {
992
994
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
+ ] ) ;
999
1000
} else {
1000
- assert ! ( return_variable . is_none( ) ) ;
1001
+ assert ! ( maybe_call_result_phi . is_none( ) ) ;
1001
1002
}
1002
1003
terminator =
1003
1004
Instruction :: new ( Op :: Branch , None , None , vec ! [ Operand :: IdRef ( return_jump) ] ) ;
0 commit comments