cpu_detect: Add BMI2 detection

PiperOrigin-RevId: 936046570
Change-Id: Ib79a392eee5ed11898ef1d98e2d6bbdfb3c72eab
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 53bac42..ea4db17 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -768,6 +768,20 @@
 )
 
 cc_test(
+    name = "cpu_detect_test",
+    size = "small",
+    srcs = ["internal/cpu_detect_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":config",
+        ":cpu_detect",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "low_level_alloc_test",
     size = "medium",
     srcs = ["internal/low_level_alloc_test.cc"],
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 8d5cf66..2a20d74 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -637,6 +637,19 @@
 
 absl_cc_test(
   NAME
+    cpu_detect_test
+  SRCS
+    "internal/cpu_detect_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::base_cpu_detect
+    absl::config
+    GTest::gtest_main
+)
+
+absl_cc_test(
+  NAME
     low_level_alloc_test
   SRCS
     "internal/low_level_alloc_test.cc"
diff --git a/absl/base/internal/cpu_detect.cc b/absl/base/internal/cpu_detect.cc
index c08637c..5275888 100644
--- a/absl/base/internal/cpu_detect.cc
+++ b/absl/base/internal/cpu_detect.cc
@@ -253,6 +253,16 @@
 
 bool SupportsArmCRC32PMULL() { return false; }
 
+bool SupportsBmi2() {
+  int cpu_info[4];
+  __cpuid(cpu_info, 0);
+  if (cpu_info[0] < 7) {
+    return false;
+  }
+  __cpuidex(cpu_info, 7, 0);
+  return (cpu_info[1] & (1 << 8)) != 0;
+}
+
 #elif defined(__aarch64__) && defined(__linux__)
 
 #ifndef HWCAP_CPUID
@@ -322,6 +332,8 @@
 #endif
 }
 
+bool SupportsBmi2() { return false; }
+
 #elif defined(__aarch64__) && defined(__APPLE__)
 
 CpuType GetCpuType() { return CpuType::kUnknown; }
@@ -365,12 +377,16 @@
   return true;
 }
 
+bool SupportsBmi2() { return false; }
+
 #else
 
 CpuType GetCpuType() { return CpuType::kUnknown; }
 
 bool SupportsArmCRC32PMULL() { return false; }
 
+bool SupportsBmi2() { return false; }
+
 #endif
 
 // Returns how many hardware contexts per CPU exist. Note: AMD CPUs prior to Zen
diff --git a/absl/base/internal/cpu_detect.h b/absl/base/internal/cpu_detect.h
index 5ea76ec..43c7c38 100644
--- a/absl/base/internal/cpu_detect.h
+++ b/absl/base/internal/cpu_detect.h
@@ -63,6 +63,9 @@
 // tuning.
 bool SupportsArmCRC32PMULL();
 
+// Returns whether the host CPU supports BMI2 instructions.
+bool SupportsBmi2();
+
 // Returns whether the host CPU supports simultaneous multithreading (SMT) and
 // if it is enabled.
 bool IsSMTEnabled();
diff --git a/absl/base/internal/cpu_detect_test.cc b/absl/base/internal/cpu_detect_test.cc
new file mode 100644
index 0000000..80b8b87
--- /dev/null
+++ b/absl/base/internal/cpu_detect_test.cc
@@ -0,0 +1,43 @@
+// Copyright 2026 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/cpu_detect.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+namespace {
+
+TEST(CpuDetectTest, SupportsBmi2) {
+#if defined(__x86_64__) || defined(_M_X64)
+#if ABSL_HAVE_BUILTIN(__builtin_cpu_supports) && defined(__linux__)
+  EXPECT_EQ(SupportsBmi2(), __builtin_cpu_supports("bmi2") != 0);
+#else
+  // If __builtin_cpu_supports is not available, we just verify it doesn't
+  // crash.
+  (void)SupportsBmi2();
+#endif
+#else
+  // On non-x86, SupportsBmi2() must return false.
+  EXPECT_FALSE(SupportsBmi2());
+#endif
+}
+
+}  // namespace
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl