// Copyright 2015, ARM Limited // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of ARM Limited nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef VIXL_COMPILER_INTRINSICS_H #define VIXL_COMPILER_INTRINSICS_H #include "globals.h" namespace vixl { // Helper to check whether the version of GCC used is greater than the specified // requirement. #define MAJOR 1000000 #define MINOR 1000 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) #define GCC_VERSION_OR_NEWER(major, minor, patchlevel) \ ((__GNUC__ * MAJOR + __GNUC_MINOR__ * MINOR + __GNUC_PATCHLEVEL__) >= \ ((major) * MAJOR + (minor) * MINOR + (patchlevel))) #elif defined(__GNUC__) && defined(__GNUC_MINOR__) #define GCC_VERSION_OR_NEWER(major, minor, patchlevel) \ ((__GNUC__ * MAJOR + __GNUC_MINOR__ * MINOR) >= \ ((major) * MAJOR + (minor) * MINOR + (patchlevel))) #else #define GCC_VERSION_OR_NEWER(major, minor, patchlevel) 0 #endif #if defined(__clang__) && !defined(VIXL_NO_COMPILER_BUILTINS) #define COMPILER_HAS_BUILTIN_CLRSB (__has_builtin(__builtin_clrsb)) #define COMPILER_HAS_BUILTIN_CLZ (__has_builtin(__builtin_clz)) #define COMPILER_HAS_BUILTIN_CTZ (__has_builtin(__builtin_ctz)) #define COMPILER_HAS_BUILTIN_FFS (__has_builtin(__builtin_ffs)) #define COMPILER_HAS_BUILTIN_POPCOUNT (__has_builtin(__builtin_popcount)) #elif defined(__GNUC__) && !defined(VIXL_NO_COMPILER_BUILTINS) // The documentation for these builtins is available at: // https://gcc.gnu.org/onlinedocs/gcc-$MAJOR.$MINOR.$PATCHLEVEL/gcc//Other-Builtins.html # define COMPILER_HAS_BUILTIN_CLRSB (GCC_VERSION_OR_NEWER(4, 7, 0)) # define COMPILER_HAS_BUILTIN_CLZ (GCC_VERSION_OR_NEWER(3, 4, 0)) # define COMPILER_HAS_BUILTIN_CTZ (GCC_VERSION_OR_NEWER(3, 4, 0)) # define COMPILER_HAS_BUILTIN_FFS (GCC_VERSION_OR_NEWER(3, 4, 0)) # define COMPILER_HAS_BUILTIN_POPCOUNT (GCC_VERSION_OR_NEWER(3, 4, 0)) #else // One can define VIXL_NO_COMPILER_BUILTINS to force using the manually // implemented C++ methods. #define COMPILER_HAS_BUILTIN_BSWAP false #define COMPILER_HAS_BUILTIN_CLRSB false #define COMPILER_HAS_BUILTIN_CLZ false #define COMPILER_HAS_BUILTIN_CTZ false #define COMPILER_HAS_BUILTIN_FFS false #define COMPILER_HAS_BUILTIN_POPCOUNT false #endif template inline bool IsPowerOf2(V value) { return (value != 0) && ((value & (value - 1)) == 0); } // Declaration of fallback functions. int CountLeadingSignBitsFallBack(int64_t value, int width); int CountLeadingZerosFallBack(uint64_t value, int width); int CountSetBitsFallBack(uint64_t value, int width); int CountTrailingZerosFallBack(uint64_t value, int width); // Implementation of intrinsics functions. // TODO: The implementations could be improved for sizes different from 32bit // and 64bit: we could mask the values and call the appropriate builtin. template inline int CountLeadingSignBits(V value, int width = (sizeof(V) * 8)) { #if COMPILER_HAS_BUILTIN_CLRSB if (width == 32) { return __builtin_clrsb(value); } else if (width == 64) { return __builtin_clrsbll(value); } #endif return CountLeadingSignBitsFallBack(value, width); } template inline int CountLeadingZeros(V value, int width = (sizeof(V) * 8)) { #if COMPILER_HAS_BUILTIN_CLZ if (width == 32) { return (value == 0) ? 32 : __builtin_clz(static_cast(value)); } else if (width == 64) { return (value == 0) ? 64 : __builtin_clzll(value); } #endif return CountLeadingZerosFallBack(value, width); } template inline int CountSetBits(V value, int width = (sizeof(V) * 8)) { #if COMPILER_HAS_BUILTIN_POPCOUNT if (width == 32) { return __builtin_popcount(static_cast(value)); } else if (width == 64) { return __builtin_popcountll(value); } #endif return CountSetBitsFallBack(value, width); } template inline int CountTrailingZeros(V value, int width = (sizeof(V) * 8)) { #if COMPILER_HAS_BUILTIN_CTZ if (width == 32) { return (value == 0) ? 32 : __builtin_ctz(static_cast(value)); } else if (width == 64) { return (value == 0) ? 64 : __builtin_ctzll(value); } #endif return CountTrailingZerosFallBack(value, width); } } // namespace vixl #endif // VIXL_COMPILER_INTRINSICS_H