浏览代码

HPCC-12708 Optimize jset and provide countTrailingZeros() helpers

Signed-off-by: Gavin Halliday <gavin.halliday@lexisnexis.com>
Gavin Halliday 10 年之前
父节点
当前提交
025fb2e836
共有 2 个文件被更改,包括 84 次插入67 次删除
  1. 36 67
      system/jlib/jset.cpp
  2. 48 0
      system/jlib/jset.hpp

+ 36 - 67
system/jlib/jset.cpp

@@ -84,91 +84,60 @@ protected:
         unsigned j=from%BitsPerItem;
         // returns index of first = val >= from
         unsigned n=getWidth();
-        unsigned i;
-        for (i=from/BitsPerItem;i<n;i++)
+        unsigned i = from/BitsPerItem;
+        if (j != 0 && i < n)
         {
             bits_t m = getBits(i);
             if (m!=noMatchMask)
             {
-#if defined(__GNUC__)
-                //Use the __builtin_ffs instead of a loop to find the first bit set/cleared
-                bits_t testMask = m;
-                if (j != 0)
-                {
-                    //Set all the bottom bits to the value we're not searching for
-                    bits_t mask = (((bits_t)1)<<j)-1;
-                    if (tst)
-                        testMask &= ~mask;
-                    else
-                        testMask |= mask;
+                //Evaluate (testMask = tst ? m : ~m); without using a conditional.
+                //After this bits will be set wherever we want a match
+                bits_t testMask = m ^ noMatchMask;
 
-                    //May possibly match exactly - if so continue main loop
-                    if (testMask==noMatchMask)
-                    {
-                        j = 0;
-                        continue;
-                    }
-                }
+                //Clear all the bottom bits
+                bits_t mask = (((bits_t)1)<<j)-1;
+                testMask &= ~mask;
 
-                //Guaranteed a match at this point
-                if (tst)
+                //May possibly be empty now ignored bits are removed - if so continue main loop
+                if (testMask != 0)
                 {
-                    //Returns one plus the index of the least significant 1-bit of testMask
+                    //Guaranteed a match at this point
+                    //Returns one the index of the least significant 1-bit of testMask
                     //(testMask != 0) since that has been checked above (noMatchMask == 0)
-                    unsigned pos = __builtin_ffs(testMask)-1;
+                    unsigned pos = countTrailingZeros(testMask);
                     if (scninv)
                     {
                         bits_t t = ((bits_t)1)<<pos;
-                        m &= ~t;
+                        m ^= t;
                         setBits(i, m);
                     }
                     return i*BitsPerItem+pos;
                 }
-                else
-                {
-                    //Same as above but invert the bitmask
-                    unsigned pos = __builtin_ffs(~testMask)-1;
-                    if (scninv)
-                    {
-                        bits_t t = ((bits_t)1)<<pos;
-                        m |= t;
-                        setBits(i, m);
-                    }
-                    return i*BitsPerItem+pos;
-                }
-#else
-                bits_t t = ((bits_t)1)<<j;
-                for (;j<BitsPerItem;j++)
+            }
+            j = 0;
+            i++;
+        }
+        for (;i<n;i++)
+        {
+            bits_t m = getBits(i);
+            if (m!=noMatchMask)
+            {
+                //Evaluate (testMask = tst ? m : ~m); without using a conditional.
+                //After this bits will be set wherever we want a match
+                bits_t testMask = m ^ noMatchMask;
+
+                //Guaranteed a match at this point
+                //Returns one the index of the least significant 1-bit of testMask
+                //(testMask != 0) since that has been checked above (noMatchMask == 0)
+                unsigned pos = countTrailingZeros(testMask);
+                if (scninv)
                 {
-                    if (t&m)
-                    {
-                        if (tst)
-                        {
-                            if (scninv)
-                            {
-                                m &= ~t;
-                                setBits(i, m);
-                            }
-                            return i*BitsPerItem+j;
-                        }
-                    }
-                    else
-                    {
-                        if (!tst)
-                        {
-                            if (scninv)
-                            {
-                                m |= t;
-                                setBits(i, m);
-                            }
-                            return i*BitsPerItem+j;
-                        }
-                    }
-                    t <<= 1;
+                    bits_t t = ((bits_t)1)<<pos;
+                    m ^= t;
+                    setBits(i, m);
                 }
-#endif
+                return i*BitsPerItem+pos;
             }
-            j = 0;
         }
         if (tst)
             return (unsigned)-1;

+ 48 - 0
system/jlib/jset.hpp

@@ -22,7 +22,55 @@
 
 #include "jiface.hpp"
 
+#if defined (_WIN32)
+#include <intrin.h>
+#endif
+
+//Return the nunber of trailing zeros. Deliberately undefined if value == 0
+inline unsigned countTrailingZeros(unsigned value)
+{
+    dbgassertex(value != 0);
+#if defined(__GNUC__)
+    return __builtin_ctz(value);
+#elif defined (_WIN32)
+    unsigned long index;
+    _BitScanForward(&index, value);
+    return (unsigned)index;
+#else
+    unsigned mask = 1U;
+    unsigned i;
+    for (i=0; i < sizeof(unsigned)*8; i++)
+    {
+        if (value & mask)
+            return i;
+        mask = mask << 1;
+    }
+    return i;
+#endif
+}
 
+//Return the nunber of leading zeros. Deliberately undefined if value == 0
+inline unsigned countLeadingZeros(unsigned value)
+{
+    dbgassertex(value != 0);
+#if defined(__GNUC__)
+    return __builtin_clz(value);
+#elif defined (_WIN32)
+    unsigned long index;
+    _BitScanReverse(&index, value);
+    return (unsigned)index;
+#else
+    unsigned mask = 1U << 31;
+    unsigned i;
+    for (i=0; i < sizeof(unsigned)*8; i++)
+    {
+        if (value & mask)
+            return i;
+        mask = mask >> 1;
+    }
+    return i;
+#endif
+}
 
 interface jlib_decl IBitSet : public IInterface 
 {