From 92db4533318a1745fdb1d6dfc5c91cd9ad1bbc3b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 19 Jul 2017 20:27:49 -0700 Subject: [PATCH] For small types, just swap directly Don't ptr::swap_nonoverlapping for things smaller than its block size. That simpler for LLVM -- particularly in debug -- and means the load/store instructions are generated with full alignment information. --- src/libcore/mem.rs | 15 +++++++++++++-- src/libcore/tests/mem.rs | 7 +++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 86e5afa4c337f..3121cc2724bac 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -548,8 +548,19 @@ pub unsafe fn uninitialized() -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { - unsafe { - ptr::swap_nonoverlapping(x, y, 1); + if size_of::() < 32 { + // For small types, just swap directly. + // This keeps alignment and lets debug not run the big loop. + unsafe { + let temp = ptr::read(x); + ptr::copy_nonoverlapping(y, x, 1); + ptr::write(y, temp); + } + } else { + // For large types, use the simd swapping code. + unsafe { + ptr::swap_nonoverlapping(x, y, 1); + } } } diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs index 86e59c736ba4a..adf0ebb35f24b 100644 --- a/src/libcore/tests/mem.rs +++ b/src/libcore/tests/mem.rs @@ -89,6 +89,13 @@ fn test_swap() { swap(&mut x, &mut y); assert_eq!(x, 42); assert_eq!(y, 31337); + + // A bigger one to hit the SIMD loop + let mut x = [1u64, 2, 3, 4, 5, 6, 7, 8]; + let mut y = [11, 12, 13, 14, 15, 16, 17, 18]; + swap(&mut x, &mut y); + assert_eq!(x, [11, 12, 13, 14, 15, 16, 17, 18]); + assert_eq!(y, [1, 2, 3, 4, 5, 6, 7, 8]); } #[test]