compiler-intrinsics.h (5824B)
1// Copyright 2015, ARM Limited 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are met: 6// 7// * Redistributions of source code must retain the above copyright notice, 8// this list of conditions and the following disclaimer. 9// * Redistributions in binary form must reproduce the above copyright notice, 10// this list of conditions and the following disclaimer in the documentation 11// and/or other materials provided with the distribution. 12// * Neither the name of ARM Limited nor the names of its contributors may be 13// used to endorse or promote products derived from this software without 14// specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 28#ifndef VIXL_COMPILER_INTRINSICS_H 29#define VIXL_COMPILER_INTRINSICS_H 30 31#include "globals.h" 32 33namespace vixl { 34 35// Helper to check whether the version of GCC used is greater than the specified 36// requirement. 37#define MAJOR 1000000 38#define MINOR 1000 39#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) 40#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) \ 41 ((__GNUC__ * MAJOR + __GNUC_MINOR__ * MINOR + __GNUC_PATCHLEVEL__) >= \ 42 ((major) * MAJOR + (minor) * MINOR + (patchlevel))) 43#elif defined(__GNUC__) && defined(__GNUC_MINOR__) 44#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) \ 45 ((__GNUC__ * MAJOR + __GNUC_MINOR__ * MINOR) >= \ 46 ((major) * MAJOR + (minor) * MINOR + (patchlevel))) 47#else 48#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) 0 49#endif 50 51 52#if defined(__clang__) && !defined(VIXL_NO_COMPILER_BUILTINS) 53 54#define COMPILER_HAS_BUILTIN_CLRSB (__has_builtin(__builtin_clrsb)) 55#define COMPILER_HAS_BUILTIN_CLZ (__has_builtin(__builtin_clz)) 56#define COMPILER_HAS_BUILTIN_CTZ (__has_builtin(__builtin_ctz)) 57#define COMPILER_HAS_BUILTIN_FFS (__has_builtin(__builtin_ffs)) 58#define COMPILER_HAS_BUILTIN_POPCOUNT (__has_builtin(__builtin_popcount)) 59 60#elif defined(__GNUC__) && !defined(VIXL_NO_COMPILER_BUILTINS) 61// The documentation for these builtins is available at: 62// https://gcc.gnu.org/onlinedocs/gcc-$MAJOR.$MINOR.$PATCHLEVEL/gcc//Other-Builtins.html 63 64# define COMPILER_HAS_BUILTIN_CLRSB (GCC_VERSION_OR_NEWER(4, 7, 0)) 65# define COMPILER_HAS_BUILTIN_CLZ (GCC_VERSION_OR_NEWER(3, 4, 0)) 66# define COMPILER_HAS_BUILTIN_CTZ (GCC_VERSION_OR_NEWER(3, 4, 0)) 67# define COMPILER_HAS_BUILTIN_FFS (GCC_VERSION_OR_NEWER(3, 4, 0)) 68# define COMPILER_HAS_BUILTIN_POPCOUNT (GCC_VERSION_OR_NEWER(3, 4, 0)) 69 70#else 71// One can define VIXL_NO_COMPILER_BUILTINS to force using the manually 72// implemented C++ methods. 73 74#define COMPILER_HAS_BUILTIN_BSWAP false 75#define COMPILER_HAS_BUILTIN_CLRSB false 76#define COMPILER_HAS_BUILTIN_CLZ false 77#define COMPILER_HAS_BUILTIN_CTZ false 78#define COMPILER_HAS_BUILTIN_FFS false 79#define COMPILER_HAS_BUILTIN_POPCOUNT false 80 81#endif 82 83 84template<typename V> 85inline bool IsPowerOf2(V value) { 86 return (value != 0) && ((value & (value - 1)) == 0); 87} 88 89 90// Declaration of fallback functions. 91int CountLeadingSignBitsFallBack(int64_t value, int width); 92int CountLeadingZerosFallBack(uint64_t value, int width); 93int CountSetBitsFallBack(uint64_t value, int width); 94int CountTrailingZerosFallBack(uint64_t value, int width); 95 96 97// Implementation of intrinsics functions. 98// TODO: The implementations could be improved for sizes different from 32bit 99// and 64bit: we could mask the values and call the appropriate builtin. 100 101template<typename V> 102inline int CountLeadingSignBits(V value, int width = (sizeof(V) * 8)) { 103#if COMPILER_HAS_BUILTIN_CLRSB 104 if (width == 32) { 105 return __builtin_clrsb(value); 106 } else if (width == 64) { 107 return __builtin_clrsbll(value); 108 } 109#endif 110 return CountLeadingSignBitsFallBack(value, width); 111} 112 113 114template<typename V> 115inline int CountLeadingZeros(V value, int width = (sizeof(V) * 8)) { 116#if COMPILER_HAS_BUILTIN_CLZ 117 if (width == 32) { 118 return (value == 0) ? 32 : __builtin_clz(static_cast<unsigned>(value)); 119 } else if (width == 64) { 120 return (value == 0) ? 64 : __builtin_clzll(value); 121 } 122#endif 123 return CountLeadingZerosFallBack(value, width); 124} 125 126 127template<typename V> 128inline int CountSetBits(V value, int width = (sizeof(V) * 8)) { 129#if COMPILER_HAS_BUILTIN_POPCOUNT 130 if (width == 32) { 131 return __builtin_popcount(static_cast<unsigned>(value)); 132 } else if (width == 64) { 133 return __builtin_popcountll(value); 134 } 135#endif 136 return CountSetBitsFallBack(value, width); 137} 138 139 140template<typename V> 141inline int CountTrailingZeros(V value, int width = (sizeof(V) * 8)) { 142#if COMPILER_HAS_BUILTIN_CTZ 143 if (width == 32) { 144 return (value == 0) ? 32 : __builtin_ctz(static_cast<unsigned>(value)); 145 } else if (width == 64) { 146 return (value == 0) ? 64 : __builtin_ctzll(value); 147 } 148#endif 149 return CountTrailingZerosFallBack(value, width); 150} 151 152} // namespace vixl 153 154#endif // VIXL_COMPILER_INTRINSICS_H 155