Auto merge of #102570 - cjgillot:deagg-debuginfo, r=oli-obk
Perform simple scalar replacement of aggregates (SROA) MIR opt This is a re-open of https://github.com/rust-lang/rust/pull/85796 I copied the debuginfo implementation (first commit) from `@eddyb's` own SROA PR. This pass replaces plain field accesses by simple locals when possible. To be eligible, the replaced locals: - must not be enums or unions; - must not be used whole; - must not have their address taken. The storage and deinit statements are duplicated on each created local. cc `@tmiasko` who reviewed the former version of this PR.
This commit is contained in:
commit
79146baa9c
29 changed files with 1228 additions and 57 deletions
|
@ -4,8 +4,9 @@ use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
|
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
|
||||||
use rustc_span::{SourceFile, Span, Symbol};
|
use rustc_span::{SourceFile, Span, Symbol};
|
||||||
use rustc_target::abi::Size;
|
|
||||||
use rustc_target::abi::call::FnAbi;
|
use rustc_target::abi::call::FnAbi;
|
||||||
|
use rustc_target::abi::Size;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
use crate::context::CodegenCx;
|
use crate::context::CodegenCx;
|
||||||
|
@ -13,7 +14,15 @@ use crate::context::CodegenCx;
|
||||||
impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
||||||
// FIXME(eddyb) find a common convention for all of the debuginfo-related
|
// FIXME(eddyb) find a common convention for all of the debuginfo-related
|
||||||
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
|
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
|
||||||
fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) {
|
fn dbg_var_addr(
|
||||||
|
&mut self,
|
||||||
|
_dbg_var: Self::DIVariable,
|
||||||
|
_scope_metadata: Self::DIScope,
|
||||||
|
_variable_alloca: Self::Value,
|
||||||
|
_direct_offset: Size,
|
||||||
|
_indirect_offsets: &[Size],
|
||||||
|
_fragment: Option<Range<Size>>,
|
||||||
|
) {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,16 +40,31 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||||
fn create_vtable_debuginfo(&self, _ty: Ty<'tcx>, _trait_ref: Option<PolyExistentialTraitRef<'tcx>>, _vtable: Self::Value) {
|
fn create_vtable_debuginfo(
|
||||||
|
&self,
|
||||||
|
_ty: Ty<'tcx>,
|
||||||
|
_trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
|
||||||
|
_vtable: Self::Value,
|
||||||
|
) {
|
||||||
// TODO(antoyo)
|
// TODO(antoyo)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
|
fn create_function_debug_context(
|
||||||
|
&self,
|
||||||
|
_instance: Instance<'tcx>,
|
||||||
|
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||||
|
_llfn: RValue<'gcc>,
|
||||||
|
_mir: &mir::Body<'tcx>,
|
||||||
|
) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
|
||||||
// TODO(antoyo)
|
// TODO(antoyo)
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope {
|
fn extend_scope_to_file(
|
||||||
|
&self,
|
||||||
|
_scope_metadata: Self::DIScope,
|
||||||
|
_file: &SourceFile,
|
||||||
|
) -> Self::DIScope {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,15 +72,32 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||||
// TODO(antoyo)
|
// TODO(antoyo)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable {
|
fn create_dbg_var(
|
||||||
|
&self,
|
||||||
|
_variable_name: Symbol,
|
||||||
|
_variable_type: Ty<'tcx>,
|
||||||
|
_scope_metadata: Self::DIScope,
|
||||||
|
_variable_kind: VariableKind,
|
||||||
|
_span: Span,
|
||||||
|
) -> Self::DIVariable {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option<RValue<'gcc>>) -> Self::DIScope {
|
fn dbg_scope_fn(
|
||||||
|
&self,
|
||||||
|
_instance: Instance<'tcx>,
|
||||||
|
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||||
|
_maybe_definition_llfn: Option<RValue<'gcc>>,
|
||||||
|
) -> Self::DIScope {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option<Self::DILocation>, _span: Span) -> Self::DILocation {
|
fn dbg_loc(
|
||||||
|
&self,
|
||||||
|
_scope: Self::DIScope,
|
||||||
|
_inlined_at: Option<Self::DILocation>,
|
||||||
|
_span: Span,
|
||||||
|
) -> Self::DILocation {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ use smallvec::SmallVec;
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
mod create_scope_map;
|
mod create_scope_map;
|
||||||
pub mod gdb;
|
pub mod gdb;
|
||||||
|
@ -163,12 +164,14 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
|
||||||
variable_alloca: Self::Value,
|
variable_alloca: Self::Value,
|
||||||
direct_offset: Size,
|
direct_offset: Size,
|
||||||
indirect_offsets: &[Size],
|
indirect_offsets: &[Size],
|
||||||
|
fragment: Option<Range<Size>>,
|
||||||
) {
|
) {
|
||||||
// Convert the direct and indirect offsets to address ops.
|
// Convert the direct and indirect offsets and fragment byte range to address ops.
|
||||||
// FIXME(eddyb) use `const`s instead of getting the values via FFI,
|
// FIXME(eddyb) use `const`s instead of getting the values via FFI,
|
||||||
// the values should match the ones in the DWARF standard anyway.
|
// the values should match the ones in the DWARF standard anyway.
|
||||||
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
|
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
|
||||||
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
|
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
|
||||||
|
let op_llvm_fragment = || unsafe { llvm::LLVMRustDIBuilderCreateOpLLVMFragment() };
|
||||||
let mut addr_ops = SmallVec::<[u64; 8]>::new();
|
let mut addr_ops = SmallVec::<[u64; 8]>::new();
|
||||||
|
|
||||||
if direct_offset.bytes() > 0 {
|
if direct_offset.bytes() > 0 {
|
||||||
|
@ -182,6 +185,13 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
|
||||||
addr_ops.push(offset.bytes() as u64);
|
addr_ops.push(offset.bytes() as u64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(fragment) = fragment {
|
||||||
|
// `DW_OP_LLVM_fragment` takes as arguments the fragment's
|
||||||
|
// offset and size, both of them in bits.
|
||||||
|
addr_ops.push(op_llvm_fragment());
|
||||||
|
addr_ops.push(fragment.start.bits() as u64);
|
||||||
|
addr_ops.push((fragment.end - fragment.start).bits() as u64);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
|
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
|
||||||
|
|
|
@ -2210,6 +2210,7 @@ extern "C" {
|
||||||
) -> &'a DILocation;
|
) -> &'a DILocation;
|
||||||
pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
|
pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
|
||||||
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
|
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
|
||||||
|
pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
|
||||||
|
|
||||||
#[allow(improper_ctypes)]
|
#[allow(improper_ctypes)]
|
||||||
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
|
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
|
||||||
|
|
|
@ -14,6 +14,8 @@ use super::operand::{OperandRef, OperandValue};
|
||||||
use super::place::PlaceRef;
|
use super::place::PlaceRef;
|
||||||
use super::{FunctionCx, LocalRef};
|
use super::{FunctionCx, LocalRef};
|
||||||
|
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
pub struct FunctionDebugContext<S, L> {
|
pub struct FunctionDebugContext<S, L> {
|
||||||
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
|
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
|
||||||
}
|
}
|
||||||
|
@ -25,7 +27,7 @@ pub enum VariableKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `mir::VarDebugInfo`, but within a `mir::Local`.
|
/// Like `mir::VarDebugInfo`, but within a `mir::Local`.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PerLocalVarDebugInfo<'tcx, D> {
|
pub struct PerLocalVarDebugInfo<'tcx, D> {
|
||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
pub source_info: mir::SourceInfo,
|
pub source_info: mir::SourceInfo,
|
||||||
|
@ -33,6 +35,10 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
|
||||||
/// `DIVariable` returned by `create_dbg_var`.
|
/// `DIVariable` returned by `create_dbg_var`.
|
||||||
pub dbg_var: Option<D>,
|
pub dbg_var: Option<D>,
|
||||||
|
|
||||||
|
/// Byte range in the `dbg_var` covered by this fragment,
|
||||||
|
/// if this is a fragment of a composite `VarDebugInfo`.
|
||||||
|
pub fragment: Option<Range<Size>>,
|
||||||
|
|
||||||
/// `.place.projection` from `mir::VarDebugInfo`.
|
/// `.place.projection` from `mir::VarDebugInfo`.
|
||||||
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
|
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
|
||||||
}
|
}
|
||||||
|
@ -145,7 +151,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
Some(per_local) => &per_local[local],
|
Some(per_local) => &per_local[local],
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).copied();
|
let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned();
|
||||||
let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
|
let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
|
||||||
|
|
||||||
let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
|
let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
|
||||||
|
@ -187,6 +193,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
name,
|
name,
|
||||||
source_info: decl.source_info,
|
source_info: decl.source_info,
|
||||||
dbg_var,
|
dbg_var,
|
||||||
|
fragment: None,
|
||||||
projection: ty::List::empty(),
|
projection: ty::List::empty(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -199,7 +206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let name = if bx.sess().fewer_names() {
|
let name = if bx.sess().fewer_names() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(match whole_local_var.or(fallback_var) {
|
Some(match whole_local_var.or(fallback_var.clone()) {
|
||||||
Some(var) if var.name != kw::Empty => var.name.to_string(),
|
Some(var) if var.name != kw::Empty => var.name.to_string(),
|
||||||
_ => format!("{:?}", local),
|
_ => format!("{:?}", local),
|
||||||
})
|
})
|
||||||
|
@ -249,7 +256,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
LocalRef::UnsizedPlace(_) => return,
|
LocalRef::UnsizedPlace(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let vars = vars.iter().copied().chain(fallback_var);
|
let vars = vars.iter().cloned().chain(fallback_var);
|
||||||
|
|
||||||
for var in vars {
|
for var in vars {
|
||||||
let Some(dbg_var) = var.dbg_var else { continue };
|
let Some(dbg_var) = var.dbg_var else { continue };
|
||||||
|
@ -312,9 +319,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
bx.store(place.llval, alloca.llval, alloca.align);
|
bx.store(place.llval, alloca.llval, alloca.align);
|
||||||
|
|
||||||
// Point the debug info to `*alloca` for the current variable
|
// Point the debug info to `*alloca` for the current variable
|
||||||
bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO]);
|
bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None);
|
||||||
} else {
|
} else {
|
||||||
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets);
|
bx.dbg_var_addr(
|
||||||
|
dbg_var,
|
||||||
|
dbg_loc,
|
||||||
|
base.llval,
|
||||||
|
direct_offset,
|
||||||
|
&indirect_offsets,
|
||||||
|
None,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,6 +396,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let ty = self.monomorphize(c.ty());
|
let ty = self.monomorphize(c.ty());
|
||||||
(ty, VariableKind::LocalVariable)
|
(ty, VariableKind::LocalVariable)
|
||||||
}
|
}
|
||||||
|
mir::VarDebugInfoContents::Composite { ty, fragments: _ } => {
|
||||||
|
let ty = self.monomorphize(ty);
|
||||||
|
(ty, VariableKind::LocalVariable)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
|
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
|
||||||
|
@ -393,6 +411,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
name: var.name,
|
name: var.name,
|
||||||
source_info: var.source_info,
|
source_info: var.source_info,
|
||||||
dbg_var,
|
dbg_var,
|
||||||
|
fragment: None,
|
||||||
projection: place.projection,
|
projection: place.projection,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -407,10 +426,48 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
bx,
|
bx,
|
||||||
);
|
);
|
||||||
|
|
||||||
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[]);
|
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mir::VarDebugInfoContents::Composite { ty, ref fragments } => {
|
||||||
|
let var_ty = self.monomorphize(ty);
|
||||||
|
let var_layout = self.cx.layout_of(var_ty);
|
||||||
|
for fragment in fragments {
|
||||||
|
let mut fragment_start = Size::ZERO;
|
||||||
|
let mut fragment_layout = var_layout;
|
||||||
|
|
||||||
|
for elem in &fragment.projection {
|
||||||
|
match *elem {
|
||||||
|
mir::ProjectionElem::Field(field, _) => {
|
||||||
|
let i = field.index();
|
||||||
|
fragment_start += fragment_layout.fields.offset(i);
|
||||||
|
fragment_layout = fragment_layout.field(self.cx, i);
|
||||||
|
}
|
||||||
|
_ => span_bug!(
|
||||||
|
var.source_info.span,
|
||||||
|
"unsupported fragment projection `{:?}`",
|
||||||
|
elem,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let place = fragment.contents;
|
||||||
|
per_local[place.local].push(PerLocalVarDebugInfo {
|
||||||
|
name: var.name,
|
||||||
|
source_info: var.source_info,
|
||||||
|
dbg_var,
|
||||||
|
fragment: if fragment_layout.size == var_layout.size {
|
||||||
|
// Fragment covers entire variable, so as far as
|
||||||
|
// DWARF is concerned, it's not really a fragment.
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(fragment_start..fragment_start + fragment_layout.size)
|
||||||
|
},
|
||||||
|
projection: place.projection,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(per_local)
|
Some(per_local)
|
||||||
|
|
|
@ -6,6 +6,8 @@ use rustc_span::{SourceFile, Span, Symbol};
|
||||||
use rustc_target::abi::call::FnAbi;
|
use rustc_target::abi::call::FnAbi;
|
||||||
use rustc_target::abi::Size;
|
use rustc_target::abi::Size;
|
||||||
|
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
pub trait DebugInfoMethods<'tcx>: BackendTypes {
|
pub trait DebugInfoMethods<'tcx>: BackendTypes {
|
||||||
fn create_vtable_debuginfo(
|
fn create_vtable_debuginfo(
|
||||||
&self,
|
&self,
|
||||||
|
@ -72,6 +74,9 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
|
||||||
direct_offset: Size,
|
direct_offset: Size,
|
||||||
// NB: each offset implies a deref (i.e. they're steps in a pointer chain).
|
// NB: each offset implies a deref (i.e. they're steps in a pointer chain).
|
||||||
indirect_offsets: &[Size],
|
indirect_offsets: &[Size],
|
||||||
|
// Byte range in the `dbg_var` covered by this fragment,
|
||||||
|
// if this is a fragment of a composite `DIVariable`.
|
||||||
|
fragment: Option<Range<Size>>,
|
||||||
);
|
);
|
||||||
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
|
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
|
||||||
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
|
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
|
||||||
|
|
|
@ -1111,6 +1111,10 @@ extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
|
||||||
return dwarf::DW_OP_plus_uconst;
|
return dwarf::DW_OP_plus_uconst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int64_t LLVMRustDIBuilderCreateOpLLVMFragment() {
|
||||||
|
return dwarf::DW_OP_LLVM_fragment;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) {
|
extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) {
|
||||||
RawRustStringOstream OS(Str);
|
RawRustStringOstream OS(Str);
|
||||||
unwrap<llvm::Type>(Ty)->print(OS);
|
unwrap<llvm::Type>(Ty)->print(OS);
|
||||||
|
|
|
@ -1071,6 +1071,18 @@ pub enum VarDebugInfoContents<'tcx> {
|
||||||
/// based on a `Local`, not a `Static`, and contains no indexing.
|
/// based on a `Local`, not a `Static`, and contains no indexing.
|
||||||
Place(Place<'tcx>),
|
Place(Place<'tcx>),
|
||||||
Const(Constant<'tcx>),
|
Const(Constant<'tcx>),
|
||||||
|
/// The user variable's data is split across several fragments,
|
||||||
|
/// each described by a `VarDebugInfoFragment`.
|
||||||
|
/// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
|
||||||
|
/// and LLVM's `DW_OP_LLVM_fragment` for more details on
|
||||||
|
/// the underlying debuginfo feature this relies on.
|
||||||
|
Composite {
|
||||||
|
/// Type of the original user variable.
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
/// All the parts of the original user variable, which ended
|
||||||
|
/// up in disjoint places, due to optimizations.
|
||||||
|
fragments: Vec<VarDebugInfoFragment<'tcx>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
||||||
|
@ -1078,7 +1090,48 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
||||||
match self {
|
match self {
|
||||||
VarDebugInfoContents::Const(c) => write!(fmt, "{}", c),
|
VarDebugInfoContents::Const(c) => write!(fmt, "{}", c),
|
||||||
VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p),
|
VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p),
|
||||||
|
VarDebugInfoContents::Composite { ty, fragments } => {
|
||||||
|
write!(fmt, "{:?}{{ ", ty)?;
|
||||||
|
for f in fragments.iter() {
|
||||||
|
write!(fmt, "{:?}, ", f)?;
|
||||||
}
|
}
|
||||||
|
write!(fmt, "}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
|
pub struct VarDebugInfoFragment<'tcx> {
|
||||||
|
/// Where in the composite user variable this fragment is,
|
||||||
|
/// represented as a "projection" into the composite variable.
|
||||||
|
/// At lower levels, this corresponds to a byte/bit range.
|
||||||
|
// NOTE(eddyb) there's an unenforced invariant that this contains
|
||||||
|
// only `Field`s, and not into `enum` variants or `union`s.
|
||||||
|
// FIXME(eddyb) support this for `enum`s by either using DWARF's
|
||||||
|
// more advanced control-flow features (unsupported by LLVM?)
|
||||||
|
// to match on the discriminant, or by using custom type debuginfo
|
||||||
|
// with non-overlapping variants for the composite variable.
|
||||||
|
pub projection: Vec<PlaceElem<'tcx>>,
|
||||||
|
|
||||||
|
/// Where the data for this fragment can be found.
|
||||||
|
// NOTE(eddyb) There's an unenforced invariant that this `Place` is
|
||||||
|
// contains no indexing (with a non-constant index).
|
||||||
|
pub contents: Place<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VarDebugInfoFragment<'_> {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
for elem in self.projection.iter() {
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Field(field, _) => {
|
||||||
|
write!(fmt, ".{:?}", field.index())?;
|
||||||
|
}
|
||||||
|
_ => bug!("unsupported fragment projection `{:?}`", elem),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(fmt, " => {:?}", self.contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -847,6 +847,17 @@ macro_rules! make_mir_visitor {
|
||||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
||||||
location
|
location
|
||||||
),
|
),
|
||||||
|
VarDebugInfoContents::Composite { ty, fragments } => {
|
||||||
|
// FIXME(eddyb) use a better `TyContext` here.
|
||||||
|
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||||
|
for VarDebugInfoFragment { projection: _, contents } in fragments {
|
||||||
|
self.visit_place(
|
||||||
|
contents,
|
||||||
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
||||||
|
location,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(drain_filter)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(map_try_insert)]
|
#![feature(map_try_insert)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
|
@ -92,6 +93,7 @@ pub mod simplify;
|
||||||
mod simplify_branches;
|
mod simplify_branches;
|
||||||
mod simplify_comparison_integral;
|
mod simplify_comparison_integral;
|
||||||
mod simplify_try;
|
mod simplify_try;
|
||||||
|
mod sroa;
|
||||||
mod uninhabited_enum_branching;
|
mod uninhabited_enum_branching;
|
||||||
mod unreachable_prop;
|
mod unreachable_prop;
|
||||||
|
|
||||||
|
@ -562,6 +564,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
&remove_zsts::RemoveZsts,
|
&remove_zsts::RemoveZsts,
|
||||||
&const_goto::ConstGoto,
|
&const_goto::ConstGoto,
|
||||||
&remove_unneeded_drops::RemoveUnneededDrops,
|
&remove_unneeded_drops::RemoveUnneededDrops,
|
||||||
|
&sroa::ScalarReplacementOfAggregates,
|
||||||
&match_branches::MatchBranchSimplification,
|
&match_branches::MatchBranchSimplification,
|
||||||
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
|
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
|
||||||
&multiple_return_terminators::MultipleReturnTerminators,
|
&multiple_return_terminators::MultipleReturnTerminators,
|
||||||
|
|
348
compiler/rustc_mir_transform/src/sroa.rs
Normal file
348
compiler/rustc_mir_transform/src/sroa.rs
Normal 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() >= 3
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,14 +30,19 @@
|
||||||
- debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10
|
- 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
|
+ 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 _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 {
|
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
|
let _11: std::option::Option<u16>; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
|
||||||
scope 7 {
|
scope 7 {
|
||||||
debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10
|
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 _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 {
|
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
|
let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
|
||||||
scope 9 {
|
scope 9 {
|
||||||
- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
|
- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
|
||||||
|
@ -78,19 +83,25 @@
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/const_debuginfo.rs:14:13: 14:28
|
// + span: $DIR/const_debuginfo.rs:14:13: 14:28
|
||||||
// + literal: Const { ty: &str, val: Value(Slice(..)) }
|
// + literal: Const { ty: &str, val: Value(Slice(..)) }
|
||||||
StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
|
StorageLive(_16); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
|
||||||
Deinit(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
|
StorageLive(_17); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
|
||||||
(_10.0: bool) = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
|
StorageLive(_18); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
|
||||||
(_10.1: bool) = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
|
Deinit(_16); // 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
|
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
|
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
|
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
|
((_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
|
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
|
StorageLive(_19); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
|
||||||
Deinit(_12); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
|
StorageLive(_20); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
|
||||||
(_12.0: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
|
Deinit(_19); // 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
|
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(_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
|
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
|
_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
|
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
|
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(_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(_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(_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(_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
|
StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
// compile-flags: -O
|
// compile-flags: -O
|
||||||
|
|
||||||
// EMIT_MIR aggregate.main.ConstProp.diff
|
// EMIT_MIR aggregate.main.ConstProp.diff
|
||||||
|
// EMIT_MIR aggregate.main.PreCodegen.after.mir
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = (0, 1, 2).1 + 0;
|
let x = (0, 1, 2).1 + 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,10 @@
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug a => _1; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
|
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 _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 {
|
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
|
let _4: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
|
||||||
scope 3 {
|
scope 3 {
|
||||||
debug y => _4; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
|
debug y => _4; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
|
||||||
|
@ -30,23 +32,26 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
StorageLive(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
|
StorageLive(_6); // 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
|
StorageLive(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
|
||||||
(_2.0: i32) = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
|
Deinit(_6); // 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
|
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
|
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
|
_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
|
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
|
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
|
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
|
+ _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
|
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(_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(_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
|
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
|
return; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:2: +6:2
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
|
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 _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 _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 {
|
scope 1 {
|
||||||
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
|
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
|
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(_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
|
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(_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
|
StorageLive(_10); // 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
|
StorageLive(_11); // 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
|
Deinit(_10); // 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
|
Deinit(_11); // 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
|
_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
|
+ _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
|
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(_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(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
|
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 _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 _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 {
|
scope 1 {
|
||||||
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
|
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
|
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(_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
|
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(_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
|
StorageLive(_10); // 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
|
StorageLive(_11); // 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
|
Deinit(_10); // 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
|
Deinit(_11); // 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
|
_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
|
+ _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
|
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(_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(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@ struct Point {
|
||||||
}
|
}
|
||||||
|
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// 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.ConstProp.diff
|
||||||
// EMIT_MIR optimizes_into_variable.main.SimplifyLocals.after.mir
|
// EMIT_MIR optimizes_into_variable.main.SimplifyLocals.after.mir
|
||||||
|
// EMIT_MIR optimizes_into_variable.main.PreCodegen.after.mir
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = 2 + 2;
|
let x = 2 + 2;
|
||||||
let y = [0, 1, 2, 3, 4, 5][3];
|
let y = [0, 1, 2, 3, 4, 5][3];
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
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 _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 _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 {
|
scope 1 {
|
||||||
debug split => _1; // in scope 1 at $DIR/issue_73223.rs:+1:9: +1:14
|
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
|
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
|
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
|
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(_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
|
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
|
_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
|
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
|
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||||
// + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
|
// + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
|
||||||
_11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
_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
|
Deinit(_29); // 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
|
Deinit(_30); // 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
|
_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(_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
|
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
|
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
|
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(_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(_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
|
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(_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(_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(_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
|
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
|
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
|
StorageDead(_6); // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
- // 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) -> bb1; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
drop((_2.0: Tag)) -> bb3; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
drop((_2.2: Tag)) -> bb2; // scope 0 at $DIR/sroa.rs:+1:32: +1:33
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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:78:34: 78: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:78:5: 78: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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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:57:52: 57: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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
88
src/test/mir-opt/sroa.rs
Normal file
88
src/test/mir-opt/sroa.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// unit-test: ScalarReplacementOfAggregates
|
||||||
|
// compile-flags: -Cpanic=abort
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue