@@ -708,7 +708,10 @@ pub const fn swap<T>(x: &mut T, y: &mut T) {
708
708
// understanding `mem::replace`, `Option::take`, etc. - a better overall
709
709
// solution might be to make `ptr::swap_nonoverlapping` into an intrinsic, which
710
710
// 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) ) ) ]
712
715
{
713
716
// For types that are larger multiples of their alignment, the simple way
714
717
// 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) {
737
740
#[ rustc_const_unstable( feature = "const_swap" , issue = "83163" ) ]
738
741
#[ inline]
739
742
pub ( 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
+
740
756
// 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.
742
758
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) ;
746
763
}
747
764
}
748
765
0 commit comments