1 /* 2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 #ifndef AOM_AOM_PORTS_BITOPS_H_ 13 #define AOM_AOM_PORTS_BITOPS_H_ 14 15 #include <assert.h> 16 #include <stdint.h> 17 18 #include "aom_ports/msvc.h" 19 #include "config/aom_config.h" 20 21 #ifdef _MSC_VER 22 #if defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64) || defined(_M_ARM) 23 #include <intrin.h> 24 #define USE_MSC_INTRINSICS 25 #endif 26 #endif 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 // get_msb: 33 // Returns (int)floor(log2(n)). n must be > 0. 34 // These versions of get_msb() are only valid when n != 0 because all 35 // of the optimized versions are undefined when n == 0: 36 37 // GCC compiler: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html 38 // MSVC: https://learn.microsoft.com/en-us/cpp/intrinsics/compiler-intrinsics 39 40 // use GNU builtins where available. 41 #if defined(__GNUC__) && \ 42 ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4) get_msb(unsigned int n)43static INLINE int get_msb(unsigned int n) { 44 assert(n != 0); 45 return 31 ^ __builtin_clz(n); 46 } 47 #elif defined(USE_MSC_INTRINSICS) 48 #pragma intrinsic(_BitScanReverse) 49 50 static INLINE int get_msb(unsigned int n) { 51 unsigned long first_set_bit; 52 assert(n != 0); 53 _BitScanReverse(&first_set_bit, n); 54 return first_set_bit; 55 } 56 #else 57 static INLINE int get_msb(unsigned int n) { 58 int log = 0; 59 unsigned int value = n; 60 61 assert(n != 0); 62 63 for (int shift = 16; shift != 0; shift >>= 1) { 64 const unsigned int x = value >> shift; 65 if (x != 0) { 66 value = x; 67 log += shift; 68 } 69 } 70 return log; 71 } 72 #endif 73 74 #if defined(__GNUC__) && \ 75 ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4) aom_clzll(uint64_t n)76static INLINE int aom_clzll(uint64_t n) { return __builtin_clzll(n); } 77 #elif defined(USE_MSC_INTRINSICS) 78 #if defined(_M_X64) || defined(_M_ARM64) 79 #pragma intrinsic(_BitScanReverse64) 80 #endif 81 aom_clzll(uint64_t n)82static INLINE int aom_clzll(uint64_t n) { 83 assert(n != 0); 84 unsigned long first_set_bit; // NOLINT(runtime/int) 85 #if defined(_M_X64) || defined(_M_ARM64) 86 const unsigned char bit_set = 87 _BitScanReverse64(&first_set_bit, (unsigned __int64)n); 88 #else // !(defined(_M_X64) || defined(_M_ARM64)) 89 const unsigned long n_hi = (unsigned long)(n >> 32); // NOLINT(runtime/int) 90 if (n_hi != 0) { 91 const unsigned char bit_set = _BitScanReverse(&first_set_bit, n_hi); 92 assert(bit_set != 0); 93 (void)bit_set; 94 return 31 ^ (int)first_set_bit; 95 } 96 const unsigned char bit_set = 97 _BitScanReverse(&first_set_bit, (unsigned long)n); // NOLINT(runtime/int) 98 #endif 99 assert(bit_set != 0); 100 (void)bit_set; 101 return 63 ^ (int)first_set_bit; 102 } 103 #undef USE_MSC_INTRINSICS 104 #else aom_clzll(uint64_t n)105static INLINE int aom_clzll(uint64_t n) { 106 assert(n != 0); 107 108 int res = 0; 109 uint64_t high_bit = 1ULL << 63; 110 while (!(n & high_bit)) { 111 res++; 112 n <<= 1; 113 } 114 return res; 115 } 116 #endif 117 118 #ifdef __cplusplus 119 } // extern "C" 120 #endif 121 122 #endif // AOM_AOM_PORTS_BITOPS_H_ 123