Flatten aggregates into locals.

This commit is contained in:
Camille GILLOT 2022-05-23 09:27:44 +02:00
parent b550eabfa6
commit e4f343191a
21 changed files with 1043 additions and 41 deletions

View file

@ -93,6 +93,7 @@ pub mod simplify;
mod simplify_branches;
mod simplify_comparison_integral;
mod simplify_try;
mod sroa;
mod uninhabited_enum_branching;
mod unreachable_prop;
@ -563,6 +564,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&remove_zsts::RemoveZsts,
&const_goto::ConstGoto,
&remove_unneeded_drops::RemoveUnneededDrops,
&sroa::ScalarReplacementOfAggregates,
&match_branches::MatchBranchSimplification,
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
&multiple_return_terminators::MultipleReturnTerminators,

View file

@ -0,0 +1,348 @@
use crate::MirPass;
use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
pub struct ScalarReplacementOfAggregates;
impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 4
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let escaping = escaping_locals(&*body);
debug!(?escaping);
let replacements = compute_flattening(tcx, body, escaping);
debug!(?replacements);
replace_flattened_locals(tcx, body, replacements);
}
}
/// Identify all locals that are not eligible for SROA.
///
/// There are 3 cases:
/// - the aggegated local is used or passed to other code (function parameters and arguments);
/// - the locals is a union or an enum;
/// - the local's address is taken, and thus the relative addresses of the fields are observable to
/// client code.
fn escaping_locals(body: &Body<'_>) -> BitSet<Local> {
let mut set = BitSet::new_empty(body.local_decls.len());
set.insert_range(RETURN_PLACE..=Local::from_usize(body.arg_count));
for (local, decl) in body.local_decls().iter_enumerated() {
if decl.ty.is_union() || decl.ty.is_enum() {
set.insert(local);
}
}
let mut visitor = EscapeVisitor { set };
visitor.visit_body(body);
return visitor.set;
struct EscapeVisitor {
set: BitSet<Local>,
}
impl<'tcx> Visitor<'tcx> for EscapeVisitor {
fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) {
self.set.insert(local);
}
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
// Mirror the implementation in PreFlattenVisitor.
if let &[PlaceElem::Field(..), ..] = &place.projection[..] {
return;
}
self.super_place(place, context, location);
}
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
if let Rvalue::AddressOf(.., place) | Rvalue::Ref(.., place) = rvalue {
if !place.is_indirect() {
// Raw pointers may be used to access anything inside the enclosing place.
self.set.insert(place.local);
return;
}
}
self.super_rvalue(rvalue, location)
}
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
if let StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::Deinit(..) = statement.kind
{
// Storage statements are expanded in run_pass.
return;
}
self.super_statement(statement, location)
}
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
// Drop implicitly calls `drop_in_place`, which takes a `&mut`.
// This implies that `Drop` implicitly takes the address of the place.
if let TerminatorKind::Drop { place, .. }
| TerminatorKind::DropAndReplace { place, .. } = terminator.kind
{
if !place.is_indirect() {
// Raw pointers may be used to access anything inside the enclosing place.
self.set.insert(place.local);
return;
}
}
self.super_terminator(terminator, location);
}
// We ignore anything that happens in debuginfo, since we expand it using
// `VarDebugInfoContents::Composite`.
fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {}
}
}
#[derive(Default, Debug)]
struct ReplacementMap<'tcx> {
fields: FxIndexMap<PlaceRef<'tcx>, Local>,
}
/// Compute the replacement of flattened places into locals.
///
/// For each eligible place, we assign a new local to each accessed field.
/// The replacement will be done later in `ReplacementVisitor`.
fn compute_flattening<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
escaping: BitSet<Local>,
) -> ReplacementMap<'tcx> {
let mut visitor = PreFlattenVisitor {
tcx,
escaping,
local_decls: &mut body.local_decls,
map: Default::default(),
};
for (block, bbdata) in body.basic_blocks.iter_enumerated() {
visitor.visit_basic_block_data(block, bbdata);
}
return visitor.map;
struct PreFlattenVisitor<'tcx, 'll> {
tcx: TyCtxt<'tcx>,
local_decls: &'ll mut LocalDecls<'tcx>,
escaping: BitSet<Local>,
map: ReplacementMap<'tcx>,
}
impl<'tcx, 'll> PreFlattenVisitor<'tcx, 'll> {
fn create_place(&mut self, place: PlaceRef<'tcx>) {
if self.escaping.contains(place.local) {
return;
}
match self.map.fields.entry(place) {
IndexEntry::Occupied(_) => {}
IndexEntry::Vacant(v) => {
let ty = place.ty(&*self.local_decls, self.tcx).ty;
let local = self.local_decls.push(LocalDecl {
ty,
user_ty: None,
..self.local_decls[place.local].clone()
});
v.insert(local);
}
}
}
}
impl<'tcx, 'll> Visitor<'tcx> for PreFlattenVisitor<'tcx, 'll> {
fn visit_place(&mut self, place: &Place<'tcx>, _: PlaceContext, _: Location) {
if let &[PlaceElem::Field(..), ..] = &place.projection[..] {
let pr = PlaceRef { local: place.local, projection: &place.projection[..1] };
self.create_place(pr)
}
}
}
}
/// Perform the replacement computed by `compute_flattening`.
fn replace_flattened_locals<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
replacements: ReplacementMap<'tcx>,
) {
let mut all_dead_locals = BitSet::new_empty(body.local_decls.len());
for p in replacements.fields.keys() {
all_dead_locals.insert(p.local);
}
debug!(?all_dead_locals);
if all_dead_locals.is_empty() {
return;
}
let mut fragments = IndexVec::new();
for (k, v) in &replacements.fields {
fragments.ensure_contains_elem(k.local, || Vec::new());
fragments[k.local].push((&k.projection[..], *v));
}
debug!(?fragments);
let mut visitor = ReplacementVisitor {
tcx,
local_decls: &body.local_decls,
replacements,
all_dead_locals,
fragments,
};
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
visitor.visit_basic_block_data(bb, data);
}
for scope in &mut body.source_scopes {
visitor.visit_source_scope_data(scope);
}
for (index, annotation) in body.user_type_annotations.iter_enumerated_mut() {
visitor.visit_user_type_annotation(index, annotation);
}
for var_debug_info in &mut body.var_debug_info {
visitor.visit_var_debug_info(var_debug_info);
}
}
struct ReplacementVisitor<'tcx, 'll> {
tcx: TyCtxt<'tcx>,
/// This is only used to compute the type for `VarDebugInfoContents::Composite`.
local_decls: &'ll LocalDecls<'tcx>,
/// Work to do.
replacements: ReplacementMap<'tcx>,
/// This is used to check that we are not leaving references to replaced locals behind.
all_dead_locals: BitSet<Local>,
/// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage
/// and deinit statement and debuginfo.
fragments: IndexVec<Local, Vec<(&'tcx [PlaceElem<'tcx>], Local)>>,
}
impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> {
fn gather_debug_info_fragments(
&self,
place: PlaceRef<'tcx>,
) -> Vec<VarDebugInfoFragment<'tcx>> {
let mut fragments = Vec::new();
let parts = &self.fragments[place.local];
for (proj, replacement_local) in parts {
if proj.starts_with(place.projection) {
fragments.push(VarDebugInfoFragment {
projection: proj[place.projection.len()..].to_vec(),
contents: Place::from(*replacement_local),
});
}
}
fragments
}
fn replace_place(&self, place: PlaceRef<'tcx>) -> Option<Place<'tcx>> {
if let &[PlaceElem::Field(..), ref rest @ ..] = place.projection {
let pr = PlaceRef { local: place.local, projection: &place.projection[..1] };
let local = self.replacements.fields.get(&pr)?;
Some(Place { local: *local, projection: self.tcx.intern_place_elems(&rest) })
} else {
None
}
}
}
impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
if let StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::Deinit(..) = statement.kind
{
// Storage statements are expanded in run_pass.
return;
}
self.super_statement(statement, location)
}
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
if let Some(repl) = self.replace_place(place.as_ref()) {
*place = repl
} else {
self.super_place(place, context, location)
}
}
fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) {
match &mut var_debug_info.value {
VarDebugInfoContents::Place(ref mut place) => {
if let Some(repl) = self.replace_place(place.as_ref()) {
*place = repl;
} else if self.all_dead_locals.contains(place.local) {
let ty = place.ty(self.local_decls, self.tcx).ty;
let fragments = self.gather_debug_info_fragments(place.as_ref());
var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments };
}
}
VarDebugInfoContents::Composite { ty: _, ref mut fragments } => {
let mut new_fragments = Vec::new();
fragments
.drain_filter(|fragment| {
if let Some(repl) = self.replace_place(fragment.contents.as_ref()) {
fragment.contents = repl;
true
} else if self.all_dead_locals.contains(fragment.contents.local) {
let frg = self.gather_debug_info_fragments(fragment.contents.as_ref());
new_fragments.extend(frg.into_iter().map(|mut f| {
f.projection.splice(0..0, fragment.projection.iter().copied());
f
}));
false
} else {
true
}
})
.for_each(drop);
fragments.extend(new_fragments);
}
VarDebugInfoContents::Const(_) => {}
}
}
fn visit_basic_block_data(&mut self, bb: BasicBlock, bbdata: &mut BasicBlockData<'tcx>) {
self.super_basic_block_data(bb, bbdata);
#[derive(Debug)]
enum Stmt {
StorageLive,
StorageDead,
Deinit,
}
bbdata.expand_statements(|stmt| {
let source_info = stmt.source_info;
let (stmt, origin_local) = match &stmt.kind {
StatementKind::StorageLive(l) => (Stmt::StorageLive, *l),
StatementKind::StorageDead(l) => (Stmt::StorageDead, *l),
StatementKind::Deinit(p) if let Some(l) = p.as_local() => (Stmt::Deinit, l),
_ => return None,
};
if !self.all_dead_locals.contains(origin_local) {
return None;
}
let final_locals = self.fragments.get(origin_local)?;
Some(final_locals.iter().map(move |&(_, l)| {
let kind = match stmt {
Stmt::StorageLive => StatementKind::StorageLive(l),
Stmt::StorageDead => StatementKind::StorageDead(l),
Stmt::Deinit => StatementKind::Deinit(Box::new(l.into())),
};
Statement { source_info, kind }
}))
});
}
fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
assert!(!self.all_dead_locals.contains(*local));
}
}

View file

@ -30,14 +30,19 @@
- debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10
+ debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10
let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
let _16: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
let _17: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
let _18: u32; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
scope 6 {
debug f => _10; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10
debug f => (bool, bool, u32){ .0 => _16, .1 => _17, .2 => _18, }; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10
let _11: std::option::Option<u16>; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
scope 7 {
debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10
let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
let _19: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
let _20: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
scope 8 {
debug p => _12; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10
debug p => Point{ .0 => _19, .1 => _20, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10
let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
scope 9 {
- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
@ -78,19 +83,25 @@
// mir::Constant
// + span: $DIR/const_debuginfo.rs:14:13: 14:28
// + literal: Const { ty: &str, val: Value(Slice(..)) }
StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
Deinit(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
(_10.0: bool) = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
(_10.1: bool) = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
(_10.2: u32) = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
StorageLive(_16); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
StorageLive(_17); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
StorageLive(_18); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
Deinit(_16); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
Deinit(_17); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
Deinit(_18); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
_16 = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
_17 = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
_18 = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
Deinit(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
discriminant(_11) = 1; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
StorageLive(_12); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
Deinit(_12); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
(_12.0: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
(_12.1: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
StorageLive(_19); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
StorageLive(_20); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
Deinit(_19); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
Deinit(_20); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
_19 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
_20 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
StorageLive(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
_14 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
@ -101,9 +112,12 @@
StorageDead(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
nop; // scope 0 at $DIR/const_debuginfo.rs:+0:11: +14:2
StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_12); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_19); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_20); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_10); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_16); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_17); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_18); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2

View file

@ -0,0 +1,28 @@
// MIR for `main` after PreCodegen
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/aggregate.rs:+0:11: +0:11
let _1: i32; // in scope 0 at $DIR/aggregate.rs:+1:9: +1:10
let mut _2: i32; // in scope 0 at $DIR/aggregate.rs:+1:13: +1:24
let mut _3: (i32, i32, i32); // in scope 0 at $DIR/aggregate.rs:+1:13: +1:22
scope 1 {
debug x => _1; // in scope 1 at $DIR/aggregate.rs:+1:9: +1:10
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/aggregate.rs:+1:9: +1:10
StorageLive(_2); // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
StorageLive(_3); // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
Deinit(_3); // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
(_3.0: i32) = const 0_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
(_3.1: i32) = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
(_3.2: i32) = const 2_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
_2 = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
_1 = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
StorageDead(_2); // scope 0 at $DIR/aggregate.rs:+1:27: +1:28
StorageDead(_3); // scope 0 at $DIR/aggregate.rs:+1:28: +1:29
_0 = const (); // scope 0 at $DIR/aggregate.rs:+0:11: +2:2
StorageDead(_1); // scope 0 at $DIR/aggregate.rs:+2:1: +2:2
return; // scope 0 at $DIR/aggregate.rs:+2:2: +2:2
}
}

View file

@ -2,6 +2,7 @@
// compile-flags: -O
// EMIT_MIR aggregate.main.ConstProp.diff
// EMIT_MIR aggregate.main.PreCodegen.after.mir
fn main() {
let x = (0, 1, 2).1 + 0;
}

View file

@ -8,8 +8,10 @@
scope 1 {
debug a => _1; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
let mut _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
let mut _6: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
let mut _7: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
scope 2 {
debug x => _2; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
debug x => (i32, i32){ .0 => _6, .1 => _7, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
let _4: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
scope 3 {
debug y => _4; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
@ -30,23 +32,26 @@
}
bb1: {
StorageLive(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
Deinit(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
(_2.0: i32) = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
(_2.1: i32) = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
StorageLive(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
StorageLive(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
Deinit(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
Deinit(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
_6 = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
_7 = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
_3 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
(_2.1: i32) = move _3; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12
_7 = move _3; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12
StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
StorageLive(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
_4 = (_2.1: i32); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16
_4 = _7; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16
StorageLive(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
- _5 = (_2.0: i32); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
- _5 = _6; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
+ _5 = const 1_i32; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
nop; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +6:2
StorageDead(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
StorageDead(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
StorageDead(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
StorageDead(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
StorageDead(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
return; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:2: +6:2
}

View file

@ -10,6 +10,8 @@
let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
scope 1 {
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
@ -51,13 +53,16 @@
StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
(_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
(_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
_10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
_11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2

View file

@ -10,6 +10,8 @@
let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
scope 1 {
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
@ -51,13 +53,16 @@
StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
(_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
(_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
_10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
_11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2

View file

@ -0,0 +1,27 @@
// MIR for `main` after PreCodegen
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
scope 1 {
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
scope 2 {
debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
scope 3 {
debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
}
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
}
}

View file

@ -0,0 +1,27 @@
// MIR for `main` after PreCodegen
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
scope 1 {
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
scope 2 {
debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
scope 3 {
debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
}
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
}
}

View file

@ -0,0 +1,72 @@
- // MIR for `main` before ScalarReplacementOfAggregates
+ // MIR for `main` after ScalarReplacementOfAggregates
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let mut _2: (i32, bool); // in scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18
let mut _4: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:31
let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
scope 1 {
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
scope 2 {
debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
scope 3 {
debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
}
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
_2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18
assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18
}
bb1: {
_1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18
StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31
_4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31
StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
_5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
_6 = Len(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
_7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
}
bb2: {
_3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
- StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
+ StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+ StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
+ StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
}
}

View file

@ -0,0 +1,72 @@
- // MIR for `main` before ScalarReplacementOfAggregates
+ // MIR for `main` after ScalarReplacementOfAggregates
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let mut _2: (i32, bool); // in scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18
let mut _4: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:31
let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
scope 1 {
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
scope 2 {
debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
scope 3 {
debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
}
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
_2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18
assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18
}
bb1: {
_1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18
StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31
_4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31
StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
_5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
_6 = Len(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
_7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
}
bb2: {
_3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
- StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
+ StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+ StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
+ StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
}
}

View file

@ -7,8 +7,10 @@ struct Point {
}
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR optimizes_into_variable.main.ScalarReplacementOfAggregates.diff
// EMIT_MIR optimizes_into_variable.main.ConstProp.diff
// EMIT_MIR optimizes_into_variable.main.SimplifyLocals.after.mir
// EMIT_MIR optimizes_into_variable.main.PreCodegen.after.mir
fn main() {
let x = 2 + 2;
let y = [0, 1, 2, 3, 4, 5][3];

View file

@ -26,6 +26,8 @@
let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _27: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _29: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _30: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 1 {
debug split => _1; // in scope 1 at $DIR/issue_73223.rs:+1:9: +1:14
let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
@ -83,7 +85,8 @@
discriminant(_6) = 1; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
StorageDead(_7); // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28
StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@ -92,15 +95,16 @@
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
_11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Deinit(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Deinit(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Deinit(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_29 = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_30 = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_13 = (_9.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_13 = _29; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_14 = (_9.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_14 = _30; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@ -150,7 +154,8 @@
StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
nop; // scope 0 at $DIR/issue_73223.rs:+0:11: +8:2
StorageDead(_6); // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2

View file

@ -0,0 +1,66 @@
- // MIR for `dropping` before ScalarReplacementOfAggregates
+ // MIR for `dropping` after ScalarReplacementOfAggregates
fn dropping() -> () {
let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19
let _1: Tag; // in scope 0 at $DIR/sroa.rs:+1:5: +1:32
let mut _2: S; // in scope 0 at $DIR/sroa.rs:+1:5: +1:30
let mut _3: Tag; // in scope 0 at $DIR/sroa.rs:+1:7: +1:13
let mut _4: Tag; // in scope 0 at $DIR/sroa.rs:+1:15: +1:21
let mut _5: Tag; // in scope 0 at $DIR/sroa.rs:+1:23: +1:29
bb0: {
StorageLive(_1); // scope 0 at $DIR/sroa.rs:+1:5: +1:32
StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:5: +1:30
StorageLive(_3); // scope 0 at $DIR/sroa.rs:+1:7: +1:13
Deinit(_3); // scope 0 at $DIR/sroa.rs:+1:7: +1:13
(_3.0: usize) = const 0_usize; // scope 0 at $DIR/sroa.rs:+1:7: +1:13
StorageLive(_4); // scope 0 at $DIR/sroa.rs:+1:15: +1:21
Deinit(_4); // scope 0 at $DIR/sroa.rs:+1:15: +1:21
(_4.0: usize) = const 1_usize; // scope 0 at $DIR/sroa.rs:+1:15: +1:21
StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:23: +1:29
Deinit(_5); // scope 0 at $DIR/sroa.rs:+1:23: +1:29
(_5.0: usize) = const 2_usize; // scope 0 at $DIR/sroa.rs:+1:23: +1:29
Deinit(_2); // scope 0 at $DIR/sroa.rs:+1:5: +1:30
(_2.0: Tag) = move _3; // scope 0 at $DIR/sroa.rs:+1:5: +1:30
(_2.1: Tag) = move _4; // scope 0 at $DIR/sroa.rs:+1:5: +1:30
(_2.2: Tag) = move _5; // scope 0 at $DIR/sroa.rs:+1:5: +1:30
StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:29: +1:30
StorageDead(_4); // scope 0 at $DIR/sroa.rs:+1:29: +1:30
StorageDead(_3); // scope 0 at $DIR/sroa.rs:+1:29: +1:30
_1 = move (_2.1: Tag); // scope 0 at $DIR/sroa.rs:+1:5: +1:32
drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
}
bb1: {
drop((_2.0: Tag)) -> [return: bb6, unwind: bb5]; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
}
bb2 (cleanup): {
drop((_2.0: Tag)) -> bb7; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
}
bb3 (cleanup): {
resume; // scope 0 at $DIR/sroa.rs:+0:1: +2:2
}
bb4: {
StorageDead(_2); // scope 0 at $DIR/sroa.rs:+1:32: +1:33
StorageDead(_1); // scope 0 at $DIR/sroa.rs:+1:32: +1:33
_0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +2:2
return; // scope 0 at $DIR/sroa.rs:+2:2: +2:2
}
bb5 (cleanup): {
drop((_2.2: Tag)) -> bb3; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
}
bb6: {
drop((_2.2: Tag)) -> [return: bb4, unwind: bb3]; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
}
bb7 (cleanup): {
drop((_2.2: Tag)) -> bb3; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
}
}

View file

@ -0,0 +1,45 @@
- // MIR for `enums` before ScalarReplacementOfAggregates
+ // MIR for `enums` after ScalarReplacementOfAggregates
fn enums(_1: usize) -> usize {
debug a => _1; // in scope 0 at $DIR/sroa.rs:+0:14: +0:15
let mut _0: usize; // return place in scope 0 at $DIR/sroa.rs:+0:27: +0:32
let mut _2: std::option::Option<usize>; // in scope 0 at $DIR/sroa.rs:+1:22: +1:29
let mut _3: usize; // in scope 0 at $DIR/sroa.rs:+1:27: +1:28
let mut _4: isize; // in scope 0 at $DIR/sroa.rs:+1:12: +1:19
scope 1 {
debug a => _5; // in scope 1 at $DIR/sroa.rs:+1:17: +1:18
let _5: usize; // in scope 1 at $DIR/sroa.rs:+1:17: +1:18
}
bb0: {
StorageLive(_2); // scope 1 at $DIR/sroa.rs:+1:22: +1:29
StorageLive(_3); // scope 1 at $DIR/sroa.rs:+1:27: +1:28
_3 = _1; // scope 1 at $DIR/sroa.rs:+1:27: +1:28
Deinit(_2); // scope 1 at $DIR/sroa.rs:+1:22: +1:29
((_2 as Some).0: usize) = move _3; // scope 1 at $DIR/sroa.rs:+1:22: +1:29
discriminant(_2) = 1; // scope 1 at $DIR/sroa.rs:+1:22: +1:29
StorageDead(_3); // scope 1 at $DIR/sroa.rs:+1:28: +1:29
_4 = discriminant(_2); // scope 1 at $DIR/sroa.rs:+1:12: +1:19
switchInt(move _4) -> [1_isize: bb1, otherwise: bb2]; // scope 1 at $DIR/sroa.rs:+1:12: +1:19
}
bb1: {
StorageLive(_5); // scope 1 at $DIR/sroa.rs:+1:17: +1:18
_5 = ((_2 as Some).0: usize); // scope 1 at $DIR/sroa.rs:+1:17: +1:18
_0 = _5; // scope 1 at $DIR/sroa.rs:+1:32: +1:33
StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:34: +1:35
goto -> bb3; // scope 0 at $DIR/sroa.rs:+1:5: +1:46
}
bb2: {
_0 = const 0_usize; // scope 0 at $DIR/sroa.rs:+1:43: +1:44
goto -> bb3; // scope 0 at $DIR/sroa.rs:+1:5: +1:46
}
bb3: {
StorageDead(_2); // scope 0 at $DIR/sroa.rs:+2:1: +2:2
return; // scope 0 at $DIR/sroa.rs:+2:2: +2:2
}
}

View file

@ -0,0 +1,47 @@
- // MIR for `escaping` before ScalarReplacementOfAggregates
+ // MIR for `escaping` after ScalarReplacementOfAggregates
fn escaping() -> () {
let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19
let _1: (); // in scope 0 at $DIR/sroa.rs:+2:5: +2:42
let mut _2: *const u32; // in scope 0 at $DIR/sroa.rs:+2:7: +2:41
let _3: &u32; // in scope 0 at $DIR/sroa.rs:+2:7: +2:41
let _4: Escaping; // in scope 0 at $DIR/sroa.rs:+2:8: +2:39
let mut _5: u32; // in scope 0 at $DIR/sroa.rs:+2:34: +2:37
bb0: {
StorageLive(_1); // scope 0 at $DIR/sroa.rs:+2:5: +2:42
StorageLive(_2); // scope 0 at $DIR/sroa.rs:+2:7: +2:41
StorageLive(_3); // scope 0 at $DIR/sroa.rs:+2:7: +2:41
StorageLive(_4); // scope 0 at $DIR/sroa.rs:+2:8: +2:39
StorageLive(_5); // scope 0 at $DIR/sroa.rs:+2:34: +2:37
_5 = g() -> bb1; // scope 0 at $DIR/sroa.rs:+2:34: +2:37
// mir::Constant
// + span: $DIR/sroa.rs:76:34: 76:35
// + literal: Const { ty: fn() -> u32 {g}, val: Value(<ZST>) }
}
bb1: {
Deinit(_4); // scope 0 at $DIR/sroa.rs:+2:8: +2:39
(_4.0: u32) = const 1_u32; // scope 0 at $DIR/sroa.rs:+2:8: +2:39
(_4.1: u32) = const 2_u32; // scope 0 at $DIR/sroa.rs:+2:8: +2:39
(_4.2: u32) = move _5; // scope 0 at $DIR/sroa.rs:+2:8: +2:39
StorageDead(_5); // scope 0 at $DIR/sroa.rs:+2:38: +2:39
_3 = &(_4.0: u32); // scope 0 at $DIR/sroa.rs:+2:7: +2:41
_2 = &raw const (*_3); // scope 0 at $DIR/sroa.rs:+2:7: +2:41
_1 = f(move _2) -> bb2; // scope 0 at $DIR/sroa.rs:+2:5: +2:42
// mir::Constant
// + span: $DIR/sroa.rs:76:5: 76:6
// + literal: Const { ty: fn(*const u32) {f}, val: Value(<ZST>) }
}
bb2: {
StorageDead(_2); // scope 0 at $DIR/sroa.rs:+2:41: +2:42
StorageDead(_4); // scope 0 at $DIR/sroa.rs:+2:42: +2:43
StorageDead(_3); // scope 0 at $DIR/sroa.rs:+2:42: +2:43
StorageDead(_1); // scope 0 at $DIR/sroa.rs:+2:42: +2:43
_0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +3:2
return; // scope 0 at $DIR/sroa.rs:+3:2: +3:2
}
}

View file

@ -0,0 +1,87 @@
- // MIR for `flat` before ScalarReplacementOfAggregates
+ // MIR for `flat` after ScalarReplacementOfAggregates
fn flat() -> () {
let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:15: +0:15
let _1: u8; // in scope 0 at $DIR/sroa.rs:+1:15: +1:16
let _2: (); // in scope 0 at $DIR/sroa.rs:+1:18: +1:19
let _3: &str; // in scope 0 at $DIR/sroa.rs:+1:21: +1:22
let _4: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:24: +1:25
let mut _5: Foo; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
let mut _6: (); // in scope 0 at $DIR/sroa.rs:+1:45: +1:47
let mut _7: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:60: +1:68
+ let mut _8: u8; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ let mut _9: (); // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ let mut _10: &str; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ let mut _11: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
scope 1 {
debug a => _1; // in scope 1 at $DIR/sroa.rs:+1:15: +1:16
debug b => _2; // in scope 1 at $DIR/sroa.rs:+1:18: +1:19
debug c => _3; // in scope 1 at $DIR/sroa.rs:+1:21: +1:22
debug d => _4; // in scope 1 at $DIR/sroa.rs:+1:24: +1:25
scope 2 {
scope 3 {
scope 4 {
scope 5 {
}
}
}
}
}
bb0: {
- StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ StorageLive(_8); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ StorageLive(_9); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ StorageLive(_10); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ StorageLive(_11); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
StorageLive(_6); // scope 0 at $DIR/sroa.rs:+1:45: +1:47
Deinit(_6); // scope 0 at $DIR/sroa.rs:+1:45: +1:47
StorageLive(_7); // scope 0 at $DIR/sroa.rs:+1:60: +1:68
Deinit(_7); // scope 0 at $DIR/sroa.rs:+1:60: +1:68
((_7 as Some).0: isize) = const -4_isize; // scope 0 at $DIR/sroa.rs:+1:60: +1:68
discriminant(_7) = 1; // scope 0 at $DIR/sroa.rs:+1:60: +1:68
- Deinit(_5); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
- (_5.0: u8) = const 5_u8; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
- (_5.1: ()) = move _6; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
- (_5.2: &str) = const "a"; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ Deinit(_8); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ Deinit(_9); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ Deinit(_10); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ Deinit(_11); // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ _8 = const 5_u8; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ _9 = move _6; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ _10 = const "a"; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
// mir::Constant
// + span: $DIR/sroa.rs:55:52: 55:55
// + literal: Const { ty: &str, val: Value(Slice(..)) }
- (_5.3: std::option::Option<isize>) = move _7; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+ _11 = move _7; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
StorageDead(_7); // scope 0 at $DIR/sroa.rs:+1:69: +1:70
StorageDead(_6); // scope 0 at $DIR/sroa.rs:+1:69: +1:70
StorageLive(_1); // scope 0 at $DIR/sroa.rs:+1:15: +1:16
- _1 = (_5.0: u8); // scope 0 at $DIR/sroa.rs:+1:15: +1:16
+ _1 = _8; // scope 0 at $DIR/sroa.rs:+1:15: +1:16
StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:18: +1:19
- _2 = (_5.1: ()); // scope 0 at $DIR/sroa.rs:+1:18: +1:19
+ _2 = _9; // scope 0 at $DIR/sroa.rs:+1:18: +1:19
StorageLive(_3); // scope 0 at $DIR/sroa.rs:+1:21: +1:22
- _3 = (_5.2: &str); // scope 0 at $DIR/sroa.rs:+1:21: +1:22
+ _3 = _10; // scope 0 at $DIR/sroa.rs:+1:21: +1:22
StorageLive(_4); // scope 0 at $DIR/sroa.rs:+1:24: +1:25
- _4 = (_5.3: std::option::Option<isize>); // scope 0 at $DIR/sroa.rs:+1:24: +1:25
- StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:70: +1:71
+ _4 = _11; // scope 0 at $DIR/sroa.rs:+1:24: +1:25
+ StorageDead(_8); // scope 0 at $DIR/sroa.rs:+1:70: +1:71
+ StorageDead(_9); // scope 0 at $DIR/sroa.rs:+1:70: +1:71
+ StorageDead(_10); // scope 0 at $DIR/sroa.rs:+1:70: +1:71
+ StorageDead(_11); // scope 0 at $DIR/sroa.rs:+1:70: +1:71
_0 = const (); // scope 0 at $DIR/sroa.rs:+0:15: +6:2
StorageDead(_4); // scope 0 at $DIR/sroa.rs:+6:1: +6:2
StorageDead(_3); // scope 0 at $DIR/sroa.rs:+6:1: +6:2
StorageDead(_2); // scope 0 at $DIR/sroa.rs:+6:1: +6:2
StorageDead(_1); // scope 0 at $DIR/sroa.rs:+6:1: +6:2
return; // scope 0 at $DIR/sroa.rs:+6:2: +6:2
}
}

86
src/test/mir-opt/sroa.rs Normal file
View file

@ -0,0 +1,86 @@
// unit-test: ScalarReplacementOfAggregates
struct Tag(usize);
#[repr(C)]
struct S(Tag, Tag, Tag);
impl Drop for Tag {
#[inline(never)]
fn drop(&mut self) {}
}
// EMIT_MIR sroa.dropping.ScalarReplacementOfAggregates.diff
pub fn dropping() {
S(Tag(0), Tag(1), Tag(2)).1;
}
// EMIT_MIR sroa.enums.ScalarReplacementOfAggregates.diff
pub fn enums(a: usize) -> usize {
if let Some(a) = Some(a) { a } else { 0 }
}
// EMIT_MIR sroa.structs.ScalarReplacementOfAggregates.diff
pub fn structs(a: f32) -> f32 {
struct U {
_foo: usize,
a: f32,
}
U { _foo: 0, a }.a
}
// EMIT_MIR sroa.unions.ScalarReplacementOfAggregates.diff
pub fn unions(a: f32) -> u32 {
union Repr {
f: f32,
u: u32,
}
unsafe { Repr { f: a }.u }
}
struct Foo {
a: u8,
b: (),
c: &'static str,
d: Option<isize>,
}
fn g() -> u32 {
3
}
// EMIT_MIR sroa.flat.ScalarReplacementOfAggregates.diff
pub fn flat() {
let Foo { a, b, c, d } = Foo { a: 5, b: (), c: "a", d: Some(-4) };
let _ = a;
let _ = b;
let _ = c;
let _ = d;
}
#[repr(C)]
struct Escaping {
a: u32,
b: u32,
c: u32,
}
fn f(a: *const u32) {
println!("{}", unsafe { *a.add(2) });
}
// EMIT_MIR sroa.escaping.ScalarReplacementOfAggregates.diff
pub fn escaping() {
// Verify this struct is not flattened.
f(&Escaping { a: 1, b: 2, c: g() }.a);
}
fn main() {
dropping();
enums(5);
structs(5.);
unions(5.);
flat();
escaping();
}

View file

@ -0,0 +1,34 @@
- // MIR for `structs` before ScalarReplacementOfAggregates
+ // MIR for `structs` after ScalarReplacementOfAggregates
fn structs(_1: f32) -> f32 {
debug a => _1; // in scope 0 at $DIR/sroa.rs:+0:16: +0:17
let mut _0: f32; // return place in scope 0 at $DIR/sroa.rs:+0:27: +0:30
let mut _2: structs::U; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21
let mut _3: f32; // in scope 0 at $DIR/sroa.rs:+6:18: +6:19
+ let mut _4: usize; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21
+ let mut _5: f32; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21
bb0: {
- StorageLive(_2); // scope 0 at $DIR/sroa.rs:+6:5: +6:21
+ StorageLive(_4); // scope 0 at $DIR/sroa.rs:+6:5: +6:21
+ StorageLive(_5); // scope 0 at $DIR/sroa.rs:+6:5: +6:21
StorageLive(_3); // scope 0 at $DIR/sroa.rs:+6:18: +6:19
_3 = _1; // scope 0 at $DIR/sroa.rs:+6:18: +6:19
- Deinit(_2); // scope 0 at $DIR/sroa.rs:+6:5: +6:21
- (_2.0: usize) = const 0_usize; // scope 0 at $DIR/sroa.rs:+6:5: +6:21
- (_2.1: f32) = move _3; // scope 0 at $DIR/sroa.rs:+6:5: +6:21
+ Deinit(_4); // scope 0 at $DIR/sroa.rs:+6:5: +6:21
+ Deinit(_5); // scope 0 at $DIR/sroa.rs:+6:5: +6:21
+ _4 = const 0_usize; // scope 0 at $DIR/sroa.rs:+6:5: +6:21
+ _5 = move _3; // scope 0 at $DIR/sroa.rs:+6:5: +6:21
StorageDead(_3); // scope 0 at $DIR/sroa.rs:+6:20: +6:21
- _0 = (_2.1: f32); // scope 0 at $DIR/sroa.rs:+6:5: +6:23
- StorageDead(_2); // scope 0 at $DIR/sroa.rs:+7:1: +7:2
+ _0 = _5; // scope 0 at $DIR/sroa.rs:+6:5: +6:23
+ StorageDead(_4); // scope 0 at $DIR/sroa.rs:+7:1: +7:2
+ StorageDead(_5); // scope 0 at $DIR/sroa.rs:+7:1: +7:2
return; // scope 0 at $DIR/sroa.rs:+7:2: +7:2
}
}

View file

@ -0,0 +1,24 @@
- // MIR for `unions` before ScalarReplacementOfAggregates
+ // MIR for `unions` after ScalarReplacementOfAggregates
fn unions(_1: f32) -> u32 {
debug a => _1; // in scope 0 at $DIR/sroa.rs:+0:15: +0:16
let mut _0: u32; // return place in scope 0 at $DIR/sroa.rs:+0:26: +0:29
let mut _2: unions::Repr; // in scope 0 at $DIR/sroa.rs:+5:14: +5:27
let mut _3: f32; // in scope 0 at $DIR/sroa.rs:+5:24: +5:25
scope 1 {
}
bb0: {
StorageLive(_2); // scope 1 at $DIR/sroa.rs:+5:14: +5:27
StorageLive(_3); // scope 1 at $DIR/sroa.rs:+5:24: +5:25
_3 = _1; // scope 1 at $DIR/sroa.rs:+5:24: +5:25
Deinit(_2); // scope 1 at $DIR/sroa.rs:+5:14: +5:27
(_2.0: f32) = move _3; // scope 1 at $DIR/sroa.rs:+5:14: +5:27
StorageDead(_3); // scope 1 at $DIR/sroa.rs:+5:26: +5:27
_0 = (_2.1: u32); // scope 1 at $DIR/sroa.rs:+5:14: +5:29
StorageDead(_2); // scope 0 at $DIR/sroa.rs:+6:1: +6:2
return; // scope 0 at $DIR/sroa.rs:+6:2: +6:2
}
}