Skip to content

Commit

Permalink
Merge pull request #645 from tea/ctz
Browse files Browse the repository at this point in the history
Implement __ctz*i2 intrinsics
  • Loading branch information
Amanieu authored Jul 26, 2024
2 parents 721e34b + 133705e commit 6e31045
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 6 deletions.
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

0 comments on commit 6e31045

Please sign in to comment.