many versions of simdid

This commit is contained in:
Youmu Liu
2026-02-25 18:02:56 +08:00
parent b71515b2d4
commit 1b04196314
6 changed files with 188 additions and 51 deletions
+49 -1
View File
@@ -77,6 +77,25 @@ static int is_intel_native_avx512(int family, int model)
}
}
/* Returns 1 if this AMD/Hygon CPU uses split-lane YMM (two fused 128-bit execution units).
* - AMD Zen1 (family 0x17, model < 0x30) and Zen+ (0x18-0x2F) use a split/glued path.
* - Hygon Dhyana is architecturally Zen1-based; always split.
* - AMD Zen2+ (family 0x17 model >= 0x30, family 0x19+) have native 256-bit execution. */
static int is_amd_glue_ymm(const char *vendor, int cpuid1_eax)
{
if (strcmp(vendor, "HygonGenuine") == 0)
return 1; /* Hygon is Zen1-based; always split YMM */
if (strcmp(vendor, "AuthenticAMD") != 0)
return 0;
int base_fam = (cpuid1_eax >> 8) & 0xF;
int ext_fam = (cpuid1_eax >> 20) & 0xFF;
int disp_fam = (base_fam < 0xF) ? base_fam : (base_fam + ext_fam);
int base_mdl = (cpuid1_eax >> 4) & 0xF;
int ext_mdl = (cpuid1_eax >> 16) & 0xF;
int disp_mdl = (ext_mdl << 4) | base_mdl;
return (disp_fam == 0x17) && (disp_mdl < 0x30); /* Zen1/Zen+ */
}
SN_API SIMDID SN_DECL sn_get_simd_level_local()
{
SIMDID _simdid = { 0 };
@@ -93,9 +112,12 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local()
const int is_intel = (strcmp(vendor, "GenuineIntel") == 0);
const int is_amd = (strcmp(vendor, "AuthenticAMD") == 0) ||
(strcmp(vendor, "HygonGenuine") == 0);
const int is_via = (strcmp(vendor, "CentaurHauls") == 0) ||
(memcmp(vendor, " Shanghai ", 12) == 0); /* VIA / Zhaoxin */
/* CPUID.1 */
get_cpuid(1, 0, &eax, &ebx, &ecx, &edx);
int cpuid1_eax = eax; /* saved for Zen1/Zen+ glue-YMM detection */
int family = ((eax >> 8) & 0xF) + ((eax >> 20) & 0xFF0);
int model = ((eax >> 4) & 0xF) | ((eax >> 12) & 0xF0);
@@ -108,12 +130,14 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local()
uint64_t root = SIMDID_PACK_ROOT(SIMDID_ROOT_X86_64);
uint64_t manu = SIMDID_PACK_MANU(is_intel ? SIMDID_MANU_INTEL :
is_amd ? SIMDID_MANU_AMD :
is_via ? SIMDID_MANU_VIA :
SIMDID_MANU_UNKNOWN);
uint64_t main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_NONE);
uint64_t avx512_bits = 0;
uint64_t amx_bits = 0;
uint64_t avx_bits = 0;
uint64_t avx10_bits = 0;
int has_hybrid = 0; /* filled from CPUID.7.0 EDX[15] when AVX present */
/* Baseline main level */
if (has_sse42)
@@ -122,6 +146,10 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local()
if (has_avx && has_osxsave && xgetbv_has_xmm_ymm()) {
avx_bits |= SIMDID_AVX;
/* Glued/split-lane YMM: early AMD Zen1/Zen+, Hygon, and VIA/Zhaoxin */
if (is_amd_glue_ymm(vendor, cpuid1_eax) || is_via)
avx_bits |= SIMDID_AVX_DUAL;
/* CPUID.7.0 */
get_cpuid(7, 0, &eax, &ebx, &ecx, &edx);
const int has_bmi1 = (ebx & (1 << 3)) != 0;
@@ -140,6 +168,7 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local()
const int has_amx_tile = (edx & (1 << 24)) != 0;
const int has_amx_int8 = (edx & (1 << 25)) != 0;
const int has_amx_bf16 = (edx & (1 << 22)) != 0;
has_hybrid = (edx & (1 << 15)) != 0; /* Intel hybrid core topology */
/* leaf 7, subleaf 1 for BF16/FP16/AVX10 convergence */
get_cpuid(7, 1, &eax, &ebx, &ecx, &edx);
@@ -217,9 +246,28 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local()
}
}
/* uArchHi: hybrid core topology and SIMD-dual summary */
uint64_t uarch_bits = 0;
if (has_hybrid) {
int h_eax = 0, h_ebx = 0, h_ecx = 0, h_edx = 0;
get_cpuid(0x1A, 0, &h_eax, &h_ebx, &h_ecx, &h_edx);
unsigned core_type = (unsigned)(h_eax >> 24) & 0xFFU;
if (core_type == 0x40) /* Intel Core / P-core → 10 */
uarch_bits |= SIMDID_UARCH_HYBRID_P;
else if (core_type == 0x20) /* Intel Atom / E-core → 01 */
uarch_bits |= SIMDID_UARCH_HYBRID_E;
/* else unknown hybrid core type → topology stays 00 */
} else {
/* Confirmed non-hybrid (unified) → set both bits = 11 (numerically strongest) */
uarch_bits |= SIMDID_UARCH_HYBRID_P | SIMDID_UARCH_HYBRID_E;
}
if ((avx_bits & SIMDID_AVX_DUAL) ||
((avx512_bits & SIMDID_AVX512_IMPL_MASK) == SIMDID_AVX512_IMPL_DUAL))
uarch_bits |= SIMDID_UARCH_SIMD_DUAL;
_simdid.mask = root | manu | main_lvl | SIMDID_PACK_AVX512(avx512_bits) |
SIMDID_PACK_AMX(amx_bits) | SIMDID_PACK_AVX(avx_bits) |
SIMDID_PACK_AVX10(avx10_bits);
SIMDID_PACK_AVX10(avx10_bits) | SIMDID_PACK_UARCH(uarch_bits);
return _simdid;
}
+24 -8
View File
@@ -61,7 +61,7 @@ static int impl_strength(uint16_t avx512)
* - AVX features : bitwise AND
* - AVX10 features : bitwise AND
* - Root / Manu : keep left (must be same arch in practice)
* - uArchHi : min (most conservative policy)
* - uArchHi : bitwise OR (HYBRID_P/E union; SIMD_DUAL set if either core is dual)
* ----------------------------------------------------------------------- */
SN_API SIMDID SN_DECL sn_get_unite_simd(SIMDID left, SIMDID right)
{
@@ -102,10 +102,14 @@ SN_API SIMDID SN_DECL sn_get_unite_simd(SIMDID left, SIMDID right)
/* AVX10 (byte 6): AND */
out.make_byte[6] = left.make_byte[6] & right.make_byte[6];
/* uArchHi (byte 7): min */
/* uArchHi (byte 7):
* topology bits [1..0]: AND — conservative intersection (weaker topology wins)
* SIMD_DUAL bit [2]: OR — dual if either core is dual */
unsigned char lu = FIELD_UARCH(left);
unsigned char ru = FIELD_UARCH(right);
out.make_byte[7] = (char)(lu < ru ? lu : ru);
unsigned char topo = (lu & 0x3u) & (ru & 0x3u);
unsigned char dual = (lu | ru) & (unsigned char)SIMDID_UARCH_SIMD_DUAL;
out.make_byte[7] = (char)(topo | dual);
return out;
}
@@ -142,8 +146,12 @@ SN_API SIMDID SN_DECL sn_get_unite_simd(SIMDID left, SIMDID right)
* DUAL(weakest) < UNKNOWN < NATIVE(strongest).
* This is not ISA capability but execution-width risk.
*
* 6. uArchHi (final tie-break)
* Higher value = more specific / stronger policy hint.
* 6. uArchHi topology bits [1..0]
* Numeric value: unified(11=3) > P-core(10=2) > E-core(01=1) > unknown(00=0).
* Higher value = stronger / higher-capability core form.
*
* 7. uArchHi SIMD_DUAL (final tie-break)
* Non-dual (SIMD_DUAL=0) > dual (SIMD_DUAL=1).
* ----------------------------------------------------------------------- */
SN_API int SN_DECL sn_compare_simd(SIMDID left, SIMDID right)
{
@@ -186,11 +194,19 @@ SN_API int SN_DECL sn_compare_simd(SIMDID left, SIMDID right)
return ls > rs ? 1 : -1;
}
/* 6. uArchHi (final tie-break) */
/* 6. uArchHi topology bits [1..0]: unified(3) > P(2) > E(1) > unknown(0) */
unsigned lu = FIELD_UARCH(left);
unsigned ru = FIELD_UARCH(right);
if (lu != ru)
return lu > ru ? 1 : -1;
unsigned lt = lu & 0x3u;
unsigned rt = ru & 0x3u;
if (lt != rt)
return lt > rt ? 1 : -1;
/* 7. uArchHi SIMD_DUAL: non-dual (SIMD_DUAL=0) > dual (SIMD_DUAL=1) */
int ld = (lu & SIMDID_UARCH_SIMD_DUAL) != 0;
int rd = (ru & SIMDID_UARCH_SIMD_DUAL) != 0;
if (ld != rd)
return ld ? -1 : 1; /* non-dual is stronger */
return 0;
}