1
Fork 0

[mir-opt] simplify Repeats that don't actually repeat the operand

This commit is contained in:
Scott McMurray 2025-01-09 22:53:14 -08:00
parent eb54a50837
commit 6e34369ef6
7 changed files with 102 additions and 23 deletions

View file

@ -49,6 +49,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
ctx.simplify_ptr_aggregate(rvalue);
ctx.simplify_cast(rvalue);
ctx.simplify_repeated_aggregate(rvalue);
ctx.simplify_repeat_once(rvalue);
}
_ => {}
}
@ -207,6 +208,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
}
}
/// Simplify `[x; 1]` to just `[x]`.
fn simplify_repeat_once(&self, rvalue: &mut Rvalue<'tcx>) {
if let Rvalue::Repeat(operand, count) = rvalue
&& let Some(1) = count.try_to_target_usize(self.tcx)
{
*rvalue = Rvalue::Aggregate(
Box::new(AggregateKind::Array(operand.ty(self.local_decls, self.tcx))),
[operand.clone()].into(),
);
}
}
fn simplify_primitive_clone(
&self,
terminator: &mut Terminator<'tcx>,

View file

@ -36,31 +36,37 @@ struct Replacer<'a, 'tcx> {
}
/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
fn maybe_zst(ty: Ty<'_>) -> bool {
///
/// `Some(true)` is definitely ZST; `Some(false)` is definitely *not* ZST.
///
/// `None` may or may not be, and must check `layout_of` to be sure.
fn trivially_zst<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<bool> {
match ty.kind() {
// definitely ZST
ty::FnDef(..) | ty::Never => Some(true),
ty::Tuple(fields) if fields.is_empty() => Some(true),
ty::Array(_ty, len) if let Some(0) = len.try_to_target_usize(tcx) => Some(true),
// maybe ZST (could be more precise)
ty::Adt(..)
| ty::Array(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Tuple(..)
| ty::Alias(ty::Opaque, ..) => true,
// definitely ZST
ty::FnDef(..) | ty::Never => true,
| ty::Alias(ty::Opaque, ..) => None,
// unreachable or can't be ZST
_ => false,
_ => Some(false),
}
}
impl<'tcx> Replacer<'_, 'tcx> {
fn known_to_be_zst(&self, ty: Ty<'tcx>) -> bool {
if !maybe_zst(ty) {
return false;
if let Some(is_zst) = trivially_zst(ty, self.tcx) {
is_zst
} else {
self.tcx
.layout_of(self.typing_env.as_query_input(ty))
.is_ok_and(|layout| layout.is_zst())
}
let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(ty)) else {
return false;
};
layout.is_zst()
}
fn make_zst(&self, ty: Ty<'tcx>) -> ConstOperand<'tcx> {