Skip to content

Commit c8fbb62

Browse files
committed
GVN: Avoid merging borrows from the dereferenced value
1 parent 6064a90 commit c8fbb62

File tree

6 files changed

+64
-23
lines changed

6 files changed

+64
-23
lines changed

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,13 @@ enum Value<'a, 'tcx> {
246246

247247
// Extractions.
248248
/// This is the *value* obtained by projecting another value.
249-
Projection(VnIndex, ProjectionElem<VnIndex, ()>),
249+
Projection {
250+
base: VnIndex,
251+
elem: ProjectionElem<VnIndex, ()>,
252+
/// Some values may be a borrow or pointer.
253+
/// Give them a different provenance, so we don't merge them.
254+
provenance: Option<VnOpaque>,
255+
},
250256
/// Discriminant of the given value.
251257
Discriminant(VnIndex),
252258

@@ -295,6 +301,7 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> {
295301
debug_assert!(match value {
296302
Value::Opaque(_) | Value::Address { .. } => true,
297303
Value::Constant { disambiguator, .. } => disambiguator.is_some(),
304+
Value::Projection { provenance, .. } => provenance.is_some(),
298305
_ => false,
299306
});
300307

@@ -539,7 +546,18 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
539546
}
540547

541548
fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex {
542-
self.insert(ty, Value::Projection(value, ProjectionElem::Deref))
549+
if ty.is_any_ptr() {
550+
// Give each borrow and pointer a different provenance, so we don't merge them.
551+
return self.insert_unique(ty, true, |provenance| Value::Projection {
552+
base: value,
553+
elem: ProjectionElem::Deref,
554+
provenance: Some(provenance),
555+
});
556+
}
557+
self.insert(
558+
ty,
559+
Value::Projection { base: value, elem: ProjectionElem::Deref, provenance: None },
560+
)
543561
}
544562

545563
#[instrument(level = "trace", skip(self), ret)]
@@ -622,7 +640,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
622640
ImmTy::from_immediate(ptr_imm, ty).into()
623641
}
624642

625-
Projection(base, elem) => {
643+
Projection { base, elem, .. } => {
626644
let base = self.eval_to_const(base)?;
627645
// `Index` by constants should have been replaced by `ConstantIndex` by
628646
// `simplify_place_projection`.
@@ -813,8 +831,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
813831
ProjectionElem::Field(f, _) => match self.get(value) {
814832
Value::Aggregate(_, fields) => return Some((projection_ty, fields[f.as_usize()])),
815833
Value::Union(active, field) if active == f => return Some((projection_ty, field)),
816-
Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant))
817-
if let Value::Aggregate(written_variant, fields) = self.get(outer_value)
834+
Value::Projection {
835+
base, elem: ProjectionElem::Downcast(_, read_variant), ..
836+
} if let Value::Aggregate(written_variant, fields) = self.get(base)
818837
// This pass is not aware of control-flow, so we do not know whether the
819838
// replacement we are doing is actually reachable. We could be in any arm of
820839
// ```
@@ -867,7 +886,10 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
867886
ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()),
868887
};
869888

870-
let value = self.insert(projection_ty.ty, Value::Projection(value, proj));
889+
let value = self.insert(
890+
projection_ty.ty,
891+
Value::Projection { base: value, elem: proj, provenance: None },
892+
);
871893
Some((projection_ty, value))
872894
}
873895

@@ -1096,11 +1118,17 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
10961118
fields: &[VnIndex],
10971119
) -> Option<VnIndex> {
10981120
let Some(&first_field) = fields.first() else { return None };
1099-
let Value::Projection(copy_from_value, _) = self.get(first_field) else { return None };
1121+
let Value::Projection { base: copy_from_value, .. } = self.get(first_field) else {
1122+
return None;
1123+
};
11001124

11011125
// All fields must correspond one-to-one and come from the same aggregate value.
11021126
if fields.iter().enumerate().any(|(index, &v)| {
1103-
if let Value::Projection(pointer, ProjectionElem::Field(from_index, _)) = self.get(v)
1127+
if let Value::Projection {
1128+
base: pointer,
1129+
elem: ProjectionElem::Field(from_index, _),
1130+
..
1131+
} = self.get(v)
11041132
&& copy_from_value == pointer
11051133
&& from_index.index() == index
11061134
{
@@ -1112,7 +1140,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
11121140
}
11131141

11141142
let mut copy_from_local_value = copy_from_value;
1115-
if let Value::Projection(pointer, proj) = self.get(copy_from_value)
1143+
if let Value::Projection { base: pointer, elem: proj, .. } = self.get(copy_from_value)
11161144
&& let ProjectionElem::Downcast(_, read_variant) = proj
11171145
{
11181146
if variant_index == read_variant {
@@ -1817,7 +1845,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
18171845
// If we are here, we failed to find a local, and we already have a `Deref`.
18181846
// Trying to add projections will only result in an ill-formed place.
18191847
return None;
1820-
} else if let Value::Projection(pointer, proj) = self.get(index)
1848+
} else if let Value::Projection { base: pointer, elem: proj, .. } = self.get(index)
18211849
&& (allow_complex_projection || proj.is_stable_offset())
18221850
&& let Some(proj) = self.try_as_place_elem(self.ty(index), proj, loc)
18231851
{

tests/mir-opt/pre-codegen/deref_nested_borrows.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
fn src(x: &&u8) -> bool {
44
// CHECK-LABEL: fn src(
5+
// CHECK: debug y => [[Y:_.*]];
6+
// CHECK: bb0:
7+
// CHECK: [[BORROW_u8:_.*]] = copy (*_1);
8+
// CHECK: [[Y]] = copy (*[[BORROW_u8]]);
9+
// CHECK: bb1:
10+
// BORROW_u8 outside its lifetime in bb1.
11+
// CHECK-NOT: copy (*[[BORROW_u8]]);
12+
// CHECK: copy (*_1);
513
// CHECK-NOT: _0 = const true;
614
// CHECK: _0 = Eq({{.*}}, {{.*}});
715
// CHECK-NOT: _0 = const true;

tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-abort.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@
2424

2525
bb1: {
2626
StorageLive(_4);
27-
- _7 = copy (*_1);
28-
- _4 = copy (*_7);
29-
+ _7 = copy _6;
30-
+ _4 = copy (*_6);
27+
_7 = copy (*_1);
28+
_4 = copy (*_7);
3129
StorageLive(_5);
3230
_5 = copy _2;
3331
- _0 = Eq(move _4, move _5);

tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@
2525
bb1: {
2626
StorageLive(_4);
2727
_7 = copy (*_1);
28-
- _4 = copy (*_7);
29-
+ _4 = copy _2;
28+
_4 = copy (*_7);
3029
StorageLive(_5);
3130
_5 = copy _2;
3231
- _0 = Eq(move _4, move _5);
33-
+ _0 = const true;
32+
+ _0 = Eq(move _4, copy _2);
3433
StorageDead(_5);
3534
StorageDead(_4);
3635
- StorageDead(_2);

tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-abort.mir

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ fn src(_1: &&u8) -> bool {
66
let mut _2: &u8;
77
let _3: u8;
88
let _4: ();
9-
let mut _5: u8;
9+
let mut _5: &u8;
10+
let mut _6: u8;
1011
scope 1 {
1112
debug y => _3;
1213
}
@@ -18,10 +19,11 @@ fn src(_1: &&u8) -> bool {
1819
}
1920

2021
bb1: {
21-
StorageLive(_5);
22-
_5 = copy (*_2);
23-
_0 = Eq(move _5, copy _3);
24-
StorageDead(_5);
22+
StorageLive(_6);
23+
_5 = copy (*_1);
24+
_6 = copy (*_5);
25+
_0 = Eq(move _6, copy _3);
26+
StorageDead(_6);
2527
return;
2628
}
2729
}

tests/mir-opt/pre-codegen/deref_nested_borrows.src.PreCodegen.after.panic-unwind.mir

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ fn src(_1: &&u8) -> bool {
66
let mut _2: &u8;
77
let _3: u8;
88
let _4: ();
9+
let mut _5: &u8;
10+
let mut _6: u8;
911
scope 1 {
1012
debug y => _3;
1113
}
@@ -17,7 +19,11 @@ fn src(_1: &&u8) -> bool {
1719
}
1820

1921
bb1: {
20-
_0 = const true;
22+
StorageLive(_6);
23+
_5 = copy (*_1);
24+
_6 = copy (*_5);
25+
_0 = Eq(move _6, copy _3);
26+
StorageDead(_6);
2127
return;
2228
}
2329
}

0 commit comments

Comments
 (0)