Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 86927ed

Browse files
committed
Allow Locals to be propagated into and from, but restricted to their own block
1 parent 3fd2d4a commit 86927ed

File tree

10 files changed

+197
-32
lines changed

10 files changed

+197
-32
lines changed

src/librustc_mir/transform/const_prop.rs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ struct ConstPropagator<'mir, 'tcx> {
326326
// Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
327327
// the last known `SourceInfo` here and just keep revisiting it.
328328
source_info: Option<SourceInfo>,
329+
// Locals we need to forget at the end of the current block
330+
locals_of_current_block: BitSet<Local>,
329331
}
330332

331333
impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
@@ -395,6 +397,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
395397
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
396398
local_decls: body.local_decls.clone(),
397399
source_info: None,
400+
locals_of_current_block: BitSet::new_empty(body.local_decls.len()),
398401
}
399402
}
400403

@@ -409,8 +412,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
409412
}
410413
}
411414

412-
fn remove_const(&mut self, local: Local) {
413-
self.ecx.frame_mut().locals[local] =
415+
/// Remove `local` from the pool of `Locals`. Allows writing to them,
416+
/// but not reading from them anymore.
417+
fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
418+
ecx.frame_mut().locals[local] =
414419
LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
415420
}
416421

@@ -756,6 +761,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
756761
enum ConstPropMode {
757762
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
758763
FullConstProp,
764+
/// The `Local` can only be propagated into and from its own block.
765+
OnlyInsideOwnBlock,
759766
/// The `Local` can be propagated into but reads cannot be propagated.
760767
OnlyPropagateInto,
761768
/// No propagation is allowed at all.
@@ -787,10 +794,18 @@ impl CanConstProp {
787794
// lint for x != y
788795
// FIXME(oli-obk): lint variables until they are used in a condition
789796
// FIXME(oli-obk): lint if return value is constant
790-
if cpv.local_kinds[local] == LocalKind::Arg || cpv.local_kinds[local] == LocalKind::Var
791-
{
797+
if cpv.local_kinds[local] == LocalKind::Arg {
792798
*val = ConstPropMode::OnlyPropagateInto;
793-
trace!("local {:?} can't be const propagated because it's not a temporary", local);
799+
trace!(
800+
"local {:?} can't be const propagated because it's a function argument",
801+
local
802+
);
803+
} else if cpv.local_kinds[local] == LocalKind::Var {
804+
*val = ConstPropMode::OnlyInsideOwnBlock;
805+
trace!(
806+
"local {:?} will only be propagated inside its block, because it's a user variable",
807+
local
808+
);
794809
}
795810
}
796811
cpv.visit_body(&body);
@@ -858,25 +873,35 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
858873
if let Some(local) = place.as_local() {
859874
let can_const_prop = self.can_const_prop[local];
860875
if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
861-
if can_const_prop == ConstPropMode::FullConstProp
862-
|| can_const_prop == ConstPropMode::OnlyPropagateInto
863-
{
876+
if can_const_prop != ConstPropMode::NoPropagation {
877+
// This will return None for Locals that are from other blocks,
878+
// so it should be okay to propagate from here on down.
864879
if let Some(value) = self.get_const(local) {
865880
if self.should_const_prop(value) {
866881
trace!("replacing {:?} with {:?}", rval, value);
867882
self.replace_with_const(rval, value, statement.source_info);
868-
869-
if can_const_prop == ConstPropMode::FullConstProp {
883+
if can_const_prop == ConstPropMode::FullConstProp
884+
|| can_const_prop == ConstPropMode::OnlyInsideOwnBlock
885+
{
870886
trace!("propagated into {:?}", local);
871887
}
872888
}
889+
if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
890+
trace!(
891+
"found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
892+
local
893+
);
894+
self.locals_of_current_block.insert(local);
895+
}
873896
}
874897
}
875898
}
876-
if self.can_const_prop[local] != ConstPropMode::FullConstProp {
899+
if self.can_const_prop[local] == ConstPropMode::OnlyPropagateInto
900+
|| self.can_const_prop[local] == ConstPropMode::NoPropagation
901+
{
877902
trace!("can't propagate into {:?}", local);
878903
if local != RETURN_PLACE {
879-
self.remove_const(local);
904+
Self::remove_const(&mut self.ecx, local);
880905
}
881906
}
882907
}
@@ -915,7 +940,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
915940
// doesn't use the invalid value
916941
match cond {
917942
Operand::Move(ref place) | Operand::Copy(ref place) => {
918-
self.remove_const(place.local);
943+
Self::remove_const(&mut self.ecx, place.local);
919944
}
920945
Operand::Constant(_) => {}
921946
}
@@ -992,5 +1017,13 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
9921017
//FIXME(wesleywiser) Call does have Operands that could be const-propagated
9931018
TerminatorKind::Call { .. } => {}
9941019
}
1020+
// We remove all Locals which are restricted in propagation to their containing blocks.
1021+
// We wouldn't need to clone, but the borrow checker can't see that we're not aliasing
1022+
// the locals_of_current_block field, so we need to clone it first.
1023+
// let ecx = &mut self.ecx;
1024+
for local in self.locals_of_current_block.iter() {
1025+
Self::remove_const(&mut self.ecx, local);
1026+
}
1027+
self.locals_of_current_block.clear();
9951028
}
9961029
}

src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@
2121
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
2222
StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
2323
StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
24-
_3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
24+
- _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
25+
+ _3 = const 1u32; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
26+
+ // ty::Const
27+
+ // + ty: u32
28+
+ // + val: Value(Scalar(0x00000001))
29+
+ // mir::Constant
30+
+ // + span: $DIR/scalar_literal_propagation.rs:4:13: 4:14
31+
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
2532
_2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
2633
// ty::Const
2734
// + ty: fn(u32) {consume}

src/test/mir-opt/const_prop/tuple_literal_propagation/rustc.main.ConstProp.diff

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,20 @@
2929
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
3030
StorageLive(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
3131
StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
32-
_3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
32+
- _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
33+
+ _3 = (const 1u32, const 2u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
34+
+ // ty::Const
35+
+ // + ty: u32
36+
+ // + val: Value(Scalar(0x00000001))
37+
+ // mir::Constant
38+
+ // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14
39+
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
40+
+ // ty::Const
41+
+ // + ty: u32
42+
+ // + val: Value(Scalar(0x00000002))
43+
+ // mir::Constant
44+
+ // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14
45+
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
3346
_2 = const consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
3447
// ty::Const
3548
// + ty: fn((u32, u32)) {consume}

src/test/mir-opt/simplify-arm-identity.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Regression test for issue #66856.
33
//
44
// compile-flags: -Zmir-opt-level=2
5+
// EMIT_MIR_FOR_EACH_BIT_WIDTH
56

67
enum Src {
78
Foo(u8),
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
- // MIR for `main` before SimplifyArmIdentity
2+
+ // MIR for `main` after SimplifyArmIdentity
3+
4+
fn main() -> () {
5+
let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11
6+
let _1: Src as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
7+
let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6
8+
let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20
9+
let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34
10+
scope 1 {
11+
debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:18:9: 18:10
12+
let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
13+
scope 2 {
14+
}
15+
scope 3 {
16+
debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:20:18: 20:19
17+
}
18+
}
19+
20+
bb0: {
21+
StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
22+
((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
23+
// ty::Const
24+
// + ty: u8
25+
// + val: Value(Scalar(0x00))
26+
// mir::Constant
27+
// + span: $DIR/simplify-arm-identity.rs:18:27: 18:28
28+
// + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
29+
discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
30+
StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
31+
_3 = const 0isize; // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
32+
// ty::Const
33+
// + ty: isize
34+
// + val: Value(Scalar(0x00000000))
35+
// mir::Constant
36+
// + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
37+
// + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
38+
_4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
39+
((_2 as Foo).0: u8) = move _4; // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
40+
discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
41+
StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
42+
_0 = const (); // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
43+
// ty::Const
44+
// + ty: ()
45+
// + val: Value(Scalar(<ZST>))
46+
// mir::Constant
47+
// + span: $DIR/simplify-arm-identity.rs:17:11: 23:2
48+
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
49+
StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2
50+
return; // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2
51+
}
52+
}
53+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
- // MIR for `main` before SimplifyArmIdentity
2+
+ // MIR for `main` after SimplifyArmIdentity
3+
4+
fn main() -> () {
5+
let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11
6+
let _1: Src as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
7+
let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6
8+
let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20
9+
let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34
10+
scope 1 {
11+
debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:18:9: 18:10
12+
let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
13+
scope 2 {
14+
}
15+
scope 3 {
16+
debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:20:18: 20:19
17+
}
18+
}
19+
20+
bb0: {
21+
StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
22+
((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
23+
// ty::Const
24+
// + ty: u8
25+
// + val: Value(Scalar(0x00))
26+
// mir::Constant
27+
// + span: $DIR/simplify-arm-identity.rs:18:27: 18:28
28+
// + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
29+
discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
30+
StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
31+
_3 = const 0isize; // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
32+
// ty::Const
33+
// + ty: isize
34+
// + val: Value(Scalar(0x0000000000000000))
35+
// mir::Constant
36+
// + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
37+
// + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
38+
_4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
39+
((_2 as Foo).0: u8) = move _4; // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
40+
discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
41+
StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
42+
_0 = const (); // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
43+
// ty::Const
44+
// + ty: ()
45+
// + val: Value(Scalar(<ZST>))
46+
// mir::Constant
47+
// + span: $DIR/simplify-arm-identity.rs:17:11: 23:2
48+
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
49+
StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2
50+
return; // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2
51+
}
52+
}
53+

0 commit comments

Comments
 (0)