Skip to content

Implement __ctz*i2 intrinsics #645

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 1 commit into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ rely on CI.
- [x] clzti2.c
- [x] comparedf2.c
- [x] comparesf2.c
- [x] ctzdi2.c
- [x] ctzsi2.c
- [x] ctzti2.c
- [x] divdf3.c
- [x] divdi3.c
- [x] divmoddi4.c
Expand Down Expand Up @@ -395,9 +398,6 @@ These builtins are never called by LLVM.
- ~~arm/switchu8.S~~
- ~~cmpdi2.c~~
- ~~cmpti2.c~~
- ~~ctzdi2.c~~
- ~~ctzsi2.c~~
- ~~ctzti2.c~~
- ~~ffssi2.c~~
- ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though!
- ~~ffsti2.c~~
Expand Down
3 changes: 0 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,6 @@ mod c {
("__addvdi3", "addvdi3.c"),
("__addvsi3", "addvsi3.c"),
("__cmpdi2", "cmpdi2.c"),
("__ctzdi2", "ctzdi2.c"),
("__ctzsi2", "ctzsi2.c"),
("__int_util", "int_util.c"),
("__mulvdi3", "mulvdi3.c"),
("__mulvsi3", "mulvsi3.c"),
Expand Down Expand Up @@ -380,7 +378,6 @@ mod c {
("__absvti2", "absvti2.c"),
("__addvti3", "addvti3.c"),
("__cmpti2", "cmpti2.c"),
("__ctzti2", "ctzti2.c"),
("__ffsti2", "ffsti2.c"),
("__mulvti3", "mulvti3.c"),
("__negti2", "negti2.c"),
Expand Down
1 change: 1 addition & 0 deletions src/int/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod leading_zeros;
pub mod mul;
pub mod sdiv;
pub mod shift;
pub mod trailing_zeros;
pub mod udiv;

pub use big::{i256, u256};
Expand Down
64 changes: 64 additions & 0 deletions src/int/trailing_zeros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::int::{CastInto, Int};

public_test_dep! {
/// Returns number of trailing binary zeros in `x`.
#[allow(dead_code)]
pub(crate) fn trailing_zeros<T: Int + CastInto<u32> + CastInto<u16> + CastInto<u8>>(x: T) -> usize {
let mut x = x;
let mut r: u32 = 0;
let mut t: u32;

const { assert!(T::BITS <= 64) };
if T::BITS >= 64 {
r += ((CastInto::<u32>::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0
x >>= r; // remove 32 zero bits
}

if T::BITS >= 32 {
t = ((CastInto::<u16>::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0
r += t;
x >>= t; // x = [0 - 0xFFFF] + higher garbage bits
}

const { assert!(T::BITS >= 16) };
t = ((CastInto::<u8>::cast(x) == 0) as u32) << 3;
x >>= t; // x = [0 - 0xFF] + higher garbage bits
r += t;

let mut x: u8 = x.cast();

t = (((x & 0x0F) == 0) as u32) << 2;
x >>= t; // x = [0 - 0xF] + higher garbage bits
r += t;

t = (((x & 0x3) == 0) as u32) << 1;
x >>= t; // x = [0 - 0x3] + higher garbage bits
r += t;

x &= 3;

r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg())
}
}

intrinsics! {
/// Returns the number of trailing binary zeros in `x` (32 bit version).
pub extern "C" fn __ctzsi2(x: u32) -> usize {
trailing_zeros(x)
}

/// Returns the number of trailing binary zeros in `x` (64 bit version).
pub extern "C" fn __ctzdi2(x: u64) -> usize {
trailing_zeros(x)
}

/// Returns the number of trailing binary zeros in `x` (128 bit version).
pub extern "C" fn __ctzti2(x: u128) -> usize {
let lo = x as u64;
if lo == 0 {
64 + __ctzdi2((x >> 64) as u64)
} else {
__ctzdi2(lo)
}
}
}
43 changes: 43 additions & 0 deletions testcrate/tests/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,49 @@ fn leading_zeros() {
}
}

#[test]
fn trailing_zeros() {
use compiler_builtins::int::trailing_zeros::{__ctzdi2, __ctzsi2, __ctzti2, trailing_zeros};
fuzz(N, |x: u32| {
if x == 0 {
return; // undefined value for an intrinsic
}
let tz = x.trailing_zeros() as usize;
let tz0 = __ctzsi2(x);
let tz1 = trailing_zeros(x);
if tz0 != tz {
panic!("__ctzsi2({}): std: {}, builtins: {}", x, tz, tz0);
}
if tz1 != tz {
panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1);
}
});
fuzz(N, |x: u64| {
if x == 0 {
return; // undefined value for an intrinsic
}
let tz = x.trailing_zeros() as usize;
let tz0 = __ctzdi2(x);
let tz1 = trailing_zeros(x);
if tz0 != tz {
panic!("__ctzdi2({}): std: {}, builtins: {}", x, tz, tz0);
}
if tz1 != tz {
panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1);
}
});
fuzz(N, |x: u128| {
if x == 0 {
return; // undefined value for an intrinsic
}
let tz = x.trailing_zeros() as usize;
let tz0 = __ctzti2(x);
if tz0 != tz {
panic!("__ctzti2({}): std: {}, builtins: {}", x, tz, tz0);
}
});
}

#[test]
#[cfg(not(target_arch = "avr"))]
fn bswap() {
Expand Down
Loading