about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-07-29 23:50:35 +1000
committerGitHub <noreply@github.com>2025-07-29 23:50:35 +1000
commit826c462c32642c8cc17d708a1bb9a7022fd5bdd5 (patch)
tree11a4ba4c50e698b28abd6fb0e1a7df77d121d925 /compiler/rustc_mir_transform/src
parentf8370285cf81e8af24c7f95b77cbb83c3d6db1cf (diff)
parent8ef9233339c09d80e12b31c523082b94d9e09b44 (diff)
downloadrust-826c462c32642c8cc17d708a1bb9a7022fd5bdd5.tar.gz
rust-826c462c32642c8cc17d708a1bb9a7022fd5bdd5.zip
Rollup merge of #144566 - scottmcm:align-of-slice, r=oli-obk
Simplify `align_of_val::<[T]>(…)` → `align_of::<T>()`

I spotted this while working on the inliner (rust-lang/rust#144561).  In particular, if [`Layout::for_value`](https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value) inlines, then it can be pretty easy to end up with an `align_of_val::<[T]>` today (demo: <https://rust.godbolt.org/z/Tesnscj4a>) where we can save at least a block, if not more, by using the version that's an rvalue and not a call.
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs31
1 files changed, 31 insertions, 0 deletions
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index dbcaed20953..c83bd25c663 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -55,6 +55,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
 
             let terminator = block.terminator.as_mut().unwrap();
             ctx.simplify_primitive_clone(terminator, &mut block.statements);
+            ctx.simplify_align_of_slice_val(terminator, &mut block.statements);
             ctx.simplify_intrinsic_assert(terminator);
             ctx.simplify_nounwind_call(terminator);
             simplify_duplicate_switch_targets(terminator);
@@ -252,6 +253,36 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
         terminator.kind = TerminatorKind::Goto { target: *destination_block };
     }
 
+    // Convert `align_of_val::<[T]>(ptr)` to `align_of::<T>()`, since the
+    // alignment of a slice doesn't actually depend on metadata at all
+    // and the element type is always `Sized`.
+    //
+    // This is here so it can run after inlining, where it's more useful.
+    // (LowerIntrinsics is done in cleanup, before the optimization passes.)
+    fn simplify_align_of_slice_val(
+        &self,
+        terminator: &mut Terminator<'tcx>,
+        statements: &mut Vec<Statement<'tcx>>,
+    ) {
+        if let TerminatorKind::Call {
+            func, args, destination, target: Some(destination_block), ..
+        } = &terminator.kind
+            && args.len() == 1
+            && let Some((fn_def_id, generics)) = func.const_fn_def()
+            && self.tcx.is_intrinsic(fn_def_id, sym::align_of_val)
+            && let ty::Slice(elem_ty) = *generics.type_at(0).kind()
+        {
+            statements.push(Statement::new(
+                terminator.source_info,
+                StatementKind::Assign(Box::new((
+                    *destination,
+                    Rvalue::NullaryOp(NullOp::AlignOf, elem_ty),
+                ))),
+            ));
+            terminator.kind = TerminatorKind::Goto { target: *destination_block };
+        }
+    }
+
     fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) {
         let TerminatorKind::Call { ref func, ref mut unwind, .. } = terminator.kind else {
             return;