Skip to content

Commit 1515cb7

Browse files
committed
Auto merge of #120689 - clubby789:copy-prop-consts, r=<try>
CopyProp: Propagate moves of constants Yet another try of #120650 - this time, keep track of SSA locals with a constant value and propagate it. Then, re-run `SimplifyConstCondition` to take advantage of it (simply reordering the pass regressed some tests). r? `@ghost`
2 parents 63f70b3 + cf02fa9 commit 1515cb7

File tree

1 file changed

+33
-13
lines changed

1 file changed

+33
-13
lines changed

compiler/rustc_mir_transform/src/copy_prop.rs

+33-13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_data_structures::fx::FxIndexMap;
12
use rustc_index::bit_set::BitSet;
23
use rustc_index::IndexSlice;
34
use rustc_middle::mir::visit::*;
@@ -37,6 +38,8 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
3738

3839
let fully_moved = fully_moved_locals(&ssa, body);
3940
debug!(?fully_moved);
41+
let const_locals = const_locals(&ssa, body);
42+
debug!(?const_locals);
4043

4144
let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size());
4245
for (local, &head) in ssa.copy_classes().iter_enumerated() {
@@ -45,12 +48,13 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
4548
}
4649
}
4750

48-
let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h);
51+
let any_replacement = !storage_to_remove.is_empty() || !const_locals.is_empty();
4952

5053
Replacer {
5154
tcx,
5255
copy_classes: ssa.copy_classes(),
5356
fully_moved,
57+
const_locals,
5458
borrowed_locals,
5559
storage_to_remove,
5660
}
@@ -75,31 +79,44 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
7579
let mut fully_moved = BitSet::new_filled(body.local_decls.len());
7680

7781
for (_, rvalue, _) in ssa.assignments(body) {
78-
let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
79-
| Rvalue::CopyForDeref(place)) = rvalue
80-
else {
82+
let (Rvalue::Use(Operand::Copy(place)) | Rvalue::CopyForDeref(place)) = rvalue else {
8183
continue;
8284
};
8385

8486
let Some(rhs) = place.as_local() else { continue };
8587
if !ssa.is_ssa(rhs) {
8688
continue;
8789
}
88-
89-
if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue {
90-
fully_moved.remove(rhs);
91-
}
90+
fully_moved.remove(rhs);
9291
}
9392

9493
ssa.meet_copy_equivalence(&mut fully_moved);
9594

9695
fully_moved
9796
}
9897

98+
/// Finds all locals that are only assigned to once with a deterministic constant
99+
#[instrument(level = "trace", skip(ssa, body))]
100+
fn const_locals<'body, 'tcx>(
101+
ssa: &'body SsaLocals,
102+
body: &'body Body<'tcx>,
103+
) -> FxIndexMap<Local, ConstOperand<'tcx>> {
104+
let mut const_locals = FxIndexMap::default();
105+
for (local, rvalue, _) in ssa.assignments(body) {
106+
let Rvalue::Use(Operand::Constant(val)) = rvalue else { continue };
107+
if !val.const_.is_deterministic() {
108+
continue;
109+
}
110+
const_locals.insert(local, **val);
111+
}
112+
const_locals
113+
}
114+
99115
/// Utility to help performing substitution of `*pattern` by `target`.
100116
struct Replacer<'a, 'tcx> {
101117
tcx: TyCtxt<'tcx>,
102118
fully_moved: BitSet<Local>,
119+
const_locals: FxIndexMap<Local, ConstOperand<'tcx>>,
103120
storage_to_remove: BitSet<Local>,
104121
borrowed_locals: BitSet<Local>,
105122
copy_classes: &'a IndexSlice<Local, Local>,
@@ -151,12 +168,15 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
151168
}
152169

153170
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
154-
if let Operand::Move(place) = *operand
171+
if let Operand::Move(place) = *operand {
155172
// A move out of a projection of a copy is equivalent to a copy of the original projection.
156-
&& !place.is_indirect_first_projection()
157-
&& !self.fully_moved.contains(place.local)
158-
{
159-
*operand = Operand::Copy(place);
173+
if !place.is_indirect_first_projection() && !self.fully_moved.contains(place.local) {
174+
*operand = Operand::Copy(place);
175+
} else if let Some(local) = place.as_local()
176+
&& let Some(val) = self.const_locals.get(&local)
177+
{
178+
*operand = Operand::Constant(Box::new(*val))
179+
}
160180
}
161181
self.super_operand(operand, loc);
162182
}

0 commit comments

Comments
 (0)