add simd id
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
# SIMDID(x86-64)64-bit 规范(按你给定的固定布局补全)
|
||||
|
||||
本文按你指定的 **64-bit SIMDID** 位布局进行补全,重点给出 **AVX512 Feature 区段([31..16])** 的设计,使其既能覆盖 AVX-512 混乱的子集,又能保持分支逻辑尽量精简。
|
||||
|
||||
> 约定:bit0 为最低位(LSB)。本文只定义 x86-64 解释器下的语义;Header 的 Root ISA 允许扩展到其他架构。
|
||||
|
||||
---
|
||||
|
||||
## 1) ASCII 位布局(最终)
|
||||
|
||||
```
|
||||
SIMDID (64 bits) [63 ........................................................ 0]
|
||||
+--------------------------+-----------+----------------+----------------+----------------+----------------+
|
||||
| [63..40] uArch/Policy | [39..32] | [31..16] | [15..8] | [7..4] | [3..0] |
|
||||
| (24 bits, optional) | AMX Future| AVX512 Feature | MainLevel | Manufacture | Root ISA |
|
||||
+--------------------------+-----------+----------------+----------------+----------------+----------------+
|
||||
```
|
||||
|
||||
- **[3..0] Root ISA**:根指令集类型(用于选择解释器)
|
||||
- **[7..4] Manufacture**:制造商信息(对 x86 来说 Intel/AMD 等)
|
||||
- **[15..8] MainLevel**:主 ISA 等级(递增、共享比特语义)
|
||||
- **[31..16] AVX512 Feature**:AVX-512 特征/子集/实现形态(重点)
|
||||
- **[39..32] AMX Future**:AMX 特征(目前可只放少量位)
|
||||
- **[63..40] uArch/Policy**:可选策略/微架构提示(默认 0,不影响功能)
|
||||
|
||||
---
|
||||
|
||||
## 2) Root ISA([3..0])
|
||||
|
||||
建议编码(你列出的架构较多,这里给一个可用的最小集合;不够可继续扩):
|
||||
|
||||
| 值 | Root ISA |
|
||||
|---:|----------|
|
||||
| 0 | Unknown |
|
||||
| 1 | x86-64 |
|
||||
| 2 | AArch64 |
|
||||
| 3 | PPC64LE |
|
||||
| 4 | Apple Silicon(如果你想把它当“制造商+ARM”以外的 note,也可放在 Manufacture;但你要求 Root ISA 里有它,那就给它一个值) |
|
||||
| 5 | RISC-V |
|
||||
| 6 | LoongArch |
|
||||
| 7..15 | Reserved |
|
||||
|
||||
> 注:从体系结构角度 Apple Silicon 属于 AArch64;但你既然希望在 Root ISA 层面区分,那就这样定义即可(解释器由你决定)。
|
||||
|
||||
---
|
||||
|
||||
## 3) Manufacture([7..4])
|
||||
|
||||
在 **x86-64** 下建议:
|
||||
|
||||
| 值 | Manufacture |
|
||||
|---:|-------------|
|
||||
| 0 | Unknown/Other |
|
||||
| 1 | Intel |
|
||||
| 2 | AMD |
|
||||
| 3 | VIA/Zhaoxin |
|
||||
| 4..15 | Reserved |
|
||||
|
||||
在其它 Root ISA 下,该 nibble 由各自解释器自行定义(例如 ARM 下可放 Apple/Qualcomm/MediaTek 等)。
|
||||
|
||||
---
|
||||
|
||||
## 4) MainLevel([15..8],递增)
|
||||
|
||||
你要求“共用比特且递增”,也就是说数值越大能力越强(或至少在你的库调度中越靠后)。建议定为:
|
||||
|
||||
| 值 | MainLevel |
|
||||
|---:|-----------|
|
||||
| 0 | NONE |
|
||||
| 1 | SSE(完整 SSE 家族:SSE1..SSE4.2) |
|
||||
| 2 | AVX2 |
|
||||
| 3 | AVX2_FMA |
|
||||
| 4 | AVX2_FMA_F16C(从该级开始可处理 16-bit 类型) |
|
||||
| 5 | AVX512(需要查询 [31..16]) |
|
||||
| 6 | AMX |
|
||||
| 7 | AVX10 |
|
||||
| 8..255 | Reserved |
|
||||
|
||||
> 建议调度:`MainLevel` 是主 switch;只有当 `MainLevel>=AVX512` 才解析 `AVX512 Feature`;当 `MainLevel>=AMX` 才解析 `AMX Future`。
|
||||
|
||||
---
|
||||
|
||||
## 5) AVX512 Feature([31..16])设计目标(精简版)
|
||||
|
||||
目标改为:
|
||||
|
||||
1) **基础 AVX512 一次性判定**:用 1 bit 表示“F+CD+VL+DQ+BW”这一捆绑基础包,避免多次子集判断。
|
||||
2) **胶水 vs 原生**:用实现字段直接区分 `AVX512-DUAL`(胶水/降频风险)与 `AVX512-NATIVE`(完整 512 位 ALU)。
|
||||
3) **小众/AI 扩展单独留位**:VNNI、BF16/FP16 等稀疏出现的扩展单独占位,基础路径不受干扰。
|
||||
|
||||
---
|
||||
|
||||
## 6) AVX512 Feature 位布局([31..16] = 16 bits,精简)
|
||||
|
||||
|
||||
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 |
|
||||
|
||||
|
||||
说明:
|
||||
|
||||
- **BASE(bit 20)**:基础 AVX512 一揽子,表示同时具备 `F + CD + VL + DQ + BW`。这是 AVX512 最低可用门槛,探测端若设为 1,应保证上述子集都成立。
|
||||
- **AVX512_IMPL([23..22],2-bit)**:实现形态(宽度策略)。
|
||||
|
||||
| 值 | 含义 |
|
||||
|---:|------|
|
||||
| 0 | Unknown(需结合 Manufacture/uArch 决定策略) |
|
||||
| 1 | AVX512-DUAL(胶水/降频风险,建议默认 256 宽路径) |
|
||||
| 2 | AVX512-NATIVE(完整 512 位 ALU,可走 512 宽路径) |
|
||||
| 3 | Reserved |
|
||||
|
||||
- **VBMI/VBMI2/VNNI/BF16/FP16([29..26])**:稀疏但常用的小类型/AI 扩展,按需设置。
|
||||
- **R/AI(bit 24)**:预留给未来 AI 或其他非密码学的自选扩展。
|
||||
- **[31..30]、[21]、[19..16]**:Reserved,按需再分配。
|
||||
|
||||
---
|
||||
|
||||
## 7) “AVX512BASE” 判定(一次性检查)
|
||||
|
||||
- **规则**:`BASE=1` 即视为具备 `F+CD+VL+DQ+BW`,无需逐项再查。探测端必须保持一致性,若无法保证全部子集齐备则应置 0。
|
||||
- **运行时分支**:
|
||||
- 若 `MainLevel < AVX512`:直接降级到 AVX2/FMA 路径。
|
||||
- 否则:
|
||||
- 检查 `BASE`;若为 0 则降级到 AVX2/FMA(或视为探测错误)。
|
||||
- 查看 `AVX512_IMPL`:`DUAL` 走 256 宽/降频安全路径,`NATIVE` 走 512 宽路径。
|
||||
- 需要小类型/AI 能力时,按位查看 `VNNI/BF16/FP16/VBMI/VBMI2`。
|
||||
|
||||
---
|
||||
|
||||
## 8) AMX Future([39..32],8 bits)
|
||||
|
||||
你已经留了 1 个字节,建议先只定义 3 个最常见位,其余保留:
|
||||
|
||||
| bit(相对 [39..32]) | 名称 | 说明 |
|
||||
|---:|------|------|
|
||||
| 0 | AMX_TILE | tile 基础 |
|
||||
| 1 | AMX_INT8 | INT8 tile |
|
||||
| 2 | AMX_BF16 | BF16 tile |
|
||||
| 3..7 | Reserved | |
|
||||
|
||||
当 `MainLevel < AMX` 时,这个字节可全为 0。
|
||||
|
||||
---
|
||||
|
||||
## 9) uArch/Policy([63..40],24 bits)
|
||||
|
||||
用途:**你不想浪费比特,但又需要解决“Intel 早期/AMD 胶水”这类非 CPUID 纯子集能解决的问题**。
|
||||
把它留作可选策略字段,默认 0;你需要时再启用。
|
||||
|
||||
建议最小化用法:
|
||||
- `0`:未使用
|
||||
- `1`:ForceDual(即使 impl unknown 也当 AVX512-DUAL)
|
||||
- `2`:ForceNative(即使 impl unknown 也当 AVX512-NATIVE)
|
||||
- `3..`:你自己维护的 uArch 枚举(例如 SKX/ICL/SPR/ZEN4/ZEN5…)
|
||||
|
||||
> 由于你是单人维护,最现实的策略是:
|
||||
> - AMD:探测端直接把 `AVX512_IMPL=DUAL`(无需 uArch)
|
||||
> - Intel:仅对你关心的少数型号做 uArch 枚举,否则 unknown 走默认策略
|
||||
|
||||
---
|
||||
|
||||
## 10) 建议的最简探测端填充规则(x86-64)
|
||||
|
||||
1) 先填 `RootISA=x86-64`、`Manufacture=Intel/AMD`
|
||||
2) 计算 `MainLevel`(按你递增规则)
|
||||
3) 若 `MainLevel >= AVX512`:
|
||||
- 若探测到 `F+CD+VL+DQ+BW` 全部成立,则置 `BASE=1`,否则 `BASE=0`
|
||||
- 填 `AVX512_IMPL`:
|
||||
- AMD:DUAL(按你的定义)
|
||||
- Intel:可按 family/model 或 policy 表决定 DUAL/NATIVE;不确定就 Unknown
|
||||
- 需要 VNNI/BF16/FP16/VBMI/VBMI2 时,按位填写对应扩展
|
||||
4) 若 `MainLevel >= AMX`:填 AMX byte
|
||||
|
||||
---
|
||||
|
||||
## 11) 你需要做的一个选择(高位保留位如何分配)
|
||||
|
||||
目前 `[31..24]` 留作扩展/AI:示例定义为 FP16/BF16/VNNI/VBMI2/VBMI + 1 个预留位。
|
||||
如果你更需要 IFMA 或其他非密码学扩展,请替换 bit26~29 的定义;`BASE` 与 `Impl` 保持不变即可。
|
||||
@@ -154,18 +154,19 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sn-src\k_panel.c" />
|
||||
<ClCompile Include="sn-src\k_basicop.c" />
|
||||
<ClCompile Include="sn-src\m.panel.x86.c" />
|
||||
<ClCompile Include="sn-src\m.basic.x86.c" />
|
||||
<ClCompile Include="sn-src\dllmain.c" />
|
||||
<ClCompile Include="sn-src\k_bufop.c" />
|
||||
<ClCompile Include="sn-src\k_pivot.c" />
|
||||
<ClCompile Include="sn-src\str_factorial.c" />
|
||||
<ClCompile Include="sn-src\k_fma.c" />
|
||||
<ClCompile Include="sn-src\str_hash.c" />
|
||||
<ClCompile Include="sn-src\m.bufop.x86.c" />
|
||||
<ClCompile Include="sn-src\m.pivot.x86.c" />
|
||||
<ClCompile Include="sn-src\s.factorial.x86.c" />
|
||||
<ClCompile Include="sn-src\m.fma.x86.c" />
|
||||
<ClCompile Include="sn-src\s.hash.x86.c" />
|
||||
<ClCompile Include="sn-src\load_intrinsic.c">
|
||||
<FileType>CCode</FileType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\load_glfw.c" />
|
||||
<ClCompile Include="sn-src\cpuid.c" />
|
||||
<ClCompile Include="sn-src\sn_native.c" />
|
||||
<ClCompile Include="sn-src\str_string.c" />
|
||||
<ClCompile Include="sn-src\vector.c" />
|
||||
@@ -189,6 +190,9 @@
|
||||
<Library Include="lib\glfw\glfw3.lib" />
|
||||
<Library Include="lib\glfw\glfw3_mt.lib" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="SIMDID.md" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
@@ -13,15 +13,18 @@
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Document">
|
||||
<UniqueIdentifier>{fbd74b53-5314-4d9d-a788-07bd1b413f74}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sn-src\dllmain.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\str_factorial.c">
|
||||
<ClCompile Include="sn-src\s.factorial.x86.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\str_hash.c">
|
||||
<ClCompile Include="sn-src\s.hash.x86.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\str_string.c">
|
||||
@@ -39,22 +42,25 @@
|
||||
<ClCompile Include="sn-src\load_glfw.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\k_basicop.c">
|
||||
<ClCompile Include="sn-src\m.basic.x86.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\k_fma.c">
|
||||
<ClCompile Include="sn-src\m.fma.x86.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\load_intrinsic.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\k_bufop.c">
|
||||
<ClCompile Include="sn-src\m.bufop.x86.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\k_panel.c">
|
||||
<ClCompile Include="sn-src\m.panel.x86.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\k_pivot.c">
|
||||
<ClCompile Include="sn-src\m.pivot.x86.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sn-src\cpuid.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
@@ -104,4 +110,9 @@
|
||||
<Filter>资源文件</Filter>
|
||||
</Library>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="SIMDID.md">
|
||||
<Filter>Document</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifndef SSC_INTRIN
|
||||
#ifndef SSC_INTRIN
|
||||
#define SSC_INTRIN
|
||||
|
||||
#define SSC_INTRIN_HEAD
|
||||
@@ -22,7 +22,8 @@
|
||||
(LASTTWO(source - 1) << 6) | (LASTTWO(target - 1) << 4) | (LAST(reset3) << 3) | \
|
||||
(LAST(reset2) << 2) | (LAST(reset1) << 1) | LAST(reset0)
|
||||
#define SSE_INSERT_SIMPLE(source, target) SSE_INSERT(source, target, 0, 0, 0, 0)
|
||||
#define M256_PERMUTE(s3, s2, s1, s0) (LASTTWO(s3) << 6) | (LASTTWO(s2) << 4) | (LASTTWO(s1) << 2) | (LASTTWO(s0)
|
||||
#define M256_PERMUTE(s3, s2, s1, s0) \
|
||||
((LASTTWO(s3) << 6) | (LASTTWO(s2) << 4) | (LASTTWO(s1) << 2) | (LASTTWO(s0)))
|
||||
#define BIT_CVRT(pack, index, T) *(T *)(pack->data + index)
|
||||
#define zero_vec _mm_setzero_ps()
|
||||
#define zero_vec_256 _mm256_setzero_ps()
|
||||
@@ -92,8 +93,8 @@ typedef struct matrix_task matrix_task;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
static_assert(sizeof(matrix_task) == 128, "matrix_parallel_task_package size mismatch");
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
_Static_assert(sizeof(MAT_TASK(float)) == 128, "matrix_parallel_task_package size mismatch");
|
||||
#elif defined(__STDC_VERSION__)
|
||||
static_assert(sizeof(MAT_TASK(float)) == 128, "matrix_parallel_task_package size mismatch");
|
||||
#endif
|
||||
|
||||
#pragma region matrix buffer operation function type
|
||||
@@ -197,6 +198,114 @@ typedef void(SN_DECL *VECTORNORMALIZEPROC)(__m128 *source, __m128 *target);
|
||||
typedef void(SN_DECL *DOTPROC)(void *transpose, __m128 *vector, __m128 *ans);
|
||||
typedef uint64_t(SN_DECL *FACTORIALROC)(int n);
|
||||
|
||||
#pragma region string
|
||||
|
||||
typedef int(SN_DECL *HASH)(byte const *str, int length);
|
||||
typedef int(SN_DECL *INDEX_PAIR)(short const *stram, uint32_t target, int length);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
typedef struct mat_intrinsic {
|
||||
BUF_PROC_LRA buffer_add;
|
||||
BUF_PROC_AS buffer_fill;
|
||||
BUF_PROC_RAS buffer_scalar_mul;
|
||||
BUF_PROC_LRA buffer_sub;
|
||||
KER_PROC_RA buffer_transpose;
|
||||
PANEL_PROC build_panel;
|
||||
PANEL_PROC clear_panel;
|
||||
PNL_PROC_LRA panel_fma;
|
||||
PIVOTPROC pivot;
|
||||
PANEL_PROC store_panel;
|
||||
|
||||
} mat_intrinsic;
|
||||
|
||||
// Mirrors C# IntrinsicContext field order so managed/unmanaged layouts stay in sync.
|
||||
typedef struct sn_intrinsic {
|
||||
HASH city_hash_simplify;
|
||||
FACTORIALROC factorial_simd;
|
||||
INDEX_PAIR index_pair;
|
||||
VECTORNORMALIZEPROC vec_f32_normalize_3;
|
||||
mat_intrinsic mat[4];
|
||||
} sn_intrinsic;
|
||||
|
||||
typedef enum elment_type { F32 = 0, F64 = 1, I32 = 2, I64 = 3 } element_type;
|
||||
|
||||
typedef enum most_advanced_instruction {
|
||||
#ifdef _MSC_VER
|
||||
SSE = __IA_SUPPORT_SSE42,
|
||||
AVX256 = __IA_SUPPORT_VECTOR256,
|
||||
AVX512 = __IA_SUPPORT_VECTOR512,
|
||||
NEON
|
||||
#else
|
||||
SSE,
|
||||
AVX256,
|
||||
AVX512,
|
||||
NEON
|
||||
#endif
|
||||
} most_advanced_instruction;
|
||||
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SIMDID layout helpers (see SIMDID.simd.md)
|
||||
// bits [3..0] : Root ISA
|
||||
// bits [7..4] : Manufacture (ISA-specific)
|
||||
// bits [15..8] : MainLevel (monotonic capability)
|
||||
// bits [31..16]: AVX512 Feature
|
||||
// bits [39..32]: AMX Feature
|
||||
// bits [63..40]: uArch / Policy (optional)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define SIMDID_SHIFT_ROOT 0
|
||||
#define SIMDID_SHIFT_MANU 4
|
||||
#define SIMDID_SHIFT_MAIN 8
|
||||
#define SIMDID_SHIFT_AVX512 16
|
||||
#define SIMDID_SHIFT_AMX 32
|
||||
#define SIMDID_SHIFT_UARCH 40
|
||||
|
||||
#define SIMDID_MASK_ROOT 0xFULL
|
||||
#define SIMDID_MASK_MANU (0xFULL << SIMDID_SHIFT_MANU)
|
||||
#define SIMDID_MASK_MAIN (0xFFULL << SIMDID_SHIFT_MAIN)
|
||||
#define SIMDID_MASK_AVX512 (0xFFFFULL << SIMDID_SHIFT_AVX512)
|
||||
#define SIMDID_MASK_AMX (0xFFULL << SIMDID_SHIFT_AMX)
|
||||
#define SIMDID_MASK_UARCH (0xFFFFFFULL << SIMDID_SHIFT_UARCH)
|
||||
|
||||
// Root ISA (low nibble)
|
||||
#define SIMDID_ROOT_UNKNOWN 0x0
|
||||
#define SIMDID_ROOT_X86_64 0x1
|
||||
#define SIMDID_ROOT_AARCH64 0x2
|
||||
#define SIMDID_ROOT_PPC64LE 0x3
|
||||
#define SIMDID_ROOT_APPLESILICON 0x4
|
||||
#define SIMDID_ROOT_RISCV64 0x5
|
||||
#define SIMDID_ROOT_LOONGARCH 0x6
|
||||
|
||||
// Manufacture (x86-64 mapping; other ISAs may reinterpret)
|
||||
#define SIMDID_MANU_UNKNOWN 0x0
|
||||
#define SIMDID_MANU_INTEL 0x1
|
||||
#define SIMDID_MANU_AMD 0x2
|
||||
#define SIMDID_MANU_VIA 0x3
|
||||
|
||||
// MainLevel (ordinal, shared bits 8..15; not bit-flags)
|
||||
#define SIMDID_MAIN_LVL_NONE 0x00u
|
||||
#define SIMDID_MAIN_LVL_SSE 0x01u /* SSE1..SSE4.2 */
|
||||
#define SIMDID_MAIN_LVL_AVX2 0x02u
|
||||
#define SIMDID_MAIN_LVL_AVX2_FMA 0x03u
|
||||
#define SIMDID_MAIN_LVL_AVX2_FMA_F16C 0x04u /* 16-bit scalar/vector ready */
|
||||
#define SIMDID_MAIN_LVL_AVX512 0x05u
|
||||
#define SIMDID_MAIN_LVL_AMX 0x06u
|
||||
#define SIMDID_MAIN_LVL_AVX10 0x07u
|
||||
|
||||
/* Pre-shifted helpers for convenience when constructing SIMDID */
|
||||
#define SIMDID_MAIN_ENC_NONE SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_NONE)
|
||||
#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_AVX2_FMA SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX2_FMA)
|
||||
#define SIMDID_MAIN_ENC_AVX2_FMA_F16C SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX2_FMA_F16C)
|
||||
#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
|
||||
|
||||
INTERNAL void f32_normalize(VEC(float) * source, VEC(float) * target);
|
||||
@@ -281,85 +390,15 @@ INTERNAL void SN_DECL dot_42_avx(MAT_KERNEL(float) const *transpose, __m128 cons
|
||||
|
||||
#pragma region string
|
||||
|
||||
typedef int(SN_DECL *HASH)(byte const *str, int length);
|
||||
typedef int(SN_DECL *INDEX_PAIR)(short const *stram, uint32_t target, int length);
|
||||
|
||||
INTERNAL int SN_DECL city_hash_simplify_sse(byte const *str, int length);
|
||||
INTERNAL int SN_DECL index_pair_sse(short const *str, uint32_t target, int length);
|
||||
INTERNAL int SN_DECL index_pair_sse(short const *stram, uint32_t target, int length);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
typedef struct mat_intrinsic {
|
||||
BUF_PROC_LRA buffer_add;
|
||||
BUF_PROC_AS buffer_fill;
|
||||
BUF_PROC_RAS buffer_scalar_mul;
|
||||
BUF_PROC_LRA buffer_sub;
|
||||
KER_PROC_RA buffer_transpose;
|
||||
PANEL_PROC build_panel;
|
||||
PANEL_PROC clear_panel;
|
||||
PNL_PROC_LRA panel_fma;
|
||||
PIVOTPROC pivot;
|
||||
PANEL_PROC store_panel;
|
||||
|
||||
} mat_intrinsic;
|
||||
|
||||
// Mirrors C# IntrinsicContext field order so managed/unmanaged layouts stay in sync.
|
||||
typedef struct sn_intrinsic {
|
||||
HASH city_hash_simplify;
|
||||
FACTORIALROC factorial_simd;
|
||||
INDEX_PAIR index_pair;
|
||||
VECTORNORMALIZEPROC vec_f32_normalize_3;
|
||||
mat_intrinsic mat[4];
|
||||
} sn_intrinsic;
|
||||
|
||||
typedef enum elment_type { F32 = 0, F64 = 1, I32 = 2, I64 = 3 } element_type;
|
||||
|
||||
typedef enum most_advanced_instruction {
|
||||
#ifdef _MSC_VER
|
||||
SSE = __IA_SUPPORT_SSE42,
|
||||
AVX256 = __IA_SUPPORT_VECTOR256,
|
||||
AVX512 = __IA_SUPPORT_VECTOR512,
|
||||
NEON
|
||||
#else
|
||||
SSE,
|
||||
AVX256,
|
||||
AVX512,
|
||||
NEON
|
||||
#endif
|
||||
} most_advanced_instruction;
|
||||
|
||||
#include "sn_target.h"
|
||||
typedef enum intrinsic_level { SIMD0 = 0 } intrinsic_level;
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
typedef enum intrinsic_level {
|
||||
// No SIMD support, will cause error if used in matrix operations
|
||||
SIMD0 = 0,
|
||||
// SSE4.2 support
|
||||
SIMD1 = 1,
|
||||
// AVX2 support
|
||||
SIMD2 = 2,
|
||||
// AVX2 and AVX2-FMA support
|
||||
SIMD3 = 3,
|
||||
// AVX2-16C support based on SIMD3
|
||||
SIMD4 = 4,
|
||||
// AVX-512-dual support
|
||||
SIMD5 = 5,
|
||||
// AVX-512-native support
|
||||
SIMD6 = 6,
|
||||
// AVX-512 with 8/16-wide support
|
||||
SIMD7 = 7,
|
||||
// AMX support
|
||||
SIMD8 = 8,
|
||||
// AVX-10 support
|
||||
SIMD9 = 9,
|
||||
// future use
|
||||
SIMD_MAX = 10
|
||||
} intrinsic_level;
|
||||
|
||||
#else
|
||||
typedef enum intrinsic_level {
|
||||
} intrinsic_level;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
#ifndef SN_TARGET
|
||||
#ifndef SN_TARGET
|
||||
#define SN_TARGET
|
||||
|
||||
typedef enum SN_OS_T {
|
||||
SN_OS_WINDOWS,
|
||||
SN_OS_LINUX,
|
||||
SN_OS_MACOS,
|
||||
SN_OS_IOS,
|
||||
SN_OS_ANDROID,
|
||||
SN_OS_UNKNOWN
|
||||
} SN_OS_T;
|
||||
#include "sn_internal.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum SN_ARCH_T {
|
||||
SN_ARCH_X86_64,
|
||||
SN_ARCH_ARM64,
|
||||
SN_ARCH_RISCV64,
|
||||
SN_ARCH_PPC64le,
|
||||
} SN_ARCH_T;
|
||||
#define SN_OS_WINDOWS 0
|
||||
#define SN_OS_LINUX 1
|
||||
#define SN_OS_MACOS 2
|
||||
#define SN_OS_IOS 3
|
||||
#define SN_OS_ANDROID 4
|
||||
#define SN_OS_UNKNOWN 5
|
||||
|
||||
#define SN_ARCH_X86_64 0
|
||||
#define SN_ARCH_ARM64 1
|
||||
#define SN_ARCH_RISCV64 2
|
||||
#define SN_ARCH_PPC64le 3
|
||||
|
||||
/*
|
||||
* Target selection policy:
|
||||
@@ -38,24 +37,28 @@ typedef enum SN_ARCH_T {
|
||||
#endif
|
||||
|
||||
/* Validate externally supplied values are within known enum constants. */
|
||||
#if (SN_OS_TARGET != SN_OS_WINDOWS) && (SN_OS_TARGET != SN_OS_LINUX) && (SN_OS_TARGET != SN_OS_MACOS) && \
|
||||
(SN_OS_TARGET != SN_OS_IOS) && (SN_OS_TARGET != SN_OS_ANDROID) && (SN_OS_TARGET != SN_OS_UNKNOWN)
|
||||
#if (SN_OS_TARGET != SN_OS_WINDOWS) && (SN_OS_TARGET != SN_OS_LINUX) && \
|
||||
(SN_OS_TARGET != SN_OS_MACOS) && (SN_OS_TARGET != SN_OS_IOS) && \
|
||||
(SN_OS_TARGET != SN_OS_ANDROID) && (SN_OS_TARGET != SN_OS_UNKNOWN)
|
||||
#error "SN_OS has an invalid value. Use SN_OS_<...> enum constants."
|
||||
#endif
|
||||
|
||||
#if (SN_ARCH_TARGET != SN_ARCH_X86_64) && (SN_ARCH_TARGET != SN_ARCH_ARM64) && (SN_ARCH_TARGET != SN_ARCH_RISCV64) && \
|
||||
(SN_ARCH_TARGET != SN_ARCH_PPC64le)
|
||||
#if (SN_ARCH_TARGET != SN_ARCH_X86_64) && (SN_ARCH_TARGET != SN_ARCH_ARM64) && \
|
||||
(SN_ARCH_TARGET != SN_ARCH_RISCV64) && (SN_ARCH_TARGET != SN_ARCH_PPC64le)
|
||||
#error "SN_ARCH has an invalid value. Use SN_ARCH_<...> enum constants."
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef SN_IS_OS
|
||||
#define SN_IS_OS(os) ((SN_OS_TARGET) == (os))
|
||||
#endif
|
||||
|
||||
#ifndef SN_IS_ARCH
|
||||
#define SN_IS_ARCH(arch) ((SN_ARCH_TARGET) == (arch))
|
||||
#endif
|
||||
|
||||
typedef union SIMDID {
|
||||
uint64_t mask;
|
||||
char make_byte[];
|
||||
} SIMDID;
|
||||
|
||||
SN_API SIMDID SN_DECL sn_get_simd_level();
|
||||
|
||||
#endif // SN_TARGET
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
#include "sn_target.h"
|
||||
#include "sn_intrinsic.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#ifndef SIMDID_AVX512_BASE
|
||||
#define SIMDID_AVX512_FP16 (1U << 29)
|
||||
#define SIMDID_AVX512_BF16 (1U << 28)
|
||||
#define SIMDID_AVX512_VNNI (1U << 27)
|
||||
#define SIMDID_AVX512_VBMI2 (1U << 26)
|
||||
#define SIMDID_AVX512_VBMI (1U << 25)
|
||||
#define SIMDID_AVX512_AI_RESERVED (1U << 24)
|
||||
#define SIMDID_AVX512_BASE (1U << 20)
|
||||
#define SIMDID_AVX512_IMPL_SHIFT 22
|
||||
#define SIMDID_AVX512_IMPL_MASK (0x3U << SIMDID_AVX512_IMPL_SHIFT)
|
||||
#define SIMDID_AVX512_IMPL_UNKNOWN (0x0U << SIMDID_AVX512_IMPL_SHIFT)
|
||||
#define SIMDID_AVX512_IMPL_DUAL (0x1U << SIMDID_AVX512_IMPL_SHIFT)
|
||||
#define SIMDID_AVX512_IMPL_NATIVE (0x2U << SIMDID_AVX512_IMPL_SHIFT)
|
||||
#endif
|
||||
|
||||
#ifndef SIMDID_AMX_TILE
|
||||
#define SIMDID_AMX_TILE (1ULL << 32)
|
||||
#define SIMDID_AMX_INT8 (1ULL << 33)
|
||||
#define SIMDID_AMX_BF16 (1ULL << 34)
|
||||
#endif
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <string.h>
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
static void get_cpuid(int leaf, int subleaf, int *eax, int *ebx, int *ecx, int *edx)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
int regs[4];
|
||||
__cpuidex(regs, leaf, subleaf);
|
||||
*eax = regs[0];
|
||||
*ebx = regs[1];
|
||||
*ecx = regs[2];
|
||||
*edx = regs[3];
|
||||
#else
|
||||
unsigned int a, b, c, d;
|
||||
__cpuid_count((unsigned int)leaf, (unsigned int)subleaf, a, b, c, d);
|
||||
*eax = (int)a;
|
||||
*ebx = (int)b;
|
||||
*ecx = (int)c;
|
||||
*edx = (int)d;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int xgetbv_has_xmm_ymm(void)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
unsigned __int64 xcr0 = _xgetbv(0);
|
||||
#else
|
||||
unsigned long long xcr0 = __builtin_ia32_xgetbv(0);
|
||||
#endif
|
||||
return ((xcr0 & 0x6) == 0x6);
|
||||
}
|
||||
|
||||
static int xgetbv_has_avx512_state(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static int is_intel_glue_avx512(int family, int model)
|
||||
{
|
||||
return (family == 6) && (model == 0x55); /* SKX/CLX/CPX */
|
||||
}
|
||||
|
||||
static int is_intel_native_avx512(int family, int model)
|
||||
{
|
||||
if (family != 6)
|
||||
return 0;
|
||||
switch (model) {
|
||||
case 0x6A: /* ICX */
|
||||
case 0x6C: /* ICX stepping */
|
||||
case 0x8F: /* SPR/EMR */
|
||||
case 0xCF: /* GNR */
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SN_API SIMDID SN_DECL sn_get_simd_level()
|
||||
{
|
||||
SIMDID simd_id;
|
||||
simd_id.mask = 0;
|
||||
|
||||
int eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
|
||||
/* Vendor */
|
||||
get_cpuid(0, 0, &eax, &ebx, &ecx, &edx);
|
||||
char vendor[13];
|
||||
((int *)vendor)[0] = ebx;
|
||||
((int *)vendor)[1] = edx;
|
||||
((int *)vendor)[2] = ecx;
|
||||
vendor[12] = '\0';
|
||||
const int is_intel = (strcmp(vendor, "GenuineIntel") == 0);
|
||||
const int is_amd = (strcmp(vendor, "AuthenticAMD") == 0) ||
|
||||
(strcmp(vendor, "HygonGenuine") == 0);
|
||||
|
||||
/* CPUID.1 */
|
||||
get_cpuid(1, 0, &eax, &ebx, &ecx, &edx);
|
||||
int family = ((eax >> 8) & 0xF) + ((eax >> 20) & 0xFF0);
|
||||
int model = ((eax >> 4) & 0xF) | ((eax >> 12) & 0xF0);
|
||||
|
||||
int has_sse42 = (ecx & (1 << 20)) != 0;
|
||||
int has_avx = (ecx & (1 << 28)) != 0;
|
||||
int has_osxsave = (ecx & (1 << 27)) != 0;
|
||||
int has_fma = (ecx & (1 << 12)) != 0;
|
||||
|
||||
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 :
|
||||
SIMDID_MANU_UNKNOWN);
|
||||
uint64_t main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_NONE);
|
||||
uint64_t avx512_bits = 0;
|
||||
uint64_t amx_bits = 0;
|
||||
|
||||
/* Baseline main level */
|
||||
if (has_sse42)
|
||||
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_SSE);
|
||||
|
||||
if (has_avx && has_osxsave && xgetbv_has_xmm_ymm()) {
|
||||
/* CPUID.7.0 */
|
||||
get_cpuid(7, 0, &eax, &ebx, &ecx, &edx);
|
||||
const int has_bmi1 = (ebx & (1 << 3)) != 0;
|
||||
const int has_bmi2 = (ebx & (1 << 8)) != 0;
|
||||
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_avx512bw = (ebx & (1 << 30)) != 0;
|
||||
const int has_avx512vl = (ebx & (1u << 31)) != 0;
|
||||
const int has_avx512_vnni = (ebx & (1 << 11)) != 0;
|
||||
const int has_vbmi = (ecx & (1 << 1)) != 0;
|
||||
const int has_vbmi2 = (ecx & (1 << 6)) != 0;
|
||||
|
||||
/* leaf 7, subleaf 1 for BF16/FP16 */
|
||||
get_cpuid(7, 1, &eax, &ebx, &ecx, &edx);
|
||||
const int has_bf16 = (eax & (1 << 5)) != 0; /* AVX512_BF16 */
|
||||
const int has_fp16 = (eax & (1 << 23)) != 0; /* AVX512_FP16 */
|
||||
|
||||
/* AMX in leaf 7 subleaf 0 EDX bits 24/25/26 */
|
||||
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 << 26)) != 0;
|
||||
|
||||
if (has_avx2) {
|
||||
if (has_fma) {
|
||||
main_lvl = SIMDID_PACK_MAIN((has_bmi1 && has_bmi2) ?
|
||||
SIMDID_MAIN_LVL_AVX2_FMA_F16C :
|
||||
SIMDID_MAIN_LVL_AVX2_FMA);
|
||||
} else {
|
||||
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX2);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_avx512f && xgetbv_has_avx512_state()) {
|
||||
/* Ensure base subset present */
|
||||
if (has_avx512bw && has_avx512vl && has_avx512dq) {
|
||||
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;
|
||||
|
||||
/* impl classification */
|
||||
const int glue = is_amd || is_intel_glue_avx512(family, model);
|
||||
const int native512 = is_intel_native_avx512(family, model);
|
||||
if (glue) {
|
||||
avx512_bits |= SIMDID_AVX512_IMPL_DUAL;
|
||||
} else if (native512) {
|
||||
avx512_bits |= SIMDID_AVX512_IMPL_NATIVE;
|
||||
} else {
|
||||
avx512_bits |= SIMDID_AVX512_IMPL_UNKNOWN;
|
||||
}
|
||||
|
||||
/* main level for AVX512 */
|
||||
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX512);
|
||||
|
||||
/* AMX promotion if present */
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simd_id.mask = root | manu | main_lvl | SIMDID_PACK_AVX512(avx512_bits) |
|
||||
SIMDID_PACK_AMX(amx_bits);
|
||||
return simd_id;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
SIMDID sn_get_simd_level()
|
||||
{
|
||||
SIMDID simd_id;
|
||||
simd_id.mask = 0;
|
||||
return simd_id; /* non-x86: no SIMD level probing */
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_intrinsic.h"
|
||||
|
||||
DECLARE_PNL_PROC_ANS(float, sse, clear)
|
||||
@@ -91,3 +95,5 @@ DECLARE_KER_PROC_RIGHT_ANS(float, 512, transpose)
|
||||
|
||||
ans->f32_z[0] = _mm512_permutexvar_ps(transpose_indices, matrix);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "sn_target.h"
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
@@ -320,4 +320,4 @@ DECLARE_BUF_PROC_RIGHT_ANS_SCALAR(double, 512, scalar_mul)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_intrinsic.h"
|
||||
|
||||
#define _FMA_SELECT(i) _MM_SHUFFLE(i, i, i, i)
|
||||
@@ -379,3 +383,5 @@ DECLARE_PNL_PROC_LEFT_RIGHT_ANS(double, 512, fma)
|
||||
_mm512_store_pd((double *)&ans->vec[col][0], ccol);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_matkernel.h"
|
||||
|
||||
DECLARE_BUILD_PANEL(avx, float)
|
||||
@@ -41,7 +45,6 @@ DECLARE_BUILD_PANEL(avx, float)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DECLARE_BUILD_PANEL(512, float)
|
||||
{
|
||||
const MAT_KERNEL(float) *const zero = (const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
@@ -77,7 +80,6 @@ DECLARE_BUILD_PANEL(512, float)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DECLARE_BUILD_PANEL(512, double)
|
||||
{
|
||||
const int Q = 8; /* max(4, lanes) for double with ZMM -> 8 columns */
|
||||
@@ -295,3 +297,5 @@ DECLARE_STORE_PANEL(512, double)
|
||||
bot_dst->f64_y[kc_col] = bot256;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_intrinsic.h"
|
||||
|
||||
// Hybrid implementation: SIMD for Abs, Scalar for Max
|
||||
@@ -62,3 +66,5 @@ INTERNAL void SN_DECL pivot_float(MAT_KERNEL(float) const *source, size_t col_be
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_internal.h"
|
||||
#include "sn_intrinsic.h"
|
||||
|
||||
@@ -21,3 +25,5 @@ INTERNAL uint64_t SN_DECL factorial_simd_sse(int n)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_intrinsic.h"
|
||||
#include "StgSharpNative.h"
|
||||
|
||||
@@ -43,3 +47,5 @@ INTERNAL int SN_DECL city_hash_simplify_sse(byte const *str, int const length)
|
||||
hash ^= hash >> 16;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_intrinsic.h"
|
||||
|
||||
INTERNAL int SN_DECL index_pair_sse(short const *str, uint32_t target, int length)
|
||||
@@ -46,3 +50,5 @@ INTERNAL int SN_DECL index_pair_sse(short const *str, uint32_t target, int lengt
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user