Added simd_i8_cmpeq for all SIMD widths. Fixed BitArray kSimdByteMask shift for 256-bit SIMD. (#466)

This commit is contained in:
Branimir Karadžić
2026-10-17 17:20:12 -07:00
committed by GitHub
parent b111b30713
commit dd261e2775
12 changed files with 156 additions and 1 deletions
+9
View File
@@ -750,6 +750,15 @@ namespace bx
return vreinterpretq_f32_s8(result);
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd128_i8_cmpeq(simd128_neon_t _a, simd128_neon_t _b)
{
const int8x16_t a = vreinterpretq_s8_f32(_a);
const int8x16_t b = vreinterpretq_s8_f32(_b);
const uint8x16_t result = vceqq_s8(a, b);
return vreinterpretq_f32_u8(result);
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd128_u8_satadd(simd128_neon_t _a, simd128_neon_t _b)
{
+21
View File
@@ -1136,6 +1136,27 @@ namespace bx
#endif // BX_SIMD_LANGEXT
}
template<>
inline BX_CONSTEXPR_FUNC simd128_ref_t simd128_i8_cmpeq(simd128_ref_t _a, simd128_ref_t _b)
{
#if BX_SIMD_LANGEXT
const simd128_i8_langext_t a = bitCast<simd128_i8_langext_t>(_a);
const simd128_i8_langext_t b = bitCast<simd128_i8_langext_t>(_b);
const auto mask = a == b;
const simd128_ref_t result = bitCast<simd128_ref_t>(mask);
return result;
#else
const simd128_u8_ref_t a = bitCast<simd128_u8_ref_t>(_a);
const simd128_u8_ref_t b = bitCast<simd128_u8_ref_t>(_b);
simd128_u8_ref_t result;
for (int ii = 0; ii < 16; ++ii)
{
result.u8[ii] = a.u8[ii] == b.u8[ii] ? 0xff : 0;
}
return bitCast<simd128_ref_t>(result);
#endif // BX_SIMD_LANGEXT
}
template<>
inline BX_CONSTEXPR_FUNC simd128_ref_t simd128_u8_satadd(simd128_ref_t _a, simd128_ref_t _b)
{
+9
View File
@@ -760,6 +760,15 @@ namespace bx
return _mm_castsi128_ps(result);
}
template<>
BX_SIMD_FORCE_INLINE simd128_sse_t simd128_i8_cmpeq(simd128_sse_t _a, simd128_sse_t _b)
{
const __m128i a = _mm_castps_si128(_a);
const __m128i b = _mm_castps_si128(_b);
const __m128i result = _mm_cmpeq_epi8(a, b);
return _mm_castsi128_ps(result);
}
template<>
BX_SIMD_FORCE_INLINE simd128_sse_t simd128_u8_satadd(simd128_sse_t _a, simd128_sse_t _b)
{
+6
View File
@@ -608,6 +608,12 @@ namespace bx
return wasm_i8x16_sub(_a, _b);
}
template<>
BX_SIMD_FORCE_INLINE simd128_wasm_t simd128_i8_cmpeq(simd128_wasm_t _a, simd128_wasm_t _b)
{
return wasm_i8x16_eq(_a, _b);
}
template<>
BX_SIMD_FORCE_INLINE simd128_wasm_t simd128_u8_satadd(simd128_wasm_t _a, simd128_wasm_t _b)
{
+30
View File
@@ -746,6 +746,16 @@ namespace bx
return result;
}
template<>
BX_SIMD_FORCE_INLINE simd256_avx_t simd256_i8_cmpeq(simd256_avx_t _a, simd256_avx_t _b)
{
const __m256i a = _mm256_castps_si256(_a);
const __m256i b = _mm256_castps_si256(_b);
const __m256i cmp = _mm256_cmpeq_epi8(a, b);
const __m256 result = _mm256_castsi256_ps(cmp);
return result;
}
template<>
BX_SIMD_FORCE_INLINE simd256_avx_t simd256_u8_satadd(simd256_avx_t _a, simd256_avx_t _b)
{
@@ -1420,6 +1430,26 @@ namespace bx
return result;
}
template<>
BX_SIMD_FORCE_INLINE simd256_avx_t simd256_i8_cmpeq(simd256_avx_t _a, simd256_avx_t _b)
{
const __m128 alo = _mm256_castps256_ps128(_a);
const __m128 ahi = _mm256_extractf128_ps(_a, 1);
const __m128 blo = _mm256_castps256_ps128(_b);
const __m128 bhi = _mm256_extractf128_ps(_b, 1);
const __m128i aloi = _mm_castps_si128(alo);
const __m128i ahii = _mm_castps_si128(ahi);
const __m128i bloi = _mm_castps_si128(blo);
const __m128i bhii = _mm_castps_si128(bhi);
const __m128i cmplo = _mm_cmpeq_epi8(aloi, bloi);
const __m128i cmphi = _mm_cmpeq_epi8(ahii, bhii);
const __m128 rlo = _mm_castsi128_ps(cmplo);
const __m128 rhi = _mm_castsi128_ps(cmphi);
const __m256 rlo256 = _mm256_castps128_ps256(rlo);
const __m256 result = _mm256_insertf128_ps(rlo256, rhi, 1);
return result;
}
template<>
BX_SIMD_FORCE_INLINE simd256_avx_t simd256_u8_satadd(simd256_avx_t _a, simd256_avx_t _b)
{
+9
View File
@@ -1513,6 +1513,15 @@ namespace bx
#endif // BX_SIMD256_LANGEXT
}
template<>
inline BX_CONSTEXPR_FUNC simd256_ref_t simd256_i8_cmpeq(simd256_ref_t _a, simd256_ref_t _b)
{
simd256_ref_t result;
result.lo = simd128_i8_cmpeq(_a.lo, _b.lo);
result.hi = simd128_i8_cmpeq(_a.hi, _b.hi);
return result;
}
template<>
inline BX_CONSTEXPR_FUNC simd256_ref_t simd256_u8_satadd(simd256_ref_t _a, simd256_ref_t _b)
{
+15
View File
@@ -571,6 +571,21 @@ BX_PRAGMA_DIAGNOSTIC_POP();
| (uint32_t(uint8_t(int8_t(_a.u32 >> 24) - int8_t(_b.u32 >> 24) ) ) << 24) };
}
inline BX_CONSTEXPR_FUNC simd32_t simd32_i8_cmpeq(simd32_t _a, simd32_t _b)
{
const simd32_t mask7 = simd32_splat(uint8_t(0x7f) );
const simd32_t diff = simd32_xor(_a, _b);
const simd32_t low7 = simd32_and(diff, mask7);
const simd32_t carry = simd32_u32_add(low7, mask7);
const simd32_t tmp0 = simd32_or(carry, diff);
const simd32_t nonZero = simd32_or(tmp0, mask7);
const simd32_t msbs = simd32_not(nonZero);
const simd32_t lsbs = simd32_x32_srl(msbs, 7);
const simd32_t low7s = simd32_u32_sub(msbs, lsbs);
const simd32_t result = simd32_or(msbs, low7s);
return result;
}
inline BX_CONSTEXPR_FUNC simd32_t simd32_u8_satadd(simd32_t _a, simd32_t _b)
{
simd32_t result{ .u32 = 0 };
+15
View File
@@ -979,6 +979,21 @@ namespace bx
return result;
}
inline BX_CONSTEXPR_FUNC simd64_t simd64_i8_cmpeq(simd64_t _a, simd64_t _b)
{
const simd64_t mask7 = simd64_splat(uint8_t(0x7f) );
const simd64_t diff = simd64_xor(_a, _b);
const simd64_t low7 = simd64_and(diff, mask7);
const simd64_t carry = simd64_u64_add(low7, mask7);
const simd64_t tmp0 = simd64_or(carry, diff);
const simd64_t nonZero = simd64_or(tmp0, mask7);
const simd64_t msbs = simd64_not(nonZero);
const simd64_t lsbs = simd64_x64_srl(msbs, 7);
const simd64_t low7s = simd64_u64_sub(msbs, lsbs);
const simd64_t result = simd64_or(msbs, low7s);
return result;
}
inline BX_CONSTEXPR_FUNC simd64_t simd64_u8_satadd(simd64_t _a, simd64_t _b)
{
simd64_t result{ .u64 = 0 };
+15
View File
@@ -93,6 +93,7 @@ namespace bx
BX_CONSTEXPR_FUNC simd32_t simd32_x16_srl(simd32_t _a, int _count);
BX_CONSTEXPR_FUNC simd32_t simd32_i8_add(simd32_t _a, simd32_t _b);
BX_CONSTEXPR_FUNC simd32_t simd32_i8_sub(simd32_t _a, simd32_t _b);
BX_CONSTEXPR_FUNC simd32_t simd32_i8_cmpeq(simd32_t _a, simd32_t _b);
BX_CONSTEXPR_FUNC simd32_t simd32_u8_satadd(simd32_t _a, simd32_t _b);
BX_CONSTEXPR_FUNC simd32_t simd32_u8_satsub(simd32_t _a, simd32_t _b);
BX_CONSTEXPR_FUNC simd32_t simd32_u16_satadd(simd32_t _a, simd32_t _b);
@@ -223,6 +224,7 @@ namespace bx
BX_CONSTEXPR_FUNC simd64_t simd64_x16_srl(simd64_t _a, int _count);
BX_CONSTEXPR_FUNC simd64_t simd64_i8_add(simd64_t _a, simd64_t _b);
BX_CONSTEXPR_FUNC simd64_t simd64_i8_sub(simd64_t _a, simd64_t _b);
BX_CONSTEXPR_FUNC simd64_t simd64_i8_cmpeq(simd64_t _a, simd64_t _b);
BX_CONSTEXPR_FUNC simd64_t simd64_u8_satadd(simd64_t _a, simd64_t _b);
BX_CONSTEXPR_FUNC simd64_t simd64_u8_satsub(simd64_t _a, simd64_t _b);
BX_CONSTEXPR_FUNC simd64_t simd64_u16_satadd(simd64_t _a, simd64_t _b);
@@ -728,6 +730,10 @@ namespace bx
template<typename Ty>
Ty simd128_u8_satadd(Ty _a, Ty _b);
///
template<typename Ty>
Ty simd128_i8_cmpeq(Ty _a, Ty _b);
/// 16xu8 saturating subtract.
///
template<typename Ty>
@@ -1067,6 +1073,7 @@ namespace bx
template<typename Ty> Ty simd256_i8_add(Ty _a, Ty _b);
template<typename Ty> Ty simd256_i8_sub(Ty _a, Ty _b);
template<typename Ty> Ty simd256_i8_cmpeq(Ty _a, Ty _b);
template<typename Ty> Ty simd256_u8_satadd(Ty _a, Ty _b);
template<typename Ty> Ty simd256_u8_satsub(Ty _a, Ty _b);
template<typename Ty> Ty simd256_u16_satadd(Ty _a, Ty _b);
@@ -1953,6 +1960,8 @@ namespace bx
template<>
BX_SIMD_FORCE_INLINE simd128_t simd_i32_mul(simd128_t _a, simd128_t _b) { return simd128_u32_mul(_a, _b); }
template<>
BX_SIMD_FORCE_INLINE simd128_t simd_i8_cmpeq(simd128_t _a, simd128_t _b) { return simd128_i8_cmpeq(_a, _b); }
template<>
BX_SIMD_FORCE_INLINE simd128_t simd_u8_satadd(simd128_t _a, simd128_t _b) { return simd128_u8_satadd(_a, _b); }
@@ -2366,6 +2375,8 @@ namespace bx
template<>
BX_SIMD_FORCE_INLINE simd256_t simd_i32_mul(simd256_t _a, simd256_t _b) { return simd256_u32_mul(_a, _b); }
template<>
BX_SIMD_FORCE_INLINE simd256_t simd_i8_cmpeq(simd256_t _a, simd256_t _b) { return simd256_i8_cmpeq(_a, _b); }
template<>
BX_SIMD_FORCE_INLINE simd256_t simd_u8_satadd(simd256_t _a, simd256_t _b) { return simd256_u8_satadd(_a, _b); }
@@ -2446,6 +2457,8 @@ namespace bx
template<>
BX_SIMD_FORCE_INLINE simd32_t simd_i32_mul(simd32_t _a, simd32_t _b) { return simd32_u32_mul(_a, _b); }
template<>
BX_SIMD_FORCE_INLINE simd32_t simd_i8_cmpeq(simd32_t _a, simd32_t _b) { return simd32_i8_cmpeq(_a, _b); }
template<>
BX_SIMD_FORCE_INLINE simd32_t simd_u8_satadd(simd32_t _a, simd32_t _b) { return simd32_u8_satadd(_a, _b); }
@@ -2826,6 +2839,8 @@ namespace bx
template<>
BX_SIMD_FORCE_INLINE simd64_t simd_i32_mul(simd64_t _a, simd64_t _b) { return simd64_u32_mul(_a, _b); }
template<>
BX_SIMD_FORCE_INLINE simd64_t simd_i8_cmpeq(simd64_t _a, simd64_t _b) { return simd64_i8_cmpeq(_a, _b); }
template<>
BX_SIMD_FORCE_INLINE simd64_t simd_u8_satadd(simd64_t _a, simd64_t _b) { return simd64_u8_satadd(_a, _b); }
+12
View File
@@ -404,6 +404,18 @@ namespace bx
template<typename Ty>
Ty simd_u8_satadd(Ty _a, Ty _b);
/// Per-lane i8 compare equal. Lanes set to all-ones if equal.
///
/// @param[in] _a First operand.
/// @param[in] _b Second operand.
///
/// @returns Per-lane comparison mask.
///
/// @remark Widths: simd32, simd64, simd128, simd256.
///
template<typename Ty>
Ty simd_i8_cmpeq(Ty _a, Ty _b);
/// Per-lane unsigned 8-bit saturating subtract: `max(_a - _b, 0)`.
///
/// @param[in] _a Minuend.
+1 -1
View File
@@ -217,7 +217,7 @@ namespace bx
return findLastWordRef<MatchT>(_ptr, _begin, _end);
}
constexpr uint32_t kSimdByteMask = 32 == sizeof(SimdWideT) ? UINT32_MAX : (1u << sizeof(SimdWideT) ) - 1;
constexpr uint32_t kSimdByteMask = uint32_t( (UINT64_C(1) << sizeof(SimdWideT) ) - 1);
template<typename Ty>
constexpr uint64_t kElementLowBits = 1 == sizeof(Ty) ? UINT64_C(0x0101010101010101)
+14
View File
@@ -1275,6 +1275,13 @@ TEST_CASE("simd128_i32_cmpeq", "[simd]")
check_u32("i32_cmpeq", simd128_i32_cmpeq(a, b), 0xffffffff, 0, 0xffffffff, 0);
}
TEST_CASE("simd128_i8_cmpeq", "[simd]")
{
const simd128_t a = simd128_ld<simd128_t>(0x00ff7f01u, 0x80808080u, 0xfefefefeu, 0x10204080u);
const simd128_t b = simd128_ld<simd128_t>(0x00fe7f80u, 0x80008080u, 0xfefeffffu, 0x10204081u);
check_u32("i8_cmpeq", simd128_i8_cmpeq(a, b), 0xff00ff00u, 0xff00ffffu, 0xffff0000u, 0xffffff00u);
}
TEST_CASE("simd128_i32_cmpgt", "[simd]")
{
const simd128_t a = simd128_ld<simd128_t>(5u, 2u, 7u, 4u);
@@ -2003,6 +2010,13 @@ TEST_CASE("simd32_i8_add_sub", "[simd]")
REQUIRE(simd32_i8_sub(a, b).u32 == 0xf1f2f3f4);
}
TEST_CASE("simd32_i8_cmpeq", "[simd]")
{
REQUIRE(simd32_i8_cmpeq(make_u32(0x00ff7f01), make_u32(0x00fe7f80)).u32 == 0xff00ff00);
REQUIRE(simd32_i8_cmpeq(make_u32(0x80808080), make_u32(0x80808080)).u32 == 0xffffffff);
REQUIRE(simd32_i8_cmpeq(make_u32(0x01020304), make_u32(0x10203040)).u32 == 0);
}
TEST_CASE("simd32_u8_sat", "[simd]")
{
// satadd: 0xf0 + 0x20 = saturates to 0xff per byte