Skip to content

Commit 50ac9c8

Browse files
committed
Simplify projections in GVN.
1 parent bd77ef5 commit 50ac9c8

13 files changed

+396
-126
lines changed

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 105 additions & 49 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;
@@ -454,6 +455,87 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
454455
Some(op)
455456
}
456457

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

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

517-
if let Some(local) = self.try_as_local(value, location)
518-
&& local != place.local // in case we had no projection to begin with.
519-
{
520-
*place = local.into();
521-
self.reused_locals.insert(local);
522-
} else if place_ref.local != place.local
523-
|| place_ref.projection.len() < place.projection.len()
524-
{
567+
if let Some(new_local) = self.try_as_local(value, location) {
568+
place_ref = PlaceRef { local: new_local, projection: &[] };
569+
}
570+
571+
if place_ref.local != place.local || place_ref.projection.len() < place.projection.len() {
525572
// By the invariant on `place_ref`.
526573
*place = place_ref.project_deeper(&[], self.tcx);
527574
self.reused_locals.insert(place_ref.local);
@@ -537,7 +584,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
537584
location: Location,
538585
) -> Option<VnIndex> {
539586
match *operand {
540-
Operand::Constant(ref constant) => Some(self.insert(Value::Constant(constant.const_))),
587+
Operand::Constant(ref mut constant) => {
588+
let const_ = constant.const_.normalize(self.tcx, self.param_env);
589+
Some(self.insert(Value::Constant(const_)))
590+
}
541591
Operand::Copy(ref mut place) | Operand::Move(ref mut place) => {
542592
let value = self.simplify_place_value(place, location)?;
543593
if let Some(const_) = self.try_as_constant(value) {
@@ -587,11 +637,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
587637
let ty = rvalue.ty(self.local_decls, self.tcx);
588638
Value::Aggregate(ty, variant_index, fields?)
589639
}
590-
Rvalue::Ref(_, borrow_kind, place) => {
591-
return self.new_pointer(place, AddressKind::Ref(borrow_kind));
640+
Rvalue::Ref(_, borrow_kind, ref mut place) => {
641+
self.simplify_place_projection(place, location);
642+
return self.new_pointer(*place, AddressKind::Ref(borrow_kind));
592643
}
593-
Rvalue::AddressOf(mutbl, place) => {
594-
return self.new_pointer(place, AddressKind::Address(mutbl));
644+
Rvalue::AddressOf(mutbl, ref mut place) => {
645+
self.simplify_place_projection(place, location);
646+
return self.new_pointer(*place, AddressKind::Address(mutbl));
595647
}
596648

597649
// Operations.
@@ -749,6 +801,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
749801
self.tcx
750802
}
751803

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

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)