Skip to content

Commit 364ecf5

Browse files
authored
Rollup merge of rust-lang#67130 - wesleywiser:const_prop_into_locals, r=oli-obk
Const prop should finish propagation into user defined variables Fixes rust-lang#66638 ~~Temporarily rebased on top of rust-lang#67015 to get those fixes.~~ r? @oli-obk
2 parents 01a4650 + 0745b8c commit 364ecf5

File tree

6 files changed

+187
-22
lines changed

6 files changed

+187
-22
lines changed

src/librustc_mir/transform/const_prop.rs

+34-18
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
262262
ecx: InterpCx<'mir, 'tcx, ConstPropMachine>,
263263
tcx: TyCtxt<'tcx>,
264264
source: MirSource<'tcx>,
265-
can_const_prop: IndexVec<Local, bool>,
265+
can_const_prop: IndexVec<Local, ConstPropMode>,
266266
param_env: ParamEnv<'tcx>,
267267
// FIXME(eddyb) avoid cloning these two fields more than once,
268268
// by accessing them through `ecx` instead.
@@ -708,17 +708,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
708708
}
709709
}
710710

711+
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
712+
#[derive(Clone, Copy, Debug, PartialEq)]
713+
enum ConstPropMode {
714+
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
715+
FullConstProp,
716+
/// The `Local` can be propagated into but reads cannot be propagated.
717+
OnlyPropagateInto,
718+
/// No propagation is allowed at all.
719+
NoPropagation,
720+
}
721+
711722
struct CanConstProp {
712-
can_const_prop: IndexVec<Local, bool>,
723+
can_const_prop: IndexVec<Local, ConstPropMode>,
713724
// false at the beginning, once set, there are not allowed to be any more assignments
714725
found_assignment: IndexVec<Local, bool>,
715726
}
716727

717728
impl CanConstProp {
718729
/// returns true if `local` can be propagated
719-
fn check(body: ReadOnlyBodyAndCache<'_, '_>) -> IndexVec<Local, bool> {
730+
fn check(body: ReadOnlyBodyAndCache<'_, '_>) -> IndexVec<Local, ConstPropMode> {
720731
let mut cpv = CanConstProp {
721-
can_const_prop: IndexVec::from_elem(true, &body.local_decls),
732+
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
722733
found_assignment: IndexVec::from_elem(false, &body.local_decls),
723734
};
724735
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
@@ -728,10 +739,10 @@ impl CanConstProp {
728739
// FIXME(oli-obk): lint variables until they are used in a condition
729740
// FIXME(oli-obk): lint if return value is constant
730741
let local_kind = body.local_kind(local);
731-
*val = local_kind == LocalKind::Temp || local_kind == LocalKind::ReturnPointer;
732742

733-
if !*val {
734-
trace!("local {:?} can't be propagated because it's not a temporary", local);
743+
if local_kind == LocalKind::Arg || local_kind == LocalKind::Var {
744+
*val = ConstPropMode::OnlyPropagateInto;
745+
trace!("local {:?} can't be const propagated because it's not a temporary", local);
735746
}
736747
}
737748
cpv.visit_body(body);
@@ -753,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
753764
// only occur in independent execution paths
754765
MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] {
755766
trace!("local {:?} can't be propagated because of multiple assignments", local);
756-
self.can_const_prop[local] = false;
767+
self.can_const_prop[local] = ConstPropMode::NoPropagation;
757768
} else {
758769
self.found_assignment[local] = true
759770
},
@@ -766,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
766777
NonUse(_) => {},
767778
_ => {
768779
trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
769-
self.can_const_prop[local] = false;
780+
self.can_const_prop[local] = ConstPropMode::NoPropagation;
770781
},
771782
}
772783
}
@@ -800,10 +811,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
800811
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
801812
if let Some(local) = place.as_local() {
802813
let source = statement.source_info;
814+
let can_const_prop = self.can_const_prop[local];
803815
if let Some(()) = self.const_prop(rval, place_layout, source, place) {
804-
if self.can_const_prop[local] {
805-
trace!("propagated into {:?}", local);
806-
816+
if can_const_prop == ConstPropMode::FullConstProp ||
817+
can_const_prop == ConstPropMode::OnlyPropagateInto {
807818
if let Some(value) = self.get_const(local) {
808819
if self.should_const_prop(value) {
809820
trace!("replacing {:?} with {:?}", rval, value);
@@ -812,21 +823,26 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
812823
value,
813824
statement.source_info,
814825
);
826+
827+
if can_const_prop == ConstPropMode::FullConstProp {
828+
trace!("propagated into {:?}", local);
829+
}
815830
}
816831
}
817-
} else {
818-
trace!("can't propagate into {:?}", local);
819-
if local != RETURN_PLACE {
820-
self.remove_const(local);
821-
}
832+
}
833+
}
834+
if self.can_const_prop[local] != ConstPropMode::FullConstProp {
835+
trace!("can't propagate into {:?}", local);
836+
if local != RETURN_PLACE {
837+
self.remove_const(local);
822838
}
823839
}
824840
}
825841
}
826842
} else {
827843
match statement.kind {
828844
StatementKind::StorageLive(local) |
829-
StatementKind::StorageDead(local) if self.can_const_prop[local] => {
845+
StatementKind::StorageDead(local) => {
830846
let frame = self.ecx.frame_mut();
831847
frame.locals[local].value =
832848
if let StatementKind::StorageLive(_) = statement.kind {

src/test/mir-opt/const_prop/aggregate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn main() {
1919
// ...
2020
// _3 = (const 0i32, const 1i32, const 2i32);
2121
// _2 = const 1i32;
22-
// _1 = Add(move _2, const 0i32);
22+
// _1 = const 1i32;
2323
// ...
2424
// }
2525
// END rustc.main.ConstProp.after.mir

src/test/mir-opt/const_prop/array_index.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn main() {
2626
// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
2727
// }
2828
// bb1: {
29-
// _1 = _2[_3];
29+
// _1 = const 2u32;
3030
// ...
3131
// return;
3232
// }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// compile-flags: -C overflow-checks=on
2+
3+
struct Point {
4+
x: u32,
5+
y: u32,
6+
}
7+
8+
fn main() {
9+
let x = 2 + 2;
10+
let y = [0, 1, 2, 3, 4, 5][3];
11+
let z = (Point { x: 12, y: 42}).y;
12+
}
13+
14+
// END RUST SOURCE
15+
// START rustc.main.ConstProp.before.mir
16+
// let mut _0: ();
17+
// let _1: i32;
18+
// let mut _2: (i32, bool);
19+
// let mut _4: [i32; 6];
20+
// let _5: usize;
21+
// let mut _6: usize;
22+
// let mut _7: bool;
23+
// let mut _9: Point;
24+
// scope 1 {
25+
// debug x => _1;
26+
// let _3: i32;
27+
// scope 2 {
28+
// debug y => _3;
29+
// let _8: u32;
30+
// scope 3 {
31+
// debug z => _8;
32+
// }
33+
// }
34+
// }
35+
// bb0: {
36+
// StorageLive(_1);
37+
// _2 = CheckedAdd(const 2i32, const 2i32);
38+
// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
39+
// }
40+
// bb1: {
41+
// _1 = move (_2.0: i32);
42+
// StorageLive(_3);
43+
// StorageLive(_4);
44+
// _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
45+
// StorageLive(_5);
46+
// _5 = const 3usize;
47+
// _6 = const 6usize;
48+
// _7 = Lt(_5, _6);
49+
// assert(move _7, "index out of bounds: the len is move _6 but the index is _5") -> bb2;
50+
// }
51+
// bb2: {
52+
// _3 = _4[_5];
53+
// StorageDead(_5);
54+
// StorageDead(_4);
55+
// StorageLive(_8);
56+
// StorageLive(_9);
57+
// _9 = Point { x: const 12u32, y: const 42u32 };
58+
// _8 = (_9.1: u32);
59+
// StorageDead(_9);
60+
// _0 = ();
61+
// StorageDead(_8);
62+
// StorageDead(_3);
63+
// StorageDead(_1);
64+
// return;
65+
// }
66+
// END rustc.main.ConstProp.before.mir
67+
// START rustc.main.ConstProp.after.mir
68+
// let mut _0: ();
69+
// let _1: i32;
70+
// let mut _2: (i32, bool);
71+
// let mut _4: [i32; 6];
72+
// let _5: usize;
73+
// let mut _6: usize;
74+
// let mut _7: bool;
75+
// let mut _9: Point;
76+
// scope 1 {
77+
// debug x => _1;
78+
// let _3: i32;
79+
// scope 2 {
80+
// debug y => _3;
81+
// let _8: u32;
82+
// scope 3 {
83+
// debug z => _8;
84+
// }
85+
// }
86+
// }
87+
// bb0: {
88+
// StorageLive(_1);
89+
// _2 = (const 4i32, const false);
90+
// assert(!const false, "attempt to add with overflow") -> bb1;
91+
// }
92+
// bb1: {
93+
// _1 = const 4i32;
94+
// StorageLive(_3);
95+
// StorageLive(_4);
96+
// _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
97+
// StorageLive(_5);
98+
// _5 = const 3usize;
99+
// _6 = const 6usize;
100+
// _7 = const true;
101+
// assert(const true, "index out of bounds: the len is move _6 but the index is _5") -> bb2;
102+
// }
103+
// bb2: {
104+
// _3 = const 3i32;
105+
// StorageDead(_5);
106+
// StorageDead(_4);
107+
// StorageLive(_8);
108+
// StorageLive(_9);
109+
// _9 = Point { x: const 12u32, y: const 42u32 };
110+
// _8 = const 42u32;
111+
// StorageDead(_9);
112+
// _0 = ();
113+
// StorageDead(_8);
114+
// StorageDead(_3);
115+
// StorageDead(_1);
116+
// return;
117+
// }
118+
// END rustc.main.ConstProp.after.mir
119+
// START rustc.main.SimplifyLocals.after.mir
120+
// let mut _0: ();
121+
// let _1: i32;
122+
// let mut _3: [i32; 6];
123+
// scope 1 {
124+
// debug x => _1;
125+
// let _2: i32;
126+
// scope 2 {
127+
// debug y => _2;
128+
// let _4: u32;
129+
// scope 3 {
130+
// debug z => _4;
131+
// }
132+
// }
133+
// }
134+
// bb0: {
135+
// StorageLive(_1);
136+
// _1 = const 4i32;
137+
// StorageLive(_2);
138+
// StorageLive(_3);
139+
// _3 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
140+
// _2 = const 3i32;
141+
// StorageDead(_3);
142+
// StorageLive(_4);
143+
// _4 = const 42u32;
144+
// StorageDead(_4);
145+
// StorageDead(_2);
146+
// StorageDead(_1);
147+
// return;
148+
// }
149+
// END rustc.main.SimplifyLocals.after.mir

src/test/mir-opt/const_prop/read_immutable_static.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn main() {
2525
// _2 = const 2u8;
2626
// ...
2727
// _4 = const 2u8;
28-
// _1 = Add(move _2, move _4);
28+
// _1 = const 4u8;
2929
// ...
3030
// }
3131
// END rustc.main.ConstProp.after.mir

src/test/mir-opt/const_prop/repeat.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn main() {
3030
// }
3131
// bb1: {
3232
// _2 = const 42u32;
33-
// _1 = Add(move _2, const 0u32);
33+
// _1 = const 42u32;
3434
// ...
3535
// return;
3636
// }

0 commit comments

Comments
 (0)