Search code examples
c#simdmemory-alignment

Are C# struct parameters and locals aligned by default?


Assume I have a struct defined like this:

[StructLayout(LayoutKind.Explicit, Size = 16, Pack = 1)]
readonly struct Example {
    [FieldOffset(0)]
    public float A;
    [FieldOffset(4)]
    public float B;
    [FieldOffset(8)]
    public float C;
    [FieldOffset(12)]
    public float D;
}

Are local and argument instances of Example guaranteed to be 16-byte aligned?

Specifically, I'm curious whether I can use Unsafe.As to re-interpret such a struct to a Vector4:

static void Test(Example e) {
    var vec4 = Unsafe.As<Example, Vector4>(ref e); // Is vec4 aligned?

    var e2 = new Example();
    vec4 = Unsafe.As<Example, Vector4>(ref e2); // Is vec4 aligned?
}

Solution

  • Locals and arguments of struct types are not necessarily "overaligned" (ie aligned to anything more than would be required for scalar code). Example doesn't require an alignment of 16 so there was no specific motivation for the JIT compiler to ensure that it gets it, it may happen anyway of course, and I had to modify the source a bit to get an unaligned address (well, not 16-aligned, from a scalar point of view it's still sufficiently aligned).

    Here's a screenshot of it actually not being 16-aligned in practice:

    Debugger showing an address of 000000D29C57E6F8

    In order to make this happen, I inserted another struct parameter before e, one with size 8.

    The redundant moves are there because this happened in unoptimized mode (JIT optimization suppressed on module load, which is the default for debugging but it can be turned off to debug optimized code, which has its own issues).

    However, clearly the load resulting from the Unsafe.As was an unaligned load (vmovupd, theoretically this is the instruction to load a vector of 2 doubles instead of 4 floats but that makes no actual difference), so no exception resulted from the misalignment. I could not find clear documentation on what kind of alignment is officially required to load a Vector4 this way.