Skip to content

Commit ba467ef

Browse files
authored
Merge pull request #5728 from tautschnig/ffs
GCC built-ins: implement __builtin_ffs{,l,ll}
2 parents 9a3b545 + 45fbabf commit ba467ef

File tree

3 files changed

+100
-0
lines changed

3 files changed

+100
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <assert.h>
2+
#include <limits.h>
3+
4+
#ifndef __GNUC__
5+
int __builtin_ffs(int);
6+
int __builtin_ffsl(long);
7+
int __builtin_ffsll(long long);
8+
#endif
9+
10+
int __VERIFIER_nondet_int();
11+
long __VERIFIER_nondet_long();
12+
long long __VERIFIER_nondet_long_long();
13+
14+
// http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
15+
static const int multiply_de_bruijn_bit_position[32] = {
16+
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
17+
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
18+
19+
int main()
20+
{
21+
assert(__builtin_ffs(0) == 0);
22+
assert(__builtin_ffs(-1) == 1);
23+
assert(__builtin_ffs(INT_MIN) == sizeof(int) * 8);
24+
assert(__builtin_ffsl(INT_MIN) == sizeof(int) * 8);
25+
assert(__builtin_ffsl(LONG_MIN) == sizeof(long) * 8);
26+
assert(__builtin_ffsll(INT_MIN) == sizeof(int) * 8);
27+
assert(__builtin_ffsll(LLONG_MIN) == sizeof(long long) * 8);
28+
assert(__builtin_ffs(INT_MAX) == 1);
29+
30+
int i = __VERIFIER_nondet_int();
31+
__CPROVER_assume(i != 0);
32+
__CPROVER_assume(sizeof(i) == 4);
33+
__CPROVER_assume(i > INT_MIN);
34+
assert(
35+
multiply_de_bruijn_bit_position
36+
[((unsigned)((i & -i) * 0x077CB531U)) >> 27] +
37+
1 ==
38+
__builtin_ffs(i));
39+
40+
return 0;
41+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check --bounds-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/ansi-c/library/gcc.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,57 @@ inline int __builtin_clzll(unsigned long long int x)
9191
return __builtin_popcountll(~x);
9292
}
9393

94+
/* FUNCTION: __builtin_ffs */
95+
96+
int __builtin_clz(unsigned int x);
97+
98+
inline int __builtin_ffs(int x)
99+
{
100+
if(x == 0)
101+
return 0;
102+
103+
#pragma CPROVER check push
104+
#pragma CPROVER check disable "conversion"
105+
unsigned int u = (unsigned int)x;
106+
#pragma CPROVER check pop
107+
108+
return sizeof(int) * 8 - __builtin_clz(u & ~(u - 1));
109+
}
110+
111+
/* FUNCTION: __builtin_ffsl */
112+
113+
int __builtin_clzl(unsigned long x);
114+
115+
inline int __builtin_ffsl(long x)
116+
{
117+
if(x == 0)
118+
return 0;
119+
120+
#pragma CPROVER check push
121+
#pragma CPROVER check disable "conversion"
122+
unsigned long u = (unsigned long)x;
123+
#pragma CPROVER check pop
124+
125+
return sizeof(long) * 8 - __builtin_clzl(u & ~(u - 1));
126+
}
127+
128+
/* FUNCTION: __builtin_ffsll */
129+
130+
int __builtin_clzll(unsigned long long x);
131+
132+
inline int __builtin_ffsll(long long x)
133+
{
134+
if(x == 0)
135+
return 0;
136+
137+
#pragma CPROVER check push
138+
#pragma CPROVER check disable "conversion"
139+
unsigned long long u = (unsigned long long)x;
140+
#pragma CPROVER check pop
141+
142+
return sizeof(long long) * 8 - __builtin_clzll(u & ~(u - 1));
143+
}
144+
94145
/* FUNCTION: __atomic_test_and_set */
95146

96147
void __atomic_thread_fence(int memorder);

0 commit comments

Comments
 (0)