Given a helper method that does some bit manipulation and which is used sometimes at runtime and sometimes as a constexpr argument:
/// <summary>Counts the number of leading zero bits in a value</summary>
/// <param name="value">Value in which the leading zero bits will be couned</param>
/// <returns>The number of leading zero bits in the value</returns>
/// <remarks>
/// The result is undefined if the input value is 0
/// </remarks>
public: static inline constexpr unsigned char CountLeadingZeroBits(std::uint32_t value) {
#if defined(_MSC_VER)
return __lzcnt(value);
#elif defined(__clang__) || (defined(__GNUC__) || defined(__GNUG__))
return static_cast<unsigned char>(__builtin_clz(value));
#else
// https://www.chessprogramming.org/BitScan#Bitscan_reverse
// https://stackoverflow.com/questions/2589096/
const unsigned char deBruijnBitPosition[32] = {
31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
};
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return deBruijnBitPosition[(value * 0x07C4ACDDU) >> 27];
#endif
}
I am trying to optimize this method via compiler built-ins / intrinsics (already shown in the above snippet).
Whether intrinsics are usable in a constexpr setting is, of course, implementation-dependent. Of the compilers/envs I'm targeting, GCC 9.2 and clang 9.0 allow __builtin_clz()
in constexpr, MSVC 14.1 (VS2017) does not.
Is there a way my function's implementation could detect whether it is being used in a constexpr
setting (then doing manual bit manipulation) or at runtime (then using the compiler intrinsic)?
i.e.
public: static inline constexpr unsigned char CountLeadingZeroBits(std::uint32_t value) {
#if defined(_MSC_VER) && (!__method_used_as_constexpr)
return __lzcnt(value);
...