| /* | |
| * Copyright (C) 2026 Apple Inc. All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE | |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
| * DAMAGE. | |
| */ | |
| #include "config.h" | |
| #include <wtf/SIMDHelpers.h> | |
| #include <array> | |
| namespace TestWebKitAPI { | |
| template<typename LaneType, size_t laneCount> | |
| static std::array<LaneType, laneCount> extractLanes(WTF::SIMD::VectorType<LaneType> vector) | |
| { | |
| std::array<LaneType, laneCount> lanes { }; | |
| WTF::SIMD::store(vector, lanes.data()); | |
| return lanes; | |
| } | |
| TEST(WTF_SIMDHelpers, LessThanUnsigned8) | |
| { | |
| std::array<uint8_t, 16> left { 0, 1, 127, 128, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| std::array<uint8_t, 16> right { 1, 0, 128, 127, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| auto result = extractLanes<uint8_t, 16>(WTF::SIMD::lessThan(WTF::SIMD::load(left.data()), WTF::SIMD::load(right.data()))); | |
| EXPECT_EQ(0xffu, result[0]); | |
| EXPECT_EQ(0x00u, result[1]); | |
| EXPECT_EQ(0xffu, result[2]); | |
| EXPECT_EQ(0x00u, result[3]); | |
| EXPECT_EQ(0x00u, result[4]); | |
| } | |
| TEST(WTF_SIMDHelpers, LessThanUnsigned16) | |
| { | |
| std::array<uint16_t, 8> left { 0, 1, 0x7fff, 0x8000, 0xffff, 0, 0, 0 }; | |
| std::array<uint16_t, 8> right { 1, 0, 0x8000, 0x7fff, 0xffff, 0, 0, 0 }; | |
| auto result = extractLanes<uint16_t, 8>(WTF::SIMD::lessThan(WTF::SIMD::load(left.data()), WTF::SIMD::load(right.data()))); | |
| EXPECT_EQ(0xffffu, result[0]); | |
| EXPECT_EQ(0x0000u, result[1]); | |
| EXPECT_EQ(0xffffu, result[2]); | |
| EXPECT_EQ(0x0000u, result[3]); | |
| EXPECT_EQ(0x0000u, result[4]); | |
| } | |
| TEST(WTF_SIMDHelpers, LessThanUnsigned32) | |
| { | |
| std::array<uint32_t, 4> left { 0, 0x7fffffffu, 0x80000000u, 0xffffffffu }; | |
| std::array<uint32_t, 4> right { 1, 0x80000000u, 0x7fffffffu, 0xffffffffu }; | |
| auto result = extractLanes<uint32_t, 4>(WTF::SIMD::lessThan(WTF::SIMD::load(left.data()), WTF::SIMD::load(right.data()))); | |
| EXPECT_EQ(0xffffffffu, result[0]); | |
| EXPECT_EQ(0xffffffffu, result[1]); | |
| EXPECT_EQ(0x00000000u, result[2]); | |
| EXPECT_EQ(0x00000000u, result[3]); | |
| } | |
| // The unsigned 64-bit compare has no single x86 instruction behind it, so simde emulates it. These | |
| // are the cases that distinguish it from a signed compare. | |
| TEST(WTF_SIMDHelpers, LessThanUnsigned64) | |
| { | |
| std::array<uint64_t, 2> left { 0x7fffffffffffffffull, 0x8000000000000000ull }; | |
| std::array<uint64_t, 2> right { 0x8000000000000000ull, 0x7fffffffffffffffull }; | |
| auto result = extractLanes<uint64_t, 2>(WTF::SIMD::lessThan(WTF::SIMD::load(left.data()), WTF::SIMD::load(right.data()))); | |
| EXPECT_EQ(0xffffffffffffffffull, result[0]); | |
| EXPECT_EQ(0x0000000000000000ull, result[1]); | |
| } | |
| TEST(WTF_SIMDHelpers, Bitwise32) | |
| { | |
| std::array<uint32_t, 4> left { 0xf0f0f0f0u, 0xffffffffu, 0x00000000u, 0x12345678u }; | |
| std::array<uint32_t, 4> right { 0x0ff00ff0u, 0x00000000u, 0xffffffffu, 0x87654321u }; | |
| auto leftVector = WTF::SIMD::load(left.data()); | |
| auto rightVector = WTF::SIMD::load(right.data()); | |
| auto andResult = extractLanes<uint32_t, 4>(WTF::SIMD::bitAnd(leftVector, rightVector)); | |
| auto orResult = extractLanes<uint32_t, 4>(WTF::SIMD::bitOr(leftVector, rightVector)); | |
| auto xorResult = extractLanes<uint32_t, 4>(WTF::SIMD::bitXor(leftVector, rightVector)); | |
| for (unsigned lane = 0; lane < 4; ++lane) { | |
| EXPECT_EQ(left[lane] & right[lane], andResult[lane]); | |
| EXPECT_EQ(left[lane] | right[lane], orResult[lane]); | |
| EXPECT_EQ(left[lane] ^ right[lane], xorResult[lane]); | |
| } | |
| } | |
| TEST(WTF_SIMDHelpers, Bitwise64) | |
| { | |
| std::array<uint64_t, 2> left { 0xf0f0f0f0f0f0f0f0ull, 0x0123456789abcdefull }; | |
| std::array<uint64_t, 2> right { 0x0ff00ff00ff00ff0ull, 0xfedcba9876543210ull }; | |
| auto leftVector = WTF::SIMD::load(left.data()); | |
| auto rightVector = WTF::SIMD::load(right.data()); | |
| auto andResult = extractLanes<uint64_t, 2>(WTF::SIMD::bitAnd(leftVector, rightVector)); | |
| auto orResult = extractLanes<uint64_t, 2>(WTF::SIMD::bitOr(leftVector, rightVector)); | |
| auto xorResult = extractLanes<uint64_t, 2>(WTF::SIMD::bitXor(leftVector, rightVector)); | |
| for (unsigned lane = 0; lane < 2; ++lane) { | |
| EXPECT_EQ(left[lane] & right[lane], andResult[lane]); | |
| EXPECT_EQ(left[lane] | right[lane], orResult[lane]); | |
| EXPECT_EQ(left[lane] ^ right[lane], xorResult[lane]); | |
| } | |
| } | |
| // isNonZero over a lessThan result is the shape callers use to turn a lane comparison into a scalar | |
| // early exit. | |
| TEST(WTF_SIMDHelpers, LessThanFeedsIsNonZero) | |
| { | |
| auto hasInversion = [](const uint16_t* data) { | |
| return WTF::SIMD::isNonZero(WTF::SIMD::lessThan(WTF::SIMD::load(data + 1), WTF::SIMD::load(data))); | |
| }; | |
| std::array<uint16_t, 9> ascending { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; | |
| std::array<uint16_t, 9> withInversion { 1, 2, 3, 4, 5, 6, 8, 7, 9 }; | |
| EXPECT_FALSE(hasInversion(ascending.data())); | |
| EXPECT_TRUE(hasInversion(withInversion.data())); | |
| } | |
| } // namespace TestWebKitAPI |