@@ -38,114 +38,111 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
3838 }
3939
4040 let mut def_use_analysis = DefUseAnalysis :: new ( body) ;
41- loop {
42- def_use_analysis. analyze ( body) ;
41+ let mut changed = true ;
4342
44- if eliminate_self_assignments ( body, & def_use_analysis) {
43+ for dest_local in body. local_decls . indices ( ) {
44+ if changed {
4545 def_use_analysis. analyze ( body) ;
46+ if eliminate_self_assignments ( body, & def_use_analysis) {
47+ def_use_analysis. analyze ( body) ;
48+ }
49+ changed = false ;
4650 }
4751
48- let mut changed = false ;
49- for dest_local in body. local_decls . indices ( ) {
50- debug ! ( "considering destination local: {:?}" , dest_local) ;
51-
52- let action;
53- let location;
54- {
55- // The destination must have exactly one def.
56- let dest_use_info = def_use_analysis. local_info ( dest_local) ;
57- let dest_def_count = dest_use_info. def_count_not_including_drop ( ) ;
58- if dest_def_count == 0 {
59- debug ! ( " Can't copy-propagate local: dest {:?} undefined" , dest_local) ;
60- continue ;
61- }
62- if dest_def_count > 1 {
63- debug ! (
64- " Can't copy-propagate local: dest {:?} defined {} times" ,
65- dest_local,
66- dest_use_info. def_count( )
67- ) ;
68- continue ;
69- }
70- if dest_use_info. use_count ( ) == 0 {
71- debug ! ( " Can't copy-propagate local: dest {:?} unused" , dest_local) ;
72- continue ;
73- }
74- // Conservatively gives up if the dest is an argument,
75- // because there may be uses of the original argument value.
76- // Also gives up on the return place, as we cannot propagate into its implicit
77- // use by `return`.
78- if matches ! (
79- body. local_kind( dest_local) ,
80- LocalKind :: Arg | LocalKind :: ReturnPointer
81- ) {
82- debug ! ( " Can't copy-propagate local: dest {:?} (argument)" , dest_local) ;
52+ debug ! ( "considering destination local: {:?}" , dest_local) ;
53+
54+ let action;
55+ let location;
56+ {
57+ // The destination must have exactly one def.
58+ let dest_use_info = def_use_analysis. local_info ( dest_local) ;
59+ let dest_def_count = dest_use_info. def_count_not_including_drop ( ) ;
60+ if dest_def_count == 0 {
61+ debug ! ( " Can't copy-propagate local: dest {:?} undefined" , dest_local) ;
62+ continue ;
63+ }
64+ if dest_def_count > 1 {
65+ debug ! (
66+ " Can't copy-propagate local: dest {:?} defined {} times" ,
67+ dest_local,
68+ dest_use_info. def_count( )
69+ ) ;
70+ continue ;
71+ }
72+ if dest_use_info. use_count ( ) == 0 {
73+ debug ! ( " Can't copy-propagate local: dest {:?} unused" , dest_local) ;
74+ continue ;
75+ }
76+ // Conservatively gives up if the dest is an argument,
77+ // because there may be uses of the original argument value.
78+ // Also gives up on the return place, as we cannot propagate into its implicit
79+ // use by `return`.
80+ if matches ! (
81+ body. local_kind( dest_local) ,
82+ LocalKind :: Arg | LocalKind :: ReturnPointer
83+ ) {
84+ debug ! ( " Can't copy-propagate local: dest {:?} (argument)" , dest_local) ;
85+ continue ;
86+ }
87+ let dest_place_def = dest_use_info. defs_not_including_drop ( ) . next ( ) . unwrap ( ) ;
88+ location = dest_place_def. location ;
89+
90+ let basic_block = & body[ location. block ] ;
91+ let statement_index = location. statement_index ;
92+ let statement = match basic_block. statements . get ( statement_index) {
93+ Some ( statement) => statement,
94+ None => {
95+ debug ! ( " Can't copy-propagate local: used in terminator" ) ;
8396 continue ;
8497 }
85- let dest_place_def = dest_use_info. defs_not_including_drop ( ) . next ( ) . unwrap ( ) ;
86- location = dest_place_def. location ;
87-
88- let basic_block = & body[ location. block ] ;
89- let statement_index = location. statement_index ;
90- let statement = match basic_block. statements . get ( statement_index) {
91- Some ( statement) => statement,
92- None => {
93- debug ! ( " Can't copy-propagate local: used in terminator" ) ;
94- continue ;
95- }
96- } ;
97-
98- // That use of the source must be an assignment.
99- match & statement. kind {
100- StatementKind :: Assign ( box ( place, Rvalue :: Use ( operand) ) ) => {
101- if let Some ( local) = place. as_local ( ) {
102- if local == dest_local {
103- let maybe_action = match operand {
104- Operand :: Copy ( src_place) | Operand :: Move ( src_place) => {
105- Action :: local_copy ( & body, & def_use_analysis, * src_place)
106- }
107- Operand :: Constant ( ref src_constant) => {
108- Action :: constant ( src_constant)
109- }
110- } ;
111- match maybe_action {
112- Some ( this_action) => action = this_action,
113- None => continue ,
98+ } ;
99+
100+ // That use of the source must be an assignment.
101+ match & statement. kind {
102+ StatementKind :: Assign ( box ( place, Rvalue :: Use ( operand) ) ) => {
103+ if let Some ( local) = place. as_local ( ) {
104+ if local == dest_local {
105+ let maybe_action = match operand {
106+ Operand :: Copy ( src_place) | Operand :: Move ( src_place) => {
107+ Action :: local_copy ( & body, & def_use_analysis, * src_place)
114108 }
115- } else {
116- debug ! (
117- " Can't copy-propagate local: source use is not an \
118- assignment"
119- ) ;
120- continue ;
109+ Operand :: Constant ( ref src_constant) => {
110+ Action :: constant ( src_constant)
111+ }
112+ } ;
113+ match maybe_action {
114+ Some ( this_action) => action = this_action,
115+ None => continue ,
121116 }
122117 } else {
123118 debug ! (
124119 " Can't copy-propagate local: source use is not an \
125- assignment"
120+ assignment"
126121 ) ;
127122 continue ;
128123 }
129- }
130- _ => {
124+ } else {
131125 debug ! (
132126 " Can't copy-propagate local: source use is not an \
133- assignment"
127+ assignment"
134128 ) ;
135129 continue ;
136130 }
137131 }
132+ _ => {
133+ debug ! (
134+ " Can't copy-propagate local: source use is not an \
135+ assignment"
136+ ) ;
137+ continue ;
138+ }
138139 }
139-
140- changed =
141- action. perform ( body, & def_use_analysis, dest_local, location, tcx) || changed;
142- // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of
143- // regenerating the chains.
144- break ;
145- }
146- if !changed {
147- break ;
148140 }
141+
142+ // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of
143+ // regenerating the chains.
144+ action. perform ( body, & def_use_analysis, dest_local, location, tcx) ;
145+ changed = true ;
149146 }
150147 }
151148}
0 commit comments