Skip to content

Commit 556f29a

Browse files
committed
Auto merge of #67130 - wesleywiser:const_prop_into_locals, r=<try>
Const prop should finish propagation into user defined variables Fixes #66638 Temporarily rebased on top of #67015 to get those fixes. r? @oli-obk
2 parents 5c5c8eb + aff458f commit 556f29a

File tree

12 files changed

+331
-34
lines changed

12 files changed

+331
-34
lines changed

Diff for: src/librustc_mir/transform/const_prop.rs

+71-29
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.
@@ -636,19 +636,45 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
636636
ScalarMaybeUndef::Scalar(one),
637637
ScalarMaybeUndef::Scalar(two)
638638
) => {
639+
// Found a value represented as a pair. For now only do cont-prop if type of
640+
// Rvalue is also a pair with two scalars. The more general case is more
641+
// complicated to implement so we'll do it later.
639642
let ty = &value.layout.ty.kind;
643+
// Only do it for tuples
640644
if let ty::Tuple(substs) = ty {
641-
*rval = Rvalue::Aggregate(
642-
Box::new(AggregateKind::Tuple),
643-
vec![
644-
self.operand_from_scalar(
645-
one, substs[0].expect_ty(), source_info.span
646-
),
647-
self.operand_from_scalar(
648-
two, substs[1].expect_ty(), source_info.span
649-
),
650-
],
651-
);
645+
// Only do it if tuple is also a pair with two scalars
646+
if substs.len() == 2 {
647+
let opt_ty1_ty2 = self.use_ecx(source_info, |this| {
648+
let ty1 = substs[0].expect_ty();
649+
let ty2 = substs[1].expect_ty();
650+
let ty_is_scalar = |ty| {
651+
this.ecx
652+
.layout_of(ty)
653+
.ok()
654+
.map(|ty| ty.details.abi.is_scalar())
655+
== Some(true)
656+
};
657+
if ty_is_scalar(ty1) && ty_is_scalar(ty2) {
658+
Ok(Some((ty1, ty2)))
659+
} else {
660+
Ok(None)
661+
}
662+
});
663+
664+
if let Some(Some((ty1, ty2))) = opt_ty1_ty2 {
665+
*rval = Rvalue::Aggregate(
666+
Box::new(AggregateKind::Tuple),
667+
vec![
668+
self.operand_from_scalar(
669+
one, ty1, source_info.span
670+
),
671+
self.operand_from_scalar(
672+
two, ty2, source_info.span
673+
),
674+
],
675+
);
676+
}
677+
}
652678
}
653679
},
654680
_ => { }
@@ -682,17 +708,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
682708
}
683709
}
684710

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+
685722
struct CanConstProp {
686-
can_const_prop: IndexVec<Local, bool>,
723+
can_const_prop: IndexVec<Local, ConstPropMode>,
687724
// false at the beginning, once set, there are not allowed to be any more assignments
688725
found_assignment: IndexVec<Local, bool>,
689726
}
690727

691728
impl CanConstProp {
692729
/// returns true if `local` can be propagated
693-
fn check(body: ReadOnlyBodyCache<'_, '_>) -> IndexVec<Local, bool> {
730+
fn check(body: ReadOnlyBodyCache<'_, '_>) -> IndexVec<Local, ConstPropMode> {
694731
let mut cpv = CanConstProp {
695-
can_const_prop: IndexVec::from_elem(true, &body.local_decls),
732+
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
696733
found_assignment: IndexVec::from_elem(false, &body.local_decls),
697734
};
698735
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
@@ -702,10 +739,10 @@ impl CanConstProp {
702739
// FIXME(oli-obk): lint variables until they are used in a condition
703740
// FIXME(oli-obk): lint if return value is constant
704741
let local_kind = body.local_kind(local);
705-
*val = local_kind == LocalKind::Temp || local_kind == LocalKind::ReturnPointer;
706742

707-
if !*val {
708-
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);
709746
}
710747
}
711748
cpv.visit_body(body);
@@ -727,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
727764
// only occur in independent execution paths
728765
MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] {
729766
trace!("local {:?} can't be propagated because of multiple assignments", local);
730-
self.can_const_prop[local] = false;
767+
self.can_const_prop[local] = ConstPropMode::NoPropagation;
731768
} else {
732769
self.found_assignment[local] = true
733770
},
@@ -740,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
740777
NonUse(_) => {},
741778
_ => {
742779
trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
743-
self.can_const_prop[local] = false;
780+
self.can_const_prop[local] = ConstPropMode::NoPropagation;
744781
},
745782
}
746783
}
@@ -774,10 +811,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
774811
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
775812
if let Some(local) = place.as_local() {
776813
let source = statement.source_info;
814+
let can_const_prop = self.can_const_prop[local];
777815
if let Some(()) = self.const_prop(rval, place_layout, source, place) {
778-
if self.can_const_prop[local] {
779-
trace!("propagated into {:?}", local);
780-
816+
if can_const_prop == ConstPropMode::FullConstProp ||
817+
can_const_prop == ConstPropMode::OnlyPropagateInto {
781818
if let Some(value) = self.get_const(local) {
782819
if self.should_const_prop(value) {
783820
trace!("replacing {:?} with {:?}", rval, value);
@@ -786,21 +823,26 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
786823
value,
787824
statement.source_info,
788825
);
826+
827+
if can_const_prop == ConstPropMode::FullConstProp {
828+
trace!("propagated into {:?}", local);
829+
}
789830
}
790831
}
791-
} else {
792-
trace!("can't propagate into {:?}", local);
793-
if local != RETURN_PLACE {
794-
self.remove_const(local);
795-
}
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);
796838
}
797839
}
798840
}
799841
}
800842
} else {
801843
match statement.kind {
802844
StatementKind::StorageLive(local) |
803-
StatementKind::StorageDead(local) if self.can_const_prop[local] => {
845+
StatementKind::StorageDead(local) => {
804846
let frame = self.ecx.frame_mut();
805847
frame.locals[local].value =
806848
if let StatementKind::StorageLive(_) = statement.kind {

Diff for: src/librustc_target/abi/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,14 @@ impl Abi {
802802
_ => false,
803803
}
804804
}
805+
806+
/// Returns `true` is this is a scalar type
807+
pub fn is_scalar(&self) -> bool {
808+
match *self {
809+
Abi::Scalar(_) => true,
810+
_ => false,
811+
}
812+
}
805813
}
806814

807815
rustc_index::newtype_index! {

Diff for: 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

Diff for: 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
// }

Diff for: src/test/mir-opt/const_prop/issue-66971.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// compile-flags: -Z mir-opt-level=2
2+
3+
// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
4+
// outputs below, after ConstProp this is how _2 would look like with the bug:
5+
//
6+
// _2 = (const Scalar(0x00) : (), const 0u8);
7+
//
8+
// Which has the wrong type.
9+
10+
fn encode(this: ((), u8, u8)) {
11+
assert!(this.2 == 0);
12+
}
13+
14+
fn main() {
15+
encode(((), 0, 0));
16+
}
17+
18+
// END RUST SOURCE
19+
// START rustc.main.ConstProp.before.mir
20+
// bb0: {
21+
// ...
22+
// _3 = ();
23+
// _2 = (move _3, const 0u8, const 0u8);
24+
// ...
25+
// _1 = const encode(move _2) -> bb1;
26+
// ...
27+
// }
28+
// END rustc.main.ConstProp.before.mir
29+
// START rustc.main.ConstProp.after.mir
30+
// bb0: {
31+
// ...
32+
// _3 = const Scalar(<ZST>) : ();
33+
// _2 = (move _3, const 0u8, const 0u8);
34+
// ...
35+
// _1 = const encode(move _2) -> bb1;
36+
// ...
37+
// }
38+
// END rustc.main.ConstProp.after.mir

Diff for: src/test/mir-opt/const_prop/issue-67019.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// compile-flags: -Z mir-opt-level=2
2+
3+
// This used to ICE in const-prop
4+
5+
fn test(this: ((u8, u8),)) {
6+
assert!((this.0).0 == 1);
7+
}
8+
9+
fn main() {
10+
test(((1, 2),));
11+
}
12+
13+
// Important bit is parameter passing so we only check that below
14+
// END RUST SOURCE
15+
// START rustc.main.ConstProp.before.mir
16+
// bb0: {
17+
// ...
18+
// _3 = (const 1u8, const 2u8);
19+
// _2 = (move _3,);
20+
// ...
21+
// _1 = const test(move _2) -> bb1;
22+
// ...
23+
// }
24+
// END rustc.main.ConstProp.before.mir
25+
// START rustc.main.ConstProp.after.mir
26+
// bb0: {
27+
// ...
28+
// _3 = (const 1u8, const 2u8);
29+
// _2 = (move _3,);
30+
// ...
31+
// _1 = const test(move _2) -> bb1;
32+
// ...
33+
// }
34+
// END rustc.main.ConstProp.after.mir

0 commit comments

Comments
 (0)