Refactor the cast-then-cast cases together, and support transmute-then-transmute
This commit is contained in:
parent
03650dd029
commit
293f8e8941
12 changed files with 589 additions and 113 deletions
|
@ -1366,110 +1366,112 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
||||||
return self.new_opaque();
|
return self.new_opaque();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut was_updated = false;
|
let mut was_ever_updated = false;
|
||||||
|
loop {
|
||||||
|
let mut was_updated_this_iteration = false;
|
||||||
|
|
||||||
// Transmuting `*const T` <=> `*mut T` is just a pointer cast,
|
// Transmuting `*const T` <=> `*mut T` is just a pointer cast,
|
||||||
// which we might be able to merge with other ones later.
|
// which we might be able to merge with other ones later.
|
||||||
if let Transmute = kind
|
if let Transmute = kind
|
||||||
&& let ty::RawPtr(from_pointee, _) = from.kind()
|
&& let ty::RawPtr(from_pointee, _) = from.kind()
|
||||||
&& let ty::RawPtr(to_pointee, _) = to.kind()
|
&& let ty::RawPtr(to_pointee, _) = to.kind()
|
||||||
&& from_pointee == to_pointee
|
&& from_pointee == to_pointee
|
||||||
{
|
{
|
||||||
*kind = PtrToPtr;
|
*kind = PtrToPtr;
|
||||||
was_updated = true;
|
was_updated_this_iteration = true;
|
||||||
}
|
|
||||||
|
|
||||||
// If a cast just casts away the metadata again, then we can get it by
|
|
||||||
// casting the original thin pointer passed to `from_raw_parts`
|
|
||||||
if let PtrToPtr = kind
|
|
||||||
&& let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
|
|
||||||
self.get(value)
|
|
||||||
&& let ty::RawPtr(to_pointee, _) = to.kind()
|
|
||||||
&& to_pointee.is_sized(self.tcx, self.typing_env())
|
|
||||||
{
|
|
||||||
from = *data_pointer_ty;
|
|
||||||
value = fields[0];
|
|
||||||
was_updated = true;
|
|
||||||
if *data_pointer_ty == to {
|
|
||||||
return Some(fields[0]);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// PtrToPtr-then-PtrToPtr can skip the intermediate step
|
// If a cast just casts away the metadata again, then we can get it by
|
||||||
if let PtrToPtr = kind
|
// casting the original thin pointer passed to `from_raw_parts`
|
||||||
&& let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } =
|
if let PtrToPtr = kind
|
||||||
*self.get(value)
|
&& let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
|
||||||
&& let PtrToPtr = inner_kind
|
self.get(value)
|
||||||
{
|
&& let ty::RawPtr(to_pointee, _) = to.kind()
|
||||||
from = inner_from;
|
&& to_pointee.is_sized(self.tcx, self.typing_env())
|
||||||
value = inner_value;
|
{
|
||||||
was_updated = true;
|
from = *data_pointer_ty;
|
||||||
if inner_from == to {
|
value = fields[0];
|
||||||
return Some(inner_value);
|
was_updated_this_iteration = true;
|
||||||
|
if *data_pointer_ty == to {
|
||||||
|
return Some(fields[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Aggregate-then-Transmute can just transmute the original field value,
|
// Aggregate-then-Transmute can just transmute the original field value,
|
||||||
// so long as the bytes of a value from only from a single field.
|
// so long as the bytes of a value from only from a single field.
|
||||||
if let Transmute = kind
|
if let Transmute = kind
|
||||||
&& let Value::Aggregate(
|
&& let Value::Aggregate(
|
||||||
AggregateTy::Def(aggregate_did, aggregate_args),
|
AggregateTy::Def(aggregate_did, aggregate_args),
|
||||||
variant_idx,
|
variant_idx,
|
||||||
field_values,
|
field_values,
|
||||||
) = self.get(value)
|
) = self.get(value)
|
||||||
&& let aggregate_ty =
|
&& let aggregate_ty =
|
||||||
self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args)
|
self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args)
|
||||||
&& let Some((field_idx, field_ty)) =
|
&& let Some((field_idx, field_ty)) =
|
||||||
self.value_is_all_in_one_field(aggregate_ty, *variant_idx)
|
self.value_is_all_in_one_field(aggregate_ty, *variant_idx)
|
||||||
{
|
{
|
||||||
from = field_ty;
|
from = field_ty;
|
||||||
value = field_values[field_idx.as_usize()];
|
value = field_values[field_idx.as_usize()];
|
||||||
was_updated = true;
|
was_updated_this_iteration = true;
|
||||||
if field_ty == to {
|
if field_ty == to {
|
||||||
return Some(value);
|
return Some(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// PtrToPtr-then-Transmute can just transmute the original, so long as the
|
// Various cast-then-cast cases can be simplified.
|
||||||
// PtrToPtr didn't change metadata (and thus the size of the pointer)
|
if let Value::Cast {
|
||||||
if let Transmute = kind
|
kind: inner_kind,
|
||||||
&& let Value::Cast {
|
|
||||||
kind: PtrToPtr,
|
|
||||||
value: inner_value,
|
value: inner_value,
|
||||||
from: inner_from,
|
from: inner_from,
|
||||||
to: inner_to,
|
to: inner_to,
|
||||||
} = *self.get(value)
|
} = *self.get(value)
|
||||||
&& self.pointers_have_same_metadata(inner_from, inner_to)
|
{
|
||||||
{
|
let new_kind = match (inner_kind, *kind) {
|
||||||
from = inner_from;
|
// Even if there's a narrowing cast in here that's fine, because
|
||||||
value = inner_value;
|
// things like `*mut [i32] -> *mut i32 -> *const i32` and
|
||||||
was_updated = true;
|
// `*mut [i32] -> *const [i32] -> *const i32` can skip the middle in MIR.
|
||||||
if inner_from == to {
|
(PtrToPtr, PtrToPtr) => Some(PtrToPtr),
|
||||||
return Some(inner_value);
|
// PtrToPtr-then-Transmute is fine so long as the pointer cast is identity:
|
||||||
|
// `*const T -> *mut T -> NonNull<T>` is fine, but we need to check for narrowing
|
||||||
|
// to skip things like `*const [i32] -> *const i32 -> NonNull<T>`.
|
||||||
|
(PtrToPtr, Transmute)
|
||||||
|
if self.pointers_have_same_metadata(inner_from, inner_to) =>
|
||||||
|
{
|
||||||
|
Some(Transmute)
|
||||||
|
}
|
||||||
|
// Similarly, for Transmute-then-PtrToPtr. Note that we need to check different
|
||||||
|
// variables for their metadata, and thus this can't merge with the previous arm.
|
||||||
|
(Transmute, PtrToPtr) if self.pointers_have_same_metadata(from, to) => {
|
||||||
|
Some(Transmute)
|
||||||
|
}
|
||||||
|
// If would be legal to always do this, but we don't want to hide information
|
||||||
|
// from the backend that it'd otherwise be able to use for optimizations.
|
||||||
|
(Transmute, Transmute)
|
||||||
|
if !self.type_may_have_niche_of_interest_to_backend(inner_to) =>
|
||||||
|
{
|
||||||
|
Some(Transmute)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(new_kind) = new_kind {
|
||||||
|
*kind = new_kind;
|
||||||
|
from = inner_from;
|
||||||
|
value = inner_value;
|
||||||
|
was_updated_this_iteration = true;
|
||||||
|
if inner_from == to {
|
||||||
|
return Some(inner_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if was_updated_this_iteration {
|
||||||
|
was_ever_updated = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transmute-then-PtrToPtr can just transmute the original, so long as the
|
if was_ever_updated && let Some(op) = self.try_as_operand(value, location) {
|
||||||
// PtrToPtr won't change metadata (and thus the size of the pointer)
|
|
||||||
if let PtrToPtr = kind
|
|
||||||
&& let Value::Cast {
|
|
||||||
kind: Transmute,
|
|
||||||
value: inner_value,
|
|
||||||
from: inner_from,
|
|
||||||
to: _inner_to,
|
|
||||||
} = *self.get(value)
|
|
||||||
&& self.pointers_have_same_metadata(from, to)
|
|
||||||
{
|
|
||||||
*kind = Transmute;
|
|
||||||
from = inner_from;
|
|
||||||
value = inner_value;
|
|
||||||
was_updated = true;
|
|
||||||
if inner_from == to {
|
|
||||||
return Some(inner_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if was_updated && let Some(op) = self.try_as_operand(value, location) {
|
|
||||||
*operand = op;
|
*operand = op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1492,6 +1494,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `false` if we know for sure that this type has no interesting niche,
|
||||||
|
/// and thus we can skip transmuting through it without worrying.
|
||||||
|
///
|
||||||
|
/// The backend will emit `assume`s when transmuting between types with niches,
|
||||||
|
/// so we want to preserve `i32 -> char -> u32` so that that data is around,
|
||||||
|
/// but it's fine to skip whole-range-is-value steps like `A -> u32 -> B`.
|
||||||
|
fn type_may_have_niche_of_interest_to_backend(&self, ty: Ty<'tcx>) -> bool {
|
||||||
|
let Ok(layout) = self.ecx.layout_of(ty) else {
|
||||||
|
// If it's too generic or something, then assume it might be interesting later.
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
match layout.backend_repr {
|
||||||
|
BackendRepr::Uninhabited => true,
|
||||||
|
BackendRepr::Scalar(a) => !a.is_always_valid(&self.ecx),
|
||||||
|
BackendRepr::ScalarPair(a, b) => {
|
||||||
|
!a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx)
|
||||||
|
}
|
||||||
|
BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn value_is_all_in_one_field(
|
fn value_is_all_in_one_field(
|
||||||
&self,
|
&self,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
|
|
@ -17,15 +17,49 @@
|
||||||
let mut _14: u16;
|
let mut _14: u16;
|
||||||
let _15: ();
|
let _15: ();
|
||||||
let mut _16: u16;
|
let mut _16: u16;
|
||||||
let mut _17: std::result::Result<aggregate_struct_then_transmute::Never, u16>;
|
let mut _17: std::result::Result<Never, u16>;
|
||||||
|
let mut _19: u16;
|
||||||
|
let _20: ();
|
||||||
|
let mut _21: u32;
|
||||||
|
let mut _22: std::option::Option<u16>;
|
||||||
|
let mut _24: u16;
|
||||||
|
let _25: ();
|
||||||
|
let mut _26: i16;
|
||||||
|
let mut _27: MyId;
|
||||||
|
let mut _29: u16;
|
||||||
|
let mut _30: u16;
|
||||||
|
let _31: ();
|
||||||
|
let mut _32: u32;
|
||||||
|
let mut _33: aggregate_struct_then_transmute::Pair;
|
||||||
|
let mut _35: u16;
|
||||||
|
let mut _36: u16;
|
||||||
|
let _37: ();
|
||||||
|
let mut _38: u16;
|
||||||
|
let mut _39: aggregate_struct_then_transmute::Pair;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug a => _2;
|
debug a => _2;
|
||||||
let _7: TypedId<std::string::String>;
|
let _7: TypedId<std::string::String>;
|
||||||
scope 2 {
|
scope 2 {
|
||||||
debug b => _7;
|
debug b => _7;
|
||||||
let _13: std::result::Result<aggregate_struct_then_transmute::Never, u16>;
|
let _13: std::result::Result<Never, u16>;
|
||||||
scope 3 {
|
scope 3 {
|
||||||
debug c => _13;
|
debug c => _13;
|
||||||
|
let _18: std::option::Option<u16>;
|
||||||
|
scope 4 {
|
||||||
|
debug d => _18;
|
||||||
|
let _23: MyId;
|
||||||
|
scope 5 {
|
||||||
|
debug e => _23;
|
||||||
|
let _28: aggregate_struct_then_transmute::Pair;
|
||||||
|
scope 6 {
|
||||||
|
debug f => _28;
|
||||||
|
let _34: aggregate_struct_then_transmute::Pair;
|
||||||
|
scope 7 {
|
||||||
|
debug g => _34;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,12 +135,105 @@
|
||||||
bb3: {
|
bb3: {
|
||||||
StorageDead(_16);
|
StorageDead(_16);
|
||||||
StorageDead(_15);
|
StorageDead(_15);
|
||||||
|
- StorageLive(_18);
|
||||||
|
+ nop;
|
||||||
|
StorageLive(_19);
|
||||||
|
_19 = copy _1;
|
||||||
|
- _18 = Option::<u16>::Some(move _19);
|
||||||
|
+ _18 = Option::<u16>::Some(copy _1);
|
||||||
|
StorageDead(_19);
|
||||||
|
StorageLive(_20);
|
||||||
|
StorageLive(_21);
|
||||||
|
StorageLive(_22);
|
||||||
|
_22 = copy _18;
|
||||||
|
- _21 = move _22 as u32 (Transmute);
|
||||||
|
+ _21 = copy _18 as u32 (Transmute);
|
||||||
|
StorageDead(_22);
|
||||||
|
_20 = opaque::<u32>(move _21) -> [return: bb4, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
StorageDead(_21);
|
||||||
|
StorageDead(_20);
|
||||||
|
StorageLive(_23);
|
||||||
|
StorageLive(_24);
|
||||||
|
_24 = copy _1;
|
||||||
|
- _23 = MyId(move _24);
|
||||||
|
+ _23 = copy _2;
|
||||||
|
StorageDead(_24);
|
||||||
|
StorageLive(_25);
|
||||||
|
StorageLive(_26);
|
||||||
|
StorageLive(_27);
|
||||||
|
- _27 = move _23;
|
||||||
|
- _26 = move _27 as i16 (Transmute);
|
||||||
|
+ _27 = copy _2;
|
||||||
|
+ _26 = copy _1 as i16 (Transmute);
|
||||||
|
StorageDead(_27);
|
||||||
|
_25 = opaque::<i16>(move _26) -> [return: bb5, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
StorageDead(_26);
|
||||||
|
StorageDead(_25);
|
||||||
|
- StorageLive(_28);
|
||||||
|
+ nop;
|
||||||
|
StorageLive(_29);
|
||||||
|
_29 = copy _1;
|
||||||
|
StorageLive(_30);
|
||||||
|
_30 = copy _1;
|
||||||
|
- _28 = Pair(move _29, move _30);
|
||||||
|
+ _28 = Pair(copy _1, copy _1);
|
||||||
|
StorageDead(_30);
|
||||||
|
StorageDead(_29);
|
||||||
|
StorageLive(_31);
|
||||||
|
StorageLive(_32);
|
||||||
|
StorageLive(_33);
|
||||||
|
- _33 = move _28;
|
||||||
|
- _32 = move _33 as u32 (Transmute);
|
||||||
|
+ _33 = copy _28;
|
||||||
|
+ _32 = copy _28 as u32 (Transmute);
|
||||||
|
StorageDead(_33);
|
||||||
|
_31 = opaque::<u32>(move _32) -> [return: bb6, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
StorageDead(_32);
|
||||||
|
StorageDead(_31);
|
||||||
|
StorageLive(_34);
|
||||||
|
StorageLive(_35);
|
||||||
|
_35 = copy _1;
|
||||||
|
StorageLive(_36);
|
||||||
|
_36 = copy _1;
|
||||||
|
- _34 = Pair(move _35, move _36);
|
||||||
|
+ _34 = copy _28;
|
||||||
|
StorageDead(_36);
|
||||||
|
StorageDead(_35);
|
||||||
|
StorageLive(_37);
|
||||||
|
StorageLive(_38);
|
||||||
|
StorageLive(_39);
|
||||||
|
- _39 = move _34;
|
||||||
|
- _38 = move _39 as u16 (Transmute);
|
||||||
|
+ _39 = copy _28;
|
||||||
|
+ _38 = copy _28 as u16 (Transmute);
|
||||||
|
StorageDead(_39);
|
||||||
|
_37 = opaque::<u16>(move _38) -> [return: bb7, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
StorageDead(_38);
|
||||||
|
StorageDead(_37);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
|
StorageDead(_34);
|
||||||
|
- StorageDead(_28);
|
||||||
|
+ nop;
|
||||||
|
StorageDead(_23);
|
||||||
|
- StorageDead(_18);
|
||||||
- StorageDead(_13);
|
- StorageDead(_13);
|
||||||
- StorageDead(_7);
|
- StorageDead(_7);
|
||||||
- StorageDead(_2);
|
- StorageDead(_2);
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,49 @@
|
||||||
let mut _14: u16;
|
let mut _14: u16;
|
||||||
let _15: ();
|
let _15: ();
|
||||||
let mut _16: u16;
|
let mut _16: u16;
|
||||||
let mut _17: std::result::Result<aggregate_struct_then_transmute::Never, u16>;
|
let mut _17: std::result::Result<Never, u16>;
|
||||||
|
let mut _19: u16;
|
||||||
|
let _20: ();
|
||||||
|
let mut _21: u32;
|
||||||
|
let mut _22: std::option::Option<u16>;
|
||||||
|
let mut _24: u16;
|
||||||
|
let _25: ();
|
||||||
|
let mut _26: i16;
|
||||||
|
let mut _27: MyId;
|
||||||
|
let mut _29: u16;
|
||||||
|
let mut _30: u16;
|
||||||
|
let _31: ();
|
||||||
|
let mut _32: u32;
|
||||||
|
let mut _33: aggregate_struct_then_transmute::Pair;
|
||||||
|
let mut _35: u16;
|
||||||
|
let mut _36: u16;
|
||||||
|
let _37: ();
|
||||||
|
let mut _38: u16;
|
||||||
|
let mut _39: aggregate_struct_then_transmute::Pair;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug a => _2;
|
debug a => _2;
|
||||||
let _7: TypedId<std::string::String>;
|
let _7: TypedId<std::string::String>;
|
||||||
scope 2 {
|
scope 2 {
|
||||||
debug b => _7;
|
debug b => _7;
|
||||||
let _13: std::result::Result<aggregate_struct_then_transmute::Never, u16>;
|
let _13: std::result::Result<Never, u16>;
|
||||||
scope 3 {
|
scope 3 {
|
||||||
debug c => _13;
|
debug c => _13;
|
||||||
|
let _18: std::option::Option<u16>;
|
||||||
|
scope 4 {
|
||||||
|
debug d => _18;
|
||||||
|
let _23: MyId;
|
||||||
|
scope 5 {
|
||||||
|
debug e => _23;
|
||||||
|
let _28: aggregate_struct_then_transmute::Pair;
|
||||||
|
scope 6 {
|
||||||
|
debug f => _28;
|
||||||
|
let _34: aggregate_struct_then_transmute::Pair;
|
||||||
|
scope 7 {
|
||||||
|
debug g => _34;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,12 +135,105 @@
|
||||||
bb3: {
|
bb3: {
|
||||||
StorageDead(_16);
|
StorageDead(_16);
|
||||||
StorageDead(_15);
|
StorageDead(_15);
|
||||||
|
- StorageLive(_18);
|
||||||
|
+ nop;
|
||||||
|
StorageLive(_19);
|
||||||
|
_19 = copy _1;
|
||||||
|
- _18 = Option::<u16>::Some(move _19);
|
||||||
|
+ _18 = Option::<u16>::Some(copy _1);
|
||||||
|
StorageDead(_19);
|
||||||
|
StorageLive(_20);
|
||||||
|
StorageLive(_21);
|
||||||
|
StorageLive(_22);
|
||||||
|
_22 = copy _18;
|
||||||
|
- _21 = move _22 as u32 (Transmute);
|
||||||
|
+ _21 = copy _18 as u32 (Transmute);
|
||||||
|
StorageDead(_22);
|
||||||
|
_20 = opaque::<u32>(move _21) -> [return: bb4, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
StorageDead(_21);
|
||||||
|
StorageDead(_20);
|
||||||
|
StorageLive(_23);
|
||||||
|
StorageLive(_24);
|
||||||
|
_24 = copy _1;
|
||||||
|
- _23 = MyId(move _24);
|
||||||
|
+ _23 = copy _2;
|
||||||
|
StorageDead(_24);
|
||||||
|
StorageLive(_25);
|
||||||
|
StorageLive(_26);
|
||||||
|
StorageLive(_27);
|
||||||
|
- _27 = move _23;
|
||||||
|
- _26 = move _27 as i16 (Transmute);
|
||||||
|
+ _27 = copy _2;
|
||||||
|
+ _26 = copy _1 as i16 (Transmute);
|
||||||
|
StorageDead(_27);
|
||||||
|
_25 = opaque::<i16>(move _26) -> [return: bb5, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
StorageDead(_26);
|
||||||
|
StorageDead(_25);
|
||||||
|
- StorageLive(_28);
|
||||||
|
+ nop;
|
||||||
|
StorageLive(_29);
|
||||||
|
_29 = copy _1;
|
||||||
|
StorageLive(_30);
|
||||||
|
_30 = copy _1;
|
||||||
|
- _28 = Pair(move _29, move _30);
|
||||||
|
+ _28 = Pair(copy _1, copy _1);
|
||||||
|
StorageDead(_30);
|
||||||
|
StorageDead(_29);
|
||||||
|
StorageLive(_31);
|
||||||
|
StorageLive(_32);
|
||||||
|
StorageLive(_33);
|
||||||
|
- _33 = move _28;
|
||||||
|
- _32 = move _33 as u32 (Transmute);
|
||||||
|
+ _33 = copy _28;
|
||||||
|
+ _32 = copy _28 as u32 (Transmute);
|
||||||
|
StorageDead(_33);
|
||||||
|
_31 = opaque::<u32>(move _32) -> [return: bb6, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
StorageDead(_32);
|
||||||
|
StorageDead(_31);
|
||||||
|
StorageLive(_34);
|
||||||
|
StorageLive(_35);
|
||||||
|
_35 = copy _1;
|
||||||
|
StorageLive(_36);
|
||||||
|
_36 = copy _1;
|
||||||
|
- _34 = Pair(move _35, move _36);
|
||||||
|
+ _34 = copy _28;
|
||||||
|
StorageDead(_36);
|
||||||
|
StorageDead(_35);
|
||||||
|
StorageLive(_37);
|
||||||
|
StorageLive(_38);
|
||||||
|
StorageLive(_39);
|
||||||
|
- _39 = move _34;
|
||||||
|
- _38 = move _39 as u16 (Transmute);
|
||||||
|
+ _39 = copy _28;
|
||||||
|
+ _38 = copy _28 as u16 (Transmute);
|
||||||
|
StorageDead(_39);
|
||||||
|
_37 = opaque::<u16>(move _38) -> [return: bb7, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
StorageDead(_38);
|
||||||
|
StorageDead(_37);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
|
StorageDead(_34);
|
||||||
|
- StorageDead(_28);
|
||||||
|
+ nop;
|
||||||
|
StorageDead(_23);
|
||||||
|
- StorageDead(_18);
|
||||||
- StorageDead(_13);
|
- StorageDead(_13);
|
||||||
- StorageDead(_7);
|
- StorageDead(_7);
|
||||||
- StorageDead(_2);
|
- StorageDead(_2);
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -946,7 +946,42 @@ unsafe fn aggregate_struct_then_transmute(id: u16) {
|
||||||
let c = Err::<Never, u16>(id);
|
let c = Err::<Never, u16>(id);
|
||||||
opaque(std::intrinsics::transmute::<_, u16>(c));
|
opaque(std::intrinsics::transmute::<_, u16>(c));
|
||||||
|
|
||||||
enum Never {}
|
// CHECK: [[TEMP1:_[0-9]+]] = Option::<u16>::Some(copy _1);
|
||||||
|
// CHECK: [[TEMP2:_[0-9]+]] = copy [[TEMP1]] as u32 (Transmute);
|
||||||
|
// CHECK: opaque::<u32>(move [[TEMP2]])
|
||||||
|
let d = Some(id);
|
||||||
|
opaque(std::intrinsics::transmute::<_, u32>(d));
|
||||||
|
|
||||||
|
// Still need the transmute, but the aggregate can be skipped
|
||||||
|
// CHECK: [[TEMP:_[0-9]+]] = copy _1 as i16 (Transmute);
|
||||||
|
// CHECK: opaque::<i16>(move [[TEMP]])
|
||||||
|
let e = MyId(id);
|
||||||
|
opaque(std::intrinsics::transmute::<_, i16>(e));
|
||||||
|
|
||||||
|
// CHECK: [[PAIR:_[0-9]+]] = Pair(copy _1, copy _1);
|
||||||
|
// CHECK: [[TEMP:_[0-9]+]] = copy [[PAIR]] as u32 (Transmute);
|
||||||
|
// CHECK: opaque::<u32>(move [[TEMP]])
|
||||||
|
struct Pair(u16, u16);
|
||||||
|
let f = Pair(id, id);
|
||||||
|
opaque(std::intrinsics::transmute::<_, u32>(f));
|
||||||
|
|
||||||
|
// CHECK: [[TEMP:_[0-9]+]] = copy [[PAIR]] as u16 (Transmute);
|
||||||
|
// CHECK: opaque::<u16>(move [[TEMP]])
|
||||||
|
let g = Pair(id, id);
|
||||||
|
opaque(std::intrinsics::transmute_unchecked::<_, u16>(g));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn transmute_then_transmute_again(a: u32, c: char) {
|
||||||
|
// CHECK: [[TEMP1:_[0-9]+]] = copy _1 as char (Transmute);
|
||||||
|
// CHECK: [[TEMP2:_[0-9]+]] = copy [[TEMP1]] as i32 (Transmute);
|
||||||
|
// CHECK: opaque::<i32>(move [[TEMP2]])
|
||||||
|
let x = std::intrinsics::transmute::<u32, char>(a);
|
||||||
|
opaque(std::intrinsics::transmute::<char, i32>(x));
|
||||||
|
|
||||||
|
// CHECK: [[TEMP:_[0-9]+]] = copy _2 as i32 (Transmute);
|
||||||
|
// CHECK: opaque::<i32>(move [[TEMP]])
|
||||||
|
let x = std::intrinsics::transmute::<char, u32>(c);
|
||||||
|
opaque(std::intrinsics::transmute::<u32, i32>(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transmuting can skip a pointer cast so long as it wasn't a fat-to-thin cast.
|
// Transmuting can skip a pointer cast so long as it wasn't a fat-to-thin cast.
|
||||||
|
@ -1050,6 +1085,8 @@ struct MyId(u16);
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct TypedId<T>(u16, PhantomData<T>);
|
struct TypedId<T>(u16, PhantomData<T>);
|
||||||
|
|
||||||
|
enum Never {}
|
||||||
|
|
||||||
// EMIT_MIR gvn.subexpression_elimination.GVN.diff
|
// EMIT_MIR gvn.subexpression_elimination.GVN.diff
|
||||||
// EMIT_MIR gvn.wrap_unwrap.GVN.diff
|
// EMIT_MIR gvn.wrap_unwrap.GVN.diff
|
||||||
// EMIT_MIR gvn.repeated_index.GVN.diff
|
// EMIT_MIR gvn.repeated_index.GVN.diff
|
||||||
|
@ -1083,6 +1120,7 @@ struct TypedId<T>(u16, PhantomData<T>);
|
||||||
// EMIT_MIR gvn.generic_cast_metadata.GVN.diff
|
// EMIT_MIR gvn.generic_cast_metadata.GVN.diff
|
||||||
// EMIT_MIR gvn.cast_pointer_eq.GVN.diff
|
// EMIT_MIR gvn.cast_pointer_eq.GVN.diff
|
||||||
// EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff
|
// EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff
|
||||||
|
// EMIT_MIR gvn.transmute_then_transmute_again.GVN.diff
|
||||||
// EMIT_MIR gvn.cast_pointer_then_transmute.GVN.diff
|
// EMIT_MIR gvn.cast_pointer_then_transmute.GVN.diff
|
||||||
// EMIT_MIR gvn.transmute_then_cast_pointer.GVN.diff
|
// EMIT_MIR gvn.transmute_then_cast_pointer.GVN.diff
|
||||||
// EMIT_MIR gvn.remove_casts_must_change_both_sides.GVN.diff
|
// EMIT_MIR gvn.remove_casts_must_change_both_sides.GVN.diff
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
- // MIR for `transmute_then_transmute_again` before GVN
|
||||||
|
+ // MIR for `transmute_then_transmute_again` after GVN
|
||||||
|
|
||||||
|
fn transmute_then_transmute_again(_1: u32, _2: char) -> () {
|
||||||
|
debug a => _1;
|
||||||
|
debug c => _2;
|
||||||
|
let mut _0: ();
|
||||||
|
let _3: char;
|
||||||
|
let mut _4: u32;
|
||||||
|
let _5: ();
|
||||||
|
let mut _6: i32;
|
||||||
|
let mut _7: char;
|
||||||
|
let mut _9: char;
|
||||||
|
let _10: ();
|
||||||
|
let mut _11: i32;
|
||||||
|
let mut _12: u32;
|
||||||
|
scope 1 {
|
||||||
|
debug x => _3;
|
||||||
|
let _8: u32;
|
||||||
|
scope 2 {
|
||||||
|
debug x => _8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
- StorageLive(_3);
|
||||||
|
+ nop;
|
||||||
|
StorageLive(_4);
|
||||||
|
_4 = copy _1;
|
||||||
|
- _3 = move _4 as char (Transmute);
|
||||||
|
+ _3 = copy _1 as char (Transmute);
|
||||||
|
StorageDead(_4);
|
||||||
|
StorageLive(_5);
|
||||||
|
StorageLive(_6);
|
||||||
|
StorageLive(_7);
|
||||||
|
_7 = copy _3;
|
||||||
|
- _6 = move _7 as i32 (Transmute);
|
||||||
|
+ _6 = copy _3 as i32 (Transmute);
|
||||||
|
StorageDead(_7);
|
||||||
|
_5 = opaque::<i32>(move _6) -> [return: bb1, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageDead(_6);
|
||||||
|
StorageDead(_5);
|
||||||
|
- StorageLive(_8);
|
||||||
|
+ nop;
|
||||||
|
StorageLive(_9);
|
||||||
|
_9 = copy _2;
|
||||||
|
- _8 = move _9 as u32 (Transmute);
|
||||||
|
+ _8 = copy _2 as u32 (Transmute);
|
||||||
|
StorageDead(_9);
|
||||||
|
StorageLive(_10);
|
||||||
|
StorageLive(_11);
|
||||||
|
StorageLive(_12);
|
||||||
|
_12 = copy _8;
|
||||||
|
- _11 = move _12 as i32 (Transmute);
|
||||||
|
+ _11 = copy _2 as i32 (Transmute);
|
||||||
|
StorageDead(_12);
|
||||||
|
_10 = opaque::<i32>(move _11) -> [return: bb2, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_11);
|
||||||
|
StorageDead(_10);
|
||||||
|
_0 = const ();
|
||||||
|
- StorageDead(_8);
|
||||||
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
|
+ nop;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
- // MIR for `transmute_then_transmute_again` before GVN
|
||||||
|
+ // MIR for `transmute_then_transmute_again` after GVN
|
||||||
|
|
||||||
|
fn transmute_then_transmute_again(_1: u32, _2: char) -> () {
|
||||||
|
debug a => _1;
|
||||||
|
debug c => _2;
|
||||||
|
let mut _0: ();
|
||||||
|
let _3: char;
|
||||||
|
let mut _4: u32;
|
||||||
|
let _5: ();
|
||||||
|
let mut _6: i32;
|
||||||
|
let mut _7: char;
|
||||||
|
let mut _9: char;
|
||||||
|
let _10: ();
|
||||||
|
let mut _11: i32;
|
||||||
|
let mut _12: u32;
|
||||||
|
scope 1 {
|
||||||
|
debug x => _3;
|
||||||
|
let _8: u32;
|
||||||
|
scope 2 {
|
||||||
|
debug x => _8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
- StorageLive(_3);
|
||||||
|
+ nop;
|
||||||
|
StorageLive(_4);
|
||||||
|
_4 = copy _1;
|
||||||
|
- _3 = move _4 as char (Transmute);
|
||||||
|
+ _3 = copy _1 as char (Transmute);
|
||||||
|
StorageDead(_4);
|
||||||
|
StorageLive(_5);
|
||||||
|
StorageLive(_6);
|
||||||
|
StorageLive(_7);
|
||||||
|
_7 = copy _3;
|
||||||
|
- _6 = move _7 as i32 (Transmute);
|
||||||
|
+ _6 = copy _3 as i32 (Transmute);
|
||||||
|
StorageDead(_7);
|
||||||
|
_5 = opaque::<i32>(move _6) -> [return: bb1, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageDead(_6);
|
||||||
|
StorageDead(_5);
|
||||||
|
- StorageLive(_8);
|
||||||
|
+ nop;
|
||||||
|
StorageLive(_9);
|
||||||
|
_9 = copy _2;
|
||||||
|
- _8 = move _9 as u32 (Transmute);
|
||||||
|
+ _8 = copy _2 as u32 (Transmute);
|
||||||
|
StorageDead(_9);
|
||||||
|
StorageLive(_10);
|
||||||
|
StorageLive(_11);
|
||||||
|
StorageLive(_12);
|
||||||
|
_12 = copy _8;
|
||||||
|
- _11 = move _12 as i32 (Transmute);
|
||||||
|
+ _11 = copy _2 as i32 (Transmute);
|
||||||
|
StorageDead(_12);
|
||||||
|
_10 = opaque::<i32>(move _11) -> [return: bb2, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_11);
|
||||||
|
StorageDead(_10);
|
||||||
|
_0 = const ();
|
||||||
|
- StorageDead(_8);
|
||||||
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
|
+ nop;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -90,11 +90,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
|
||||||
StorageLive(_11);
|
StorageLive(_11);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
StorageLive(_5);
|
StorageLive(_4);
|
||||||
_3 = PtrMetadata(copy _1);
|
_3 = PtrMetadata(copy _1);
|
||||||
_4 = &raw const (*_1);
|
_4 = &raw const (*_1);
|
||||||
|
StorageLive(_5);
|
||||||
_5 = copy _4 as *const T (PtrToPtr);
|
_5 = copy _4 as *const T (PtrToPtr);
|
||||||
_6 = NonNull::<T> { pointer: copy _5 };
|
_6 = NonNull::<T> { pointer: move _5 };
|
||||||
|
StorageDead(_5);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
||||||
}
|
}
|
||||||
|
@ -121,7 +123,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
|
||||||
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
||||||
StorageDead(_10);
|
StorageDead(_10);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
StorageDead(_5);
|
StorageDead(_4);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize };
|
_12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize };
|
||||||
|
|
|
@ -65,11 +65,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
|
||||||
StorageLive(_11);
|
StorageLive(_11);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
StorageLive(_5);
|
StorageLive(_4);
|
||||||
_3 = PtrMetadata(copy _1);
|
_3 = PtrMetadata(copy _1);
|
||||||
_4 = &raw const (*_1);
|
_4 = &raw const (*_1);
|
||||||
|
StorageLive(_5);
|
||||||
_5 = copy _4 as *const T (PtrToPtr);
|
_5 = copy _4 as *const T (PtrToPtr);
|
||||||
_6 = NonNull::<T> { pointer: copy _5 };
|
_6 = NonNull::<T> { pointer: move _5 };
|
||||||
|
StorageDead(_5);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
||||||
}
|
}
|
||||||
|
@ -96,7 +98,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
|
||||||
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
||||||
StorageDead(_10);
|
StorageDead(_10);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
StorageDead(_5);
|
StorageDead(_4);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize };
|
_12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize };
|
||||||
|
|
|
@ -57,11 +57,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
StorageLive(_5);
|
StorageLive(_4);
|
||||||
_3 = PtrMetadata(copy _1);
|
_3 = PtrMetadata(copy _1);
|
||||||
_4 = &raw const (*_1);
|
_4 = &raw const (*_1);
|
||||||
|
StorageLive(_5);
|
||||||
_5 = copy _4 as *const T (PtrToPtr);
|
_5 = copy _4 as *const T (PtrToPtr);
|
||||||
_6 = NonNull::<T> { pointer: copy _5 };
|
_6 = NonNull::<T> { pointer: move _5 };
|
||||||
|
StorageDead(_5);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
||||||
}
|
}
|
||||||
|
@ -88,7 +90,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
|
||||||
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
||||||
StorageDead(_10);
|
StorageDead(_10);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
StorageDead(_5);
|
StorageDead(_4);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
|
|
|
@ -57,11 +57,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
StorageLive(_5);
|
StorageLive(_4);
|
||||||
_3 = PtrMetadata(copy _1);
|
_3 = PtrMetadata(copy _1);
|
||||||
_4 = &raw const (*_1);
|
_4 = &raw const (*_1);
|
||||||
|
StorageLive(_5);
|
||||||
_5 = copy _4 as *const T (PtrToPtr);
|
_5 = copy _4 as *const T (PtrToPtr);
|
||||||
_6 = NonNull::<T> { pointer: copy _5 };
|
_6 = NonNull::<T> { pointer: move _5 };
|
||||||
|
StorageDead(_5);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
||||||
}
|
}
|
||||||
|
@ -88,7 +90,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
|
||||||
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
||||||
StorageDead(_10);
|
StorageDead(_10);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
StorageDead(_5);
|
StorageDead(_4);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
|
|
|
@ -65,11 +65,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
|
||||||
StorageLive(_11);
|
StorageLive(_11);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
StorageLive(_5);
|
StorageLive(_4);
|
||||||
_3 = PtrMetadata(copy _1);
|
_3 = PtrMetadata(copy _1);
|
||||||
_4 = &raw const (*_1);
|
_4 = &raw const (*_1);
|
||||||
|
StorageLive(_5);
|
||||||
_5 = copy _4 as *const T (PtrToPtr);
|
_5 = copy _4 as *const T (PtrToPtr);
|
||||||
_6 = NonNull::<T> { pointer: copy _5 };
|
_6 = NonNull::<T> { pointer: move _5 };
|
||||||
|
StorageDead(_5);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
||||||
}
|
}
|
||||||
|
@ -96,7 +98,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
|
||||||
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
||||||
StorageDead(_10);
|
StorageDead(_10);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
StorageDead(_5);
|
StorageDead(_4);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 };
|
_12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 };
|
||||||
|
|
|
@ -65,11 +65,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
|
||||||
StorageLive(_11);
|
StorageLive(_11);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
StorageLive(_5);
|
StorageLive(_4);
|
||||||
_3 = PtrMetadata(copy _1);
|
_3 = PtrMetadata(copy _1);
|
||||||
_4 = &raw const (*_1);
|
_4 = &raw const (*_1);
|
||||||
|
StorageLive(_5);
|
||||||
_5 = copy _4 as *const T (PtrToPtr);
|
_5 = copy _4 as *const T (PtrToPtr);
|
||||||
_6 = NonNull::<T> { pointer: copy _5 };
|
_6 = NonNull::<T> { pointer: move _5 };
|
||||||
|
StorageDead(_5);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
|
||||||
}
|
}
|
||||||
|
@ -96,7 +98,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
|
||||||
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
|
||||||
StorageDead(_10);
|
StorageDead(_10);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
StorageDead(_5);
|
StorageDead(_4);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 };
|
_12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue