@@ -38,114 +38,111 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
38
38
}
39
39
40
40
let mut def_use_analysis = DefUseAnalysis :: new ( body) ;
41
- loop {
42
- def_use_analysis. analyze ( body) ;
41
+ let mut changed = true ;
43
42
44
- if eliminate_self_assignments ( body, & def_use_analysis) {
43
+ for dest_local in body. local_decls . indices ( ) {
44
+ if changed {
45
45
def_use_analysis. analyze ( body) ;
46
+ if eliminate_self_assignments ( body, & def_use_analysis) {
47
+ def_use_analysis. analyze ( body) ;
48
+ }
49
+ changed = false ;
46
50
}
47
51
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" ) ;
83
96
continue ;
84
97
}
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)
114
108
}
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 ,
121
116
}
122
117
} else {
123
118
debug ! (
124
119
" Can't copy-propagate local: source use is not an \
125
- assignment"
120
+ assignment"
126
121
) ;
127
122
continue ;
128
123
}
129
- }
130
- _ => {
124
+ } else {
131
125
debug ! (
132
126
" Can't copy-propagate local: source use is not an \
133
- assignment"
127
+ assignment"
134
128
) ;
135
129
continue ;
136
130
}
137
131
}
132
+ _ => {
133
+ debug ! (
134
+ " Can't copy-propagate local: source use is not an \
135
+ assignment"
136
+ ) ;
137
+ continue ;
138
+ }
138
139
}
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 ;
148
140
}
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 ;
149
146
}
150
147
}
151
148
}
0 commit comments