Skip to content

Commit d2e5a3d

Browse files
committed
gvn: avoid creating overlapping assignments
1 parent ac17c34 commit d2e5a3d

3 files changed

Lines changed: 67 additions & 6 deletions

File tree

‎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
fnsimplify_rvalue(
838838
&mutself,
839+
lhs:&Place<'tcx>,
839840
rvalue:&mutRvalue<'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(..) => returnself.simplify_aggregate(rvalue, location),
859+
Rvalue::Aggregate(..) => returnself.simplify_aggregate(lhs,rvalue, location),
859860
Rvalue::Ref(_, borrow_kind,refmut place) => {
860861
self.simplify_place_projection(place, location);
861862
returnSome(self.new_pointer(*place,AddressKind::Ref(borrow_kind)));
@@ -943,6 +944,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
943944

944945
fnsimplify_aggregate_to_copy(
945946
&mutself,
947+
lhs:&Place<'tcx>,
946948
rvalue:&mutRvalue<'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-
ifletSome(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+
ifletSome(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-
returnSome(copy_from_local_value);
990995
}
996+
returnSome(copy_from_local_value);
991997
}
992998

993999
None
9941000
}
9951001

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

10911098
ifletAggregateTy::Def(_, _) = ty
10921099
&& letSome(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
returnSome(value);
10961103
}
@@ -1765,7 +1772,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
17651772
ifletStatementKind::Assign(box (refmut lhs,refmut 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 = ifletSome(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+
fnoverlapping(_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:*mutAdt;
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+
fnmain(){
30+
overlapping(Adt::Some(0));
31+
}
32+
33+
enumAdt{
34+
None,
35+
Some(u32),
36+
}

0 commit comments

Comments
 (0)