aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfixthgame <fixthgame@yandex-team.com>2023-10-23 11:32:53 +0300
committerfixthgame <fixthgame@yandex-team.com>2023-10-23 12:05:42 +0300
commit6fbfea3ad8bd28aa205d7e594543af7d4670280c (patch)
tree272c8b3e4dbaabba5c66b1df15da2485302ff322
parenta1e69eeebcd7f2be7c421e9f450d877f7660bc7a (diff)
downloadydb-6fbfea3ad8bd28aa205d7e594543af7d4670280c.tar.gz
Traits
Using shortcuts Traits
-rw-r--r--ydb/library/yql/utils/simd/simd.h34
-rw-r--r--ydb/library/yql/utils/simd/simd_avx2.h51
-rw-r--r--ydb/library/yql/utils/simd/simd_fallback.h259
-rw-r--r--ydb/library/yql/utils/simd/simd_sse42.h52
-rw-r--r--ydb/library/yql/utils/simd/simd_ut.cpp85
5 files changed, 432 insertions, 49 deletions
diff --git a/ydb/library/yql/utils/simd/simd.h b/ydb/library/yql/utils/simd/simd.h
new file mode 100644
index 00000000000..ba94889351a
--- /dev/null
+++ b/ydb/library/yql/utils/simd/simd.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "simd_avx2.h"
+#include "simd_sse42.h"
+#include "simd_fallback.h"
+
+namespace NSimd {
+
+template<int RegisterSize, typename TBaseRegister, template<typename> typename TSimd>
+struct TSimdTraits {
+ template<typename T>
+ using TSimd8 = TSimd<T>;
+ using TRegister = TBaseRegister;
+
+ static constexpr int Size = RegisterSize;
+};
+
+using TSimdAVX2Traits = TSimdTraits<32, __m256i, NSimd::NAVX2::TSimd8>;
+using TSimdSSE42Traits = TSimdTraits<16, __m128i, NSimd::NSSE42::TSimd8>;
+using TSimdFallbackTraits = TSimdTraits<8, ui64, NSimd::NFallback::TSimd8>;
+
+
+template<typename TFactory>
+auto SelectSimdTraits(const TFactory& factory) {
+ if (NX86::HaveAVX2()) {
+ return factory.template Create<TSimdAVX2Traits>();
+ } else if (NX86::HaveSSE42()) {
+ return factory.template Create<TSimdSSE42Traits>();
+ } else {
+ return factory.template Create<TSimdFallbackTraits>();
+ }
+}
+
+} \ No newline at end of file
diff --git a/ydb/library/yql/utils/simd/simd_avx2.h b/ydb/library/yql/utils/simd/simd_avx2.h
index 97e3d951999..f6c1979fe50 100644
--- a/ydb/library/yql/utils/simd/simd_avx2.h
+++ b/ydb/library/yql/utils/simd/simd_avx2.h
@@ -3,6 +3,9 @@
#include <cstdint>
#include <immintrin.h>
+
+#pragma clang attribute push(__attribute__((target("avx2"))), apply_to=function)
+
namespace NSimd {
namespace NAVX2 {
@@ -21,24 +24,24 @@ struct TBase {
: Value(value) {
}
- inline operator const __m256i&() const {
+ explicit inline operator const __m256i&() const {
return this->Value;
}
- inline operator __m256i&() {
+ explicit inline operator __m256i&() {
return this->Value;
}
inline Child operator|(const Child other) const {
- return _mm256_or_si256(*this, other);
+ return _mm256_or_si256(this->Value, other.Value);
}
inline Child operator&(const Child other) const {
- return _mm256_and_si256(*this, other);
+ return _mm256_and_si256(this->Value, other.Value);
}
inline Child operator^(const Child other) const {
- return _mm256_xor_si256(*this, other);
+ return _mm256_xor_si256(this->Value, other.Value);
}
inline Child BitAndNot(const Child other) const {
- return _mm256_andnot_si256(*this, other);
+ return _mm256_andnot_si256(this->Value, other.Value);
};
inline Child& operator|=(const Child other) {
auto cast = static_cast<Child*>(*this);
@@ -71,7 +74,7 @@ struct TBase8: TBase<TSimd8<T>> {
}
friend inline Mask operator==(const TSimd8<T> lhs, const TSimd8<T> rhs) {
- return _mm256_cmpeq_epi8(lhs, rhs);
+ return _mm256_cmpeq_epi8(lhs.Value, rhs.Value);
}
static const int SIZE = sizeof(TBase<T>::Value);
@@ -100,7 +103,7 @@ struct TSimd8<bool>: TBase8<bool> {
}
inline bool Any() const {
- return !_mm256_testz_si256(*this, *this);
+ return !_mm256_testz_si256(this->Value, this->Value);
}
inline TSimd8<bool> operator~() const {
@@ -143,14 +146,14 @@ struct TBase8Numeric: TBase8<T> {
}
inline void Store(T dst[32]) const {
- return _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst), *this);
+ return _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst), this->Value);
}
inline TSimd8<T> operator+(const TSimd8<T> other) const {
- return _mm256_add_epi8(*this, other);
+ return _mm256_add_epi8(this->Value, other.Value);
}
inline TSimd8<T> operator-(const TSimd8<T> other) const {
- return _mm256_sub_epi8(*this, other);
+ return _mm256_sub_epi8(this->Value, other.Value);
}
inline TSimd8<T>& operator+=(const TSimd8<T> other) {
*this = *this + other;
@@ -212,16 +215,16 @@ struct TSimd8<i8> : TBase8Numeric<i8> {
}
inline TSimd8<i8> MaxValue(const TSimd8<i8> other) const {
- return _mm256_max_epi8(*this, other);
+ return _mm256_max_epi8(this->Value, other.Value);
}
inline TSimd8<i8> MinValue(const TSimd8<i8> other) const {
- return _mm256_min_epi8(*this, other);
+ return _mm256_min_epi8(this->Value, other.Value);
}
inline TSimd8<bool> operator>(const TSimd8<i8> other) const {
- return _mm256_cmpgt_epi8(*this, other);
+ return _mm256_cmpgt_epi8(this->Value, other.Value);
}
inline TSimd8<bool> operator<(const TSimd8<i8> other) const {
- return _mm256_cmpgt_epi8(other, *this);
+ return _mm256_cmpgt_epi8(other.Value, this->Value);
}
};
@@ -268,10 +271,10 @@ struct TSimd8<ui8>: TBase8Numeric<ui8> {
}
inline TSimd8<ui8> MaxValue(const TSimd8<ui8> other) const {
- return _mm256_max_epu8(*this, other);
+ return _mm256_max_epu8(this->Value, other.Value);
}
inline TSimd8<ui8> MinValue(const TSimd8<ui8> other) const {
- return _mm256_min_epu8(other, *this);
+ return _mm256_min_epu8(other.Value, this->Value);
}
inline TSimd8<bool> operator<=(const TSimd8<ui8> other) const {
return other.MaxValue(*this) == other;
@@ -287,13 +290,13 @@ struct TSimd8<ui8>: TBase8Numeric<ui8> {
return ~this->BitsNotSet();
}
inline bool BitsNotSetAnywhere() const {
- return _mm256_testz_si256(*this, *this);
+ return _mm256_testz_si256(this->Value, this->Value);
}
inline bool AnyBitsSetAnywhere() const {
return !BitsNotSetAnywhere();
}
inline bool BitsNotSetAnywhere(TSimd8<ui8> bits) const {
- return _mm256_testz_si256(*this, bits);
+ return _mm256_testz_si256(this->Value, bits.Value);
}
inline bool AnyBitsSetAnywhere(TSimd8<ui8> bits) const {
return !BitsNotSetAnywhere(bits);
@@ -301,18 +304,20 @@ struct TSimd8<ui8>: TBase8Numeric<ui8> {
template<int N>
inline TSimd8<ui8> Shr() const {
- return TSimd8<ui8>(_mm256_srli_epi16(*this, N)) & ui8(0xFFu >> N);
+ return TSimd8<ui8>(_mm256_srli_epi16(this->Value, N)) & ui8(0xFFu >> N);
}
template<int N>
inline TSimd8<ui8> Shl() const {
- return TSimd8<ui8>(_mm256_slli_epi16(*this, N)) & ui8(0xFFu << N);
+ return TSimd8<ui8>(_mm256_slli_epi16(this->Value, N)) & ui8(0xFFu << N);
}
template<int N>
inline int GetBit() const {
- return _mm256_movemask_epi8(_mm256_slli_epi16(*this, 7-N));
+ return _mm256_movemask_epi8(_mm256_slli_epi16(this->Value, 7-N));
}
};
}
-} \ No newline at end of file
+}
+
+#pragma clang attribute pop \ No newline at end of file
diff --git a/ydb/library/yql/utils/simd/simd_fallback.h b/ydb/library/yql/utils/simd/simd_fallback.h
new file mode 100644
index 00000000000..0bdaf3e303b
--- /dev/null
+++ b/ydb/library/yql/utils/simd/simd_fallback.h
@@ -0,0 +1,259 @@
+#pragma once
+
+#include <cstdint>
+#include <immintrin.h>
+
+namespace NSimd {
+namespace NFallback {
+
+template <typename T>
+struct TSimd8;
+
+template<typename Child>
+struct TBase {
+ ui64 Value;
+
+ inline TBase()
+ : Value{ui64()} {
+ }
+
+ inline TBase(const ui64 value)
+ : Value(value) {
+ }
+
+ explicit inline operator const ui64&() const {
+ return this->Value;
+ }
+ explicit inline operator ui64&() {
+ return this->Value;
+ }
+
+ inline Child operator|(const Child other) const {
+ return this->Value | other.Value;
+ }
+ inline Child operator&(const Child other) const {
+ return this->Value & other.Value;
+ }
+ inline Child operator^(const Child other) const {
+ return this->Value ^ other.Value;
+ }
+ inline Child BitAndNot(const Child other) const {
+ return (~this->Value) & other.Value;
+ };
+ inline Child& operator|=(const Child other) {
+ auto cast = static_cast<Child*>(*this);
+ *cast = *cast | other;
+ return *cast;
+ }
+ inline Child& operator&=(const Child other) {
+ auto cast = static_cast<Child*>(*this);
+ *cast = *cast & other;
+ return *cast;
+ };
+ inline Child& operator^=(const Child other) {
+ auto cast = static_cast<Child*>(*this);
+ *cast = *cast ^ other;
+ return *cast;
+ };
+};
+
+template<typename T, typename Mask=TSimd8<bool>>
+struct TBase8: TBase<TSimd8<T>> {
+
+ inline TBase8()
+ : TBase<TSimd8<T>>()
+ {
+ }
+
+ inline TBase8(const ui64 _value)
+ : TBase<TSimd8<T>>(_value)
+ {
+ }
+
+ friend inline Mask operator==(const TSimd8<T> lhs, const TSimd8<T> rhs) {
+ return lhs.Value == rhs.Value;
+ }
+
+ static const int SIZE = sizeof(TBase<T>::Value);
+};
+
+template<>
+struct TSimd8<bool>: TBase8<bool> {
+
+ inline TSimd8<bool>()
+ : TBase8()
+ {
+ }
+
+ inline TSimd8<bool>(const ui64 value)
+ : TBase8<bool>(value)
+ {
+ }
+
+ inline TSimd8<bool>(bool value)
+ : TBase8<bool>(Set(value))
+ {
+ }
+
+ static inline TSimd8<bool> Set(bool value) {
+ return ui64(-value);
+ }
+
+ inline bool Any() const {
+ return Value != 0;
+ }
+
+ inline TSimd8<bool> operator~() const {
+ return *this ^ true;
+ }
+};
+
+template<typename T>
+struct TBase8Numeric: TBase8<T> {
+
+ inline TBase8Numeric()
+ : TBase8<T>()
+ {
+ }
+ inline TBase8Numeric(const ui64 value)
+ : TBase8<T>(value)
+ {
+ }
+
+ static inline TSimd8<T> Set(T value) {
+ TSimd8<T> result = TSimd8<T>::Zero();
+ auto dst = (ui8*)(&result.Value);
+ dst[0] = dst[1] = dst[2] = dst[3] = value;
+ dst[4] = dst[5] = dst[6] = dst[7] = value;
+ return result;
+ }
+ static inline TSimd8<T> Zero() {
+ return (ui64) 0;
+ }
+ static inline TSimd8<T> Load(const T values[8]) {
+ return TSimd8<T>(*((const ui64*) values));
+ }
+
+ inline void Store(T dst[8]) const {
+ *((ui64*) dst) = this->Value;
+ }
+
+ inline TSimd8<T> operator+(const TSimd8<T> other) const {
+ return this->Value + other.Value;
+ }
+ inline TSimd8<T> operator-(const TSimd8<T> other) const {
+ return this->Value - other.Value;
+ }
+ inline TSimd8<T>& operator+=(const TSimd8<T> other) {
+ *this = *this + other;
+ return *static_cast<TSimd8<T>*>(this);
+ }
+ inline TSimd8<T>& operator-=(const TSimd8<T> other) {
+ *this = *this - other;
+ return *static_cast<TSimd8<T>*>(this);
+ }
+
+ // 0xFFu = 11111111 = 2^8 - 1
+ inline TSimd8<T> operator~() const {
+ return *this ^ ui8(0xFFu);
+ }
+};
+
+template<>
+struct TSimd8<i8> : TBase8Numeric<i8> {
+ inline TSimd8()
+ : TBase8Numeric<i8>()
+ {
+ }
+ inline TSimd8(const ui64 value)
+ : TBase8Numeric<i8>(value)
+ {
+ }
+ inline TSimd8(i8 value)
+ : TSimd8(Set(value))
+ {
+ }
+ inline TSimd8(const i8 values[8])
+ : TSimd8(Load(values))
+ {
+ }
+ inline TSimd8(
+ i8 v0, i8 v1, i8 v2, i8 v3, i8 v4, i8 v5, i8 v6, i8 v7
+ ) : TSimd8({v0, v1, v2, v3, v4, v5, v6, v7})
+ {
+ }
+
+ inline TSimd8<i8> MaxValue(const TSimd8<i8> other) const {
+ return (*this > other).Any() ? *this : other;
+ }
+ inline TSimd8<i8> MinValue(const TSimd8<i8> other) const {
+ return (*this < other).Any() ? *this : other;
+ }
+
+ inline TSimd8<bool> operator>(const TSimd8<i8> other) const {
+ return i64(this->Value) > i64(other.Value);
+ }
+ inline TSimd8<bool> operator<(const TSimd8<i8> other) const {
+ return i64(this->Value) < i64(other.Value);
+ }
+};
+
+template<>
+struct TSimd8<ui8>: TBase8Numeric<ui8> {
+ inline TSimd8()
+ : TBase8Numeric<ui8>()
+ {
+ }
+ inline TSimd8(const ui64 _value)
+ : TBase8Numeric<ui8>(_value)
+ {
+ }
+ inline TSimd8(ui8 _value)
+ : TSimd8(Set(_value))
+ {
+ }
+ inline TSimd8(const ui8 values[8])
+ : TSimd8(Load(values))
+ {
+ }
+ inline TSimd8(
+ ui8 v0, ui8 v1, ui8 v2, ui8 v3, ui8 v4, ui8 v5, ui8 v6, ui8 v7
+ ) : TSimd8({v0, v1, v2, v3, v4, v5, v6, v7}
+ ) {}
+
+ inline TSimd8<ui8> MaxValue(const TSimd8<ui8> other) const {
+ return this->Value > other.Value ? *this : other;
+ }
+ inline TSimd8<ui8> MinValue(const TSimd8<ui8> other) const {
+ return this->Value < other.Value ? *this : other;
+ }
+
+ inline TSimd8<bool> operator<=(const TSimd8<ui8> other) const {
+ return other.MaxValue(*this) == other;
+ }
+ inline TSimd8<bool> operator>=(const TSimd8<ui8> other) const {
+ return other.MinValue(*this) == other;
+ }
+
+ inline TSimd8<bool> BitsNotSet() const {
+ return this->Value == 0;
+ }
+ inline TSimd8<bool> AnyBitsSet() const {
+ return ~this->BitsNotSet();
+ }
+ inline bool BitsNotSetAnywhere() const {
+ return BitsNotSet().Any();
+ }
+ inline bool AnyBitsSetAnywhere() const {
+ return !BitsNotSetAnywhere();
+ }
+ inline bool BitsNotSetAnywhere(TSimd8<ui8> bits) const {
+ return ((*this) & bits).Value == 0;
+ }
+ inline bool AnyBitsSetAnywhere(TSimd8<ui8> bits) const {
+ return !BitsNotSetAnywhere(bits);
+ }
+};
+
+}
+}
diff --git a/ydb/library/yql/utils/simd/simd_sse42.h b/ydb/library/yql/utils/simd/simd_sse42.h
index d2d74dc0e72..3e6e1a1c9a8 100644
--- a/ydb/library/yql/utils/simd/simd_sse42.h
+++ b/ydb/library/yql/utils/simd/simd_sse42.h
@@ -3,6 +3,8 @@
#include <cstdint>
#include <immintrin.h>
+#pragma clang attribute push(__attribute__((target("sse4.2"))), apply_to=function)
+
namespace NSimd {
namespace NSSE42 {
@@ -21,24 +23,24 @@ struct TBase {
: Value(value) {
}
- inline operator const __m128i&() const {
+ explicit inline operator const __m128i&() const {
return this->Value;
}
- inline operator __m128i&() {
+ explicit inline operator __m128i&() {
return this->Value;
}
inline Child operator|(const Child other) const {
- return _mm_or_si128(*this, other);
+ return _mm_or_si128(this->Value, other.Value);
}
inline Child operator&(const Child other) const {
- return _mm_and_si128(*this, other);
+ return _mm_and_si128(this->Value, other.Value);
}
inline Child operator^(const Child other) const {
- return _mm_xor_si128(*this, other);
+ return _mm_xor_si128(this->Value, other.Value);
}
inline Child BitAndNot(const Child other) const {
- return _mm_andnot_si128(*this, other);
+ return _mm_andnot_si128(this->Value, other.Value);
};
inline Child& operator|=(const Child other) {
auto cast = static_cast<Child*>(*this);
@@ -71,7 +73,7 @@ struct TBase8: TBase<TSimd8<T>> {
}
friend inline Mask operator==(const TSimd8<T> lhs, const TSimd8<T> rhs) {
- return _mm_cmpeq_epi8(lhs, rhs);
+ return _mm_cmpeq_epi8(lhs.Value, rhs.Value);
}
static const int SIZE = sizeof(TBase<T>::Value);
@@ -100,7 +102,7 @@ struct TSimd8<bool>: TBase8<bool> {
}
inline bool Any() const {
- return !_mm_testz_si128(*this, *this);
+ return !_mm_testz_si128(this->Value, this->Value);
}
inline TSimd8<bool> operator~() const {
@@ -141,14 +143,14 @@ struct TBase8Numeric: TBase8<T> {
}
inline void Store(T dst[16]) const {
- return _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), *this);
+ return _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), this->Value);
}
inline TSimd8<T> operator+(const TSimd8<T> other) const {
- return _mm_add_epi8(*this, other);
+ return _mm_add_epi8(this->Value, other.Value);
}
inline TSimd8<T> operator-(const TSimd8<T> other) const {
- return _mm_sub_epi8(*this, other);
+ return _mm_sub_epi8(this->Value, other.Value);
}
inline TSimd8<T>& operator+=(const TSimd8<T> other) {
*this = *this + other;
@@ -204,16 +206,16 @@ struct TSimd8<i8> : TBase8Numeric<i8> {
}
inline TSimd8<i8> MaxValue(const TSimd8<i8> other) const {
- return _mm_max_epi8(*this, other);
+ return _mm_max_epi8(this->Value, other.Value);
}
inline TSimd8<i8> MinValue(const TSimd8<i8> other) const {
- return _mm_min_epi8(*this, other);
+ return _mm_min_epi8(this->Value, other.Value);
}
inline TSimd8<bool> operator>(const TSimd8<i8> other) const {
- return _mm_cmpgt_epi8(*this, other);
+ return _mm_cmpgt_epi8(this->Value, other.Value);
}
inline TSimd8<bool> operator<(const TSimd8<i8> other) const {
- return _mm_cmpgt_epi8(other, *this);
+ return _mm_cmpgt_epi8(other.Value, this->Value);
}
};
@@ -254,10 +256,10 @@ struct TSimd8<ui8>: TBase8Numeric<ui8> {
}
inline TSimd8<ui8> MaxValue(const TSimd8<ui8> other) const {
- return _mm_max_epu8(*this, other);
+ return _mm_max_epu8(this->Value, other.Value);
}
inline TSimd8<ui8> MinValue(const TSimd8<ui8> other) const {
- return _mm_min_epu8(other, *this);
+ return _mm_min_epu8(other.Value, this->Value);
}
inline TSimd8<bool> operator<=(const TSimd8<ui8> other) const {
return other.MaxValue(*this) == other;
@@ -273,13 +275,13 @@ struct TSimd8<ui8>: TBase8Numeric<ui8> {
return ~this->BitsNotSet();
}
inline bool BitsNotSetAnywhere() const {
- return _mm_testz_si128(*this, *this);
+ return _mm_testz_si128(this->Value, this->Value);
}
inline bool AnyBitsSetAnywhere() const {
return !BitsNotSetAnywhere();
}
inline bool BitsNotSetAnywhere(TSimd8<ui8> bits) const {
- return _mm_testz_si128(*this, bits);
+ return _mm_testz_si128(this->Value, bits.Value);
}
inline bool AnyBitsSetAnywhere(TSimd8<ui8> bits) const {
return !BitsNotSetAnywhere(bits);
@@ -287,18 +289,22 @@ struct TSimd8<ui8>: TBase8Numeric<ui8> {
template<int N>
inline TSimd8<ui8> Shr() const {
- return TSimd8<ui8>(_mm_srli_epi16(*this, N)) & ui8(0xFFu >> N);
+ return TSimd8<ui8>(_mm_srli_epi16(this->Value, N)) & ui8(0xFFu >> N);
}
template<int N>
inline TSimd8<ui8> Shl() const {
- return TSimd8<ui8>(_mm_slli_epi16(*this, N)) & ui8(0xFFu << N);
+ return TSimd8<ui8>(_mm_slli_epi16(this->Value, N)) & ui8(0xFFu << N);
}
template<int N>
inline int GetBit() const {
- return _mm_movemask_epi8(_mm_slli_epi16(*this, 7-N));
+ return _mm_movemask_epi8(_mm_slli_epi16(this->Value, 7-N));
}
};
}
-} \ No newline at end of file
+}
+
+
+
+#pragma clang attribute pop \ No newline at end of file
diff --git a/ydb/library/yql/utils/simd/simd_ut.cpp b/ydb/library/yql/utils/simd/simd_ut.cpp
index b13421a6e48..5fb5b299573 100644
--- a/ydb/library/yql/utils/simd/simd_ut.cpp
+++ b/ydb/library/yql/utils/simd/simd_ut.cpp
@@ -1,8 +1,30 @@
#include <library/cpp/testing/unittest/registar.h>
#include <util/system/cpu_id.h>
+#include "simd.h"
+
+template<typename TTraits>
+void Reverse(ui8* buf, ui8 *result_buf, int len) {
+ using TSimdUI8 = typename TTraits::template TSimd8<ui8>;
+ int id = 0;
+ while (id + TTraits::Size <= len) {
+ TSimdUI8 x(buf + id);
+ (~x).Store(result_buf + id);
+ id += TTraits::Size;
+ }
+ while (id < len) {
+ *(result_buf + id) = ~(*(buf + id));
+ id += 1;
+ }
+}
+
+struct TTestFactory {
+ template<typename T>
+ int Create() const {
+ return T::Size;
+ }
+};
#pragma clang attribute push(__attribute__((target("avx2"))), apply_to=function)
-#include <ydb/library/yql/utils/simd/simd_avx2.h>
Y_UNIT_TEST_SUITE(TSimdAVX2) {
using namespace NSimd::NAVX2;
Y_UNIT_TEST(SimdBool) {
@@ -86,11 +108,27 @@ Y_UNIT_TEST_SUITE(TSimdAVX2) {
UNIT_ASSERT_EQUAL(((a + b) == a3).Any(), true);
UNIT_ASSERT_EQUAL(((a - b) == a2).Any(), true);
}
+
+ Y_UNIT_TEST(SimdTrait) {
+ if (!NX86::HaveAVX2()) {
+ return;
+ }
+
+ ui8 buf[1000];
+ for (int i = 0; i < 1000; i += 1) {
+ buf[i] = i;
+ }
+ ui8 result_buf[1000] = {0};
+ Reverse<NSimd::TSimdAVX2Traits>(buf, result_buf, 1000);
+ for (int i = 0; i < 1000; i += 1) {
+ UNIT_ASSERT_EQUAL(result_buf[i], ui8(~buf[i]));
+ }
+ }
}
+
#pragma clang attribute pop
#pragma clang attribute push(__attribute__((target("sse4.2"))), apply_to=function)
-#include <ydb/library/yql/utils/simd/simd_sse42.h>
Y_UNIT_TEST_SUITE(TSimdSSE42) {
using namespace NSimd::NSSE42;
Y_UNIT_TEST(SimdBool) {
@@ -174,5 +212,46 @@ Y_UNIT_TEST_SUITE(TSimdSSE42) {
UNIT_ASSERT_EQUAL(((a + b) == a3).Any(), true);
UNIT_ASSERT_EQUAL(((a - b) == a2).Any(), true);
}
+
+ Y_UNIT_TEST(SimdTrait) {
+ if (!NX86::HaveSSE42()) {
+ return;
+ }
+
+ ui8 buf[1000];
+ for (int i = 0; i < 1000; i += 1) {
+ buf[i] = i;
+ }
+ ui8 result_buf[1000] = {0};
+ Reverse<NSimd::TSimdSSE42Traits>(buf, result_buf, 1000);
+ for (int i = 0; i < 1000; i += 1) {
+ UNIT_ASSERT_EQUAL(result_buf[i], ui8(~buf[i]));
+ }
+ }
}
-#pragma clang attribute pop \ No newline at end of file
+#pragma clang attribute pop
+
+Y_UNIT_TEST_SUITE(SimdFallback) {
+ Y_UNIT_TEST(SimdTrait) {
+ ui8 buf[1000];
+ for (int i = 0; i < 1000; i += 1) {
+ buf[i] = i;
+ }
+ ui8 result_buf[1000] = {0};
+ Reverse<NSimd::TSimdFallbackTraits>(buf, result_buf, 1000);
+ for (int i = 0; i < 1000; i += 1) {
+ UNIT_ASSERT_EQUAL(result_buf[i], ui8(~buf[i]));
+ }
+ }
+
+ Y_UNIT_TEST(BestTrait) {
+ TTestFactory x;
+ if (NX86::HaveAVX2()) {
+ UNIT_ASSERT_EQUAL(NSimd::SelectSimdTraits(x), 32);
+ } else if (NX86::HaveSSE42()) {
+ UNIT_ASSERT_EQUAL(NSimd::SelectSimdTraits(x), 16);
+ } else {
+ UNIT_ASSERT_EQUAL(NSimd::SelectSimdTraits(x), 8);
+ }
+ }
+} \ No newline at end of file