1 /*
2  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6 
7 /*
8  * This test ensures that the backends can deal with bit manipulation
9  * intrinsics.
10  */
11 
12 #include <stdio.h>
13 #include <stdint.h>
14 #include "native_client/tests/toolchain/utils.h"
15 
16 /*  __builtin_popcount[ll](x) */
17 uint32_t llvm_intrinsic_ctpop(uint32_t) __asm__("llvm.ctpop.i32");
18 uint64_t llvm_intrinsic_ctpopll(uint64_t) __asm__("llvm.ctpop.i64");
19 
20 /* __builtin_clz[ll](x) */
21 uint32_t llvm_intrinsic_ctlz(uint32_t, _Bool) __asm__("llvm.ctlz.i32");
22 uint64_t llvm_intrinsic_ctlzll(uint64_t, _Bool) __asm__("llvm.ctlz.i64");
23 
24 /* __builtin_ctz[ll](x) */
25 uint32_t llvm_intrinsic_cttz(uint32_t, _Bool) __asm__("llvm.cttz.i32");
26 uint64_t llvm_intrinsic_cttzll(uint64_t, _Bool) __asm__("llvm.cttz.i64");
27 
28 /* __builtin_bswap{16,32,64}(x) */
29 uint16_t llvm_intrinsic_bswap16(uint16_t) __asm__("llvm.bswap.i16");
30 uint32_t llvm_intrinsic_bswap32(uint32_t) __asm__("llvm.bswap.i32");
31 uint64_t llvm_intrinsic_bswap64(uint64_t) __asm__("llvm.bswap.i64");
32 
33 /* volatile prevents partial evaluation by llvm */
34 volatile uint16_t i16[] = {0, 0xabcd, 0xdcba, 0xffff};
35 volatile uint32_t i32[] = {0, 0x01234567, 0x12345670, 0xffffffff};
36 volatile uint64_t i64[] = {0, 0x0123456789abcdefll,
37                            0x0123456789abcdef0ll, 0xffffffffffffffffll};
38 
39 /*
40  * LLVM had a bug generating ARM code with large array offsets. The function
41  * needs a constant offset > 255 to trigger the bug.
42  */
43 volatile uint16_t i16l[257] = {[256] = 0xabcd};
44 volatile uint32_t i32l[257] = {[256] = 0x01234567};
45 volatile uint64_t i64l[257] = {[256] = 0x0123456789abcdefll};
46 
47 #define print_op(op, x)                                                 \
48   printf("%30s: %u\n", #op " (llvm)", (unsigned) llvm_intrinsic_ ## op(x))
49 
50 #define print_op2(op, x, y)                                             \
51   printf("%30s: %u\n", #op " (llvm)", (unsigned) llvm_intrinsic_ ## op(x, y))
52 
53 #define print_op_builtin(op, x)                                     \
54   printf("%30s: %u\n", #op " (builtin)", (unsigned) __builtin_ ## op(x))
55 
main(int argc,char * argv[])56 int main(int argc, char* argv[]) {
57   int i;
58 
59   for (i = 0; i < ARRAY_SIZE_UNSAFE(i16); ++i) {
60     printf("\n%30s: 0x%04hx\n", "i16 value is", i16[i]);
61     printf("%30s: 0x%04hx\n", "bswap (llvm)", llvm_intrinsic_bswap16(i16[i]));
62     printf("%30s: 0x%04hx\n", "bswap (builtin)", __builtin_bswap16(i16[i]));
63   }
64 
65   for (i = 0; i < ARRAY_SIZE_UNSAFE(i32); ++i) {
66     printf("\n%30s: 0x%08x\n", "i32 value is", i32[i]);
67     print_op(ctpop, i32[i]);
68     print_op_builtin(popcount, i32[i]);
69 
70     print_op2(ctlz, i32[i], 0 /* Don't return undef for 0 input! */);
71     /* 0 gives undefined results for the builtin on x86 */
72     if (i32[i] == 0)
73       printf("%30s: %u\n", "clz (builtin-manual-check)", 32);
74     else
75       print_op_builtin(clz, i32[i]);
76 
77     print_op2(cttz, i32[i], 0 /* Don't return undef for 0 input! */);
78     /* 0 gives undefined results for the builtin on x86 */
79     if (i32[i] == 0)
80       printf("%30s: %u\n", "ctz (builtin-manual-check)", 32);
81     else
82       print_op_builtin(ctz, i32[i]);
83 
84     printf("%30s: 0x%08x\n", "bswap (llvm)", llvm_intrinsic_bswap32(i32[i]));
85     printf("%30s: 0x%08x\n", "bswap (builtin)", __builtin_bswap32(i32[i]));
86   }
87 
88   for (i = 0; i < ARRAY_SIZE_UNSAFE(i64); ++i) {
89     printf("\n%30s: 0x%016llx\n", "i64 value is", i64[i]);
90     print_op(ctpopll, i64[i]);
91     print_op_builtin(popcountll, i64[i]);
92 
93     print_op2(ctlzll, i64[i], 0 /* Don't return undef for 0 input! */);
94     /* 0 gives undefined results for the builtin on x86 */
95     if (i64[i] == 0)
96       printf("%30s: %u\n", "clzll (builtin-manual-check)", 64);
97     else
98       print_op_builtin(clzll, i64[i]);
99 
100     print_op2(cttzll, i64[i], 0 /* Don't return undef for 0 input! */);
101     /* 0 gives undefined results for the builtin on x86 */
102     if (i64[i] == 0)
103       printf("%30s: %u\n", "ctzll (builtin-manual-check)", 64);
104     else
105       print_op_builtin(ctzll, i64[i]);
106 
107     printf("%30s: 0x%016llx\n", "bswapll (llvm)",
108            llvm_intrinsic_bswap64(i64[i]));
109     printf("%30s: 0x%016llx\n", "bswapll (builtin)",
110            __builtin_bswap64(i64[i]));
111   }
112 
113   printf("\nLarge offset tests:\n");
114   printf("%30s: 0x%04hx\n", "bswap (llvm)", llvm_intrinsic_bswap16(i16l[256]));
115   printf("%30s: 0x%04hx\n", "bswap (builtin)", __builtin_bswap16(i16l[256]));
116   printf("%30s: 0x%08x\n", "bswap (llvm)", llvm_intrinsic_bswap32(i32l[256]));
117   printf("%30s: 0x%08x\n", "bswap (builtin)", __builtin_bswap32(i32l[256]));
118   printf("%30s: 0x%016llx\n", "bswapll (llvm)",
119          llvm_intrinsic_bswap64(i64l[256]));
120   printf("%30s: 0x%016llx\n", "bswapll (builtin)",
121          __builtin_bswap64(i64l[256]));
122 
123   return 0;
124 }
125