[libcxx-commits] [libcxx] [libcxx] enable AltiVec vectorization with element-wise comparison wrapper (PR #207832)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jul 6 22:18:17 PDT 2026


https://github.com/Himadhith updated https://github.com/llvm/llvm-project/pull/207832

>From 451c89af5f6abf5927e6cbf0620e78479399694a Mon Sep 17 00:00:00 2001
From: himadhith <himadhith.v at ibm.com>
Date: Mon, 6 Jul 2026 19:37:14 +0530
Subject: [PATCH 1/4] [libcxx] enable AltiVec vectorization with element-wise
 comparison wrapper

---
 libcxx/include/__algorithm/find.h             |  6 ++--
 libcxx/include/__algorithm/mismatch.h         |  6 ++--
 libcxx/include/__algorithm/simd_utils.h       | 34 +++++++++++++++++--
 .../include/__cxx03/__algorithm/simd_utils.h  |  3 +-
 libcxx/include/__locale_dir/num.h             |  2 +-
 .../algorithms/vectorization.compile.pass.cpp |  3 --
 6 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h
index f677fb2c7392d..94087fb4afe78 100644
--- a/libcxx/include/__algorithm/find.h
+++ b/libcxx/include/__algorithm/find.h
@@ -81,7 +81,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find_vectorized(_Tp* __first, _Tp* __last,
         __lhs[__i] = std::__load_vector<__vec>(__first + __i * __vec_size);
 
       for (size_t __i = 0; __i != __unroll_count; ++__i) {
-        if (auto __cmp_res = __lhs[__i] == __values; std::__any_of(__cmp_res)) {
+        if (auto __cmp_res = std::__simd_compare_eq(__lhs[__i], __values); std::__any_of(__cmp_res)) {
           auto __offset = __i * __vec_size + std::__find_first_set(__cmp_res);
           return __first + __offset;
         }
@@ -92,7 +92,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find_vectorized(_Tp* __first, _Tp* __last,
 
     // check the remaining 0-3 vectors
     while (static_cast<size_t>(__last - __first) >= __vec_size) {
-      if (auto __cmp_res = std::__load_vector<__vec>(__first) == __values; std::__any_of(__cmp_res)) {
+      if (auto __cmp_res = std::__simd_compare_eq(std::__load_vector<__vec>(__first), __values); std::__any_of(__cmp_res)) {
         return __first + std::__find_first_set(__cmp_res);
       }
       __first += __vec_size;
@@ -105,7 +105,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find_vectorized(_Tp* __first, _Tp* __last,
     // (last - vector_size) to check the remaining elements
     if (static_cast<size_t>(__first - __orig_first) >= __vec_size) {
       __first = __last - __vec_size;
-      return __first + std::__find_first_set(std::__load_vector<__vec>(__first) == __values);
+      return __first + std::__find_first_set(std::__simd_compare_eq(std::__load_vector<__vec>(__first), __values));
     }
   }
 
diff --git a/libcxx/include/__algorithm/mismatch.h b/libcxx/include/__algorithm/mismatch.h
index 7111cd9398838..aba1e111ce470 100644
--- a/libcxx/include/__algorithm/mismatch.h
+++ b/libcxx/include/__algorithm/mismatch.h
@@ -78,7 +78,7 @@ __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) {
       }
 
       for (size_t __i = 0; __i != __unroll_count; ++__i) {
-        if (auto __cmp_res = __lhs[__i] == __rhs[__i]; !std::__all_of(__cmp_res)) {
+        if (auto __cmp_res = std::__simd_compare_eq(__lhs[__i], __rhs[__i]); !std::__all_of(__cmp_res)) {
           auto __offset = __i * __vec_size + std::__find_first_not_set(__cmp_res);
           return {__first1 + __offset, __first2 + __offset};
         }
@@ -90,7 +90,7 @@ __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) {
 
     // check the remaining 0-3 vectors
     while (static_cast<size_t>(__last1 - __first1) >= __vec_size) {
-      if (auto __cmp_res = std::__load_vector<__vec>(__first1) == std::__load_vector<__vec>(__first2);
+      if (auto __cmp_res = std::__simd_compare_eq(std::__load_vector<__vec>(__first1), std::__load_vector<__vec>(__first2));
           !std::__all_of(__cmp_res)) {
         auto __offset = std::__find_first_not_set(__cmp_res);
         return {__first1 + __offset, __first2 + __offset};
@@ -108,7 +108,7 @@ __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) {
       __first1 = __last1 - __vec_size;
       __first2 = __last2 - __vec_size;
       auto __offset =
-          std::__find_first_not_set(std::__load_vector<__vec>(__first1) == std::__load_vector<__vec>(__first2));
+          std::__find_first_not_set(std::__simd_compare_eq(std::__load_vector<__vec>(__first1), std::__load_vector<__vec>(__first2)));
       return {__first1 + __offset, __first2 + __offset};
     } // else loop over the elements individually
   }
diff --git a/libcxx/include/__algorithm/simd_utils.h b/libcxx/include/__algorithm/simd_utils.h
index c47f79ac7f1dd..95da2066f44ae 100644
--- a/libcxx/include/__algorithm/simd_utils.h
+++ b/libcxx/include/__algorithm/simd_utils.h
@@ -25,8 +25,13 @@
 _LIBCPP_PUSH_MACROS
 #include <__undef_macros>
 
-// TODO: Find out how altivec changes things and allow vectorizations there too.
-#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_COMPILER_CLANG_BASED) && !defined(__ALTIVEC__)
+// AltiVec changes the semantics of vector comparisons: in `-faltivec-src-compat=xl`
+// mode, == on vector types yields a scalar bool rather than an element-wise mask,
+// which silently breaks the mask-based algorithms below. We enable vectorization on
+// AIX (where we can enforce the correct mode via a static_assert) but leave other
+// AltiVec platforms disabled until they are explicitly validated.
+#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_COMPILER_CLANG_BASED) &&                                                 \
+    (!defined(__ALTIVEC__) || defined(_AIX))
 #  define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 1
 #else
 #  define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 0
@@ -76,7 +81,7 @@ using __get_as_integer_type_t _LIBCPP_NODEBUG = typename __get_as_integer_type_i
 #  if defined(__AVX__) || defined(__MVS__)
 template <class _Tp>
 inline constexpr size_t __native_vector_size = 32 / sizeof(_Tp);
-#  elif defined(__SSE__) || defined(__ARM_NEON)
+#  elif defined(__SSE__) || defined(__ARM_NEON) || defined(__ALTIVEC__)
 template <class _Tp>
 inline constexpr size_t __native_vector_size = 16 / sizeof(_Tp);
 #  elif defined(__MMX__)
@@ -126,6 +131,29 @@ template <class _VecT, size_t _Np, class _Iter>
 }
 _LIBCPP_DIAGNOSTIC_POP
 
+// On targets with Altivec (PowerPC), the == operator on __ext_vector_type__
+// vectors produces a deprecated vector bool result under the old XL compat mode.
+// Centralise the comparison here so the suppression is in one place.
+_LIBCPP_DIAGNOSTIC_PUSH
+_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated-altivec-src-compat")
+template <class _Tp, size_t _Np>
+[[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI __simd_vector<_Tp, _Np>
+__simd_compare_eq(__simd_vector<_Tp, _Np> __lhs, __simd_vector<_Tp, _Np> __rhs) noexcept {
+  return __lhs == __rhs;
+}
+_LIBCPP_DIAGNOSTIC_POP
+
+#  if defined(__ALTIVEC__)
+// In -faltivec-src-compat=xl mode, == on vector types returns a scalar bool,
+// which silently breaks the mask-based algorithms below. Refuse to compile in
+// that mode rather than produce wrong results.
+static_assert(sizeof(std::__simd_compare_eq(std::declval<__simd_vector<int, 4>>(),
+                                             std::declval<__simd_vector<int, 4>>())) ==
+                  sizeof(__simd_vector<int, 4>),
+              "libc++'s vectorized algorithms require element-wise vector comparison semantics. "
+              "Compile with -faltivec-src-compat=mixed or -faltivec-src-compat=gcc (not =xl).");
+#  endif
+
 template <class _Tp, size_t _Np>
 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __any_of(__simd_vector<_Tp, _Np> __vec) noexcept {
   return __builtin_reduce_or(__builtin_convertvector(__vec, __simd_vector<bool, _Np>));
diff --git a/libcxx/include/__cxx03/__algorithm/simd_utils.h b/libcxx/include/__cxx03/__algorithm/simd_utils.h
index 7b0e825afaa1f..d61a9f0524486 100644
--- a/libcxx/include/__cxx03/__algorithm/simd_utils.h
+++ b/libcxx/include/__cxx03/__algorithm/simd_utils.h
@@ -26,7 +26,8 @@
 _LIBCPP_PUSH_MACROS
 #include <__cxx03/__undef_macros>
 
-// TODO: Find out how altivec changes things and allow vectorizations there too.
+// The __cxx03 layer is a frozen C++03 ABI shim. Vectorization is handled by
+// the standard headers; do not enable it here.
 #define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 0
 
 #if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS && !defined(__OPTIMIZE_SIZE__)
diff --git a/libcxx/include/__locale_dir/num.h b/libcxx/include/__locale_dir/num.h
index 5b3b917384121..792b24e72dd09 100644
--- a/libcxx/include/__locale_dir/num.h
+++ b/libcxx/include/__locale_dir/num.h
@@ -97,7 +97,7 @@ struct __num_get : protected __num_get_base {
       _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi")
       using __vec   = __simd_vector<char, 32>;
       __vec __cmp   = std::__partial_load<__vec, __int_chr_cnt>(__atoms);
-      auto __res    = __vec(__val) == __cmp;
+      auto __res    = std::__simd_compare_eq(__vec(__val), __cmp);
       if (std::__none_of(__res))
         return __int_chr_cnt;
       return std::min(__int_chr_cnt, std::__find_first_set(__res));
diff --git a/libcxx/test/libcxx/algorithms/vectorization.compile.pass.cpp b/libcxx/test/libcxx/algorithms/vectorization.compile.pass.cpp
index 109fc78507cc4..2b6a794652630 100644
--- a/libcxx/test/libcxx/algorithms/vectorization.compile.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/vectorization.compile.pass.cpp
@@ -12,9 +12,6 @@
 // We don't vectorize algorithms before C++14
 // XFAIL: c++03, c++11
 
-// We don't vectorize algorithms on AIX right now.
-// XFAIL: target={{.+}}-aix{{.*}}
-
 // This test ensures that we enable the vectorization of algorithms on the expected
 // platforms.
 

>From 9380904348d900771216519ecf3e8e03b5450896 Mon Sep 17 00:00:00 2001
From: himadhith <himadhith.v at ibm.com>
Date: Tue, 7 Jul 2026 02:08:19 +0530
Subject: [PATCH 2/4] [libcxx] use decltype for __simd_compare_eq return type
 on Altivec targets

---
 libcxx/include/__algorithm/find.h       |  3 ++-
 libcxx/include/__algorithm/mismatch.h   |  7 ++++---
 libcxx/include/__algorithm/simd_utils.h | 13 +++++++------
 3 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h
index 94087fb4afe78..c1c8f81bf3144 100644
--- a/libcxx/include/__algorithm/find.h
+++ b/libcxx/include/__algorithm/find.h
@@ -92,7 +92,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find_vectorized(_Tp* __first, _Tp* __last,
 
     // check the remaining 0-3 vectors
     while (static_cast<size_t>(__last - __first) >= __vec_size) {
-      if (auto __cmp_res = std::__simd_compare_eq(std::__load_vector<__vec>(__first), __values); std::__any_of(__cmp_res)) {
+      if (auto __cmp_res = std::__simd_compare_eq(std::__load_vector<__vec>(__first), __values);
+          std::__any_of(__cmp_res)) {
         return __first + std::__find_first_set(__cmp_res);
       }
       __first += __vec_size;
diff --git a/libcxx/include/__algorithm/mismatch.h b/libcxx/include/__algorithm/mismatch.h
index aba1e111ce470..f6e65822549b1 100644
--- a/libcxx/include/__algorithm/mismatch.h
+++ b/libcxx/include/__algorithm/mismatch.h
@@ -90,7 +90,8 @@ __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) {
 
     // check the remaining 0-3 vectors
     while (static_cast<size_t>(__last1 - __first1) >= __vec_size) {
-      if (auto __cmp_res = std::__simd_compare_eq(std::__load_vector<__vec>(__first1), std::__load_vector<__vec>(__first2));
+      if (auto __cmp_res =
+              std::__simd_compare_eq(std::__load_vector<__vec>(__first1), std::__load_vector<__vec>(__first2));
           !std::__all_of(__cmp_res)) {
         auto __offset = std::__find_first_not_set(__cmp_res);
         return {__first1 + __offset, __first2 + __offset};
@@ -107,8 +108,8 @@ __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) {
     if (static_cast<size_t>(__first1 - __orig_first1) >= __vec_size) {
       __first1 = __last1 - __vec_size;
       __first2 = __last2 - __vec_size;
-      auto __offset =
-          std::__find_first_not_set(std::__simd_compare_eq(std::__load_vector<__vec>(__first1), std::__load_vector<__vec>(__first2)));
+      auto __offset = std::__find_first_not_set(
+          std::__simd_compare_eq(std::__load_vector<__vec>(__first1), std::__load_vector<__vec>(__first2)));
       return {__first1 + __offset, __first2 + __offset};
     } // else loop over the elements individually
   }
diff --git a/libcxx/include/__algorithm/simd_utils.h b/libcxx/include/__algorithm/simd_utils.h
index 95da2066f44ae..44530d6cd8cae 100644
--- a/libcxx/include/__algorithm/simd_utils.h
+++ b/libcxx/include/__algorithm/simd_utils.h
@@ -30,8 +30,7 @@ _LIBCPP_PUSH_MACROS
 // which silently breaks the mask-based algorithms below. We enable vectorization on
 // AIX (where we can enforce the correct mode via a static_assert) but leave other
 // AltiVec platforms disabled until they are explicitly validated.
-#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_COMPILER_CLANG_BASED) &&                                                 \
-    (!defined(__ALTIVEC__) || defined(_AIX))
+#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_COMPILER_CLANG_BASED) && (!defined(__ALTIVEC__) || defined(_AIX))
 #  define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 1
 #else
 #  define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 0
@@ -134,11 +133,14 @@ _LIBCPP_DIAGNOSTIC_POP
 // On targets with Altivec (PowerPC), the == operator on __ext_vector_type__
 // vectors produces a deprecated vector bool result under the old XL compat mode.
 // Centralise the comparison here so the suppression is in one place.
+// The return type is deduced via decltype because under Altivec the comparison
+// result element type differs from the operand element type (e.g. char16_t
+// operands yield a short mask vector).
 _LIBCPP_DIAGNOSTIC_PUSH
 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated-altivec-src-compat")
 template <class _Tp, size_t _Np>
-[[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI __simd_vector<_Tp, _Np>
-__simd_compare_eq(__simd_vector<_Tp, _Np> __lhs, __simd_vector<_Tp, _Np> __rhs) noexcept {
+[[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI auto
+__simd_compare_eq(__simd_vector<_Tp, _Np> __lhs, __simd_vector<_Tp, _Np> __rhs) noexcept -> decltype(__lhs == __rhs) {
   return __lhs == __rhs;
 }
 _LIBCPP_DIAGNOSTIC_POP
@@ -148,8 +150,7 @@ _LIBCPP_DIAGNOSTIC_POP
 // which silently breaks the mask-based algorithms below. Refuse to compile in
 // that mode rather than produce wrong results.
 static_assert(sizeof(std::__simd_compare_eq(std::declval<__simd_vector<int, 4>>(),
-                                             std::declval<__simd_vector<int, 4>>())) ==
-                  sizeof(__simd_vector<int, 4>),
+                                            std::declval<__simd_vector<int, 4>>())) == sizeof(__simd_vector<int, 4>),
               "libc++'s vectorized algorithms require element-wise vector comparison semantics. "
               "Compile with -faltivec-src-compat=mixed or -faltivec-src-compat=gcc (not =xl).");
 #  endif

>From ed766f8b8eb0f7c21e511fe77cec106a009ebb55 Mon Sep 17 00:00:00 2001
From: himadhith <himadhith.v at ibm.com>
Date: Tue, 7 Jul 2026 02:34:57 +0530
Subject: [PATCH 3/4] [libcxx][AIX] add -faltivec-src-compat=mixed to fix
 vector comparisons

---
 libcxx/CMakeLists.txt                   |  3 +++
 libcxx/include/__algorithm/find.h       |  2 +-
 libcxx/include/__algorithm/mismatch.h   |  2 +-
 libcxx/include/__algorithm/simd_utils.h | 22 +++++++++-------------
 libcxx/include/__locale_dir/num.h       |  2 +-
 5 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 31aaf2977a9af..4f86542020207 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -532,6 +532,9 @@ include(HandleLibcxxFlags)
 
 if ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
   add_flags_if_supported("-mdefault-visibility-export-mapping=explicit")
+  # Required for __ext_vector_type__ comparisons to produce element-wise masks, not scalar bools (=xl default).
+  # Appended directly to LIBCXX_COMPILE_FLAGS so it applies only to the library sources, not the test suite.
+  list(APPEND LIBCXX_COMPILE_FLAGS "-faltivec-src-compat=mixed")
   set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
 endif()
 
diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h
index c1c8f81bf3144..343aec518f358 100644
--- a/libcxx/include/__algorithm/find.h
+++ b/libcxx/include/__algorithm/find.h
@@ -66,7 +66,7 @@ __find(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) {
 template <class _Tp, class _Up>
 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI
 _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find_vectorized(_Tp* __first, _Tp* __last, _Up __value) {
-  if (!__libcpp_is_constant_evaluated()) {
+  if (!__libcpp_is_constant_evaluated() && std::__altivec_has_element_wise_compare) {
     constexpr size_t __unroll_count = 4;
     constexpr size_t __vec_size     = __native_vector_size<_Tp>;
     using __vec                     = __simd_vector<_Tp, __vec_size>;
diff --git a/libcxx/include/__algorithm/mismatch.h b/libcxx/include/__algorithm/mismatch.h
index f6e65822549b1..ed9b8862953ba 100644
--- a/libcxx/include/__algorithm/mismatch.h
+++ b/libcxx/include/__algorithm/mismatch.h
@@ -65,7 +65,7 @@ __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) {
   constexpr size_t __vec_size     = __native_vector_size<__value_type>;
   using __vec                     = __simd_vector<__value_type, __vec_size>;
 
-  if (!__libcpp_is_constant_evaluated()) {
+  if (!__libcpp_is_constant_evaluated() && std::__altivec_has_element_wise_compare) {
     auto __orig_first1 = __first1;
     auto __last2       = __first2 + (__last1 - __first1);
     while (static_cast<size_t>(__last1 - __first1) >= __unroll_count * __vec_size) [[__unlikely__]] {
diff --git a/libcxx/include/__algorithm/simd_utils.h b/libcxx/include/__algorithm/simd_utils.h
index 44530d6cd8cae..040bdf9eb3c8c 100644
--- a/libcxx/include/__algorithm/simd_utils.h
+++ b/libcxx/include/__algorithm/simd_utils.h
@@ -130,12 +130,8 @@ template <class _VecT, size_t _Np, class _Iter>
 }
 _LIBCPP_DIAGNOSTIC_POP
 
-// On targets with Altivec (PowerPC), the == operator on __ext_vector_type__
-// vectors produces a deprecated vector bool result under the old XL compat mode.
-// Centralise the comparison here so the suppression is in one place.
-// The return type is deduced via decltype because under Altivec the comparison
-// result element type differs from the operand element type (e.g. char16_t
-// operands yield a short mask vector).
+// The return type uses decltype because under Altivec the comparison result
+// element type differs from the operand type (e.g. char16_t -> short mask).
 _LIBCPP_DIAGNOSTIC_PUSH
 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated-altivec-src-compat")
 template <class _Tp, size_t _Np>
@@ -145,14 +141,14 @@ __simd_compare_eq(__simd_vector<_Tp, _Np> __lhs, __simd_vector<_Tp, _Np> __rhs)
 }
 _LIBCPP_DIAGNOSTIC_POP
 
+// On non-Altivec targets this is always true. On Altivec targets it is false
+// when -faltivec-src-compat=xl is active (== returns scalar bool, not a mask).
 #  if defined(__ALTIVEC__)
-// In -faltivec-src-compat=xl mode, == on vector types returns a scalar bool,
-// which silently breaks the mask-based algorithms below. Refuse to compile in
-// that mode rather than produce wrong results.
-static_assert(sizeof(std::__simd_compare_eq(std::declval<__simd_vector<int, 4>>(),
-                                            std::declval<__simd_vector<int, 4>>())) == sizeof(__simd_vector<int, 4>),
-              "libc++'s vectorized algorithms require element-wise vector comparison semantics. "
-              "Compile with -faltivec-src-compat=mixed or -faltivec-src-compat=gcc (not =xl).");
+inline constexpr bool __altivec_has_element_wise_compare =
+    sizeof(std::__simd_compare_eq(std::declval<__simd_vector<int, 4>>(),
+                                  std::declval<__simd_vector<int, 4>>())) == sizeof(__simd_vector<int, 4>);
+#  else
+inline constexpr bool __altivec_has_element_wise_compare = true;
 #  endif
 
 template <class _Tp, size_t _Np>
diff --git a/libcxx/include/__locale_dir/num.h b/libcxx/include/__locale_dir/num.h
index 792b24e72dd09..d1927be96f734 100644
--- a/libcxx/include/__locale_dir/num.h
+++ b/libcxx/include/__locale_dir/num.h
@@ -91,7 +91,7 @@ struct __num_get : protected __num_get_base {
   _LIBCPP_HIDE_FROM_ABI static ptrdiff_t __atoms_offset(const _CharT* __atoms, _CharT __val) {
     // TODO: Remove the manual vectorization once https://llvm.org/PR168551 is resolved
 #  if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS
-    if constexpr (is_same<_CharT, char>::value) {
+    if constexpr (is_same<_CharT, char>::value && std::__altivec_has_element_wise_compare) {
       // TODO(LLVM 24): This can be removed, since -Wpsabi doesn't warn on [[gnu::always_inline]] functions anymore.
       _LIBCPP_DIAGNOSTIC_PUSH
       _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi")

>From 2c04e251ed46c8044587ea6ef60586d3bd96baac Mon Sep 17 00:00:00 2001
From: himadhith <himadhith.v at ibm.com>
Date: Tue, 7 Jul 2026 10:48:04 +0530
Subject: [PATCH 4/4] [libcxx][AIX] use if constexpr to guard xl-mode vector
 comparison paths

---
 libcxx/include/__algorithm/find.h     | 4 +++-
 libcxx/include/__algorithm/mismatch.h | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h
index 343aec518f358..b3d3d8edf7410 100644
--- a/libcxx/include/__algorithm/find.h
+++ b/libcxx/include/__algorithm/find.h
@@ -66,7 +66,8 @@ __find(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) {
 template <class _Tp, class _Up>
 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI
 _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find_vectorized(_Tp* __first, _Tp* __last, _Up __value) {
-  if (!__libcpp_is_constant_evaluated() && std::__altivec_has_element_wise_compare) {
+  if (!__libcpp_is_constant_evaluated()) {
+    if constexpr (std::__altivec_has_element_wise_compare) {
     constexpr size_t __unroll_count = 4;
     constexpr size_t __vec_size     = __native_vector_size<_Tp>;
     using __vec                     = __simd_vector<_Tp, __vec_size>;
@@ -108,6 +109,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find_vectorized(_Tp* __first, _Tp* __last,
       __first = __last - __vec_size;
       return __first + std::__find_first_set(std::__simd_compare_eq(std::__load_vector<__vec>(__first), __values));
     }
+    } // end if constexpr
   }
 
   __identity __proj;
diff --git a/libcxx/include/__algorithm/mismatch.h b/libcxx/include/__algorithm/mismatch.h
index ed9b8862953ba..c14f27650cf7a 100644
--- a/libcxx/include/__algorithm/mismatch.h
+++ b/libcxx/include/__algorithm/mismatch.h
@@ -65,7 +65,8 @@ __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) {
   constexpr size_t __vec_size     = __native_vector_size<__value_type>;
   using __vec                     = __simd_vector<__value_type, __vec_size>;
 
-  if (!__libcpp_is_constant_evaluated() && std::__altivec_has_element_wise_compare) {
+  if (!__libcpp_is_constant_evaluated()) {
+    if constexpr (std::__altivec_has_element_wise_compare) {
     auto __orig_first1 = __first1;
     auto __last2       = __first2 + (__last1 - __first1);
     while (static_cast<size_t>(__last1 - __first1) >= __unroll_count * __vec_size) [[__unlikely__]] {
@@ -112,6 +113,7 @@ __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) {
           std::__simd_compare_eq(std::__load_vector<__vec>(__first1), std::__load_vector<__vec>(__first2)));
       return {__first1 + __offset, __first2 + __offset};
     } // else loop over the elements individually
+    } // end if constexpr
   }
 
   __equal_to __pred;



More information about the libcxx-commits mailing list