Make "front and back" prefix accel work with MSVC.

Change-Id: Idbae09ca9a97c1f8ce08ddefd0bb2863d4deb325
Reviewed-on: https://code-review.googlesource.com/c/re2/+/56774
Reviewed-by: Paul Wankadia <junyer@google.com>
diff --git a/re2/prog.cc b/re2/prog.cc
index fdc8022..ac9c085 100644
--- a/re2/prog.cc
+++ b/re2/prog.cc
@@ -7,8 +7,11 @@
 
 #include "re2/prog.h"
 
-#if defined(__GNUC__) && defined(__AVX2__)
+#if defined(__AVX2__)
 #include <immintrin.h>
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
 #endif
 #include <stdint.h>
 #include <string.h>
@@ -913,6 +916,30 @@
   }
 }
 
+#if defined(__AVX2__)
+// Finds the least significant non-zero bit in n.
+static int FindLSBSet(uint32_t n) {
+  DCHECK_NE(n, 0);
+#if defined(__GNUC__)
+  return __builtin_ctz(n);
+#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+  unsigned long c;
+  _BitScanForward(&c, n);
+  return static_cast<int>(c);
+#else
+  int c = 31;
+  for (int shift = 1 << 4; shift != 0; shift >>= 1) {
+    uint32_t word = n << shift;
+    if (word != 0) {
+      n = word;
+      c -= shift;
+    }
+  }
+  return c;
+#endif
+}
+#endif
+
 const void* Prog::PrefixAccel_FrontAndBack(const void* data, size_t size) {
   DCHECK_GE(prefix_size_, 2);
   if (size < prefix_size_)
@@ -921,7 +948,7 @@
   // This also means that probing for prefix_back_ doesn't go out of bounds.
   size -= prefix_size_-1;
 
-#if defined(__GNUC__) && defined(__AVX2__)
+#if defined(__AVX2__)
   // Use AVX2 to look for prefix_front_ and prefix_back_ 32 bytes at a time.
   if (size >= sizeof(__m256i)) {
     const __m256i* fp = reinterpret_cast<const __m256i*>(
@@ -940,7 +967,7 @@
       if (fb_testz == 0) {  // ZF: 1 means zero, 0 means non-zero.
         const __m256i fb_and = _mm256_and_si256(f_cmpeq, b_cmpeq);
         const int fb_movemask = _mm256_movemask_epi8(fb_and);
-        const int fb_ctz = __builtin_ctz(fb_movemask);
+        const int fb_ctz = FindLSBSet(fb_movemask);
         return reinterpret_cast<const char*>(fp-1) + fb_ctz;
       }
     }