如何在 C# 中获取 AVX512?
How to get AVX512 in C#?
我想在C#中使用AVX-512
指令,但我的理解是:不支持它(或者我在网上搜索非常糟糕)。所以我决定为它创建自己的绑定。但是我得到:
External component has thrown an exception.
而且我不知道我在这里搞砸了什么。
这是我的 C
代码:
#include <immintrin.h>
__declspec(dllexport)
__m512i
load_s32(const void *ptr) {
return _mm512_load_epi32(ptr);
}
使用以下命令编译:
gcc -c decl.c -mavx512f
gcc -shared -o libavx512.dll decl.o -Wl,--out-implib,libavx512.dll.a -mavx512f
在 C#
中,我创建了一个包含以下部分的库:
using System.Runtime.InteropServices;
using S64 = System.Int64;
namespace AVX512Sharp
{
[StructLayout(LayoutKind.Sequential, Size = 64)]
public struct M512S32
{
public S64 M0;
public S64 M1;
public S64 M2;
public S64 M3;
public S64 M4;
public S64 M5;
public S64 M6;
public S64 M7;
}
public static class AVX512
{
[DllImport("libavx512.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "load_s32")]
public extern unsafe static M512S32 LoadS32(void* ptr);
}
}
在我的测试程序中,我是这样使用它的:
int* mem = stackalloc int[16];
for (int i = 0; i < 16; ++i)
mem[i] = i * 10;
M512S32 zmm0;
zmm0 = AVX512.LoadS32(mem);
我真的不知道我做错了什么。
备注
- 为了测试绑定是否有效,我删除了 SIMD 功能:
__declspec(dllexport)
void
load_s32(const void *ptr) {
return;
}
并且还更新了 AVX512
class:
public static class AVX512
{
[DllImport("libavx512.dll", EntryPoint = "load_s32")]
public extern unsafe static void LoadS32(void* ptr);
}
这没有抛出异常。
- 在第二步中,我尝试在
C
应用程序中使用 dll
。这也没有任何错误。
- 还尝试使用额外的属性,例如:
-Wl,--export-all-symbols
、-Wl,--enable-auto-import
。相关文档是 here.
I decided to create my own binding for it.
你不能。您可以做的最好的事情是,用 C 或 C++ 编写一个使用 AVX512 的 DLL,然后使用 C# 中的 DLL。如果您尝试从 DLL 中导出单个指令,性能将不会很好,因为内存访问和 pinvoke 开销。相反,您应该用 C 编写更大的功能。
I really don't know what I did wrong here.
您的 C 函数需要 rcx
寄存器中的输入指针,并且 return 导致 zmm0
向量寄存器。
您的 C# 函数不知道 zmm0
。运行时在堆栈上为 return 值分配 64 个字节,在 rcx
寄存器中传递 return 值缓冲区的地址,在 rdx
寄存器中传递输入指针,并期望函数到 return 在 rax
寄存器中传入 rcx
的指针。
互操作两侧的语言不同意调用约定,并且您的代码在运行时崩溃。
我想在C#中使用AVX-512
指令,但我的理解是:不支持它(或者我在网上搜索非常糟糕)。所以我决定为它创建自己的绑定。但是我得到:
External component has thrown an exception.
而且我不知道我在这里搞砸了什么。
这是我的 C
代码:
#include <immintrin.h>
__declspec(dllexport)
__m512i
load_s32(const void *ptr) {
return _mm512_load_epi32(ptr);
}
使用以下命令编译:
gcc -c decl.c -mavx512f
gcc -shared -o libavx512.dll decl.o -Wl,--out-implib,libavx512.dll.a -mavx512f
在 C#
中,我创建了一个包含以下部分的库:
using System.Runtime.InteropServices;
using S64 = System.Int64;
namespace AVX512Sharp
{
[StructLayout(LayoutKind.Sequential, Size = 64)]
public struct M512S32
{
public S64 M0;
public S64 M1;
public S64 M2;
public S64 M3;
public S64 M4;
public S64 M5;
public S64 M6;
public S64 M7;
}
public static class AVX512
{
[DllImport("libavx512.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "load_s32")]
public extern unsafe static M512S32 LoadS32(void* ptr);
}
}
在我的测试程序中,我是这样使用它的:
int* mem = stackalloc int[16];
for (int i = 0; i < 16; ++i)
mem[i] = i * 10;
M512S32 zmm0;
zmm0 = AVX512.LoadS32(mem);
我真的不知道我做错了什么。
备注
- 为了测试绑定是否有效,我删除了 SIMD 功能:
__declspec(dllexport)
void
load_s32(const void *ptr) {
return;
}
并且还更新了 AVX512
class:
public static class AVX512
{
[DllImport("libavx512.dll", EntryPoint = "load_s32")]
public extern unsafe static void LoadS32(void* ptr);
}
这没有抛出异常。
- 在第二步中,我尝试在
C
应用程序中使用dll
。这也没有任何错误。 - 还尝试使用额外的属性,例如:
-Wl,--export-all-symbols
、-Wl,--enable-auto-import
。相关文档是 here.
I decided to create my own binding for it.
你不能。您可以做的最好的事情是,用 C 或 C++ 编写一个使用 AVX512 的 DLL,然后使用 C# 中的 DLL。如果您尝试从 DLL 中导出单个指令,性能将不会很好,因为内存访问和 pinvoke 开销。相反,您应该用 C 编写更大的功能。
I really don't know what I did wrong here.
您的 C 函数需要 rcx
寄存器中的输入指针,并且 return 导致 zmm0
向量寄存器。
您的 C# 函数不知道 zmm0
。运行时在堆栈上为 return 值分配 64 个字节,在 rcx
寄存器中传递 return 值缓冲区的地址,在 rdx
寄存器中传递输入指针,并期望函数到 return 在 rax
寄存器中传入 rcx
的指针。
互操作两侧的语言不同意调用约定,并且您的代码在运行时崩溃。