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 LIBC_INLINE constexpr int find_first_set(simd m) { } template LIBC_INLINE constexpr int find_last_set(simd m) { constexpr size_t size = simd_size_v>; - 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..600bf65057b21 --- /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/Test.h" + +static_assert(LIBC_HAS_VECTOR_TYPE, "compiler needs ext_vector_type support"); + +using namespace LIBC_NAMESPACE; + +TEST(LlvmLibcSIMDTest, Basic) {} +TEST(LlvmLibcSIMDTest, VectorCreation) { + cpp::simd v1 = cpp::splat(5); + cpp::simd v2 = cpp::iota(); + + EXPECT_EQ(v1[0], 5); + EXPECT_EQ(v2[0], 0); +} + +TEST(LlvmLibcSIMDTest, TypeTraits) { + cpp::simd v1 = cpp::splat(0); + + static_assert(cpp::is_simd_v, "v1 should be a SIMD type"); + static_assert(!cpp::is_simd_v, "int is not a SIMD type"); + static_assert(cpp::is_simd_mask_v>, + "should be a SIMD mask"); + + using Elem = cpp::simd_element_type_t; + static_assert(cpp::is_same_v, "element type should be int"); +} + +TEST(LlvmLibcSIMDTest, ElementwiseOperations) { + cpp::simd vi1 = cpp::splat(1); + cpp::simd vi2 = cpp::splat(-1); + + cpp::simd v_abs = cpp::abs(vi2); + cpp::simd v_min = cpp::min(vi1, vi2); + cpp::simd v_max = cpp::max(vi1, vi2); + + EXPECT_EQ(v_abs[0], 1); + EXPECT_EQ(v_min[0], -1); + EXPECT_EQ(v_max[0], 1); +} + +TEST(LlvmLibcSIMDTest, ReductionOperations) { + cpp::simd v = cpp::splat(1); + + int sum = cpp::reduce(v); + int prod = cpp::reduce(v, cpp::multiplies<>{}); + + EXPECT_EQ(sum, static_cast(cpp::simd_size_v)); + EXPECT_EQ(prod, 1); +} + +TEST(LlvmLibcSIMDTest, MaskOperations) { + cpp::simd mask{true, false, true, false, false, false, false, false}; + + 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); +}