Skip to content

Commit

Permalink
Auto merge of #111061 - cjgillot:reorder-passes, r=<try>
Browse files Browse the repository at this point in the history
[perf] Enable some more MIR optimizations

r? `@ghost`
  • Loading branch information
bors committed Jan 20, 2024
2 parents 88189a7 + 0c2525b commit 9ef5d52
Show file tree
Hide file tree
Showing 242 changed files with 11,161 additions and 5,483 deletions.
139 changes: 85 additions & 54 deletions compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
use super::{FunctionCx, LocalRef};

use std::ops::Range;

pub struct FunctionDebugContext<'tcx, S, L> {
/// Maps from source code to the corresponding debug info scope.
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
Expand All @@ -36,17 +34,17 @@ pub enum VariableKind {
#[derive(Clone)]
pub struct PerLocalVarDebugInfo<'tcx, D> {
pub name: Symbol,
pub ty: Ty<'tcx>,
pub source_info: mir::SourceInfo,

/// `DIVariable` returned by `create_dbg_var`.
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`.
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
pub projection: &'tcx [mir::PlaceElem<'tcx>],

/// Projection from fragment debuginfo.
pub fragment: &'tcx [mir::PlaceElem<'tcx>],
}

#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -149,6 +147,8 @@ struct DebugInfoOffset<T> {
indirect_offsets: Vec<Size>,
/// The final location debuginfo should point to.
result: T,
/// Whether the final location is a fragment of a larger contiguous projection.
fragment: bool,
}

fn calculate_debuginfo_offset<
Expand All @@ -165,17 +165,21 @@ fn calculate_debuginfo_offset<
// FIXME(eddyb) use smallvec here.
let mut indirect_offsets = vec![];
let mut place = base;
let mut fragment = false;

for elem in projection {
let layout = place.layout();
match *elem {
mir::ProjectionElem::Deref => {
indirect_offsets.push(Size::ZERO);
place = place.deref(bx);
fragment = false;
}
mir::ProjectionElem::Field(field, _) => {
let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
*offset += place.layout().fields.offset(field.index());
place = place.project_field(bx, field);
fragment |= place.layout().size != layout.size;
}
mir::ProjectionElem::Downcast(_, variant) => {
place = place.downcast(bx, variant);
Expand All @@ -191,16 +195,17 @@ fn calculate_debuginfo_offset<
};
*offset += stride * index;
place = place.project_constant_index(bx, index);
fragment |= place.layout().size != layout.size;
}
_ => {
// Sanity check for `can_use_in_debuginfo`.
debug_assert!(!elem.can_use_in_debuginfo());
bug!("unsupported var debuginfo projection `{:?}`", projection)
bug!("unsupported var debuginfo place `{:?}`", projection)
}
}
}

DebugInfoOffset { direct_offset, indirect_offsets, result: place }
DebugInfoOffset { direct_offset, indirect_offsets, result: place, fragment }
}

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Expand Down Expand Up @@ -290,14 +295,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
let name = kw::Empty;
let decl = &self.mir.local_decls[local];
let arg_ty = self.monomorphize(decl.ty);

let dbg_var = if full_debug_info {
self.adjusted_span_and_dbg_scope(decl.source_info).map(
|(dbg_scope, _, span)| {
// FIXME(eddyb) is this `+ 1` needed at all?
let kind = VariableKind::ArgumentVariable(arg_index + 1);

let arg_ty = self.monomorphize(decl.ty);

self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span)
},
)
Expand All @@ -307,10 +312,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

Some(PerLocalVarDebugInfo {
name,
ty: arg_ty,
source_info: decl.source_info,
dbg_var,
fragment: None,
projection: ty::List::empty(),
fragment: &[],
projection: &[],
})
}
} else {
Expand Down Expand Up @@ -392,8 +398,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let Some(dbg_var) = var.dbg_var else { return };
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };

let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
let DebugInfoOffset { mut direct_offset, indirect_offsets, result: _, fragment: _ } =
calculate_debuginfo_offset(bx, var.projection, base.layout);
let mut indirect_offsets = &indirect_offsets[..];

// When targeting MSVC, create extra allocas for arguments instead of pointing multiple
// dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
Expand All @@ -410,8 +417,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&& (direct_offset != Size::ZERO || !matches!(&indirect_offsets[..], [Size::ZERO] | []));

if should_create_individual_allocas {
let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
calculate_debuginfo_offset(bx, var.projection, base);
let DebugInfoOffset {
direct_offset: _,
indirect_offsets: _,
fragment: _,
result: place,
} = calculate_debuginfo_offset(bx, var.projection, base);

// Create a variable which will be a pointer to the actual value
let ptr_ty = Ty::new_ptr(
Expand All @@ -426,24 +437,53 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.store(place.llval, alloca.llval, alloca.align);

// Point the debug info to `*alloca` for the current variable
bx.dbg_var_addr(
dbg_var,
dbg_loc,
alloca.llval,
Size::ZERO,
&[Size::ZERO],
var.fragment,
);
direct_offset = Size::ZERO;
indirect_offsets = &[Size::ZERO];
}

self.debug_introduce_place(
bx,
dbg_var,
dbg_loc,
base.llval,
direct_offset,
indirect_offsets,
var.ty,
var.fragment,
);
}

fn debug_introduce_place(
&self,
bx: &mut Bx,
dbg_var: Bx::DIVariable,
dbg_loc: Bx::DILocation,
base: Bx::Value,
direct_offset: Size,
indirect_offsets: &[Size],
ty: Ty<'tcx>,
fragment: &[mir::PlaceElem<'tcx>],
) {
let DebugInfoOffset {
direct_offset: fragment_offset,
indirect_offsets: fragment_indirect,
result: fragment_layout,
fragment,
} = calculate_debuginfo_offset(bx, fragment, bx.layout_of(ty));

let fragment = if fragment_layout.size == Size::ZERO {
return;
} else if fragment {
Some(fragment_offset..fragment_offset + fragment_layout.size)
} else {
bx.dbg_var_addr(
dbg_var,
dbg_loc,
base.llval,
direct_offset,
&indirect_offsets,
var.fragment,
);
None
};

if !fragment_indirect.is_empty() {
return;
}

bx.dbg_var_addr(dbg_var, dbg_loc, base, direct_offset, indirect_offsets, fragment);
}

pub fn debug_introduce_locals(&self, bx: &mut Bx) {
Expand Down Expand Up @@ -515,32 +555,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
});

let fragment = if let Some(ref fragment) = var.composite {
let var_layout = self.cx.layout_of(var_ty);

let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } =
calculate_debuginfo_offset(bx, &fragment.projection, var_layout);
debug_assert!(indirect_offsets.is_empty());

if fragment_layout.size == Size::ZERO {
// Fragment is a ZST, so does not represent anything. Avoid generating anything
// as this may conflict with a fragment that covers the entire variable.
continue;
} else 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(direct_offset..direct_offset + fragment_layout.size)
}
} else {
None
};
let fragment =
if let Some(ref fragment) = var.composite { &fragment.projection[..] } else { &[] };

match var.value {
mir::VarDebugInfoContents::Place(place) => {
per_local[place.local].push(PerLocalVarDebugInfo {
name: var.name,
ty: var_ty,
source_info: var.source_info,
dbg_var,
fragment,
Expand All @@ -556,7 +578,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let base =
Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);

bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment);
self.debug_introduce_place(
bx,
dbg_var,
dbg_loc,
base.llval,
Size::ZERO,
&[],
var_ty,
fragment,
);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}

fn unsize_into(
pub fn unsize_into(
&mut self,
src: &OpTy<'tcx, M::Provenance>,
cast_ty: TyAndLayout<'tcx>,
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
format!("invalid empty projection in debuginfo for {:?}", debuginfo.name),
);
}
if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
if !projection.iter().all(|p| {
matches!(
p,
PlaceElem::Field(..) | PlaceElem::Deref | PlaceElem::ConstantIndex { .. }
)
}) {
self.fail(
START_BLOCK.start_location(),
format!(
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,13 @@ macro_rules! make_mir_visitor {
if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite {
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
for elem in projection {
let ProjectionElem::Field(_, ty) = elem else { bug!() };
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
match elem {
ProjectionElem::Deref | ProjectionElem::ConstantIndex { .. } => {}
ProjectionElem::Field(_, ty) => {
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location))
}
_ => bug!("unexpected projection in debuginfo: {elem:?}"),
}
}
}
match value {
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_mir_dataflow/src/value_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ impl Map {
/// This is currently the only way to create a [`Map`]. The way in which the tracked places are
/// chosen is an implementation detail and may not be relied upon (other than that their type
/// are scalars).
pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option<usize>) -> Self {
pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place_limit: Option<usize>) -> Self {
let mut map = Self {
locals: IndexVec::new(),
projections: FxHashMap::default(),
Expand All @@ -730,7 +730,7 @@ impl Map {
inner_values_buffer: Vec::new(),
};
let exclude = excluded_locals(body);
map.register(tcx, body, exclude, value_limit);
map.register(tcx, body, exclude, place_limit);
debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len());
map
}
Expand All @@ -741,9 +741,9 @@ impl Map {
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
exclude: BitSet<Local>,
value_limit: Option<usize>,
place_limit: Option<usize>,
) {
let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len()));
let mut worklist = VecDeque::with_capacity(place_limit.unwrap_or(body.local_decls.len()));
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());

// Start by constructing the places for each bare local.
Expand All @@ -766,8 +766,8 @@ impl Map {
// `elem1` is either `Some(Variant(i))` or `None`.
while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() {
// The user requires a bound on the number of created values.
if let Some(value_limit) = value_limit
&& self.value_count >= value_limit
if let Some(place_limit) = place_limit
&& self.places.len() >= place_limit
{
break;
}
Expand Down
Loading

0 comments on commit 9ef5d52

Please sign in to comment.