Fixed issues with MSVC emulations of clz and clzll.

Both clang-cl and Clang/C2 #define _MSC_VER but also have support for __builtin_clz and __builtin_clzll, leading to duplicate macro definition warnings. Emulation of clz using _BitScanReverse is suppressed if the builtins are already available.

Additionally, the value of the output parameter of _BitScanReverse is undefined if the input value is 0, which is avoided by construction, so the code analysis warning for using uninitialized data is now suppressed.
This commit is contained in:
Michael Winterberg 2016-01-05 16:03:06 -08:00
parent 251a0869be
commit 7185e96da1

View File

@ -75,7 +75,7 @@ typedef __int64 intmax_t;
# define FMT_API # define FMT_API
#endif #endif
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER)
# include <intrin.h> // _BitScanReverse, _BitScanReverse64 # include <intrin.h> // _BitScanReverse, _BitScanReverse64
namespace fmt { namespace fmt {
@ -84,9 +84,14 @@ namespace internal {
inline uint32_t clz(uint32_t x) { inline uint32_t clz(uint32_t x) {
unsigned long r = 0; unsigned long r = 0;
_BitScanReverse(&r, x); _BitScanReverse(&r, x);
assert(x != 0);
// Static analysis complains about using uninitialized data
// "r", but the only way that can happen is if "x" is 0,
// which the callers guarantee to not happen.
#pragma warning(suppress: 6102)
return 31 - r; return 31 - r;
} }
# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
# ifdef _WIN64 # ifdef _WIN64
# pragma intrinsic(_BitScanReverse64) # pragma intrinsic(_BitScanReverse64)
@ -104,9 +109,14 @@ inline uint32_t clzll(uint64_t x) {
// Scan the low 32 bits. // Scan the low 32 bits.
_BitScanReverse(&r, static_cast<uint32_t>(x)); _BitScanReverse(&r, static_cast<uint32_t>(x));
# endif # endif
assert(x != 0);
// Static analysis complains about using uninitialized data
// "r", but the only way that can happen is if "x" is 0,
// which the callers guarantee to not happen.
#pragma warning(suppress: 6102)
return 63 - r; return 63 - r;
} }
# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
} }
} }
#endif #endif
@ -801,6 +811,23 @@ typedef BasicData<> Data;
# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
#endif #endif
#if defined(_MSC_VER)
// Some compilers masquerade as both MSVC and GCC-likes or
// otherwise support __builtin_clz and __builtin_clzll, so
// only define FMT_BUILTIN_CLZ using the MSVC intrinsics
// if the clz and clzll builtins are not available.
#if !defined(FMT_BUILTIN_CLZ)
# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
#endif
#if !defined(FMT_BUILTIN_CLZLL)
# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
#endif
#endif
#ifdef FMT_BUILTIN_CLZLL #ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted // Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1. // except for n == 0 in which case count_digits returns 1.