Skip to content

Specialize strlen for x86_64. #516

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 12, 2023
Merged
10 changes: 10 additions & 0 deletions src/mem/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,3 +279,13 @@ pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 {
}
0
}

#[inline(always)]
pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize {
let mut n = 0;
while *s != 0 {
n += 1;
s = s.add(1);
}
n
}
8 changes: 1 addition & 7 deletions src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,7 @@ intrinsics! {
#[mem_builtin]
#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")]
pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize {
let mut n = 0;
let mut s = s;
while *s != 0 {
n += 1;
s = s.offset(1);
}
n
impls::c_string_length(s)
}
}

Expand Down
29 changes: 29 additions & 0 deletions src/mem/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,35 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 {
c16(a.cast(), b.cast(), n)
}

#[inline(always)]
pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize {
let mut n: usize;

asm!(
// search for a zero byte
"xor al, al",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xor eax, eax avoids a potential partial register stall and is 1 byte shorter I believe.


// unbounded memory region
"xor rcx, rcx",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xor ecx, ecx has the same effect and saves a rex prefix.

"not rcx",

// forward direction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is guaranteed to be set to the forward direction already due to abi requirements.

"cld",

// perform search
"repne scasb",

// extract length
"not rcx",
"dec rcx",
inout("rdi") s => _,
out("rcx") n,
options(nostack),
);

n
}

/// Determine optimal parameters for a `rep` instruction.
fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) {
// Unaligned writes are still slow on modern processors, so align the destination address.
Expand Down