slice.get(i) should use a slice projection in MIR, like slice[i] does

This commit is contained in:
Scott McMurray 2025-03-29 02:34:15 -07:00
parent aa5832b142
commit 4668124cc7
15 changed files with 385 additions and 86 deletions

View file

@ -265,6 +265,7 @@ pub(crate) fn check_intrinsic_type(
vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.isize],
Ty::new_imm_ptr(tcx, param(0)),
),
sym::slice_get_unchecked => (3, 0, vec![param(1), tcx.types.usize], param(0)),
sym::ptr_mask => (
1,
0,

View file

@ -262,6 +262,52 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
});
terminator.kind = TerminatorKind::Goto { target };
}
sym::slice_get_unchecked => {
let target = target.unwrap();
let Ok([ptrish, index]) = take_array(args) else {
span_bug!(
terminator.source_info.span,
"Wrong number of arguments for {intrinsic:?}",
);
};
let place = ptrish.node.place().unwrap();
assert!(!place.is_indirect());
let updated_place = place.project_deeper(
&[
ProjectionElem::Deref,
ProjectionElem::Index(
index.node.place().unwrap().as_local().unwrap(),
),
],
tcx,
);
let ret_ty = generic_args.type_at(0);
let rvalue = match *ret_ty.kind() {
ty::RawPtr(_, Mutability::Not) => {
Rvalue::RawPtr(RawPtrKind::Const, updated_place)
}
ty::RawPtr(_, Mutability::Mut) => {
Rvalue::RawPtr(RawPtrKind::Mut, updated_place)
}
ty::Ref(region, _, Mutability::Not) => {
Rvalue::Ref(region, BorrowKind::Shared, updated_place)
}
ty::Ref(region, _, Mutability::Mut) => Rvalue::Ref(
region,
BorrowKind::Mut { kind: MutBorrowKind::Default },
updated_place,
),
_ => bug!("Unknown return type {ret_ty:?}"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((*destination, rvalue))),
});
terminator.kind = TerminatorKind::Goto { target };
}
sym::transmute | sym::transmute_unchecked => {
let dst_ty = destination.ty(local_decls, tcx).ty;
let Ok([arg]) = take_array(args) else {

View file

@ -2000,6 +2000,7 @@ symbols! {
slice,
slice_from_raw_parts,
slice_from_raw_parts_mut,
slice_get_unchecked,
slice_into_vec,
slice_iter,
slice_len_fn,

View file

@ -0,0 +1,39 @@
//! Various traits used to restrict intrinsics to not-completely-wrong types.
/// Types with a built-in dereference operator in runtime MIR,
/// aka references and raw pointers.
///
/// # Safety
/// Must actually *be* such a type.
pub unsafe trait BuiltinDeref: Sized {
type Pointee: ?Sized;
}
unsafe impl<T: ?Sized> BuiltinDeref for &mut T {
type Pointee = T;
}
unsafe impl<T: ?Sized> BuiltinDeref for &T {
type Pointee = T;
}
unsafe impl<T: ?Sized> BuiltinDeref for *mut T {
type Pointee = T;
}
unsafe impl<T: ?Sized> BuiltinDeref for *const T {
type Pointee = T;
}
pub trait ChangePointee<U: ?Sized>: BuiltinDeref {
type Output;
}
impl<'a, T: ?Sized + 'a, U: ?Sized + 'a> ChangePointee<U> for &'a mut T {
type Output = &'a mut U;
}
impl<'a, T: ?Sized + 'a, U: ?Sized + 'a> ChangePointee<U> for &'a T {
type Output = &'a U;
}
impl<T: ?Sized, U: ?Sized> ChangePointee<U> for *mut T {
type Output = *mut U;
}
impl<T: ?Sized, U: ?Sized> ChangePointee<U> for *const T {
type Output = *const U;
}

View file

@ -53,6 +53,7 @@
use crate::marker::{ConstParamTy, DiscriminantKind, Tuple};
use crate::ptr;
mod bounds;
pub mod fallback;
pub mod mir;
pub mod simd;
@ -1730,7 +1731,7 @@ pub const fn needs_drop<T: ?Sized>() -> bool;
#[rustc_intrinsic_const_stable_indirect]
#[rustc_nounwind]
#[rustc_intrinsic]
pub const unsafe fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
pub const unsafe fn offset<Ptr: bounds::BuiltinDeref, Delta>(dst: Ptr, offset: Delta) -> Ptr;
/// Calculates the offset from a pointer, potentially wrapping.
///
@ -1751,6 +1752,33 @@ pub const unsafe fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
#[rustc_intrinsic]
pub const unsafe fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
/// Projects to the `index`-th element of `slice_ptr`, as the same kind of pointer
/// as the slice was provided -- so `&mut [T] → &mut T`, `&[T] → &T`,
/// `*mut [T] → *mut T`, or `*const [T] → *const T` -- without a bounds check.
///
/// This is exposed via `<usize as SliceIndex>::get(_unchecked)(_mut)`,
/// and isn't intended to be used elsewhere.
///
/// Expands in MIR to `{&, &mut, &raw const, &raw mut} (*slice_ptr)[index]`,
/// depending on the types involved, so no backend support is needed.
///
/// # Safety
///
/// - `index < PtrMetadata(slice_ptr)`, so the indexing is in-bounds for the slice
/// - the resulting offsetting is in-bounds of the allocated object, which is
/// always the case for references, but needs to be upheld manually for pointers
#[cfg(not(bootstrap))]
#[rustc_nounwind]
#[rustc_intrinsic]
pub const unsafe fn slice_get_unchecked<
ItemPtr: bounds::ChangePointee<[T], Pointee = T, Output = SlicePtr>,
SlicePtr,
T,
>(
slice_ptr: SlicePtr,
index: usize,
) -> ItemPtr;
/// Masks out bits of the pointer according to a mask.
///
/// Note that, unlike most intrinsics, this is safe to call;
@ -3575,18 +3603,9 @@ pub const fn type_id<T: ?Sized + 'static>() -> u128;
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic_const_stable_indirect]
#[rustc_intrinsic]
pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(data: D, meta: M) -> P;
#[unstable(feature = "core_intrinsics", issue = "none")]
pub trait AggregateRawPtr<D> {
type Metadata: Copy;
}
impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*const T> for *const P {
type Metadata = <P as ptr::Pointee>::Metadata;
}
impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
type Metadata = <P as ptr::Pointee>::Metadata;
}
pub const fn aggregate_raw_ptr<P: bounds::BuiltinDeref, D, M>(data: D, meta: M) -> P
where
<P as bounds::BuiltinDeref>::Pointee: ptr::Pointee<Metadata = M>;
/// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`.
///

View file

@ -1,5 +1,7 @@
//! Indexing implementations for `[T]`.
#[cfg(not(bootstrap))]
use crate::intrinsics::slice_get_unchecked;
use crate::panic::const_panic;
use crate::ub_checks::assert_unsafe_precondition;
use crate::{ops, range};
@ -83,6 +85,7 @@ const fn slice_end_index_overflow_fail() -> ! {
// Both the safe and unsafe public methods share these helpers,
// which use intrinsics directly to get *no* extra checks.
#[cfg(bootstrap)]
#[inline(always)]
const unsafe fn get_noubcheck<T>(ptr: *const [T], index: usize) -> *const T {
let ptr = ptr as *const T;
@ -90,6 +93,7 @@ const unsafe fn get_noubcheck<T>(ptr: *const [T], index: usize) -> *const T {
unsafe { crate::intrinsics::offset(ptr, index) }
}
#[cfg(bootstrap)]
#[inline(always)]
const unsafe fn get_mut_noubcheck<T>(ptr: *mut [T], index: usize) -> *mut T {
let ptr = ptr as *mut T;
@ -103,8 +107,9 @@ const unsafe fn get_offset_len_noubcheck<T>(
offset: usize,
len: usize,
) -> *const [T] {
let ptr = ptr as *const T;
// SAFETY: The caller already checked these preconditions
let ptr = unsafe { get_noubcheck(ptr, offset) };
let ptr = unsafe { crate::intrinsics::offset(ptr, offset) };
crate::intrinsics::aggregate_raw_ptr(ptr, len)
}
@ -114,8 +119,9 @@ const unsafe fn get_offset_len_mut_noubcheck<T>(
offset: usize,
len: usize,
) -> *mut [T] {
let ptr = ptr as *mut T;
// SAFETY: The caller already checked these preconditions
let ptr = unsafe { get_mut_noubcheck(ptr, offset) };
let ptr = unsafe { crate::intrinsics::offset(ptr, offset) };
crate::intrinsics::aggregate_raw_ptr(ptr, len)
}
@ -224,15 +230,35 @@ unsafe impl<T> SliceIndex<[T]> for usize {
#[inline]
fn get(self, slice: &[T]) -> Option<&T> {
// SAFETY: `self` is checked to be in bounds.
if self < slice.len() { unsafe { Some(&*get_noubcheck(slice, self)) } } else { None }
if self < slice.len() {
#[cfg(bootstrap)]
// SAFETY: `self` is checked to be in bounds.
unsafe {
Some(&*get_noubcheck(slice, self))
}
#[cfg(not(bootstrap))]
// SAFETY: `self` is checked to be in bounds.
unsafe {
Some(slice_get_unchecked(slice, self))
}
} else {
None
}
}
#[inline]
fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
if self < slice.len() {
#[cfg(bootstrap)]
// SAFETY: `self` is checked to be in bounds.
unsafe { Some(&mut *get_mut_noubcheck(slice, self)) }
unsafe {
Some(&mut *get_mut_noubcheck(slice, self))
}
#[cfg(not(bootstrap))]
// SAFETY: `self` is checked to be in bounds.
unsafe {
Some(slice_get_unchecked(slice, self))
}
} else {
None
}
@ -254,7 +280,14 @@ unsafe impl<T> SliceIndex<[T]> for usize {
// Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the
// precondition of this function twice.
crate::intrinsics::assume(self < slice.len());
get_noubcheck(slice, self)
#[cfg(bootstrap)]
{
get_noubcheck(slice, self)
}
#[cfg(not(bootstrap))]
{
slice_get_unchecked(slice, self)
}
}
}
@ -267,7 +300,16 @@ unsafe impl<T> SliceIndex<[T]> for usize {
(this: usize = self, len: usize = slice.len()) => this < len
);
// SAFETY: see comments for `get_unchecked` above.
unsafe { get_mut_noubcheck(slice, self) }
unsafe {
#[cfg(bootstrap)]
{
get_mut_noubcheck(slice, self)
}
#[cfg(not(bootstrap))]
{
slice_get_unchecked(slice, self)
}
}
}
#[inline]

View file

@ -263,3 +263,24 @@ pub fn get_metadata(a: *const i32, b: *const [u8], c: *const dyn std::fmt::Debug
let _usize = ptr_metadata(b);
let _vtable = ptr_metadata(c);
}
// EMIT_MIR lower_intrinsics.slice_get.LowerIntrinsics.diff
pub unsafe fn slice_get<'a, 'b>(
r: &'a [i8],
rm: &'b mut [i16],
p: *const [i32],
pm: *mut [i64],
i: usize,
) -> (&'a i8, &'b mut i16, *const i32, *mut i64) {
use std::intrinsics::slice_get_unchecked;
// CHECK: = &(*_{{[0-9]+}})[_{{[0-9]+}}]
// CHECK: = &mut (*_{{[0-9]+}})[_{{[0-9]+}}]
// CHECK: = &raw const (*_{{[0-9]+}})[_{{[0-9]+}}]
// CHECK: = &raw mut (*_{{[0-9]+}})[_{{[0-9]+}}]
(
slice_get_unchecked(r, i),
slice_get_unchecked(rm, i),
slice_get_unchecked(p, i),
slice_get_unchecked(pm, i),
)
}

View file

@ -0,0 +1,85 @@
- // MIR for `slice_get` before LowerIntrinsics
+ // MIR for `slice_get` after LowerIntrinsics
fn slice_get(_1: &[i8], _2: &mut [i16], _3: *const [i32], _4: *mut [i64], _5: usize) -> (&i8, &mut i16, *const i32, *mut i64) {
debug r => _1;
debug rm => _2;
debug p => _3;
debug pm => _4;
debug i => _5;
let mut _0: (&i8, &mut i16, *const i32, *mut i64);
let mut _6: &i8;
let mut _7: &[i8];
let mut _8: usize;
let mut _9: &mut i16;
let mut _10: &mut [i16];
let mut _11: usize;
let mut _12: *const i32;
let mut _13: *const [i32];
let mut _14: usize;
let mut _15: *mut i64;
let mut _16: *mut [i64];
let mut _17: usize;
bb0: {
StorageLive(_6);
StorageLive(_7);
_7 = copy _1;
StorageLive(_8);
_8 = copy _5;
- _6 = slice_get_unchecked::<&i8, &[i8], i8>(move _7, move _8) -> [return: bb1, unwind unreachable];
+ _6 = &(*_7)[_8];
+ goto -> bb1;
}
bb1: {
StorageDead(_8);
StorageDead(_7);
StorageLive(_9);
StorageLive(_10);
_10 = move _2;
StorageLive(_11);
_11 = copy _5;
- _9 = slice_get_unchecked::<&mut i16, &mut [i16], i16>(move _10, move _11) -> [return: bb2, unwind unreachable];
+ _9 = &mut (*_10)[_11];
+ goto -> bb2;
}
bb2: {
StorageDead(_11);
StorageDead(_10);
StorageLive(_12);
StorageLive(_13);
_13 = copy _3;
StorageLive(_14);
_14 = copy _5;
- _12 = slice_get_unchecked::<*const i32, *const [i32], i32>(move _13, move _14) -> [return: bb3, unwind unreachable];
+ _12 = &raw const (*_13)[_14];
+ goto -> bb3;
}
bb3: {
StorageDead(_14);
StorageDead(_13);
StorageLive(_15);
StorageLive(_16);
_16 = copy _4;
StorageLive(_17);
_17 = copy _5;
- _15 = slice_get_unchecked::<*mut i64, *mut [i64], i64>(move _16, move _17) -> [return: bb4, unwind unreachable];
+ _15 = &raw mut (*_16)[_17];
+ goto -> bb4;
}
bb4: {
StorageDead(_17);
StorageDead(_16);
_0 = (move _6, move _9, move _12, move _15);
StorageDead(_15);
StorageDead(_12);
StorageDead(_9);
StorageDead(_6);
return;
}
}

View file

@ -0,0 +1,85 @@
- // MIR for `slice_get` before LowerIntrinsics
+ // MIR for `slice_get` after LowerIntrinsics
fn slice_get(_1: &[i8], _2: &mut [i16], _3: *const [i32], _4: *mut [i64], _5: usize) -> (&i8, &mut i16, *const i32, *mut i64) {
debug r => _1;
debug rm => _2;
debug p => _3;
debug pm => _4;
debug i => _5;
let mut _0: (&i8, &mut i16, *const i32, *mut i64);
let mut _6: &i8;
let mut _7: &[i8];
let mut _8: usize;
let mut _9: &mut i16;
let mut _10: &mut [i16];
let mut _11: usize;
let mut _12: *const i32;
let mut _13: *const [i32];
let mut _14: usize;
let mut _15: *mut i64;
let mut _16: *mut [i64];
let mut _17: usize;
bb0: {
StorageLive(_6);
StorageLive(_7);
_7 = copy _1;
StorageLive(_8);
_8 = copy _5;
- _6 = slice_get_unchecked::<&i8, &[i8], i8>(move _7, move _8) -> [return: bb1, unwind unreachable];
+ _6 = &(*_7)[_8];
+ goto -> bb1;
}
bb1: {
StorageDead(_8);
StorageDead(_7);
StorageLive(_9);
StorageLive(_10);
_10 = move _2;
StorageLive(_11);
_11 = copy _5;
- _9 = slice_get_unchecked::<&mut i16, &mut [i16], i16>(move _10, move _11) -> [return: bb2, unwind unreachable];
+ _9 = &mut (*_10)[_11];
+ goto -> bb2;
}
bb2: {
StorageDead(_11);
StorageDead(_10);
StorageLive(_12);
StorageLive(_13);
_13 = copy _3;
StorageLive(_14);
_14 = copy _5;
- _12 = slice_get_unchecked::<*const i32, *const [i32], i32>(move _13, move _14) -> [return: bb3, unwind unreachable];
+ _12 = &raw const (*_13)[_14];
+ goto -> bb3;
}
bb3: {
StorageDead(_14);
StorageDead(_13);
StorageLive(_15);
StorageLive(_16);
_16 = copy _4;
StorageLive(_17);
_17 = copy _5;
- _15 = slice_get_unchecked::<*mut i64, *mut [i64], i64>(move _16, move _17) -> [return: bb4, unwind unreachable];
+ _15 = &raw mut (*_16)[_17];
+ goto -> bb4;
}
bb4: {
StorageDead(_17);
StorageDead(_16);
_0 = (move _6, move _9, move _12, move _15);
StorageDead(_15);
StorageDead(_12);
StorageDead(_9);
StorageDead(_6);
return;
}
}

View file

@ -8,19 +8,11 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
scope 2 (inlined <usize as SliceIndex<[u32]>>::get_mut) {
let mut _3: usize;
let mut _4: bool;
let mut _5: *mut [u32];
let mut _7: *mut u32;
let mut _8: &mut u32;
scope 3 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
let _6: *mut u32;
scope 4 {
}
}
let mut _5: &mut u32;
}
}
bb0: {
StorageLive(_8);
StorageLive(_4);
StorageLive(_3);
_3 = PtrMetadata(copy _1);
@ -36,23 +28,15 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
bb2: {
StorageDead(_3);
StorageLive(_7);
StorageLive(_5);
_5 = &raw mut (*_1);
StorageLive(_6);
_6 = copy _5 as *mut u32 (PtrToPtr);
_7 = Offset(copy _6, copy _2);
StorageDead(_6);
_5 = &mut (*_1)[_2];
_0 = Option::<&mut u32>::Some(move _5);
StorageDead(_5);
_8 = &mut (*_7);
_0 = Option::<&mut u32>::Some(copy _8);
StorageDead(_7);
goto -> bb3;
}
bb3: {
StorageDead(_4);
StorageDead(_8);
return;
}
}

View file

@ -8,19 +8,11 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
scope 2 (inlined <usize as SliceIndex<[u32]>>::get_mut) {
let mut _3: usize;
let mut _4: bool;
let mut _5: *mut [u32];
let mut _7: *mut u32;
let mut _8: &mut u32;
scope 3 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
let _6: *mut u32;
scope 4 {
}
}
let mut _5: &mut u32;
}
}
bb0: {
StorageLive(_8);
StorageLive(_4);
StorageLive(_3);
_3 = PtrMetadata(copy _1);
@ -36,23 +28,15 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
bb2: {
StorageDead(_3);
StorageLive(_7);
StorageLive(_5);
_5 = &raw mut (*_1);
StorageLive(_6);
_6 = copy _5 as *mut u32 (PtrToPtr);
_7 = Offset(copy _6, copy _2);
StorageDead(_6);
_5 = &mut (*_1)[_2];
_0 = Option::<&mut u32>::Some(move _5);
StorageDead(_5);
_8 = &mut (*_7);
_0 = Option::<&mut u32>::Some(copy _8);
StorageDead(_7);
goto -> bb3;
}
bb3: {
StorageDead(_4);
StorageDead(_8);
return;
}
}

View file

@ -15,12 +15,10 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
let _8: usize;
scope 3 {
scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
let _10: *mut u32;
let _9: *mut u32;
scope 7 {
}
scope 8 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
let _9: *mut u32;
scope 9 {
let _10: *mut u32;
scope 8 {
}
}
}
@ -47,13 +45,13 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
bb1: {
StorageDead(_6);
_8 = SubUnchecked(copy _4, copy _3);
StorageLive(_10);
StorageLive(_9);
StorageLive(_10);
_9 = copy _5 as *mut u32 (PtrToPtr);
_10 = Offset(copy _9, copy _3);
StorageDead(_9);
_11 = *mut [u32] from (copy _10, copy _8);
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_5);
_0 = &mut (*_11);

View file

@ -15,12 +15,10 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
let _8: usize;
scope 3 {
scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) {
let _10: *mut u32;
let _9: *mut u32;
scope 7 {
}
scope 8 (inlined core::slice::index::get_mut_noubcheck::<u32>) {
let _9: *mut u32;
scope 9 {
let _10: *mut u32;
scope 8 {
}
}
}
@ -47,13 +45,13 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
bb1: {
StorageDead(_6);
_8 = SubUnchecked(copy _4, copy _3);
StorageLive(_10);
StorageLive(_9);
StorageLive(_10);
_9 = copy _5 as *mut u32 (PtrToPtr);
_10 = Offset(copy _9, copy _3);
StorageDead(_9);
_11 = *mut [u32] from (copy _10, copy _8);
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
StorageDead(_5);
_0 = &mut (*_11);

View file

@ -13,12 +13,10 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
let _7: usize;
scope 3 {
scope 6 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
let _9: *const u32;
let _8: *const u32;
scope 7 {
}
scope 8 (inlined core::slice::index::get_noubcheck::<u32>) {
let _8: *const u32;
scope 9 {
let _9: *const u32;
scope 8 {
}
}
}
@ -42,13 +40,13 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
bb1: {
StorageDead(_5);
_7 = SubUnchecked(copy _4, copy _3);
StorageLive(_9);
StorageLive(_8);
StorageLive(_9);
_8 = copy _1 as *const u32 (PtrToPtr);
_9 = Offset(copy _8, copy _3);
StorageDead(_8);
_0 = *const [u32] from (copy _9, copy _7);
StorageDead(_9);
StorageDead(_8);
StorageDead(_7);
return;
}

View file

@ -13,12 +13,10 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
let _7: usize;
scope 3 {
scope 6 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) {
let _9: *const u32;
let _8: *const u32;
scope 7 {
}
scope 8 (inlined core::slice::index::get_noubcheck::<u32>) {
let _8: *const u32;
scope 9 {
let _9: *const u32;
scope 8 {
}
}
}
@ -42,13 +40,13 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
bb1: {
StorageDead(_5);
_7 = SubUnchecked(copy _4, copy _3);
StorageLive(_9);
StorageLive(_8);
StorageLive(_9);
_8 = copy _1 as *const u32 (PtrToPtr);
_9 = Offset(copy _8, copy _3);
StorageDead(_8);
_0 = *const [u32] from (copy _9, copy _7);
StorageDead(_9);
StorageDead(_8);
StorageDead(_7);
return;
}