Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions libc/cmake/modules/CheckCompilerFeatures.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(
"fixed_point"
"cfloat16"
"cfloat128"
"ext_vector_type"
)

# Making sure ALL_COMPILER_FEATURES is sorted.
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 1 addition & 1 deletion libc/src/__support/CPP/simd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 12 additions & 0 deletions libc/test/src/__support/CPP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,15 @@ add_libc_test(
DEPENDS
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.

add_libc_test(
simd_test
SUITE
libc-cpp-utils-tests
SRCS
simd_test.cpp
DEPENDS
libc.src.__support.CPP.simd
)
endif()
70 changes: 70 additions & 0 deletions libc/test/src/__support/CPP/simd_test.cpp
Original file line number Diff line number Diff line change
@@ -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<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) {
cpp::simd<int> v1 = cpp::splat(0);

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 = cpp::simd_element_type_t<decltype(v1)>;
static_assert(cpp::is_same_v<Elem, int>, "element type should be int");
}

TEST(LlvmLibcSIMDTest, ElementwiseOperations) {
cpp::simd<int> vi1 = cpp::splat(1);
cpp::simd<int> vi2 = cpp::splat(-1);

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);

EXPECT_EQ(v_abs[0], 1);
EXPECT_EQ(v_min[0], -1);
EXPECT_EQ(v_max[0], 1);
}

TEST(LlvmLibcSIMDTest, ReductionOperations) {
cpp::simd<int> v = cpp::splat(1);

int sum = cpp::reduce(v);
int prod = cpp::reduce(v, cpp::multiplies<>{});

EXPECT_EQ(sum, static_cast<int>(cpp::simd_size_v<decltype(v)>));
EXPECT_EQ(prod, 1);
}

TEST(LlvmLibcSIMDTest, MaskOperations) {
cpp::simd<bool, 8> 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);
}
Loading