Files
gencpp/base/dependencies/simd.hpp
T
ed b5b7b9ab4b Added new string template formatter
- Based on a template formatter I have in used/evolved in other projects.
- Will eventually replace the current token formatter used in untyped code.
- Has some x86 simd support.. (opt-in if avail).
2026-10-16 13:30:42 -04:00

64 lines
2.2 KiB
C++

#ifdef INTELLISENSE_DIRECTIVES
#pragma once
#include "debug.hpp"
#endif
#pragma region SIMD
// Lane names use bit widths: sixteen unsigned 8-bit lanes or four unsigned 32-bit lanes.
// Vector operations are available on Windows x64.
#if defined(GEN_SYSTEM_WINDOWS) && (defined(_M_X64) || defined(__x86_64__))
typedef __m128i u8x16;
typedef __m128i u32x4;
// Unaligned loads require 16 or 8 readable bytes respectively. load8 zeros lanes 8 through 15.
internal forceinline u8x16 u8x16_load (void const* address) { return _mm_loadu_si128(rcast(__m128i const*, address)); }
internal forceinline u8x16 u8x16_load8(void const* address) { return _mm_loadl_epi64(rcast(__m128i const*, address)); }
internal forceinline u8x16 u8x16_splat(u8 value) { return _mm_set1_epi8(scast(char, value)); }
internal forceinline u8x16 u8x16_equal(u8x16 lhs, u8x16 rhs) { return _mm_cmpeq_epi8(lhs, rhs); }
// Extract each lane's high bit. Bit 0 represents lane 0 at the lowest address.
internal forceinline u16 u8x16_mask(u8x16 value) { return scast(u16, _mm_movemask_epi8(value)); }
// Reads 16 bytes without requiring alignment.
internal forceinline u32x4 u32x4_load(void const* address) { return _mm_loadu_si128(rcast(__m128i const*, address)); }
internal forceinline u32x4 u32x4_splat(u32 value) { return _mm_set1_epi32(scast(s32, value)); }
internal forceinline u32x4 u32x4_equal(u32x4 lhs, u32x4 rhs) { return _mm_cmpeq_epi32(lhs, rhs); }
// Extract each lane's high bit into bits 0 through 3. Higher result bits are zero.
internal forceinline u8 u32x4_mask(u32x4 value) { return scast(u8, _mm_movemask_ps(_mm_castsi128_ps(value))); }
#endif
// Requires a nonzero mask. Returns the lowest set-bit index, from 0 through 31.
s32 u32_mask_first_set(u32 mask);
#if defined(GEN_SYSTEM_WINDOWS)
internal forceinline
s32 u32_mask_first_set(u32 mask) {
GEN_ASSERT(mask != 0);
unsigned long bit_index = 0;
_BitScanForward(& bit_index, scast(unsigned long, mask));
return scast(s32, bit_index);
}
#endif
#if ! defined(GEN_SYSTEM_WINDOWS)
internal forceinline
s32 u32_mask_first_set(u32 mask) {
GEN_ASSERT(mask != 0);
s32 bit = 0;
u32 bits = mask;
while ((bits & 1u) == 0u) {
bits >>= 1;
bit += 1;
}
return bit;
}
#endif
#pragma endregion SIMD