Skip to content

Commit 0b0011c

Browse files
committed
CopyProp: Propagate moves of constants
1 parent 6cc4843 commit 0b0011c

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

compiler/rustc_mir_transform/src/copy_prop.rs

Lines changed: 29 additions & 2 deletions
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() {
@@ -51,6 +54,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
5154
tcx,
5255
copy_classes: ssa.copy_classes(),
5356
fully_moved,
57+
const_locals,
5458
borrowed_locals,
5559
storage_to_remove,
5660
}
@@ -96,10 +100,28 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
96100
fully_moved
97101
}
98102

103+
/// Finds all locals that are only assigned to once with a deterministic constant
104+
#[instrument(level = "trace", skip(ssa, body))]
105+
fn const_locals<'body, 'tcx>(
106+
ssa: &'body SsaLocals,
107+
body: &'body Body<'tcx>,
108+
) -> FxIndexMap<Local, ConstOperand<'tcx>> {
109+
let mut const_locals = FxIndexMap::default();
110+
for (local, rvalue, _) in ssa.assignments(body) {
111+
let Rvalue::Use(Operand::Constant(val)) = rvalue else { continue };
112+
if !val.const_.is_deterministic() {
113+
continue;
114+
}
115+
const_locals.insert(local, **val);
116+
}
117+
const_locals
118+
}
119+
99120
/// Utility to help performing substitution of `*pattern` by `target`.
100121
struct Replacer<'a, 'tcx> {
101122
tcx: TyCtxt<'tcx>,
102123
fully_moved: BitSet<Local>,
124+
const_locals: FxIndexMap<Local, ConstOperand<'tcx>>,
103125
storage_to_remove: BitSet<Local>,
104126
borrowed_locals: BitSet<Local>,
105127
copy_classes: &'a IndexSlice<Local, Local>,
@@ -154,9 +176,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
154176
if let Operand::Move(place) = *operand
155177
// A move out of a projection of a copy is equivalent to a copy of the original projection.
156178
&& !place.is_indirect_first_projection()
157-
&& !self.fully_moved.contains(place.local)
158179
{
159-
*operand = Operand::Copy(place);
180+
if !self.fully_moved.contains(place.local) {
181+
*operand = Operand::Copy(place);
182+
} else if let Some(local) = place.as_local()
183+
&& let Some(val) = self.const_locals.get(&local)
184+
{
185+
*operand = Operand::Constant(Box::new(*val))
186+
}
160187
}
161188
self.super_operand(operand, loc);
162189
}

0 commit comments

Comments
 (0)