Skip to content

Conversation

jhuber6
Copy link
Contributor

@jhuber6 jhuber6 commented Sep 9, 2025

Summary:
This adds a few basic tests for the SIMD helpers and adds a CMake
variable we can use to detect support.

@llvmbot
Copy link
Member

llvmbot commented Sep 9, 2025

@llvm/pr-subscribers-libc

Author: Joseph Huber (jhuber6)

Changes

Summary:
This adds a few basic tests for the SIMD helpers and adds a CMake
variable we can use to detect support.


Full diff: https://github.com/llvm/llvm-project/pull/157746.diff

4 Files Affected:

  • (modified) libc/cmake/modules/CheckCompilerFeatures.cmake (+3)
  • (added) libc/cmake/modules/compiler_features/check_ext_vector_type.cpp (+7)
  • (modified) libc/test/src/__support/CPP/CMakeLists.txt (+12)
  • (added) libc/test/src/__support/CPP/simd_test.cpp (+70)
diff --git a/libc/cmake/modules/CheckCompilerFeatures.cmake b/libc/cmake/modules/CheckCompilerFeatures.cmake
index a5ea66a5935b7..4d50d81e0ce45 100644
--- a/libc/cmake/modules/CheckCompilerFeatures.cmake
+++ b/libc/cmake/modules/CheckCompilerFeatures.cmake
@@ -15,6 +15,7 @@ set(
     "fixed_point"
     "cfloat16"
     "cfloat128"
+    "ext_vector_type"
 )
 
 # Making sure ALL_COMPILER_FEATURES is sorted.
@@ -126,6 +127,8 @@ foreach(feature IN LISTS ALL_COMPILER_FEATURES)
       set(LIBC_COMPILER_HAS_BUILTIN_ROUND TRUE)
     elseif(${feature} STREQUAL "builtin_roundeven")
       set(LIBC_COMPILER_HAS_BUILTIN_ROUNDEVEN TRUE)
+    elseif(${feature} STREQUAL "ext_vector_type")
+      set(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE TRUE)
     endif()
   endif()
 endforeach()
diff --git a/libc/cmake/modules/compiler_features/check_ext_vector_type.cpp b/libc/cmake/modules/compiler_features/check_ext_vector_type.cpp
new file mode 100644
index 0000000000000..f268a8ff540f2
--- /dev/null
+++ b/libc/cmake/modules/compiler_features/check_ext_vector_type.cpp
@@ -0,0 +1,7 @@
+#include "src/__support/macros/attributes.h"
+
+#if !LIBC_HAS_VECTOR_TYPE
+#error unsupported
+#endif
+
+bool [[clang::ext_vector_type(1)]] v;
diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index 3e1379d812c37..70965d6055bbe 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -160,3 +160,15 @@ add_libc_test(
   DEPENDS
   libc.src.__support.CPP.type_traits
 )
+
+if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
+  add_libc_test(
+    simd_test
+    SUITE
+      libc-cpp-utils-tests
+    SRCS
+      simd_test.cpp
+    DEPENDS
+      libc.src.__support.CPP.simd
+  )
+endif()
diff --git a/libc/test/src/__support/CPP/simd_test.cpp b/libc/test/src/__support/CPP/simd_test.cpp
new file mode 100644
index 0000000000000..69324cc913986
--- /dev/null
+++ b/libc/test/src/__support/CPP/simd_test.cpp
@@ -0,0 +1,70 @@
+//===-- Unittests for cpp::simd -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/simd.h"
+#include "src/__support/CPP/utility.h"
+
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+static_assert(LIBC_HAS_VECTOR_TYPE, "compiler needs ext_vector_type support");
+
+using namespace LIBC_NAMESPACE::cpp;
+
+TEST(LlvmLibcSIMDTest, Basic) {}
+TEST(LlvmLibcSIMDTest, VectorCreation) {
+  simd<int> v1 = splat(5);
+  simd<int> v2 = iota<int>();
+
+  EXPECT_EQ(v1[0], 5);
+  EXPECT_EQ(v2[0], 0);
+}
+
+TEST(LlvmLibcSIMDTest, TypeTraits) {
+  simd<int> v1 = splat(0);
+
+  static_assert(is_simd_v<decltype(v1)>, "v1 should be a SIMD type");
+  static_assert(!is_simd_v<int>, "int is not a SIMD type");
+  static_assert(is_simd_mask_v<simd<bool, 4>>, "should be a SIMD mask");
+
+  using Elem = simd_element_type_t<decltype(v1)>;
+  static_assert(is_same_v<Elem, int>, "element type should be int");
+}
+
+TEST(LlvmLibcSIMDTest, ElementwiseOperations) {
+  simd<int> v1 = splat(1);
+  simd<int> v2 = splat(-1);
+
+  simd<int> v_abs = abs(v2);
+  simd<int> v_min = min(v1, v2);
+  simd<int> v_max = max(v1, v2);
+
+  EXPECT_EQ(v_min[0], -1);
+  EXPECT_EQ(v_max[0], 1);
+  EXPECT_EQ(v_abs[0], 1);
+}
+
+TEST(LlvmLibcSIMDTest, ReductionOperations) {
+  simd<int> v = splat(1);
+
+  int sum = reduce(v);
+  int prod = reduce(v, multiplies<>{});
+
+  EXPECT_EQ(sum, static_cast<int>(simd_size_v<decltype(v)>));
+  EXPECT_EQ(prod, 1); // 1*3*5*7
+}
+
+TEST(LlvmLibcSIMDTest, MaskOperations) {
+  simd<bool, 4> mask{true, false, true, false};
+
+  EXPECT_TRUE(any_of(mask));
+  EXPECT_FALSE(all_of(mask));
+  EXPECT_TRUE(some_of(mask));
+  EXPECT_EQ(find_first_set(mask), 0);
+  EXPECT_EQ(find_last_set(mask), 2);
+}

Summary:
This adds a few basic tests for the SIMD helpers and adds a CMake
variable we can use to detect support.
Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after fixes.

libc.src.__support.CPP.type_traits
)

if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to wrap the header library target for simd.h in this check as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would I do for bazel with that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point, for the bazel we don't want the check. The cmake doesn't have to exactly match but leaving it out of the cmake is fine. When I get a chance I'll try to get the simd tests working in bazel, but that can be a separate patch.


simd<int> v_abs = abs(v2);
simd<int> v_min = min(v1, v2);
simd<int> v_max = max(v1, v2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add tests for all of the elementwise operations?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured just showing they work was enough, since they're pretty much all just wrappers around the clang builtins which are expected to work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be useful to check that they all work even if they're not fully exercised. That way if we end up with a second implementation, like if GCC implements similar intrinsics, we can be confident they behave the same.

Copy link
Contributor

@SchrodingerZhu SchrodingerZhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for getting these tested!

@jhuber6
Copy link
Contributor Author

jhuber6 commented Sep 9, 2025

Undoing those new tests, they make the bots unhappy because of some math conflicts when run through the unit testing version. I want to merge this stuff and I don't think it really tests much anyway.

@jhuber6 jhuber6 merged commit 44d1404 into llvm:main Sep 10, 2025
19 checks passed
@jhuber6 jhuber6 deleted the simd_test branch September 10, 2025 00:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants