summaryrefslogtreecommitdiff
path: root/src/gc/env/gcenv.base.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gc/env/gcenv.base.h')
-rw-r--r--src/gc/env/gcenv.base.h52
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)