many things
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
//-----------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="ElementType"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload Space
|
||||
// Copyright (c) Nitload Space. All rights reserved.
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -25,15 +25,52 @@
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable CA1028
|
||||
namespace StgSharp.Mathematics.Numeric
|
||||
{
|
||||
public enum MatrixElementType : int
|
||||
[StructLayout(LayoutKind.Explicit, Size = 4)]
|
||||
public struct MatrixElementType
|
||||
{
|
||||
|
||||
F32 = 0,
|
||||
F64 = 1,
|
||||
I32 = 2,
|
||||
I64 = 3,
|
||||
public static readonly MatrixElementType F32 = new(0x03000004);
|
||||
public static readonly MatrixElementType F64 = new(0x03000008);
|
||||
public static readonly MatrixElementType I08 = new(0x0100001);
|
||||
public static readonly MatrixElementType I16 = new(0x0100002);
|
||||
public static readonly MatrixElementType I32 = new(0x0100004);
|
||||
public static readonly MatrixElementType I64 = new(0x0100008);
|
||||
public static readonly MatrixElementType U08 = new(0x0200001);
|
||||
public static readonly MatrixElementType U16 = new(0x0200002);
|
||||
public static readonly MatrixElementType U32 = new(0x0200004);
|
||||
public static readonly MatrixElementType U64 = new(0x0200008);
|
||||
|
||||
[FieldOffset(0)] internal readonly int Mask;
|
||||
[FieldOffset(3)] public readonly MatrixElementTypeGroup Group;
|
||||
|
||||
[FieldOffset(0)] public readonly ushort Size;
|
||||
|
||||
private MatrixElementType(
|
||||
int mask
|
||||
)
|
||||
{
|
||||
Unsafe.SkipInit(out this);
|
||||
Unsafe.SkipInit(out Size);
|
||||
Unsafe.SkipInit(out Group);
|
||||
this.Mask = mask;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum MatrixElementTypeGroup : byte
|
||||
{
|
||||
|
||||
None = 0,
|
||||
Singed = 1,
|
||||
Unsigned = 2,
|
||||
Float = 3,
|
||||
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1028
|
||||
|
||||
@@ -40,68 +40,6 @@ namespace StgSharp.Mathematics.Numeric
|
||||
public partial class MatrixCompute
|
||||
{
|
||||
|
||||
internal static unsafe void ComputeFmaPanelF32(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
int f32 = (int)MatrixElementType.F32;
|
||||
MatrixKernel* leftBuffer = (MatrixKernel*)p->Left;
|
||||
MatrixKernel* rightBuffer = (MatrixKernel*)p->Right;
|
||||
MatrixKernel* ansBuffer = (MatrixKernel*)p->Answer;
|
||||
ref long offsetRef = ref Unsafe.As<int, long>(ref p->PrimTileOffset);
|
||||
ref long lengthRef = ref Unsafe.As<int, long>(ref p->PrimCount);
|
||||
int ansWidth = p->AnsPrimOffset;
|
||||
int ansHeight = p->AnsSecOffset;
|
||||
int commonK = p->LeftPrimOffset;
|
||||
|
||||
M128* enumeration = stackalloc M128[1];
|
||||
enumeration->Member<int>(2) = commonK;
|
||||
enumeration->Member<int>(3) = ansHeight;
|
||||
|
||||
// in this occasion size must be 1
|
||||
for (long c = offsetRef; c < offsetRef + lengthRef; c++)
|
||||
{
|
||||
int i = (int)(c / ansHeight);
|
||||
int j = (int)(c % ansHeight);
|
||||
enumeration->Member<int>(0) = i;
|
||||
enumeration->Member<int>(1) = j;
|
||||
NativeIntrinsic.Context.mat[f32].kernel_tile_fma(leftBuffer, rightBuffer, ansBuffer,
|
||||
enumeration);
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void ComputeFmaPanelF64(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
int f64 = (int)MatrixElementType.F64;
|
||||
|
||||
// int size = 1;
|
||||
MatrixKernel* leftBuffer = (MatrixKernel*)p->Left;
|
||||
MatrixKernel* rightBuffer = (MatrixKernel*)p->Right;
|
||||
MatrixKernel* ansBuffer = (MatrixKernel*)p->Answer;
|
||||
ref long offsetRef = ref Unsafe.As<int, long>(ref p->PrimTileOffset);
|
||||
ref long lengthRef = ref Unsafe.As<int, long>(ref p->PrimCount);
|
||||
int ansWidth = p->AnsPrimOffset;
|
||||
int ansHeight = p->AnsSecOffset;
|
||||
int commonK = p->LeftPrimOffset;
|
||||
|
||||
M128* enumeration = stackalloc M128[1];
|
||||
enumeration->Member<int>(2) = commonK;
|
||||
enumeration->Member<int>(3) = ansHeight;
|
||||
|
||||
// in this occasion size must be 1
|
||||
for (long c = offsetRef; c < offsetRef + lengthRef; c++)
|
||||
{
|
||||
int i = (int)(c / ansHeight);
|
||||
int j = (int)(c % ansHeight);
|
||||
enumeration->Member<int>(0) = i;
|
||||
enumeration->Member<int>(1) = j;
|
||||
NativeIntrinsic.Context.mat[f64].kernel_tile_fma(leftBuffer, rightBuffer, ansBuffer,
|
||||
enumeration);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static unsafe MatrixKernel* GetKernelAddressUnsafe<T>(
|
||||
MatrixKernel<T>* buffer,
|
||||
|
||||
@@ -71,11 +71,9 @@ namespace StgSharp.Mathematics.Numeric
|
||||
|
||||
long recommendCount = count / 1024;
|
||||
MatrixParallelThread[] pool = LeadParallel((int)recommendCount);
|
||||
MatrixParallelWrap handle = new MatrixParallelWrap(pool);
|
||||
|
||||
// TODO set parallel queue for handle
|
||||
handle.TaskQueue = MatrixParallelQueue.Rent(package);
|
||||
return handle;
|
||||
MatrixParallelWrap wrap = new MatrixParallelWrap(pool);
|
||||
wrap.TaskQueue = MatrixParallelQueue.Rent(package);
|
||||
return wrap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ namespace StgSharp.Mathematics.Numeric
|
||||
}
|
||||
|
||||
// TODO 构建全局的保底上下文
|
||||
foreach (MatrixParallelThread thread in _threads) { }
|
||||
if (contextMap.Keys.Count == 1)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
@@ -113,7 +114,7 @@ namespace StgSharp.Mathematics.Numeric
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
[LibraryImport(Native.LibName, EntryPoint = "load_intrinsic_function")]
|
||||
[LibraryImport(Native.LibName, EntryPoint = "sn_compare_simd")]
|
||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static unsafe partial ulong CompareSIMDID(
|
||||
IntrinsicContext* context,
|
||||
|
||||
@@ -52,48 +52,12 @@ namespace StgSharp.Mathematics.Numeric
|
||||
* matrix_op_mode;
|
||||
*/
|
||||
|
||||
public enum MatrixOperationSpecial : short
|
||||
public enum MatrixIndexStyle : int
|
||||
{
|
||||
|
||||
SEQ_FMA = -1,
|
||||
|
||||
}
|
||||
|
||||
public enum MatrixIndexStyle : short
|
||||
{
|
||||
|
||||
SPECIAL = 0,
|
||||
NONE = 0,
|
||||
BUFFER_INDEX = 1,
|
||||
|
||||
}
|
||||
|
||||
public enum MatrixOperationParam : short
|
||||
{
|
||||
|
||||
RIGHT_ANS_PARAM = 1,
|
||||
LEFT_RIGHT_ANS_PARAM = 2,
|
||||
RIGHT_ANS_SCALAR_PARAM = 3,
|
||||
LEFT_RIGHT_ANS_SCALAR_PARAM = 4,
|
||||
ANS_SCALAR_PARAM = 5,
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MatrixOpMode(
|
||||
MatrixIndexStyle style,
|
||||
MatrixOperationParam paramLayout
|
||||
)
|
||||
{
|
||||
|
||||
public MatrixIndexStyle OperationStyle = style;
|
||||
|
||||
public MatrixOperationParam ParameterStyle = paramLayout;
|
||||
|
||||
public MatrixOpMode(
|
||||
MatrixIndexStyle style,
|
||||
MatrixOperationSpecial paramLayout
|
||||
)
|
||||
: this(style, (MatrixOperationParam)paramLayout) { }
|
||||
SEQ_FMA = -1,
|
||||
|
||||
}
|
||||
|
||||
@@ -166,7 +130,7 @@ namespace StgSharp.Mathematics.Numeric
|
||||
|
||||
[FieldOffset(96)]public int PrimCount; // 4
|
||||
[FieldOffset(100)]public int SecCount; // 4
|
||||
[FieldOffset(104)]public MatrixOpMode ComputeMode; // 4
|
||||
[FieldOffset(104)]public MatrixIndexStyle ComputeMode; // 4
|
||||
[FieldOffset(108)]private int ReservedInt0; // 4
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using StgSharp.HighPerformance;
|
||||
using StgSharp.Internal;
|
||||
|
||||
namespace StgSharp.Mathematics.Numeric
|
||||
{
|
||||
public partial class MatrixParallelThread
|
||||
{
|
||||
|
||||
internal static unsafe void ComputeFmaPanelF32(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
int f32 = (int)MatrixElementType.F32;
|
||||
MatrixKernel* leftBuffer = (MatrixKernel*)p->Left;
|
||||
MatrixKernel* rightBuffer = (MatrixKernel*)p->Right;
|
||||
MatrixKernel* ansBuffer = (MatrixKernel*)p->Answer;
|
||||
ref long offsetRef = ref Unsafe.As<int, long>(ref p->PrimTileOffset);
|
||||
ref long lengthRef = ref Unsafe.As<int, long>(ref p->PrimCount);
|
||||
int ansWidth = p->AnsPrimOffset;
|
||||
int ansHeight = p->AnsSecOffset;
|
||||
int commonK = p->LeftPrimOffset;
|
||||
|
||||
M128* enumeration = stackalloc M128[1];
|
||||
enumeration->Member<int>(2) = commonK;
|
||||
enumeration->Member<int>(3) = ansHeight;
|
||||
|
||||
// in this occasion size must be 1
|
||||
for (long c = offsetRef; c < offsetRef + lengthRef; c++)
|
||||
{
|
||||
int i = (int)(c / ansHeight);
|
||||
int j = (int)(c % ansHeight);
|
||||
enumeration->Member<int>(0) = i;
|
||||
enumeration->Member<int>(1) = j;
|
||||
NativeIntrinsic.Context.mat[f32].kernel_tile_fma(leftBuffer, rightBuffer, ansBuffer,
|
||||
enumeration);
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void ComputeFmaPanelF64(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
int f64 = (int)MatrixElementType.F64;
|
||||
|
||||
// int size = 1;
|
||||
MatrixKernel* leftBuffer = (MatrixKernel*)p->Left;
|
||||
MatrixKernel* rightBuffer = (MatrixKernel*)p->Right;
|
||||
MatrixKernel* ansBuffer = (MatrixKernel*)p->Answer;
|
||||
ref long offsetRef = ref Unsafe.As<int, long>(ref p->PrimTileOffset);
|
||||
ref long lengthRef = ref Unsafe.As<int, long>(ref p->PrimCount);
|
||||
int ansWidth = p->AnsPrimOffset;
|
||||
int ansHeight = p->AnsSecOffset;
|
||||
int commonK = p->LeftPrimOffset;
|
||||
|
||||
M128* enumeration = stackalloc M128[1];
|
||||
enumeration->Member<int>(2) = commonK;
|
||||
enumeration->Member<int>(3) = ansHeight;
|
||||
|
||||
// in this occasion size must be 1
|
||||
for (long c = offsetRef; c < offsetRef + lengthRef; c++)
|
||||
{
|
||||
int i = (int)(c / ansHeight);
|
||||
int j = (int)(c % ansHeight);
|
||||
enumeration->Member<int>(0) = i;
|
||||
enumeration->Member<int>(1) = j;
|
||||
NativeIntrinsic.Context.mat[f64].kernel_tile_fma(leftBuffer, rightBuffer, ansBuffer,
|
||||
enumeration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,100 +34,41 @@ namespace StgSharp.Mathematics.Numeric
|
||||
public partial class MatrixParallelThread
|
||||
{
|
||||
|
||||
internal static unsafe void BufferComputeBinary(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
int size = p->ElementSize * 16;
|
||||
long count = Unsafe.As<int, long>(ref p->PrimCount);
|
||||
long offset = Unsafe.As<int, long>(ref p->PrimTileOffset) * size;
|
||||
private const int KernelStealCount = 64;
|
||||
|
||||
((delegate* unmanaged[Cdecl]<void*, void*, void*, long, void>)p->ComputeHandle)((void*)(p->Left + offset),
|
||||
(void*)(p->Right + offset),
|
||||
(void*)(p->Answer + offset),
|
||||
count);
|
||||
MatrixParallelFactory.Release(p);
|
||||
}
|
||||
|
||||
internal static unsafe void BufferComputeBinaryScalar(
|
||||
MatrixParallelTaskPackage* p
|
||||
internal unsafe void BufferCompute(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
// while () { }
|
||||
int size = p->ElementSize * 16;
|
||||
long count = Unsafe.As<int, long>(ref p->PrimCount);
|
||||
long offset = Unsafe.As<int, long>(ref p->PrimTileOffset) * size;
|
||||
ScalarPacket* scalar = p->Scalar;
|
||||
((delegate* unmanaged[Cdecl]<void*, void*, void*, ScalarPacket*, long, void>)p->ComputeHandle)((void*)(p->Left + offset),
|
||||
(void*)(p->Right + offset),
|
||||
(void*)(p->Answer + offset),
|
||||
scalar,
|
||||
count);
|
||||
MatrixParallelFactory.Release(p);
|
||||
IntPtr computeHandle = _context[p->ComputeHandle];
|
||||
((delegate* unmanaged[Cdecl]<void*, void*, void*, void*, long, void>)computeHandle)((void*)(p->Left + offset),
|
||||
(void*)(p->Right + offset),
|
||||
(void*)(p->Answer + offset),
|
||||
scalar,
|
||||
count);
|
||||
}
|
||||
|
||||
internal static unsafe void BufferComputeNoOperatorScalar(
|
||||
MatrixParallelTaskPackage* p
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal unsafe void SpecialBufferCompute(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
int size = p->ElementSize * 16;
|
||||
long count = Unsafe.As<int, long>(ref p->PrimCount);
|
||||
long offset = Unsafe.As<int, long>(ref p->PrimTileOffset) * size;
|
||||
((delegate* unmanaged[Cdecl]<void*, ScalarPacket*, long, void>)p->ComputeHandle)((void*)(p->Answer + offset),
|
||||
p->Scalar, count);
|
||||
MatrixParallelFactory.Release(p);
|
||||
}
|
||||
|
||||
internal static unsafe void BufferComputeUnary(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
int size = p->ElementSize * 16;
|
||||
long count = Unsafe.As<int, long>(ref p->PrimCount);
|
||||
long offset = Unsafe.As<int, long>(ref p->PrimTileOffset) * size;
|
||||
|
||||
((delegate* unmanaged[Cdecl]<void*, void*, long, void>)p->ComputeHandle)((void*)(p->Right + offset),
|
||||
(void*)(p->Answer + offset),
|
||||
count);
|
||||
MatrixParallelFactory.Release(p);
|
||||
}
|
||||
|
||||
internal static unsafe void BufferComputeUnaryScalar(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
int size = p->ElementSize * 16;
|
||||
long count = Unsafe.As<int, long>(ref p->PrimCount);
|
||||
long offset = Unsafe.As<int, long>(ref p->PrimTileOffset) * size;
|
||||
((delegate* unmanaged[Cdecl]<void*, void*, ScalarPacket*, long, void>)p->ComputeHandle)((void*)(p->Right + offset),
|
||||
(void*)(p->Answer + offset),
|
||||
p->Scalar,
|
||||
count);
|
||||
MatrixParallelFactory.Release(p);
|
||||
}
|
||||
|
||||
internal static unsafe void SpecialBufferCompute(
|
||||
MatrixParallelTaskPackage* p
|
||||
)
|
||||
{
|
||||
switch ((MatrixOperationSpecial)p->ComputeMode.ParameterStyle)
|
||||
switch ((MatrixElementType)p->ElementSize)
|
||||
{
|
||||
case MatrixOperationSpecial.SEQ_FMA:
|
||||
switch ((MatrixElementType)p->ElementSize)
|
||||
{
|
||||
case MatrixElementType.F64:
|
||||
MatrixCompute.ComputeFmaPanelF64(p);
|
||||
return;
|
||||
case MatrixElementType.F32:
|
||||
MatrixCompute.ComputeFmaPanelF32(p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case MatrixElementType.F64:
|
||||
ComputeFmaPanelF64(p);
|
||||
return;
|
||||
case MatrixElementType.F32:
|
||||
ComputeFmaPanelF32(p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
MatrixParallelFactory.Release(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -83,44 +83,6 @@ namespace StgSharp.Mathematics.Numeric
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void ExecuteTaskPackage(
|
||||
MatrixParallelQueue taskQueue
|
||||
)
|
||||
{
|
||||
MatrixParallelTaskPackage* p = taskQueue.Package;
|
||||
switch (p->ComputeMode.OperationStyle)
|
||||
{
|
||||
case MatrixIndexStyle.BUFFER_INDEX:
|
||||
switch (p->ComputeMode.ParameterStyle)
|
||||
{
|
||||
case MatrixOperationParam.RIGHT_ANS_PARAM:
|
||||
BufferComputeUnary(p);
|
||||
break;
|
||||
case MatrixOperationParam.LEFT_RIGHT_ANS_PARAM:
|
||||
BufferComputeBinary(p);
|
||||
break;
|
||||
case MatrixOperationParam.RIGHT_ANS_SCALAR_PARAM:
|
||||
BufferComputeUnaryScalar(p);
|
||||
break;
|
||||
case MatrixOperationParam.LEFT_RIGHT_ANS_SCALAR_PARAM:
|
||||
BufferComputeBinaryScalar(p);
|
||||
break;
|
||||
case MatrixOperationParam.ANS_SCALAR_PARAM:
|
||||
BufferComputeNoOperatorScalar(p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MatrixIndexStyle.SPECIAL:
|
||||
SpecialBufferCompute(p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Restart()
|
||||
{
|
||||
@@ -182,7 +144,19 @@ namespace StgSharp.Mathematics.Numeric
|
||||
// TODO 将外部线程绑定到当前线程上,并执行任务包
|
||||
} else
|
||||
{
|
||||
ExecuteTaskPackage(BindedWrap.TaskQueue);
|
||||
MatrixParallelQueue taskQueue = BindedWrap.TaskQueue;
|
||||
MatrixParallelTaskPackage* p = taskQueue.Package;
|
||||
if (0 > (int)p ->ComputeHandle) {
|
||||
SpecialBufferCompute(p);
|
||||
}
|
||||
switch (p->ComputeMode)
|
||||
{
|
||||
case MatrixIndexStyle.BUFFER_INDEX:
|
||||
BufferCompute(p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
BindedWrap.ReportThreadAccomplished();
|
||||
}
|
||||
_managedThread.Priority = AfterWork;
|
||||
|
||||
@@ -55,7 +55,8 @@ For **x86-64**:
|
||||
| 1 | Intel |
|
||||
| 2 | AMD |
|
||||
| 3 | VIA/Zhaoxin |
|
||||
| 4..15 | Reserved |
|
||||
| 4 | Hygon (海光) |
|
||||
| 5..15 | Reserved |
|
||||
|
||||
For **AArch64**:
|
||||
|
||||
@@ -111,15 +112,17 @@ AVX512 Feature (bits 31..16)
|
||||
Notes:
|
||||
|
||||
- **BASE (bit 20)**: Base AVX512 bundle, indicating `F + CD + VL + DQ + BW` are all present. If set to 1, the detecting side must guarantee these subsets are all available.
|
||||
- **AVX512_IMPL ([23..22], 2-bit)**: Implementation form (width policy).
|
||||
- **AVX512_IMPL ([23..22], 2-bit)**: 512-bit execution width policy — not port count, not frequency behaviour.
|
||||
|
||||
| Value | Meaning |
|
||||
|---:|------|
|
||||
| 0 | Unknown (strategy decided by Manufacture/uArch) |
|
||||
| 1 | AVX512-DUAL (glue/downclock risk; prefer 256-bit path) |
|
||||
| 2 | AVX512-NATIVE (full 512-bit ALU; 512-bit path is usable) |
|
||||
| 0 | Unknown — cannot determine; use conservative 256-bit kernels |
|
||||
| 1 | DUAL-PUMP — single 256-bit ALU executes 512-bit ops as two consecutive 256-bit micro-ops; ZMM throughput halved (example: AMD Zen4, Family 0x19) |
|
||||
| 2 | NATIVE — genuine 512-bit execution unit(s); full ZMM throughput (Intel all models including SKX; AMD Zen5 Family 0x1A and later) |
|
||||
| 3 | Reserved |
|
||||
|
||||
> **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.
|
||||
- **R/AI (bit 24)**: Reserved for future AI or other non-crypto extensions.
|
||||
- **[31..30], [21], [19..16]**: Reserved for future allocation.
|
||||
@@ -243,13 +246,17 @@ Detection:
|
||||
|
||||
## 12) Minimal Detection-Side Fill Rules (x86-64)
|
||||
|
||||
1) Set `RootISA = x86-64`, `Manufacture = Intel/AMD`.
|
||||
1) Set `RootISA = x86-64`, `Manufacture = Intel / AMD / Hygon / VIA`.
|
||||
2) Compute `MainLevel` (per ascending rule).
|
||||
3) If `MainLevel >= AVX512`:
|
||||
- If `F+CD+VL+DQ+BW` are all present, set `BASE = 1`; otherwise `BASE = 0`.
|
||||
- Set `AVX512_IMPL`:
|
||||
- AMD: DUAL (per definition)
|
||||
- Intel: Decide DUAL/NATIVE based on family/model or policy table; if uncertain, use Unknown
|
||||
- **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)
|
||||
- **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).
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#define SIMDID_MANU_INTEL 0x1
|
||||
#define SIMDID_MANU_AMD 0x2
|
||||
#define SIMDID_MANU_VIA 0x3
|
||||
#define SIMDID_MANU_HYGON 0x4 /* 海光: Zen1-derived, separate from AMD */
|
||||
|
||||
// MainLevel (ordinal, shared bits 8..15; not bit-flags)
|
||||
#define SIMDID_MAIN_LVL_NONE 0x00u
|
||||
|
||||
@@ -14,9 +14,7 @@
|
||||
#endif // _MSC_VER
|
||||
|
||||
PRIVATE void load_intrinsic_sse(sn_intrinsic *context, SIMDID id);
|
||||
PRIVATE void load_intrinsic_avx_dual(sn_intrinsic *context, SIMDID id);
|
||||
PRIVATE void load_intrinsic_avx(sn_intrinsic *context, SIMDID id);
|
||||
PRIVATE void load_intrinsic_512_dual(sn_intrinsic *context, SIMDID id);
|
||||
PRIVATE void load_intrinsic_512(sn_intrinsic *context, SIMDID id);
|
||||
|
||||
SN_API void load_intrinsic_function(void *intrinsic_context, uint64_t id)
|
||||
|
||||
@@ -151,29 +151,34 @@ DECLARE_KER_PROC_LEFT_RIGHT_ANS(float, avx, _fma, fma)
|
||||
|
||||
DECLARE_KER_PROC_LEFT_RIGHT_ANS(float, 512, , fma)
|
||||
{
|
||||
static const __m512i b_shift = { .m512i_i32 = { 0, 1, 2, 3, 5, 6, 7, 4, 10, 11, 8, 9, 15,
|
||||
12, 13, 14 } };
|
||||
static const __m512i b_shift = { .m512i_i32 = {
|
||||
// shuff order
|
||||
0, 1, 2, 3, // col0
|
||||
5, 6, 7, 4, //col1
|
||||
10, 11, 8, 9, //col2
|
||||
15, 12, 13, 14 //col3
|
||||
} };
|
||||
|
||||
register __m512 a = _mm512_load_ps((float *)left);
|
||||
register __m512 b = _mm512_load_ps((float *)right);
|
||||
register __m512 c = _mm512_load_ps((float *)ans);
|
||||
|
||||
b = _mm512_permutexvar_ps(b_shift, b);
|
||||
register __m512 a_perm = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(3, 2, 1, 0));
|
||||
register __m512 b_perm = _mm512_permute_ps(b, _FMA_SELECT(0));
|
||||
c = _mm512_fmadd_ps(a_perm, b_perm, c);
|
||||
register __m512 a_perm0 = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(3, 2, 1, 0));
|
||||
register __m512 b_perm0 = _mm512_permute_ps(b, _FMA_SELECT(0));
|
||||
c = _mm512_fmadd_ps(a_perm0, b_perm0, c);
|
||||
|
||||
a_perm = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(2, 1, 0, 3));
|
||||
b_perm = _mm512_permute_ps(b, _FMA_SELECT(1));
|
||||
c = _mm512_fmadd_ps(a_perm, b_perm, c);
|
||||
register __m512 a_perm1 = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(2, 1, 0, 3));
|
||||
register __m512 b_perm1 = _mm512_permute_ps(b, _FMA_SELECT(1));
|
||||
c = _mm512_fmadd_ps(a_perm1, b_perm1, c);
|
||||
|
||||
a_perm = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
b_perm = _mm512_permute_ps(b, _FMA_SELECT(2));
|
||||
c = _mm512_fmadd_ps(a_perm, b_perm, c);
|
||||
register __m512 a_perm2 = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
register __m512 b_perm2 = _mm512_permute_ps(b, _FMA_SELECT(2));
|
||||
c = _mm512_fmadd_ps(a_perm2, b_perm2, c);
|
||||
|
||||
a_perm = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(0, 3, 2, 1));
|
||||
b_perm = _mm512_permute_ps(b, _FMA_SELECT(3));
|
||||
c = _mm512_fmadd_ps(a_perm, b_perm, c);
|
||||
register __m512 a_perm3 = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(0, 3, 2, 1));
|
||||
register __m512 b_perm3 = _mm512_permute_ps(b, _FMA_SELECT(3));
|
||||
c = _mm512_fmadd_ps(a_perm3, b_perm3, c);
|
||||
|
||||
_mm512_store_ps((float *)ans, c);
|
||||
}
|
||||
|
||||
@@ -201,8 +201,13 @@ DECLARE_KERTILE_PROC_LEFT_RIGHT_ANS(float, avx, _fma, fma)
|
||||
|
||||
DECLARE_KERTILE_PROC_LEFT_RIGHT_ANS(float, 512, , fma)
|
||||
{
|
||||
static const __m512i b_shift_source = { .m512i_i32 = { 0, 1, 2, 3, 5, 6, 7, 4, 10, 11, 8, 9,
|
||||
15, 12, 13, 14 } };
|
||||
static const __m512i b_shift_source = { .m512i_i32 = {
|
||||
// shuff order
|
||||
0, 1, 2, 3, // col0
|
||||
5, 6, 7, 4, //col1
|
||||
10, 11, 8, 9, //col2
|
||||
15, 12, 13, 14 //col3
|
||||
} };
|
||||
int i = enumeration->m128_i32[0];
|
||||
int j = enumeration->m128_i32[1];
|
||||
int commonK = enumeration->m128_i32[2];
|
||||
|
||||
@@ -1,301 +1,301 @@
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_matkernel.h"
|
||||
|
||||
DECLARE_BUILD_PANEL(avx, float)
|
||||
{
|
||||
const int Q = 8; /* fixed for AVX float panel */
|
||||
|
||||
/* Neighbor kernels; substitute global zero kernel where out-of-bounds */
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
const MAT_KERNEL(float) *const k_lt = matrix + (row_index * col_length + col_index);
|
||||
const MAT_KERNEL(float) *const k_rt =
|
||||
has_right ? (matrix + (row_index * col_length + (col_index + 1))) :
|
||||
(const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(float) *const k_lb =
|
||||
has_bottom ? (matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
(const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(float) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
(const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
|
||||
register __m128 top128, bot128;
|
||||
register __m256 col256;
|
||||
|
||||
for (int pc = 0; pc < Q; ++pc) {
|
||||
const int is_right_half = (pc >= 4);
|
||||
const int kc_col = pc & 3; /* column index inside 4x4 kernel */
|
||||
|
||||
const MAT_KERNEL(float) *src_top = is_right_half ? k_rt : k_lt;
|
||||
const MAT_KERNEL(float) *src_bot = is_right_half ? k_rb : k_lb;
|
||||
|
||||
/* Vector loads: each kernel column is a compact __m128 */
|
||||
top128 = src_top->f32_x[kc_col];
|
||||
bot128 = src_bot->f32_x[kc_col];
|
||||
|
||||
/* Combine into an AVX column: low 128 = top, high 128 = bottom */
|
||||
col256 = _mm256_set_m128(bot128, top128);
|
||||
|
||||
PANEL_COL_VEC((*panel), pc, 0) = col256;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_BUILD_PANEL(512, float)
|
||||
{
|
||||
const MAT_KERNEL(float) *const zero = (const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(float) * k[4][4];
|
||||
|
||||
for (int kc = 0; kc < 4; ++kc) {
|
||||
for (int kr = 0; kr < 4; ++kr) {
|
||||
const int col = col_index + kc;
|
||||
const int row = row_index + kr;
|
||||
k[kc][kr] = (col < col_length && row < row_length) ?
|
||||
(matrix + (row * col_length + col)) :
|
||||
zero;
|
||||
}
|
||||
}
|
||||
|
||||
/* Each panel column corresponds to a kernel column (0..3) within a block col (0..3). */
|
||||
for (int pc = 0; pc < 16; ++pc) {
|
||||
const int blk_col = pc >> 2; /* which kernel column block (0..3) */
|
||||
const int kc_col = pc & 3; /* column inside a 4x4 kernel */
|
||||
|
||||
const __m128 r0 = k[blk_col][0]->f32_x[kc_col];
|
||||
const __m128 r1 = k[blk_col][1]->f32_x[kc_col];
|
||||
const __m128 r2 = k[blk_col][2]->f32_x[kc_col];
|
||||
const __m128 r3 = k[blk_col][3]->f32_x[kc_col];
|
||||
|
||||
const __m256 top = _mm256_set_m128(r1, r0);
|
||||
const __m256 bot = _mm256_set_m128(r3, r2);
|
||||
|
||||
__m512 col = _mm512_castps256_ps512(top);
|
||||
col = _mm512_insertf32x8(col, bot, 1);
|
||||
|
||||
PANEL_COL_VEC((*panel), pc, 0) = col;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_BUILD_PANEL(512, double)
|
||||
{
|
||||
const int Q = 8; /* max(4, lanes) for double with ZMM -> 8 columns */
|
||||
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
const MAT_KERNEL(double) *const k_lt = matrix + (row_index * col_length + col_index);
|
||||
const MAT_KERNEL(double) *const k_rt =
|
||||
has_right ? (matrix + (row_index * col_length + (col_index + 1))) :
|
||||
(const MAT_KERNEL(double) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(double) *const k_lb =
|
||||
has_bottom ? (matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
(const MAT_KERNEL(double) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(double) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
(const MAT_KERNEL(double) *)&SN_ZERO_KERNEL;
|
||||
|
||||
for (int pc = 0; pc < Q; ++pc) {
|
||||
const int is_right_half = (pc >= 4);
|
||||
const int kc_col = pc & 3; /* column index inside 4x4 kernel */
|
||||
|
||||
const MAT_KERNEL(double) *src_top = is_right_half ? k_rt : k_lt;
|
||||
const MAT_KERNEL(double) *src_bot = is_right_half ? k_rb : k_lb;
|
||||
|
||||
const __m256d top256 = src_top->f64_y[kc_col];
|
||||
const __m256d bot256 = src_bot->f64_y[kc_col];
|
||||
|
||||
__m512d col = _mm512_castpd256_pd512(top256);
|
||||
col = _mm512_insertf64x4(col, bot256, 1);
|
||||
|
||||
PANEL_COL_VEC((*panel), pc, 0) = _mm512_castpd_ps(col);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(avx, float)
|
||||
{
|
||||
const int Q = 8; /* fixed for AVX float panel */
|
||||
|
||||
/* Local dummy kernel to swallow out-of-bounds writes; no init needed */
|
||||
MAT_KERNEL(float) zero;
|
||||
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
MAT_KERNEL(float) *const k_lt = (col_index < col_length && row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(float) *const k_rt =
|
||||
has_right && (row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
MAT_KERNEL(float) *const k_lb =
|
||||
has_bottom && (col_index < col_length) ?
|
||||
(matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(float) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
|
||||
register __m128 top128, bot128;
|
||||
int i = 0;
|
||||
for (; i < Q / 2; i++) {
|
||||
const int kc_col = i; /* column index inside 4x4 kernel */
|
||||
|
||||
/* Load the panel column vector */
|
||||
const __m256 col256 = PANEL_COL_VEC((*panel), i, 0);
|
||||
/* Split into top/bottom halves */
|
||||
top128 = _mm256_castps256_ps128(col256); /* low 128 */
|
||||
bot128 = _mm256_extractf128_ps(col256, 1); /* high 128 */
|
||||
|
||||
/* Store back into kernels directly (out-of-bounds writes go to dummy) */
|
||||
k_rt->f32_x[kc_col] = top128;
|
||||
k_rb->f32_x[kc_col] = bot128;
|
||||
}
|
||||
for (; i < Q; i++) {
|
||||
const int kc_col = i - 4; /* column index inside 4x4 kernel */
|
||||
|
||||
/* Load the panel column vector */
|
||||
const __m256 col256 = PANEL_COL_VEC((*panel), i, 0);
|
||||
/* Split into top/bottom halves */
|
||||
top128 = _mm256_castps256_ps128(col256); /* low 128 */
|
||||
bot128 = _mm256_extractf128_ps(col256, 1); /* high 128 */
|
||||
|
||||
/* Store back into kernels directly (out-of-bounds writes go to dummy) */
|
||||
k_lt->f32_x[kc_col] = top128;
|
||||
k_lb->f32_x[kc_col] = bot128;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(512, float)
|
||||
{
|
||||
MAT_KERNEL(float) zero;
|
||||
MAT_KERNEL(float) * k[4][4];
|
||||
|
||||
for (int kc = 0; kc < 4; ++kc) {
|
||||
for (int kr = 0; kr < 4; ++kr) {
|
||||
const int col = col_index + kc;
|
||||
const int row = row_index + kr;
|
||||
k[kc][kr] = (col < col_length && row < row_length) ?
|
||||
(matrix + (row * col_length + col)) :
|
||||
&zero;
|
||||
}
|
||||
}
|
||||
|
||||
for (int pc = 0; pc < 16; ++pc) {
|
||||
const int blk_col = pc >> 2; /* which kernel column block (0..3) */
|
||||
const int kc_col = pc & 3; /* column inside a 4x4 kernel */
|
||||
|
||||
const __m512 col = PANEL_COL_VEC((*panel), pc, 0);
|
||||
|
||||
const __m256 top = _mm512_castps512_ps256(col);
|
||||
const __m256 bot = _mm512_extractf32x8_ps(col, 1);
|
||||
|
||||
const __m128 r0 = _mm256_castps256_ps128(top);
|
||||
const __m128 r1 = _mm256_extractf128_ps(top, 1);
|
||||
const __m128 r2 = _mm256_castps256_ps128(bot);
|
||||
const __m128 r3 = _mm256_extractf128_ps(bot, 1);
|
||||
|
||||
k[blk_col][0]->f32_x[kc_col] = r0;
|
||||
k[blk_col][1]->f32_x[kc_col] = r1;
|
||||
k[blk_col][2]->f32_x[kc_col] = r2;
|
||||
k[blk_col][3]->f32_x[kc_col] = r3;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(sse, double)
|
||||
{
|
||||
MAT_KERNEL(double) *dst = matrix + (row_index * col_length + col_index);
|
||||
|
||||
for (int pc = 0; pc < 4; ++pc) {
|
||||
const int base = pc * 2;
|
||||
dst->f64_x[base] = _mm_castps_pd(PANEL_COL_VEC((*panel), pc, 0));
|
||||
dst->f64_x[base + 1] = _mm_castps_pd(PANEL_COL_VEC((*panel), pc, 1));
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(avx, double)
|
||||
{
|
||||
const int Q = 8; /* fixed for AVX double panel */
|
||||
|
||||
MAT_KERNEL(double) zero;
|
||||
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
MAT_KERNEL(double) *const k_lt = (col_index < col_length && row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_rt =
|
||||
has_right && (row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_lb =
|
||||
has_bottom && (col_index < col_length) ?
|
||||
(matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
|
||||
for (int i = 0; i < Q; ++i) {
|
||||
const int kc_col = (i < 4) ? i : (i - 4);
|
||||
const __m256 top_chunk = PANEL_COL_VEC((*panel), i, 0);
|
||||
const __m256 bot_chunk = PANEL_COL_VEC((*panel), i, 1);
|
||||
|
||||
MAT_KERNEL(double) *const top_dst = (i < 4) ? k_rt : k_lt;
|
||||
MAT_KERNEL(double) *const bot_dst = (i < 4) ? k_rb : k_lb;
|
||||
|
||||
top_dst->f64_y[kc_col] = _mm256_castps_pd(top_chunk);
|
||||
bot_dst->f64_y[kc_col] = _mm256_castps_pd(bot_chunk);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(512, double)
|
||||
{
|
||||
const int Q = 8; /* max(4, lanes) -> 8 columns, one ZMM per column */
|
||||
|
||||
MAT_KERNEL(double) zero;
|
||||
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
MAT_KERNEL(double) *const k_lt = (col_index < col_length && row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_rt =
|
||||
has_right && (row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_lb =
|
||||
has_bottom && (col_index < col_length) ?
|
||||
(matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
|
||||
for (int i = 0; i < Q; ++i) {
|
||||
const int kc_col = (i < 4) ? i : (i - 4);
|
||||
const __m512 col = PANEL_COL_VEC((*panel), i, 0);
|
||||
const __m512d col_pd = _mm512_castps_pd(col);
|
||||
|
||||
const __m256d top256 = _mm512_castpd512_pd256(col_pd);
|
||||
const __m256d bot256 = _mm512_extractf64x4_pd(col_pd, 1);
|
||||
|
||||
MAT_KERNEL(double) *const top_dst = (i < 4) ? k_rt : k_lt;
|
||||
MAT_KERNEL(double) *const bot_dst = (i < 4) ? k_rb : k_lb;
|
||||
|
||||
top_dst->f64_y[kc_col] = top256;
|
||||
bot_dst->f64_y[kc_col] = bot256;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#include "sn_target.h"
|
||||
|
||||
#if SN_IS_ARCH(SN_ARCH_X86_64)
|
||||
|
||||
#include "sn_matkernel.h"
|
||||
|
||||
DECLARE_BUILD_PANEL(avx, float)
|
||||
{
|
||||
const int Q = 8; /* fixed for AVX float panel */
|
||||
|
||||
/* Neighbor kernels; substitute global zero kernel where out-of-bounds */
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
const MAT_KERNEL(float) *const k_lt = matrix + (row_index * col_length + col_index);
|
||||
const MAT_KERNEL(float) *const k_rt =
|
||||
has_right ? (matrix + (row_index * col_length + (col_index + 1))) :
|
||||
(const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(float) *const k_lb =
|
||||
has_bottom ? (matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
(const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(float) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
(const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
|
||||
register __m128 top128, bot128;
|
||||
register __m256 col256;
|
||||
|
||||
for (int pc = 0; pc < Q; ++pc) {
|
||||
const int is_right_half = (pc >= 4);
|
||||
const int kc_col = pc & 3; /* column index inside 4x4 kernel */
|
||||
|
||||
const MAT_KERNEL(float) *src_top = is_right_half ? k_rt : k_lt;
|
||||
const MAT_KERNEL(float) *src_bot = is_right_half ? k_rb : k_lb;
|
||||
|
||||
/* Vector loads: each kernel column is a compact __m128 */
|
||||
top128 = src_top->f32_x[kc_col];
|
||||
bot128 = src_bot->f32_x[kc_col];
|
||||
|
||||
/* Combine into an AVX column: low 128 = top, high 128 = bottom */
|
||||
col256 = _mm256_set_m128(bot128, top128);
|
||||
|
||||
PANEL_COL_VEC((*panel), pc, 0) = col256;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_BUILD_PANEL(512, float)
|
||||
{
|
||||
const MAT_KERNEL(float) *const zero = (const MAT_KERNEL(float) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(float) * k[4][4];
|
||||
|
||||
for (int kc = 0; kc < 4; ++kc) {
|
||||
for (int kr = 0; kr < 4; ++kr) {
|
||||
const int col = col_index + kc;
|
||||
const int row = row_index + kr;
|
||||
k[kc][kr] = (col < col_length && row < row_length) ?
|
||||
(matrix + (row * col_length + col)) :
|
||||
zero;
|
||||
}
|
||||
}
|
||||
|
||||
/* Each panel column corresponds to a kernel column (0..3) within a block col (0..3). */
|
||||
for (int pc = 0; pc < 16; ++pc) {
|
||||
const int blk_col = pc >> 2; /* which kernel column block (0..3) */
|
||||
const int kc_col = pc & 3; /* column inside a 4x4 kernel */
|
||||
|
||||
const __m128 r0 = k[blk_col][0]->f32_x[kc_col];
|
||||
const __m128 r1 = k[blk_col][1]->f32_x[kc_col];
|
||||
const __m128 r2 = k[blk_col][2]->f32_x[kc_col];
|
||||
const __m128 r3 = k[blk_col][3]->f32_x[kc_col];
|
||||
|
||||
const __m256 top = _mm256_set_m128(r1, r0);
|
||||
const __m256 bot = _mm256_set_m128(r3, r2);
|
||||
|
||||
__m512 col = _mm512_castps256_ps512(top);
|
||||
col = _mm512_insertf32x8(col, bot, 1);
|
||||
|
||||
PANEL_COL_VEC((*panel), pc, 0) = col;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_BUILD_PANEL(512, double)
|
||||
{
|
||||
const int Q = 8; /* max(4, lanes) for double with ZMM -> 8 columns */
|
||||
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
const MAT_KERNEL(double) *const k_lt = matrix + (row_index * col_length + col_index);
|
||||
const MAT_KERNEL(double) *const k_rt =
|
||||
has_right ? (matrix + (row_index * col_length + (col_index + 1))) :
|
||||
(const MAT_KERNEL(double) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(double) *const k_lb =
|
||||
has_bottom ? (matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
(const MAT_KERNEL(double) *)&SN_ZERO_KERNEL;
|
||||
const MAT_KERNEL(double) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
(const MAT_KERNEL(double) *)&SN_ZERO_KERNEL;
|
||||
|
||||
for (int pc = 0; pc < Q; ++pc) {
|
||||
const int is_right_half = (pc >= 4);
|
||||
const int kc_col = pc & 3; /* column index inside 4x4 kernel */
|
||||
|
||||
const MAT_KERNEL(double) *src_top = is_right_half ? k_rt : k_lt;
|
||||
const MAT_KERNEL(double) *src_bot = is_right_half ? k_rb : k_lb;
|
||||
|
||||
const __m256d top256 = src_top->f64_y[kc_col];
|
||||
const __m256d bot256 = src_bot->f64_y[kc_col];
|
||||
|
||||
__m512d col = _mm512_castpd256_pd512(top256);
|
||||
col = _mm512_insertf64x4(col, bot256, 1);
|
||||
|
||||
PANEL_COL_VEC((*panel), pc, 0) = _mm512_castpd_ps(col);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(avx, float)
|
||||
{
|
||||
const int Q = 8; /* fixed for AVX float panel */
|
||||
|
||||
/* Local dummy kernel to swallow out-of-bounds writes; no init needed */
|
||||
MAT_KERNEL(float) zero;
|
||||
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
MAT_KERNEL(float) *const k_lt = (col_index < col_length && row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(float) *const k_rt =
|
||||
has_right && (row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
MAT_KERNEL(float) *const k_lb =
|
||||
has_bottom && (col_index < col_length) ?
|
||||
(matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(float) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
|
||||
register __m128 top128, bot128;
|
||||
int i = 0;
|
||||
for (; i < Q / 2; i++) {
|
||||
const int kc_col = i; /* column index inside 4x4 kernel */
|
||||
|
||||
/* Load the panel column vector */
|
||||
const __m256 col256 = PANEL_COL_VEC((*panel), i, 0);
|
||||
/* Split into top/bottom halves */
|
||||
top128 = _mm256_castps256_ps128(col256); /* low 128 */
|
||||
bot128 = _mm256_extractf128_ps(col256, 1); /* high 128 */
|
||||
|
||||
/* Store back into kernels directly (out-of-bounds writes go to dummy) */
|
||||
k_rt->f32_x[kc_col] = top128;
|
||||
k_rb->f32_x[kc_col] = bot128;
|
||||
}
|
||||
for (; i < Q; i++) {
|
||||
const int kc_col = i - 4; /* column index inside 4x4 kernel */
|
||||
|
||||
/* Load the panel column vector */
|
||||
const __m256 col256 = PANEL_COL_VEC((*panel), i, 0);
|
||||
/* Split into top/bottom halves */
|
||||
top128 = _mm256_castps256_ps128(col256); /* low 128 */
|
||||
bot128 = _mm256_extractf128_ps(col256, 1); /* high 128 */
|
||||
|
||||
/* Store back into kernels directly (out-of-bounds writes go to dummy) */
|
||||
k_lt->f32_x[kc_col] = top128;
|
||||
k_lb->f32_x[kc_col] = bot128;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(512, float)
|
||||
{
|
||||
MAT_KERNEL(float) zero;
|
||||
MAT_KERNEL(float) * k[4][4];
|
||||
|
||||
for (int kc = 0; kc < 4; ++kc) {
|
||||
for (int kr = 0; kr < 4; ++kr) {
|
||||
const int col = col_index + kc;
|
||||
const int row = row_index + kr;
|
||||
k[kc][kr] = (col < col_length && row < row_length) ?
|
||||
(matrix + (row * col_length + col)) :
|
||||
&zero;
|
||||
}
|
||||
}
|
||||
|
||||
for (int pc = 0; pc < 16; ++pc) {
|
||||
const int blk_col = pc >> 2; /* which kernel column block (0..3) */
|
||||
const int kc_col = pc & 3; /* column inside a 4x4 kernel */
|
||||
|
||||
const __m512 col = PANEL_COL_VEC((*panel), pc, 0);
|
||||
|
||||
const __m256 top = _mm512_castps512_ps256(col);
|
||||
const __m256 bot = _mm512_extractf32x8_ps(col, 1);
|
||||
|
||||
const __m128 r0 = _mm256_castps256_ps128(top);
|
||||
const __m128 r1 = _mm256_extractf128_ps(top, 1);
|
||||
const __m128 r2 = _mm256_castps256_ps128(bot);
|
||||
const __m128 r3 = _mm256_extractf128_ps(bot, 1);
|
||||
|
||||
k[blk_col][0]->f32_x[kc_col] = r0;
|
||||
k[blk_col][1]->f32_x[kc_col] = r1;
|
||||
k[blk_col][2]->f32_x[kc_col] = r2;
|
||||
k[blk_col][3]->f32_x[kc_col] = r3;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(sse, double)
|
||||
{
|
||||
MAT_KERNEL(double) *dst = matrix + (row_index * col_length + col_index);
|
||||
|
||||
for (int pc = 0; pc < 4; ++pc) {
|
||||
const int base = pc * 2;
|
||||
dst->f64_x[base] = _mm_castps_pd(PANEL_COL_VEC((*panel), pc, 0));
|
||||
dst->f64_x[base + 1] = _mm_castps_pd(PANEL_COL_VEC((*panel), pc, 1));
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(avx, double)
|
||||
{
|
||||
const int Q = 8; /* fixed for AVX double panel */
|
||||
|
||||
MAT_KERNEL(double) zero;
|
||||
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
MAT_KERNEL(double) *const k_lt = (col_index < col_length && row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_rt =
|
||||
has_right && (row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_lb =
|
||||
has_bottom && (col_index < col_length) ?
|
||||
(matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
|
||||
for (int i = 0; i < Q; ++i) {
|
||||
const int kc_col = (i < 4) ? i : (i - 4);
|
||||
const __m256 top_chunk = PANEL_COL_VEC((*panel), i, 0);
|
||||
const __m256 bot_chunk = PANEL_COL_VEC((*panel), i, 1);
|
||||
|
||||
MAT_KERNEL(double) *const top_dst = (i < 4) ? k_rt : k_lt;
|
||||
MAT_KERNEL(double) *const bot_dst = (i < 4) ? k_rb : k_lb;
|
||||
|
||||
top_dst->f64_y[kc_col] = _mm256_castps_pd(top_chunk);
|
||||
bot_dst->f64_y[kc_col] = _mm256_castps_pd(bot_chunk);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_STORE_PANEL(512, double)
|
||||
{
|
||||
const int Q = 8; /* max(4, lanes) -> 8 columns, one ZMM per column */
|
||||
|
||||
MAT_KERNEL(double) zero;
|
||||
|
||||
const int has_right = (col_index + 1) < col_length;
|
||||
const int has_bottom = (row_index + 1) < row_length;
|
||||
|
||||
MAT_KERNEL(double) *const k_lt = (col_index < col_length && row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_rt =
|
||||
has_right && (row_index < row_length) ?
|
||||
(matrix + (row_index * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_lb =
|
||||
has_bottom && (col_index < col_length) ?
|
||||
(matrix + ((row_index + 1) * col_length + col_index)) :
|
||||
&zero;
|
||||
MAT_KERNEL(double) *const k_rb =
|
||||
(has_right && has_bottom) ?
|
||||
(matrix + ((row_index + 1) * col_length + (col_index + 1))) :
|
||||
&zero;
|
||||
|
||||
for (int i = 0; i < Q; ++i) {
|
||||
const int kc_col = (i < 4) ? i : (i - 4);
|
||||
const __m512 col = PANEL_COL_VEC((*panel), i, 0);
|
||||
const __m512d col_pd = _mm512_castps_pd(col);
|
||||
|
||||
const __m256d top256 = _mm512_castpd512_pd256(col_pd);
|
||||
const __m256d bot256 = _mm512_extractf64x4_pd(col_pd, 1);
|
||||
|
||||
MAT_KERNEL(double) *const top_dst = (i < 4) ? k_rt : k_lt;
|
||||
MAT_KERNEL(double) *const bot_dst = (i < 4) ? k_rb : k_lb;
|
||||
|
||||
top_dst->f64_y[kc_col] = top256;
|
||||
bot_dst->f64_y[kc_col] = bot256;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -57,24 +57,15 @@ static int xgetbv_has_avx512_state(void)
|
||||
return ((xcr0 & mask) == mask);
|
||||
}
|
||||
|
||||
static int is_intel_dual_avx512(int family, int model)
|
||||
/* 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (family == 0x19) return SIMDID_AVX512_IMPL_DUAL;
|
||||
if (family >= 0x1A) 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).
|
||||
@@ -110,9 +101,9 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local()
|
||||
((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);
|
||||
const int is_via = (strcmp(vendor, "CentaurHauls") == 0) ||
|
||||
const int is_amd = (strcmp(vendor, "AuthenticAMD") == 0);
|
||||
const int is_hygon = (strcmp(vendor, "HygonGenuine") == 0); /* 海光: separate from AMD */
|
||||
const int is_via = (strcmp(vendor, "CentaurHauls") == 0) ||
|
||||
(memcmp(vendor, " Shanghai ", 12) == 0); /* VIA / Zhaoxin */
|
||||
|
||||
/* CPUID.1 */
|
||||
@@ -128,9 +119,10 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local()
|
||||
int has_f16c = (ecx & (1 << 29)) != 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 :
|
||||
is_via ? SIMDID_MANU_VIA :
|
||||
uint64_t manu = SIMDID_PACK_MANU(is_intel ? SIMDID_MANU_INTEL :
|
||||
is_amd ? SIMDID_MANU_AMD :
|
||||
is_hygon ? SIMDID_MANU_HYGON :
|
||||
is_via ? SIMDID_MANU_VIA :
|
||||
SIMDID_MANU_UNKNOWN);
|
||||
uint64_t main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_NONE);
|
||||
uint64_t avx512_bits = 0;
|
||||
@@ -202,16 +194,17 @@ SN_API SIMDID SN_DECL sn_get_simd_level_local()
|
||||
if (has_vbmi2)
|
||||
avx512_bits |= SIMDID_AVX512_VBMI2;
|
||||
|
||||
/* impl classification */
|
||||
const int glue = is_amd || is_intel_dual_avx512(family, model);
|
||||
const int native512 = is_intel_native_avx512(family, model);
|
||||
if (glue) {
|
||||
avx512_bits |= SIMDID_AVX512_IMPL_DUAL;
|
||||
} else if (native512) {
|
||||
/* Execution-width classification:
|
||||
* Intel all → NATIVE (genuine 512-bit ALU; SKX dual-port is native)
|
||||
* AMD Zen4 → DUAL (dual-pump 256-bit, Family 0x19)
|
||||
* AMD Zen5+ → NATIVE (native 512-bit, Family >= 0x1A)
|
||||
* Hygon/VIA/unknown → UNKNOWN (conservative) */
|
||||
if (is_intel)
|
||||
avx512_bits |= SIMDID_AVX512_IMPL_NATIVE;
|
||||
} else {
|
||||
else if (is_amd)
|
||||
avx512_bits |= amd_avx512_impl(family);
|
||||
else
|
||||
avx512_bits |= SIMDID_AVX512_IMPL_UNKNOWN;
|
||||
}
|
||||
|
||||
/* main level for AVX512 */
|
||||
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX512);
|
||||
|
||||
Reference in New Issue
Block a user