Skip to content

Commit 57b4ac9

Browse files
committed
Simplify projections in GVN.
1 parent c0042a9 commit 57b4ac9

13 files changed

+395
-125
lines changed

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 104 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ use rustc_middle::ty::layout::LayoutOf;
6666
use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut};
6767
use rustc_span::DUMMY_SP;
6868
use rustc_target::abi::{self, Abi, Size, VariantIdx, FIRST_VARIANT};
69+
use std::borrow::Cow;
6970

7071
use crate::dataflow_const_prop::DummyMachine;
7172
use crate::ssa::SsaLocals;
@@ -453,6 +454,86 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
453454
Some(op)
454455
}
455456

457+
fn project(
458+
&mut self,
459+
place: PlaceRef<'tcx>,
460+
value: VnIndex,
461+
proj: PlaceElem<'tcx>,
462+
) -> Option<VnIndex> {
463+
let proj = match proj {
464+
ProjectionElem::Deref => {
465+
let ty = place.ty(self.local_decls, self.tcx).ty;
466+
if let Some(Mutability::Not) = ty.ref_mutability()
467+
&& let Some(pointee_ty) = ty.builtin_deref(true)
468+
&& pointee_ty.ty.is_freeze(self.tcx, self.param_env)
469+
{
470+
// An immutable borrow `_x` always points to the same value for the
471+
// lifetime of the borrow, so we can merge all instances of `*_x`.
472+
ProjectionElem::Deref
473+
} else {
474+
return None;
475+
}
476+
}
477+
ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index),
478+
ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty),
479+
ProjectionElem::Index(idx) => {
480+
let idx = self.locals[idx]?;
481+
ProjectionElem::Index(idx)
482+
}
483+
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
484+
ProjectionElem::ConstantIndex { offset, min_length, from_end }
485+
}
486+
ProjectionElem::Subslice { from, to, from_end } => {
487+
ProjectionElem::Subslice { from, to, from_end }
488+
}
489+
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
490+
};
491+
492+
Some(self.insert(Value::Projection(value, proj)))
493+
}
494+
495+
/// Simplify the projection chain if we know better.
496+
#[instrument(level = "trace", skip(self))]
497+
fn simplify_place_projection(&mut self, place: &mut Place<'tcx>, location: Location) {
498+
// If the projection is indirect, we treat the local as a value, so can replace it with
499+
// another local.
500+
if place.is_indirect()
501+
&& let Some(base) = self.locals[place.local]
502+
&& let Some(new_local) = self.try_as_local(base, location)
503+
{
504+
place.local = new_local;
505+
self.reused_locals.insert(new_local);
506+
}
507+
508+
let mut projection = Cow::Borrowed(&place.projection[..]);
509+
510+
for i in 0..projection.len() {
511+
let elem = projection[i];
512+
if let ProjectionElem::Index(idx) = elem
513+
&& let Some(idx) = self.locals[idx]
514+
{
515+
if let Some(offset) = self.evaluated[idx].as_ref()
516+
&& let Ok(offset) = self.ecx.read_target_usize(offset)
517+
{
518+
projection.to_mut()[i] = ProjectionElem::ConstantIndex {
519+
offset,
520+
min_length: offset + 1,
521+
from_end: false,
522+
};
523+
} else if let Some(new_idx) = self.try_as_local(idx, location) {
524+
projection.to_mut()[i] = ProjectionElem::Index(new_idx);
525+
self.reused_locals.insert(new_idx);
526+
}
527+
}
528+
}
529+
530+
if projection.is_owned() {
531+
place.projection = self.tcx.mk_place_elems(&projection);
532+
}
533+
534+
trace!(?place);
535+
}
536+
456537
/// Represent the *value* which would be read from `place`, and point `place` to a preexisting
457538
/// place with the same value (if that already exists).
458539
#[instrument(level = "trace", skip(self), ret)]
@@ -461,6 +542,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
461542
place: &mut Place<'tcx>,
462543
location: Location,
463544
) -> Option<VnIndex> {
545+
self.simplify_place_projection(place, location);
546+
464547
// Invariant: `place` and `place_ref` point to the same value, even if they point to
465548
// different memory locations.
466549
let mut place_ref = place.as_ref();
@@ -475,51 +558,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
475558
place_ref = PlaceRef { local, projection: &place.projection[index..] };
476559
}
477560

478-
let proj = match proj {
479-
ProjectionElem::Deref => {
480-
let ty = Place::ty_from(
481-
place.local,
482-
&place.projection[..index],
483-
self.local_decls,
484-
self.tcx,
485-
)
486-
.ty;
487-
if let Some(Mutability::Not) = ty.ref_mutability()
488-
&& let Some(pointee_ty) = ty.builtin_deref(true)
489-
&& pointee_ty.ty.is_freeze(self.tcx, self.param_env)
490-
{
491-
// An immutable borrow `_x` always points to the same value for the
492-
// lifetime of the borrow, so we can merge all instances of `*_x`.
493-
ProjectionElem::Deref
494-
} else {
495-
return None;
496-
}
497-
}
498-
ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty),
499-
ProjectionElem::Index(idx) => {
500-
let idx = self.locals[idx]?;
501-
ProjectionElem::Index(idx)
502-
}
503-
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
504-
ProjectionElem::ConstantIndex { offset, min_length, from_end }
505-
}
506-
ProjectionElem::Subslice { from, to, from_end } => {
507-
ProjectionElem::Subslice { from, to, from_end }
508-
}
509-
ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index),
510-
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
511-
};
512-
value = self.insert(Value::Projection(value, proj));
561+
let base = PlaceRef { local: place.local, projection: &place.projection[..index] };
562+
value = self.project(base, value, proj)?;
513563
}
514564

515-
if let Some(local) = self.try_as_local(value, location)
516-
&& local != place.local // in case we had no projection to begin with.
517-
{
518-
*place = local.into();
519-
self.reused_locals.insert(local);
520-
} else if place_ref.local != place.local
521-
|| place_ref.projection.len() < place.projection.len()
522-
{
565+
if let Some(new_local) = self.try_as_local(value, location) {
566+
place_ref = PlaceRef { local: new_local, projection: &[] };
567+
}
568+
569+
if place_ref.local != place.local || place_ref.projection.len() < place.projection.len() {
523570
// By the invariant on `place_ref`.
524571
*place = place_ref.project_deeper(&[], self.tcx);
525572
self.reused_locals.insert(place_ref.local);
@@ -535,7 +582,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
535582
location: Location,
536583
) -> Option<VnIndex> {
537584
match *operand {
538-
Operand::Constant(ref constant) => Some(self.insert(Value::Constant(constant.const_))),
585+
Operand::Constant(ref mut constant) => {
586+
let const_ = constant.const_.normalize(self.tcx, self.param_env);
587+
Some(self.insert(Value::Constant(const_)))
588+
}
539589
Operand::Copy(ref mut place) | Operand::Move(ref mut place) => {
540590
let value = self.simplify_place_value(place, location)?;
541591
if let Some(const_) = self.try_as_constant(value) {
@@ -585,11 +635,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
585635
let ty = rvalue.ty(self.local_decls, self.tcx);
586636
Value::Aggregate(ty, variant_index, fields?)
587637
}
588-
Rvalue::Ref(_, borrow_kind, place) => {
589-
return self.new_pointer(place, AddressKind::Ref(borrow_kind));
638+
Rvalue::Ref(_, borrow_kind, ref mut place) => {
639+
self.simplify_place_projection(place, location);
640+
return self.new_pointer(*place, AddressKind::Ref(borrow_kind));
590641
}
591-
Rvalue::AddressOf(mutbl, place) => {
592-
return self.new_pointer(place, AddressKind::Address(mutbl));
642+
Rvalue::AddressOf(mutbl, ref mut place) => {
643+
self.simplify_place_projection(place, location);
644+
return self.new_pointer(*place, AddressKind::Address(mutbl));
593645
}
594646

595647
// Operations.
@@ -747,6 +799,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
747799
self.tcx
748800
}
749801

802+
fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) {
803+
self.simplify_place_projection(place, location);
804+
}
805+
750806
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
751807
self.simplify_operand(operand, location);
752808
}

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![deny(rustc::untranslatable_diagnostic)]
33
#![deny(rustc::diagnostic_outside_of_impl)]
44
#![feature(box_patterns)]
5+
#![feature(cow_is_borrowed)]
56
#![feature(decl_macro)]
67
#![feature(is_sorted)]
78
#![feature(let_chains)]

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@
7272
bb2: {
7373
StorageDead(_7);
7474
StorageDead(_6);
75-
StorageLive(_8);
75+
- StorageLive(_8);
76+
+ nop;
7677
_8 = &raw const (*_1);
7778
StorageLive(_9);
7879
StorageLive(_10);
@@ -92,7 +93,8 @@
9293
bb4: {
9394
StorageDead(_12);
9495
StorageDead(_11);
95-
StorageLive(_13);
96+
- StorageLive(_13);
97+
+ nop;
9698
_13 = &raw mut (*_1);
9799
StorageLive(_14);
98100
StorageLive(_15);
@@ -112,7 +114,8 @@
112114
bb6: {
113115
StorageDead(_17);
114116
StorageDead(_16);
115-
StorageLive(_18);
117+
- StorageLive(_18);
118+
+ nop;
116119
_18 = &(*_1);
117120
StorageLive(_19);
118121
- StorageLive(_20);
@@ -188,9 +191,12 @@
188191
StorageDead(_32);
189192
StorageDead(_31);
190193
_0 = const ();
191-
StorageDead(_18);
192-
StorageDead(_13);
193-
StorageDead(_8);
194+
- StorageDead(_18);
195+
- StorageDead(_13);
196+
- StorageDead(_8);
197+
+ nop;
198+
+ nop;
199+
+ nop;
194200
return;
195201
}
196202
}

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@
7272
bb2: {
7373
StorageDead(_7);
7474
StorageDead(_6);
75-
StorageLive(_8);
75+
- StorageLive(_8);
76+
+ nop;
7677
_8 = &raw const (*_1);
7778
StorageLive(_9);
7879
StorageLive(_10);
@@ -92,7 +93,8 @@
9293
bb4: {
9394
StorageDead(_12);
9495
StorageDead(_11);
95-
StorageLive(_13);
96+
- StorageLive(_13);
97+
+ nop;
9698
_13 = &raw mut (*_1);
9799
StorageLive(_14);
98100
StorageLive(_15);
@@ -112,7 +114,8 @@
112114
bb6: {
113115
StorageDead(_17);
114116
StorageDead(_16);
115-
StorageLive(_18);
117+
- StorageLive(_18);
118+
+ nop;
116119
_18 = &(*_1);
117120
StorageLive(_19);
118121
- StorageLive(_20);
@@ -188,9 +191,12 @@
188191
StorageDead(_32);
189192
StorageDead(_31);
190193
_0 = const ();
191-
StorageDead(_18);
192-
StorageDead(_13);
193-
StorageDead(_8);
194+
- StorageDead(_18);
195+
- StorageDead(_13);
196+
- StorageDead(_8);
197+
+ nop;
198+
+ nop;
199+
+ nop;
194200
return;
195201
}
196202
}

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

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@
2020
let mut _15: *mut impl Sized;
2121
let _16: ();
2222
let mut _17: *mut impl Sized;
23+
let _18: &mut impl Sized;
24+
let mut _20: S<&mut impl Sized>;
25+
let mut _21: &mut impl Sized;
26+
let _22: ();
27+
let mut _23: &impl Sized;
28+
let _24: ();
29+
let mut _25: &mut impl Sized;
30+
let _26: ();
31+
let mut _27: *const impl Sized;
32+
let _28: ();
33+
let mut _29: *mut impl Sized;
34+
scope 1 {
35+
debug r => _18;
36+
let _19: &mut impl Sized;
37+
scope 2 {
38+
debug s => _19;
39+
}
40+
}
2341

2442
bb0: {
2543
StorageLive(_2);
@@ -94,11 +112,65 @@
94112
bb8: {
95113
StorageDead(_17);
96114
StorageDead(_16);
97-
_0 = const ();
98-
drop(_1) -> [return: bb9, unwind unreachable];
115+
- StorageLive(_18);
116+
+ nop;
117+
_18 = &mut _1;
118+
- StorageLive(_19);
119+
+ nop;
120+
StorageLive(_20);
121+
StorageLive(_21);
122+
- _21 = move _18;
123+
- _20 = S::<&mut impl Sized>(move _21);
124+
+ _21 = _18;
125+
+ _20 = S::<&mut impl Sized>(_18);
126+
StorageDead(_21);
127+
_19 = move (_20.0: &mut impl Sized);
128+
StorageDead(_20);
129+
StorageLive(_22);
130+
StorageLive(_23);
131+
_23 = &(*_19);
132+
_22 = opaque::<&impl Sized>(move _23) -> [return: bb9, unwind unreachable];
99133
}
100134

101135
bb9: {
136+
StorageDead(_23);
137+
StorageDead(_22);
138+
StorageLive(_24);
139+
StorageLive(_25);
140+
_25 = &mut (*_19);
141+
_24 = opaque::<&mut impl Sized>(move _25) -> [return: bb10, unwind unreachable];
142+
}
143+
144+
bb10: {
145+
StorageDead(_25);
146+
StorageDead(_24);
147+
StorageLive(_26);
148+
StorageLive(_27);
149+
_27 = &raw const (*_19);
150+
_26 = opaque::<*const impl Sized>(move _27) -> [return: bb11, unwind unreachable];
151+
}
152+
153+
bb11: {
154+
StorageDead(_27);
155+
StorageDead(_26);
156+
StorageLive(_28);
157+
StorageLive(_29);
158+
_29 = &raw mut (*_19);
159+
_28 = opaque::<*mut impl Sized>(move _29) -> [return: bb12, unwind unreachable];
160+
}
161+
162+
bb12: {
163+
StorageDead(_29);
164+
StorageDead(_28);
165+
_0 = const ();
166+
- StorageDead(_19);
167+
- StorageDead(_18);
168+
+ nop;
169+
+ nop;
170+
drop(_1) -> [return: bb13, unwind unreachable];
171+
}
172+
173+
bb13: {
102174
return;
103175
}
104176
}

0 commit comments

Comments
 (0)