Skip to content

Commit fa4f9fd

Browse files
committed
Auto merge of rust-lang#127087 - cjgillot:small-map, r=<try>
Only track mentionned places for jump threading This PR aims to reduce the state space size in jump threading and dataflow const-prop opts. The current implementation walks the types of all locals, and creates a place for each possible projection. This can easily lead to a large number of places and tracked values, most being useless to the actual pass. With this PR, we instead collect places that appear syntactically in the MIR (first commit). However, this is not sufficient (second commit), and we miss places that we could track in aggregate assignments. The third commit tracks such assignments to mirror place projections, see the inline comment. This is complementary to rust-lang#127036 r? `@oli-obk`
2 parents 99f77a2 + 845d318 commit fa4f9fd

13 files changed

+506
-186
lines changed

compiler/rustc_mir_dataflow/src/value_analysis.rs

+221-122
Large diffs are not rendered by default.

compiler/rustc_mir_transform/src/dataflow_const_prop.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
6666
}
6767

6868
struct ConstAnalysis<'a, 'tcx> {
69-
map: Map,
69+
map: Map<'tcx>,
7070
tcx: TyCtxt<'tcx>,
7171
local_decls: &'a LocalDecls<'tcx>,
7272
ecx: InterpCx<'tcx, DummyMachine>,
@@ -78,7 +78,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
7878

7979
const NAME: &'static str = "ConstAnalysis";
8080

81-
fn map(&self) -> &Map {
81+
fn map(&self) -> &Map<'tcx> {
8282
&self.map
8383
}
8484

@@ -335,7 +335,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
335335
}
336336

337337
impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
338-
pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self {
338+
pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self {
339339
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
340340
Self {
341341
map,
@@ -565,12 +565,13 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
565565
Self { patch: Patch::new(tcx), local_decls }
566566
}
567567

568+
#[instrument(level = "trace", skip(self, ecx, map), ret)]
568569
fn try_make_constant(
569570
&self,
570571
ecx: &mut InterpCx<'tcx, DummyMachine>,
571572
place: Place<'tcx>,
572573
state: &State<FlatSet<Scalar>>,
573-
map: &Map,
574+
map: &Map<'tcx>,
574575
) -> Option<Const<'tcx>> {
575576
let ty = place.ty(self.local_decls, self.patch.tcx).ty;
576577
let layout = ecx.layout_of(ty).ok()?;
@@ -603,10 +604,11 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
603604
}
604605
}
605606

607+
#[instrument(level = "trace", skip(map), ret)]
606608
fn propagatable_scalar(
607609
place: PlaceIndex,
608610
state: &State<FlatSet<Scalar>>,
609-
map: &Map,
611+
map: &Map<'_>,
610612
) -> Option<Scalar> {
611613
if let FlatSet::Elem(value) = state.get_idx(place, map)
612614
&& value.try_to_scalar_int().is_ok()
@@ -618,14 +620,14 @@ fn propagatable_scalar(
618620
}
619621
}
620622

621-
#[instrument(level = "trace", skip(ecx, state, map))]
623+
#[instrument(level = "trace", skip(ecx, state, map), ret)]
622624
fn try_write_constant<'tcx>(
623625
ecx: &mut InterpCx<'tcx, DummyMachine>,
624626
dest: &PlaceTy<'tcx>,
625627
place: PlaceIndex,
626628
ty: Ty<'tcx>,
627629
state: &State<FlatSet<Scalar>>,
628-
map: &Map,
630+
map: &Map<'tcx>,
629631
) -> InterpResult<'tcx> {
630632
let layout = ecx.layout_of(ty)?;
631633

@@ -724,6 +726,7 @@ impl<'mir, 'tcx>
724726
{
725727
type FlowState = State<FlatSet<Scalar>>;
726728

729+
#[instrument(level = "trace", skip(self, results, statement))]
727730
fn visit_statement_before_primary_effect(
728731
&mut self,
729732
results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
@@ -745,6 +748,7 @@ impl<'mir, 'tcx>
745748
}
746749
}
747750

751+
#[instrument(level = "trace", skip(self, results, statement))]
748752
fn visit_statement_after_primary_effect(
749753
&mut self,
750754
results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
@@ -839,7 +843,7 @@ struct OperandCollector<'tcx, 'map, 'locals, 'a> {
839843
state: &'a State<FlatSet<Scalar>>,
840844
visitor: &'a mut Collector<'tcx, 'locals>,
841845
ecx: &'map mut InterpCx<'tcx, DummyMachine>,
842-
map: &'map Map,
846+
map: &'map Map<'tcx>,
843847
}
844848

845849
impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {

compiler/rustc_mir_transform/src/jump_threading.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ struct TOFinder<'tcx, 'a> {
157157
param_env: ty::ParamEnv<'tcx>,
158158
ecx: InterpCx<'tcx, DummyMachine>,
159159
body: &'a Body<'tcx>,
160-
map: &'a Map,
160+
map: &'a Map<'tcx>,
161161
loop_headers: &'a BitSet<BasicBlock>,
162162
/// We use an arena to avoid cloning the slices when cloning `state`.
163163
arena: &'a DroplessArena,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
- // MIR for `foo` before DataflowConstProp
2+
+ // MIR for `foo` after DataflowConstProp
3+
4+
fn foo() -> u32 {
5+
let mut _0: u32;
6+
let _1: (u32, u32);
7+
let mut _4: bool;
8+
let mut _5: u32;
9+
scope 1 {
10+
debug a => _1;
11+
let _2: (u32, u32);
12+
scope 2 {
13+
debug b => _2;
14+
let _3: u32;
15+
scope 3 {
16+
debug c => _3;
17+
}
18+
}
19+
}
20+
21+
bb0: {
22+
StorageLive(_1);
23+
_1 = const Foo;
24+
StorageLive(_2);
25+
- _2 = _1;
26+
+ _2 = const (5_u32, 3_u32);
27+
StorageLive(_3);
28+
- _3 = (_2.1: u32);
29+
+ _3 = const 3_u32;
30+
StorageLive(_4);
31+
StorageLive(_5);
32+
- _5 = _3;
33+
- _4 = Ge(move _5, const 2_u32);
34+
- switchInt(move _4) -> [0: bb2, otherwise: bb1];
35+
+ _5 = const 3_u32;
36+
+ _4 = const true;
37+
+ switchInt(const true) -> [0: bb2, otherwise: bb1];
38+
}
39+
40+
bb1: {
41+
StorageDead(_5);
42+
- _0 = (_2.0: u32);
43+
+ _0 = const 5_u32;
44+
goto -> bb3;
45+
}
46+
47+
bb2: {
48+
StorageDead(_5);
49+
_0 = const 13_u32;
50+
goto -> bb3;
51+
}
52+
53+
bb3: {
54+
StorageDead(_4);
55+
StorageDead(_3);
56+
StorageDead(_2);
57+
StorageDead(_1);
58+
return;
59+
}
60+
+ }
61+
+
62+
+ ALLOC0 (size: 8, align: 4) {
63+
+ 05 00 00 00 03 00 00 00 │ ........
64+
}
65+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning
2+
//! the contained scalars.
3+
//@ test-mir-pass: DataflowConstProp
4+
5+
const Foo: (u32, u32) = (5, 3);
6+
7+
fn foo() -> u32 {
8+
// CHECK-LABEL: fn foo(
9+
// CHECK: debug a => [[a:_.*]];
10+
// CHECK: debug b => [[b:_.*]];
11+
// CHECK: debug c => [[c:_.*]];
12+
13+
// CHECK:bb0: {
14+
// CHECK: [[a]] = const Foo;
15+
// CHECK: [[b]] = const (5_u32, 3_u32);
16+
// CHECK: [[c]] = const 3_u32;
17+
// CHECK: {{_.*}} = const 3_u32;
18+
// CHECK: {{_.*}} = const true;
19+
// CHECK: switchInt(const true) -> [0: bb2, otherwise: bb1];
20+
21+
// CHECK:bb1: {
22+
// CHECK: _0 = const 5_u32;
23+
// CHECK: goto -> bb3;
24+
25+
// CHECK:bb2: {
26+
// CHECK: _0 = const 13_u32;
27+
// CHECK: goto -> bb3;
28+
29+
let a = Foo;
30+
// This copies the struct in `a`. We want to ensure that we do track the contents of `a`
31+
// because we need to read `b` later.
32+
let b = a;
33+
let c = b.1;
34+
if c >= 2 { b.0 } else { 13 }
35+
}
36+
37+
fn main() {
38+
// CHECK-LABEL: fn main(
39+
foo();
40+
}
41+
42+
// EMIT_MIR aggregate_copy.foo.DataflowConstProp.diff

tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff

+5-24
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@
106106
- _7 = (_10.0: f32);
107107
+ _7 = const 4f32;
108108
StorageLive(_8);
109-
- _8 = (_10.1: std::option::Option<S>);
110-
+ _8 = const Option::<S>::Some(S(1_i32));
109+
_8 = (_10.1: std::option::Option<S>);
111110
StorageLive(_9);
112111
_9 = (_10.2: &[f32]);
113112
StorageDead(_10);
@@ -157,8 +156,7 @@
157156
+ _23 = const 82f32;
158157
StorageLive(_24);
159158
_37 = deref_copy (*_26);
160-
- _24 = ((*_37).1: std::option::Option<S>);
161-
+ _24 = const Option::<S>::Some(S(35_i32));
159+
_24 = ((*_37).1: std::option::Option<S>);
162160
StorageLive(_25);
163161
_38 = deref_copy (*_26);
164162
_25 = ((*_38).2: &[f32]);
@@ -168,12 +166,11 @@
168166
- _28 = _23;
169167
+ _28 = const 82f32;
170168
StorageLive(_29);
171-
- _29 = _24;
172-
+ _29 = const Option::<S>::Some(S(35_i32));
169+
_29 = _24;
173170
StorageLive(_30);
174171
_30 = _25;
175172
- _27 = BigStruct(move _28, move _29, move _30);
176-
+ _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
173+
+ _27 = BigStruct(const 82f32, move _29, move _30);
177174
StorageDead(_30);
178175
StorageDead(_29);
179176
StorageDead(_28);
@@ -199,23 +196,7 @@
199196
}
200197
+ }
201198
+
202-
+ ALLOC6 (size: 8, align: 4) {
203-
+ 01 00 00 00 23 00 00 00 │ ....#...
204-
+ }
205-
+
206-
+ ALLOC7 (size: 8, align: 4) {
207-
+ 01 00 00 00 23 00 00 00 │ ....#...
208-
+ }
209-
+
210-
+ ALLOC8 (size: 8, align: 4) {
211-
+ 01 00 00 00 23 00 00 00 │ ....#...
212-
+ }
213-
+
214-
+ ALLOC9 (size: 8, align: 4) {
215-
+ 01 00 00 00 01 00 00 00 │ ........
216-
+ }
217-
+
218-
+ ALLOC10 (size: 4, align: 4) {
199+
+ ALLOC6 (size: 4, align: 4) {
219200
+ 01 00 00 00 │ ....
220201
}
221202

tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff

+5-24
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@
106106
- _7 = (_10.0: f32);
107107
+ _7 = const 4f32;
108108
StorageLive(_8);
109-
- _8 = (_10.1: std::option::Option<S>);
110-
+ _8 = const Option::<S>::Some(S(1_i32));
109+
_8 = (_10.1: std::option::Option<S>);
111110
StorageLive(_9);
112111
_9 = (_10.2: &[f32]);
113112
StorageDead(_10);
@@ -157,8 +156,7 @@
157156
+ _23 = const 82f32;
158157
StorageLive(_24);
159158
_37 = deref_copy (*_26);
160-
- _24 = ((*_37).1: std::option::Option<S>);
161-
+ _24 = const Option::<S>::Some(S(35_i32));
159+
_24 = ((*_37).1: std::option::Option<S>);
162160
StorageLive(_25);
163161
_38 = deref_copy (*_26);
164162
_25 = ((*_38).2: &[f32]);
@@ -168,12 +166,11 @@
168166
- _28 = _23;
169167
+ _28 = const 82f32;
170168
StorageLive(_29);
171-
- _29 = _24;
172-
+ _29 = const Option::<S>::Some(S(35_i32));
169+
_29 = _24;
173170
StorageLive(_30);
174171
_30 = _25;
175172
- _27 = BigStruct(move _28, move _29, move _30);
176-
+ _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
173+
+ _27 = BigStruct(const 82f32, move _29, move _30);
177174
StorageDead(_30);
178175
StorageDead(_29);
179176
StorageDead(_28);
@@ -199,23 +196,7 @@
199196
}
200197
+ }
201198
+
202-
+ ALLOC6 (size: 8, align: 4) {
203-
+ 01 00 00 00 23 00 00 00 │ ....#...
204-
+ }
205-
+
206-
+ ALLOC7 (size: 8, align: 4) {
207-
+ 01 00 00 00 23 00 00 00 │ ....#...
208-
+ }
209-
+
210-
+ ALLOC8 (size: 8, align: 4) {
211-
+ 01 00 00 00 23 00 00 00 │ ....#...
212-
+ }
213-
+
214-
+ ALLOC9 (size: 8, align: 4) {
215-
+ 01 00 00 00 01 00 00 00 │ ........
216-
+ }
217-
+
218-
+ ALLOC10 (size: 4, align: 4) {
199+
+ ALLOC6 (size: 4, align: 4) {
219200
+ 01 00 00 00 │ ....
220201
}
221202

tests/mir-opt/dataflow-const-prop/struct.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fn main() {
4545
const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]);
4646

4747
// CHECK: [[a1]] = const 4f32;
48-
// CHECK: [[b1]] = const Option::<S>::Some(S(1_i32));
48+
// CHECK: [[b1]] = ({{_.*}}.1: std::option::Option<S>);
4949
// CHECK: [[c1]] = ({{_.*}}.2: &[f32]);
5050
let SmallStruct(a1, b1, c1) = SMALL_VAL;
5151

@@ -68,12 +68,12 @@ fn main() {
6868

6969
static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]);
7070
// CHECK: [[a4]] = const 82f32;
71-
// CHECK: [[b4]] = const Option::<S>::Some(S(35_i32));
71+
// CHECK: [[b4]] = ((*{{_.*}}).1: std::option::Option<S>);
7272
// CHECK: [[c4]] = ((*{{_.*}}).2: &[f32]);
7373
let BigStruct(a4, b4, c4) = *BIG_STAT;
7474

7575
// We arbitrarily limit the size of synthetized values to 4 pointers.
7676
// `BigStruct` can be read, but we will keep a MIR aggregate for this.
77-
// CHECK: [[bs]] = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move {{_.*}});
77+
// CHECK: [[bs]] = BigStruct(const 82f32, move {{.*}}, move {{_.*}});
7878
let bs = BigStruct(a4, b4, c4);
7979
}

tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff

+12-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,20 @@
77

88
bb0: {
99
StorageLive(_1);
10-
_1 = Less;
11-
_0 = move _1 as i8 (Transmute);
10+
- _1 = Less;
11+
- _0 = move _1 as i8 (Transmute);
12+
+ _1 = const Less;
13+
+ _0 = const std::cmp::Ordering::Less as i8 (Transmute);
1214
StorageDead(_1);
1315
return;
1416
}
17+
+ }
18+
+
19+
+ ALLOC0 (size: 1, align: 1) {
20+
+ ff │ .
21+
+ }
22+
+
23+
+ ALLOC1 (size: 1, align: 1) {
24+
+ ff │ .
1525
}
1626

0 commit comments

Comments
 (0)