diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 84d642ea4ebc0..b92938c7094eb 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -56,7 +56,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_size_or_align_of_val(terminator, &mut block.statements); ctx.simplify_intrinsic_assert(terminator); ctx.simplify_nounwind_call(terminator); simplify_duplicate_switch_targets(terminator); @@ -246,13 +246,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { terminator.kind = TerminatorKind::Goto { target: *destination_block }; } - // Convert `align_of_val::<[T]>(ptr)` to `align_of::()`, 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( + /// Simplify `size_of_val` and `align_of_val` if we don't actually need + /// to look at the value in order to calculate the result: + /// - For `Sized` types we can always do this for both, + /// - For `align_of_val::<[T]>` we can return `align_of::()`, since it + /// doesn't depend on the slice's length and the elements are sized. + /// + /// This is here so it can run after inlining, where it's more useful. + /// (LowerIntrinsics is done in cleanup, before the optimization passes.) + /// + /// Note that we intentionally just produce the lang item constants so this + /// works on generic types and avoids any risk of layout calculation cycles. + fn simplify_size_or_align_of_val( &self, terminator: &mut Terminator<'tcx>, statements: &mut Vec>, @@ -263,19 +268,35 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } = &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() { - let align_def_id = self.tcx.require_lang_item(LangItem::AlignOf, source_info.span); - let align_const = Operand::unevaluated_constant( + let lang_item = if self.tcx.is_intrinsic(fn_def_id, sym::size_of_val) { + LangItem::SizeOf + } else if self.tcx.is_intrinsic(fn_def_id, sym::align_of_val) { + LangItem::AlignOf + } else { + return; + }; + let generic_ty = generics.type_at(0); + let ty = if generic_ty.is_sized(self.tcx, self.typing_env) { + generic_ty + } else if let LangItem::AlignOf = lang_item + && let ty::Slice(elem_ty) = *generic_ty.kind() + { + elem_ty + } else { + return; + }; + + let const_def_id = self.tcx.require_lang_item(lang_item, source_info.span); + let const_op = Operand::unevaluated_constant( self.tcx, - align_def_id, - &[elem_ty.into()], + const_def_id, + &[ty.into()], source_info.span, ); statements.push(Statement::new( source_info, - StatementKind::Assign(Box::new((*destination, Rvalue::Use(align_const)))), + StatementKind::Assign(Box::new((*destination, Rvalue::Use(const_op)))), )); terminator.kind = TerminatorKind::Goto { target: *destination_block }; } diff --git a/tests/mir-opt/instsimplify/align_or_size_of_sized_val.align_of_val_sized.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/align_or_size_of_sized_val.align_of_val_sized.InstSimplify-after-simplifycfg.diff new file mode 100644 index 0000000000000..1fc160e9b07b2 --- /dev/null +++ b/tests/mir-opt/instsimplify/align_or_size_of_sized_val.align_of_val_sized.InstSimplify-after-simplifycfg.diff @@ -0,0 +1,22 @@ +- // MIR for `align_of_val_sized` before InstSimplify-after-simplifycfg ++ // MIR for `align_of_val_sized` after InstSimplify-after-simplifycfg + + fn align_of_val_sized(_1: &T) -> usize { + debug val => _1; + let mut _0: usize; + let mut _2: *const T; + + bb0: { + StorageLive(_2); + _2 = &raw const (*_1); +- _0 = std::intrinsics::align_of_val::(move _2) -> [return: bb1, unwind unreachable]; ++ _0 = const ::ALIGN; ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/instsimplify/align_or_size_of_sized_val.rs b/tests/mir-opt/instsimplify/align_or_size_of_sized_val.rs new file mode 100644 index 0000000000000..d186e1bc90141 --- /dev/null +++ b/tests/mir-opt/instsimplify/align_or_size_of_sized_val.rs @@ -0,0 +1,19 @@ +//@ test-mir-pass: InstSimplify-after-simplifycfg +//@ needs-unwind + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// EMIT_MIR align_or_size_of_sized_val.align_of_val_sized.InstSimplify-after-simplifycfg.diff +pub fn align_of_val_sized(val: &T) -> usize { + // CHECK-LABEL: fn align_of_val_sized + // CHECK: _0 = const ::ALIGN; + unsafe { core::intrinsics::align_of_val(val) } +} + +// EMIT_MIR align_or_size_of_sized_val.size_of_val_sized.InstSimplify-after-simplifycfg.diff +pub fn size_of_val_sized(val: &T) -> usize { + // CHECK-LABEL: fn size_of_val_sized + // CHECK: _0 = const ::SIZE; + unsafe { core::intrinsics::size_of_val(val) } +} diff --git a/tests/mir-opt/instsimplify/align_or_size_of_sized_val.size_of_val_sized.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/align_or_size_of_sized_val.size_of_val_sized.InstSimplify-after-simplifycfg.diff new file mode 100644 index 0000000000000..e96c4d25b8358 --- /dev/null +++ b/tests/mir-opt/instsimplify/align_or_size_of_sized_val.size_of_val_sized.InstSimplify-after-simplifycfg.diff @@ -0,0 +1,22 @@ +- // MIR for `size_of_val_sized` before InstSimplify-after-simplifycfg ++ // MIR for `size_of_val_sized` after InstSimplify-after-simplifycfg + + fn size_of_val_sized(_1: &T) -> usize { + debug val => _1; + let mut _0: usize; + let mut _2: *const T; + + bb0: { + StorageLive(_2); + _2 = &raw const (*_1); +- _0 = std::intrinsics::size_of_val::(move _2) -> [return: bb1, unwind unreachable]; ++ _0 = const ::SIZE; ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-abort.mir new file mode 100644 index 0000000000000..4b5ed1d223822 --- /dev/null +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-abort.mir @@ -0,0 +1,81 @@ +// MIR for `drop_bytes` after PreCodegen + +fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () { + debug x => _1; + let mut _0: (); + scope 1 (inlined drop_in_place::> - shim(Some(Box<[u8; 1024]>))) { + scope 2 (inlined as Drop>::drop) { + let _2: std::ptr::NonNull<[u8; 1024]>; + let _4: (); + scope 3 { + scope 4 { + scope 17 (inlined Layout::size) { + } + scope 18 (inlined std::ptr::Unique::<[u8; 1024]>::cast::) { + scope 19 (inlined NonNull::<[u8; 1024]>::cast::) { + scope 20 (inlined NonNull::<[u8; 1024]>::as_ptr) { + } + } + } + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { + } + } + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _3: *mut u8; + scope 26 (inlined Layout::size) { + } + scope 27 (inlined NonNull::::as_ptr) { + } + scope 28 (inlined std::alloc::dealloc) { + scope 29 (inlined Layout::size) { + } + scope 30 (inlined Layout::alignment) { + } + } + } + } + } + } + scope 5 (inlined std::ptr::Unique::<[u8; 1024]>::as_ptr) { + scope 6 (inlined NonNull::<[u8; 1024]>::as_ptr) { + } + } + scope 7 (inlined Layout::for_value_raw::<[u8; 1024]>) { + scope 8 { + scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { + } + } + scope 9 (inlined size_of_val_raw::<[u8; 1024]>) { + } + scope 10 (inlined std::ptr::Alignment::of_val_raw::<[u8; 1024]>) { + scope 11 { + scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + scope 12 (inlined align_of_val_raw::<[u8; 1024]>) { + } + } + } + } + } + } + + bb0: { + _2 = copy (((*_1).0: std::ptr::Unique<[u8; 1024]>).0: std::ptr::NonNull<[u8; 1024]>); + StorageLive(_3); + _3 = copy _2 as *mut u8 (Transmute); + _4 = alloc::alloc::__rust_dealloc(move _3, const 1024_usize, const std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }}) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-unwind.mir new file mode 100644 index 0000000000000..4b5ed1d223822 --- /dev/null +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,81 @@ +// MIR for `drop_bytes` after PreCodegen + +fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () { + debug x => _1; + let mut _0: (); + scope 1 (inlined drop_in_place::> - shim(Some(Box<[u8; 1024]>))) { + scope 2 (inlined as Drop>::drop) { + let _2: std::ptr::NonNull<[u8; 1024]>; + let _4: (); + scope 3 { + scope 4 { + scope 17 (inlined Layout::size) { + } + scope 18 (inlined std::ptr::Unique::<[u8; 1024]>::cast::) { + scope 19 (inlined NonNull::<[u8; 1024]>::cast::) { + scope 20 (inlined NonNull::<[u8; 1024]>::as_ptr) { + } + } + } + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { + } + } + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _3: *mut u8; + scope 26 (inlined Layout::size) { + } + scope 27 (inlined NonNull::::as_ptr) { + } + scope 28 (inlined std::alloc::dealloc) { + scope 29 (inlined Layout::size) { + } + scope 30 (inlined Layout::alignment) { + } + } + } + } + } + } + scope 5 (inlined std::ptr::Unique::<[u8; 1024]>::as_ptr) { + scope 6 (inlined NonNull::<[u8; 1024]>::as_ptr) { + } + } + scope 7 (inlined Layout::for_value_raw::<[u8; 1024]>) { + scope 8 { + scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { + } + } + scope 9 (inlined size_of_val_raw::<[u8; 1024]>) { + } + scope 10 (inlined std::ptr::Alignment::of_val_raw::<[u8; 1024]>) { + scope 11 { + scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + scope 12 (inlined align_of_val_raw::<[u8; 1024]>) { + } + } + } + } + } + } + + bb0: { + _2 = copy (((*_1).0: std::ptr::Unique<[u8; 1024]>).0: std::ptr::NonNull<[u8; 1024]>); + StorageLive(_3); + _3 = copy _2 as *mut u8 (Transmute); + _4 = alloc::alloc::__rust_dealloc(move _3, const 1024_usize, const std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }}) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-abort.mir new file mode 100644 index 0000000000000..c446ab395f3ec --- /dev/null +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-abort.mir @@ -0,0 +1,97 @@ +// MIR for `drop_generic` after PreCodegen + +fn drop_generic(_1: *mut Box) -> () { + debug x => _1; + let mut _0: (); + scope 1 (inlined drop_in_place::> - shim(Some(Box))) { + scope 2 (inlined as Drop>::drop) { + let _2: std::ptr::NonNull; + let _7: (); + scope 3 { + scope 4 { + scope 17 (inlined Layout::size) { + } + scope 18 (inlined std::ptr::Unique::::cast::) { + scope 19 (inlined NonNull::::cast::) { + scope 20 (inlined NonNull::::as_ptr) { + } + } + } + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { + } + } + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _6: *mut u8; + scope 26 (inlined Layout::size) { + } + scope 27 (inlined NonNull::::as_ptr) { + } + scope 28 (inlined std::alloc::dealloc) { + scope 29 (inlined Layout::size) { + } + scope 30 (inlined Layout::alignment) { + } + } + } + } + } + } + scope 5 (inlined std::ptr::Unique::::as_ptr) { + scope 6 (inlined NonNull::::as_ptr) { + } + } + scope 7 (inlined Layout::for_value_raw::) { + let mut _3: usize; + let mut _5: std::ptr::Alignment; + scope 8 { + scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { + } + } + scope 9 (inlined size_of_val_raw::) { + } + scope 10 (inlined std::ptr::Alignment::of_val_raw::) { + let _4: usize; + scope 11 { + scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + scope 12 (inlined align_of_val_raw::) { + } + } + } + } + } + } + + bb0: { + _2 = copy (((*_1).0: std::ptr::Unique).0: std::ptr::NonNull); + _3 = const ::SIZE; + StorageLive(_4); + _4 = const ::ALIGN; + _5 = copy _4 as std::ptr::Alignment (Transmute); + StorageDead(_4); + switchInt(copy _3) -> [0: bb3, otherwise: bb1]; + } + + bb1: { + StorageLive(_6); + _6 = copy _2 as *mut u8 (Transmute); + _7 = alloc::alloc::__rust_dealloc(move _6, move _3, move _5) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_6); + goto -> bb3; + } + + bb3: { + return; + } +} diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-unwind.mir new file mode 100644 index 0000000000000..c446ab395f3ec --- /dev/null +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,97 @@ +// MIR for `drop_generic` after PreCodegen + +fn drop_generic(_1: *mut Box) -> () { + debug x => _1; + let mut _0: (); + scope 1 (inlined drop_in_place::> - shim(Some(Box))) { + scope 2 (inlined as Drop>::drop) { + let _2: std::ptr::NonNull; + let _7: (); + scope 3 { + scope 4 { + scope 17 (inlined Layout::size) { + } + scope 18 (inlined std::ptr::Unique::::cast::) { + scope 19 (inlined NonNull::::cast::) { + scope 20 (inlined NonNull::::as_ptr) { + } + } + } + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { + } + } + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _6: *mut u8; + scope 26 (inlined Layout::size) { + } + scope 27 (inlined NonNull::::as_ptr) { + } + scope 28 (inlined std::alloc::dealloc) { + scope 29 (inlined Layout::size) { + } + scope 30 (inlined Layout::alignment) { + } + } + } + } + } + } + scope 5 (inlined std::ptr::Unique::::as_ptr) { + scope 6 (inlined NonNull::::as_ptr) { + } + } + scope 7 (inlined Layout::for_value_raw::) { + let mut _3: usize; + let mut _5: std::ptr::Alignment; + scope 8 { + scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { + } + } + scope 9 (inlined size_of_val_raw::) { + } + scope 10 (inlined std::ptr::Alignment::of_val_raw::) { + let _4: usize; + scope 11 { + scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + scope 12 (inlined align_of_val_raw::) { + } + } + } + } + } + } + + bb0: { + _2 = copy (((*_1).0: std::ptr::Unique).0: std::ptr::NonNull); + _3 = const ::SIZE; + StorageLive(_4); + _4 = const ::ALIGN; + _5 = copy _4 as std::ptr::Alignment (Transmute); + StorageDead(_4); + switchInt(copy _3) -> [0: bb3, otherwise: bb1]; + } + + bb1: { + StorageLive(_6); + _6 = copy _2 as *mut u8 (Transmute); + _7 = alloc::alloc::__rust_dealloc(move _6, move _3, move _5) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_6); + goto -> bb3; + } + + bb3: { + return; + } +} diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.rs b/tests/mir-opt/pre-codegen/drop_box_of_sized.rs new file mode 100644 index 0000000000000..1e2953aa46b75 --- /dev/null +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -O -Zmir-opt-level=2 +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![crate_type = "lib"] + +// EMIT_MIR drop_box_of_sized.drop_generic.PreCodegen.after.mir +pub unsafe fn drop_generic(x: *mut Box) { + // CHECK-LABEL: fn drop_generic + // CHECK: [[SIZE:_.+]] = const ::SIZE; + // CHECK: [[ALIGN:_.+]] = const ::ALIGN; + // CHECK: [[ALIGNMENT:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute) + // CHECK: alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[ALIGNMENT]]) + std::ptr::drop_in_place(x) +} + +// EMIT_MIR drop_box_of_sized.drop_bytes.PreCodegen.after.mir +pub unsafe fn drop_bytes(x: *mut Box<[u8; 1024]>) { + // CHECK-LABEL: fn drop_bytes + // CHECK: alloc::alloc::__rust_dealloc({{.+}}, const 1024_usize, {{.+}}Align1Shl0 {{.+}}) + std::ptr::drop_in_place(x) +}