about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2025-01-09 22:53:14 -0800
committerScott McMurray <scottmcm@users.noreply.github.com>2025-01-11 15:56:53 -0800
commit6e34369ef6ec53f571565298b0d0de489f343acc (patch)
tree57abe5c44d75de3a854b0cc71471fafe843a3de1 /compiler/rustc_mir_transform
parenteb54a50837ad4bcc9842924f27e7287ca66e294c (diff)
downloadrust-6e34369ef6ec53f571565298b0d0de489f343acc.tar.gz
rust-6e34369ef6ec53f571565298b0d0de489f343acc.zip
[mir-opt] simplify `Repeat`s that don't actually repeat the operand
Diffstat (limited to 'compiler/rustc_mir_transform')
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs13
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs28
2 files changed, 30 insertions, 11 deletions
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index f74a577c598..20e2e3e8ba2 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -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>,
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 64e183bcbc0..e37ead3674b 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -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> {