Skip to content

Commit 698c6d9

Browse files
committed
Let codegen decide when to mem::swap with immediates
Making `libcore` decide this is silly; the backend has so much better information about when it's a good idea. So introduce a new `typed_swap` intrinsic with a fallback body, but replace that implementation for immediates and scalar pairs.
1 parent d1f5e67 commit 698c6d9

File tree

3 files changed

+26
-25
lines changed

3 files changed

+26
-25
lines changed

core/src/intrinsics.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
use crate::marker::DiscriminantKind;
6767
use crate::marker::Tuple;
6868
use crate::mem::align_of;
69+
use crate::ptr;
6970

7071
pub mod mir;
7172
pub mod simd;
@@ -2628,6 +2629,27 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
26282629
false
26292630
}
26302631

2632+
/// Non-overlapping *typed* swap of a single value.
2633+
///
2634+
/// The codegen backends will replace this with a better implementation when
2635+
/// `T` is a simple type that can be loaded and stored as an immediate.
2636+
///
2637+
/// The stabilized form of this intrinsic is [`crate::mem::swap`].
2638+
///
2639+
/// # Safety
2640+
///
2641+
/// `x` and `y` are readable and writable as `T`, and non-overlapping.
2642+
#[rustc_nounwind]
2643+
#[inline]
2644+
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
2645+
// This has fallback `const fn` MIR, so shouldn't need stability, see #122652
2646+
#[rustc_const_unstable(feature = "const_typed_swap", issue = "none")]
2647+
pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
2648+
// SAFETY: The caller provided single non-overlapping items behind
2649+
// pointers, so swapping them with `count: 1` is fine.
2650+
unsafe { ptr::swap_nonoverlapping(x, y, 1) };
2651+
}
2652+
26312653
/// Returns whether we should check for library UB. This evaluate to the value of `cfg!(debug_assertions)`
26322654
/// during monomorphization.
26332655
///

core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@
168168
#![feature(const_try)]
169169
#![feature(const_type_id)]
170170
#![feature(const_type_name)]
171+
#![feature(const_typed_swap)]
171172
#![feature(const_unicode_case_lookup)]
172173
#![feature(const_unsafecell_get_mut)]
173174
#![feature(const_waker)]

core/src/mem/mod.rs

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -726,31 +726,9 @@ pub unsafe fn uninitialized<T>() -> T {
726726
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
727727
#[rustc_diagnostic_item = "mem_swap"]
728728
pub const fn swap<T>(x: &mut T, y: &mut T) {
729-
// NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
730-
// reinterpretation of values as (chunkable) byte arrays, and the loop in the
731-
// block optimization in `swap_slice` is hard to rewrite back
732-
// into the (unoptimized) direct swapping implementation, so we disable it.
733-
#[cfg(not(any(target_arch = "spirv")))]
734-
{
735-
// For types that are larger multiples of their alignment, the simple way
736-
// tends to copy the whole thing to stack rather than doing it one part
737-
// at a time, so instead treat them as one-element slices and piggy-back
738-
// the slice optimizations that will split up the swaps.
739-
if const { size_of::<T>() / align_of::<T>() > 2 } {
740-
// SAFETY: exclusive references always point to one non-overlapping
741-
// element and are non-null and properly aligned.
742-
return unsafe { ptr::swap_nonoverlapping(x, y, 1) };
743-
}
744-
}
745-
746-
// If a scalar consists of just a small number of alignment units, let
747-
// the codegen just swap those pieces directly, as it's likely just a
748-
// few instructions and anything else is probably overcomplicated.
749-
//
750-
// Most importantly, this covers primitives and simd types that tend to
751-
// have size=align where doing anything else can be a pessimization.
752-
// (This will also be used for ZSTs, though any solution works for them.)
753-
swap_simple(x, y);
729+
// SAFETY: `&mut` guarantees these are typed readable and writable
730+
// as well as non-overlapping.
731+
unsafe { intrinsics::typed_swap(x, y) }
754732
}
755733

756734
/// Same as [`swap`] semantically, but always uses the simple implementation.

0 commit comments

Comments
 (0)