Skip to content

Commit 6e31045

Browse files
authored
Merge pull request #645 from tea/ctz
Implement __ctz*i2 intrinsics
2 parents 721e34b + 133705e commit 6e31045

File tree

5 files changed

+111
-6
lines changed

5 files changed

+111
-6
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ rely on CI.
171171
- [x] clzti2.c
172172
- [x] comparedf2.c
173173
- [x] comparesf2.c
174+
- [x] ctzdi2.c
175+
- [x] ctzsi2.c
176+
- [x] ctzti2.c
174177
- [x] divdf3.c
175178
- [x] divdi3.c
176179
- [x] divmoddi4.c
@@ -395,9 +398,6 @@ These builtins are never called by LLVM.
395398
- ~~arm/switchu8.S~~
396399
- ~~cmpdi2.c~~
397400
- ~~cmpti2.c~~
398-
- ~~ctzdi2.c~~
399-
- ~~ctzsi2.c~~
400-
- ~~ctzti2.c~~
401401
- ~~ffssi2.c~~
402402
- ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though!
403403
- ~~ffsti2.c~~

build.rs

-3
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,6 @@ mod c {
345345
("__addvdi3", "addvdi3.c"),
346346
("__addvsi3", "addvsi3.c"),
347347
("__cmpdi2", "cmpdi2.c"),
348-
("__ctzdi2", "ctzdi2.c"),
349-
("__ctzsi2", "ctzsi2.c"),
350348
("__int_util", "int_util.c"),
351349
("__mulvdi3", "mulvdi3.c"),
352350
("__mulvsi3", "mulvsi3.c"),
@@ -380,7 +378,6 @@ mod c {
380378
("__absvti2", "absvti2.c"),
381379
("__addvti3", "addvti3.c"),
382380
("__cmpti2", "cmpti2.c"),
383-
("__ctzti2", "ctzti2.c"),
384381
("__ffsti2", "ffsti2.c"),
385382
("__mulvti3", "mulvti3.c"),
386383
("__negti2", "negti2.c"),

src/int/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod leading_zeros;
99
pub mod mul;
1010
pub mod sdiv;
1111
pub mod shift;
12+
pub mod trailing_zeros;
1213
pub mod udiv;
1314

1415
pub use big::{i256, u256};

src/int/trailing_zeros.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use crate::int::{CastInto, Int};
2+
3+
public_test_dep! {
4+
/// Returns number of trailing binary zeros in `x`.
5+
#[allow(dead_code)]
6+
pub(crate) fn trailing_zeros<T: Int + CastInto<u32> + CastInto<u16> + CastInto<u8>>(x: T) -> usize {
7+
let mut x = x;
8+
let mut r: u32 = 0;
9+
let mut t: u32;
10+
11+
const { assert!(T::BITS <= 64) };
12+
if T::BITS >= 64 {
13+
r += ((CastInto::<u32>::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0
14+
x >>= r; // remove 32 zero bits
15+
}
16+
17+
if T::BITS >= 32 {
18+
t = ((CastInto::<u16>::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0
19+
r += t;
20+
x >>= t; // x = [0 - 0xFFFF] + higher garbage bits
21+
}
22+
23+
const { assert!(T::BITS >= 16) };
24+
t = ((CastInto::<u8>::cast(x) == 0) as u32) << 3;
25+
x >>= t; // x = [0 - 0xFF] + higher garbage bits
26+
r += t;
27+
28+
let mut x: u8 = x.cast();
29+
30+
t = (((x & 0x0F) == 0) as u32) << 2;
31+
x >>= t; // x = [0 - 0xF] + higher garbage bits
32+
r += t;
33+
34+
t = (((x & 0x3) == 0) as u32) << 1;
35+
x >>= t; // x = [0 - 0x3] + higher garbage bits
36+
r += t;
37+
38+
x &= 3;
39+
40+
r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg())
41+
}
42+
}
43+
44+
intrinsics! {
45+
/// Returns the number of trailing binary zeros in `x` (32 bit version).
46+
pub extern "C" fn __ctzsi2(x: u32) -> usize {
47+
trailing_zeros(x)
48+
}
49+
50+
/// Returns the number of trailing binary zeros in `x` (64 bit version).
51+
pub extern "C" fn __ctzdi2(x: u64) -> usize {
52+
trailing_zeros(x)
53+
}
54+
55+
/// Returns the number of trailing binary zeros in `x` (128 bit version).
56+
pub extern "C" fn __ctzti2(x: u128) -> usize {
57+
let lo = x as u64;
58+
if lo == 0 {
59+
64 + __ctzdi2((x >> 64) as u64)
60+
} else {
61+
__ctzdi2(lo)
62+
}
63+
}
64+
}

testcrate/tests/misc.rs

+43
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,49 @@ fn leading_zeros() {
131131
}
132132
}
133133

134+
#[test]
135+
fn trailing_zeros() {
136+
use compiler_builtins::int::trailing_zeros::{__ctzdi2, __ctzsi2, __ctzti2, trailing_zeros};
137+
fuzz(N, |x: u32| {
138+
if x == 0 {
139+
return; // undefined value for an intrinsic
140+
}
141+
let tz = x.trailing_zeros() as usize;
142+
let tz0 = __ctzsi2(x);
143+
let tz1 = trailing_zeros(x);
144+
if tz0 != tz {
145+
panic!("__ctzsi2({}): std: {}, builtins: {}", x, tz, tz0);
146+
}
147+
if tz1 != tz {
148+
panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1);
149+
}
150+
});
151+
fuzz(N, |x: u64| {
152+
if x == 0 {
153+
return; // undefined value for an intrinsic
154+
}
155+
let tz = x.trailing_zeros() as usize;
156+
let tz0 = __ctzdi2(x);
157+
let tz1 = trailing_zeros(x);
158+
if tz0 != tz {
159+
panic!("__ctzdi2({}): std: {}, builtins: {}", x, tz, tz0);
160+
}
161+
if tz1 != tz {
162+
panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1);
163+
}
164+
});
165+
fuzz(N, |x: u128| {
166+
if x == 0 {
167+
return; // undefined value for an intrinsic
168+
}
169+
let tz = x.trailing_zeros() as usize;
170+
let tz0 = __ctzti2(x);
171+
if tz0 != tz {
172+
panic!("__ctzti2({}): std: {}, builtins: {}", x, tz, tz0);
173+
}
174+
});
175+
}
176+
134177
#[test]
135178
#[cfg(not(target_arch = "avr"))]
136179
fn bswap() {

0 commit comments

Comments
 (0)