Skip to content

Commit 895e215

Browse files
committed
Also propagate ScalarPair operands.
1 parent 12a2edd commit 895e215

7 files changed

+71
-90
lines changed

compiler/rustc_mir_transform/src/const_prop.rs

Lines changed: 59 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use rustc_middle::mir::visit::{
1414
};
1515
use rustc_middle::mir::*;
1616
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
17-
use rustc_middle::ty::GenericArgs;
18-
use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
17+
use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
1918
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
2019
use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
2120
use rustc_target::spec::abi::Abi as CallAbi;
@@ -434,24 +433,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
434433
}
435434

436435
fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
437-
match *operand {
438-
Operand::Copy(l) | Operand::Move(l) => {
439-
if let Some(value) = self.get_const(l) && self.should_const_prop(&value) {
440-
// FIXME(felix91gr): this code only handles `Scalar` cases.
441-
// For now, we're not handling `ScalarPair` cases because
442-
// doing so here would require a lot of code duplication.
443-
// We should hopefully generalize `Operand` handling into a fn,
444-
// and use it to do const-prop here and everywhere else
445-
// where it makes sense.
446-
if let interpret::Operand::Immediate(interpret::Immediate::Scalar(
447-
scalar,
448-
)) = *value
449-
{
450-
*operand = self.operand_from_scalar(scalar, value.layout.ty);
451-
}
452-
}
453-
}
454-
Operand::Constant(_) => (),
436+
if let Some(place) = operand.place() && let Some(op) = self.replace_with_const(place) {
437+
*operand = op;
455438
}
456439
}
457440

@@ -579,78 +562,63 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
579562
}))
580563
}
581564

582-
fn replace_with_const(&mut self, place: Place<'tcx>, rval: &mut Rvalue<'tcx>) {
565+
fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Operand<'tcx>> {
583566
// This will return None if the above `const_prop` invocation only "wrote" a
584567
// type whose creation requires no write. E.g. a generator whose initial state
585568
// consists solely of uninitialized memory (so it doesn't capture any locals).
586-
let Some(ref value) = self.get_const(place) else { return };
587-
if !self.should_const_prop(value) {
588-
return;
589-
}
590-
trace!("replacing {:?}={:?} with {:?}", place, rval, value);
591-
592-
if let Rvalue::Use(Operand::Constant(c)) = rval {
593-
match c.literal {
594-
ConstantKind::Ty(c) if matches!(c.kind(), ConstKind::Unevaluated(..)) => {}
595-
_ => {
596-
trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
597-
return;
598-
}
599-
}
569+
let value = self.get_const(place)?;
570+
if !self.should_const_prop(&value) {
571+
return None;
600572
}
573+
trace!("replacing {:?} with {:?}", place, value);
601574

602-
trace!("attempting to replace {:?} with {:?}", rval, value);
603575
// FIXME> figure out what to do when read_immediate_raw fails
604-
let imm = self.ecx.read_immediate_raw(value).ok();
576+
let imm = self.ecx.read_immediate_raw(&value).ok()?;
605577

606-
if let Some(Right(imm)) = imm {
607-
match *imm {
608-
interpret::Immediate::Scalar(scalar) => {
609-
*rval = Rvalue::Use(self.operand_from_scalar(scalar, value.layout.ty));
610-
}
611-
Immediate::ScalarPair(..) => {
612-
// Found a value represented as a pair. For now only do const-prop if the type
613-
// of `rvalue` is also a tuple with two scalars.
614-
// FIXME: enable the general case stated above ^.
615-
let ty = value.layout.ty;
616-
// Only do it for tuples
617-
if let ty::Tuple(types) = ty.kind() {
618-
// Only do it if tuple is also a pair with two scalars
619-
if let [ty1, ty2] = types[..] {
620-
let ty_is_scalar = |ty| {
621-
self.ecx.layout_of(ty).ok().map(|layout| layout.abi.is_scalar())
622-
== Some(true)
623-
};
624-
let alloc = if ty_is_scalar(ty1) && ty_is_scalar(ty2) {
625-
let alloc = self
626-
.ecx
627-
.intern_with_temp_alloc(value.layout, |ecx, dest| {
628-
ecx.write_immediate(*imm, dest)
629-
})
630-
.unwrap();
631-
Some(alloc)
632-
} else {
633-
None
634-
};
635-
636-
if let Some(alloc) = alloc {
637-
// Assign entire constant in a single statement.
638-
// We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
639-
let const_val = ConstValue::ByRef { alloc, offset: Size::ZERO };
640-
let literal = ConstantKind::Val(const_val, ty);
641-
*rval = Rvalue::Use(Operand::Constant(Box::new(Constant {
642-
span: DUMMY_SP,
643-
user_ty: None,
644-
literal,
645-
})));
646-
}
647-
}
648-
}
578+
let Right(imm) = imm else { return None };
579+
match *imm {
580+
interpret::Immediate::Scalar(scalar) => {
581+
Some(self.operand_from_scalar(scalar, value.layout.ty))
582+
}
583+
Immediate::ScalarPair(..) => {
584+
// Found a value represented as a pair. For now only do const-prop if the type
585+
// of `rvalue` is also a tuple with two scalars.
586+
// FIXME: enable the general case stated above ^.
587+
let ty = value.layout.ty;
588+
// Only do it for tuples
589+
let ty::Tuple(types) = ty.kind() else { return None };
590+
// Only do it if tuple is also a pair with two scalars
591+
if let [ty1, ty2] = types[..] {
592+
let ty_is_scalar = |ty| {
593+
self.ecx.layout_of(ty).ok().map(|layout| layout.abi.is_scalar())
594+
== Some(true)
595+
};
596+
let alloc = if ty_is_scalar(ty1) && ty_is_scalar(ty2) {
597+
self.ecx
598+
.intern_with_temp_alloc(value.layout, |ecx, dest| {
599+
ecx.write_immediate(*imm, dest)
600+
})
601+
.unwrap()
602+
} else {
603+
return None;
604+
};
605+
606+
// Assign entire constant in a single statement.
607+
// We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
608+
let const_val = ConstValue::ByRef { alloc, offset: Size::ZERO };
609+
let literal = ConstantKind::Val(const_val, ty);
610+
Some(Operand::Constant(Box::new(Constant {
611+
span: DUMMY_SP,
612+
user_ty: None,
613+
literal,
614+
})))
615+
} else {
616+
None
649617
}
650-
// Scalars or scalar pairs that contain undef values are assumed to not have
651-
// successfully evaluated and are thus not propagated.
652-
_ => {}
653618
}
619+
// Scalars or scalar pairs that contain undef values are assumed to not have
620+
// successfully evaluated and are thus not propagated.
621+
_ => None,
654622
}
655623
}
656624

@@ -847,7 +815,14 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
847815
ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local),
848816
ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {
849817
if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) {
850-
self.replace_with_const(*place, rvalue);
818+
// If this was already an evaluated constant, keep it.
819+
if let Rvalue::Use(Operand::Constant(c)) = rvalue
820+
&& let ConstantKind::Val(..) = c.literal
821+
{
822+
trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
823+
} else if let Some(operand) = self.replace_with_const(*place) {
824+
*rvalue = Rvalue::Use(operand);
825+
}
851826
} else {
852827
// Const prop failed, so erase the destination, ensuring that whatever happens
853828
// from here on, does not know about the previous value.

tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-abort.diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88

99
bb0: {
1010
StorageLive(_1);
11-
_1 = const _;
11+
- _1 = const _;
1212
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
13+
+ _1 = const false;
1314
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
1415
}
1516

tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88

99
bb0: {
1010
StorageLive(_1);
11-
_1 = const _;
11+
- _1 = const _;
1212
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
13+
+ _1 = const false;
1314
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
1415
}
1516

tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-abort.diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
StorageLive(_2);
1212
StorageLive(_3);
1313
- _3 = (const 1_u8, const 2_u8);
14+
- _2 = (move _3,);
1415
+ _3 = const (1_u8, 2_u8);
15-
_2 = (move _3,);
16+
+ _2 = (const (1_u8, 2_u8),);
1617
StorageDead(_3);
1718
_1 = test(move _2) -> [return: bb1, unwind unreachable];
1819
}

tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
StorageLive(_2);
1212
StorageLive(_3);
1313
- _3 = (const 1_u8, const 2_u8);
14+
- _2 = (move _3,);
1415
+ _3 = const (1_u8, 2_u8);
15-
_2 = (move _3,);
16+
+ _2 = (const (1_u8, 2_u8),);
1617
StorageDead(_3);
1718
_1 = test(move _2) -> [return: bb1, unwind continue];
1819
}

tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-abort.diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
StorageLive(_2);
1818
StorageLive(_3);
1919
- _3 = _1;
20+
- _2 = consume(move _3) -> [return: bb1, unwind unreachable];
2021
+ _3 = const (1_u32, 2_u32);
21-
_2 = consume(move _3) -> [return: bb1, unwind unreachable];
22+
+ _2 = consume(const (1_u32, 2_u32)) -> [return: bb1, unwind unreachable];
2223
}
2324

2425
bb1: {

tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
StorageLive(_2);
1818
StorageLive(_3);
1919
- _3 = _1;
20+
- _2 = consume(move _3) -> [return: bb1, unwind continue];
2021
+ _3 = const (1_u32, 2_u32);
21-
_2 = consume(move _3) -> [return: bb1, unwind continue];
22+
+ _2 = consume(const (1_u32, 2_u32)) -> [return: bb1, unwind continue];
2223
}
2324

2425
bb1: {

0 commit comments

Comments
 (0)