]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Consistent, unambiguous, non-colliding bit function names
authorVMware, Inc <>
Thu, 17 Jun 2010 21:20:34 +0000 (14:20 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Thu, 17 Jun 2010 21:20:34 +0000 (14:20 -0700)
We don't have complete set of find most/least significant bit
set functions available throughout the source base. Create them.

I created these functions by taking the monitor's complete set of
functions, moving them to vm_basic_asm.h and renaming them such that
they have consistent, unambiguous names that don't collide with ANSI,
Linux or MacOS functions or differ in data types. The immediately
problematic functions were ffs, fls, ffsl, flsl and fls64.

Here is a table to assist with reviewing the change:

NAME      FUNCTION               BITS          ON ZERO    MONITOR NAME
-----     --------               ----          -------    ------------
lssb32    LSB set (uint32)       1..32         0          ffs
lssb32_0  LSB set (uint32)       0..31         -1         ffs0
lssb64    LSB set (uint64)       1..64         0          ffs64
lssb64_0  LSB set (uint64)       0..63         -1
lssbPtr   LSB set (uintptr_t)    1..32|64      0          ffsl
lssbPtr_0 LSB set (uintptr_t)    0..31|63      -1         ffs0l
mssb32    MSB set (uint32)       1..32         0          fls
mssb32_0  MSB set (uint32)       0..31         -1         fls0
mssb64    MSB set (uint64)       1..64         0          fls64
mssb64_0  MSB set (uint64)       0..63         -1
mssbPtr   MSB set (uintptr_t)    1..32|64      0          flsl
mssbPtr_0 MSB set (uintptr_t)    0..31|63      -1         fls0l

This change is the first of several. It establishes the functions and
make one use of them in an obvious, easy place.

I'll start converting the source base to use these functions in pieces.
The monitor will be the last piece touched and there I'll demonstrate
no size or performance changes - and correctness too.

In the end the entire source base will be using the one consistent set
of bit functions.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/lib/include/vm_basic_asm.h

index 9e19843440716d35d88917586d352bcf415079e0..08af6813afde3f68d9e77ce06c9c4fae40993f6c 100644 (file)
@@ -60,7 +60,6 @@
 #include "vm_basic_asm_x86.h"
 #endif
 
-
 /*
  * x86-64 windows doesn't support inline asm so we have to use these
  * intrinsic functions defined in the compiler.  Not all of these are well
@@ -101,20 +100,20 @@ void _ReadWriteBarrier(void);
  * intrinsic functions only supported by x86-64 windows as of 2k3sp1
  */
 unsigned __int64 __rdtsc(void);
-void             __stosw(unsigned short*, unsigned short, size_t);
-void             __stosd(unsigned long*, unsigned long, size_t);
-#pragma intrinsic(__rdtsc, __stosw, __stosd)
-
-/*
- * intrinsic functions supported by x86-64 windows and newer x86
- * compilers (13.01.2035 for _BitScanForward).
- */
-unsigned char  _BitScanForward(unsigned long*, unsigned long);
-unsigned char  _BitScanReverse(unsigned long*, unsigned long);
-void           _mm_pause(void);
-#pragma intrinsic(_BitScanForward, _BitScanReverse, _mm_pause)
+void             __stosw(unsigned short *, unsigned short, size_t);
+void             __stosd(unsigned long *, unsigned long, size_t);
+void             _mm_pause(void);
+#pragma intrinsic(__rdtsc, __stosw, __stosd, _mm_pause)
+
+unsigned char  _BitScanForward64(unsigned long *, unsigned __int64);
+unsigned char  _BitScanReverse64(unsigned long *, unsigned __int64);
+#pragma intrinsic(_BitScanForward64, _BitScanReverse64)
 #endif /* VM_X86_64 */
 
+unsigned char  _BitScanForward(unsigned long *, unsigned long);
+unsigned char  _BitScanReverse(unsigned long *, unsigned long);
+#pragma intrinsic(_BitScanForward, _BitScanReverse)
+
 #ifdef __cplusplus
 }
 #endif
@@ -232,39 +231,248 @@ OUT32(uint16 port, uint32 value)
    __GET_EAX_FROM_CPUID(1),                     \
    __GET_MSR(MSR_BIOS_SIGN_ID))
 
-#ifdef _MSC_VER   
+/*
+ * Locate most and least significant bit set functions. Use our own name
+ * space to avoid namespace collisions. The new names follow a pattern,
+ * <prefix><size><option>, where:
+ *
+ * <prefix> is [lm]ssb (least/most significant bit set)
+ * <size> is size of the argument: 32 (32-bit), 64 (64-bit) or Ptr (pointer)
+ * <option> is for alternative versions of the functions
+ *
+ * NAME        FUNCTION                    BITS     FUNC(0)
+ *-----        --------                    ----     -------
+ * lssb32_0    LSB set (uint32)            0..31    -1
+ * mssb32_0    MSB set (uint32)            0..31    -1
+ * lssb64_0    LSB set (uint64)            0..63    -1
+ * mssb64_0    MSB set (uint64)            0..63    -1
+ * lssbPtr_0   LSB set (uintptr_t;32-bit)  0..31    -1
+ * lssbPtr_0   LSB set (uintptr_t;64-bit)  0..63    -1
+ * mssbPtr_0   MSB set (uintptr_t;32-bit)  0..31    -1
+ * mssbPtr_0   MSB set (uintptr_t;64-bit)  0..63    -1
+ * lssbPtr     LSB set (uintptr_t;32-bit)  1..32    0
+ * lssbPtr     LSB set (uintptr_t;64-bit)  1..64    0
+ * mssbPtr     MSB set (uintptr_t;32-bit)  1..32    0
+ * mssbPtr     MSB set (uintptr_t;64-bit)  1..64    0
+ * lssb32      LSB set (uint32)            1..32    0
+ * mssb32      MSB set (uint32)            1..32    0
+ * lssb64      LSB set (uint64)            1..64    0
+ * mssb64      MSB set (uint64)            1..64    0
+ */
+
+#if defined(_MSC_VER)
 static INLINE int
-ffs(uint32 bitVector)
+lssb32_0(const uint32 value)
 {
-   int idx;
-   if (!bitVector) {
-      return 0;
+   unsigned long idx;
+   if (UNLIKELY(value == 0)) {
+      return -1;
    }
-#ifdef VM_X86_64
-   _BitScanForward((unsigned long*)&idx, (unsigned long)bitVector);
+   _BitScanForward(&idx, (unsigned long) value);
+   return idx;
+}
+
+static INLINE int
+mssb32_0(const uint32 value)
+{
+   unsigned long idx;
+   if (UNLIKELY(value == 0)) {
+      return -1;
+   }
+   _BitScanReverse(&idx, (unsigned long) value);
+   return idx;
+}
+
+static INLINE int
+lssb64_0(const uint64 value)
+{
+   if (UNLIKELY(value == 0)) {
+      return -1;
+   } else {
+#if defined(VM_X86_64)
+      unsigned long idx;
+      _BitScanForward64(&idx, (unsigned __int64) value);
+      return idx;
 #else
-   __asm bsf eax, bitVector
-   __asm mov idx, eax
+      /* The coding was chosen to minimize conditionals and operations */
+      int lowFirstBit = lssb32_0((uint32) value);
+      if (lowFirstBit == -1) {
+         lowFirstBit = lssb32_0((uint32) (value >> 32));
+         if (lowFirstBit != -1) {
+            return lowFirstBit + 32;
+         }
+      }
+      return lowFirstBit;
 #endif
-   return idx+1;
+   }
 }
 
 static INLINE int
-fls(uint32 bitVector)
+mssb64_0(const uint64 value)
 {
-   int idx;
-   if (!bitVector) {
-      return 0;
+   if (UNLIKELY(value == 0)) {
+      return -1;
+   } else {
+#if defined(VM_X86_64)
+      unsigned long idx;
+      _BitScanReverse64(&idx, (unsigned __int64) value);
+      return idx;
+#else
+      /* The coding was chosen to minimize conditionals and operations */
+      if (value > 0xFFFFFFFFULL) {
+         return 32 + mssb32_0((uint32) (value >> 32));
+      }
+      return mssb32_0((uint32) value);
+#endif
    }
-#ifdef VM_X86_64
-   _BitScanReverse((unsigned long*)&idx, (unsigned long)bitVector);
+}
+
+static INLINE int
+ffs(uint32 value)
+{
+   return lssb32_0(value) + 1;  // temporary alias
+}
+
+static INLINE int
+fls(uint32 value)
+{
+   return mssb32_0(value) + 1;  // temporary alias
+}
+#endif
+
+#if defined(__GNUC__)
+#if defined(__i386__) || defined(__x86_64__)
+static INLINE int
+lssb32_0(uint32 value)
+{
+   if (UNLIKELY(value == 0)) {
+      return -1;
+   } else {
+      int pos;
+      __asm__ __volatile__("bsfl %1, %0\n" : "=r" (pos) : "rm" (value) : "cc");
+      return pos;
+   }
+}
+
+static INLINE int
+mssb32_0(uint32 value)
+{
+   if (UNLIKELY(value == 0)) {
+      return -1;
+   } else {
+      int pos;
+      __asm__ __volatile__("bsrl %1, %0\n" : "=r" (pos) : "rm" (value) : "cc");
+      return pos;
+   }
+}
+
+static INLINE int
+lssb64_0(const uint64 value)
+{
+   if (UNLIKELY(value == 0)) {
+      return -1;
+   } else {
+#if defined(VM_X86_64)
+      intptr_t pos;
+      __asm__ __volatile__("bsf %1, %0\n" : "=r" (pos) : "rm" (value) : "cc");
+      return pos;
 #else
-   __asm bsr eax, bitVector
-   __asm mov idx, eax
+      /* The coding was chosen to minimize conditionals and operations */
+      int lowFirstBit = lssb32_0((uint32) value);
+      if (lowFirstBit == -1) {
+         lowFirstBit = lssb32_0((uint32) (value >> 32));
+         if (lowFirstBit != -1) {
+            return lowFirstBit + 32;
+         }
+      }
+      return lowFirstBit;
 #endif
-   return idx+1;
+   }
+}
+
+static INLINE int
+mssb64_0(const uint64 value)
+{
+   if (UNLIKELY(value == 0)) {
+      return -1;
+   } else {
+      /* Replace body of else with "64 - __builtin_clzll(value) - 1"? */
+#if defined(VM_X86_64)
+      intptr_t pos;
+      __asm__ __volatile__("bsr %1, %0\n" : "=r" (pos) : "rm" (value) : "cc");
+      return pos;
+#else
+      /* The coding was chosen to minimize conditionals and operations */
+      if (value > 0xFFFFFFFFULL) {
+         return 32 + mssb32_0((uint32) (value >> 32));
+      }
+      return mssb32_0((uint32) value);
+#endif
+   }
+}
+#endif
+
+/*
+ * ARM and other architectures will live here, implementing the 4 basic
+ * functions.
+ */
+#endif
+
+static INLINE int
+lssbPtr_0(const uintptr_t value)
+{
+#if defined(VM_X86_64)
+   return lssb64_0((uint64) value);
+#else
+   return lssb32_0((uint32) value);
+#endif
+}
+
+static INLINE int
+lssbPtr(const uintptr_t value)
+{
+   return lssbPtr_0(value) + 1;
 }
+
+static INLINE int
+mssbPtr_0(const uintptr_t value)
+{
+#if defined(VM_X86_64)
+   return mssb64_0((uint64) value);
+#else
+   return mssb32_0((uint32) value);
 #endif
+}
+
+static INLINE int
+mssbPtr(const uintptr_t value)
+{
+   return mssbPtr_0(value) + 1;
+}
+
+static INLINE int
+lssb32(const uint32 value)
+{
+   return lssb32_0(value) + 1;
+}
+
+static INLINE int
+mssb32(const uint32 value)
+{
+   return mssb32_0(value) + 1;
+}
+
+static INLINE int
+lssb64(const uint64 value)
+{
+   return lssb64_0(value) + 1;
+}
+
+static INLINE int
+mssb64(const uint64 value)
+{
+   return mssb64_0(value) + 1;
+}
 
 #ifdef __GNUC__
 #if defined(__i386__) || defined(__x86_64__)