@@ -708,7 +708,10 @@ pub const fn swap<T>(x: &mut T, y: &mut T) {
708708 // understanding `mem::replace`, `Option::take`, etc. - a better overall
709709 // solution might be to make `ptr::swap_nonoverlapping` into an intrinsic, which
710710 // a backend can choose to implement using the block optimization, or not.
711- #[ cfg( not( target_arch = "spirv" ) ) ]
711+ // NOTE(scottmcm) MIRI is disabled here as reading in smaller units is a
712+ // pessimization for it. Also, if the type contains any unaligned pointers,
713+ // copying those over multiple reads is difficult to support.
714+ #[ cfg( not( any( target_arch = "spirv" , miri) ) ) ]
712715 {
713716 // For types that are larger multiples of their alignment, the simple way
714717 // tends to copy the whole thing to stack rather than doing it one part
@@ -737,12 +740,26 @@ pub const fn swap<T>(x: &mut T, y: &mut T) {
737740#[ rustc_const_unstable( feature = "const_swap" , issue = "83163" ) ]
738741#[ inline]
739742pub ( crate ) const fn swap_simple < T > ( x : & mut T , y : & mut T ) {
743+ // We arrange for this to typically be called with small types,
744+ // so this reads-and-writes approach is actually better than using
745+ // copy_nonoverlapping as it easily puts things in LLVM registers
746+ // directly and doesn't end up inlining allocas.
747+ // And LLVM actually optimizes it to 3×memcpy if called with
748+ // a type larger than it's willing to keep in a register.
749+ // Having typed reads and writes in MIR here is also good as
750+ // it lets MIRI and CTFE understand them better, including things
751+ // like enforcing type validity for them.
752+ // Importantly, read+copy_nonoverlapping+write introduces confusing
753+ // asymmetry to the behaviour where one value went through read+write
754+ // whereas the other was copied over by the intrinsic (see #94371).
755+
740756 // SAFETY: exclusive references are always valid to read/write,
741- // are non-overlapping , and nothing here panics so it's drop-safe.
757+ // including being aligned , and nothing here panics so it's drop-safe.
742758 unsafe {
743- let z = ptr:: read ( x) ;
744- ptr:: copy_nonoverlapping ( y, x, 1 ) ;
745- ptr:: write ( y, z) ;
759+ let a = ptr:: read ( x) ;
760+ let b = ptr:: read ( y) ;
761+ ptr:: write ( x, b) ;
762+ ptr:: write ( y, a) ;
746763 }
747764}
748765
0 commit comments