Skip to content

Commit de634ba

Browse files
committed
Auto merge of #153085 - oli-obk:transmute_project, r=<try>
GVN: transmute adts to their fields if a field projection is immediately transmuted anyway
2 parents 58745ca + c50b9af commit de634ba

File tree

43 files changed

+1022
-938
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1022
-938
lines changed

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,6 +1494,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
14941494
}
14951495
}
14961496

1497+
#[instrument(level = "trace", skip(self), ret)]
14971498
fn simplify_cast(
14981499
&mut self,
14991500
initial_kind: &mut CastKind,
@@ -1549,6 +1550,38 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
15491550
}
15501551
}
15511552

1553+
// Field-Access-then-Transmute can just transmute the original value,
1554+
// so long as the bytes of a value from only from a single field.
1555+
if let Transmute = kind
1556+
&& let Value::Projection(field_value, ProjectionElem::Field(field_idx, ())) =
1557+
self.get(value)
1558+
{
1559+
if let Value::Projection(downcast_value, ProjectionElem::Downcast(_, _variant_idx)) =
1560+
self.get(field_value)
1561+
&& let downcast_ty = self.ty(downcast_value)
1562+
&& let Ok(downcast_layout) = self.ecx.layout_of(downcast_ty)
1563+
&& let Ok(projected_layout) = self.ecx.layout_of(self.ty(value))
1564+
&& downcast_layout.size == projected_layout.size
1565+
{
1566+
from = downcast_ty;
1567+
value = downcast_value;
1568+
was_updated_this_iteration = true;
1569+
if projected_layout.ty == to {
1570+
return Some(value);
1571+
}
1572+
} else if let Some((f_idx, field_ty)) =
1573+
self.value_is_all_in_one_field(self.ty(field_value), FIRST_VARIANT)
1574+
{
1575+
assert_eq!(field_idx, f_idx, "{from} -> {field_ty}");
1576+
from = self.ty(field_value);
1577+
value = field_value;
1578+
was_updated_this_iteration = true;
1579+
if field_ty == to {
1580+
return Some(value);
1581+
}
1582+
}
1583+
}
1584+
15521585
// Aggregate-then-Transmute can just transmute the original field value,
15531586
// so long as the bytes of a value from only from a single field.
15541587
if let Transmute = kind

library/core/src/ptr/non_null.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::clone::TrivialClone;
22
use crate::cmp::Ordering;
33
use crate::marker::{Destruct, PointeeSized, Unsize};
4-
use crate::mem::{MaybeUninit, SizedTypeProperties};
4+
use crate::mem::{MaybeUninit, SizedTypeProperties, transmute};
55
use crate::num::NonZero;
66
use crate::ops::{CoerceUnsized, DispatchFromDyn};
77
use crate::pin::PinCoerceUnsized;
@@ -100,9 +100,8 @@ impl<T: Sized> NonNull<T> {
100100
#[must_use]
101101
#[inline]
102102
pub const fn without_provenance(addr: NonZero<usize>) -> Self {
103-
let pointer = crate::ptr::without_provenance(addr.get());
104-
// SAFETY: we know `addr` is non-zero.
105-
unsafe { NonNull { pointer } }
103+
// SAFETY: we know `addr` is non-zero and all nonzero integers are valid raw pointers.
104+
unsafe { transmute(addr) }
106105
}
107106

108107
/// Creates a new `NonNull` that is dangling, but well-aligned.
@@ -239,7 +238,7 @@ impl<T: PointeeSized> NonNull<T> {
239238
"NonNull::new_unchecked requires that the pointer is non-null",
240239
(ptr: *mut () = ptr as *mut ()) => !ptr.is_null()
241240
);
242-
NonNull { pointer: ptr as _ }
241+
transmute(ptr)
243242
}
244243
}
245244

@@ -282,7 +281,7 @@ impl<T: PointeeSized> NonNull<T> {
282281
#[inline]
283282
pub const fn from_ref(r: &T) -> Self {
284283
// SAFETY: A reference cannot be null.
285-
unsafe { NonNull { pointer: r as *const T } }
284+
unsafe { transmute(r as *const T) }
286285
}
287286

288287
/// Converts a mutable reference to a `NonNull` pointer.
@@ -291,7 +290,7 @@ impl<T: PointeeSized> NonNull<T> {
291290
#[inline]
292291
pub const fn from_mut(r: &mut T) -> Self {
293292
// SAFETY: A mutable reference cannot be null.
294-
unsafe { NonNull { pointer: r as *mut T } }
293+
unsafe { transmute(r as *mut T) }
295294
}
296295

297296
/// Performs the same functionality as [`std::ptr::from_raw_parts`], except that a
@@ -502,7 +501,7 @@ impl<T: PointeeSized> NonNull<T> {
502501
#[inline]
503502
pub const fn cast<U>(self) -> NonNull<U> {
504503
// SAFETY: `self` is a `NonNull` pointer which is necessarily non-null
505-
unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
504+
unsafe { transmute(self.as_ptr() as *mut U) }
506505
}
507506

508507
/// Try to cast to a pointer of another type by checking alignment.
@@ -581,7 +580,7 @@ impl<T: PointeeSized> NonNull<T> {
581580
// Additionally safety contract of `offset` guarantees that the resulting pointer is
582581
// pointing to an allocation, there can't be an allocation at null, thus it's safe to
583582
// construct `NonNull`.
584-
unsafe { NonNull { pointer: intrinsics::offset(self.as_ptr(), count) } }
583+
unsafe { transmute(intrinsics::offset(self.as_ptr(), count)) }
585584
}
586585

587586
/// Calculates the offset from a pointer in bytes.
@@ -605,7 +604,7 @@ impl<T: PointeeSized> NonNull<T> {
605604
// Additionally safety contract of `offset` guarantees that the resulting pointer is
606605
// pointing to an allocation, there can't be an allocation at null, thus it's safe to
607606
// construct `NonNull`.
608-
unsafe { NonNull { pointer: self.as_ptr().byte_offset(count) } }
607+
unsafe { transmute(self.as_ptr().byte_offset(count)) }
609608
}
610609

611610
/// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
@@ -657,7 +656,7 @@ impl<T: PointeeSized> NonNull<T> {
657656
// Additionally safety contract of `offset` guarantees that the resulting pointer is
658657
// pointing to an allocation, there can't be an allocation at null, thus it's safe to
659658
// construct `NonNull`.
660-
unsafe { NonNull { pointer: intrinsics::offset(self.as_ptr(), count) } }
659+
unsafe { transmute(intrinsics::offset(self.as_ptr(), count)) }
661660
}
662661

663662
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
@@ -681,7 +680,7 @@ impl<T: PointeeSized> NonNull<T> {
681680
// Additionally safety contract of `add` guarantees that the resulting pointer is pointing
682681
// to an allocation, there can't be an allocation at null, thus it's safe to construct
683682
// `NonNull`.
684-
unsafe { NonNull { pointer: self.as_ptr().byte_add(count) } }
683+
unsafe { transmute(self.as_ptr().byte_add(count)) }
685684
}
686685

687686
/// Subtracts an offset from a pointer (convenience for
@@ -763,7 +762,7 @@ impl<T: PointeeSized> NonNull<T> {
763762
// Additionally safety contract of `sub` guarantees that the resulting pointer is pointing
764763
// to an allocation, there can't be an allocation at null, thus it's safe to construct
765764
// `NonNull`.
766-
unsafe { NonNull { pointer: self.as_ptr().byte_sub(count) } }
765+
unsafe { transmute(self.as_ptr().byte_sub(count)) }
767766
}
768767

769768
/// Calculates the distance between two pointers within the same allocation. The returned value is in

tests/codegen-llvm/loads.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 {
5858
// CHECK-LABEL: @load_box
5959
#[no_mangle]
6060
pub fn load_box<'a>(x: Box<Box<i32>>) -> Box<i32> {
61-
// CHECK: load ptr, ptr %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
61+
// CHECK: load ptr, ptr %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !noundef !{{[0-9]+}}
6262
*x
6363
}
6464

tests/codegen-units/item-collection/opaque-return-impls.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,4 @@ pub fn foo3() -> Box<dyn Iterator<Item = usize>> {
8686
//~ MONO_ITEM fn std::boxed::Box::<Counter>::new
8787
//~ MONO_ITEM fn Counter::new
8888
//~ MONO_ITEM fn std::fmt::Arguments::<'_>::from_str
89+
//~ MONO_ITEM fn std::boxed::box_new_uninit
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
- // MIR for `option_field` before GVN
2+
+ // MIR for `option_field` after GVN
3+
4+
fn option_field(_1: Option<NonNull<()>>) -> *const () {
5+
debug x => _1;
6+
let mut _0: *const ();
7+
let mut _2: isize;
8+
let mut _4: std::ptr::NonNull<()>;
9+
scope 1 {
10+
debug x => _3;
11+
let _3: std::ptr::NonNull<()>;
12+
}
13+
14+
bb0: {
15+
_2 = discriminant(_1);
16+
switchInt(move _2) -> [1: bb1, otherwise: bb2];
17+
}
18+
19+
bb1: {
20+
- StorageLive(_3);
21+
+ nop;
22+
_3 = copy ((_1 as Some).0: std::ptr::NonNull<()>);
23+
StorageLive(_4);
24+
_4 = copy _3;
25+
- _0 = move _4 as *const () (Transmute);
26+
+ _0 = copy _1 as *const () (Transmute);
27+
StorageDead(_4);
28+
- StorageDead(_3);
29+
+ nop;
30+
goto -> bb3;
31+
}
32+
33+
bb2: {
34+
_0 = const 0_usize as *const () (PointerWithExposedProvenance);
35+
goto -> bb3;
36+
}
37+
38+
bb3: {
39+
return;
40+
}
41+
}
42+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
- // MIR for `option_field` before GVN
2+
+ // MIR for `option_field` after GVN
3+
4+
fn option_field(_1: Option<NonNull<()>>) -> *const () {
5+
debug x => _1;
6+
let mut _0: *const ();
7+
let mut _2: isize;
8+
let mut _4: std::ptr::NonNull<()>;
9+
scope 1 {
10+
debug x => _3;
11+
let _3: std::ptr::NonNull<()>;
12+
}
13+
14+
bb0: {
15+
_2 = discriminant(_1);
16+
switchInt(move _2) -> [1: bb1, otherwise: bb2];
17+
}
18+
19+
bb1: {
20+
- StorageLive(_3);
21+
+ nop;
22+
_3 = copy ((_1 as Some).0: std::ptr::NonNull<()>);
23+
StorageLive(_4);
24+
_4 = copy _3;
25+
- _0 = move _4 as *const () (Transmute);
26+
+ _0 = copy _1 as *const () (Transmute);
27+
StorageDead(_4);
28+
- StorageDead(_3);
29+
+ nop;
30+
goto -> bb3;
31+
}
32+
33+
bb2: {
34+
_0 = const 0_usize as *const () (PointerWithExposedProvenance);
35+
goto -> bb3;
36+
}
37+
38+
bb3: {
39+
return;
40+
}
41+
}
42+

tests/mir-opt/const_prop/transmute.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,12 @@ pub unsafe fn unreachable_box() -> ! {
8484
match *x {}
8585
}
8686

87+
// EMIT_MIR transmute.option_field.GVN.diff
88+
pub unsafe fn option_field(x: Option<std::ptr::NonNull<()>>) -> *const () {
89+
// CHECK-LABEL: fn option_field(
90+
// CHECK: _3 = copy ((_1 as Some).0: std::ptr::NonNull<()>)
91+
// CHECK: _0 = copy _1 as *const () (Transmute)
92+
if let Some(x) = x { unsafe { transmute(x) } } else { 0 as *const () }
93+
}
94+
8795
enum Never {}

tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
- _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
1515
- _2 = copy ((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>) as *const Never (Transmute);
1616
+ _1 = const Box::<Never>(std::ptr::Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
17-
+ _2 = const std::ptr::NonNull::<Never> {{ pointer: {0x1 as *const Never} }} as *const Never (Transmute);
17+
+ _2 = const std::boxed::Box::<Never>(std::ptr::Unique::<Never> {{ pointer: std::ptr::NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: std::marker::PhantomData::<Never> }}, std::alloc::Global) as *const Never (Transmute);
1818
unreachable;
1919
}
2020
}

tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
- _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
1515
- _2 = copy ((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>) as *const Never (Transmute);
1616
+ _1 = const Box::<Never>(std::ptr::Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
17-
+ _2 = const std::ptr::NonNull::<Never> {{ pointer: {0x1 as *const Never} }} as *const Never (Transmute);
17+
+ _2 = const std::boxed::Box::<Never>(std::ptr::Unique::<Never> {{ pointer: std::ptr::NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: std::marker::PhantomData::<Never> }}, std::alloc::Global) as *const Never (Transmute);
1818
unreachable;
1919
}
2020
}

tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,6 @@
2020
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
2121
}
2222
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
23-
let _6: *const [bool; 0];
24-
scope 10 {
25-
}
26-
scope 11 (inlined NonZero::<usize>::get) {
27-
}
28-
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
29-
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
30-
}
31-
}
3223
}
3324
}
3425
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
@@ -43,10 +34,7 @@
4334
StorageLive(_3);
4435
StorageLive(_4);
4536
StorageLive(_5);
46-
StorageLive(_6);
47-
_6 = const {0x1 as *const [bool; 0]};
4837
_5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
49-
StorageDead(_6);
5038
_4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
5139
StorageDead(_5);
5240
_3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};

0 commit comments

Comments
 (0)