Skip to content

Commit 649e027

Browse files
committed
mir-simplify {size,align}_of_val::<impl Sized>
1 parent 61d3b2d commit 649e027

9 files changed

+144
-133
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+

tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-abort.mir

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
66
scope 1 (inlined drop_in_place::<Box<[u8; 1024]>> - shim(Some(Box<[u8; 1024]>))) {
77
scope 2 (inlined <Box<[u8; 1024]> as Drop>::drop) {
88
let _2: std::ptr::NonNull<[u8; 1024]>;
9-
let mut _3: *const [u8; 1024];
10-
let _8: ();
9+
let _4: ();
1110
scope 3 {
1211
scope 4 {
1312
scope 17 (inlined Layout::size) {
@@ -25,7 +24,7 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
2524
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
2625
scope 24 (inlined std::alloc::Global::deallocate_impl) {
2726
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
28-
let mut _7: *mut u8;
27+
let mut _3: *mut u8;
2928
scope 26 (inlined Layout::size) {
3029
}
3130
scope 27 (inlined NonNull::<u8>::as_ptr) {
@@ -45,16 +44,13 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
4544
}
4645
}
4746
scope 7 (inlined Layout::for_value_raw::<[u8; 1024]>) {
48-
let mut _4: usize;
49-
let mut _6: std::ptr::Alignment;
5047
scope 8 {
5148
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
5249
}
5350
}
5451
scope 9 (inlined size_of_val_raw::<[u8; 1024]>) {
5552
}
5653
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[u8; 1024]>) {
57-
let _5: usize;
5854
scope 11 {
5955
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
6056
scope 14 (inlined core::ub_checks::check_language_ub) {
@@ -74,34 +70,12 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
7470
bb0: {
7571
_2 = copy (((*_1).0: std::ptr::Unique<[u8; 1024]>).0: std::ptr::NonNull<[u8; 1024]>);
7672
StorageLive(_3);
77-
_3 = copy _2 as *const [u8; 1024] (Transmute);
78-
_4 = std::intrinsics::size_of_val::<[u8; 1024]>(copy _3) -> [return: bb1, unwind unreachable];
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];
7975
}
8076

8177
bb1: {
82-
StorageLive(_5);
83-
_5 = std::intrinsics::align_of_val::<[u8; 1024]>(move _3) -> [return: bb2, unwind unreachable];
84-
}
85-
86-
bb2: {
87-
_6 = copy _5 as std::ptr::Alignment (Transmute);
88-
StorageDead(_5);
8978
StorageDead(_3);
90-
switchInt(copy _4) -> [0: bb5, otherwise: bb3];
91-
}
92-
93-
bb3: {
94-
StorageLive(_7);
95-
_7 = copy _2 as *mut u8 (Transmute);
96-
_8 = alloc::alloc::__rust_dealloc(move _7, move _4, move _6) -> [return: bb4, unwind unreachable];
97-
}
98-
99-
bb4: {
100-
StorageDead(_7);
101-
goto -> bb5;
102-
}
103-
104-
bb5: {
10579
return;
10680
}
10781
}

tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-unwind.mir

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
66
scope 1 (inlined drop_in_place::<Box<[u8; 1024]>> - shim(Some(Box<[u8; 1024]>))) {
77
scope 2 (inlined <Box<[u8; 1024]> as Drop>::drop) {
88
let _2: std::ptr::NonNull<[u8; 1024]>;
9-
let mut _3: *const [u8; 1024];
10-
let _8: ();
9+
let _4: ();
1110
scope 3 {
1211
scope 4 {
1312
scope 17 (inlined Layout::size) {
@@ -25,7 +24,7 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
2524
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
2625
scope 24 (inlined std::alloc::Global::deallocate_impl) {
2726
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
28-
let mut _7: *mut u8;
27+
let mut _3: *mut u8;
2928
scope 26 (inlined Layout::size) {
3029
}
3130
scope 27 (inlined NonNull::<u8>::as_ptr) {
@@ -45,16 +44,13 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
4544
}
4645
}
4746
scope 7 (inlined Layout::for_value_raw::<[u8; 1024]>) {
48-
let mut _4: usize;
49-
let mut _6: std::ptr::Alignment;
5047
scope 8 {
5148
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
5249
}
5350
}
5451
scope 9 (inlined size_of_val_raw::<[u8; 1024]>) {
5552
}
5653
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[u8; 1024]>) {
57-
let _5: usize;
5854
scope 11 {
5955
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
6056
scope 14 (inlined core::ub_checks::check_language_ub) {
@@ -74,34 +70,12 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
7470
bb0: {
7571
_2 = copy (((*_1).0: std::ptr::Unique<[u8; 1024]>).0: std::ptr::NonNull<[u8; 1024]>);
7672
StorageLive(_3);
77-
_3 = copy _2 as *const [u8; 1024] (Transmute);
78-
_4 = std::intrinsics::size_of_val::<[u8; 1024]>(copy _3) -> [return: bb1, unwind unreachable];
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];
7975
}
8076

8177
bb1: {
82-
StorageLive(_5);
83-
_5 = std::intrinsics::align_of_val::<[u8; 1024]>(move _3) -> [return: bb2, unwind unreachable];
84-
}
85-
86-
bb2: {
87-
_6 = copy _5 as std::ptr::Alignment (Transmute);
88-
StorageDead(_5);
8978
StorageDead(_3);
90-
switchInt(copy _4) -> [0: bb5, otherwise: bb3];
91-
}
92-
93-
bb3: {
94-
StorageLive(_7);
95-
_7 = copy _2 as *mut u8 (Transmute);
96-
_8 = alloc::alloc::__rust_dealloc(move _7, move _4, move _6) -> [return: bb4, unwind unreachable];
97-
}
98-
99-
bb4: {
100-
StorageDead(_7);
101-
goto -> bb5;
102-
}
103-
104-
bb5: {
10579
return;
10680
}
10781
}

tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-abort.mir

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ fn drop_generic(_1: *mut Box<T>) -> () {
66
scope 1 (inlined drop_in_place::<Box<T>> - shim(Some(Box<T>))) {
77
scope 2 (inlined <Box<T> as Drop>::drop) {
88
let _2: std::ptr::NonNull<T>;
9-
let mut _3: *const T;
10-
let _8: ();
9+
let _7: ();
1110
scope 3 {
1211
scope 4 {
1312
scope 17 (inlined Layout::size) {
@@ -25,7 +24,7 @@ fn drop_generic(_1: *mut Box<T>) -> () {
2524
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
2625
scope 24 (inlined std::alloc::Global::deallocate_impl) {
2726
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
28-
let mut _7: *mut u8;
27+
let mut _6: *mut u8;
2928
scope 26 (inlined Layout::size) {
3029
}
3130
scope 27 (inlined NonNull::<u8>::as_ptr) {
@@ -45,16 +44,16 @@ fn drop_generic(_1: *mut Box<T>) -> () {
4544
}
4645
}
4746
scope 7 (inlined Layout::for_value_raw::<T>) {
48-
let mut _4: usize;
49-
let mut _6: std::ptr::Alignment;
47+
let mut _3: usize;
48+
let mut _5: std::ptr::Alignment;
5049
scope 8 {
5150
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
5251
}
5352
}
5453
scope 9 (inlined size_of_val_raw::<T>) {
5554
}
5655
scope 10 (inlined std::ptr::Alignment::of_val_raw::<T>) {
57-
let _5: usize;
56+
let _4: usize;
5857
scope 11 {
5958
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
6059
scope 14 (inlined core::ub_checks::check_language_ub) {
@@ -73,35 +72,26 @@ fn drop_generic(_1: *mut Box<T>) -> () {
7372

7473
bb0: {
7574
_2 = copy (((*_1).0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>);
76-
StorageLive(_3);
77-
_3 = copy _2 as *const T (Transmute);
78-
_4 = std::intrinsics::size_of_val::<T>(copy _3) -> [return: bb1, unwind unreachable];
75+
_3 = const <T as std::mem::SizedTypeProperties>::SIZE;
76+
StorageLive(_4);
77+
_4 = const <T as std::mem::SizedTypeProperties>::ALIGN;
78+
_5 = copy _4 as std::ptr::Alignment (Transmute);
79+
StorageDead(_4);
80+
switchInt(copy _3) -> [0: bb3, otherwise: bb1];
7981
}
8082

8183
bb1: {
82-
StorageLive(_5);
83-
_5 = std::intrinsics::align_of_val::<T>(move _3) -> [return: bb2, unwind unreachable];
84+
StorageLive(_6);
85+
_6 = copy _2 as *mut u8 (Transmute);
86+
_7 = alloc::alloc::__rust_dealloc(move _6, move _3, move _5) -> [return: bb2, unwind unreachable];
8487
}
8588

8689
bb2: {
87-
_6 = copy _5 as std::ptr::Alignment (Transmute);
88-
StorageDead(_5);
89-
StorageDead(_3);
90-
switchInt(copy _4) -> [0: bb5, otherwise: bb3];
90+
StorageDead(_6);
91+
goto -> bb3;
9192
}
9293

9394
bb3: {
94-
StorageLive(_7);
95-
_7 = copy _2 as *mut u8 (Transmute);
96-
_8 = alloc::alloc::__rust_dealloc(move _7, move _4, move _6) -> [return: bb4, unwind unreachable];
97-
}
98-
99-
bb4: {
100-
StorageDead(_7);
101-
goto -> bb5;
102-
}
103-
104-
bb5: {
10595
return;
10696
}
10797
}

0 commit comments

Comments
 (0)