@@ -217,6 +217,17 @@ impl SsaCopyFlow {
217217 value
218218 }
219219
220+ fn omitted_source ( & self , mut value : SsaVar ) -> SsaVar {
221+ let mut visited = BTreeSet :: new ( ) ;
222+ while self . omitted . contains ( & value) && visited. insert ( value) {
223+ let Some ( source) = self . sources . get ( & value) . copied ( ) else {
224+ break ;
225+ } ;
226+ value = source;
227+ }
228+ value
229+ }
230+
220231 fn argument ( & self , value : SsaVar ) -> InsnArg {
221232 InsnArg :: reg_ssa (
222233 value. reg_num ,
@@ -431,9 +442,14 @@ impl<'ir> ValueFlowGraph<'ir> {
431442 } ;
432443 for input in & phi. inputs {
433444 self . retained_phi_inputs . insert ( input. value ) ;
445+ let source = self . copies . omitted_source ( input. value ) ;
446+ self . retained_phi_inputs . insert ( source) ;
434447 if excluded. contains_key ( & input. value ) {
435448 pending. push ( input. value ) ;
436449 }
450+ if source != input. value && excluded. contains_key ( & source) {
451+ pending. push ( source) ;
452+ }
437453 }
438454 }
439455 self . phis . retain ( |phi| !recovered. contains ( & phi. result ) ) ;
@@ -800,35 +816,52 @@ impl<'ir> ValueFlowGraph<'ir> {
800816 }
801817
802818 fn required_phi_inputs ( & self ) -> BTreeSet < SsaVar > {
803- let phis = self
804- . phis
805- . iter ( )
806- . map ( |phi| ( phi. result , phi) )
807- . collect :: < BTreeMap < _ , _ > > ( ) ;
808- let mut pending = self
819+ let pending = self
809820 . phis
810821 . iter ( )
811822 . filter ( |phi| self . has_reaching_use ( phi. result ) )
812823 . map ( |phi| phi. result )
813824 . collect :: < Vec < _ > > ( ) ;
814- let mut required = self . retained_phi_inputs . clone ( ) ;
815- let mut visited = BTreeSet :: new ( ) ;
816- while let Some ( result) = pending. pop ( ) {
817- if !visited. insert ( result) {
818- continue ;
825+ required_phi_input_closure (
826+ & self . phis ,
827+ & self . copies ,
828+ pending,
829+ self . retained_phi_inputs . clone ( ) ,
830+ )
831+ }
832+ }
833+
834+ fn required_phi_input_closure (
835+ phis : & [ PhiMerge ] ,
836+ copies : & SsaCopyFlow ,
837+ mut pending : Vec < SsaVar > ,
838+ mut required : BTreeSet < SsaVar > ,
839+ ) -> BTreeSet < SsaVar > {
840+ let phis = phis
841+ . iter ( )
842+ . map ( |phi| ( phi. result , phi) )
843+ . collect :: < BTreeMap < _ , _ > > ( ) ;
844+ let mut visited = BTreeSet :: new ( ) ;
845+ while let Some ( result) = pending. pop ( ) {
846+ if !visited. insert ( result) {
847+ continue ;
848+ }
849+ let Some ( phi) = phis. get ( & result) else {
850+ continue ;
851+ } ;
852+ for input in & phi. inputs {
853+ required. insert ( input. value ) ;
854+ let source = copies. omitted_source ( input. value ) ;
855+ required. insert ( source) ;
856+ if phis. contains_key ( & input. value ) {
857+ pending. push ( input. value ) ;
819858 }
820- let Some ( phi) = phis. get ( & result) else {
821- continue ;
822- } ;
823- for input in & phi. inputs {
824- required. insert ( input. value ) ;
825- if phis. contains_key ( & input. value ) {
826- pending. push ( input. value ) ;
827- }
859+ if source != input. value && phis. contains_key ( & source) {
860+ pending. push ( source) ;
828861 }
829862 }
830- required
831863 }
864+ required
832865}
833866
834867#[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
@@ -875,8 +908,10 @@ impl SemanticVisitor for ControlSymbolClosure {
875908#[ cfg( test) ]
876909mod tests {
877910 use super :: * ;
911+ use crate :: ir:: analysis:: PhiInput ;
878912 use crate :: ir:: {
879- InsnNode , InsnType , InstructionId , RegionId , SemanticCatch , SemanticExpression ,
913+ BlockId , EdgeKind , InsnNode , InsnType , InstructionId , RegionId , SemanticCatch ,
914+ SemanticExpression ,
880915 } ;
881916
882917 fn operation (
@@ -945,4 +980,38 @@ mod tests {
945980
946981 assert ! ( graph. is_bound( binding) ) ;
947982 }
983+
984+ #[ test]
985+ fn required_phi_inputs_retain_transitive_copy_sources ( ) {
986+ let headers = SsaVar :: new ( 12 , 1 ) ;
987+ let handler_copy = SsaVar :: new ( 13 , 3 ) ;
988+ let null = SsaVar :: new ( 13 , 0 ) ;
989+ let merged = SsaVar :: new ( 13 , 4 ) ;
990+ let phis = vec ! [ PhiMerge {
991+ block: BlockId :: new( 113 ) ,
992+ instruction: InstructionId :: new( 200 ) ,
993+ result: merged,
994+ inputs: vec![
995+ PhiInput {
996+ predecessor: BlockId :: new( 108 ) ,
997+ edge_kind: EdgeKind :: Normal ,
998+ value: handler_copy,
999+ } ,
1000+ PhiInput {
1001+ predecessor: BlockId :: new( 110 ) ,
1002+ edge_kind: EdgeKind :: Normal ,
1003+ value: null,
1004+ } ,
1005+ ] ,
1006+ } ] ;
1007+ let mut copies = SsaCopyFlow :: default ( ) ;
1008+ copies. sources . insert ( handler_copy, headers) ;
1009+ copies. omitted . insert ( handler_copy) ;
1010+
1011+ let required = required_phi_input_closure ( & phis, & copies, vec ! [ merged] , BTreeSet :: new ( ) ) ;
1012+
1013+ assert ! ( required. contains( & handler_copy) ) ;
1014+ assert ! ( required. contains( & headers) ) ;
1015+ assert ! ( required. contains( & null) ) ;
1016+ }
9481017}
0 commit comments