Skip to content

Commit fb03d26

Browse files
committed
mem: Add REP MOVSB/STOSB implementations
The assembly generated seems correct: https://rust.godbolt.org/z/GGnec8 Signed-off-by: Joe Richey <[email protected]>
1 parent ee54782 commit fb03d26

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/mem/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use core::mem;
1010
use core::ops::{BitOr, Shl};
1111

1212
// memcpy/memmove/memset have optimized implementations on some architectures
13+
#[cfg_attr(all(feature = "asm", target_arch = "x86_64"), path = "x86_64.rs")]
1314
mod memcpy;
1415
pub use self::memcpy::*;
1516

src/mem/x86_64.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use super::c_int;
2+
3+
#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
4+
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 {
5+
asm!(
6+
"rep movsb [rdi], [rsi]",
7+
inout("rcx") count => _,
8+
inout("rdi") dest => _,
9+
inout("rsi") src => _,
10+
options(nostack, preserves_flags)
11+
);
12+
dest
13+
}
14+
15+
#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
16+
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 {
17+
let delta = dest as usize - src as usize;
18+
if delta >= count {
19+
// We can copy forwards because either dest is far enough ahead of src,
20+
// or src is ahead of dest (and delta overflowed).
21+
return self::memcpy(dest, src, count);
22+
}
23+
// copy backwards
24+
asm!(
25+
"std",
26+
"rep movsb [rdi], [rsi]",
27+
"cld",
28+
inout("rcx") count => _,
29+
inout("rdi") dest.add(count).sub(1) => _,
30+
inout("rsi") src.add(count).sub(1) => _,
31+
options(nostack, preserves_flags)
32+
);
33+
dest
34+
}
35+
36+
#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
37+
pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, count: usize) -> *mut u8 {
38+
asm!(
39+
"rep stosb [rdi], al",
40+
inout("rcx") count => _,
41+
inout("rdi") dest => _,
42+
in("al") c as u8,
43+
options(nostack, preserves_flags)
44+
);
45+
dest
46+
}

0 commit comments

Comments
 (0)