Skip to content

Commit a139e2a

Browse files
tautschnigDaniel Kroening
authored and
Daniel Kroening
committed
Model GCC's __builtin_clz{,l,ll}
Implement counting leading zeros based on algorithms described in Hacker's Delight.
1 parent 2825f54 commit a139e2a

File tree

3 files changed

+121
-0
lines changed

3 files changed

+121
-0
lines changed

regression/cbmc/gcc_clz1/main.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <assert.h>
2+
3+
#ifndef __GNUC__
4+
int __builtin_clz(unsigned int);
5+
int __builtin_clzl(unsigned long);
6+
int __builtin_clzll(unsigned long long);
7+
#endif
8+
9+
unsigned int __VERIFIER_nondet_unsigned();
10+
unsigned long __VERIFIER_nondet_unsigned_long();
11+
unsigned long long __VERIFIER_nondet_unsigned_long_long();
12+
13+
// Hacker's Delight
14+
// http://www.hackersdelight.org/permissions.htm
15+
int nlz2a(unsigned x)
16+
{
17+
unsigned y;
18+
int n, c;
19+
20+
n = sizeof(x) * 8;
21+
c = n / 2;
22+
// variant with additional bounding to make sure symbolic execution always
23+
// terminates without having to specify an unwinding bound
24+
int i = 0;
25+
do
26+
{
27+
y = x >> c;
28+
if(y != 0)
29+
{
30+
n = n - c;
31+
x = y;
32+
}
33+
c = c >> 1;
34+
++i;
35+
} while(c != 0 && i < sizeof(x) * 8);
36+
37+
return n - x;
38+
}
39+
40+
int main()
41+
{
42+
assert(nlz2a(42) == 26);
43+
assert(__builtin_clz(42) == 26);
44+
assert(
45+
__builtin_clzl(42) == 26 + (sizeof(unsigned long) - sizeof(unsigned)) * 8);
46+
assert(
47+
__builtin_clzll(42) ==
48+
26 + (sizeof(unsigned long long) - sizeof(unsigned)) * 8);
49+
50+
unsigned int u = __VERIFIER_nondet_unsigned();
51+
__CPROVER_assume(u != 0);
52+
assert(nlz2a(u) == __builtin_clz(u));
53+
54+
return 0;
55+
}

regression/cbmc/gcc_clz1/test.desc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/ansi-c/library/gcc.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,61 @@ inline void __sync_synchronize(void)
3232
"WWcumul", "RRcumul", "RWcumul", "WRcumul");
3333
#endif
3434
}
35+
36+
/* FUNCTION: __builtin_clz */
37+
38+
int __builtin_popcount(unsigned int);
39+
40+
inline int __builtin_clz(unsigned int x)
41+
{
42+
__CPROVER_precondition(x != 0, "__builtin_clz(0) is undefined");
43+
44+
x = x | (x >> 1);
45+
x = x | (x >> 2);
46+
x = x | (x >> 4);
47+
x = x | (x >> 8);
48+
if(sizeof(x) >= 4)
49+
x = x | (x >> 16);
50+
51+
return __builtin_popcount(~x);
52+
}
53+
54+
/* FUNCTION: __builtin_clzl */
55+
56+
int __builtin_popcountl(unsigned long int);
57+
58+
inline int __builtin_clzl(unsigned long int x)
59+
{
60+
__CPROVER_precondition(x != 0, "__builtin_clzl(0) is undefined");
61+
62+
x = x | (x >> 1);
63+
x = x | (x >> 2);
64+
x = x | (x >> 4);
65+
x = x | (x >> 8);
66+
if(sizeof(x) >= 4)
67+
x = x | (x >> 16);
68+
if(sizeof(x) >= 8)
69+
x = x | (x >> 32);
70+
71+
return __builtin_popcountl(~x);
72+
}
73+
74+
/* FUNCTION: __builtin_clzll */
75+
76+
int __builtin_popcountll(unsigned long long int);
77+
78+
inline int __builtin_clzll(unsigned long long int x)
79+
{
80+
__CPROVER_precondition(x != 0, "__builtin_clzll(0) is undefined");
81+
82+
x = x | (x >> 1);
83+
x = x | (x >> 2);
84+
x = x | (x >> 4);
85+
x = x | (x >> 8);
86+
if(sizeof(x) >= 4)
87+
x = x | (x >> 16);
88+
if(sizeof(x) >= 8)
89+
x = x | (x >> 32);
90+
91+
return __builtin_popcountll(~x);
92+
}

0 commit comments

Comments
 (0)