[libc-commits] [libc] [libc] Add check for support and a test for libc SIMD helpers (PR #157746)
Joseph Huber via libc-commits
libc-commits at lists.llvm.org
Tue Sep 9 16:52:59 PDT 2025
https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/157746
>From 71ecbf74b5b2399ca815b2a178c0f4c63f225fd1 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Tue, 9 Sep 2025 15:41:22 -0500
Subject: [PATCH 1/5] [libc] Add check for support and a test for libc SIMD
helpers
Summary:
This adds a few basic tests for the SIMD helpers and adds a CMake
variable we can use to detect support.
---
.../cmake/modules/CheckCompilerFeatures.cmake | 3 +
.../check_ext_vector_type.cpp | 7 ++
libc/src/__support/CPP/simd.h | 2 +-
libc/test/src/__support/CPP/CMakeLists.txt | 12 ++++
libc/test/src/__support/CPP/simd_test.cpp | 70 +++++++++++++++++++
5 files changed, 93 insertions(+), 1 deletion(-)
create mode 100644 libc/cmake/modules/compiler_features/check_ext_vector_type.cpp
create mode 100644 libc/test/src/__support/CPP/simd_test.cpp
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/src/__support/CPP/simd.h b/libc/src/__support/CPP/simd.h
index 449455c5c0390..12a493f6c7138 100644
--- a/libc/src/__support/CPP/simd.h
+++ b/libc/src/__support/CPP/simd.h
@@ -115,7 +115,7 @@ template <size_t N> LIBC_INLINE constexpr int find_first_set(simd<bool, N> m) {
}
template <size_t N> LIBC_INLINE constexpr int find_last_set(simd<bool, N> m) {
constexpr size_t size = simd_size_v<simd<bool, N>>;
- return size - __builtin_clzg(m);
+ return size - 1 - __builtin_clzg(m);
}
// Elementwise operations.
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..2c899f64d08d2
--- /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);
+}
+
+TEST(LlvmLibcSIMDTest, MaskOperations) {
+ simd<bool, 8> mask{true, false, true, false, false, false, false, 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);
+}
>From 7f97038381e36e45b7a9f00c642f4f564eef2459 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Tue, 9 Sep 2025 17:19:13 -0500
Subject: [PATCH 2/5] test all the things
---
libc/test/src/__support/CPP/simd_test.cpp | 38 ++++++++++++++++++-----
1 file changed, 31 insertions(+), 7 deletions(-)
diff --git a/libc/test/src/__support/CPP/simd_test.cpp b/libc/test/src/__support/CPP/simd_test.cpp
index 2c899f64d08d2..d9d1c1eed8939 100644
--- a/libc/test/src/__support/CPP/simd_test.cpp
+++ b/libc/test/src/__support/CPP/simd_test.cpp
@@ -37,16 +37,40 @@ TEST(LlvmLibcSIMDTest, TypeTraits) {
}
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);
+ simd<int> vi1 = splat(1);
+ simd<int> vi2 = splat(-1);
+ simd<float> vf1 = splat(1.0f);
+ simd<float> vf2 = splat(-1.0f);
+
+ simd<int> v_abs = abs(vi2);
+ simd<int> v_min = min(vi1, vi2);
+ simd<int> v_max = max(vi1, vi2);
+ simd<float> v_fma = fma(vf1, vf2, vf1);
+ simd<float> v_ceil = ceil(splat(1.2f));
+ simd<float> v_floor = floor(splat(1.8f));
+ simd<float> v_roundeven = roundeven(splat(2.5f));
+ simd<float> v_round = round(splat(2.5f));
+ simd<float> v_trunc = trunc(splat(-2.9f));
+ simd<float> v_nearbyint = nearbyint(splat(3.4f));
+ simd<float> v_rint = rint(splat(3.6f));
+ simd<float> v_canonicalize = canonicalize(splat(1.0f));
+ simd<float> v_copysign = copysign(vf1, vf2);
+ simd<float> v_fmod = fmod(splat(5.5f), splat(2.0f));
+ EXPECT_EQ(v_abs[0], 1);
EXPECT_EQ(v_min[0], -1);
EXPECT_EQ(v_max[0], 1);
- EXPECT_EQ(v_abs[0], 1);
+ EXPECT_FP_EQ(v_fma[0], 0.0f);
+ EXPECT_FP_EQ(v_ceil[0], 2.0f);
+ EXPECT_FP_EQ(v_floor[0], 1.0f);
+ EXPECT_FP_EQ(v_roundeven[0], 2.0f);
+ EXPECT_FP_EQ(v_round[0], 3.0f);
+ EXPECT_FP_EQ(v_trunc[0], -2.0f);
+ EXPECT_FP_EQ(v_nearbyint[0], 3.0f);
+ EXPECT_FP_EQ(v_rint[0], 4.0f);
+ EXPECT_FP_EQ(v_canonicalize[0], 1.0f);
+ EXPECT_FP_EQ(v_copysign[0], -1.0f);
+ EXPECT_FP_EQ(v_fmod[0], 1.5f);
}
TEST(LlvmLibcSIMDTest, ReductionOperations) {
>From 0ae3da5569ca97d07422a6cfa9abeeabf8e9aca6 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Tue, 9 Sep 2025 17:28:44 -0500
Subject: [PATCH 3/5] try fix errno on some platforms
---
libc/test/src/__support/CPP/simd_test.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/libc/test/src/__support/CPP/simd_test.cpp b/libc/test/src/__support/CPP/simd_test.cpp
index d9d1c1eed8939..ad786764075c5 100644
--- a/libc/test/src/__support/CPP/simd_test.cpp
+++ b/libc/test/src/__support/CPP/simd_test.cpp
@@ -55,7 +55,6 @@ TEST(LlvmLibcSIMDTest, ElementwiseOperations) {
simd<float> v_rint = rint(splat(3.6f));
simd<float> v_canonicalize = canonicalize(splat(1.0f));
simd<float> v_copysign = copysign(vf1, vf2);
- simd<float> v_fmod = fmod(splat(5.5f), splat(2.0f));
EXPECT_EQ(v_abs[0], 1);
EXPECT_EQ(v_min[0], -1);
@@ -70,7 +69,6 @@ TEST(LlvmLibcSIMDTest, ElementwiseOperations) {
EXPECT_FP_EQ(v_rint[0], 4.0f);
EXPECT_FP_EQ(v_canonicalize[0], 1.0f);
EXPECT_FP_EQ(v_copysign[0], -1.0f);
- EXPECT_FP_EQ(v_fmod[0], 1.5f);
}
TEST(LlvmLibcSIMDTest, ReductionOperations) {
>From 79afef92c0cf6dc9ab1ddffba67c6a60d848c065 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Tue, 9 Sep 2025 18:21:36 -0500
Subject: [PATCH 4/5] namespace
---
libc/test/src/__support/CPP/simd_test.cpp | 75 ++++++++++++-----------
1 file changed, 38 insertions(+), 37 deletions(-)
diff --git a/libc/test/src/__support/CPP/simd_test.cpp b/libc/test/src/__support/CPP/simd_test.cpp
index ad786764075c5..a769cd635999b 100644
--- a/libc/test/src/__support/CPP/simd_test.cpp
+++ b/libc/test/src/__support/CPP/simd_test.cpp
@@ -14,47 +14,48 @@
static_assert(LIBC_HAS_VECTOR_TYPE, "compiler needs ext_vector_type support");
-using namespace LIBC_NAMESPACE::cpp;
+using namespace LIBC_NAMESPACE;
TEST(LlvmLibcSIMDTest, Basic) {}
TEST(LlvmLibcSIMDTest, VectorCreation) {
- simd<int> v1 = splat(5);
- simd<int> v2 = iota<int>();
+ cpp::simd<int> v1 = cpp::splat(5);
+ cpp::simd<int> v2 = cpp::iota<int>();
EXPECT_EQ(v1[0], 5);
EXPECT_EQ(v2[0], 0);
}
TEST(LlvmLibcSIMDTest, TypeTraits) {
- simd<int> v1 = splat(0);
+ cpp::simd<int> v1 = cpp::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");
+ static_assert(cpp::is_simd_v<decltype(v1)>, "v1 should be a SIMD type");
+ static_assert(!cpp::is_simd_v<int>, "int is not a SIMD type");
+ static_assert(cpp::is_simd_mask_v<cpp::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");
+ using Elem = cpp::simd_element_type_t<decltype(v1)>;
+ static_assert(cpp::is_same_v<Elem, int>, "element type should be int");
}
TEST(LlvmLibcSIMDTest, ElementwiseOperations) {
- simd<int> vi1 = splat(1);
- simd<int> vi2 = splat(-1);
- simd<float> vf1 = splat(1.0f);
- simd<float> vf2 = splat(-1.0f);
-
- simd<int> v_abs = abs(vi2);
- simd<int> v_min = min(vi1, vi2);
- simd<int> v_max = max(vi1, vi2);
- simd<float> v_fma = fma(vf1, vf2, vf1);
- simd<float> v_ceil = ceil(splat(1.2f));
- simd<float> v_floor = floor(splat(1.8f));
- simd<float> v_roundeven = roundeven(splat(2.5f));
- simd<float> v_round = round(splat(2.5f));
- simd<float> v_trunc = trunc(splat(-2.9f));
- simd<float> v_nearbyint = nearbyint(splat(3.4f));
- simd<float> v_rint = rint(splat(3.6f));
- simd<float> v_canonicalize = canonicalize(splat(1.0f));
- simd<float> v_copysign = copysign(vf1, vf2);
+ cpp::simd<int> vi1 = cpp::splat(1);
+ cpp::simd<int> vi2 = cpp::splat(-1);
+ cpp::simd<float> vf1 = cpp::splat(1.0f);
+ cpp::simd<float> vf2 = cpp::splat(-1.0f);
+
+ cpp::simd<int> v_abs = cpp::abs(vi2);
+ cpp::simd<int> v_min = cpp::min(vi1, vi2);
+ cpp::simd<int> v_max = cpp::max(vi1, vi2);
+ cpp::simd<float> v_fma = cpp::fma(vf1, vf2, vf1);
+ cpp::simd<float> v_ceil = cpp::ceil(cpp::splat(1.2f));
+ cpp::simd<float> v_floor = cpp::floor(cpp::splat(1.8f));
+ cpp::simd<float> v_roundeven = cpp::roundeven(cpp::splat(2.5f));
+ cpp::simd<float> v_round = cpp::round(cpp::splat(2.5f));
+ cpp::simd<float> v_trunc = cpp::trunc(cpp::splat(-2.9f));
+ cpp::simd<float> v_nearbyint = cpp::nearbyint(cpp::splat(3.4f));
+ cpp::simd<float> v_rint = cpp::rint(cpp::splat(3.6f));
+ cpp::simd<float> v_canonicalize = cpp::canonicalize(cpp::splat(1.0f));
+ cpp::simd<float> v_copysign = cpp::copysign(vf1, vf2);
EXPECT_EQ(v_abs[0], 1);
EXPECT_EQ(v_min[0], -1);
@@ -72,21 +73,21 @@ TEST(LlvmLibcSIMDTest, ElementwiseOperations) {
}
TEST(LlvmLibcSIMDTest, ReductionOperations) {
- simd<int> v = splat(1);
+ cpp::simd<int> v = cpp::splat(1);
- int sum = reduce(v);
- int prod = reduce(v, multiplies<>{});
+ int sum = cpp::reduce(v);
+ int prod = cpp::reduce(v, cpp::multiplies<>{});
- EXPECT_EQ(sum, static_cast<int>(simd_size_v<decltype(v)>));
+ EXPECT_EQ(sum, static_cast<int>(cpp::simd_size_v<decltype(v)>));
EXPECT_EQ(prod, 1);
}
TEST(LlvmLibcSIMDTest, MaskOperations) {
- simd<bool, 8> mask{true, false, true, false, false, false, false, false};
+ cpp::simd<bool, 8> mask{true, false, true, false, false, false, false, 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);
+ EXPECT_TRUE(cpp::any_of(mask));
+ EXPECT_FALSE(cpp::all_of(mask));
+ EXPECT_TRUE(cpp::some_of(mask));
+ EXPECT_EQ(cpp::find_first_set(mask), 0);
+ EXPECT_EQ(cpp::find_last_set(mask), 2);
}
>From caddca5d0b1f6edece90b0ce49a63e004753dc7b Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Tue, 9 Sep 2025 18:52:48 -0500
Subject: [PATCH 5/5] undo
---
libc/test/src/__support/CPP/simd_test.cpp | 23 -----------------------
1 file changed, 23 deletions(-)
diff --git a/libc/test/src/__support/CPP/simd_test.cpp b/libc/test/src/__support/CPP/simd_test.cpp
index a769cd635999b..600bf65057b21 100644
--- a/libc/test/src/__support/CPP/simd_test.cpp
+++ b/libc/test/src/__support/CPP/simd_test.cpp
@@ -9,7 +9,6 @@
#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");
@@ -40,36 +39,14 @@ TEST(LlvmLibcSIMDTest, TypeTraits) {
TEST(LlvmLibcSIMDTest, ElementwiseOperations) {
cpp::simd<int> vi1 = cpp::splat(1);
cpp::simd<int> vi2 = cpp::splat(-1);
- cpp::simd<float> vf1 = cpp::splat(1.0f);
- cpp::simd<float> vf2 = cpp::splat(-1.0f);
cpp::simd<int> v_abs = cpp::abs(vi2);
cpp::simd<int> v_min = cpp::min(vi1, vi2);
cpp::simd<int> v_max = cpp::max(vi1, vi2);
- cpp::simd<float> v_fma = cpp::fma(vf1, vf2, vf1);
- cpp::simd<float> v_ceil = cpp::ceil(cpp::splat(1.2f));
- cpp::simd<float> v_floor = cpp::floor(cpp::splat(1.8f));
- cpp::simd<float> v_roundeven = cpp::roundeven(cpp::splat(2.5f));
- cpp::simd<float> v_round = cpp::round(cpp::splat(2.5f));
- cpp::simd<float> v_trunc = cpp::trunc(cpp::splat(-2.9f));
- cpp::simd<float> v_nearbyint = cpp::nearbyint(cpp::splat(3.4f));
- cpp::simd<float> v_rint = cpp::rint(cpp::splat(3.6f));
- cpp::simd<float> v_canonicalize = cpp::canonicalize(cpp::splat(1.0f));
- cpp::simd<float> v_copysign = cpp::copysign(vf1, vf2);
EXPECT_EQ(v_abs[0], 1);
EXPECT_EQ(v_min[0], -1);
EXPECT_EQ(v_max[0], 1);
- EXPECT_FP_EQ(v_fma[0], 0.0f);
- EXPECT_FP_EQ(v_ceil[0], 2.0f);
- EXPECT_FP_EQ(v_floor[0], 1.0f);
- EXPECT_FP_EQ(v_roundeven[0], 2.0f);
- EXPECT_FP_EQ(v_round[0], 3.0f);
- EXPECT_FP_EQ(v_trunc[0], -2.0f);
- EXPECT_FP_EQ(v_nearbyint[0], 3.0f);
- EXPECT_FP_EQ(v_rint[0], 4.0f);
- EXPECT_FP_EQ(v_canonicalize[0], 1.0f);
- EXPECT_FP_EQ(v_copysign[0], -1.0f);
}
TEST(LlvmLibcSIMDTest, ReductionOperations) {
More information about the libc-commits
mailing list