2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
19 #if !defined(__x86_64__) && !defined(__aarch64__)
20 #include <folly/Bits.h>
23 #include "hphp/util/assertions.h"
27 // GLIBC doesn't provide an fls primitive. Since we're rolling our own
28 // anyway, fix ffs's wacky offset-by-one historical implementation. These
29 // guys return success/failure (failure for input of all zeros) and the
30 // unoffset bit position in their reference param.
31 template<typename I64
, typename J64
>
32 inline bool ffs64(I64 input
, J64
&out
) {
34 #if defined(__x86_64__)
36 "bsfq %2, %1\n\t" // bit scan forward
37 "setnz %0\n\t": // zero retval if input == 0
38 "=r"(retval
), "=r"(out
):
42 #elif defined(__aarch64__)
44 "rbit %2, %2\n\t" // reverse bits
45 "clz %1, %2\n\t" // count leading zeros
47 "cset %w0, NE": // return (result != 64)
48 "=r"(retval
), "=r"(out
), "+r"(input
):
52 #elif defined(__powerpc64__)
53 // In PowerPC 64, bit 0 is the most significant
55 "neg %0, %2\n\t" // 2-complement of input, using retval as temp
57 "cntlzd %1, %0\n\t" // count leading zeros (starting from index 0)
59 "li %0, 1\n\t" // using retval as temp
60 "iseleq %0, 0, %0\n\t" // (input == 0) ? 0 : 1
62 "addi %1, %1, 63\n\t":// 63 - amount of leading zeros -> position in LSB
63 "+r"(retval
), "=r"(out
):// +r else %0 and %2 will be the same register
68 out
= folly::findFirstSet(input
);
74 template<typename I64
, typename J64
>
75 inline bool fls64(I64 input
, J64
&out
) {
77 #if defined(__x86_64__)
79 "bsrq %2, %1\n\t" // bit scan reverse
80 "setnz %0\n\t": // zero retval if input == 0
81 "=r"(retval
), "=r"(out
):
85 #elif defined(__aarch64__)
87 "clz %1, %2\n\t" // count leading zeros
89 "adds %1, %1, #63\n\t" // result = 63 - (# of leading zeros)
90 // "s" suffix sets condition flags
91 "cset %w0, PL": // return (result >= 0)
92 // because result < 0 iff input == 0
93 "=r"(retval
), "=r"(out
):
97 #elif defined(__powerpc64__)
98 // In PowerPC 64, bit 0 is the most significant
100 "cntlzd %1, %2\n\t" // count leading zeros (starting from index 0)
102 "li %0, 1\n\t" // using retval as temp
103 "iseleq %0, 0, %0\n\t" // (input == 0) ? 0 : 1
105 "addi %1, %1, 63\n\t":// 63 - amount of leading zeros -> position in LSB
106 "=r"(retval
), "=r"(out
):
111 out
= folly::findLastSet(input
) - 1;
118 * Return the index (0..63) of the most significant bit in x.
121 inline size_t fls64(size_t x
) {
123 #if defined(__x86_64__)
125 __asm__ ("bsrq %1, %0"
126 : "=r"(ret
) // Outputs.
130 #elif defined(__powerpc64__)
132 __asm__ ("cntlzd %0, %1"
133 : "=r"(ret
) // Outputs.
137 #elif defined(__aarch64__)
139 __asm__ ("clz %x0, %x1"
140 : "=r"(ret
) // Outputs.
145 // Equivalent (but incompletely strength-reduced by gcc):
146 return 63 - __builtin_clzl(x
);
151 * Return the index (0..63) of the least significant bit in x.
154 inline size_t ffs64(size_t x
) {
156 #if defined(__x86_64__)
158 __asm__ ("bsfq %1, %0"
159 : "=r"(ret
) // Outputs.
163 #elif defined(__aarch64__)
165 __asm__ ("rbit %0, %1\n\t"
167 : "=r"(ret
) // Outputs.
172 return __builtin_ffsll(x
) - 1;
176 inline void bitvec_set(uint64_t* bits
, size_t index
) {
177 #if defined(__x86_64__)
178 asm ("bts %1,%0" : "+m"(*bits
) : "r"(index
));
180 bits
[index
/ 64] |= 1ull << (index
% 64);
184 inline void bitvec_clear(uint64_t* bits
, size_t index
) {
185 #if defined(__x86_64__)
186 asm ("btr %1,%0" : "+m"(*bits
) : "r"(index
));
188 bits
[index
/ 64] &= ~(1ull << (index
% 64));
192 inline bool bitvec_test(const uint64_t* bits
, size_t index
) {
193 #if defined(__x86_64__)
196 "setc %0\n" : "=r"(b
) : "m"(*bits
), "r"(index
));
199 return (bits
[index
/ 64] & (1ull << (index
% 64))) != 0;