Auto merge of #115796 - cjgillot:const-prop-rvalue, r=oli-obk

Generate aggregate constants in DataflowConstProp.
This commit is contained in:
bors 2023-10-24 21:47:53 +00:00
commit df871fbf05
23 changed files with 797 additions and 170 deletions

View File

@ -2,13 +2,13 @@
//!
//! Currently, this pass only propagates scalar values.
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::value_analysis::{
Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
@ -16,8 +16,9 @@ use rustc_mir_dataflow::value_analysis::{
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
use rustc_span::def_id::DefId;
use rustc_span::DUMMY_SP;
use rustc_target::abi::{FieldIdx, VariantIdx};
use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
use crate::const_prop::throw_machine_stop_str;
use crate::MirPass;
// These constants are somewhat random guesses and have not been optimized.
@ -553,18 +554,153 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
fn try_make_constant(
&self,
ecx: &mut InterpCx<'tcx, 'tcx, DummyMachine>,
place: Place<'tcx>,
state: &State<FlatSet<Scalar>>,
map: &Map,
) -> Option<Const<'tcx>> {
let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
return None;
};
let ty = place.ty(self.local_decls, self.patch.tcx).ty;
Some(Const::Val(ConstValue::Scalar(value.into()), ty))
let layout = ecx.layout_of(ty).ok()?;
if layout.is_zst() {
return Some(Const::zero_sized(ty));
}
if layout.is_unsized() {
return None;
}
let place = map.find(place.as_ref())?;
if layout.abi.is_scalar()
&& let Some(value) = propagatable_scalar(place, state, map)
{
return Some(Const::Val(ConstValue::Scalar(value), ty));
}
if matches!(layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
let alloc_id = ecx
.intern_with_temp_alloc(layout, |ecx, dest| {
try_write_constant(ecx, dest, place, ty, state, map)
})
.ok()?;
return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty));
}
None
}
}
fn propagatable_scalar(
place: PlaceIndex,
state: &State<FlatSet<Scalar>>,
map: &Map,
) -> Option<Scalar> {
if let FlatSet::Elem(value) = state.get_idx(place, map) && value.try_to_int().is_ok() {
// Do not attempt to propagate pointers, as we may fail to preserve their identity.
Some(value)
} else {
None
}
}
#[instrument(level = "trace", skip(ecx, state, map))]
fn try_write_constant<'tcx>(
ecx: &mut InterpCx<'_, 'tcx, DummyMachine>,
dest: &PlaceTy<'tcx>,
place: PlaceIndex,
ty: Ty<'tcx>,
state: &State<FlatSet<Scalar>>,
map: &Map,
) -> InterpResult<'tcx> {
let layout = ecx.layout_of(ty)?;
// Fast path for ZSTs.
if layout.is_zst() {
return Ok(());
}
// Fast path for scalars.
if layout.abi.is_scalar()
&& let Some(value) = propagatable_scalar(place, state, map)
{
return ecx.write_immediate(Immediate::Scalar(value), dest);
}
match ty.kind() {
// ZSTs. Nothing to do.
ty::FnDef(..) => {}
// Those are scalars, must be handled above.
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => throw_machine_stop_str!("primitive type with provenance"),
ty::Tuple(elem_tys) => {
for (i, elem) in elem_tys.iter().enumerate() {
let Some(field) = map.apply(place, TrackElem::Field(FieldIdx::from_usize(i))) else {
throw_machine_stop_str!("missing field in tuple")
};
let field_dest = ecx.project_field(dest, i)?;
try_write_constant(ecx, &field_dest, field, elem, state, map)?;
}
}
ty::Adt(def, args) => {
if def.is_union() {
throw_machine_stop_str!("cannot propagate unions")
}
let (variant_idx, variant_def, variant_place, variant_dest) = if def.is_enum() {
let Some(discr) = map.apply(place, TrackElem::Discriminant) else {
throw_machine_stop_str!("missing discriminant for enum")
};
let FlatSet::Elem(Scalar::Int(discr)) = state.get_idx(discr, map) else {
throw_machine_stop_str!("discriminant with provenance")
};
let discr_bits = discr.assert_bits(discr.size());
let Some((variant, _)) = def.discriminants(*ecx.tcx).find(|(_, var)| discr_bits == var.val) else {
throw_machine_stop_str!("illegal discriminant for enum")
};
let Some(variant_place) = map.apply(place, TrackElem::Variant(variant)) else {
throw_machine_stop_str!("missing variant for enum")
};
let variant_dest = ecx.project_downcast(dest, variant)?;
(variant, def.variant(variant), variant_place, variant_dest)
} else {
(FIRST_VARIANT, def.non_enum_variant(), place, dest.clone())
};
for (i, field) in variant_def.fields.iter_enumerated() {
let ty = field.ty(*ecx.tcx, args);
let Some(field) = map.apply(variant_place, TrackElem::Field(i)) else {
throw_machine_stop_str!("missing field in ADT")
};
let field_dest = ecx.project_field(&variant_dest, i.as_usize())?;
try_write_constant(ecx, &field_dest, field, ty, state, map)?;
}
ecx.write_discriminant(variant_idx, dest)?;
}
// Unsupported for now.
ty::Array(_, _)
// Do not attempt to support indirection in constants.
| ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_)
| ty::Never
| ty::Foreign(..)
| ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Closure(..)
| ty::Coroutine(..)
| ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"),
ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(),
}
Ok(())
}
impl<'mir, 'tcx>
ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
for Collector<'tcx, '_>
@ -580,8 +716,13 @@ impl<'mir, 'tcx>
) {
match &statement.kind {
StatementKind::Assign(box (_, rvalue)) => {
OperandCollector { state, visitor: self, map: &results.analysis.0.map }
.visit_rvalue(rvalue, location);
OperandCollector {
state,
visitor: self,
ecx: &mut results.analysis.0.ecx,
map: &results.analysis.0.map,
}
.visit_rvalue(rvalue, location);
}
_ => (),
}
@ -599,7 +740,12 @@ impl<'mir, 'tcx>
// Don't overwrite the assignment if it already uses a constant (to keep the span).
}
StatementKind::Assign(box (place, _)) => {
if let Some(value) = self.try_make_constant(place, state, &results.analysis.0.map) {
if let Some(value) = self.try_make_constant(
&mut results.analysis.0.ecx,
place,
state,
&results.analysis.0.map,
) {
self.patch.assignments.insert(location, value);
}
}
@ -614,8 +760,13 @@ impl<'mir, 'tcx>
terminator: &'mir Terminator<'tcx>,
location: Location,
) {
OperandCollector { state, visitor: self, map: &results.analysis.0.map }
.visit_terminator(terminator, location);
OperandCollector {
state,
visitor: self,
ecx: &mut results.analysis.0.ecx,
map: &results.analysis.0.map,
}
.visit_terminator(terminator, location);
}
}
@ -670,6 +821,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
struct OperandCollector<'tcx, 'map, 'locals, 'a> {
state: &'a State<FlatSet<Scalar>>,
visitor: &'a mut Collector<'tcx, 'locals>,
ecx: &'map mut InterpCx<'tcx, 'tcx, DummyMachine>,
map: &'map Map,
}
@ -682,7 +834,7 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
location: Location,
) {
if let PlaceElem::Index(local) = elem
&& let Some(value) = self.visitor.try_make_constant(local.into(), self.state, self.map)
&& let Some(value) = self.visitor.try_make_constant(self.ecx, local.into(), self.state, self.map)
{
self.visitor.patch.before_effect.insert((location, local.into()), value);
}
@ -690,7 +842,9 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
if let Some(place) = operand.place() {
if let Some(value) = self.visitor.try_make_constant(place, self.state, self.map) {
if let Some(value) =
self.visitor.try_make_constant(self.ecx, place, self.state, self.map)
{
self.visitor.patch.before_effect.insert((location, place), value);
} else if !place.projection.is_empty() {
// Try to propagate into `Index` projections.
@ -713,7 +867,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
}
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
unimplemented!()
false
}
fn before_access_global(
@ -725,13 +879,13 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
is_write: bool,
) -> InterpResult<'tcx> {
if is_write {
crate::const_prop::throw_machine_stop_str!("can't write to global");
throw_machine_stop_str!("can't write to global");
}
// If the static allocation is mutable, then we can't const prop it as its content
// might be different at runtime.
if alloc.inner().mutability.is_mut() {
crate::const_prop::throw_machine_stop_str!("can't access mutable globals in ConstProp");
throw_machine_stop_str!("can't access mutable globals in ConstProp");
}
Ok(())
@ -781,7 +935,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
_left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
_right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
crate::const_prop::throw_machine_stop_str!("can't do pointer arithmetic");
throw_machine_stop_str!("can't do pointer arithmetic");
}
fn expose_ptr(

View File

@ -41,7 +41,8 @@
+ debug ((f: (bool, bool, u32)).2: u32) => const 123_u32;
let _10: std::option::Option<u16>;
scope 7 {
debug o => _10;
- debug o => _10;
+ debug o => const Option::<u16>::Some(99_u16);
let _17: u32;
let _18: u32;
scope 8 {
@ -81,7 +82,7 @@
_15 = const false;
_16 = const 123_u32;
StorageLive(_10);
_10 = Option::<u16>::Some(const 99_u16);
_10 = const Option::<u16>::Some(99_u16);
_17 = const 32_u32;
_18 = const 32_u32;
StorageLive(_11);
@ -97,3 +98,7 @@
}
}
ALLOC0 (size: 4, align: 2) {
01 00 63 00 │ ..c.
}

View File

@ -43,7 +43,7 @@
- _6 = CheckedAdd(_4, _5);
- assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind unreachable];
+ _5 = const 2_i32;
+ _6 = CheckedAdd(const 1_i32, const 2_i32);
+ _6 = const (3_i32, false);
+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind unreachable];
}
@ -60,7 +60,7 @@
- _10 = CheckedAdd(_9, const 1_i32);
- assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind unreachable];
+ _9 = const i32::MAX;
+ _10 = CheckedAdd(const i32::MAX, const 1_i32);
+ _10 = const (i32::MIN, true);
+ assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind unreachable];
}
@ -76,5 +76,13 @@
StorageDead(_1);
return;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 00 00 00 80 01 __ __ __ │ .....░░░
+ }
+
+ ALLOC1 (size: 8, align: 4) {
+ 03 00 00 00 00 __ __ __ │ .....░░░
}

View File

@ -43,7 +43,7 @@
- _6 = CheckedAdd(_4, _5);
- assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind continue];
+ _5 = const 2_i32;
+ _6 = CheckedAdd(const 1_i32, const 2_i32);
+ _6 = const (3_i32, false);
+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind continue];
}
@ -60,7 +60,7 @@
- _10 = CheckedAdd(_9, const 1_i32);
- assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind continue];
+ _9 = const i32::MAX;
+ _10 = CheckedAdd(const i32::MAX, const 1_i32);
+ _10 = const (i32::MIN, true);
+ assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind continue];
}
@ -76,5 +76,13 @@
StorageDead(_1);
return;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 00 00 00 80 01 __ __ __ │ .....░░░
+ }
+
+ ALLOC1 (size: 8, align: 4) {
+ 03 00 00 00 00 __ __ __ │ .....░░░
}

View File

@ -1,7 +1,7 @@
// skip-filecheck
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
// unit-test: DataflowConstProp
// compile-flags: -Coverflow-checks=on
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
// EMIT_MIR checked.main.DataflowConstProp.diff
#[allow(arithmetic_overflow)]

View File

@ -23,7 +23,8 @@
bb0: {
StorageLive(_1);
_1 = E::V1(const 0_i32);
- _1 = E::V1(const 0_i32);
+ _1 = const E::V1(0_i32);
StorageLive(_2);
- _3 = discriminant(_1);
- switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
@ -59,5 +60,9 @@
StorageDead(_1);
return;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 00 00 00 00 00 00 00 00 │ ........
}

View File

@ -23,7 +23,8 @@
bb0: {
StorageLive(_1);
_1 = E::V1(const 0_i32);
- _1 = E::V1(const 0_i32);
+ _1 = const E::V1(0_i32);
StorageLive(_2);
- _3 = discriminant(_1);
- switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
@ -59,5 +60,9 @@
StorageDead(_1);
return;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 00 00 00 00 00 00 00 00 │ ........
}

View File

@ -44,7 +44,8 @@
StorageLive(_1);
StorageLive(_2);
_2 = const {ALLOC1: &E};
_1 = (*_2);
- _1 = (*_2);
+ _1 = const E::V1(0_i32);
StorageDead(_2);
StorageLive(_3);
- _4 = discriminant(_1);
@ -110,6 +111,10 @@
StorageDead(_1);
return;
}
+ }
+
+ ALLOC3 (size: 8, align: 4) {
+ 00 00 00 00 00 00 00 00 │ ........
}
ALLOC2 (static: RC, size: 4, align: 4) {

View File

@ -44,7 +44,8 @@
StorageLive(_1);
StorageLive(_2);
_2 = const {ALLOC1: &E};
_1 = (*_2);
- _1 = (*_2);
+ _1 = const E::V1(0_i32);
StorageDead(_2);
StorageLive(_3);
- _4 = discriminant(_1);
@ -110,6 +111,10 @@
StorageDead(_1);
return;
}
+ }
+
+ ALLOC3 (size: 8, align: 4) {
+ 00 00 00 00 00 00 00 00 │ ........
}
ALLOC2 (static: RC, size: 8, align: 8) {

View File

@ -23,7 +23,7 @@
StorageLive(_4);
- _4 = CheckedAdd(_2, _3);
- assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
+ _4 = CheckedAdd(const u8::MAX, const 1_u8);
+ _4 = const (0_u8, true);
+ assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable];
}
@ -37,5 +37,9 @@
_0 = const ();
return;
}
+ }
+
+ ALLOC0 (size: 2, align: 1) {
+ 00 01 │ ..
}

View File

@ -23,7 +23,7 @@
StorageLive(_4);
- _4 = CheckedAdd(_2, _3);
- assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
+ _4 = CheckedAdd(const u8::MAX, const 1_u8);
+ _4 = const (0_u8, true);
+ assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
}
@ -37,5 +37,9 @@
_0 = const ();
return;
}
+ }
+
+ ALLOC0 (size: 2, align: 1) {
+ 00 01 │ ..
}

View File

@ -17,7 +17,8 @@
bb0: {
StorageLive(_1);
_1 = I32(const 0_i32);
- _1 = I32(const 0_i32);
+ _1 = const I32(0_i32);
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
@ -31,12 +32,20 @@
StorageDead(_5);
StorageDead(_4);
- _2 = I32(move _3);
+ _2 = I32(const 0_i32);
+ _2 = const I32(0_i32);
StorageDead(_3);
_0 = const ();
StorageDead(_2);
StorageDead(_1);
return;
}
+ }
+
+ ALLOC0 (size: 4, align: 4) {
+ 00 00 00 00 │ ....
+ }
+
+ ALLOC1 (size: 4, align: 4) {
+ 00 00 00 00 │ ....
}

View File

@ -7,13 +7,24 @@
let mut _3: i32;
let mut _5: i32;
let mut _6: i32;
let mut _11: BigStruct;
let mut _16: &&BigStruct;
let mut _17: &BigStruct;
let mut _18: &BigStruct;
let mut _19: &BigStruct;
let mut _20: &BigStruct;
let mut _21: &BigStruct;
let mut _10: SmallStruct;
let mut _14: &&SmallStruct;
let mut _16: f32;
let mut _17: std::option::Option<S>;
let mut _18: &[f32];
let mut _22: BigStruct;
let mut _26: &&BigStruct;
let mut _28: f32;
let mut _29: std::option::Option<S>;
let mut _30: &[f32];
let mut _31: &SmallStruct;
let mut _32: &SmallStruct;
let mut _33: &SmallStruct;
let mut _34: &SmallStruct;
let mut _35: &BigStruct;
let mut _36: &BigStruct;
let mut _37: &BigStruct;
let mut _38: &BigStruct;
scope 1 {
debug s => _1;
let _2: i32;
@ -22,24 +33,44 @@
let _4: i32;
scope 3 {
debug b => _4;
let _7: S;
let _8: u8;
let _9: f32;
let _10: S;
let _7: f32;
let _8: std::option::Option<S>;
let _9: &[f32];
scope 4 {
debug a => _7;
debug b => _8;
debug c => _9;
debug d => _10;
let _12: S;
let _13: u8;
let _14: f32;
let _15: S;
let _11: f32;
let _12: std::option::Option<S>;
let _13: &[f32];
scope 5 {
debug a => _12;
debug b => _13;
debug c => _14;
debug d => _15;
debug a => _11;
debug b => _12;
debug c => _13;
let _15: SmallStruct;
scope 6 {
debug ss => _15;
let _19: f32;
let _20: std::option::Option<S>;
let _21: &[f32];
scope 7 {
debug a => _19;
debug b => _20;
debug c => _21;
let _23: f32;
let _24: std::option::Option<S>;
let _25: &[f32];
scope 8 {
debug a => _23;
debug b => _24;
debug c => _25;
let _27: BigStruct;
scope 9 {
debug bs => _27;
}
}
}
}
}
}
}
@ -48,7 +79,8 @@
bb0: {
StorageLive(_1);
_1 = S(const 1_i32);
- _1 = S(const 1_i32);
+ _1 = const S(1_i32);
StorageLive(_2);
StorageLive(_3);
- _3 = (_1.0: i32);
@ -68,47 +100,95 @@
+ _4 = const 6_i32;
StorageDead(_6);
StorageDead(_5);
StorageLive(_11);
_11 = const _;
StorageLive(_7);
- _7 = (_11.0: S);
+ _7 = const S(1_i32);
StorageLive(_8);
- _8 = (_11.1: u8);
+ _8 = const 5_u8;
StorageLive(_9);
- _9 = (_11.2: f32);
+ _9 = const 7f32;
StorageLive(_10);
- _10 = (_11.3: S);
+ _10 = const S(13_i32);
StorageDead(_11);
StorageLive(_16);
_16 = const {ALLOC1: &&BigStruct};
_17 = deref_copy (*_16);
StorageLive(_12);
_18 = deref_copy (*_16);
- _12 = ((*_18).0: S);
+ _12 = const S(1_i32);
StorageLive(_13);
_19 = deref_copy (*_16);
- _13 = ((*_19).1: u8);
+ _13 = const 5_u8;
_10 = const _;
StorageLive(_7);
- _7 = (_10.0: f32);
+ _7 = const 4f32;
StorageLive(_8);
- _8 = (_10.1: std::option::Option<S>);
+ _8 = const Option::<S>::Some(S(1_i32));
StorageLive(_9);
_9 = (_10.2: &[f32]);
StorageDead(_10);
StorageLive(_14);
_20 = deref_copy (*_16);
- _14 = ((*_20).2: f32);
+ _14 = const 7f32;
StorageLive(_15);
_21 = deref_copy (*_16);
- _15 = ((*_21).3: S);
+ _15 = const S(13_i32);
StorageDead(_16);
_0 = const ();
StorageDead(_15);
_14 = const {ALLOC4: &&SmallStruct};
_31 = deref_copy (*_14);
StorageLive(_11);
_32 = deref_copy (*_14);
- _11 = ((*_32).0: f32);
+ _11 = const 9f32;
StorageLive(_12);
_33 = deref_copy (*_14);
_12 = ((*_33).1: std::option::Option<S>);
StorageLive(_13);
_34 = deref_copy (*_14);
_13 = ((*_34).2: &[f32]);
StorageDead(_14);
StorageLive(_15);
StorageLive(_16);
- _16 = _11;
+ _16 = const 9f32;
StorageLive(_17);
_17 = _12;
StorageLive(_18);
_18 = _13;
- _15 = SmallStruct(move _16, move _17, move _18);
+ _15 = SmallStruct(const 9f32, move _17, move _18);
StorageDead(_18);
StorageDead(_17);
StorageDead(_16);
StorageLive(_22);
_22 = const _;
StorageLive(_19);
- _19 = (_22.0: f32);
+ _19 = const 25f32;
StorageLive(_20);
_20 = (_22.1: std::option::Option<S>);
StorageLive(_21);
_21 = (_22.2: &[f32]);
StorageDead(_22);
StorageLive(_26);
_26 = const {ALLOC5: &&BigStruct};
_35 = deref_copy (*_26);
StorageLive(_23);
_36 = deref_copy (*_26);
- _23 = ((*_36).0: f32);
+ _23 = const 82f32;
StorageLive(_24);
_37 = deref_copy (*_26);
- _24 = ((*_37).1: std::option::Option<S>);
+ _24 = const Option::<S>::Some(S(35_i32));
StorageLive(_25);
_38 = deref_copy (*_26);
_25 = ((*_38).2: &[f32]);
StorageDead(_26);
StorageLive(_27);
StorageLive(_28);
- _28 = _23;
+ _28 = const 82f32;
StorageLive(_29);
- _29 = _24;
+ _29 = const Option::<S>::Some(S(35_i32));
StorageLive(_30);
_30 = _25;
- _27 = BigStruct(move _28, move _29, move _30);
+ _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
StorageDead(_30);
StorageDead(_29);
StorageDead(_28);
_0 = const ();
StorageDead(_27);
StorageDead(_25);
StorageDead(_24);
StorageDead(_23);
StorageDead(_21);
StorageDead(_20);
StorageDead(_19);
StorageDead(_15);
StorageDead(_13);
StorageDead(_12);
StorageDead(_10);
StorageDead(_11);
StorageDead(_9);
StorageDead(_8);
StorageDead(_7);
@ -117,13 +197,51 @@
StorageDead(_1);
return;
}
+ }
+
+ ALLOC6 (size: 8, align: 4) {
+ 01 00 00 00 23 00 00 00 │ ....#...
+ }
+
+ ALLOC7 (size: 8, align: 4) {
+ 01 00 00 00 23 00 00 00 │ ....#...
+ }
+
+ ALLOC8 (size: 8, align: 4) {
+ 01 00 00 00 23 00 00 00 │ ....#...
+ }
+
+ ALLOC9 (size: 8, align: 4) {
+ 01 00 00 00 01 00 00 00 │ ........
+ }
+
+ ALLOC10 (size: 4, align: 4) {
+ 01 00 00 00 │ ....
}
ALLOC1 (static: STAT, size: 4, align: 4) {
ALLOC5 (static: BIG_STAT, size: 4, align: 4) {
╾ALLOC0╼ │ ╾──╼
}
ALLOC0 (size: 16, align: 4) {
01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
ALLOC0 (size: 20, align: 4) {
0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼....
0x10 │ 00 00 a4 42 │ ...B
}
ALLOC1 (size: 8, align: 4) {
00 00 34 42 00 00 90 42 │ ..4B...B
}
ALLOC4 (static: SMALL_STAT, size: 4, align: 4) {
╾ALLOC2╼ │ ╾──╼
}
ALLOC2 (size: 20, align: 4) {
0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼....
0x10 │ 00 00 10 41 │ ...A
}
ALLOC3 (size: 4, align: 4) {
00 00 50 41 │ ..PA
}

View File

@ -7,13 +7,24 @@
let mut _3: i32;
let mut _5: i32;
let mut _6: i32;
let mut _11: BigStruct;
let mut _16: &&BigStruct;
let mut _17: &BigStruct;
let mut _18: &BigStruct;
let mut _19: &BigStruct;
let mut _20: &BigStruct;
let mut _21: &BigStruct;
let mut _10: SmallStruct;
let mut _14: &&SmallStruct;
let mut _16: f32;
let mut _17: std::option::Option<S>;
let mut _18: &[f32];
let mut _22: BigStruct;
let mut _26: &&BigStruct;
let mut _28: f32;
let mut _29: std::option::Option<S>;
let mut _30: &[f32];
let mut _31: &SmallStruct;
let mut _32: &SmallStruct;
let mut _33: &SmallStruct;
let mut _34: &SmallStruct;
let mut _35: &BigStruct;
let mut _36: &BigStruct;
let mut _37: &BigStruct;
let mut _38: &BigStruct;
scope 1 {
debug s => _1;
let _2: i32;
@ -22,24 +33,44 @@
let _4: i32;
scope 3 {
debug b => _4;
let _7: S;
let _8: u8;
let _9: f32;
let _10: S;
let _7: f32;
let _8: std::option::Option<S>;
let _9: &[f32];
scope 4 {
debug a => _7;
debug b => _8;
debug c => _9;
debug d => _10;
let _12: S;
let _13: u8;
let _14: f32;
let _15: S;
let _11: f32;
let _12: std::option::Option<S>;
let _13: &[f32];
scope 5 {
debug a => _12;
debug b => _13;
debug c => _14;
debug d => _15;
debug a => _11;
debug b => _12;
debug c => _13;
let _15: SmallStruct;
scope 6 {
debug ss => _15;
let _19: f32;
let _20: std::option::Option<S>;
let _21: &[f32];
scope 7 {
debug a => _19;
debug b => _20;
debug c => _21;
let _23: f32;
let _24: std::option::Option<S>;
let _25: &[f32];
scope 8 {
debug a => _23;
debug b => _24;
debug c => _25;
let _27: BigStruct;
scope 9 {
debug bs => _27;
}
}
}
}
}
}
}
@ -48,7 +79,8 @@
bb0: {
StorageLive(_1);
_1 = S(const 1_i32);
- _1 = S(const 1_i32);
+ _1 = const S(1_i32);
StorageLive(_2);
StorageLive(_3);
- _3 = (_1.0: i32);
@ -68,47 +100,95 @@
+ _4 = const 6_i32;
StorageDead(_6);
StorageDead(_5);
StorageLive(_11);
_11 = const _;
StorageLive(_7);
- _7 = (_11.0: S);
+ _7 = const S(1_i32);
StorageLive(_8);
- _8 = (_11.1: u8);
+ _8 = const 5_u8;
StorageLive(_9);
- _9 = (_11.2: f32);
+ _9 = const 7f32;
StorageLive(_10);
- _10 = (_11.3: S);
+ _10 = const S(13_i32);
StorageDead(_11);
StorageLive(_16);
_16 = const {ALLOC1: &&BigStruct};
_17 = deref_copy (*_16);
StorageLive(_12);
_18 = deref_copy (*_16);
- _12 = ((*_18).0: S);
+ _12 = const S(1_i32);
StorageLive(_13);
_19 = deref_copy (*_16);
- _13 = ((*_19).1: u8);
+ _13 = const 5_u8;
_10 = const _;
StorageLive(_7);
- _7 = (_10.0: f32);
+ _7 = const 4f32;
StorageLive(_8);
- _8 = (_10.1: std::option::Option<S>);
+ _8 = const Option::<S>::Some(S(1_i32));
StorageLive(_9);
_9 = (_10.2: &[f32]);
StorageDead(_10);
StorageLive(_14);
_20 = deref_copy (*_16);
- _14 = ((*_20).2: f32);
+ _14 = const 7f32;
StorageLive(_15);
_21 = deref_copy (*_16);
- _15 = ((*_21).3: S);
+ _15 = const S(13_i32);
StorageDead(_16);
_0 = const ();
StorageDead(_15);
_14 = const {ALLOC4: &&SmallStruct};
_31 = deref_copy (*_14);
StorageLive(_11);
_32 = deref_copy (*_14);
- _11 = ((*_32).0: f32);
+ _11 = const 9f32;
StorageLive(_12);
_33 = deref_copy (*_14);
_12 = ((*_33).1: std::option::Option<S>);
StorageLive(_13);
_34 = deref_copy (*_14);
_13 = ((*_34).2: &[f32]);
StorageDead(_14);
StorageLive(_15);
StorageLive(_16);
- _16 = _11;
+ _16 = const 9f32;
StorageLive(_17);
_17 = _12;
StorageLive(_18);
_18 = _13;
- _15 = SmallStruct(move _16, move _17, move _18);
+ _15 = SmallStruct(const 9f32, move _17, move _18);
StorageDead(_18);
StorageDead(_17);
StorageDead(_16);
StorageLive(_22);
_22 = const _;
StorageLive(_19);
- _19 = (_22.0: f32);
+ _19 = const 25f32;
StorageLive(_20);
_20 = (_22.1: std::option::Option<S>);
StorageLive(_21);
_21 = (_22.2: &[f32]);
StorageDead(_22);
StorageLive(_26);
_26 = const {ALLOC5: &&BigStruct};
_35 = deref_copy (*_26);
StorageLive(_23);
_36 = deref_copy (*_26);
- _23 = ((*_36).0: f32);
+ _23 = const 82f32;
StorageLive(_24);
_37 = deref_copy (*_26);
- _24 = ((*_37).1: std::option::Option<S>);
+ _24 = const Option::<S>::Some(S(35_i32));
StorageLive(_25);
_38 = deref_copy (*_26);
_25 = ((*_38).2: &[f32]);
StorageDead(_26);
StorageLive(_27);
StorageLive(_28);
- _28 = _23;
+ _28 = const 82f32;
StorageLive(_29);
- _29 = _24;
+ _29 = const Option::<S>::Some(S(35_i32));
StorageLive(_30);
_30 = _25;
- _27 = BigStruct(move _28, move _29, move _30);
+ _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
StorageDead(_30);
StorageDead(_29);
StorageDead(_28);
_0 = const ();
StorageDead(_27);
StorageDead(_25);
StorageDead(_24);
StorageDead(_23);
StorageDead(_21);
StorageDead(_20);
StorageDead(_19);
StorageDead(_15);
StorageDead(_13);
StorageDead(_12);
StorageDead(_10);
StorageDead(_11);
StorageDead(_9);
StorageDead(_8);
StorageDead(_7);
@ -117,13 +197,51 @@
StorageDead(_1);
return;
}
+ }
+
+ ALLOC6 (size: 8, align: 4) {
+ 01 00 00 00 23 00 00 00 │ ....#...
+ }
+
+ ALLOC7 (size: 8, align: 4) {
+ 01 00 00 00 23 00 00 00 │ ....#...
+ }
+
+ ALLOC8 (size: 8, align: 4) {
+ 01 00 00 00 23 00 00 00 │ ....#...
+ }
+
+ ALLOC9 (size: 8, align: 4) {
+ 01 00 00 00 01 00 00 00 │ ........
+ }
+
+ ALLOC10 (size: 4, align: 4) {
+ 01 00 00 00 │ ....
}
ALLOC1 (static: STAT, size: 8, align: 8) {
ALLOC5 (static: BIG_STAT, size: 8, align: 8) {
╾ALLOC0╼ │ ╾──────╼
}
ALLOC0 (size: 16, align: 4) {
01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
ALLOC0 (size: 32, align: 8) {
0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼
0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........B░░░░
}
ALLOC1 (size: 8, align: 4) {
00 00 34 42 00 00 90 42 │ ..4B...B
}
ALLOC4 (static: SMALL_STAT, size: 8, align: 8) {
╾ALLOC2╼ │ ╾──────╼
}
ALLOC2 (size: 32, align: 8) {
0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼
0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........A░░░░
}
ALLOC3 (size: 4, align: 4) {
00 00 50 41 │ ..PA
}

View File

@ -6,7 +6,10 @@
struct S(i32);
#[derive(Copy, Clone)]
struct BigStruct(S, u8, f32, S);
struct SmallStruct(f32, Option<S>, &'static [f32]);
#[derive(Copy, Clone)]
struct BigStruct(f32, Option<S>, &'static [f32]);
// EMIT_MIR struct.main.DataflowConstProp.diff
fn main() {
@ -15,9 +18,21 @@ fn main() {
s.0 = 3;
let b = a + s.0;
const VAL: BigStruct = BigStruct(S(1), 5, 7., S(13));
let BigStruct(a, b, c, d) = VAL;
const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]);
let SmallStruct(a, b, c) = SMALL_VAL;
static STAT: &BigStruct = &BigStruct(S(1), 5, 7., S(13));
let BigStruct(a, b, c, d) = *STAT;
static SMALL_STAT: &SmallStruct = &SmallStruct(9., None, &[13.]);
let SmallStruct(a, b, c) = *SMALL_STAT;
let ss = SmallStruct(a, b, c);
const BIG_VAL: BigStruct = BigStruct(25., None, &[]);
let BigStruct(a, b, c) = BIG_VAL;
static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]);
let BigStruct(a, b, c) = *BIG_STAT;
// We arbitrarily limit the size of synthetized values to 4 pointers.
// `BigStruct` can be read, but we will keep a MIR aggregate for this.
let bs = BigStruct(a, b, c);
}

View File

@ -52,8 +52,8 @@ pub unsafe fn undef_union_as_integer() -> u32 {
// EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff
pub unsafe fn unreachable_direct() -> ! {
// CHECK-LABEL: fn unreachable_direct(
// CHECK: [[unit:_.*]] = ();
// CHECK: move [[unit]] as Never (Transmute);
// CHECK: = const ();
// CHECK: = const ZeroSized: Never;
let x: Never = unsafe { transmute(()) };
match x {}
}

View File

@ -11,8 +11,10 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = ();
_1 = Union32 { value: move _2 };
- _2 = ();
- _1 = Union32 { value: move _2 };
+ _2 = const ();
+ _1 = Union32 { value: const () };
StorageDead(_2);
_0 = move _1 as u32 (Transmute);
StorageDead(_1);

View File

@ -11,8 +11,10 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = ();
_1 = Union32 { value: move _2 };
- _2 = ();
- _1 = Union32 { value: move _2 };
+ _2 = const ();
+ _1 = Union32 { value: const () };
StorageDead(_2);
_0 = move _1 as u32 (Transmute);
StorageDead(_1);

View File

@ -14,8 +14,10 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = ();
_1 = move _2 as Never (Transmute);
- _2 = ();
- _1 = move _2 as Never (Transmute);
+ _2 = const ();
+ _1 = const ZeroSized: Never;
unreachable;
}
}

View File

@ -14,8 +14,10 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = ();
_1 = move _2 as Never (Transmute);
- _2 = ();
- _1 = move _2 as Never (Transmute);
+ _2 = const ();
+ _1 = const ZeroSized: Never;
unreachable;
}
}

View File

@ -11,6 +11,9 @@
let mut _8: i32;
let mut _9: i32;
let mut _10: i32;
let mut _12: i32;
let mut _13: (i32, i32);
let mut _14: i32;
scope 1 {
debug a => _1;
let _2: i32;
@ -19,13 +22,18 @@
let _6: i32;
scope 3 {
debug c => _6;
let _11: (i32, (i32, i32), i32);
scope 4 {
debug d => _11;
}
}
}
}
bb0: {
StorageLive(_1);
_1 = (const 1_i32, const 2_i32);
- _1 = (const 1_i32, const 2_i32);
+ _1 = const (1_i32, 2_i32);
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
@ -41,7 +49,8 @@
- _2 = Add(move _3, const 3_i32);
+ _2 = const 6_i32;
StorageDead(_3);
_1 = (const 2_i32, const 3_i32);
- _1 = (const 2_i32, const 3_i32);
+ _1 = const (2_i32, 3_i32);
StorageLive(_6);
StorageLive(_7);
StorageLive(_8);
@ -61,11 +70,43 @@
+ _6 = const 11_i32;
StorageDead(_10);
StorageDead(_7);
StorageLive(_11);
StorageLive(_12);
- _12 = _2;
+ _12 = const 6_i32;
StorageLive(_13);
- _13 = _1;
+ _13 = const (2_i32, 3_i32);
StorageLive(_14);
- _14 = _6;
- _11 = (move _12, move _13, move _14);
+ _14 = const 11_i32;
+ _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32);
StorageDead(_14);
StorageDead(_13);
StorageDead(_12);
_0 = const ();
StorageDead(_11);
StorageDead(_6);
StorageDead(_2);
StorageDead(_1);
return;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 02 00 00 00 03 00 00 00 │ ........
+ }
+
+ ALLOC1 (size: 8, align: 4) {
+ 02 00 00 00 03 00 00 00 │ ........
+ }
+
+ ALLOC2 (size: 8, align: 4) {
+ 02 00 00 00 03 00 00 00 │ ........
+ }
+
+ ALLOC3 (size: 8, align: 4) {
+ 01 00 00 00 02 00 00 00 │ ........
}

View File

@ -0,0 +1,112 @@
- // MIR for `main` before DataflowConstProp
+ // MIR for `main` after DataflowConstProp
fn main() -> () {
let mut _0: ();
let mut _1: (i32, i32);
let mut _3: i32;
let mut _4: i32;
let mut _5: i32;
let mut _7: i32;
let mut _8: i32;
let mut _9: i32;
let mut _10: i32;
let mut _12: i32;
let mut _13: (i32, i32);
let mut _14: i32;
scope 1 {
debug a => _1;
let _2: i32;
scope 2 {
debug b => _2;
let _6: i32;
scope 3 {
debug c => _6;
let _11: (i32, (i32, i32), i32);
scope 4 {
debug d => _11;
}
}
}
}
bb0: {
StorageLive(_1);
- _1 = (const 1_i32, const 2_i32);
+ _1 = const (1_i32, 2_i32);
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = (_1.0: i32);
+ _4 = const 1_i32;
StorageLive(_5);
- _5 = (_1.1: i32);
- _3 = Add(move _4, move _5);
+ _5 = const 2_i32;
+ _3 = const 3_i32;
StorageDead(_5);
StorageDead(_4);
- _2 = Add(move _3, const 3_i32);
+ _2 = const 6_i32;
StorageDead(_3);
- _1 = (const 2_i32, const 3_i32);
+ _1 = const (2_i32, 3_i32);
StorageLive(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = (_1.0: i32);
+ _8 = const 2_i32;
StorageLive(_9);
- _9 = (_1.1: i32);
- _7 = Add(move _8, move _9);
+ _9 = const 3_i32;
+ _7 = const 5_i32;
StorageDead(_9);
StorageDead(_8);
StorageLive(_10);
- _10 = _2;
- _6 = Add(move _7, move _10);
+ _10 = const 6_i32;
+ _6 = const 11_i32;
StorageDead(_10);
StorageDead(_7);
StorageLive(_11);
StorageLive(_12);
- _12 = _2;
+ _12 = const 6_i32;
StorageLive(_13);
- _13 = _1;
+ _13 = const (2_i32, 3_i32);
StorageLive(_14);
- _14 = _6;
- _11 = (move _12, move _13, move _14);
+ _14 = const 11_i32;
+ _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32);
StorageDead(_14);
StorageDead(_13);
StorageDead(_12);
_0 = const ();
StorageDead(_11);
StorageDead(_6);
StorageDead(_2);
StorageDead(_1);
return;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 02 00 00 00 03 00 00 00 │ ........
+ }
+
+ ALLOC1 (size: 8, align: 4) {
+ 02 00 00 00 03 00 00 00 │ ........
+ }
+
+ ALLOC2 (size: 8, align: 4) {
+ 02 00 00 00 03 00 00 00 │ ........
+ }
+
+ ALLOC3 (size: 8, align: 4) {
+ 01 00 00 00 02 00 00 00 │ ........
}

View File

@ -1,5 +1,6 @@
// skip-filecheck
// unit-test: DataflowConstProp
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR tuple.main.DataflowConstProp.diff
fn main() {
@ -7,4 +8,6 @@ fn main() {
let b = a.0 + a.1 + 3;
a = (2, 3);
let c = a.0 + a.1 + b;
let d = (b, a, c);
}