Skip to content

[perf] Enable some more MIR optimizations #111061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 37 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
dca02d6
Enable DestinationPropagation by default.
cjgillot Apr 30, 2023
fce6510
Fold consecutive PtrToPtr casts.
cjgillot Oct 11, 2023
7bfb31f
Simplify operands in unions.
cjgillot Oct 31, 2023
44c48d7
Compute unsizing casts in GVN.
cjgillot Dec 17, 2023
cf3ad0e
Compute binary ops between pointers in GVN.
cjgillot Jan 16, 2024
aa05458
Split gvn wide ptr tests.
cjgillot Dec 30, 2023
a6441a6
Perform GVN into debuginfo.
cjgillot Jun 5, 2023
0167761
Const-prop pointers.
cjgillot Jan 6, 2024
47cb509
Dest prop: Support removing writes when this unblocks optimizations
JakobDegen Dec 17, 2022
31e8901
Dest prop: Separate writes to remove into separate data structure in …
JakobDegen Dec 18, 2022
a2cc501
GVN borrowed locals too.
cjgillot Dec 30, 2023
375263d
Merge borrowed locals too.
cjgillot Jan 2, 2024
8e5a9e4
Dereference immutable borrows in GVN.
cjgillot Jan 5, 2024
f5def50
Bless coverage.
cjgillot Jan 16, 2024
8429c25
Enable by default.
cjgillot Jan 18, 2023
d402dc7
Remove ConstGoto and SeparateConstSwitch.
cjgillot Feb 26, 2023
fb38ce6
Reimplement references debuginfo as projection.
cjgillot Aug 26, 2023
ac932b7
Add assume statements in NonZero library types.
cjgillot Oct 15, 2023
e445d0d
Lower inling cost for a statement.
cjgillot Oct 15, 2023
26a6f6f
INSTR_COST=2.
cjgillot Dec 30, 2023
f9c1799
INSTR_COST=1.
cjgillot Dec 30, 2023
25d8366
Limit recursion in terms of places.
cjgillot Jan 14, 2024
7386a8b
Enable DataflowConstProp by default.
cjgillot Oct 22, 2023
0b3a2e8
Merge branch 'dest-prop-move'
cjgillot Jan 19, 2024
532ade3
Merge branch 'gvn-borrowed'
cjgillot Jan 19, 2024
655d7ae
Merge branch 'jump-threading-default'
cjgillot Jan 19, 2024
b0a57b4
Merge branch 'mir-composite-deref'
cjgillot Jan 19, 2024
6d1fdaa
Merge branch 'cheap-stmt'
cjgillot Jan 19, 2024
aacb6b5
Merge branch 'enable-dcp'
cjgillot Jan 19, 2024
19aaef4
Reorder MIR passes.
cjgillot Feb 5, 2023
879be36
InstSimplify calls to constructors.
cjgillot May 16, 2023
83162cd
SROA short arrays too.
cjgillot Jun 24, 2023
4a591aa
Fortify codegen test.
cjgillot Sep 24, 2023
e792ee8
Add more simplify passes.
cjgillot Sep 24, 2023
5f1fd2f
Add test.
cjgillot Oct 3, 2023
d192eb0
Merge places for debuginfo.
cjgillot Jan 19, 2024
0c2525b
Also address in debuginfo.
cjgillot Oct 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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