History

Add builtins ffs, clz, ctz, clrsb, popcount, parity

Add new file lib/builtin.c Modify include/tccdefs.h, lib/Makefile to compile it. Update tests/tcctest.c to test it.

herman ten brugge committed 3 years ago

Commit dd691431 parent ea0c57e4 files · +193 −5Browse files

Unified · Split

4 files
  1. include/tccdefs.h +15 −0
  2. lib/Makefile +5 −5
  3. lib/builtin.c +124 −0
  4. tests/tcctest.c +49 −0
include/tccdefs.h+15−0
@@ -309,4 +309,19 @@ · 308 unmodified lines
309309 #undef __MAYBE_REDIR
310310 #undef __RENAME
311311
312+#if !defined _WIN32
313+ #define __BUILTIN_EXTERN(name,u) \
314+ int __builtin_##name(u int); \
315+ int __builtin_##name##l(u long); \
316+ int __builtin_##name##ll(u long long);
317+
318+ __BUILTIN_EXTERN(ffs,)
319+ __BUILTIN_EXTERN(clz, unsigned)
320+ __BUILTIN_EXTERN(ctz, unsigned)
321+ __BUILTIN_EXTERN(clrsb,)
322+ __BUILTIN_EXTERN(popcount, unsigned)
323+ __BUILTIN_EXTERN(parity, unsigned)
324+ #undef __BUILTIN_EXTERN
325+#endif
326+
312327 #endif /* ndef __TCC_PP__ */
lib/Makefile+5−5
@@ -42,11 +42,11 @@ $(X)BT_O += tcov.o · 41 unmodified lines
4242
4343 DSO_O = dsohandle.o
4444
45−I386_O = libtcc1.o alloca.o alloca-bt.o stdatomic.o atomic.o $(BT_O)
46−X86_64_O = libtcc1.o alloca.o alloca-bt.o stdatomic.o atomic.o $(BT_O)
47−ARM_O = libtcc1.o armeabi.o alloca.o armflush.o stdatomic.o atomic.o $(BT_O)
48−ARM64_O = lib-arm64.o stdatomic.o atomic.o $(BT_O)
49−RISCV64_O = lib-arm64.o stdatomic.o atomic.o $(BT_O)
45+I386_O = libtcc1.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o $(BT_O)
46+X86_64_O = libtcc1.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o $(BT_O)
47+ARM_O = libtcc1.o armeabi.o alloca.o armflush.o stdatomic.o atomic.o builtin.o $(BT_O)
48+ARM64_O = lib-arm64.o stdatomic.o atomic.o builtin.o $(BT_O)
49+RISCV64_O = lib-arm64.o stdatomic.o atomic.o builtin.o $(BT_O)
5050 WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
5151
5252 OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
lib/builtin.c+124−0
@@ -0,0 +1,124 @@
1+/* ---------------------------------------------- */
2+/* This file implements:
3+ * __builtin_ffs
4+ * __builtin_clz
5+ * __builtin_ctz
6+ * __builtin_clrsb
7+ * __builtin_popcount
8+ * __builtin_parity
9+ * for int, long and long long
10+ */
11+
12+static const unsigned char table_1_32[] = {
13+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
14+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
15+};
16+static const unsigned char table_2_32[32] = {
17+ 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
18+ 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
19+};
20+static const unsigned char table_1_64[] = {
21+ 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
22+ 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
23+ 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
24+ 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
25+};
26+static const unsigned char table_2_64[] = {
27+ 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
28+ 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
29+ 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
30+ 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
31+};
32+
33+#define FFSI(x) \
34+ return table_1_32[((x & -x) * 0x077cb531u) >> 27] + (x != 0);
35+#define FFSL(x) \
36+ return table_1_64[((x & -x) * 0x022fdd63cc95386dull) >> 58] + (x != 0);
37+#define CTZI(x) \
38+ return table_1_32[((x & -x) * 0x077cb531u) >> 27];
39+#define CTZL(x) \
40+ return table_1_64[((x & -x) * 0x022fdd63cc95386dull) >> 58];
41+#define CLZI(x) \
42+ x |= x >> 1; \
43+ x |= x >> 2; \
44+ x |= x >> 4; \
45+ x |= x >> 8; \
46+ x |= x >> 16; \
47+ return table_2_32[(x * 0x07c4acddu) >> 27];
48+#define CLZL(x) \
49+ x |= x >> 1; \
50+ x |= x >> 2; \
51+ x |= x >> 4; \
52+ x |= x >> 8; \
53+ x |= x >> 16; \
54+ x |= x >> 32; \
55+ return table_2_64[x * 0x03f79d71b4cb0a89ull >> 58];
56+#define POPCOUNTI(x, m) \
57+ x = x - ((x >> 1) & 0x55555555); \
58+ x = (x & 0x33333333) + ((x >> 2) & 0x33333333); \
59+ x = (x + (x >> 4)) & 0xf0f0f0f; \
60+ return ((x * 0x01010101) >> 24) & m;
61+#define POPCOUNTL(x, m) \
62+ x = x - ((x >> 1) & 0x5555555555555555ull); \
63+ x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull); \
64+ x = (x + (x >> 4)) & 0xf0f0f0f0f0f0f0full; \
65+ return ((x * 0x0101010101010101ull) >> 56) & m;
66+
67+/* Returns one plus the index of the least significant 1-bit of x,
68+ or if x is zero, returns zero. */
69+int __builtin_ffs (int x) { FFSI(x) }
70+#if __SIZEOF_LONG__ == 4
71+int __builtin_ffsl (long x) { FFSI(x) }
72+#else
73+int __builtin_ffsl (long x) { FFSL(x) }
74+#endif
75+int __builtin_ffsll (long long x) { FFSL(x) }
76+
77+/* Returns the number of leading 0-bits in x, starting at the most significant
78+ bit position. If x is 0, the result is undefined. */
79+int __builtin_clz (unsigned int x) { CLZI(x) }
80+#if __SIZEOF_LONG__ == 4
81+int __builtin_clzl (unsigned long x) { CLZI(x) }
82+#else
83+int __builtin_clzl (unsigned long x) { CLZL(x) }
84+#endif
85+int __builtin_clzll (unsigned long long x) { CLZL(x) }
86+
87+/* Returns the number of trailing 0-bits in x, starting at the least
88+ significant bit position. If x is 0, the result is undefined. */
89+int __builtin_ctz (unsigned int x) { CTZI(x) }
90+#if __SIZEOF_LONG__ == 4
91+int __builtin_ctzl (unsigned long x) { CTZI(x) }
92+#else
93+int __builtin_ctzl (unsigned long x) { CTZL(x) }
94+#endif
95+int __builtin_ctzll (unsigned long long x) { CTZL(x) }
96+
97+/* Returns the number of leading redundant sign bits in x, i.e. the number
98+ of bits following the most significant bit that are identical to it.
99+ There are no special cases for 0 or other values. */
100+int __builtin_clrsb (int x) { if (x < 0) x = ~x; x <<= 1; CLZI(x) }
101+#if __SIZEOF_LONG__ == 4
102+int __builtin_clrsbl (long x) { if (x < 0) x = ~x; x <<= 1; CLZI(x) }
103+#else
104+int __builtin_clrsbl (long x) { if (x < 0) x = ~x; x <<= 1; CLZL(x) }
105+#endif
106+int __builtin_clrsbll (long long x) { if (x < 0) x = ~x; x <<= 1; CLZL(x) }
107+
108+/* Returns the number of 1-bits in x.*/
109+int __builtin_popcount (unsigned int x) { POPCOUNTI(x, 0x3f) }
110+#if __SIZEOF_LONG__ == 4
111+int __builtin_popcountl (unsigned long x) { POPCOUNTI(x, 0x3f) }
112+#else
113+int __builtin_popcountl (unsigned long x) { POPCOUNTL(x, 0x7f) }
114+#endif
115+int __builtin_popcountll (unsigned long long x) { POPCOUNTL(x, 0x7f) }
116+
117+/* Returns the parity of x, i.e. the number of 1-bits in x modulo 2. */
118+int __builtin_parity (unsigned int x) { POPCOUNTI(x, 0x01) }
119+#if __SIZEOF_LONG__ == 4
120+int __builtin_parityl (unsigned long x) { POPCOUNTI(x, 0x01) }
121+#else
122+int __builtin_parityl (unsigned long x) { POPCOUNTL(x, 0x01) }
123+#endif
124+int __builtin_parityll (unsigned long long x) { POPCOUNTL(x, 0x01) }
tests/tcctest.c+49−0
@@ -3844,6 +3844,36 @@ int constant_p_var; · 3843 unmodified lines
38443844
38453845 int func(void);
38463846
3847+#if !defined _WIN32
3848+/* __builtin_clz and __builtin_ctz return random values for 0 */
3849+static void builtin_test_bits(unsigned long long x, int cnt[])
3850+{
3851+ cnt[0] += __builtin_ffs(x);
3852+ cnt[1] += __builtin_ffsl(x);
3853+ cnt[2] += __builtin_ffsll(x);
3854+
3855+ if ((unsigned int) x) cnt[3] += __builtin_clz(x);
3856+ if ((unsigned long) x) cnt[4] += __builtin_clzl(x);
3857+ if ((unsigned long long) x) cnt[5] += __builtin_clzll(x);
3858+
3859+ if ((unsigned int) x) cnt[6] += __builtin_ctz(x);
3860+ if ((unsigned long) x) cnt[7] += __builtin_ctzl(x);
3861+ if ((unsigned long long) x) cnt[8] += __builtin_ctzll(x);
3862+
3863+ cnt[9] += __builtin_clrsb(x);
3864+ cnt[10] += __builtin_clrsbl(x);
3865+ cnt[11] += __builtin_clrsbll(x);
3866+
3867+ cnt[12] += __builtin_popcount(x);
3868+ cnt[13] += __builtin_popcountl(x);
3869+ cnt[14] += __builtin_popcountll(x);
3870+
3871+ cnt[15] += __builtin_parity(x);
3872+ cnt[16] += __builtin_parityl(x);
3873+ cnt[17] += __builtin_parityll(x);
3874+}
3875+#endif
3876+
38473877 void builtin_test(void)
38483878 {
38493879 short s;
@@ -3897,6 +3927,25 @@ void builtin_test(void) · 47 unmodified lines
38973927 printf("bce: %d\n", i);
38983928
38993929 //printf("bera: %p\n", __builtin_extract_return_addr((void*)43));
3930+
3931+#if !defined _WIN32
3932+ {
3933+ int cnt[18];
3934+ unsigned long long r = 0;
3935+
3936+ memset(cnt, 0, sizeof(cnt));
3937+ builtin_test_bits(0, cnt);
3938+ builtin_test_bits(0xffffffffffffffffull, cnt);
3939+ for (i = 0; i < 64; i++)
3940+ builtin_test_bits(1ull << i, cnt);
3941+ for (i = 0; i < 1000; i++) {
3942+ r = 0x5851f42d4c957f2dull * r + 0x14057b7ef767814full;
3943+ builtin_test_bits(r, cnt);
3944+ }
3945+ for (i = 0; i < 18; i++)
3946+ printf ("%d %d\n", i, cnt[i]);
3947+ }
3948+#endif
39003949 }
39013950
39023951 #if defined _WIN32

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t