Search code examples
c#simdavxavx512

How to get AVX512 in C#?


I wanted to use the AVX-512 instruction in C#, but what I understood is: there is no support for it (or I am extremely bad on searching on internet). So I decided to create my own binding for it. However I'm getting:

External component has thrown an exception.

And I can't figure out what I messed up here.

Here is my C code:

#include <immintrin.h>

__declspec(dllexport) 
__m512i
load_s32(const void *ptr) {
    return _mm512_load_epi32(ptr);
}

which is compiled using following commands:

gcc -c decl.c -mavx512f
gcc -shared -o libavx512.dll decl.o -Wl,--out-implib,libavx512.dll.a -mavx512f

In C# I created a library which contains following part:

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);
    }
}

And in my test program I'm using it like this:

int* mem = stackalloc int[16];
for (int i = 0; i < 16; ++i)
    mem[i] = i * 10;

M512S32 zmm0;
zmm0 = AVX512.LoadS32(mem);

I really don't know what I did wrong here.

Notes

  • To test if the binding work I removed the SIMD function:
__declspec(dllexport) 
void
load_s32(const void *ptr) {
    return;
}

and also updated the AVX512 class:

public static class AVX512
{
    [DllImport("libavx512.dll", EntryPoint = "load_s32")]
    public extern unsafe static void LoadS32(void* ptr);
}

this didn't throw an exception.

  • In the second step I tried to use the dll in a C application. which also worked out without any errors.
  • Also tried to use extra attributes such as: -Wl,--export-all-symbols, -Wl,--enable-auto-import. The related doc is here.

Solution

  • I decided to create my own binding for it.

    You can't. Best thing you can do instead, write a DLL in C or C++ which uses AVX512, and consume the DLL from C#. If you try to export individual instructions from the DLL, the performance won't be good because memory access, and because pinvoke overhead. Instead, you should write larger pieces of functionality in C.

    I really don't know what I did wrong here.

    Your C function expects input pointer in rcx register, and returns result in zmm0 vector register.

    Your C# function doesn't know about zmm0. The runtime allocates 64 bytes on stack for the return value, passes address of the return value buffer in rcx register, passes input pointer in rdx register, and expects the function to return the pointer passed in rcx in rax register.

    The languages on two sides of the interop disagree about the calling convention, and your code crashes in runtime.