//===-- 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_FALSE(cpp::none_of(mask)); EXPECT_TRUE(cpp::some_of(mask)); EXPECT_EQ(cpp::find_first_set(mask), 0); EXPECT_EQ(cpp::find_last_set(mask), 2); EXPECT_EQ(cpp::popcount(mask), 2); } TEST(LlvmLibcSIMDTest, SplitConcat) { cpp::simd v{1, 1, 2, 2, 3, 3, 4, 4}; auto [v1, v2, v3, v4] = cpp::split<2, 2, 2, 2>(v); EXPECT_TRUE(cpp::all_of(v1 == 1)); EXPECT_TRUE(cpp::all_of(v2 == 2)); EXPECT_TRUE(cpp::all_of(v3 == 3)); EXPECT_TRUE(cpp::all_of(v4 == 4)); cpp::simd m = cpp::concat(v1, v2, v3, v4); EXPECT_TRUE(cpp::all_of(m == v)); cpp::simd c(~0); cpp::simd n = cpp::concat(c, c, c, c, c, c, c, c); EXPECT_TRUE(cpp::all_of(n == ~0)); } TEST(LlvmLibcSIMDTest, LoadStore) { constexpr size_t SIZE = cpp::simd_size_v>; alignas(alignof(cpp::simd)) int buf[SIZE]; cpp::simd v1 = cpp::splat(1); cpp::store(v1, buf); cpp::simd v2 = cpp::load>(buf); EXPECT_TRUE(cpp::all_of(v1 == 1)); EXPECT_TRUE(cpp::all_of(v2 == 1)); cpp::simd v3 = cpp::splat(2); cpp::store(v3, buf, /*aligned=*/true); cpp::simd v4 = cpp::load>(buf, /*aligned=*/true); EXPECT_TRUE(cpp::all_of(v3 == 2)); EXPECT_TRUE(cpp::all_of(v4 == 2)); } TEST(LlvmLibcSIMDTest, MaskedLoadStore) { constexpr size_t SIZE = cpp::simd_size_v>; alignas(alignof(cpp::simd)) int buf[SIZE] = {0}; cpp::simd mask = cpp::iota(0) % 2 == 0; cpp::simd v1 = cpp::splat(1); cpp::store_masked>(mask, v1, buf); cpp::simd v2 = cpp::load_masked>(mask, buf); EXPECT_TRUE(cpp::all_of((v2 == 1) == mask)); } TEST(LlvmLibcSIMDTest, GatherScatter) { constexpr int SIZE = cpp::simd_size_v>; alignas(alignof(cpp::simd)) int buf[SIZE]; cpp::simd mask = cpp::iota(1); cpp::simd idx = cpp::iota(0); cpp::simd v1 = cpp::splat(1); cpp::scatter>(mask, idx, v1, buf); cpp::simd v2 = cpp::gather>(mask, idx, buf); EXPECT_TRUE(cpp::all_of(v1 == 1)); EXPECT_TRUE(cpp::all_of(v2 == 1)); } TEST(LlvmLibcSIMDTest, MaskedCompressExpand) { constexpr size_t SIZE = cpp::simd_size_v>; alignas(alignof(cpp::simd)) int buf[SIZE] = {0}; cpp::simd mask_expand = cpp::iota(0) % 2 == 0; cpp::simd mask_compress = 1; cpp::simd v1 = cpp::iota(0); cpp::compress>(mask_compress, v1, buf); cpp::simd v2 = cpp::expand>(mask_expand, buf); EXPECT_TRUE(cpp::all_of(!mask_expand || v2 <= SIZE / 2)); }