Skip to content

Commit 4d38227

Browse files
committed
Simplify projections in GVN.
1 parent ac6497b commit 4d38227

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::{AssignedValue, SsaLocals};
@@ -461,6 +462,87 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
461462
Some(op)
462463
}
463464

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

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

524-
if let Some(local) = self.try_as_local(value, location)
525-
&& local != place.local // in case we had no projection to begin with.
526-
{
527-
*place = local.into();
528-
self.reused_locals.insert(local);
529-
} else if place_ref.local != place.local
530-
|| place_ref.projection.len() < place.projection.len()
531-
{
574+
if let Some(new_local) = self.try_as_local(value, location) {
575+
place_ref = PlaceRef { local: new_local, projection: &[] };
576+
}
577+
578+
if place_ref.local != place.local || place_ref.projection.len() < place.projection.len() {
532579
// By the invariant on `place_ref`.
533580
*place = place_ref.project_deeper(&[], self.tcx);
534581
self.reused_locals.insert(place_ref.local);
@@ -544,7 +591,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
544591
location: Location,
545592
) -> Option<VnIndex> {
546593
match *operand {
547-
Operand::Constant(ref constant) => Some(self.insert(Value::Constant(constant.const_))),
594+
Operand::Constant(ref mut constant) => {
595+
let const_ = constant.const_.normalize(self.tcx, self.param_env);
596+
Some(self.insert(Value::Constant(const_)))
597+
}
548598
Operand::Copy(ref mut place) | Operand::Move(ref mut place) => {
549599
let value = self.simplify_place_value(place, location)?;
550600
if let Some(const_) = self.try_as_constant(value) {
@@ -594,11 +644,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
594644
let ty = rvalue.ty(self.local_decls, self.tcx);
595645
Value::Aggregate(ty, variant_index, fields?)
596646
}
597-
Rvalue::Ref(_, borrow_kind, place) => {
598-
return self.new_pointer(place, AddressKind::Ref(borrow_kind));
647+
Rvalue::Ref(_, borrow_kind, ref mut place) => {
648+
self.simplify_place_projection(place, location);
649+
return self.new_pointer(*place, AddressKind::Ref(borrow_kind));
599650
}
600-
Rvalue::AddressOf(mutbl, place) => {
601-
return self.new_pointer(place, AddressKind::Address(mutbl));
651+
Rvalue::AddressOf(mutbl, ref mut place) => {
652+
self.simplify_place_projection(place, location);
653+
return self.new_pointer(*place, AddressKind::Address(mutbl));
602654
}
603655

604656
// Operations.
@@ -756,6 +808,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
756808
self.tcx
757809
}
758810

811+
fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) {
812+
self.simplify_place_projection(place, location);
813+
}
814+
759815
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
760816
self.simplify_operand(operand, location);
761817
}

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)