many versions of simdid
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user