Skip to content

Commit 2ee57d7

Browse files
committed
copy-prop: Attempt to propagate each local only once
The copy propagation as currently implemented does not introduce new copy propagation opportunities. Examine each local for possible optimization only once. Additionally, this also fixes the issue where copy propagation optimization would stop without examining all locals after failing to completely propagate a constant.
1 parent 63f3dce commit 2ee57d7

File tree

2 files changed

+127
-108
lines changed

2 files changed

+127
-108
lines changed

compiler/rustc_mir/src/transform/copy_prop.rs

+83-86
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)