| // Copyright 2019 Google LLC |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "third_party/highway/hwy/base.h" |
| |
| #include <limits> |
| |
| #include "third_party/highway/hwy/nanobenchmark.h" |
| |
| #undef HWY_TARGET_INCLUDE |
| #define HWY_TARGET_INCLUDE "base_test.cc" |
| #include "third_party/highway/hwy/foreach_target.h" // IWYU pragma: keep |
| #include "third_party/highway/hwy/highway.h" |
| #include "third_party/highway/hwy/tests/test_util-inl.h" |
| |
| HWY_BEFORE_NAMESPACE(); |
| namespace hwy { |
| namespace HWY_NAMESPACE { |
| namespace { |
| |
| HWY_NOINLINE void TestUnreachable() { |
| if (!hwy::Unpredictable1()) { |
| HWY_UNREACHABLE; |
| } |
| } |
| |
| HWY_NOINLINE void TestAllLimits() { |
| HWY_ASSERT_EQ(uint8_t{0}, LimitsMin<uint8_t>()); |
| HWY_ASSERT_EQ(uint16_t{0}, LimitsMin<uint16_t>()); |
| HWY_ASSERT_EQ(uint32_t{0}, LimitsMin<uint32_t>()); |
| HWY_ASSERT_EQ(uint64_t{0}, LimitsMin<uint64_t>()); |
| |
| HWY_ASSERT_EQ(int8_t{-128}, LimitsMin<int8_t>()); |
| HWY_ASSERT_EQ(int16_t{-32768}, LimitsMin<int16_t>()); |
| HWY_ASSERT_EQ(static_cast<int32_t>(0x80000000u), LimitsMin<int32_t>()); |
| HWY_ASSERT_EQ(static_cast<int64_t>(0x8000000000000000ull), |
| LimitsMin<int64_t>()); |
| |
| HWY_ASSERT_EQ(uint8_t{0xFF}, LimitsMax<uint8_t>()); |
| HWY_ASSERT_EQ(uint16_t{0xFFFF}, LimitsMax<uint16_t>()); |
| HWY_ASSERT_EQ(uint32_t{0xFFFFFFFFu}, LimitsMax<uint32_t>()); |
| HWY_ASSERT_EQ(uint64_t{0xFFFFFFFFFFFFFFFFull}, LimitsMax<uint64_t>()); |
| |
| HWY_ASSERT_EQ(int8_t{0x7F}, LimitsMax<int8_t>()); |
| HWY_ASSERT_EQ(int16_t{0x7FFF}, LimitsMax<int16_t>()); |
| HWY_ASSERT_EQ(int32_t{0x7FFFFFFFu}, LimitsMax<int32_t>()); |
| HWY_ASSERT_EQ(int64_t{0x7FFFFFFFFFFFFFFFull}, LimitsMax<int64_t>()); |
| |
| HWY_ASSERT(LimitsMin<signed char>() == LimitsMin<int8_t>()); |
| HWY_ASSERT(LimitsMin<short>() <= LimitsMin<int16_t>()); // NOLINT |
| HWY_ASSERT(LimitsMin<int>() <= LimitsMin<int16_t>()); |
| HWY_ASSERT(LimitsMin<long>() <= LimitsMin<int32_t>()); // NOLINT |
| HWY_ASSERT(LimitsMin<long long>() <= LimitsMin<int64_t>()); // NOLINT |
| |
| HWY_ASSERT(LimitsMax<signed char>() == LimitsMax<int8_t>()); |
| HWY_ASSERT(LimitsMax<short>() >= LimitsMax<int16_t>()); // NOLINT |
| HWY_ASSERT(LimitsMax<int>() >= LimitsMax<int16_t>()); |
| HWY_ASSERT(LimitsMax<long>() >= LimitsMax<int32_t>()); // NOLINT |
| HWY_ASSERT(LimitsMax<long long>() >= LimitsMax<int64_t>()); // NOLINT |
| |
| HWY_ASSERT_EQ(static_cast<unsigned char>(0), LimitsMin<unsigned char>()); |
| HWY_ASSERT_EQ(static_cast<unsigned short>(0), LimitsMin<unsigned short>()); |
| HWY_ASSERT_EQ(0u, LimitsMin<unsigned>()); |
| HWY_ASSERT_EQ(0ul, LimitsMin<unsigned long>()); // NOLINT |
| HWY_ASSERT_EQ(0ull, LimitsMin<unsigned long long>()); // NOLINT |
| |
| HWY_ASSERT(LimitsMax<unsigned char>() == LimitsMax<uint8_t>()); |
| HWY_ASSERT(LimitsMax<unsigned short>() >= LimitsMax<uint16_t>()); // NOLINT |
| HWY_ASSERT(LimitsMax<unsigned>() >= LimitsMax<uint16_t>()); |
| HWY_ASSERT(LimitsMax<unsigned long>() >= LimitsMax<uint32_t>()); // NOLINT |
| // NOLINTNEXTLINE |
| HWY_ASSERT(LimitsMax<unsigned long long>() >= LimitsMax<uint64_t>()); |
| |
| HWY_ASSERT(LimitsMin<char>() == 0 || |
| LimitsMin<char>() == LimitsMin<int8_t>()); |
| HWY_ASSERT(LimitsMax<char>() == LimitsMax<int8_t>() || |
| LimitsMax<char>() == LimitsMax<uint8_t>()); |
| |
| HWY_ASSERT_EQ(size_t{0}, LimitsMin<size_t>()); |
| HWY_ASSERT(LimitsMin<ptrdiff_t>() < ptrdiff_t{0}); |
| HWY_ASSERT(LimitsMin<intptr_t>() < intptr_t{0}); |
| HWY_ASSERT_EQ(uintptr_t{0}, LimitsMin<uintptr_t>()); |
| HWY_ASSERT(LimitsMin<wchar_t>() <= wchar_t{0}); |
| |
| HWY_ASSERT(LimitsMax<size_t>() > size_t{0}); |
| HWY_ASSERT(LimitsMax<ptrdiff_t>() > ptrdiff_t{0}); |
| HWY_ASSERT(LimitsMax<intptr_t>() > intptr_t{0}); |
| HWY_ASSERT(LimitsMax<uintptr_t>() > uintptr_t{0}); |
| HWY_ASSERT(LimitsMax<wchar_t>() > wchar_t{0}); |
| } |
| |
| struct TestLowestHighest { |
| template <class T> |
| HWY_NOINLINE void operator()(T /*unused*/) const { |
| // numeric_limits<T>::lowest is only guaranteed to be what we expect (-max) |
| // for built-in floating-point types. |
| if (!IsSpecialFloat<T>()) { |
| HWY_ASSERT_EQ(std::numeric_limits<T>::lowest(), LowestValue<T>()); |
| HWY_ASSERT_EQ(std::numeric_limits<T>::max(), HighestValue<T>()); |
| |
| if (IsFloat<T>()) { |
| HWY_ASSERT(ScalarSignBit(NegativeInfOrLowestValue<T>())); |
| HWY_ASSERT(!ScalarIsFinite(NegativeInfOrLowestValue<T>())); |
| HWY_ASSERT(!ScalarSignBit(PositiveInfOrHighestValue<T>())); |
| HWY_ASSERT(!ScalarIsFinite(PositiveInfOrHighestValue<T>())); |
| HWY_ASSERT(NegativeInfOrLowestValue<T>() < |
| std::numeric_limits<T>::lowest()); |
| HWY_ASSERT(PositiveInfOrHighestValue<T>() > |
| std::numeric_limits<T>::max()); |
| } else { |
| HWY_ASSERT_EQ(std::numeric_limits<T>::lowest(), |
| NegativeInfOrLowestValue<T>()); |
| HWY_ASSERT_EQ(std::numeric_limits<T>::max(), |
| PositiveInfOrHighestValue<T>()); |
| } |
| } |
| } |
| }; |
| |
| HWY_NOINLINE void TestAllLowestHighest() { ForAllTypes(TestLowestHighest()); } |
| struct TestIsUnsigned { |
| template <class T> |
| HWY_NOINLINE void operator()(T /*unused*/) const { |
| static_assert(!IsFloat<T>(), "Expected !IsFloat"); |
| static_assert(!IsSigned<T>(), "Expected !IsSigned"); |
| static_assert(IsInteger<T>(), "Expected IsInteger"); |
| } |
| }; |
| |
| struct TestIsSigned { |
| template <class T> |
| HWY_NOINLINE void operator()(T /*unused*/) const { |
| static_assert(!IsFloat<T>(), "Expected !IsFloat"); |
| static_assert(IsSigned<T>(), "Expected IsSigned"); |
| static_assert(IsInteger<T>(), "Expected IsInteger"); |
| } |
| }; |
| |
| struct TestIsFloat { |
| template <class T> |
| HWY_NOINLINE void operator()(T /*unused*/) const { |
| static_assert(IsFloat<T>(), "Expected IsFloat"); |
| static_assert(!IsInteger<T>(), "Expected !IsInteger"); |
| static_assert(IsSigned<T>(), "Floats are also considered signed"); |
| } |
| }; |
| |
| HWY_NOINLINE void TestAllType() { |
| const TestIsUnsigned is_unsigned_test; |
| const TestIsSigned is_signed_test; |
| |
| ForUnsignedTypes(is_unsigned_test); |
| ForSignedTypes(is_signed_test); |
| ForFloatTypes(TestIsFloat()); |
| |
| is_unsigned_test(static_cast<unsigned char>(0)); |
| is_unsigned_test(static_cast<unsigned short>(0)); |
| is_unsigned_test(0u); |
| is_unsigned_test(0ul); |
| is_unsigned_test(0ull); |
| is_unsigned_test(size_t{0}); |
| is_unsigned_test(uintptr_t{0}); |
| |
| is_signed_test(static_cast<signed char>(0)); |
| is_signed_test(static_cast<signed short>(0)); |
| is_signed_test(0); |
| is_signed_test(0L); |
| is_signed_test(0LL); |
| is_signed_test(ptrdiff_t{0}); |
| is_signed_test(intptr_t{0}); |
| |
| static_assert(!IsFloat<char>(), "Expected !IsFloat<char>()"); |
| static_assert(!IsFloat<wchar_t>(), "Expected !IsFloat<wchar_t>()"); |
| static_assert(IsInteger<char>(), "Expected IsInteger<char>()"); |
| static_assert(IsInteger<wchar_t>(), "Expected IsInteger<wchar_t>()"); |
| |
| static_assert(sizeof(MakeUnsigned<hwy::uint128_t>) == 16, ""); |
| static_assert(sizeof(MakeWide<uint64_t>) == 16, "Expected uint128_t"); |
| static_assert(sizeof(MakeNarrow<hwy::uint128_t>) == 8, "Expected uint64_t"); |
| } |
| |
| struct TestIsSame { |
| template <class T> |
| HWY_NOINLINE void operator()(T /*unused*/) const { |
| static_assert(IsSame<T, T>(), "T == T"); |
| static_assert(!IsSame<MakeSigned<T>, MakeUnsigned<T>>(), "S != U"); |
| static_assert(!IsSame<MakeUnsigned<T>, MakeSigned<T>>(), "U != S"); |
| } |
| }; |
| |
| HWY_NOINLINE void TestAllIsSame() { ForAllTypes(TestIsSame()); } |
| |
| HWY_NOINLINE void TestAllBitScan() { |
| HWY_ASSERT_EQ(size_t{0}, Num0BitsAboveMS1Bit_Nonzero32(0x80000000u)); |
| HWY_ASSERT_EQ(size_t{0}, Num0BitsAboveMS1Bit_Nonzero32(0xFFFFFFFFu)); |
| HWY_ASSERT_EQ(size_t{1}, Num0BitsAboveMS1Bit_Nonzero32(0x40000000u)); |
| HWY_ASSERT_EQ(size_t{1}, Num0BitsAboveMS1Bit_Nonzero32(0x40108210u)); |
| HWY_ASSERT_EQ(size_t{30}, Num0BitsAboveMS1Bit_Nonzero32(2u)); |
| HWY_ASSERT_EQ(size_t{30}, Num0BitsAboveMS1Bit_Nonzero32(3u)); |
| HWY_ASSERT_EQ(size_t{31}, Num0BitsAboveMS1Bit_Nonzero32(1u)); |
| |
| HWY_ASSERT_EQ(size_t{0}, |
| Num0BitsAboveMS1Bit_Nonzero64(0x8000000000000000ull)); |
| HWY_ASSERT_EQ(size_t{0}, |
| Num0BitsAboveMS1Bit_Nonzero64(0xFFFFFFFFFFFFFFFFull)); |
| HWY_ASSERT_EQ(size_t{1}, |
| Num0BitsAboveMS1Bit_Nonzero64(0x4000000000000000ull)); |
| HWY_ASSERT_EQ(size_t{1}, |
| Num0BitsAboveMS1Bit_Nonzero64(0x4010821004200011ull)); |
| HWY_ASSERT_EQ(size_t{62}, Num0BitsAboveMS1Bit_Nonzero64(2ull)); |
| HWY_ASSERT_EQ(size_t{62}, Num0BitsAboveMS1Bit_Nonzero64(3ull)); |
| HWY_ASSERT_EQ(size_t{63}, Num0BitsAboveMS1Bit_Nonzero64(1ull)); |
| |
| HWY_ASSERT_EQ(size_t{0}, Num0BitsBelowLS1Bit_Nonzero32(1u)); |
| HWY_ASSERT_EQ(size_t{1}, Num0BitsBelowLS1Bit_Nonzero32(2u)); |
| HWY_ASSERT_EQ(size_t{30}, Num0BitsBelowLS1Bit_Nonzero32(0xC0000000u)); |
| HWY_ASSERT_EQ(size_t{31}, Num0BitsBelowLS1Bit_Nonzero32(0x80000000u)); |
| |
| HWY_ASSERT_EQ(size_t{0}, Num0BitsBelowLS1Bit_Nonzero64(1ull)); |
| HWY_ASSERT_EQ(size_t{1}, Num0BitsBelowLS1Bit_Nonzero64(2ull)); |
| HWY_ASSERT_EQ(size_t{62}, |
| Num0BitsBelowLS1Bit_Nonzero64(0xC000000000000000ull)); |
| HWY_ASSERT_EQ(size_t{63}, |
| Num0BitsBelowLS1Bit_Nonzero64(0x8000000000000000ull)); |
| } |
| |
| HWY_NOINLINE void TestAllPopCount() { |
| HWY_ASSERT_EQ(size_t{0}, PopCount(0u)); |
| HWY_ASSERT_EQ(size_t{1}, PopCount(1u)); |
| HWY_ASSERT_EQ(size_t{1}, PopCount(2u)); |
| HWY_ASSERT_EQ(size_t{2}, PopCount(3u)); |
| HWY_ASSERT_EQ(size_t{1}, PopCount(0x80000000u)); |
| HWY_ASSERT_EQ(size_t{31}, PopCount(0x7FFFFFFFu)); |
| HWY_ASSERT_EQ(size_t{32}, PopCount(0xFFFFFFFFu)); |
| |
| HWY_ASSERT_EQ(size_t{1}, PopCount(0x80000000ull)); |
| HWY_ASSERT_EQ(size_t{31}, PopCount(0x7FFFFFFFull)); |
| HWY_ASSERT_EQ(size_t{32}, PopCount(0xFFFFFFFFull)); |
| HWY_ASSERT_EQ(size_t{33}, PopCount(0x10FFFFFFFFull)); |
| HWY_ASSERT_EQ(size_t{63}, PopCount(0xFFFEFFFFFFFFFFFFull)); |
| HWY_ASSERT_EQ(size_t{64}, PopCount(0xFFFFFFFFFFFFFFFFull)); |
| } |
| |
| // Exhaustive test for small/large dividends and divisors |
| HWY_NOINLINE void TestAllDivisor() { |
| // Small d, small n |
| for (uint32_t d = 1; d < 256; ++d) { |
| const Divisor divisor(d); |
| for (uint32_t n = 0; n < 256; ++n) { |
| HWY_ASSERT(divisor.Divide(n) == n / d); |
| HWY_ASSERT(divisor.Remainder(n) == n % d); |
| } |
| } |
| |
| // Large d, small n |
| for (uint32_t d = 0xFFFFFF00u; d != 0; ++d) { |
| const Divisor divisor(d); |
| for (uint32_t n = 0; n < 256; ++n) { |
| HWY_ASSERT(divisor.Divide(n) == n / d); |
| HWY_ASSERT(divisor.Remainder(n) == n % d); |
| } |
| } |
| |
| // Small d, large n |
| for (uint32_t d = 1; d < 256; ++d) { |
| const Divisor divisor(d); |
| for (uint32_t n = 0xFFFFFF00u; n != 0; ++n) { |
| HWY_ASSERT(divisor.Divide(n) == n / d); |
| HWY_ASSERT(divisor.Remainder(n) == n % d); |
| } |
| } |
| |
| // Large d, large n |
| for (uint32_t d = 0xFFFFFF00u; d != 0; ++d) { |
| const Divisor divisor(d); |
| for (uint32_t n = 0xFFFFFF00u; n != 0; ++n) { |
| HWY_ASSERT(divisor.Divide(n) == n / d); |
| HWY_ASSERT(divisor.Remainder(n) == n % d); |
| } |
| } |
| } |
| |
| HWY_NOINLINE void TestAllDivisor64() { |
| // Small d, small n |
| for (uint64_t d = 1; d < 256; ++d) { |
| const Divisor64 divisor(d); |
| for (uint64_t n = 0; n < 256; ++n) { |
| HWY_ASSERT(divisor.Divide(n) == n / d); |
| HWY_ASSERT(divisor.Remainder(n) == n % d); |
| } |
| } |
| |
| // Large d, small n |
| for (uint64_t d = 0xFFFFFFFFFFFFFF00ULL; d != 0; ++d) { |
| const Divisor64 divisor(d); |
| for (uint64_t n = 0; n < 256; ++n) { |
| HWY_ASSERT(divisor.Divide(n) == n / d); |
| HWY_ASSERT(divisor.Remainder(n) == n % d); |
| } |
| } |
| |
| // Small d, large n |
| for (uint64_t d = 1; d < 256; ++d) { |
| const Divisor64 divisor(d); |
| for (uint64_t n = 0xFFFFFFFFFFFFFF00ULL; n != 0; ++n) { |
| HWY_ASSERT(divisor.Divide(n) == n / d); |
| HWY_ASSERT(divisor.Remainder(n) == n % d); |
| } |
| } |
| |
| // Large d, large n |
| for (uint64_t d = 0xFFFFFFFFFFFFFF00ULL; d != 0; ++d) { |
| const Divisor64 divisor(d); |
| for (uint64_t n = 0xFFFFFFFFFFFFFF00ULL; n != 0; ++n) { |
| HWY_ASSERT(divisor.Divide(n) == n / d); |
| HWY_ASSERT(divisor.Remainder(n) == n % d); |
| } |
| } |
| } |
| |
| struct TestScalarShr { |
| template <class T> |
| HWY_NOINLINE void operator()(T /*unused*/) const { |
| using TU = MakeUnsigned<T>; |
| constexpr T kMsb = static_cast<T>(1ULL << (sizeof(T) * 8 - 1)); |
| constexpr int kSizeInBits = static_cast<int>(sizeof(T) * 8); |
| |
| constexpr T kVal1 = static_cast<T>(0x776B0405296C183BULL & LimitsMax<TU>()); |
| constexpr T kVal2 = static_cast<T>(kVal1 | kMsb); |
| |
| for (int i = 0; i < kSizeInBits; i++) { |
| T expected1; |
| T expected2; |
| |
| const TU expected1_bits = static_cast<TU>(static_cast<TU>(kVal1) >> i); |
| const TU expected2_bits = static_cast<TU>( |
| (static_cast<TU>(kVal2) >> i) | |
| ((IsSigned<T>() && i > 0) |
| ? (~((static_cast<TU>(1) << (kSizeInBits - i)) - 1)) |
| : 0)); |
| |
| CopySameSize(&expected1_bits, &expected1); |
| CopySameSize(&expected2_bits, &expected2); |
| |
| HWY_ASSERT_EQ(expected1, ScalarShr(kVal1, i)); |
| HWY_ASSERT_EQ(expected2, ScalarShr(kVal2, i)); |
| } |
| } |
| }; |
| |
| HWY_NOINLINE void TestAllScalarShr() { ForIntegerTypes(TestScalarShr()); } |
| |
| template <class T> |
| static HWY_INLINE void AssertMul128Result(T expected_hi, T expected_lo, T a, |
| T b, const char* file, |
| const int line) { |
| RemoveCvRef<T> actual_hi; |
| const RemoveCvRef<T> actual_lo = Mul128(a, b, &actual_hi); |
| hwy::AssertEqual(expected_lo, actual_lo, hwy::TargetName(HWY_TARGET), file, |
| line); |
| hwy::AssertEqual(expected_hi, actual_hi, hwy::TargetName(HWY_TARGET), file, |
| line); |
| } |
| |
| HWY_NOINLINE void TestAllMul128() { |
| AssertMul128Result(static_cast<int64_t>(0), static_cast<int64_t>(0), |
| static_cast<int64_t>(0), static_cast<int64_t>(0), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<int64_t>(0), static_cast<int64_t>(0), |
| static_cast<int64_t>(0), static_cast<int64_t>(1), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<int64_t>(0), static_cast<int64_t>(0), |
| static_cast<int64_t>(0), static_cast<int64_t>(-1), |
| __FILE__, __LINE__); |
| AssertMul128Result(static_cast<int64_t>(0), static_cast<int64_t>(0), |
| static_cast<int64_t>(1), static_cast<int64_t>(0), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<int64_t>(0), static_cast<int64_t>(0), |
| static_cast<int64_t>(-1), static_cast<int64_t>(0), |
| __FILE__, __LINE__); |
| |
| AssertMul128Result(static_cast<int64_t>(0), static_cast<int64_t>(1), |
| static_cast<int64_t>(1), static_cast<int64_t>(1), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<int64_t>(-1), static_cast<int64_t>(-1), |
| static_cast<int64_t>(-1), static_cast<int64_t>(1), |
| __FILE__, __LINE__); |
| AssertMul128Result(static_cast<int64_t>(-1), static_cast<int64_t>(-1), |
| static_cast<int64_t>(1), static_cast<int64_t>(-1), |
| __FILE__, __LINE__); |
| AssertMul128Result(static_cast<int64_t>(0), static_cast<int64_t>(1), |
| static_cast<int64_t>(-1), static_cast<int64_t>(-1), |
| __FILE__, __LINE__); |
| |
| AssertMul128Result(static_cast<uint64_t>(0), static_cast<uint64_t>(0), |
| static_cast<uint64_t>(0), static_cast<uint64_t>(0), |
| __FILE__, __LINE__); |
| AssertMul128Result(static_cast<uint64_t>(0), static_cast<uint64_t>(0), |
| static_cast<uint64_t>(0), static_cast<uint64_t>(1), |
| __FILE__, __LINE__); |
| AssertMul128Result(static_cast<uint64_t>(0), static_cast<uint64_t>(0), |
| static_cast<uint64_t>(1), static_cast<uint64_t>(0), |
| __FILE__, __LINE__); |
| AssertMul128Result(static_cast<uint64_t>(0), static_cast<uint64_t>(1), |
| static_cast<uint64_t>(1), static_cast<uint64_t>(1), |
| __FILE__, __LINE__); |
| |
| AssertMul128Result(static_cast<int64_t>(0x24E331A77C96011DULL), |
| static_cast<int64_t>(0x3C5385F8E294E438ULL), |
| static_cast<int64_t>(0x4F87AE233A08DD18ULL), |
| static_cast<int64_t>(0x76BCCD32975A49CDULL), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<int64_t>(0xFD1F5A95DF919291ULL), |
| static_cast<int64_t>(0x3C5385F8E294E438ULL), |
| static_cast<int64_t>(0x4F87AE233A08DD18ULL), |
| static_cast<int64_t>(0xF6BCCD32975A49CDULL), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<int64_t>(0xE984CB0E30E8DC36ULL), |
| static_cast<int64_t>(0xBC5385F8E294E438ULL), |
| static_cast<int64_t>(0xCF87AE233A08DD18ULL), |
| static_cast<int64_t>(0x76BCCD32975A49CDULL), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<int64_t>(0x01C0F3FC93E46DAAULL), |
| static_cast<int64_t>(0xBC5385F8E294E438ULL), |
| static_cast<int64_t>(0xCF87AE233A08DD18ULL), |
| static_cast<int64_t>(0xF6BCCD32975A49CDULL), __FILE__, |
| __LINE__); |
| |
| AssertMul128Result(static_cast<uint64_t>(0x24E331A77C96011DULL), |
| static_cast<uint64_t>(0x3C5385F8E294E438ULL), |
| static_cast<uint64_t>(0x4F87AE233A08DD18ULL), |
| static_cast<uint64_t>(0x76BCCD32975A49CDULL), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<uint64_t>(0x4CA708B9199A6FA9ULL), |
| static_cast<uint64_t>(0x3C5385F8E294E438ULL), |
| static_cast<uint64_t>(0x4F87AE233A08DD18ULL), |
| static_cast<uint64_t>(0xF6BCCD32975A49CDULL), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<uint64_t>(0x60419840C8432603ULL), |
| static_cast<uint64_t>(0xBC5385F8E294E438ULL), |
| static_cast<uint64_t>(0xCF87AE233A08DD18ULL), |
| static_cast<uint64_t>(0x76BCCD32975A49CDULL), __FILE__, |
| __LINE__); |
| AssertMul128Result(static_cast<uint64_t>(0xC8056F526547948FULL), |
| static_cast<uint64_t>(0xBC5385F8E294E438ULL), |
| static_cast<uint64_t>(0xCF87AE233A08DD18ULL), |
| static_cast<uint64_t>(0xF6BCCD32975A49CDULL), __FILE__, |
| __LINE__); |
| } |
| |
| template <class T> |
| static HWY_INLINE T TestEndianGetIntegerVal(T val) { |
| static_assert(!IsFloat<T>() && !IsSpecialFloat<T>(), |
| "T must not be a floating-point type"); |
| using TU = MakeUnsigned<T>; |
| static_assert(sizeof(T) == sizeof(TU), |
| "sizeof(T) == sizeof(TU) must be true"); |
| |
| uint8_t result_bytes[sizeof(T)]; |
| const TU val_u = static_cast<TU>(val); |
| |
| for (size_t i = 0; i < sizeof(T); i++) { |
| #if HWY_IS_BIG_ENDIAN |
| const size_t shift_amt = (sizeof(T) - 1 - i) * 8; |
| #else |
| const size_t shift_amt = i * 8; |
| #endif |
| result_bytes[i] = static_cast<uint8_t>((val_u >> shift_amt) & 0xFF); |
| } |
| |
| T result; |
| CopyBytes<sizeof(T)>(result_bytes, &result); |
| return result; |
| } |
| |
| template <class T, class... Bytes> |
| static HWY_INLINE T TestEndianCreateValueFromBytes(Bytes&&... bytes) { |
| static_assert(sizeof(T) > 0, "sizeof(T) > 0 must be true"); |
| static_assert(sizeof...(Bytes) == sizeof(T), |
| "sizeof...(Bytes) == sizeof(T) must be true"); |
| |
| const uint8_t src_bytes[sizeof(T)]{static_cast<uint8_t>(bytes)...}; |
| |
| T result; |
| CopyBytes<sizeof(T)>(src_bytes, &result); |
| return result; |
| } |
| |
| #define HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(val) \ |
| HWY_ASSERT_EQ(val, TestEndianGetIntegerVal(val)) |
| |
| HWY_NOINLINE void TestAllEndian() { |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(int8_t{0x01}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(uint8_t{0x01}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(int16_t{0x0102}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(uint16_t{0x0102}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(int32_t{0x01020304}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(uint32_t{0x01020304}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(int64_t{0x0102030405060708}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(uint64_t{0x0102030405060708}); |
| |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(int16_t{0x0201}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(uint16_t{0x0201}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(int32_t{0x04030201}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(uint32_t{0x04030201}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(int64_t{0x0807060504030201}); |
| HWY_TEST_ENDIAN_CHECK_INTEGER_VAL(uint64_t{0x0807060504030201}); |
| |
| HWY_ASSERT_EQ(HWY_IS_BIG_ENDIAN ? int16_t{0x0102} : int16_t{0x0201}, |
| TestEndianCreateValueFromBytes<int16_t>(0x01, 0x02)); |
| HWY_ASSERT_EQ(HWY_IS_BIG_ENDIAN ? uint16_t{0x0102} : uint16_t{0x0201}, |
| TestEndianCreateValueFromBytes<uint16_t>(0x01, 0x02)); |
| HWY_ASSERT_EQ( |
| HWY_IS_BIG_ENDIAN ? int32_t{0x01020304} : int32_t{0x04030201}, |
| TestEndianCreateValueFromBytes<int32_t>(0x01, 0x02, 0x03, 0x04)); |
| HWY_ASSERT_EQ( |
| HWY_IS_BIG_ENDIAN ? uint32_t{0x01020304} : uint32_t{0x04030201}, |
| TestEndianCreateValueFromBytes<uint32_t>(0x01, 0x02, 0x03, 0x04)); |
| HWY_ASSERT_EQ(HWY_IS_BIG_ENDIAN ? int64_t{0x0102030405060708} |
| : int64_t{0x0807060504030201}, |
| TestEndianCreateValueFromBytes<int64_t>( |
| 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)); |
| HWY_ASSERT_EQ(HWY_IS_BIG_ENDIAN ? uint64_t{0x0102030405060708} |
| : uint64_t{0x0807060504030201}, |
| TestEndianCreateValueFromBytes<uint64_t>( |
| 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)); |
| |
| HWY_ASSERT_EQ(HWY_IS_BIG_ENDIAN ? int16_t{-0x5EFE} : int16_t{0x02A1}, |
| TestEndianCreateValueFromBytes<int16_t>(0xA1, 0x02)); |
| HWY_ASSERT_EQ( |
| HWY_IS_BIG_ENDIAN ? int32_t{-0x5E4D3CFC} : int32_t{0x04C3B2A1}, |
| TestEndianCreateValueFromBytes<int32_t>(0xA1, 0xB2, 0xC3, 0x04)); |
| HWY_ASSERT_EQ(HWY_IS_BIG_ENDIAN ? int64_t{-0x6E5D4C3B2A1908F8} |
| : int64_t{0x08F7E6D5C4B3A291}, |
| TestEndianCreateValueFromBytes<int64_t>( |
| 0x91, 0xA2, 0xB3, 0xC4, 0xD5, 0xE6, 0xF7, 0x08)); |
| |
| HWY_ASSERT_EQ(HWY_IS_LITTLE_ENDIAN ? int16_t{-0x5DFF} : int16_t{0x01A2}, |
| TestEndianCreateValueFromBytes<int16_t>(0x01, 0xA2)); |
| HWY_ASSERT_EQ( |
| HWY_IS_LITTLE_ENDIAN ? int32_t{-0x3B4C5DFF} : int32_t{0x01A2B3C4}, |
| TestEndianCreateValueFromBytes<int32_t>(0x01, 0xA2, 0xB3, 0xC4)); |
| HWY_ASSERT_EQ(HWY_IS_LITTLE_ENDIAN ? int64_t{-0x0718293A4B5C6DFF} |
| : int64_t{0x0192A3B4C5D6E7F8}, |
| TestEndianCreateValueFromBytes<int64_t>( |
| 0x01, 0x92, 0xA3, 0xB4, 0xC5, 0xD6, 0xE7, 0xF8)); |
| |
| #if HWY_IS_BIG_ENDIAN |
| HWY_ASSERT_EQ(1.0f, |
| TestEndianCreateValueFromBytes<float>(0x3F, 0x80, 0x00, 0x00)); |
| HWY_ASSERT_EQ(15922433.0f, |
| TestEndianCreateValueFromBytes<float>(0x4B, 0x72, 0xF5, 0x01)); |
| HWY_ASSERT_EQ(-12357485.0f, |
| TestEndianCreateValueFromBytes<float>(0xCB, 0x3C, 0x8F, 0x6D)); |
| #else |
| HWY_ASSERT_EQ(1.0f, |
| TestEndianCreateValueFromBytes<float>(0x00, 0x00, 0x80, 0x3F)); |
| HWY_ASSERT_EQ(15922433.0f, |
| TestEndianCreateValueFromBytes<float>(0x01, 0xF5, 0x72, 0x4B)); |
| HWY_ASSERT_EQ(-12357485.0f, |
| TestEndianCreateValueFromBytes<float>(0x6D, 0x8F, 0x3C, 0xCB)); |
| #endif |
| |
| #if HWY_HAVE_FLOAT64 |
| #if HWY_IS_BIG_ENDIAN |
| HWY_ASSERT_EQ(1.0, TestEndianCreateValueFromBytes<double>( |
| 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| HWY_ASSERT_EQ(8707235690688195.0, |
| TestEndianCreateValueFromBytes<double>(0x43, 0x3E, 0xEF, 0x2F, |
| 0x4A, 0x51, 0xAE, 0xC3)); |
| HWY_ASSERT_EQ(-6815854340348452.0, |
| TestEndianCreateValueFromBytes<double>(0xC3, 0x38, 0x36, 0xFB, |
| 0xC0, 0xCC, 0x1A, 0x24)); |
| #else |
| HWY_ASSERT_EQ(1.0, TestEndianCreateValueFromBytes<double>( |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F)); |
| HWY_ASSERT_EQ(8707235690688195.0, |
| TestEndianCreateValueFromBytes<double>(0xC3, 0xAE, 0x51, 0x4A, |
| 0x2F, 0xEF, 0x3E, 0x43)); |
| HWY_ASSERT_EQ(-6815854340348452.0, |
| TestEndianCreateValueFromBytes<double>(0x24, 0x1A, 0xCC, 0xC0, |
| 0xFB, 0x36, 0x38, 0xC3)); |
| #endif // HWY_IS_BIG_ENDIAN |
| #endif // HWY_HAVE_FLOAT64 |
| |
| #if HWY_IS_BIG_ENDIAN |
| HWY_ASSERT_EQ(ConvertScalarTo<bfloat16_t>(1.0f), |
| BitCastScalar<bfloat16_t>( |
| TestEndianCreateValueFromBytes<uint16_t>(0x3F, 0x80))); |
| HWY_ASSERT_EQ(ConvertScalarTo<bfloat16_t>(0.333984375f), |
| BitCastScalar<bfloat16_t>( |
| TestEndianCreateValueFromBytes<uint16_t>(0x3E, 0xAB))); |
| HWY_ASSERT_EQ(ConvertScalarTo<bfloat16_t>(167121905303526337111381770240.0f), |
| BitCastScalar<bfloat16_t>( |
| TestEndianCreateValueFromBytes<uint16_t>(0x70, 0x07))); |
| #else |
| HWY_ASSERT_EQ(ConvertScalarTo<bfloat16_t>(1.0f), |
| BitCastScalar<bfloat16_t>( |
| TestEndianCreateValueFromBytes<uint16_t>(0x80, 0x3F))); |
| HWY_ASSERT_EQ(ConvertScalarTo<bfloat16_t>(0.333984375f), |
| BitCastScalar<bfloat16_t>( |
| TestEndianCreateValueFromBytes<uint16_t>(0xAB, 0x3E))); |
| HWY_ASSERT_EQ(ConvertScalarTo<bfloat16_t>(167121905303526337111381770240.0f), |
| BitCastScalar<bfloat16_t>( |
| TestEndianCreateValueFromBytes<uint16_t>(0x07, 0x70))); |
| #endif |
| } |
| |
| struct TestSpecialFloat { |
| template <class T> |
| static constexpr bool EnableSpecialFloatArithOpTest() { |
| return (hwy::IsSame<T, float16_t>() && HWY_HAVE_SCALAR_F16_OPERATORS) || |
| (hwy::IsSame<T, bfloat16_t>() && HWY_HAVE_SCALAR_BF16_OPERATORS); |
| } |
| |
| template <class T> |
| static constexpr HWY_INLINE T EnsureNotNativeSpecialFloat(T&& val) { |
| #if HWY_HAVE_SCALAR_F16_TYPE |
| static_assert(!hwy::IsSame<RemoveCvRef<T>, float16_t::Native>(), |
| "The operator must not return a float16_t::Native"); |
| #endif |
| #if HWY_HAVE_SCALAR_BF16_TYPE |
| static_assert(!hwy::IsSame<RemoveCvRef<T>, bfloat16_t::Native>(), |
| "The operator must not return a bfloat16_t::Native"); |
| #endif |
| return static_cast<T&&>(val); |
| } |
| |
| template <class T> |
| static HWY_INLINE void AssertSpecialFloatOpResultInRange(float min_expected, |
| float max_expected, |
| T actual, |
| const char* filename, |
| const int line) { |
| if (!(actual >= min_expected && actual <= max_expected)) { |
| hwy::Abort( |
| filename, line, |
| "mismatch: value was expected to be between %g and %g, got %g\n", |
| static_cast<double>(min_expected), static_cast<double>(max_expected), |
| ConvertScalarTo<double>(actual)); |
| } |
| } |
| |
| template <class T, |
| hwy::EnableIf<EnableSpecialFloatArithOpTest<T>()>* = nullptr> |
| static HWY_NOINLINE void TestSpecialFloatArithOperators(T /*unused*/) { |
| #if HWY_HAVE_SCALAR_F16_OPERATORS || HWY_HAVE_SCALAR_BF16_OPERATORS |
| AssertSpecialFloatOpResultInRange( |
| -0.008422852f, -0.008361816f, |
| EnsureNotNativeSpecialFloat(static_cast<T>(-0.008911133f) + |
| static_cast<T>(5.264282E-4f)), |
| __FILE__, __LINE__); |
| AssertSpecialFloatOpResultInRange( |
| 0.44335937f, 0.4453125f, |
| EnsureNotNativeSpecialFloat(static_cast<T>(-0.0014266968f) + |
| 0.4453125f), |
| __FILE__, __LINE__); |
| AssertSpecialFloatOpResultInRange( |
| 39.25f, 39.5f, |
| EnsureNotNativeSpecialFloat(34.25f + static_cast<T>(5.0625f)), __FILE__, |
| __LINE__); |
| |
| AssertSpecialFloatOpResultInRange( |
| 7456.0f, 7488.0f, |
| EnsureNotNativeSpecialFloat(static_cast<T>(0.29101562f) - |
| static_cast<T>(-7456.0f)), |
| __FILE__, __LINE__); |
| AssertSpecialFloatOpResultInRange( |
| -2.21875f, -2.203125f, |
| EnsureNotNativeSpecialFloat(static_cast<T>(1.66893E-4f) - 2.21875f), |
| __FILE__, __LINE__); |
| AssertSpecialFloatOpResultInRange( |
| 0.32421875f, 0.32617188f, |
| EnsureNotNativeSpecialFloat(0.35351562f - static_cast<T>(0.028198242f)), |
| __FILE__, __LINE__); |
| |
| AssertSpecialFloatOpResultInRange( |
| -0.01135254f, -0.011291503f, |
| EnsureNotNativeSpecialFloat(static_cast<T>(2.109375f) * |
| static_cast<T>(-0.0053710938f)), |
| __FILE__, __LINE__); |
| AssertSpecialFloatOpResultInRange( |
| 2.359375f, 2.375f, |
| EnsureNotNativeSpecialFloat(static_cast<T>(0.0019454956f) * 1216.0f), |
| __FILE__, __LINE__); |
| AssertSpecialFloatOpResultInRange( |
| -1.1014938E-4f, 3.453125f, |
| EnsureNotNativeSpecialFloat(-0.00038146973f * |
| static_cast<T>(-0.00037956237f)), |
| __FILE__, __LINE__); |
| |
| AssertSpecialFloatOpResultInRange( |
| -27.875f, -27.75f, |
| EnsureNotNativeSpecialFloat(static_cast<T>(-56.5f) / |
| static_cast<T>(2.03125f)), |
| __FILE__, __LINE__); |
| AssertSpecialFloatOpResultInRange( |
| 0.033203125f, 0.033447266f, |
| EnsureNotNativeSpecialFloat(static_cast<T>(470.0f) / 14080.0f), |
| __FILE__, __LINE__); |
| AssertSpecialFloatOpResultInRange( |
| 0.51953125f, 0.5234375f, |
| EnsureNotNativeSpecialFloat(0.26367188f / static_cast<T>(0.50390625f)), |
| __FILE__, __LINE__); |
| |
| T incr_assign_result_1 = static_cast<T>(1.373291E-4f); |
| EnsureNotNativeSpecialFloat(incr_assign_result_1 += |
| static_cast<T>(-20.375f)); |
| AssertSpecialFloatOpResultInRange(-20.375f, -20.25f, incr_assign_result_1, |
| __FILE__, __LINE__); |
| |
| T incr_assign_result_2 = static_cast<T>(2.1457672E-4f); |
| EnsureNotNativeSpecialFloat(incr_assign_result_2 += static_cast<int8_t>(7)); |
| AssertSpecialFloatOpResultInRange(7.0f, 7.03125f, incr_assign_result_2, |
| __FILE__, __LINE__); |
| |
| float incr_assign_result3 = -6.747985f; |
| incr_assign_result3 += static_cast<T>(4.15625f); |
| AssertSpecialFloatOpResultInRange(-2.59375f, -2.578125f, |
| incr_assign_result3, __FILE__, __LINE__); |
| |
| float incr_assign_result4 = 6.71875; |
| incr_assign_result4 += static_cast<T>(2.359375); |
| AssertSpecialFloatOpResultInRange(9.0625, 9.125, incr_assign_result4, |
| __FILE__, __LINE__); |
| |
| T decr_assign_result_1 = static_cast<T>(4.4059753E-4f); |
| EnsureNotNativeSpecialFloat(decr_assign_result_1 -= |
| static_cast<T>(6880.0f)); |
| AssertSpecialFloatOpResultInRange(-6880, -6848, decr_assign_result_1, |
| __FILE__, __LINE__); |
| |
| T decr_assign_result_2 = static_cast<T>(85.5f); |
| EnsureNotNativeSpecialFloat(decr_assign_result_2 -= static_cast<int8_t>(5)); |
| AssertSpecialFloatOpResultInRange(80.5f, 80.5f, decr_assign_result_2, |
| __FILE__, __LINE__); |
| |
| float decr_assign_result3 = 9.875f; |
| decr_assign_result3 -= static_cast<T>(1.5234375f); |
| AssertSpecialFloatOpResultInRange(8.3125f, 8.375f, decr_assign_result3, |
| __FILE__, __LINE__); |
| |
| double decr_assign_result4 = 0.337890625; |
| decr_assign_result4 -= static_cast<T>(2.328125); |
| AssertSpecialFloatOpResultInRange(-1.9921875, -1.984375, |
| decr_assign_result4, __FILE__, __LINE__); |
| |
| T mul_assign_result_1 = static_cast<T>(15680.0f); |
| EnsureNotNativeSpecialFloat(mul_assign_result_1 *= |
| static_cast<T>(0.001373291f)); |
| AssertSpecialFloatOpResultInRange(21.5f, 21.625f, mul_assign_result_1, |
| __FILE__, __LINE__); |
| |
| T mul_assign_result_2 = static_cast<T>(2.609375f); |
| EnsureNotNativeSpecialFloat(mul_assign_result_2 *= static_cast<int8_t>(7)); |
| AssertSpecialFloatOpResultInRange(18.25, 18.375, mul_assign_result_2, |
| __FILE__, __LINE__); |
| |
| float mul_assign_result3 = 4.125f; |
| mul_assign_result3 *= static_cast<T>(3.375f); |
| AssertSpecialFloatOpResultInRange(13.875f, 13.9375f, mul_assign_result3, |
| __FILE__, __LINE__); |
| |
| double mul_assign_result4 = 7.9375; |
| mul_assign_result4 *= static_cast<T>(0.79296875); |
| AssertSpecialFloatOpResultInRange(6.28125, 6.3125, mul_assign_result4, |
| __FILE__, __LINE__); |
| |
| T div_assign_result_1 = static_cast<T>(11584.0f); |
| EnsureNotNativeSpecialFloat(div_assign_result_1 /= static_cast<T>(9.5625f)); |
| AssertSpecialFloatOpResultInRange(1208.0f, 1216.0f, div_assign_result_1, |
| __FILE__, __LINE__); |
| |
| T div_assign_result_2 = static_cast<T>(0.12109375f); |
| EnsureNotNativeSpecialFloat(div_assign_result_2 /= static_cast<int8_t>(3)); |
| AssertSpecialFloatOpResultInRange(0.040283203f, 0.040527344f, |
| div_assign_result_2, __FILE__, __LINE__); |
| |
| float div_assign_result_3 = 0.21679688f; |
| div_assign_result_3 /= static_cast<T>(3.421875f); |
| AssertSpecialFloatOpResultInRange(0.06298828125f, 0.0634765625f, |
| div_assign_result_3, __FILE__, __LINE__); |
| |
| double div_assign_result_4 = 5.34375; |
| div_assign_result_4 /= static_cast<T>(0.337890625); |
| AssertSpecialFloatOpResultInRange(15.8125, 15.875, div_assign_result_4, |
| __FILE__, __LINE__); |
| |
| HWY_ASSERT_EQ(static_cast<T>(-1.0f), |
| EnsureNotNativeSpecialFloat(-static_cast<T>(1.0f))); |
| HWY_ASSERT_EQ(static_cast<T>(1.0f), |
| EnsureNotNativeSpecialFloat(+static_cast<T>(1.0f))); |
| |
| T pre_incr_result_1 = static_cast<T>(1.0f); |
| T pre_incr_result_2 = EnsureNotNativeSpecialFloat(++pre_incr_result_1); |
| HWY_ASSERT_EQ(static_cast<T>(2.0f), pre_incr_result_1); |
| HWY_ASSERT_EQ(static_cast<T>(2.0f), pre_incr_result_2); |
| |
| T post_incr_result_1 = static_cast<T>(5.0f); |
| T post_incr_result_2 = EnsureNotNativeSpecialFloat(post_incr_result_1++); |
| HWY_ASSERT_EQ(static_cast<T>(6.0f), post_incr_result_1); |
| HWY_ASSERT_EQ(static_cast<T>(5.0f), post_incr_result_2); |
| |
| T pre_decr_result_1 = static_cast<T>(-2.0f); |
| T pre_decr_result_2 = EnsureNotNativeSpecialFloat(--pre_decr_result_1); |
| HWY_ASSERT_EQ(static_cast<T>(-3.0f), pre_decr_result_1); |
| HWY_ASSERT_EQ(static_cast<T>(-3.0f), pre_decr_result_2); |
| |
| T post_decr_result_1 = static_cast<T>(-7.0f); |
| T post_decr_result_2 = EnsureNotNativeSpecialFloat(post_decr_result_1--); |
| HWY_ASSERT_EQ(static_cast<T>(-8.0f), post_decr_result_1); |
| HWY_ASSERT_EQ(static_cast<T>(-7.0f), post_decr_result_2); |
| |
| HWY_ASSERT(static_cast<T>(1.0f) == 1.0f); |
| HWY_ASSERT(static_cast<T>(-2.40625f) != 0.0033416748f); |
| HWY_ASSERT(static_cast<T>(-3248.0f) < 0.0018997193f); |
| HWY_ASSERT(static_cast<T>(-27904.0f) <= -3.859375f); |
| HWY_ASSERT(static_cast<T>(1.078125f) > 0.010009765f); |
| HWY_ASSERT(static_cast<T>(45312.0f) >= 0.00024318695f); |
| |
| HWY_ASSERT(2.0f == static_cast<T>(2.0f)); |
| HWY_ASSERT(-5.78125f != static_cast<T>(-15168.0f)); |
| HWY_ASSERT(-0.056884766f < static_cast<T>(0.000088214875f)); |
| HWY_ASSERT(0.00008392333f <= static_cast<T>(1384.0f)); |
| HWY_ASSERT(21888.0f > static_cast<T>(-2.578125f)); |
| HWY_ASSERT(0.087402344 >= static_cast<T>(-0.65625f)); |
| #endif // HWY_HAVE_SCALAR_F16_OPERATORS || HWY_HAVE_SCALAR_BF16_OPERATORS |
| } |
| |
| template <class T, |
| hwy::EnableIf<!EnableSpecialFloatArithOpTest<T>()>* = nullptr> |
| static HWY_INLINE void TestSpecialFloatArithOperators(T /*unused*/) {} |
| |
| template <class T> |
| HWY_NOINLINE void operator()(T /*unused*/) const { |
| static_assert(IsSpecialFloat<T>(), "IsSpecialFloat<T>() must be true"); |
| |
| HWY_ASSERT_EQ(static_cast<uint32_t>(0x436B0000u), |
| BitCastScalar<uint32_t>(ConvertScalarTo<float>( |
| BitCastScalar<T>(static_cast<uint16_t>( |
| IsSame<T, hwy::float16_t>() ? 0x5B58u : 0x436Bu))))); |
| HWY_ASSERT_EQ(static_cast<uint32_t>(0xBB790000u), |
| BitCastScalar<uint32_t>(ConvertScalarTo<float>( |
| BitCastScalar<T>(static_cast<uint16_t>( |
| IsSame<T, hwy::float16_t>() ? 0x9BC8u : 0xBB79u))))); |
| |
| HWY_ASSERT_EQ(static_cast<uint32_t>( |
| IsSame<T, hwy::float16_t>() ? 0xC0B86000u : 0xC5C30000u), |
| BitCastScalar<uint32_t>(ConvertScalarTo<float>( |
| BitCastScalar<T>(static_cast<uint16_t>(0xC5C3u))))); |
| HWY_ASSERT_EQ(static_cast<uint32_t>( |
| IsSame<T, hwy::float16_t>() ? 0x41D20000u : 0x4E900000u), |
| BitCastScalar<uint32_t>(ConvertScalarTo<float>( |
| BitCastScalar<T>(static_cast<uint16_t>(0x4E90u))))); |
| |
| HWY_ASSERT_EQ(1696.0, ConvertScalarTo<double>(ConvertScalarTo<T>(1696.0f))); |
| HWY_ASSERT_EQ( |
| -0.00177001953125f, |
| ConvertScalarTo<float>(ConvertScalarTo<T>(-0.00177001953125f))); |
| |
| HWY_ASSERT_EQ(0.49609375f, |
| ConvertScalarTo<float>(ConvertScalarTo<T>(0.49609375))); |
| HWY_ASSERT_EQ( |
| 0.000553131103515625, |
| ConvertScalarTo<double>(ConvertScalarTo<T>(0.000553131103515625))); |
| |
| HWY_ASSERT_EQ(ConvertScalarTo<T>(3.0f), ConvertScalarTo<T>(3)); |
| HWY_ASSERT_EQ(ConvertScalarTo<T>(-5.5f), ConvertScalarTo<T>(-5.5)); |
| HWY_ASSERT_EQ(ConvertScalarTo<T>(0.82421875f), |
| ConvertScalarTo<T>(BF16FromF32(0.82421875f))); |
| HWY_ASSERT_EQ(ConvertScalarTo<T>(-6.375f), |
| ConvertScalarTo<T>(F16FromF32(-6.375f))); |
| |
| HWY_ASSERT(ConvertScalarTo<T>(-3.671875f) < |
| ConvertScalarTo<T>(0.0218505859375f)); |
| HWY_ASSERT(ConvertScalarTo<T>(-0.033447265625f) <= |
| ConvertScalarTo<T>(8.249282836914062E-5f)); |
| HWY_ASSERT(ConvertScalarTo<T>(23296.0f) > ConvertScalarTo<T>(192.0f)); |
| HWY_ASSERT(ConvertScalarTo<T>(41984.0f) >= ConvertScalarTo<T>(370.0f)); |
| |
| TestSpecialFloatArithOperators(T()); |
| } |
| }; |
| |
| HWY_NOINLINE void TestAllSpecialFloat() { |
| TestSpecialFloat test; |
| test(float16_t()); |
| test(bfloat16_t()); |
| } |
| |
| } // namespace |
| // NOLINTNEXTLINE(google-readability-namespace-comments) |
| } // namespace HWY_NAMESPACE |
| } // namespace hwy |
| HWY_AFTER_NAMESPACE(); |
| |
| #if HWY_ONCE |
| namespace hwy { |
| namespace { |
| HWY_BEFORE_TEST(BaseTest); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestUnreachable); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllLimits); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllLowestHighest); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllType); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllIsSame); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllBitScan); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllPopCount); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllDivisor); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllDivisor64); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllScalarShr); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllMul128); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllEndian); |
| HWY_EXPORT_AND_TEST_P(BaseTest, TestAllSpecialFloat); |
| HWY_AFTER_TEST(); |
| } // namespace |
| } // namespace hwy |
| HWY_TEST_MAIN(); |
| #endif // HWY_ONCE |