Skip to content

Commit 8308505

Browse files
committed
Use MaybeUninitializedLocals analysis in GVN mir-opt to remove fewer storage statements
1 parent 6e41a60 commit 8308505

File tree

132 files changed

+999
-1329
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

132 files changed

+999
-1329
lines changed

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ use rustc_middle::mir::visit::*;
107107
use rustc_middle::mir::*;
108108
use rustc_middle::ty::layout::HasTypingEnv;
109109
use rustc_middle::ty::{self, Ty, TyCtxt};
110+
use rustc_mir_dataflow::impls::MaybeUninitializedLocals;
111+
use rustc_mir_dataflow::{Analysis, ResultsCursor};
110112
use rustc_span::DUMMY_SP;
111113
use smallvec::SmallVec;
112114
use tracing::{debug, instrument, trace};
@@ -142,10 +144,31 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
142144
state.visit_basic_block_data(bb, data);
143145
}
144146

145-
// For each local that is reused (`y` above), we remove its storage statements do avoid any
146-
// difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage
147-
// statements.
148-
StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body);
147+
// If we emit storage annotations, use `MaybeStorageDead` to check which reused locals
148+
// require storage removal (making them alive for the duration of the function).
149+
let storage_to_remove = if tcx.sess.emit_lifetime_markers() {
150+
let maybe_uninit = MaybeUninitializedLocals::new()
151+
.iterate_to_fixpoint(tcx, body, Some("mir_opt::gvn"))
152+
.into_results_cursor(body);
153+
154+
let mut storage_checker = StorageChecker {
155+
storage_to_check: state.reused_locals.clone(),
156+
storage_to_remove: DenseBitSet::new_empty(body.local_decls.len()),
157+
maybe_uninit,
158+
};
159+
160+
storage_checker.visit_body(body);
161+
162+
storage_checker.storage_to_remove
163+
} else {
164+
// Conservatively remove all storage statements for reused locals.
165+
state.reused_locals.clone()
166+
};
167+
168+
debug!(?storage_to_remove);
169+
170+
StorageRemover { tcx, reused_locals: state.reused_locals, storage_to_remove }
171+
.visit_body_preserves_cfg(body);
149172
}
150173

151174
fn is_required(&self) -> bool {
@@ -1855,6 +1878,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
18551878
struct StorageRemover<'tcx> {
18561879
tcx: TyCtxt<'tcx>,
18571880
reused_locals: DenseBitSet<Local>,
1881+
storage_to_remove: DenseBitSet<Local>,
18581882
}
18591883

18601884
impl<'tcx> MutVisitor<'tcx> for StorageRemover<'tcx> {
@@ -1875,11 +1899,48 @@ impl<'tcx> MutVisitor<'tcx> for StorageRemover<'tcx> {
18751899
match stmt.kind {
18761900
// When removing storage statements, we need to remove both (#107511).
18771901
StatementKind::StorageLive(l) | StatementKind::StorageDead(l)
1878-
if self.reused_locals.contains(l) =>
1902+
if self.storage_to_remove.contains(l) =>
18791903
{
18801904
stmt.make_nop(true)
18811905
}
18821906
_ => self.super_statement(stmt, loc),
18831907
}
18841908
}
18851909
}
1910+
1911+
struct StorageChecker<'a, 'tcx> {
1912+
storage_to_check: DenseBitSet<Local>,
1913+
storage_to_remove: DenseBitSet<Local>,
1914+
maybe_uninit: ResultsCursor<'a, 'tcx, MaybeUninitializedLocals>,
1915+
}
1916+
1917+
impl<'a, 'tcx> Visitor<'tcx> for StorageChecker<'a, 'tcx> {
1918+
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
1919+
match context {
1920+
// These mutating uses do not require the local to be initialized.
1921+
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput)
1922+
| PlaceContext::MutatingUse(MutatingUseContext::Call)
1923+
| PlaceContext::MutatingUse(MutatingUseContext::Store)
1924+
| PlaceContext::MutatingUse(MutatingUseContext::Yield)
1925+
| PlaceContext::NonUse(_) => {
1926+
return;
1927+
}
1928+
// Must check validity for other mutating usages and all non-mutating uses.
1929+
PlaceContext::MutatingUse(_) | PlaceContext::NonMutatingUse(_) => {}
1930+
}
1931+
1932+
if self.storage_to_check.contains(local) {
1933+
self.maybe_uninit.seek_before_primary_effect(location);
1934+
1935+
if self.maybe_uninit.get().contains(local) {
1936+
debug!(
1937+
?location,
1938+
?local,
1939+
"local is maybe uninit in this location, removing storage"
1940+
);
1941+
self.storage_to_remove.insert(local);
1942+
self.storage_to_check.remove(local);
1943+
}
1944+
}
1945+
}
1946+
}

tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@
5555
}
5656

5757
bb0: {
58-
nop;
58+
StorageLive(_1);
5959
- _1 = const 1_u8;
60-
nop;
61-
- _2 = const 2_u8;
62-
nop;
63-
- _3 = const 3_u8;
6460
+ nop;
61+
StorageLive(_2);
62+
- _2 = const 2_u8;
6563
+ nop;
64+
StorageLive(_3);
65+
- _3 = const 3_u8;
6666
+ nop;
6767
StorageLive(_4);
6868
StorageLive(_5);
@@ -95,7 +95,7 @@
9595
- _12 = const Point {{ x: 32_u32, y: 32_u32 }};
9696
+ nop;
9797
StorageLive(_13);
98-
nop;
98+
StorageLive(_14);
9999
- _14 = const 32_u32;
100100
+ nop;
101101
StorageLive(_15);
@@ -104,17 +104,17 @@
104104
+ nop;
105105
+ nop;
106106
StorageDead(_15);
107-
nop;
107+
StorageDead(_14);
108108
_0 = const ();
109109
StorageDead(_13);
110110
StorageDead(_12);
111111
StorageDead(_11);
112112
StorageDead(_10);
113113
StorageDead(_9);
114114
StorageDead(_4);
115-
nop;
116-
nop;
117-
nop;
115+
StorageDead(_3);
116+
StorageDead(_2);
117+
StorageDead(_1);
118118
return;
119119
}
120120
}

tests/mir-opt/const_prop/aggregate.main.GVN.panic-abort.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
}
1414

1515
bb0: {
16-
- StorageLive(_1);
17-
+ nop;
16+
StorageLive(_1);
1817
StorageLive(_2);
1918
StorageLive(_3);
2019
_3 = (const 0_i32, const 1_u8, const 2_i32);
@@ -36,8 +35,7 @@
3635
StorageDead(_5);
3736
StorageDead(_4);
3837
_0 = const ();
39-
- StorageDead(_1);
40-
+ nop;
38+
StorageDead(_1);
4139
return;
4240
}
4341
}

tests/mir-opt/const_prop/aggregate.main.GVN.panic-unwind.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
}
1414

1515
bb0: {
16-
- StorageLive(_1);
17-
+ nop;
16+
StorageLive(_1);
1817
StorageLive(_2);
1918
StorageLive(_3);
2019
_3 = (const 0_i32, const 1_u8, const 2_i32);
@@ -36,8 +35,7 @@
3635
StorageDead(_5);
3736
StorageDead(_4);
3837
_0 = const ();
39-
- StorageDead(_1);
40-
+ nop;
38+
StorageDead(_1);
4139
return;
4240
}
4341
}

tests/mir-opt/const_prop/bad_op_div_by_zero.main.GVN.panic-abort.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
}
1919

2020
bb0: {
21-
- StorageLive(_1);
22-
+ nop;
21+
StorageLive(_1);
2322
_1 = const 0_i32;
2423
StorageLive(_2);
2524
StorageLive(_3);
@@ -48,8 +47,7 @@
4847
StorageDead(_3);
4948
_0 = const ();
5049
StorageDead(_2);
51-
- StorageDead(_1);
52-
+ nop;
50+
StorageDead(_1);
5351
return;
5452
}
5553
}

tests/mir-opt/const_prop/bad_op_div_by_zero.main.GVN.panic-unwind.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
}
1919

2020
bb0: {
21-
- StorageLive(_1);
22-
+ nop;
21+
StorageLive(_1);
2322
_1 = const 0_i32;
2423
StorageLive(_2);
2524
StorageLive(_3);
@@ -48,8 +47,7 @@
4847
StorageDead(_3);
4948
_0 = const ();
5049
StorageDead(_2);
51-
- StorageDead(_1);
52-
+ nop;
50+
StorageDead(_1);
5351
return;
5452
}
5553
}

tests/mir-opt/const_prop/bad_op_mod_by_zero.main.GVN.panic-abort.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
}
1919

2020
bb0: {
21-
- StorageLive(_1);
22-
+ nop;
21+
StorageLive(_1);
2322
_1 = const 0_i32;
2423
StorageLive(_2);
2524
StorageLive(_3);
@@ -48,8 +47,7 @@
4847
StorageDead(_3);
4948
_0 = const ();
5049
StorageDead(_2);
51-
- StorageDead(_1);
52-
+ nop;
50+
StorageDead(_1);
5351
return;
5452
}
5553
}

tests/mir-opt/const_prop/bad_op_mod_by_zero.main.GVN.panic-unwind.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
}
1919

2020
bb0: {
21-
- StorageLive(_1);
22-
+ nop;
21+
StorageLive(_1);
2322
_1 = const 0_i32;
2423
StorageLive(_2);
2524
StorageLive(_3);
@@ -48,8 +47,7 @@
4847
StorageDead(_3);
4948
_0 = const ();
5049
StorageDead(_2);
51-
- StorageDead(_1);
52-
+ nop;
50+
StorageDead(_1);
5351
return;
5452
}
5553
}

tests/mir-opt/const_prop/boolean_identities.test.GVN.diff

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@
1919
}
2020

2121
bb0: {
22-
- StorageLive(_3);
23-
+ nop;
22+
StorageLive(_3);
2423
StorageLive(_4);
2524
_4 = copy _2;
2625
- _3 = BitOr(move _4, const true);
2726
+ _3 = const true;
2827
StorageDead(_4);
29-
- StorageLive(_5);
30-
+ nop;
28+
StorageLive(_5);
3129
StorageLive(_6);
3230
_6 = copy _1;
3331
- _5 = BitAnd(move _6, const false);
@@ -43,10 +41,8 @@
4341
+ _0 = const false;
4442
StorageDead(_8);
4543
StorageDead(_7);
46-
- StorageDead(_5);
47-
- StorageDead(_3);
48-
+ nop;
49-
+ nop;
44+
StorageDead(_5);
45+
StorageDead(_3);
5046
return;
5147
}
5248
}

tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818

1919
bb0: {
2020
StorageLive(_1);
21-
- StorageLive(_2);
22-
+ nop;
21+
StorageLive(_2);
2322
StorageLive(_3);
2423
- _4 = SizeOf(i32);
2524
- _5 = AlignOf(i32);
@@ -39,9 +38,8 @@
3938
_9 = copy ((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
4039
_2 = copy (*_9);
4140
- _1 = Add(move _2, const 0_i32);
42-
- StorageDead(_2);
4341
+ _1 = copy _2;
44-
+ nop;
42+
StorageDead(_2);
4543
drop(_3) -> [return: bb2, unwind unreachable];
4644
}
4745

0 commit comments

Comments
 (0)