Skip to content

Commit 5f9d64d

Browse files
committed
Embed simplification into VnState.
1 parent 3311536 commit 5f9d64d

9 files changed

+136
-101
lines changed

compiler/rustc_mir_transform/src/gvn.rs

+94-77
Original file line numberDiff line numberDiff line change
@@ -86,46 +86,37 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
8686
// Clone dominators as we need them while mutating the body.
8787
let dominators = body.basic_blocks.dominators().clone();
8888

89-
let mut state = VnState::new(tcx, param_env, &body.local_decls);
89+
let mut state = VnState::new(tcx, param_env, &ssa, &dominators, &body.local_decls);
9090
for arg in body.args_iter() {
9191
if ssa.is_ssa(arg) {
9292
let value = state.new_opaque().unwrap();
9393
state.assign(arg, value);
9494
}
9595
}
9696

97-
for (local, rvalue, _) in ssa.assignments(body) {
98-
let value = state.insert_rvalue(rvalue).or_else(|| state.new_opaque()).unwrap();
97+
ssa.for_each_assignment_mut(&mut body.basic_blocks, |local, rvalue, location| {
98+
let value = state.simplify_rvalue(rvalue, location).or_else(|| state.new_opaque()).unwrap();
9999
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as
100100
// reusable if we have an exact type match.
101101
if state.local_decls[local].ty == rvalue.ty(state.local_decls, tcx) {
102102
state.assign(local, value);
103103
}
104-
}
104+
});
105105

106106
// Stop creating opaques during replacement as it is useless.
107107
state.next_opaque = None;
108108

109-
let mut any_replacement = false;
110-
let mut replacer = Replacer {
111-
tcx,
112-
ssa,
113-
dominators,
114-
state,
115-
reused_locals: BitSet::new_empty(body.local_decls.len()),
116-
any_replacement: &mut any_replacement,
117-
};
118-
119109
let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
120110
for bb in reverse_postorder {
121111
let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
122-
replacer.visit_basic_block_data(bb, data);
112+
state.visit_basic_block_data(bb, data);
123113
}
114+
let any_replacement = state.any_replacement;
124115

125116
// For each local that is reused (`y` above), we remove its storage statements do avoid any
126117
// difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage
127118
// statements.
128-
StorageRemover { tcx, reused_locals: replacer.reused_locals }.visit_body_preserves_cfg(body);
119+
StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body);
129120

130121
if any_replacement {
131122
crate::simplify::remove_unused_definitions(body);
@@ -189,12 +180,18 @@ struct VnState<'body, 'tcx> {
189180
/// Counter to generate different values.
190181
/// This is an option to stop creating opaques during replacement.
191182
next_opaque: Option<usize>,
183+
ssa: &'body SsaLocals,
184+
dominators: &'body Dominators<BasicBlock>,
185+
reused_locals: BitSet<Local>,
186+
any_replacement: bool,
192187
}
193188

194189
impl<'body, 'tcx> VnState<'body, 'tcx> {
195190
fn new(
196191
tcx: TyCtxt<'tcx>,
197192
param_env: ty::ParamEnv<'tcx>,
193+
ssa: &'body SsaLocals,
194+
dominators: &'body Dominators<BasicBlock>,
198195
local_decls: &'body LocalDecls<'tcx>,
199196
) -> Self {
200197
VnState {
@@ -205,6 +202,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
205202
rev_locals: FxHashMap::default(),
206203
values: FxIndexSet::default(),
207204
next_opaque: Some(0),
205+
ssa,
206+
dominators,
207+
reused_locals: BitSet::new_empty(local_decls.len()),
208+
any_replacement: false,
208209
}
209210
}
210211

@@ -252,10 +253,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
252253

253254
/// Represent the *value* which would be read from `place`.
254255
#[instrument(level = "trace", skip(self), ret)]
255-
fn insert_place(&mut self, place: Place<'tcx>) -> Option<VnIndex> {
256+
fn simplify_place(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
257+
// Another place that holds the same value.
258+
let mut place_ref = place.as_ref();
256259
let mut value = self.locals[place.local]?;
257260

258261
for (index, proj) in place.projection.iter().enumerate() {
262+
if let Some(local) = self.try_as_local(value, location) {
263+
place_ref = PlaceRef { local, projection: &place.projection[index..] };
264+
}
265+
259266
let proj = match proj {
260267
ProjectionElem::Deref => {
261268
let ty = Place::ty_from(
@@ -293,31 +300,65 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
293300
value = self.insert(Value::Projection(value, proj));
294301
}
295302

303+
if let Some(local) = self.try_as_local(value, location)
304+
&& local != place.local
305+
{
306+
*place = local.into();
307+
self.reused_locals.insert(local);
308+
self.any_replacement = true;
309+
} else if place_ref.local != place.local
310+
|| place_ref.projection.len() < place.projection.len()
311+
{
312+
*place = place_ref.project_deeper(&[], self.tcx);
313+
self.reused_locals.insert(place_ref.local);
314+
self.any_replacement = true;
315+
}
316+
296317
Some(value)
297318
}
298319

299320
#[instrument(level = "trace", skip(self), ret)]
300-
fn insert_operand(&mut self, operand: &Operand<'tcx>) -> Option<VnIndex> {
321+
fn simplify_operand(
322+
&mut self,
323+
operand: &mut Operand<'tcx>,
324+
location: Location,
325+
) -> Option<VnIndex> {
301326
match *operand {
302327
Operand::Constant(ref constant) => Some(self.insert(Value::Constant(constant.const_))),
303-
Operand::Copy(place) | Operand::Move(place) => self.insert_place(place),
328+
Operand::Copy(ref mut place) | Operand::Move(ref mut place) => {
329+
let value = self.simplify_place(place, location)?;
330+
if let Some(const_) = self.try_as_constant(value) {
331+
*operand = Operand::Constant(Box::new(const_));
332+
self.any_replacement = true;
333+
}
334+
Some(value)
335+
}
304336
}
305337
}
306338

307339
#[instrument(level = "trace", skip(self), ret)]
308-
fn insert_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Option<VnIndex> {
340+
fn simplify_rvalue(
341+
&mut self,
342+
rvalue: &mut Rvalue<'tcx>,
343+
location: Location,
344+
) -> Option<VnIndex> {
309345
let value = match *rvalue {
310346
// Forward values.
311-
Rvalue::Use(ref operand) => return self.insert_operand(operand),
312-
Rvalue::CopyForDeref(place) => return self.insert_operand(&Operand::Copy(place)),
347+
Rvalue::Use(ref mut operand) => return self.simplify_operand(operand, location),
348+
Rvalue::CopyForDeref(place) => {
349+
let mut operand = Operand::Copy(place);
350+
let val = self.simplify_operand(&mut operand, location);
351+
*rvalue = Rvalue::Use(operand);
352+
return val;
353+
}
313354

314355
// Roots.
315-
Rvalue::Repeat(ref op, amount) => {
316-
let op = self.insert_operand(op)?;
356+
Rvalue::Repeat(ref mut op, amount) => {
357+
let op = self.simplify_operand(op, location)?;
317358
Value::Repeat(op, amount)
318359
}
319360
Rvalue::NullaryOp(op, ty) => Value::NullaryOp(op, ty),
320-
Rvalue::Aggregate(box ref kind, ref fields) => {
361+
Rvalue::Aggregate(box ref kind, ref mut fields) => {
321362
let variant_index = match *kind {
322363
AggregateKind::Array(..)
323364
| AggregateKind::Tuple
@@ -328,40 +369,40 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
328369
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
329370
};
330371
let fields: Option<Vec<_>> = fields
331-
.iter()
332-
.map(|op| self.insert_operand(op).or_else(|| self.new_opaque()))
372+
.iter_mut()
373+
.map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
333374
.collect();
334375
let ty = rvalue.ty(self.local_decls, self.tcx);
335376
Value::Aggregate(ty, variant_index, fields?)
336377
}
337378
Rvalue::Ref(.., place) | Rvalue::AddressOf(_, place) => return self.new_pointer(place),
338379

339380
// Operations.
340-
Rvalue::Len(place) => {
341-
let place = self.insert_place(place)?;
381+
Rvalue::Len(ref mut place) => {
382+
let place = self.simplify_place(place, location)?;
342383
Value::Len(place)
343384
}
344-
Rvalue::Cast(kind, ref value, to) => {
385+
Rvalue::Cast(kind, ref mut value, to) => {
345386
let from = value.ty(self.local_decls, self.tcx);
346-
let value = self.insert_operand(value)?;
387+
let value = self.simplify_operand(value, location)?;
347388
Value::Cast { kind, value, from, to }
348389
}
349-
Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
350-
let lhs = self.insert_operand(lhs)?;
351-
let rhs = self.insert_operand(rhs)?;
352-
Value::BinaryOp(op, lhs, rhs)
390+
Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
391+
let lhs = self.simplify_operand(lhs, location);
392+
let rhs = self.simplify_operand(rhs, location);
393+
Value::BinaryOp(op, lhs?, rhs?)
353394
}
354-
Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
355-
let lhs = self.insert_operand(lhs)?;
356-
let rhs = self.insert_operand(rhs)?;
357-
Value::CheckedBinaryOp(op, lhs, rhs)
395+
Rvalue::CheckedBinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
396+
let lhs = self.simplify_operand(lhs, location);
397+
let rhs = self.simplify_operand(rhs, location);
398+
Value::CheckedBinaryOp(op, lhs?, rhs?)
358399
}
359-
Rvalue::UnaryOp(op, ref arg) => {
360-
let arg = self.insert_operand(arg)?;
400+
Rvalue::UnaryOp(op, ref mut arg) => {
401+
let arg = self.simplify_operand(arg, location)?;
361402
Value::UnaryOp(op, arg)
362403
}
363-
Rvalue::Discriminant(place) => {
364-
let place = self.insert_place(place)?;
404+
Rvalue::Discriminant(ref mut place) => {
405+
let place = self.simplify_place(place, location)?;
365406
Value::Discriminant(place)
366407
}
367408

@@ -373,22 +414,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373414
}
374415
}
375416

376-
struct Replacer<'a, 'tcx> {
377-
tcx: TyCtxt<'tcx>,
378-
ssa: SsaLocals,
379-
dominators: Dominators<BasicBlock>,
380-
state: VnState<'a, 'tcx>,
381-
/// Set of locals that are reused, and for which we should remove storage statements to avoid a
382-
/// use-after-StorageDead.
383-
reused_locals: BitSet<Local>,
384-
any_replacement: &'a mut bool,
385-
}
386-
387-
impl<'tcx> Replacer<'_, 'tcx> {
417+
impl<'tcx> VnState<'_, 'tcx> {
388418
/// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
389419
fn try_as_constant(&mut self, index: VnIndex) -> Option<ConstOperand<'tcx>> {
390-
if let Value::Constant(const_) = self.state.get(index) {
391-
Some(ConstOperand { span: rustc_span::DUMMY_SP, user_ty: None, const_: const_.clone() })
420+
if let Value::Constant(const_) = *self.get(index) {
421+
Some(ConstOperand { span: rustc_span::DUMMY_SP, user_ty: None, const_ })
392422
} else {
393423
None
394424
}
@@ -397,50 +427,37 @@ impl<'tcx> Replacer<'_, 'tcx> {
397427
/// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
398428
/// return it.
399429
fn try_as_local(&mut self, index: VnIndex, loc: Location) -> Option<Local> {
400-
let other = self.state.rev_locals.get(&index)?;
430+
let other = self.rev_locals.get(&index)?;
401431
other
402432
.iter()
403433
.copied()
404-
.find(|&other| self.ssa.assignment_dominates(&self.dominators, other, loc))
434+
.find(|&other| self.ssa.assignment_dominates(self.dominators, other, loc))
405435
}
406436
}
407437

408-
impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
438+
impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
409439
fn tcx(&self) -> TyCtxt<'tcx> {
410440
self.tcx
411441
}
412442

413443
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
414-
if let Some(place) = operand.place()
415-
&& let Some(value) = self.state.insert_place(place)
416-
{
417-
if let Some(const_) = self.try_as_constant(value) {
418-
*operand = Operand::Constant(Box::new(const_));
419-
*self.any_replacement = true;
420-
} else if let Some(local) = self.try_as_local(value, location)
421-
&& *operand != Operand::Move(local.into())
422-
{
423-
*operand = Operand::Copy(local.into());
424-
self.reused_locals.insert(local);
425-
*self.any_replacement = true;
426-
}
427-
}
444+
self.simplify_operand(operand, location);
428445
}
429446

430447
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
431448
self.super_statement(stmt, location);
432449
if let StatementKind::Assign(box (_, ref mut rvalue)) = stmt.kind
433-
&& let Some(value) = self.state.insert_rvalue(rvalue)
450+
&& let Some(value) = self.simplify_rvalue(rvalue, location)
434451
{
435452
if let Some(const_) = self.try_as_constant(value) {
436453
*rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
437-
*self.any_replacement = true;
454+
self.any_replacement = true;
438455
} else if let Some(local) = self.try_as_local(value, location)
439456
&& *rvalue != Rvalue::Use(Operand::Move(local.into()))
440457
{
441458
*rvalue = Rvalue::Use(Operand::Copy(local.into()));
442459
self.reused_locals.insert(local);
443-
*self.any_replacement = true;
460+
self.any_replacement = true;
444461
}
445462
}
446463
}

compiler/rustc_mir_transform/src/ssa.rs

+18
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,24 @@ impl SsaLocals {
164164
})
165165
}
166166

167+
pub fn for_each_assignment_mut<'tcx>(
168+
&self,
169+
basic_blocks: &mut BasicBlocks<'tcx>,
170+
mut f: impl FnMut(Local, &mut Rvalue<'tcx>, Location),
171+
) {
172+
for &local in &self.assignment_order {
173+
if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] {
174+
// `loc` must point to a direct assignment to `local`.
175+
let bbs = basic_blocks.as_mut_preserves_cfg();
176+
let bb = &mut bbs[loc.block];
177+
let stmt = &mut bb.statements[loc.statement_index];
178+
let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else { bug!() };
179+
assert_eq!(target.as_local(), Some(local));
180+
f(local, rvalue, loc)
181+
}
182+
}
183+
}
184+
167185
/// Compute the equivalence classes for locals, based on copy statements.
168186
///
169187
/// The returned vector maps each local to the one it copies. In the following case:

tests/mir-opt/gvn.cast.GVN.panic-abort.diff

+6-6
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@
104104
}
105105

106106
bb0: {
107-
StorageLive(_1);
107+
- StorageLive(_1);
108108
_1 = const 1_i64;
109-
StorageLive(_2);
109+
- StorageLive(_2);
110110
_2 = const 1_u64;
111-
StorageLive(_3);
111+
- StorageLive(_3);
112112
_3 = const 1f64;
113113
StorageLive(_4);
114114
StorageLive(_5);
@@ -492,9 +492,9 @@
492492
- StorageDead(_90);
493493
StorageDead(_89);
494494
_0 = const ();
495-
StorageDead(_3);
496-
StorageDead(_2);
497-
StorageDead(_1);
495+
- StorageDead(_3);
496+
- StorageDead(_2);
497+
- StorageDead(_1);
498498
return;
499499
}
500500
}

tests/mir-opt/gvn.cast.GVN.panic-unwind.diff

+6-6
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@
104104
}
105105

106106
bb0: {
107-
StorageLive(_1);
107+
- StorageLive(_1);
108108
_1 = const 1_i64;
109-
StorageLive(_2);
109+
- StorageLive(_2);
110110
_2 = const 1_u64;
111-
StorageLive(_3);
111+
- StorageLive(_3);
112112
_3 = const 1f64;
113113
StorageLive(_4);
114114
StorageLive(_5);
@@ -492,9 +492,9 @@
492492
- StorageDead(_90);
493493
StorageDead(_89);
494494
_0 = const ();
495-
StorageDead(_3);
496-
StorageDead(_2);
497-
StorageDead(_1);
495+
- StorageDead(_3);
496+
- StorageDead(_2);
497+
- StorageDead(_1);
498498
return;
499499
}
500500
}

0 commit comments

Comments
 (0)