@@ -3669,6 +3669,84 @@ impl Function {
36693669 } )
36703670 }
36713671
3672+ fn clean_ssa ( & mut self ) {
3673+ let mut predecessors: HashMap < BlockId , HashSet < InsnId > > = HashMap :: new ( ) ;
3674+ let rpo = self . rpo ( ) ;
3675+ for & block in & rpo {
3676+ for & insn_id in & self . blocks [ block. 0 ] . insns {
3677+ // Instructions without output, including branch instructions, can't be targets of
3678+ // make_equal_to, so we don't need find() here.
3679+ match & self . insns [ insn_id. 0 ] {
3680+ Insn :: IfTrue { target, .. }
3681+ | Insn :: IfFalse { target, .. }
3682+ | Insn :: Jump ( target) => {
3683+ predecessors. entry ( target. target ) . or_default ( ) . insert ( insn_id) ;
3684+ }
3685+ // Entries does not pass block arguments
3686+ _ => { }
3687+ }
3688+ }
3689+ }
3690+
3691+ fn is_trivial ( out : InsnId , operands : & [ InsnId ] ) -> Option < InsnId > {
3692+ let mut same = None ;
3693+ for & op in operands {
3694+ if Some ( op) == same || op == out {
3695+ continue ; // Unique value or self-reference
3696+ }
3697+ if !same. is_none ( ) {
3698+ return None ; // Merges at least two values: not trivial
3699+ }
3700+ same = Some ( op) ;
3701+ }
3702+ same
3703+ }
3704+
3705+ let mut changed = true ;
3706+ while changed {
3707+ changed = false ;
3708+ for & block in & rpo {
3709+ let Some ( preds) = predecessors. get ( & block) else { continue ; } ;
3710+ let mut new_params = vec ! [ ] ;
3711+ let mut num_removed = 0 ;
3712+ for ( idx, & param) in self . blocks [ block. 0 ] . params . iter ( ) . enumerate ( ) {
3713+ let incoming = preds. iter ( ) . map ( |& pred_insn| {
3714+ // Instructions without output, including branch instructions, can't be targets of
3715+ // make_equal_to, so we don't need find() here.
3716+ match & self . insns [ pred_insn. 0 ] {
3717+ Insn :: IfTrue { target, .. }
3718+ | Insn :: IfFalse { target, .. }
3719+ | Insn :: Jump ( target) => {
3720+ self . union_find . borrow ( ) . find_const ( target. args [ idx - num_removed] )
3721+ }
3722+ _ => unreachable ! ( ) ,
3723+ }
3724+ } ) . collect :: < Vec < _ > > ( ) ;
3725+ if let Some ( same) = is_trivial ( param, & incoming) {
3726+ self . union_find . borrow_mut ( ) . make_equal_to ( param, same) ;
3727+ for & pred in preds {
3728+ match & mut self . insns [ pred. 0 ] {
3729+ Insn :: IfTrue { target, .. }
3730+ | Insn :: IfFalse { target, .. }
3731+ | Insn :: Jump ( target) => {
3732+ target. args . remove ( idx - num_removed) ;
3733+ }
3734+ _ => unreachable ! ( ) ,
3735+ }
3736+ }
3737+ num_removed += 1 ;
3738+ } else {
3739+ new_params. push ( param) ;
3740+ }
3741+ }
3742+ if num_removed > 0 {
3743+ self . blocks [ block. 0 ] . params = new_params;
3744+ changed = true ;
3745+ }
3746+ }
3747+ }
3748+ }
3749+
36723750 /// Rewrite eligible Send opcodes into SendDirect
36733751 /// opcodes if we know the target ISEQ statically. This removes run-time method lookups and
36743752 /// opens the door for inlining.
@@ -5932,6 +6010,7 @@ impl Function {
59326010 // End strength reduction bucket
59336011 ( optimize_load_store) => { Counter :: compile_hir_optimize_load_store_time_ns } ;
59346012 ( fold_constants) => { Counter :: compile_hir_fold_constants_time_ns } ;
6013+ ( clean_ssa) => { Counter :: compile_hir_clean_ssa_time_ns } ;
59356014 ( clean_cfg) => { Counter :: compile_hir_clean_cfg_time_ns } ;
59366015 ( remove_redundant_patch_points) => { Counter :: compile_hir_remove_redundant_patch_points_time_ns } ;
59376016 ( remove_duplicate_check_interrupts) => { Counter :: compile_hir_remove_duplicate_check_interrupts_time_ns } ;
@@ -5959,6 +6038,7 @@ impl Function {
59596038 }
59606039
59616040 // Function is assumed to have types inferred already
6041+ run_pass ! ( clean_ssa) ;
59626042 run_pass ! ( type_specialize) ;
59636043 run_pass ! ( inline) ;
59646044 run_pass ! ( optimize_getivar) ;
0 commit comments