Skip to content

Commit b84cdac

Browse files
committed
(features_cpu) Fix SIMD detection on macOS
The macOS branch of cpu_features_get() checked only the return value of sysctlbyname(), which is 0 (success) whenever the key exists -- regardless of whether the feature is actually supported. Apple's hw.optional.* keys are present on every machine and report 0 when the feature is unavailable, so the existence check incorrectly flagged unsupported features as present. Most visibly, AVX-512 was reported on Intel Macs without AVX-512 support (e.g. i9-9880H / Coffee Lake) because hw.optional.avx512f exists but returns 0 there. SSE/AVX/AVX2/NEON happened to produce correct results only because their keys always read 1 on hardware that supports them. Pass a buffer to sysctlbyname() and check the actual value.
1 parent 33b7386 commit b84cdac

1 file changed

Lines changed: 54 additions & 32 deletions

File tree

libretro-common/features/features_cpu.c

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -614,56 +614,78 @@ uint64_t cpu_features_get(void)
614614
const int avx_flags = (1 << 27) | (1 << 28);
615615
#endif
616616
#if defined(__MACH__)
617-
size_t _len = sizeof(size_t);
618-
if (sysctlbyname("hw.optional.floatingpoint", NULL, &_len, NULL, 0) == 0)
617+
/* sysctlbyname() returns 0 (success) whenever the key exists, regardless
618+
* of its value. On Intel Macs the hw.optional.* keys are always present
619+
* but report 0 when the feature is unsupported (e.g. avx512f on pre-Skylake
620+
* Xeon CPUs). We therefore have to read the value, not just the success
621+
* code. */
622+
int _val = 0;
623+
size_t _len = sizeof(_val);
624+
if ( sysctlbyname("hw.optional.floatingpoint", &_val, &_len, NULL, 0) == 0
625+
&& _val)
619626
cpu |= RETRO_SIMD_CMOV;
620627

621628
#if defined(CPU_X86)
622-
_len = sizeof(size_t);
623-
if (sysctlbyname("hw.optional.mmx", NULL, &_len, NULL, 0) == 0)
629+
_val = 0;
630+
_len = sizeof(_val);
631+
if (sysctlbyname("hw.optional.mmx", &_val, &_len, NULL, 0) == 0 && _val)
624632
cpu |= RETRO_SIMD_MMX | RETRO_SIMD_MMXEXT;
625-
_len = sizeof(size_t);
626-
if (sysctlbyname("hw.optional.sse", NULL, &_len, NULL, 0) == 0)
633+
_val = 0;
634+
_len = sizeof(_val);
635+
if (sysctlbyname("hw.optional.sse", &_val, &_len, NULL, 0) == 0 && _val)
627636
cpu |= RETRO_SIMD_SSE;
628-
_len = sizeof(size_t);
629-
if (sysctlbyname("hw.optional.sse2", NULL, &_len, NULL, 0) == 0)
637+
_val = 0;
638+
_len = sizeof(_val);
639+
if (sysctlbyname("hw.optional.sse2", &_val, &_len, NULL, 0) == 0 && _val)
630640
cpu |= RETRO_SIMD_SSE2;
631-
_len = sizeof(size_t);
632-
if (sysctlbyname("hw.optional.sse3", NULL, &_len, NULL, 0) == 0)
641+
_val = 0;
642+
_len = sizeof(_val);
643+
if (sysctlbyname("hw.optional.sse3", &_val, &_len, NULL, 0) == 0 && _val)
633644
cpu |= RETRO_SIMD_SSE3;
634-
_len = sizeof(size_t);
635-
if (sysctlbyname("hw.optional.supplementalsse3", NULL, &_len, NULL, 0) == 0)
645+
_val = 0;
646+
_len = sizeof(_val);
647+
if (sysctlbyname("hw.optional.supplementalsse3", &_val, &_len, NULL, 0) == 0 && _val)
636648
cpu |= RETRO_SIMD_SSSE3;
637-
_len = sizeof(size_t);
638-
if (sysctlbyname("hw.optional.sse4_1", NULL, &_len, NULL, 0) == 0)
649+
_val = 0;
650+
_len = sizeof(_val);
651+
if (sysctlbyname("hw.optional.sse4_1", &_val, &_len, NULL, 0) == 0 && _val)
639652
cpu |= RETRO_SIMD_SSE4;
640-
_len = sizeof(size_t);
641-
if (sysctlbyname("hw.optional.sse4_2", NULL, &_len, NULL, 0) == 0)
653+
_val = 0;
654+
_len = sizeof(_val);
655+
if (sysctlbyname("hw.optional.sse4_2", &_val, &_len, NULL, 0) == 0 && _val)
642656
cpu |= RETRO_SIMD_SSE42;
643-
_len = sizeof(size_t);
644-
if (sysctlbyname("hw.optional.aes", NULL, &_len, NULL, 0) == 0)
657+
_val = 0;
658+
_len = sizeof(_val);
659+
if (sysctlbyname("hw.optional.aes", &_val, &_len, NULL, 0) == 0 && _val)
645660
cpu |= RETRO_SIMD_AES;
646-
_len = sizeof(size_t);
647-
if (sysctlbyname("hw.optional.avx1_0", NULL, &_len, NULL, 0) == 0)
661+
_val = 0;
662+
_len = sizeof(_val);
663+
if (sysctlbyname("hw.optional.avx1_0", &_val, &_len, NULL, 0) == 0 && _val)
648664
cpu |= RETRO_SIMD_AVX;
649-
_len = sizeof(size_t);
650-
if (sysctlbyname("hw.optional.avx2_0", NULL, &_len, NULL, 0) == 0)
665+
_val = 0;
666+
_len = sizeof(_val);
667+
if (sysctlbyname("hw.optional.avx2_0", &_val, &_len, NULL, 0) == 0 && _val)
651668
cpu |= RETRO_SIMD_AVX2;
652-
_len = sizeof(size_t);
653-
if (sysctlbyname("hw.optional.avx512f", NULL, &_len, NULL, 0) == 0)
669+
_val = 0;
670+
_len = sizeof(_val);
671+
if (sysctlbyname("hw.optional.avx512f", &_val, &_len, NULL, 0) == 0 && _val)
654672
cpu |= RETRO_SIMD_AVX512;
655-
_len = sizeof(size_t);
656-
if (sysctlbyname("hw.optional.altivec", NULL, &_len, NULL, 0) == 0)
673+
_val = 0;
674+
_len = sizeof(_val);
675+
if (sysctlbyname("hw.optional.altivec", &_val, &_len, NULL, 0) == 0 && _val)
657676
cpu |= RETRO_SIMD_VMX;
658677
#else
659-
_len = sizeof(size_t);
660-
if (sysctlbyname("hw.optional.neon", NULL, &_len, NULL, 0) == 0)
678+
_val = 0;
679+
_len = sizeof(_val);
680+
if (sysctlbyname("hw.optional.neon", &_val, &_len, NULL, 0) == 0 && _val)
661681
cpu |= RETRO_SIMD_NEON;
662-
_len = sizeof(size_t);
663-
if (sysctlbyname("hw.optional.neon_fp16", NULL, &_len, NULL, 0) == 0)
682+
_val = 0;
683+
_len = sizeof(_val);
684+
if (sysctlbyname("hw.optional.neon_fp16", &_val, &_len, NULL, 0) == 0 && _val)
664685
cpu |= RETRO_SIMD_VFPV3;
665-
_len = sizeof(size_t);
666-
if (sysctlbyname("hw.optional.neon_hpfp", NULL, &_len, NULL, 0) == 0)
686+
_val = 0;
687+
_len = sizeof(_val);
688+
if (sysctlbyname("hw.optional.neon_hpfp", &_val, &_len, NULL, 0) == 0 && _val)
667689
cpu |= RETRO_SIMD_VFPV4;
668690
#endif
669691
#elif defined(_XBOX1)

0 commit comments

Comments
 (0)