Skip to content

Commit c179d81

Browse files
authored
Make __builtin_clz/__builtin_clzll constexpr to match gcc/clang (#136)
1 parent 1e03581 commit c179d81

File tree

1 file changed

+48
-22
lines changed

1 file changed

+48
-22
lines changed

libdivide.h

+48-22
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
#include <stdlib.h>
2525
#endif
2626

27+
#if defined(_MSC_VER) && (defined(__cplusplus) && (__cplusplus >= 202002L)) || \
28+
(defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L))
29+
#include <limits.h>
30+
#include <type_traits>
31+
#define LIBDIVIDE_VC_CXX20
32+
#endif
33+
2734
#if defined(LIBDIVIDE_SSE2)
2835
#include <emmintrin.h>
2936
#endif
@@ -126,11 +133,42 @@
126133
#endif
127134

128135
#ifdef __cplusplus
136+
137+
// For constexpr zero initialization, c++11 might handle things ok,
138+
// but just limit to at least c++14 to ensure we don't break anyone's code:
139+
140+
// for gcc and clang, use https://en.cppreference.com/w/cpp/feature_test#cpp_constexpr
141+
#if (defined(__GNUC__) || defined(__clang__)) && (__cpp_constexpr >= 201304L)
142+
#define LIBDIVIDE_CONSTEXPR constexpr LIBDIVIDE_INLINE
143+
144+
// Supposedly, MSVC might not implement feature test macros right (https://stackoverflow.com/questions/49316752/feature-test-macros-not-working-properly-in-visual-c)
145+
// so check that _MSVC_LANG corresponds to at least c++14, and _MSC_VER corresponds to at least VS 2017 15.0 (for extended constexpr support https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-170)
146+
#elif defined(_MSC_VER) && _MSC_VER >= 1910 && defined(_MSVC_LANG) && _MSVC_LANG >=201402L
147+
#define LIBDIVIDE_CONSTEXPR constexpr LIBDIVIDE_INLINE
148+
149+
// in case some other obscure compiler has the right __cpp_constexpr :
150+
#elif defined(__cpp_constexpr) && __cpp_constexpr >= 201304L
151+
#define LIBDIVIDE_CONSTEXPR constexpr LIBDIVIDE_INLINE
152+
153+
#else
154+
#define LIBDIVIDE_CONSTEXPR LIBDIVIDE_INLINE
155+
#endif
156+
129157
namespace libdivide {
130158
#endif
131159

132160
#if defined(_MSC_VER) && !defined(__clang__)
161+
#if defined(LIBDIVIDE_VC_CXX20)
162+
static LIBDIVIDE_CONSTEXPR int __builtin_clz(unsigned x) {
163+
if (std::is_constant_evaluated()) {
164+
for (int i = 0; i < sizeof(x) * CHAR_BIT; ++i) {
165+
if (x >> (sizeof(x) * CHAR_BIT - 1 - i)) return i;
166+
}
167+
return sizeof(x) * CHAR_BIT;
168+
}
169+
#else
133170
static LIBDIVIDE_INLINE int __builtin_clz(unsigned x) {
171+
#endif
134172
#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC)
135173
return (int)_CountLeadingZeros(x);
136174
#elif defined(__AVX2__) || defined(__LZCNT__)
@@ -142,7 +180,17 @@ static LIBDIVIDE_INLINE int __builtin_clz(unsigned x) {
142180
#endif
143181
}
144182

183+
#if defined(LIBDIVIDE_VC_CXX20)
184+
static LIBDIVIDE_CONSTEXPR int __builtin_clzll(unsigned long long x) {
185+
if (std::is_constant_evaluated()) {
186+
for (int i = 0; i < sizeof(x) * CHAR_BIT; ++i) {
187+
if (x >> (sizeof(x) * CHAR_BIT - 1 - i)) return i;
188+
}
189+
return sizeof(x) * CHAR_BIT;
190+
}
191+
#else
145192
static LIBDIVIDE_INLINE int __builtin_clzll(unsigned long long x) {
193+
#endif
146194
#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC)
147195
return (int)_CountLeadingZeros64(x);
148196
#elif defined(_WIN64)
@@ -3018,28 +3066,6 @@ __m128i libdivide_s64_branchfree_do_vec128(
30183066

30193067
#ifdef __cplusplus
30203068

3021-
//for constexpr zero initialization,
3022-
//c++11 might handle things ok,
3023-
//but just limit to at least c++14 to ensure
3024-
//we don't break anyone's code:
3025-
3026-
// for gcc and clang, use https://en.cppreference.com/w/cpp/feature_test#cpp_constexpr
3027-
#if (defined(__GNUC__) || defined(__clang__)) && (__cpp_constexpr >= 201304L)
3028-
#define LIBDIVIDE_CONSTEXPR constexpr
3029-
3030-
// supposedly, MSVC might not implement feature test macros right (https://stackoverflow.com/questions/49316752/feature-test-macros-not-working-properly-in-visual-c)
3031-
// so check that _MSVC_LANG corresponds to at least c++14, and _MSC_VER corresponds to at least VS 2017 15.0 (for extended constexpr support https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-170)
3032-
#elif defined(_MSC_VER) && _MSC_VER >= 1910 && defined(_MSVC_LANG) && _MSVC_LANG >=201402L
3033-
#define LIBDIVIDE_CONSTEXPR constexpr
3034-
3035-
// in case some other obscure compiler has the right __cpp_constexpr :
3036-
#elif defined(__cpp_constexpr) && __cpp_constexpr >= 201304L
3037-
#define LIBDIVIDE_CONSTEXPR constexpr
3038-
3039-
#else
3040-
#define LIBDIVIDE_CONSTEXPR LIBDIVIDE_INLINE
3041-
#endif
3042-
30433069
enum Branching {
30443070
BRANCHFULL, // use branching algorithms
30453071
BRANCHFREE // use branchfree algorithms

0 commit comments

Comments
 (0)