diff options
Diffstat (limited to 'src/gc/env/gcenv.base.h')
-rw-r--r-- | src/gc/env/gcenv.base.h | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/src/gc/env/gcenv.base.h b/src/gc/env/gcenv.base.h index da66e9b8a3..187d9ca723 100644 --- a/src/gc/env/gcenv.base.h +++ b/src/gc/env/gcenv.base.h @@ -220,8 +220,10 @@ typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(void* lpThreadParameter); #ifdef _MSC_VER #pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse) #if _WIN64 #pragma intrinsic(_BitScanForward64) + #pragma intrinsic(_BitScanReverse64) #endif #endif // _MSC_VER @@ -281,6 +283,56 @@ inline uint8_t BitScanForward64(uint32_t *bitIndex, uint64_t mask) #endif // _MSC_VER } +// Cross-platform wrapper for the _BitScanReverse compiler intrinsic. +inline uint8_t BitScanReverse(uint32_t *bitIndex, uint32_t mask) +{ +#ifdef _MSC_VER + return _BitScanReverse((unsigned long*)bitIndex, mask); +#else // _MSC_VER + // The result of __builtin_clzl is undefined when mask is zero, + // but it's still OK to call the intrinsic in that case (just don't use the output). + // Unconditionally calling the intrinsic in this way allows the compiler to + // emit branchless code for this function when possible (depending on how the + // intrinsic is implemented for the target platform). + int lzcount = __builtin_clzl(mask); + *bitIndex = static_cast<uint32_t>(31 - lzcount); + return mask != 0 ? TRUE : FALSE; +#endif // _MSC_VER +} + +// Cross-platform wrapper for the _BitScanReverse64 compiler intrinsic. +inline uint8_t BitScanReverse64(uint32_t *bitIndex, uint64_t mask) +{ +#ifdef _MSC_VER + #if _WIN64 + return _BitScanReverse64((unsigned long*)bitIndex, mask); + #else + // MSVC targeting a 32-bit target does not support this intrinsic. + // We can fake it checking whether the upper 32 bits are zeros (or not) + // then calling _BitScanReverse() on either the upper or lower 32 bits. + uint32_t upper = static_cast<uint32_t>(mask >> 32); + + if (upper != 0) + { + uint8_t result = _BitScanReverse((unsigned long*)bitIndex, upper); + *bitIndex += 32; + return result; + } + + return _BitScanReverse((unsigned long*)bitIndex, static_cast<uint32_t>(mask)); + #endif // _WIN64 +#else + // The result of __builtin_clzll is undefined when mask is zero, + // but it's still OK to call the intrinsic in that case (just don't use the output). + // Unconditionally calling the intrinsic in this way allows the compiler to + // emit branchless code for this function when possible (depending on how the + // intrinsic is implemented for the target platform). + int lzcount = __builtin_clzll(mask); + *bitIndex = static_cast<uint32_t>(63 - lzcount); + return mask != 0 ? TRUE : FALSE; +#endif // _MSC_VER +} + // Aligns a size_t to the specified alignment. Alignment must be a power // of two. inline size_t ALIGN_UP(size_t val, size_t alignment) |