x86 SIMD: build only baseline ISA tiers under PlayStation clang

Clang's immintrin.h for PlayStation targets (and clang-cl) declares
only the intrinsics of ISAs the whole build enables, so the AVX2 and
AVX-512 kernels that sinc_resampler, pixconv, float_to_s16 and
state_manager compile under per-function targets do not exist there.
On those compilers a tier is built only when the baseline carries it:
the PS4 keeps sinc's AVX kernel, the PS5 keeps the AVX2 tiers, and the
run-time choice never picks a tier that was left out.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-10-27 20:39:56 +01:00
1 parent 7b23ab8aa4
commit cabaa7b04d
4 files changed
+67

No files matched your search

@@ -140,12 +140,27 @@ void convert_float_to_s16_init_simd(void)
#if defined(_MSC_VER) && !defined(__clang__)
#if _MSC_VER >= 1911
#define FLOAT_TO_S16_HAVE_WIDE 1
#define FLOAT_TO_S16_HAVE_AVX512 1
#define FLOAT_TO_S16_TARGET_AVX2
#define FLOAT_TO_S16_TARGET_AVX512
#endif
#elif defined(__clang__) && (defined(__SCE__) || defined(_MSC_VER))
/* Clang's immintrin.h for PlayStation and clang-cl only declares the
* intrinsics of ISAs enabled for the whole build, so per-function
* targets cannot reach them; build a tier only when the baseline has
* it (PS5's Zen 2 keeps AVX2, PS4's Jaguar has neither). */
#ifdef __AVX2__
#define FLOAT_TO_S16_HAVE_WIDE 1
#define FLOAT_TO_S16_TARGET_AVX2
#ifdef __AVX512F__
#define FLOAT_TO_S16_HAVE_AVX512 1
#define FLOAT_TO_S16_TARGET_AVX512
#endif
#endif
#elif (defined(__clang__) && __clang_major__ >= 4) \
|| (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 5)
#define FLOAT_TO_S16_HAVE_WIDE 1
#define FLOAT_TO_S16_HAVE_AVX512 1
#define FLOAT_TO_S16_TARGET_AVX2 __attribute__((target("avx2")))
#define FLOAT_TO_S16_TARGET_AVX512 __attribute__((target("avx512f")))
#endif
@@ -206,6 +221,7 @@ static size_t float_to_s16_avx2(int16_t *s, const float *in, size_t len)
/* Sixteen samples a step, the last step masked: the loads and the
* saturating narrow-and-store skip lanes past the end instead of a
* scalar tail, so it converts the whole buffer. */
#ifdef FLOAT_TO_S16_HAVE_AVX512
FLOAT_TO_S16_TARGET_AVX512
static void float_to_s16_avx512(int16_t *s, const float *in, size_t len)
{
@@ -235,6 +251,7 @@ static void float_to_s16_avx512(int16_t *s, const float *in, size_t len)
FLOAT_TO_S16_ZEROUPPER();
}
#endif
#endif
/* The SSE2 / AltiVec / Allegrex loop and the scalar tail. */
static void convert_float_to_s16_base(int16_t *s, const float *in, size_t len)
@@ -390,11 +407,13 @@ void convert_float_to_s16(int16_t *s, const float *in, size_t len)
if (float_to_s16_tier_cap >= 0 && tier > float_to_s16_tier_cap)
tier = float_to_s16_tier_cap;
#endif
#ifdef FLOAT_TO_S16_HAVE_AVX512
if (tier == 2)
{
float_to_s16_avx512(s, in, len);
return;
}
#endif
if (tier == 1)
{
size_t done = float_to_s16_avx2(s, in, len);
@@ -413,8 +432,10 @@ void convert_float_to_s16_init_simd(void)
float_to_s16_tier = 0;
if (cpu & RETRO_SIMD_AVX2)
float_to_s16_tier = 1;
#ifdef FLOAT_TO_S16_HAVE_AVX512
if (cpu & RETRO_SIMD_AVX512)
float_to_s16_tier = 2;
#endif
#endif
}
#endif
@@ -63,6 +63,18 @@
#define SINC_HAVE_AVX512 1
#define SINC_TARGET_AVX512
#endif
#elif defined(__clang__) && (defined(__SCE__) || defined(_MSC_VER))
/* Clang's immintrin.h for PlayStation and clang-cl only declares the
* intrinsics of ISAs enabled for the whole build, so per-function
* targets cannot reach them; build a tier only when the baseline has it. */
#ifdef __AVX__
#define SINC_HAVE_AVX 1
#define SINC_TARGET_AVX
#endif
#ifdef __AVX512F__
#define SINC_HAVE_AVX512 1
#define SINC_TARGET_AVX512
#endif
#elif (defined(__clang__) && __clang_major__ >= 4) \
|| (defined(__GNUC__) && !defined(__clang__) \
&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)))
+22
View File
@@ -177,12 +177,27 @@ void conv_0rgb1555_rgb565(void *output_, const void *input_,
#if defined(_MSC_VER) && !defined(__clang__)
#if _MSC_VER >= 1911
#define PIXCONV_HAVE_WIDE 1
#define PIXCONV_HAVE_AVX512 1
#define PIXCONV_TARGET_AVX2
#define PIXCONV_TARGET_AVX512
#endif
#elif defined(__clang__) && (defined(__SCE__) || defined(_MSC_VER))
/* Clang's immintrin.h for PlayStation and clang-cl only declares the
* intrinsics of ISAs enabled for the whole build, so per-function
* targets cannot reach them; build a tier only when the baseline has
* it (PS5's Zen 2 keeps AVX2, PS4's Jaguar has neither). */
#ifdef __AVX2__
#define PIXCONV_HAVE_WIDE 1
#define PIXCONV_TARGET_AVX2
#if defined(__AVX512F__) && defined(__AVX512BW__)
#define PIXCONV_HAVE_AVX512 1
#define PIXCONV_TARGET_AVX512
#endif
#endif
#elif (defined(__clang__) && __clang_major__ >= 4) \
|| (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 5)
#define PIXCONV_HAVE_WIDE 1
#define PIXCONV_HAVE_AVX512 1
#define PIXCONV_TARGET_AVX2 __attribute__((target("avx2")))
#define PIXCONV_TARGET_AVX512 __attribute__((target("avx512f,avx512bw")))
#endif
@@ -229,8 +244,10 @@ static int pixconv_simd_tier(void)
tier = 0;
if (cpu & RETRO_SIMD_AVX2)
tier = 1;
#ifdef PIXCONV_HAVE_AVX512
if (cpu & RETRO_SIMD_AVX512)
tier = 2;
#endif
retro_atomic_store_release_int(&pixconv_tier_cached, 4 | tier);
}
#ifdef PIXCONV_TEST_HOOKS
@@ -314,6 +331,7 @@ static void pixconv_16to32_avx2(uint32_t *output, const uint16_t *input,
PIXCONV_ZEROUPPER();
}
#ifdef PIXCONV_HAVE_AVX512
PIXCONV_TARGET_AVX512
static void pixconv_16to32_avx512(uint32_t *output, const uint16_t *input,
int width, int height, int out_stride, int in_stride, int fmt)
@@ -371,6 +389,8 @@ static void pixconv_16to32_avx512(uint32_t *output, const uint16_t *input,
PIXCONV_ZEROUPPER();
}
#endif
/* Runs the conversion wide and returns 1, or returns 0 for the caller's
* own SSE2 path. */
static int pixconv_16to32_wide(void *output, const void *input,
@@ -378,10 +398,12 @@ static int pixconv_16to32_wide(void *output, const void *input,
{
switch (pixconv_simd_tier())
{
#ifdef PIXCONV_HAVE_AVX512
case 2:
pixconv_16to32_avx512((uint32_t*)output, (const uint16_t*)input,
width, height, out_stride, in_stride, fmt);
return 1;
#endif
case 1:
pixconv_16to32_avx2((uint32_t*)output, (const uint16_t*)input,
width, height, out_stride, in_stride, fmt);
+12
View File
@@ -77,6 +77,17 @@
#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
#include <immintrin.h>
#include <features/features_cpu.h>
#if defined(__clang__) && (defined(__SCE__) || defined(_MSC_VER))
/* Clang's immintrin.h for PlayStation and clang-cl only declares the
* intrinsics of ISAs enabled for the whole build, so per-function
* targets cannot reach them; build a tier only when the baseline has it. */
#ifdef __AVX2__
#define STATE_MANAGER_HAVE_AVX2_SCAN 1
#endif
#if defined(__AVX512F__) && defined(__AVX512BW__)
#define STATE_MANAGER_HAVE_AVX512_SCAN 1
#endif
#else
#define STATE_MANAGER_HAVE_AVX2_SCAN 1
/* AVX-512BW intrinsics need GCC 5 or Clang 4. RETRO_SIMD_AVX512 promises
* BW, so the flag alone gates the scanner at runtime. */
@@ -86,6 +97,7 @@
#endif
#endif
#endif
#endif
/* Tail padding on each block, in bytes. Must be >= the widest vector load
* find_change() or find_same() can issue (64 for AVX-512). */