@@ -726,63 +726,9 @@ pub unsafe fn uninitialized<T>() -> T {
726
726
#[ rustc_const_unstable( feature = "const_swap" , issue = "83163" ) ]
727
727
#[ rustc_diagnostic_item = "mem_swap" ]
728
728
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) ;
754
- }
755
-
756
- /// Same as [`swap`] semantically, but always uses the simple implementation.
757
- ///
758
- /// Used elsewhere in `mem` and `ptr` at the bottom layer of calls.
759
- #[ rustc_const_unstable( feature = "const_swap" , issue = "83163" ) ]
760
- #[ inline]
761
- pub ( crate ) const fn swap_simple < T > ( x : & mut T , y : & mut T ) {
762
- // We arrange for this to typically be called with small types,
763
- // so this reads-and-writes approach is actually better than using
764
- // copy_nonoverlapping as it easily puts things in LLVM registers
765
- // directly and doesn't end up inlining allocas.
766
- // And LLVM actually optimizes it to 3×memcpy if called with
767
- // a type larger than it's willing to keep in a register.
768
- // Having typed reads and writes in MIR here is also good as
769
- // it lets Miri and CTFE understand them better, including things
770
- // like enforcing type validity for them.
771
- // Importantly, read+copy_nonoverlapping+write introduces confusing
772
- // asymmetry to the behaviour where one value went through read+write
773
- // whereas the other was copied over by the intrinsic (see #94371).
774
- // Furthermore, using only read+write here benefits limited backends
775
- // such as SPIR-V that work on an underlying *typed* view of memory,
776
- // and thus have trouble with Rust's untyped memory operations.
777
-
778
- // SAFETY: exclusive references are always valid to read/write,
779
- // including being aligned, and nothing here panics so it's drop-safe.
780
- unsafe {
781
- let a = ptr:: read ( x) ;
782
- let b = ptr:: read ( y) ;
783
- ptr:: write ( x, b) ;
784
- ptr:: write ( y, a) ;
785
- }
729
+ // SAFETY: `&mut` guarantees these are typed readable and writable
730
+ // as well as non-overlapping.
731
+ unsafe { intrinsics:: typed_swap ( x, y) }
786
732
}
787
733
788
734
/// Replaces `dest` with the default value of `T`, returning the previous `dest` value.
0 commit comments