From eb60422fa3c73702660598a38afe7ea8291325e5 Mon Sep 17 00:00:00 2001 From: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com> Date: Tue, 18 Aug 2026 18:19:30 +0800 Subject: [PATCH] improve sidmdid config --- .../Internal/MatrixPanel.cs | 2 + src/StgSharp.Mathematics/Internal/SIMDID.cs | 2 +- .../Numeric/NumericalModule.cs | 1 - src/StgSharp.Native/SIMDID.x86.md | 122 +++++++---------- .../sn-head/sn_intrinsic.context.x86.h | 45 ++----- .../sn-src/load_intrinsic.x86.c | 3 +- src/StgSharp.Native/sn-src/simdid.x86.c | 123 +++++++----------- .../sn-src/simdid_compare.x86.c | 61 +++++---- .../Text/TextRegexSourceGen.GenClass.cs | 7 +- 9 files changed, 154 insertions(+), 212 deletions(-) diff --git a/src/StgSharp.Mathematics/Internal/MatrixPanel.cs b/src/StgSharp.Mathematics/Internal/MatrixPanel.cs index 217c8567..0a5b8a8e 100644 --- a/src/StgSharp.Mathematics/Internal/MatrixPanel.cs +++ b/src/StgSharp.Mathematics/Internal/MatrixPanel.cs @@ -86,6 +86,7 @@ namespace StgSharp.Mathematics.Numeric 1 => KernelSideCountSse(), 2 => KernelSideCountAvx2(), 3 => KernelSideCountAvx512(), + 4 => KernelSideCountAvx512(), _ => throw new NotSupportedException("Unsupported SIMD level."), }; default: @@ -145,6 +146,7 @@ namespace StgSharp.Mathematics.Numeric 1 => PanelSideFromBits(128), 2 => PanelSideFromBits(256), 3 => PanelSideFromBits(512), + 4 => PanelSideFromBits(512), _ => throw new NotSupportedException("Unsupported SIMD level."), }; default: diff --git a/src/StgSharp.Mathematics/Internal/SIMDID.cs b/src/StgSharp.Mathematics/Internal/SIMDID.cs index d810e7b0..8b58bb3a 100644 --- a/src/StgSharp.Mathematics/Internal/SIMDID.cs +++ b/src/StgSharp.Mathematics/Internal/SIMDID.cs @@ -19,7 +19,7 @@ namespace StgSharp.Mathematics.Internal internal unsafe struct SIMDID { - [FieldOffset(0)] public fixed byte MaskByte[16]; + [FieldOffset(0)] public fixed byte MaskByte[8]; [FieldOffset(0)] public ulong Mask; internal SIMDID( diff --git a/src/StgSharp.Mathematics/Numeric/NumericalModule.cs b/src/StgSharp.Mathematics/Numeric/NumericalModule.cs index 6e090747..23b51996 100644 --- a/src/StgSharp.Mathematics/Numeric/NumericalModule.cs +++ b/src/StgSharp.Mathematics/Numeric/NumericalModule.cs @@ -31,7 +31,6 @@ namespace StgSharp.Mathematics.Numeric 2 => 32, 3 => 64, 4 => 64, - 5 => 64, _ => 8, }, _ => 8, diff --git a/src/StgSharp.Native/SIMDID.x86.md b/src/StgSharp.Native/SIMDID.x86.md index 2df8db89..c351a0c9 100644 --- a/src/StgSharp.Native/SIMDID.x86.md +++ b/src/StgSharp.Native/SIMDID.x86.md @@ -1,6 +1,6 @@ # SIMDID (x86-64) 64-bit Specification (Completed per fixed layout) -This document completes the **64-bit SIMDID** bit layout as specified, with emphasis on the design of the **AVX512 Feature section ([31..16])**, so it can cover the messy AVX-512 subsets while keeping branching logic compact. It also allocates an **AVX Feature byte** adjacent to the AVX512/AMX regions for AVX-family capabilities, and an **AVX10 Feature byte** for the converged AVX10 ISA. +This document defines the compact **64-bit SIMDID** layout, including AVX/AVX-512/AVX10 capabilities and per-core execution-policy hints. AMX is not represented by the current policy. > Convention: bit0 is the least significant bit (LSB). Only x86-64 interpreter semantics are defined here; the header's Root ISA allows extension to other architectures. @@ -12,7 +12,7 @@ This document completes the **64-bit SIMDID** bit layout as specified, with emph SIMDID (64 bits) [63 ........................................................ 0] +----------+-----------+-----------+----------------+----------------+----------------+--------+-------+ | [63..56] | [55..48] | [47..40] | [39..32] | [31..16] | [15..8] | [7..4] | [3..0]| -| uArchHi | AVX10Feat | AVX Feat | AMX Future | AVX512 Feature | MainLevel | Manuf | Root | +| Reserved | uArchHi | AVX10Feat | AVX Feature | AVX512 Feature | MainLevel | Manuf | Root | +----------+-----------+-----------+----------------+----------------+----------------+--------+-------+ ``` @@ -20,10 +20,10 @@ SIMDID (64 bits) [63 ........................................................ 0 - **[7..4] Manufacture**: Vendor info (Intel/AMD for x86) - **[15..8] MainLevel**: Main ISA level (ascending, shared bit semantics) - **[31..16] AVX512 Feature**: AVX-512 features/subsets/implementation form (key part) -- **[39..32] AMX Future**: AMX features (few bits for now) -- **[47..40] AVX Feature**: AVX-family capabilities (base requires AVX+AVX2; key extensions include FMA/F16C) -- **[55..48] AVX10 Feature**: AVX10 converged ISA version and vector width support -- **[63..56] uArchHi**: Optional microarchitecture/policy hints (default 0, no functional impact). +- **[39..32] AVX Feature**: AVX-family capabilities (base requires AVX+AVX2; key extensions include FMA/F16C) +- **[47..40] AVX10 Feature**: AVX10 version and tracked discrete features +- **[55..48] uArchHi**: Optional microarchitecture/policy hints +- **[63..56] Reserved**: tail space for future extension --- @@ -82,14 +82,11 @@ For other Root ISAs, this nibble is defined by their interpreters. | 0 | NONE | | 1 | SSE (full SSE family: SSE1..SSE4.2) | | 2 | AVX2 | -| 3 | AVX2_FMA | -| 4 | AVX2_FMA_F16C (from this level onward, 16-bit types are supported) | -| 5 | AVX512 (check [31..16]) | -| 6 | AMX | -| 7 | AVX10 (check [55..48]) | -| 8..255 | Reserved | +| 3 | AVX512 (check [31..16]) | +| 4 | AVX10 (check [47..40]) | +| 5..255 | Reserved | -> Scheduling suggestion: `MainLevel` is the primary switch; only when `MainLevel >= AVX512` should `AVX512 Feature` be parsed; only when `MainLevel >= AMX` should `AMX Future` be parsed; only when `MainLevel >= AVX10` should `AVX10 Feature` be parsed. AVX Feature sits beside AMX/AVX512 and is meaningful when AVX or higher is present. +> `MainLevel` is the primary switch. Parse AVX512 Feature at AVX512 or later and AVX10 Feature only at AVX10. --- @@ -97,7 +94,7 @@ For other Root ISAs, this nibble is defined by their interpreters. 1) **Base AVX512 one-shot check**: Use 1 bit for the bundle `F + CD + VL + DQ + BW`, avoiding multiple subset checks. 2) **Glue vs native**: Use an implementation field to distinguish `AVX512-DUAL` (glue/downclock risk) from `AVX512-NATIVE` (full 512-bit ALU). -3) **Niche/AI extensions separated**: VNNI, BF16/FP16, and similar extensions each get a dedicated bit so the base path stays simple. +3) **Minimal extension tracking**: VNNI is the only AVX-512 extension currently retained. --- @@ -107,7 +104,7 @@ AVX512 Feature (bits 31..16) | **bit** | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | |-----------|-----|-----|------|------|------|-------|------|------|-------|-------|----|------|----|----|----|----| -| **Usage** | R | R | FP16 | BF16 | VNNI | VBMI2 | VBMI | R/AI | Impl1 | Impl0 | R | BASE | R | R | R | R | +| **Usage** | R | R | R | R | VNNI | R | R | R | Impl1 | Impl0 | R | BASE | R | R | R | R | Notes: @@ -123,61 +120,56 @@ Notes: > **Note**: Intel SKX/CLX/CPX have two 512-bit FMA ports (port-0 + port-5) and are **NATIVE** — genuine 512-bit throughput. Intel downclocking on heavy ZMM workloads is a separate concern not encoded here. DUAL-PUMP applies only where a single 256-bit unit fires twice per 512-bit op (AMD Zen4-style). -- **VBMI/VBMI2/VNNI/BF16/FP16 ([29..25])**: Commonly needed niche or AI-related small-type extensions; set as needed. +- **VNNI (bit 27)**: the only AVX-512 extension currently tracked; the surrounding extension bits are reserved. - **R/AI (bit 24)**: Reserved for future AI or other non-crypto extensions. - **[31..30], [21], [19..16]**: Reserved for future allocation. --- -## 7) AVX Feature Byte ([47..40], 8 bits) +## 7) AVX Feature Byte ([39..32], 8 bits) -Purpose: compact AVX-family capability encoding adjacent to AVX512/AMX. Base requirement: AVX **and** AVX2 present. Key extensions: FMA and F16C. Additional bits reserved for other extensions. +Purpose: compact AVX-family capability encoding. Base requirement: AVX **and** AVX2 present. Key extensions: FMA and F16C. -AVX Feature (bits 47..40) +AVX Feature (bits 39..32) -| bit | 47 | 46 | 45 | 44 | 43 | 42 | 41 | 40 | +| bit | 39 | 38 | 37 | 36 | 35 | 34 | 33 | 32 | |-----|----|----|----|----|----|----|----|----| | use | R | R | R | DUAL | F16C | FMA | AVX2 | AVX | Rules: -- **AVX (bit 40)**: AVX present. -- **AVX2 (bit 41)**: AVX2 present. For the AVX feature byte to be considered valid, both AVX and AVX2 must be set. -- **FMA (bit 42)**: FMA present. -- **F16C (bit 43)**: F16C present. -- **DUAL (bit 44)**: YMM execution is **glued/split-lane** (two fused 128-bit units rather than a native 256-bit path). Detection: AMD Zen1/Zen+ (Family 0x17, model < 0x30), Hygon (all, Zen1-based), VIA/Zhaoxin (all). When set, code using YMM operations may incur split-register overhead; prefer 128-bit SSE paths on these targets. -- **[45..47]**: Reserved for other AVX-family extensions (e.g., IFMA, XOP) as needed. +- **AVX (bit 32)**: AVX present. +- **AVX2 (bit 33)**: AVX2 present. For the AVX feature byte to be considered valid, both AVX and AVX2 must be set. +- **FMA (bit 34)**: FMA present. +- **F16C (bit 35)**: F16C present. +- **DUAL (bit 36)**: YMM execution is **glued/split-lane** (two fused 128-bit units rather than a native 256-bit path). Detection: AMD Zen1/Zen+ (Family 0x17, model < 0x30), Hygon (all, Zen1-based), VIA/Zhaoxin (all). When set, code using YMM operations may incur split-register overhead; prefer 128-bit SSE paths on these targets. +- **[37..39]**: Reserved for other AVX-family extensions as needed. --- -## 8) AVX10 Feature Byte ([55..48], 8 bits) +## 8) AVX10 Feature Byte ([47..40], 8 bits) -Purpose: encode the converged AVX10 ISA version and supported vector widths. AVX10 unifies and replaces the fragmented AVX-512 subset model; a single version number implies a defined set of instructions (e.g., AVX10.1 implies F+CD+VL+DQ+BW+VBMI+VBMI2+VNNI+BF16+FP16 converged). The width bits indicate what maximum vector width the hardware actually implements. +Purpose: encode the converged AVX10 ISA version and the discrete features relevant to this runtime. Under the current specification every AVX10 processor supports 128-, 256-, and 512-bit vector lengths, so vector width is not encoded. **CPUID detection**: `CPUID leaf 0x24, subleaf 0`. - EBX[7:0] = AVX10 converged ISA version number (≥ 1 if supported). -- EBX[16] = 128-bit vector support (always 1 when AVX10 is present). -- EBX[17] = 256-bit vector support. -- EBX[18] = 512-bit vector support. +- EBX[18:16] are reserved at 1. Earlier specifications used them for VL128/VL256/VL512; they must not be interpreted as width capabilities. +- `CPUID.24H.1:ECX[2]` enumerates `AVX10_VNNI_INT` when subleaf 1 exists. -AVX10 Feature (bits 55..48) +AVX10 Feature (bits 47..40) -| bit | 55 | 54 | 53 | 52 | 51 | 50 | 49 | 48 | -|-----|----|----|----| ---- | ---- |----|----|------| -| use | R | R | R | 512W | 256W | V2 | V1 | AVX10 | +| bit | 47 | 46..40 | +|-----|----------|---------| +| use | VNNI_INT | Version | Rules: -- **AVX10 (bit 48)**: CPU declares AVX10 converged ISA support (leaf 0x24 reports a valid version ≥ 1). -- **V1 (bit 49)**: AVX10 version ≥ 1 (AVX10.1). Set when `EBX[7:0] >= 1`. -- **V2 (bit 50)**: AVX10 version ≥ 2 (AVX10.2). Set when `EBX[7:0] >= 2`. -- **256W (bit 51)**: Hardware supports 256-bit vector width for AVX10 instructions (`EBX[17]` == 1). -- **512W (bit 52)**: Hardware supports 512-bit vector width for AVX10 instructions (`EBX[18]` == 1). -- **[53..55]**: Reserved for future AVX10 versions (V3, V4...) or additional width/feature bits. +- **Version ([46..40])**: numeric AVX10 version, saturated to 7 bits. Zero means AVX10 is absent. +- **VNNI_INT (bit 47)**: `CPUID.24H.1:ECX[2]`. -> Note: When `AVX10 == 1`, the 128-bit width is always implied and does not need a dedicated bit. `V1` and `V2` are cumulative — if `V2` is set, `V1` must also be set. +> AVX10 version comparison is numeric. Merging two SIMDIDs keeps the lower version and intersects discrete feature bits. **Relationship with AVX512 Feature**: - AVX10 is a superset specification. When `MainLevel == AVX10`, the `AVX512 Feature` field may still be populated for backward-compatible code paths (e.g., checking `AVX512_IMPL` to select DUAL vs NATIVE 512-bit policy). -- AVX10/256 hardware does **not** support 512-bit operations; code should check `512W` before using zmm registers. +- Current AVX10 hardware is architecturally AVX10/512. OS support still requires the full XCR0 SSE/AVX/opmask/ZMM state. --- @@ -189,33 +181,18 @@ Rules: - Otherwise: - Check `BASE`; if 0, fall back to AVX2/FMA (or treat as detection failure). - Check `AVX512_IMPL`: `DUAL` uses 256-bit/downclock-safe path, `NATIVE` uses 512-bit path. - - When small-type/AI capabilities are required, consult `VNNI/BF16/FP16/VBMI/VBMI2` bits. + - Consult `VNNI` when the integer dot-product path requires it. - If `MainLevel == AVX10`: prefer AVX10 Feature for capability checks; `AVX512 Feature` remains valid for legacy branching. --- -## 10) AMX Future ([39..32], 8 bits) - -A single byte is reserved; define three common bits for now, leave the rest reserved: - -| bit (relative to [39..32]) | Name | Note | -|---:|------|------| -| 0 | AMX_TILE | Tile base | -| 1 | AMX_INT8 | INT8 tile | -| 2 | AMX_BF16 | BF16 tile | -| 3..7 | Reserved | | - -When `MainLevel < AMX`, this byte can be all zeros. - ---- - -## 11) uArchHi ([63..56], 8 bits) +## 10) uArchHi ([55..48], 8 bits) Purpose: **bitmask** byte encoding core topology classification and SIMD execution-width policy for the detected core. All bits default to 0. uArchHi bitmask layout: -| bit (relative to [63..56]) | Name | Note | +| bit (relative to [55..48]) | Name | Note | |---:|------|------| | 0 | HYBRID_E | E-core (efficiency/small core) in a hybrid-topology processor (e.g., Intel Alder Lake+ E-core) | | 1 | HYBRID_P | P-core (performance/big core) in a hybrid-topology processor (e.g., Intel Alder Lake+ P-core) | @@ -253,21 +230,20 @@ Detection: - Set `AVX512_IMPL`: - **Intel (all)**: NATIVE — all Intel AVX-512 CPUs have genuine 512-bit execution units - **AMD Zen4 (Family 0x19)**: DUAL — single 256-bit ALU, dual-pump - - **AMD Zen5+ (Family 0x1A+)**: NATIVE — native full-width 512-bit units - - **AMD other/future**: UNKNOWN (conservative) + - **AMD Family 0x1A models 00h..0Fh (EPYC 9005)**: NATIVE — full-width 512-bit path + - **AMD Family 0x1A models 10h..1Fh**: UNKNOWN — this CPUID range is shared by full-width EPYC 9005 Zen5c and 256-bit dual-pumped EPYC 8005 products + - **AMD other client/future models**: UNKNOWN unless their execution width can be identified without an ambiguous product-name heuristic - **Hygon**: UNKNOWN (AVX-512 characteristics unclear) - **VIA/other**: UNKNOWN - - When VNNI/BF16/FP16/VBMI/VBMI2 are detected, set the corresponding bits. -4) If `MainLevel >= AMX`: fill the AMX byte. -5) When AVX/AVX2 are present, populate the AVX Feature byte: set `AVX` and `AVX2`; set `FMA` and `F16C` when detected; set `DUAL` when the YMM execution path is split/glued (AMD Zen1/Zen+ Family 0x17 model < 0x30, Hygon all models, VIA/Zhaoxin all models). -6) **AVX10 detection** (requires `CPUID leaf 7 subleaf 1, EDX[19] == 1` as the AVX10 convergence bit): + - Set VNNI when detected; other AVX-512 extension bits remain reserved. +4) When AVX/AVX2 are present, populate the AVX Feature byte: set `AVX` and `AVX2`; set `FMA` and `F16C` when detected; set `DUAL` when the YMM execution path is split/glued (AMD Zen1/Zen+ Family 0x17 model < 0x30, Hygon all models, VIA/Zhaoxin all models). +5) **AVX10 detection** (requires `CPUID leaf 7 subleaf 1, EDX[19] == 1` as the AVX10 convergence bit): - If AVX10 is indicated, query `CPUID leaf 0x24, subleaf 0`: - - Read `EBX[7:0]` for version number; set `AVX10`, `V1`, and optionally `V2`. - - Read `EBX[17]` for 256-bit support → set `256W`. - - Read `EBX[18]` for 512-bit support → set `512W`. - - Promote `MainLevel` to `AVX10` (value 7). + - Read `EBX[7:0]` as the numeric version; do not interpret `EBX[18:16]` as vector-width bits. + - If subleaf 1 exists, read `ECX[2]` as `AVX10_VNNI_INT`. + - Promote `MainLevel` to `AVX10` (value 4). - The `AVX512 Feature` field should still be filled for backward compatibility. -7) Populate uArchHi: +6) Populate uArchHi: - If `CPUID.7.0 EDX[15]` (HYBRID) **not** set: set `HYBRID_P | HYBRID_E` (unified = 11). - If HYBRID is set, read `CPUID.0x1A.0 EAX[31:24]`: - `0x40` (P-core) → set only `HYBRID_P` (topology = 10). @@ -279,4 +255,4 @@ Detection: ## 13) Choice for High Bits Reservation -`[31..24]` is reserved for AVX512 extensions/AI. `[47..45]` is reserved for AVX-family extensions (bit 44 is now `DUAL`). `[55..53]` is reserved for future AVX10 versions. uArchHi `[63..56]` bits [3..7] are reserved; bits [0..2] encode hybrid topology and SIMD-dual policy. \ No newline at end of file +`[31..24]` is reserved for AVX512 extensions/AI. `[39..37]` is reserved for AVX-family extensions. AVX10 `[47..40]` stores one tracked discrete feature plus a 7-bit version. uArchHi `[55..48]` bits [3..7] are reserved; bits [0..2] encode hybrid topology and SIMD-dual policy. `[63..56]` is reserved tail space. diff --git a/src/StgSharp.Native/sn-head/sn_intrinsic.context.x86.h b/src/StgSharp.Native/sn-head/sn_intrinsic.context.x86.h index b8883461..88a10492 100644 --- a/src/StgSharp.Native/sn-head/sn_intrinsic.context.x86.h +++ b/src/StgSharp.Native/sn-head/sn_intrinsic.context.x86.h @@ -23,19 +23,17 @@ // bits [7..4] : Manufacture (ISA-specific) // bits [15..8] : MainLevel (monotonic capability) // bits [31..16]: AVX512 Feature -// bits [39..32]: AMX Feature -// bits [47..40]: AVX Feature -// bits [55..48]: AVX10 Feature -// bits [63..56]: uArchHi / Policy (optional) +// bits [39..32]: AVX Feature +// bits [47..40]: AVX10 Feature +// bits [55..48]: uArchHi / Policy (optional) +// bits [63..56]: Reserved for future tail extension // ----------------------------------------------------------------------------- #define SIMDID_SHIFT_AVX512 16 -#define SIMDID_SHIFT_AMX 32 -#define SIMDID_SHIFT_AVX 40 -#define SIMDID_SHIFT_AVX10 48 -#define SIMDID_SHIFT_UARCH 56 +#define SIMDID_SHIFT_AVX 32 +#define SIMDID_SHIFT_AVX10 40 +#define SIMDID_SHIFT_UARCH 48 #define SIMDID_MASK_AVX512 (0xFFFFULL << SIMDID_SHIFT_AVX512) -#define SIMDID_MASK_AMX (0xFFULL << SIMDID_SHIFT_AMX) #define SIMDID_MASK_AVX (0xFFULL << SIMDID_SHIFT_AVX) #define SIMDID_MASK_AVX10 (0xFFULL << SIMDID_SHIFT_AVX10) #define SIMDID_MASK_UARCH (0xFFULL << SIMDID_SHIFT_UARCH) @@ -52,16 +50,10 @@ #define SIMDID_MAIN_LVL_SSE 0x01u /* SSE1..SSE4.2 */ #define SIMDID_MAIN_LVL_AVX2 0x02u #define SIMDID_MAIN_LVL_AVX512 0x03u -#define SIMDID_MAIN_LVL_AMX 0x04u -#define SIMDID_MAIN_LVL_AVX10 0x05u +#define SIMDID_MAIN_LVL_AVX10 0x04u #ifndef SIMDID_AVX512_BASE -#define SIMDID_AVX512_FP16 (1U << 13) /* relative bit 13 within [31..16] */ -#define SIMDID_AVX512_BF16 (1U << 12) #define SIMDID_AVX512_VNNI (1U << 11) -#define SIMDID_AVX512_VBMI2 (1U << 10) -#define SIMDID_AVX512_VBMI (1U << 9) -#define SIMDID_AVX512_AI_RESERVED (1U << 8) #define SIMDID_AVX512_BASE (1U << 4) #define SIMDID_AVX512_IMPL_SHIFT 6 #define SIMDID_AVX512_IMPL_MASK (0x3U << SIMDID_AVX512_IMPL_SHIFT) @@ -71,7 +63,7 @@ #endif #ifndef SIMDID_AVX_BASE -#define SIMDID_AVX (1U << 0) /* relative bit 0 within [47..40] */ +#define SIMDID_AVX (1U << 0) /* relative bit 0 within [39..32] */ #define SIMDID_AVX2 (1U << 1) #define SIMDID_AVX_FMA (1U << 2) #define SIMDID_AVX_F16C (1U << 3) @@ -79,21 +71,12 @@ (1U << 4) /* glued/split-lane YMM (two 128-bit units; Zen1, Hygon, VIA/Zhaoxin) */ #endif -#ifndef SIMDID_AMX_TILE -#define SIMDID_AMX_TILE (1U << 0) /* relative bit 0 within [39..32] */ -#define SIMDID_AMX_INT8 (1U << 1) -#define SIMDID_AMX_BF16 (1U << 2) +#ifndef SIMDID_AVX10_VERSION_MASK +#define SIMDID_AVX10_VERSION_MASK 0x7FU /* CPUID.24H.0:EBX[7:0], saturated to 7 bits */ +#define SIMDID_AVX10_VNNI_INT (1U << 7) /* CPUID.24H.1:ECX[2] */ #endif -#ifndef SIMDID_AVX10_BASE -#define SIMDID_AVX10 (1U << 0) /* relative bit 0 within [55..48] */ -#define SIMDID_AVX10_V1 (1U << 1) -#define SIMDID_AVX10_V2 (1U << 2) -#define SIMDID_AVX10_256W (1U << 3) -#define SIMDID_AVX10_512W (1U << 4) -#endif - -/* uArchHi ([63..56]) bitmask — core topology and SIMD-width execution policy */ +/* uArchHi ([55..48]) bitmask — core topology and SIMD-width execution policy */ #ifndef SIMDID_UARCH_HYBRID_P /* Topology 2-bit field (bits [1..0] of uArchHi byte): * 00 = unknown (undetected hybrid type or pre-CPUID.1A hardware) @@ -112,7 +95,6 @@ (SIMDID_PACK_ROOT(root) | SIMDID_PACK_MANU(manu) | SIMDID_PACK_MAIN(main)) #define SIMDID_PACK_AVX512(avx512_bits) \ (((uint64_t)(avx512_bits) & 0xFFFFULL) << SIMDID_SHIFT_AVX512) -#define SIMDID_PACK_AMX(amx_bits) (((uint64_t)(amx_bits) & 0xFFULL) << SIMDID_SHIFT_AMX) #define SIMDID_PACK_AVX(avx_bits) (((uint64_t)(avx_bits) & 0xFFULL) << SIMDID_SHIFT_AVX) #define SIMDID_PACK_AVX10(avx10_bits) (((uint64_t)(avx10_bits) & 0xFFULL) << SIMDID_SHIFT_AVX10) #define SIMDID_PACK_UARCH(uarch_hi) (((uint64_t)(uarch_hi) & 0xFFULL) << SIMDID_SHIFT_UARCH) @@ -123,7 +105,6 @@ #define SIMDID_MAIN_ENC_SSE SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_SSE) #define SIMDID_MAIN_ENC_AVX2 SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX2) #define SIMDID_MAIN_ENC_AVX512 SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX512) -#define SIMDID_MAIN_ENC_AMX SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AMX) #define SIMDID_MAIN_ENC_AVX10 SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX10) #pragma region matix function diff --git a/src/StgSharp.Native/sn-src/load_intrinsic.x86.c b/src/StgSharp.Native/sn-src/load_intrinsic.x86.c index dd04839f..8c0bb6d5 100644 --- a/src/StgSharp.Native/sn-src/load_intrinsic.x86.c +++ b/src/StgSharp.Native/sn-src/load_intrinsic.x86.c @@ -32,7 +32,6 @@ SN_API void SN_DECL load_intrinsic_function(void *intrinsic_context, uint64_t id load_intrinsic_avx(context, simdid); break; case SIMDID_MAIN_LVL_AVX512: - case SIMDID_MAIN_LVL_AMX: case SIMDID_MAIN_LVL_AVX10: load_intrinsic_512(context, simdid); break; @@ -65,7 +64,7 @@ void load_intrinsic_sse(sn_intrinsic *context, SIMDID id) void load_intrinsic_avx(sn_intrinsic *context, SIMDID id) { - char avx_seg = id.make_byte[5]; + char avx_seg = id.make_byte[4]; char is_fma = (avx_seg & SIMDID_AVX_FMA) != 0; context->city_hash_simplify = city_hash_simplify_sse; diff --git a/src/StgSharp.Native/sn-src/simdid.x86.c b/src/StgSharp.Native/sn-src/simdid.x86.c index 4c4301ba..c59b1c1f 100644 --- a/src/StgSharp.Native/sn-src/simdid.x86.c +++ b/src/StgSharp.Native/sn-src/simdid.x86.c @@ -36,28 +36,32 @@ static void get_cpuid(int leaf, int subleaf, int *eax, int *ebx, int *ecx, int * #endif } -static int xgetbv_has_xmm_ymm(void) +/* XCR0 is per logical processor. Reading it after thread affinity is applied + * verifies that the OS saves/restores the register state needed by this core. */ +static unsigned long long read_xcr0(void) { #if defined(_MSC_VER) - unsigned __int64 xcr0 = _xgetbv(0); + return _xgetbv(0); #else - unsigned long long xcr0 = __builtin_ia32_xgetbv(0); + return __builtin_ia32_xgetbv(0); #endif - return ((xcr0 & 0x6) == 0x6); } -static int xgetbv_has_avx512_state(void) +static int os_has_xsave_state(unsigned long long required) { - const unsigned long long mask = (1ull << 0) | (1ull << 1) | (1ull << 2) | (1ull << 5) | - (1ull << 6); -#if defined(_MSC_VER) - unsigned __int64 xcr0 = _xgetbv(0); -#else - unsigned long long xcr0 = __builtin_ia32_xgetbv(0); -#endif - return ((xcr0 & mask) == mask); + return (read_xcr0() & required) == required; } +#define XCR0_X87 (1ull << 0) +#define XCR0_XMM (1ull << 1) +#define XCR0_YMM (1ull << 2) +#define XCR0_OPMASK (1ull << 5) +#define XCR0_ZMM_HI256 (1ull << 6) +#define XCR0_HI16_ZMM (1ull << 7) +#define XCR0_AVX_STATE (XCR0_X87 | XCR0_XMM | XCR0_YMM) +#define XCR0_AVX512_STATE \ + (XCR0_AVX_STATE | XCR0_OPMASK | XCR0_ZMM_HI256 | XCR0_HI16_ZMM) + static void decode_family_model(int cpuid1_eax, int *family, int *model) { int family_value = 0; @@ -83,19 +87,23 @@ static void decode_family_model(int cpuid1_eax, int *family, int *model) *model = model_value; } -/* AVX-512 execution-width classification for AMD, by CPU family. - * Zen4 (0x19): single 256-bit ALU, 512-bit op = two 256-bit micro-ops (dual-pump) → DUAL. - * Zen5+ (>=0x1A): native 512-bit execution units → NATIVE. - * Other/future AMD families → UNKNOWN (conservative). */ -static uint64_t amd_avx512_impl(int family) +/* AVX-512 execution-width classification for AMD. + * Family 19h (Zen4) uses a 256-bit dual-pumped path. + * Family 1Ah models 00h-0Fh are documented for the full-width EPYC 9005 + * implementation. Models 10h-1Fh are intentionally UNKNOWN: that CPUID + * range is used by both full-width EPYC 9005 Zen5c and dual-pumped EPYC + * 8005 products, and CPUID has no architectural execution-width bit. */ +static uint64_t amd_avx512_impl(int family, int model) { if (family == 0x19) { return SIMDID_AVX512_IMPL_DUAL; - } else if (family >= 0x1A) { - return SIMDID_AVX512_IMPL_NATIVE; - } else { - return SIMDID_AVX512_IMPL_UNKNOWN; } + if (family == 0x1A) { + if (model >= 0x00 && model <= 0x0F) { + return SIMDID_AVX512_IMPL_NATIVE; + } + } + return SIMDID_AVX512_IMPL_UNKNOWN; } /* Returns 1 if this AMD/Hygon CPU uses split-lane YMM (two fused 128-bit execution units). @@ -172,7 +180,6 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local() uint64_t main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_NONE); uint64_t avx_bits = 0; uint64_t avx512_bits = 0; - uint64_t amx_bits = 0; uint64_t avx10_bits = 0; uint64_t uarch_bits = 0; int has_hybrid = 0; @@ -181,7 +188,7 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local() main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_SSE); } - if (has_avx && has_osxsave && xgetbv_has_xmm_ymm()) { + if (has_avx && has_osxsave && os_has_xsave_state(XCR0_AVX_STATE)) { avx_bits |= SIMDID_AVX; if (is_amd_glue_ymm(vendor, cpuid1_eax) || is_via) { @@ -194,24 +201,15 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local() const int has_avx2 = (ebx & (1 << 5)) != 0; const int has_avx512f = (ebx & (1 << 16)) != 0; const int has_avx512dq = (ebx & (1 << 17)) != 0; + const int has_avx512cd = (ebx & (1 << 28)) != 0; const int has_avx512bw = (ebx & (1 << 30)) != 0; const int has_avx512vl = (ebx & (1u << 31)) != 0; const int has_avx512_vnni = (ecx & (1 << 11)) != 0; - const int has_vbmi = (ecx & (1 << 1)) != 0; - const int has_vbmi2 = (ecx & (1 << 6)) != 0; - - 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; - int has_bf16 = 0; - int has_fp16 = 0; int has_avx10 = 0; if (eax >= 1) { get_cpuid(7, 1, &eax, &ebx, &ecx, &edx); - has_bf16 = (eax & (1 << 5)) != 0; - has_fp16 = (eax & (1 << 23)) != 0; has_avx10 = (edx & (1 << 19)) != 0; } @@ -226,70 +224,46 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local() main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX2); } - if (has_avx512f && xgetbv_has_avx512_state()) { - if (has_avx512bw && has_avx512vl && has_avx512dq) { - avx512_bits |= SIMDID_AVX512_BASE; - } + if (has_avx512f && has_avx512cd && has_avx512dq && has_avx512bw && + has_avx512vl && os_has_xsave_state(XCR0_AVX512_STATE)) { + avx512_bits |= SIMDID_AVX512_BASE; if (has_avx512_vnni) { avx512_bits |= SIMDID_AVX512_VNNI; } - if (has_bf16) { - avx512_bits |= SIMDID_AVX512_BF16; - } - if (has_fp16) { - avx512_bits |= SIMDID_AVX512_FP16; - } - if (has_vbmi) { - avx512_bits |= SIMDID_AVX512_VBMI; - } - if (has_vbmi2) { - avx512_bits |= SIMDID_AVX512_VBMI2; - } if (is_intel) { avx512_bits |= SIMDID_AVX512_IMPL_NATIVE; } else if (is_amd) { - avx512_bits |= amd_avx512_impl(family); + avx512_bits |= amd_avx512_impl(family, model); } else { avx512_bits |= SIMDID_AVX512_IMPL_UNKNOWN; } main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX512); - if (has_amx_tile) { - amx_bits |= SIMDID_AMX_TILE; - if (has_amx_int8) { - amx_bits |= SIMDID_AMX_INT8; - } - if (has_amx_bf16) { - amx_bits |= SIMDID_AMX_BF16; - } - main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AMX); - } - if (has_avx10 && (max_basic_leaf >= 0x24)) { int a10_eax = 0; int a10_ebx = 0; int a10_ecx = 0; int a10_edx = 0; int avx10_ver = 0; - int has_256w = 0; - int has_512w = 0; get_cpuid(0x24, 0, &a10_eax, &a10_ebx, &a10_ecx, &a10_edx); avx10_ver = a10_ebx & 0xFF; if (avx10_ver >= 1) { - avx10_bits |= SIMDID_AVX10 | SIMDID_AVX10_V1; - if (avx10_ver >= 2) { - avx10_bits |= SIMDID_AVX10_V2; + unsigned max_avx10_subleaf = (unsigned)a10_eax; + unsigned stored_version = (unsigned)avx10_ver; + if (stored_version > SIMDID_AVX10_VERSION_MASK) { + stored_version = SIMDID_AVX10_VERSION_MASK; } - has_256w = (a10_ebx & (1 << 17)) != 0; - has_512w = (a10_ebx & (1 << 18)) != 0; - if (has_256w) { - avx10_bits |= SIMDID_AVX10_256W; - } - if (has_512w) { - avx10_bits |= SIMDID_AVX10_512W; + avx10_bits = stored_version; + + if (max_avx10_subleaf >= 1) { + get_cpuid(0x24, 1, &a10_eax, &a10_ebx, + &a10_ecx, &a10_edx); + if ((a10_ecx & (1 << 2)) != 0) { + avx10_bits |= SIMDID_AVX10_VNNI_INT; + } } main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX10); } @@ -331,7 +305,6 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local() final_mask |= manu; final_mask |= main_lvl; final_mask |= SIMDID_PACK_AVX512(avx512_bits); - final_mask |= SIMDID_PACK_AMX(amx_bits); final_mask |= SIMDID_PACK_AVX(avx_bits); final_mask |= SIMDID_PACK_AVX10(avx10_bits); final_mask |= SIMDID_PACK_UARCH(uarch_bits); diff --git a/src/StgSharp.Native/sn-src/simdid_compare.x86.c b/src/StgSharp.Native/sn-src/simdid_compare.x86.c index 739bff27..42d4c5ff 100644 --- a/src/StgSharp.Native/sn-src/simdid_compare.x86.c +++ b/src/StgSharp.Native/sn-src/simdid_compare.x86.c @@ -13,19 +13,18 @@ * [7..4] Manufacture make_byte[0] high nibble * [15..8] MainLevel make_byte[1] * [31..16] AVX512 Feature make_byte[2..3] (16 bits) - * [39..32] AMX Feature make_byte[4] - * [47..40] AVX Feature make_byte[5] - * [55..48] AVX10 Feature make_byte[6] - * [63..56] uArchHi make_byte[7] + * [39..32] AVX Feature make_byte[4] + * [47..40] AVX10 Feature make_byte[5] + * [55..48] uArchHi make_byte[6] + * [63..56] Reserved make_byte[7] * ----------------------------------------------------------------------- */ #define FIELD_MAIN(id) ((unsigned char)(id).make_byte[1]) #define FIELD_AVX512(id) \ ((uint16_t)((unsigned char)(id).make_byte[2] | ((unsigned char)(id).make_byte[3] << 8))) -#define FIELD_AMX(id) ((unsigned char)(id).make_byte[4]) -#define FIELD_AVX(id) ((unsigned char)(id).make_byte[5]) -#define FIELD_AVX10(id) ((unsigned char)(id).make_byte[6]) -#define FIELD_UARCH(id) ((unsigned char)(id).make_byte[7]) +#define FIELD_AVX(id) ((unsigned char)(id).make_byte[4]) +#define FIELD_AVX10(id) ((unsigned char)(id).make_byte[5]) +#define FIELD_UARCH(id) ((unsigned char)(id).make_byte[6]) /* Portable popcount for a 16-bit value. */ static int popcount16(uint16_t v) @@ -56,9 +55,8 @@ static int impl_strength(uint16_t avx512) * capability set that is safe to use on BOTH cores: * - MainLevel : min (only assume what both cores support) * - AVX512 features : bitwise AND (IMPL field: pick the weaker one) - * - AMX features : bitwise AND * - AVX features : bitwise AND - * - AVX10 features : bitwise AND + * - AVX10 version : min; discrete features: bitwise AND * - Root / Manu : keep left (must be same arch in practice) * - uArchHi : bitwise OR (HYBRID_P/E union; SIMD_DUAL set if either core is dual) * ----------------------------------------------------------------------- */ @@ -92,23 +90,28 @@ SN_API SIMDID SN_DECL sn_get_unite_simd(SIMDID left, SIMDID right) out.make_byte[2] = (char)(merged & 0xFF); out.make_byte[3] = (char)((merged >> 8) & 0xFF); - /* AMX (byte 4): AND */ + /* AVX (byte 4): AND */ out.make_byte[4] = left.make_byte[4] & right.make_byte[4]; - /* AVX (byte 5): AND */ - out.make_byte[5] = left.make_byte[5] & right.make_byte[5]; + /* AVX10 (byte 5): minimum version and common discrete features. */ + unsigned char lavx10 = FIELD_AVX10(left); + unsigned char ravx10 = FIELD_AVX10(right); + unsigned char lver = lavx10 & SIMDID_AVX10_VERSION_MASK; + unsigned char rver = ravx10 & SIMDID_AVX10_VERSION_MASK; + unsigned char common = (lavx10 & ravx10) & SIMDID_AVX10_VNNI_INT; + out.make_byte[5] = (char)((lver < rver ? lver : rver) | common); - /* AVX10 (byte 6): AND */ - out.make_byte[6] = left.make_byte[6] & right.make_byte[6]; - - /* uArchHi (byte 7): + /* uArchHi (byte 6): * 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); 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); + out.make_byte[6] = (char)(topo | dual); + + /* Reserved tail byte. */ + out.make_byte[7] = 0; return out; } @@ -125,19 +128,18 @@ SN_API SIMDID SN_DECL sn_get_unite_simd(SIMDID left, SIMDID right) * * 1. MainLevel ([15..8]) * Higher value = stronger. This is the primary discriminator: - * NONE < SSE < AVX2 < AVX512 < AMX < AVX10 + * NONE < SSE < AVX2 < AVX512 < AVX10 * - * 2. AVX10 vector width ([55..48]) + * 2. AVX10 version and discrete features ([47..40]) * Only meaningful when both MainLevel == AVX10. - * 512W > 256W-only. Compared by the full AVX10 byte value since - * width bits are in higher positions than version bits. + * Higher versions are stronger; VNNI_INT is a tie-breaker. * * 3. AVX512 BASE bit (bit 4 of [31..16]) * Only meaningful when both MainLevel >= AVX512. * BASE=1 (F+CD+VL+DQ+BW all present) > BASE=0. * * 4. AVX512 extension popcount - * Count of set extension bits (VNNI/BF16/FP16/VBMI/VBMI2/AI_RESERVED). + * VNNI is currently the only tracked AVX512 extension. * The IMPL and BASE bits are masked out before counting so they don't * inflate the extension count. * @@ -160,12 +162,19 @@ SN_API int SN_DECL sn_compare_simd(SIMDID left, SIMDID right) if (lm != rm) return lm > rm ? 1 : -1; - /* 2. AVX10 width (only when MainLevel == AVX10) */ + /* 2. AVX10 version and discrete features (only at AVX10). */ if (lm >= SIMDID_MAIN_LVL_AVX10) { unsigned la = FIELD_AVX10(left); unsigned ra = FIELD_AVX10(right); - if (la != ra) - return la > ra ? 1 : -1; + unsigned lv = la & SIMDID_AVX10_VERSION_MASK; + unsigned rv = ra & SIMDID_AVX10_VERSION_MASK; + if (lv != rv) + return lv > rv ? 1 : -1; + + int lvnni = (la & SIMDID_AVX10_VNNI_INT) != 0; + int rvnni = (ra & SIMDID_AVX10_VNNI_INT) != 0; + if (lvnni != rvnni) + return lvnni ? 1 : -1; } /* 3. AVX512 BASE (only when MainLevel >= AVX512) */ diff --git a/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs b/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs index fc7312cb..5ffa9e8a 100644 --- a/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs +++ b/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs @@ -72,13 +72,16 @@ namespace StgSharp.RegularAnalysis.Text #endregion - #region verb generate + #region basic verb generate private static void GenerateAlt( RegexAstNode node, [NotNull] in SequenceEmitter sc, in List> func_list - ) { } + ) + { + + } private static void GenerateConcat( RegexAstNode node,