Skip to content

Commit 50b20b7

Browse files
authored
Rollup merge of rust-lang#141218 - dianqk:gvn-overlapping, r=oli-obk
gvn: avoid creating overlapping assignments Quick fix rust-lang#141038, as I couldn't find a way to avoid in-place modification. I'm considering handling all `ravlue` modifications within the `visit_statement` function. r? mir-opt
2 parents cf3b1b1 + d2e5a3d commit 50b20b7

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
836836
#[instrument(level = "trace", skip(self), ret)]
837837
fn simplify_rvalue(
838838
&mut self,
839+
lhs: &Place<'tcx>,
839840
rvalue: &mut Rvalue<'tcx>,
840841
location: Location,
841842
) -> Option<VnIndex> {
@@ -855,7 +856,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
855856
Value::Repeat(op, amount)
856857
}
857858
Rvalue::NullaryOp(op, ty) => Value::NullaryOp(op, ty),
858-
Rvalue::Aggregate(..) => return self.simplify_aggregate(rvalue, location),
859+
Rvalue::Aggregate(..) => return self.simplify_aggregate(lhs, rvalue, location),
859860
Rvalue::Ref(_, borrow_kind, ref mut place) => {
860861
self.simplify_place_projection(place, location);
861862
return Some(self.new_pointer(*place, AddressKind::Ref(borrow_kind)));
@@ -943,6 +944,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
943944

944945
fn simplify_aggregate_to_copy(
945946
&mut self,
947+
lhs: &Place<'tcx>,
946948
rvalue: &mut Rvalue<'tcx>,
947949
location: Location,
948950
fields: &[VnIndex],
@@ -982,19 +984,24 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
982984

983985
// Allow introducing places with non-constant offsets, as those are still better than
984986
// reconstructing an aggregate.
985-
if let Some(place) = self.try_as_place(copy_from_local_value, location, true) {
986-
if rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty {
987+
if let Some(place) = self.try_as_place(copy_from_local_value, location, true)
988+
&& rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty
989+
{
990+
// Avoid creating `*a = copy (*b)`, as they might be aliases resulting in overlapping assignments.
991+
// FIXME: This also avoids any kind of projection, not just derefs. We can add allowed projections.
992+
if lhs.as_local().is_some() {
987993
self.reused_locals.insert(place.local);
988994
*rvalue = Rvalue::Use(Operand::Copy(place));
989-
return Some(copy_from_local_value);
990995
}
996+
return Some(copy_from_local_value);
991997
}
992998

993999
None
9941000
}
9951001

9961002
fn simplify_aggregate(
9971003
&mut self,
1004+
lhs: &Place<'tcx>,
9981005
rvalue: &mut Rvalue<'tcx>,
9991006
location: Location,
10001007
) -> Option<VnIndex> {
@@ -1090,7 +1097,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
10901097

10911098
if let AggregateTy::Def(_, _) = ty
10921099
&& let Some(value) =
1093-
self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index)
1100+
self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index)
10941101
{
10951102
return Some(value);
10961103
}
@@ -1765,7 +1772,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
17651772
if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind {
17661773
self.simplify_place_projection(lhs, location);
17671774

1768-
let value = self.simplify_rvalue(rvalue, location);
1775+
let value = self.simplify_rvalue(lhs, rvalue, location);
17691776
let value = if let Some(local) = lhs.as_local()
17701777
&& self.ssa.is_ssa(local)
17711778
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
- // MIR for `overlapping` before GVN
2+
+ // MIR for `overlapping` after GVN
3+
4+
fn overlapping(_1: Adt) -> () {
5+
let mut _0: ();
6+
let mut _2: *mut Adt;
7+
let mut _3: u32;
8+
let mut _4: &Adt;
9+
10+
bb0: {
11+
_2 = &raw mut _1;
12+
_4 = &(*_2);
13+
_3 = copy (((*_4) as variant#1).0: u32);
14+
(*_2) = Adt::Some(copy _3);
15+
return;
16+
}
17+
}
18+

tests/mir-opt/gvn_overlapping.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//@ test-mir-pass: GVN
2+
3+
#![feature(custom_mir, core_intrinsics)]
4+
5+
// Check that we do not create overlapping assignments.
6+
7+
use std::intrinsics::mir::*;
8+
9+
// EMIT_MIR gvn_overlapping.overlapping.GVN.diff
10+
#[custom_mir(dialect = "runtime")]
11+
fn overlapping(_17: Adt) {
12+
// CHECK-LABEL: fn overlapping(
13+
// CHECK: let mut [[PTR:.*]]: *mut Adt;
14+
// CHECK: (*[[PTR]]) = Adt::Some(copy {{.*}});
15+
mir! {
16+
let _33: *mut Adt;
17+
let _48: u32;
18+
let _73: &Adt;
19+
{
20+
_33 = core::ptr::addr_of_mut!(_17);
21+
_73 = &(*_33);
22+
_48 = Field(Variant((*_73), 1), 0);
23+
(*_33) = Adt::Some(_48);
24+
Return()
25+
}
26+
}
27+
}
28+
29+
fn main() {
30+
overlapping(Adt::Some(0));
31+
}
32+
33+
enum Adt {
34+
None,
35+
Some(u32),
36+
}

0 commit comments

Comments
 (0)