Skip to content

Commit 85c1367

Browse files
committed
Auto merge of #152689 - scottmcm:also-simplify-of-sized-val-alt, r=<try>
Simplify `size/align_of_val<T: Sized>` to `size/align_of<T>` instead
2 parents 1396514 + 649e027 commit 85c1367

9 files changed

+476
-15
lines changed

compiler/rustc_mir_transform/src/instsimplify.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
5656

5757
let terminator = block.terminator.as_mut().unwrap();
5858
ctx.simplify_primitive_clone(terminator, &mut block.statements);
59-
ctx.simplify_align_of_slice_val(terminator, &mut block.statements);
59+
ctx.simplify_size_or_align_of_val(terminator, &mut block.statements);
6060
ctx.simplify_intrinsic_assert(terminator);
6161
ctx.simplify_nounwind_call(terminator);
6262
simplify_duplicate_switch_targets(terminator);
@@ -246,13 +246,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
246246
terminator.kind = TerminatorKind::Goto { target: *destination_block };
247247
}
248248

249-
// Convert `align_of_val::<[T]>(ptr)` to `align_of::<T>()`, since the
250-
// alignment of a slice doesn't actually depend on metadata at all
251-
// and the element type is always `Sized`.
252-
//
253-
// This is here so it can run after inlining, where it's more useful.
254-
// (LowerIntrinsics is done in cleanup, before the optimization passes.)
255-
fn simplify_align_of_slice_val(
249+
/// Simplify `size_of_val` and `align_of_val` if we don't actually need
250+
/// to look at the value in order to calculate the result:
251+
/// - For `Sized` types we can always do this for both,
252+
/// - For `align_of_val::<[T]>` we can return `align_of::<T>()`, since it
253+
/// doesn't depend on the slice's length and the elements are sized.
254+
///
255+
/// This is here so it can run after inlining, where it's more useful.
256+
/// (LowerIntrinsics is done in cleanup, before the optimization passes.)
257+
///
258+
/// Note that we intentionally just produce the lang item constants so this
259+
/// works on generic types and avoids any risk of layout calculation cycles.
260+
fn simplify_size_or_align_of_val(
256261
&self,
257262
terminator: &mut Terminator<'tcx>,
258263
statements: &mut Vec<Statement<'tcx>>,
@@ -263,19 +268,35 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
263268
} = &terminator.kind
264269
&& args.len() == 1
265270
&& let Some((fn_def_id, generics)) = func.const_fn_def()
266-
&& self.tcx.is_intrinsic(fn_def_id, sym::align_of_val)
267-
&& let ty::Slice(elem_ty) = *generics.type_at(0).kind()
268271
{
269-
let align_def_id = self.tcx.require_lang_item(LangItem::AlignOf, source_info.span);
270-
let align_const = Operand::unevaluated_constant(
272+
let lang_item = if self.tcx.is_intrinsic(fn_def_id, sym::size_of_val) {
273+
LangItem::SizeOf
274+
} else if self.tcx.is_intrinsic(fn_def_id, sym::align_of_val) {
275+
LangItem::AlignOf
276+
} else {
277+
return;
278+
};
279+
let generic_ty = generics.type_at(0);
280+
let ty = if generic_ty.is_sized(self.tcx, self.typing_env) {
281+
generic_ty
282+
} else if let LangItem::AlignOf = lang_item
283+
&& let ty::Slice(elem_ty) = *generic_ty.kind()
284+
{
285+
elem_ty
286+
} else {
287+
return;
288+
};
289+
290+
let const_def_id = self.tcx.require_lang_item(lang_item, source_info.span);
291+
let const_op = Operand::unevaluated_constant(
271292
self.tcx,
272-
align_def_id,
273-
&[elem_ty.into()],
293+
const_def_id,
294+
&[ty.into()],
274295
source_info.span,
275296
);
276297
statements.push(Statement::new(
277298
source_info,
278-
StatementKind::Assign(Box::new((*destination, Rvalue::Use(align_const)))),
299+
StatementKind::Assign(Box::new((*destination, Rvalue::Use(const_op)))),
279300
));
280301
terminator.kind = TerminatorKind::Goto { target: *destination_block };
281302
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
- // MIR for `align_of_val_sized` before InstSimplify-after-simplifycfg
2+
+ // MIR for `align_of_val_sized` after InstSimplify-after-simplifycfg
3+
4+
fn align_of_val_sized(_1: &T) -> usize {
5+
debug val => _1;
6+
let mut _0: usize;
7+
let mut _2: *const T;
8+
9+
bb0: {
10+
StorageLive(_2);
11+
_2 = &raw const (*_1);
12+
- _0 = std::intrinsics::align_of_val::<T>(move _2) -> [return: bb1, unwind unreachable];
13+
+ _0 = const <T as std::mem::SizedTypeProperties>::ALIGN;
14+
+ goto -> bb1;
15+
}
16+
17+
bb1: {
18+
StorageDead(_2);
19+
return;
20+
}
21+
}
22+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ test-mir-pass: InstSimplify-after-simplifycfg
2+
//@ needs-unwind
3+
4+
#![crate_type = "lib"]
5+
#![feature(core_intrinsics)]
6+
7+
// EMIT_MIR align_or_size_of_sized_val.align_of_val_sized.InstSimplify-after-simplifycfg.diff
8+
pub fn align_of_val_sized<T>(val: &T) -> usize {
9+
// CHECK-LABEL: fn align_of_val_sized
10+
// CHECK: _0 = const <T as std::mem::SizedTypeProperties>::ALIGN;
11+
unsafe { core::intrinsics::align_of_val(val) }
12+
}
13+
14+
// EMIT_MIR align_or_size_of_sized_val.size_of_val_sized.InstSimplify-after-simplifycfg.diff
15+
pub fn size_of_val_sized<T>(val: &T) -> usize {
16+
// CHECK-LABEL: fn size_of_val_sized
17+
// CHECK: _0 = const <T as std::mem::SizedTypeProperties>::SIZE;
18+
unsafe { core::intrinsics::size_of_val(val) }
19+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
- // MIR for `size_of_val_sized` before InstSimplify-after-simplifycfg
2+
+ // MIR for `size_of_val_sized` after InstSimplify-after-simplifycfg
3+
4+
fn size_of_val_sized(_1: &T) -> usize {
5+
debug val => _1;
6+
let mut _0: usize;
7+
let mut _2: *const T;
8+
9+
bb0: {
10+
StorageLive(_2);
11+
_2 = &raw const (*_1);
12+
- _0 = std::intrinsics::size_of_val::<T>(move _2) -> [return: bb1, unwind unreachable];
13+
+ _0 = const <T as std::mem::SizedTypeProperties>::SIZE;
14+
+ goto -> bb1;
15+
}
16+
17+
bb1: {
18+
StorageDead(_2);
19+
return;
20+
}
21+
}
22+
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// MIR for `drop_bytes` after PreCodegen
2+
3+
fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
4+
debug x => _1;
5+
let mut _0: ();
6+
scope 1 (inlined drop_in_place::<Box<[u8; 1024]>> - shim(Some(Box<[u8; 1024]>))) {
7+
scope 2 (inlined <Box<[u8; 1024]> as Drop>::drop) {
8+
let _2: std::ptr::NonNull<[u8; 1024]>;
9+
let _4: ();
10+
scope 3 {
11+
scope 4 {
12+
scope 17 (inlined Layout::size) {
13+
}
14+
scope 18 (inlined std::ptr::Unique::<[u8; 1024]>::cast::<u8>) {
15+
scope 19 (inlined NonNull::<[u8; 1024]>::cast::<u8>) {
16+
scope 20 (inlined NonNull::<[u8; 1024]>::as_ptr) {
17+
}
18+
}
19+
}
20+
scope 21 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
21+
scope 22 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
22+
}
23+
}
24+
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
25+
scope 24 (inlined std::alloc::Global::deallocate_impl) {
26+
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
27+
let mut _3: *mut u8;
28+
scope 26 (inlined Layout::size) {
29+
}
30+
scope 27 (inlined NonNull::<u8>::as_ptr) {
31+
}
32+
scope 28 (inlined std::alloc::dealloc) {
33+
scope 29 (inlined Layout::size) {
34+
}
35+
scope 30 (inlined Layout::alignment) {
36+
}
37+
}
38+
}
39+
}
40+
}
41+
}
42+
scope 5 (inlined std::ptr::Unique::<[u8; 1024]>::as_ptr) {
43+
scope 6 (inlined NonNull::<[u8; 1024]>::as_ptr) {
44+
}
45+
}
46+
scope 7 (inlined Layout::for_value_raw::<[u8; 1024]>) {
47+
scope 8 {
48+
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
49+
}
50+
}
51+
scope 9 (inlined size_of_val_raw::<[u8; 1024]>) {
52+
}
53+
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[u8; 1024]>) {
54+
scope 11 {
55+
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
56+
scope 14 (inlined core::ub_checks::check_language_ub) {
57+
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
58+
}
59+
}
60+
}
61+
}
62+
scope 12 (inlined align_of_val_raw::<[u8; 1024]>) {
63+
}
64+
}
65+
}
66+
}
67+
}
68+
}
69+
70+
bb0: {
71+
_2 = copy (((*_1).0: std::ptr::Unique<[u8; 1024]>).0: std::ptr::NonNull<[u8; 1024]>);
72+
StorageLive(_3);
73+
_3 = copy _2 as *mut u8 (Transmute);
74+
_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];
75+
}
76+
77+
bb1: {
78+
StorageDead(_3);
79+
return;
80+
}
81+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// MIR for `drop_bytes` after PreCodegen
2+
3+
fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
4+
debug x => _1;
5+
let mut _0: ();
6+
scope 1 (inlined drop_in_place::<Box<[u8; 1024]>> - shim(Some(Box<[u8; 1024]>))) {
7+
scope 2 (inlined <Box<[u8; 1024]> as Drop>::drop) {
8+
let _2: std::ptr::NonNull<[u8; 1024]>;
9+
let _4: ();
10+
scope 3 {
11+
scope 4 {
12+
scope 17 (inlined Layout::size) {
13+
}
14+
scope 18 (inlined std::ptr::Unique::<[u8; 1024]>::cast::<u8>) {
15+
scope 19 (inlined NonNull::<[u8; 1024]>::cast::<u8>) {
16+
scope 20 (inlined NonNull::<[u8; 1024]>::as_ptr) {
17+
}
18+
}
19+
}
20+
scope 21 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
21+
scope 22 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
22+
}
23+
}
24+
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
25+
scope 24 (inlined std::alloc::Global::deallocate_impl) {
26+
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
27+
let mut _3: *mut u8;
28+
scope 26 (inlined Layout::size) {
29+
}
30+
scope 27 (inlined NonNull::<u8>::as_ptr) {
31+
}
32+
scope 28 (inlined std::alloc::dealloc) {
33+
scope 29 (inlined Layout::size) {
34+
}
35+
scope 30 (inlined Layout::alignment) {
36+
}
37+
}
38+
}
39+
}
40+
}
41+
}
42+
scope 5 (inlined std::ptr::Unique::<[u8; 1024]>::as_ptr) {
43+
scope 6 (inlined NonNull::<[u8; 1024]>::as_ptr) {
44+
}
45+
}
46+
scope 7 (inlined Layout::for_value_raw::<[u8; 1024]>) {
47+
scope 8 {
48+
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
49+
}
50+
}
51+
scope 9 (inlined size_of_val_raw::<[u8; 1024]>) {
52+
}
53+
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[u8; 1024]>) {
54+
scope 11 {
55+
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
56+
scope 14 (inlined core::ub_checks::check_language_ub) {
57+
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
58+
}
59+
}
60+
}
61+
}
62+
scope 12 (inlined align_of_val_raw::<[u8; 1024]>) {
63+
}
64+
}
65+
}
66+
}
67+
}
68+
}
69+
70+
bb0: {
71+
_2 = copy (((*_1).0: std::ptr::Unique<[u8; 1024]>).0: std::ptr::NonNull<[u8; 1024]>);
72+
StorageLive(_3);
73+
_3 = copy _2 as *mut u8 (Transmute);
74+
_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];
75+
}
76+
77+
bb1: {
78+
StorageDead(_3);
79+
return;
80+
}
81+
}

0 commit comments

Comments
 (0)