From 528ffa985ae85daff33821721f27ca2cfaa253c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Jedelsk=C3=BD?= <hjajet@gmail.com>
Date: Thu, 5 Oct 2017 14:19:25 +0200
Subject: [PATCH] Deduplicate memcpy, memmove, memset and memcmp functions

---
 src/externs.rs | 203 +++++++++----------------------------------------
 src/lib.rs     |   1 +
 2 files changed, 36 insertions(+), 168 deletions(-)

diff --git a/src/externs.rs b/src/externs.rs
index 42fb3e63..03bc34cd 100644
--- a/src/externs.rs
+++ b/src/externs.rs
@@ -1,45 +1,25 @@
+use core::mem;
+
+const WORD_SIZE: usize = mem::size_of::<usize>();
+
 /// Memcpy
 ///
 /// Copy N bytes of memory from one location to another.
 ///
 /// This faster implementation works by copying bytes not one-by-one, but in
 /// groups of 8 bytes (or 4 bytes in the case of 32-bit architectures).
-#[cfg(target_pointer_width = "64")]
 #[no_mangle]
 pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
                             n: usize) -> *mut u8 {
-    let n_64: usize = n/8; // Number of 64-bit groups
-    let mut i: usize = 0;
-
-    // Copy 8 bytes at a time
-    while i < n_64 {
-        *((dest as usize + i) as *mut u64) =
-            *((src as usize + i) as *const u64);
-        i += 8;
-    }
-
-    // Copy 1 byte at a time
-    while i < n {
-        *((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8);
-        i += 1;
-    }
-
-    dest
-}
 
-// 32-bit version of the function above
-#[cfg(target_pointer_width = "32")]
-#[no_mangle]
-pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
-                            n: usize) -> *mut u8 {
-    let n_32: usize = n/4; // Number of 32-bit groups
+    let n_usize: usize = n/WORD_SIZE; // Number of word sized groups
     let mut i: usize = 0;
 
-    // Copy 4 bytes at a time
-    while i < n_32 {
-        *((dest as usize + i) as *mut u32) =
-            *((src as usize + i) as *const u32);
-        i += 4;
+    // Copy `WORD_SIZE` bytes at a time
+    while i < n_usize {
+        *((dest as usize + i) as *mut usize) =
+            *((src as usize + i) as *const usize);
+        i += WORD_SIZE;
     }
 
     // Copy 1 byte at a time
@@ -57,84 +37,37 @@ pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
 ///
 /// This faster implementation works by copying bytes not one-by-one, but in
 /// groups of 8 bytes (or 4 bytes in the case of 32-bit architectures).
-#[cfg(target_pointer_width = "64")]
-#[no_mangle]
-pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
-                             n: usize) -> *mut u8 {
-    if src < dest as *const u8 {
-        let n_64: usize = n/8; // Number of 64-bit groups
-        let mut i: usize = n_64*8;
-
-        // Copy 8 bytes at a time
-        while i != 0 {
-            i -= 8;
-            *((dest as usize + i) as *mut u64) =
-                *((src as usize + i) as *const u64);
-        }
-
-        let mut i: usize = n;
-
-        // Copy 1 byte at a time
-        while i != n_64*8 {
-            i -= 1;
-            *((dest as usize + i) as *mut u8) =
-                *((src as usize + i) as *const u8);
-        }
-    } else {
-        let n_64: usize = n/8; // Number of 64-bit groups
-        let mut i: usize = 0;
-
-        // Copy 8 bytes at a time
-        while i < n_64 {
-            *((dest as usize + i) as *mut u64) =
-                *((src as usize + i) as *const u64);
-            i += 8;
-        }
-
-        // Copy 1 byte at a time
-        while i < n {
-            *((dest as usize + i) as *mut u8) =
-                *((src as usize + i) as *const u8);
-            i += 1;
-        }
-    }
-
-    dest
-}
-
-// 32-bit version of the function above
-#[cfg(target_pointer_width = "32")]
 #[no_mangle]
 pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
                              n: usize) -> *mut u8 {
     if src < dest as *const u8 {
-        let n_32: usize = n/4; // Number of 32-bit groups
-        let mut i: usize = n_32*4;
+        let n_usize: usize = n/WORD_SIZE; // Number of word sized groups
+        let mut i: usize = n_usize*WORD_SIZE;
 
-        // Copy 4 bytes at a time
+        // Copy `WORD_SIZE` bytes at a time
         while i != 0 {
-            i -= 4;
-            *((dest as usize + i) as *mut u32) =
-                *((src as usize + i) as *const u32);
+            i -= WORD_SIZE;
+            *((dest as usize + i) as *mut usize) =
+                *((src as usize + i) as *const usize);
         }
 
         let mut i: usize = n;
 
         // Copy 1 byte at a time
-        while i != n_32*4 {
+        while i != n_usize*WORD_SIZE {
             i -= 1;
             *((dest as usize + i) as *mut u8) =
                 *((src as usize + i) as *const u8);
         }
     } else {
-        let n_32: usize = n/4; // Number of 32-bit groups
+        let n_usize: usize = n/WORD_SIZE; // Number of 64-bit groups
         let mut i: usize = 0;
 
-        // Copy 4 bytes at a time
-        while i < n_32 {
-            *((dest as usize + i) as *mut u32) =
-                *((src as usize + i) as *const u32);
-            i += 4;
+        // Copy `WORD_SIZE` bytes at a time
+        while i < n_usize {
+            *((dest as usize + i) as *mut usize) =
+                *((src as usize + i) as *const usize);
+            i += WORD_SIZE;
         }
 
         // Copy 1 byte at a time
@@ -154,45 +87,16 @@ pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
 ///
 /// This faster implementation works by setting bytes not one-by-one, but in
 /// groups of 8 bytes (or 4 bytes in the case of 32-bit architectures).
-#[cfg(target_pointer_width = "64")]
-#[no_mangle]
-pub unsafe extern fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 {
-    let c = c as u64;
-    let c = (c << 56) | (c << 48) | (c << 40) | (c << 32)
-          | (c << 24) | (c << 16) | (c << 8)  | c;
-    let n_64: usize = n/8;
-    let mut i: usize = 0;
-
-    // Set 8 bytes at a time
-    while i < n_64 {
-        *((dest as usize + i) as *mut u64) = c;
-        i += 8;
-    }
-
-    let c = c as u8;
-
-    // Set 1 byte at a time
-    while i < n {
-        *((dest as usize + i) as *mut u8) = c;
-        i += 1;
-    }
-
-    dest
-}
-
-// 32-bit version of the function above
-#[cfg(target_pointer_width = "32")]
 #[no_mangle]
 pub unsafe extern fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 {
-    let c = c as u32;
-    let c = (c << 24) | (c << 16) | (c << 8)  | c;
-    let n_32: usize = n/4;
+    let c: usize = mem::transmute([c as u8; WORD_SIZE]);
+    let n_usize: usize = n/WORD_SIZE;
     let mut i: usize = 0;
 
-    // Set 4 bytes at a time
-    while i < n_32 {
-        *((dest as usize + i) as *mut u32) = c;
-        i += 4;
+    // Set `WORD_SIZE` bytes at a time
+    while i < n_usize {
+        *((dest as usize + i) as *mut usize) = c;
+        i += WORD_SIZE;
     }
 
     let c = c as u8;
@@ -212,53 +116,16 @@ pub unsafe extern fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 {
 ///
 /// This faster implementation works by comparing bytes not one-by-one, but in
 /// groups of 8 bytes (or 4 bytes in the case of 32-bit architectures).
-#[cfg(target_pointer_width = "64")]
-#[no_mangle]
-pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
-    let n_64: usize = n/8;
-    let mut i: usize = 0;
-
-    while i < n_64 {
-        let a = *((s1 as usize + i) as *const u64);
-        let b = *((s2 as usize + i) as *const u64);
-        if a != b {
-            let n: usize = i + 8;
-            // Find the one byte that is not equal
-            while i < n {
-                let a = *((s1 as usize + i) as *const u8);
-                let b = *((s2 as usize + i) as *const u8);
-                if a != b {
-                    return a as i32 - b as i32;
-                }
-                i += 1;
-            }
-        }
-        i += 8;
-    }
-
-    while i < n {
-        let a = *((s1 as usize + i) as *const u8);
-        let b = *((s2 as usize + i) as *const u8);
-        if a != b {
-            return a as i32 - b as i32;
-        }
-        i += 1;
-    }
-
-    0
-}
-
-#[cfg(target_pointer_width = "32")]
 #[no_mangle]
 pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
-    let n_32: usize = n/4;
+    let n_usize: usize = n/WORD_SIZE;
     let mut i: usize = 0;
 
-    while i < n_32 {
-        let a = *((s1 as usize + i) as *const u32);
-        let b = *((s2 as usize + i) as *const u32);
+    while i < n_usize {
+        let a = *((s1 as usize + i) as *const usize);
+        let b = *((s2 as usize + i) as *const usize);
         if a != b {
-            let n: usize = i + 4;
+            let n: usize = i + WORD_SIZE;
             // Find the one byte that is not equal
             while i < n {
                 let a = *((s1 as usize + i) as *const u8);
@@ -269,7 +136,7 @@ pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
                 i += 1;
             }
         }
-        i += 4;
+        i += WORD_SIZE;
     }
 
     while i < n {
diff --git a/src/lib.rs b/src/lib.rs
index 92c2dbbc..56ec8f16 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -22,6 +22,7 @@
 #![feature(never_type)]
 #![feature(thread_local)]
 #![feature(unique)]
+#![feature(const_size_of)]
 #![no_std]
 
 extern crate alloc_kernel as allocator;
-- 
GitLab