Skip to content

Commit 57c4163

Browse files
committed
Remove an unnecessary restriction in dest_prop
1 parent 9ecd75b commit 57c4163

File tree

3 files changed

+20
-33
lines changed

3 files changed

+20
-33
lines changed

compiler/rustc_mir_transform/src/dest_prop.rs

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@
3838
//! It must also not contain any indexing projections, since those take an arbitrary `Local` as
3939
//! the index, and that local might only be initialized shortly before `dest` is used.
4040
//!
41-
//! Subtle case: If `dest` is a, or projects through a union, then we have to make sure that there
42-
//! remains an assignment to it, since that sets the "active field" of the union. But if `src` is
43-
//! a ZST, it might not be initialized, so there might not be any use of it before the assignment,
44-
//! and performing the optimization would simply delete the assignment, leaving `dest`
45-
//! uninitialized.
46-
//!
4741
//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Is this a
4842
//! fundamental restriction or just current impl state?). It can be copied or moved by the
4943
//! assignment.
@@ -103,7 +97,6 @@ use rustc_index::{
10397
bit_set::{BitMatrix, BitSet},
10498
vec::IndexVec,
10599
};
106-
use rustc_middle::mir::tcx::PlaceTy;
107100
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
108101
use rustc_middle::mir::{dump_mir, PassWhere};
109102
use rustc_middle::mir::{
@@ -135,7 +128,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
135128
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
136129
let def_id = body.source.def_id();
137130

138-
let candidates = find_candidates(tcx, body);
131+
let candidates = find_candidates(body);
139132
if candidates.is_empty() {
140133
debug!("{:?}: no dest prop candidates, done", def_id);
141134
return;
@@ -803,9 +796,8 @@ struct CandidateAssignment<'tcx> {
803796
/// comment) and also throw out assignments that involve a local that has its address taken or is
804797
/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate
805798
/// arbitrary places into array indices).
806-
fn find_candidates<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> Vec<CandidateAssignment<'tcx>> {
799+
fn find_candidates<'tcx>(body: &Body<'tcx>) -> Vec<CandidateAssignment<'tcx>> {
807800
let mut visitor = FindAssignments {
808-
tcx,
809801
body,
810802
candidates: Vec::new(),
811803
ever_borrowed_locals: ever_borrowed_locals(body),
@@ -816,7 +808,6 @@ fn find_candidates<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> Vec<CandidateA
816808
}
817809

818810
struct FindAssignments<'a, 'tcx> {
819-
tcx: TyCtxt<'tcx>,
820811
body: &'a Body<'tcx>,
821812
candidates: Vec<CandidateAssignment<'tcx>>,
822813
ever_borrowed_locals: BitSet<Local>,
@@ -845,10 +836,11 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
845836
return;
846837
}
847838

848-
// Can't optimize if both locals ever have their address taken (can introduce
849-
// aliasing).
850-
// FIXME: This can be smarter and take `StorageDead` into account (which
851-
// invalidates borrows).
839+
// Can't optimize if either local ever has their address taken. This optimization does
840+
// liveness analysis only based on assignments, and a local can be live even if its
841+
// never assigned to again, because a reference to it might be live.
842+
// FIXME: This can be smarter and take `StorageDead` into account (which invalidates
843+
// borrows).
852844
if self.ever_borrowed_locals.contains(dest.local)
853845
|| self.ever_borrowed_locals.contains(src.local)
854846
{
@@ -862,22 +854,11 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
862854
return;
863855
}
864856

865-
// Handle the "subtle case" described above by rejecting any `dest` that is or
866-
// projects through a union.
867-
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
868-
if place_ty.ty.is_union() {
869-
return;
870-
}
871857
for elem in dest.projection {
872858
if let PlaceElem::Index(_) = elem {
873859
// `dest` contains an indexing projection.
874860
return;
875861
}
876-
877-
place_ty = place_ty.projection_ty(self.tcx, elem);
878-
if place_ty.ty.is_union() {
879-
return;
880-
}
881862
}
882863

883864
self.candidates.push(CandidateAssignment {

src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,29 @@
1717
}
1818

1919
bb0: {
20-
StorageLive(_1); // scope 0 at $DIR/union.rs:13:9: 13:11
21-
StorageLive(_2); // scope 0 at $DIR/union.rs:13:23: 13:28
22-
_2 = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28
20+
- StorageLive(_1); // scope 0 at $DIR/union.rs:13:9: 13:11
21+
- StorageLive(_2); // scope 0 at $DIR/union.rs:13:23: 13:28
22+
- _2 = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28
23+
+ nop; // scope 0 at $DIR/union.rs:13:9: 13:11
24+
+ nop; // scope 0 at $DIR/union.rs:13:23: 13:28
25+
+ (_1.0: u32) = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28
2326
// mir::Constant
2427
// + span: $DIR/union.rs:13:23: 13:26
2528
// + literal: Const { ty: fn() -> u32 {val}, val: Value(Scalar(<ZST>)) }
2629
}
2730

2831
bb1: {
29-
(_1.0: u32) = move _2; // scope 0 at $DIR/union.rs:13:14: 13:30
30-
StorageDead(_2); // scope 0 at $DIR/union.rs:13:29: 13:30
32+
- (_1.0: u32) = move _2; // scope 0 at $DIR/union.rs:13:14: 13:30
33+
- StorageDead(_2); // scope 0 at $DIR/union.rs:13:29: 13:30
34+
+ nop; // scope 0 at $DIR/union.rs:13:14: 13:30
35+
+ nop; // scope 0 at $DIR/union.rs:13:29: 13:30
3136
StorageLive(_3); // scope 1 at $DIR/union.rs:15:5: 15:27
3237
StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26
3338
_4 = (_1.0: u32); // scope 2 at $DIR/union.rs:15:19: 15:24
3439
StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27
3540
StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28
36-
StorageDead(_1); // scope 0 at $DIR/union.rs:16:1: 16:2
41+
- StorageDead(_1); // scope 0 at $DIR/union.rs:16:1: 16:2
42+
+ nop; // scope 0 at $DIR/union.rs:16:1: 16:2
3743
return; // scope 0 at $DIR/union.rs:16:2: 16:2
3844
}
3945
}

src/test/mir-opt/dest-prop/union.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Tests that projections through unions cancel `DestinationPropagation`.
1+
//! Tests that we can propogate into places that are projections into unions
22
// compile-flags: -Zunsound-mir-opts
33
fn val() -> u32 {
44
1

0 commit comments

Comments
 (0)