¿Cómo implementar "_mm_storeu_epi64" sin problemas de alias?

(Nota: aunque esta pregunta es sobre "almacenar", el caso de "carga" tiene los mismos problemas y es perfectamente simétrico).

Los intrínsecos SSE proporcionan un_mm_storeu_pd funcionar con la siguiente firma:

void _mm_storeu_pd (double *p, __m128d a);

Entonces, si tengo un vector de dos dobles, y quiero almacenarlo en una matriz de dos dobles, puedo usar este intrínseco.

Sin embargo, mi vector no es dos dobles; son dos enteros de 64 bits, y quiero almacenarlo en una matriz de dos enteros de 64 bits. Es decir, quiero una función con la siguiente firma:

void _mm_storeu_epi64 (int64_t *p, __m128i a);

Pero los intrínsecos no proporcionan tal función. Lo más cerca que tienen es_mm_storeu_si128:

void _mm_storeu_si128 (__m128i *p, __m128i a);

El problema es que esta función lleva un puntero a__m128i, mientras que mi matriz es una matriz deint64_t. Escribir en un objeto a través del tipo de puntero incorrecto es una violación dealias estricto y definitivamente es un comportamiento indefinido. Me preocupa que mi compilador, ahora o en el futuro, reordene u optimice la tienda, rompiendo así mi programa de maneras extrañas.

Para que quede claro, lo que quiero es una función que pueda invocar así:

__m128i v = _mm_set_epi64x(2,1);
int64_t ra[2];
_mm_storeu_epi64(&ra[0], v); // does not exist, so I want to implement it

Aquí hay seis intentos para crear dicha función.

Intento n. ° 1
void _mm_storeu_epi64(int64_t *p, __m128i a) {
    _mm_storeu_si128(reinterpret_cast<__m128i *>(p), a);
}

Esto parece tener el estricto problema de alias que me preocupa.

Intento n. ° 2
void _mm_storeu_epi64(int64_t *p, __m128i a) {
    _mm_storeu_si128(static_cast<__m128i *>(static_cast<void *>(p)), a);
}

Posiblemente mejor en general, pero no creo que haga ninguna diferencia en este caso.

Intento n. ° 3
void _mm_storeu_epi64(int64_t *p, __m128i a) {
    union TypePun {
        int64_t a[2];
        __m128i v;
     };
    TypePun *p_u = reinterpret_cast<TypePun *>(p);
    p_u->v = a;
}

Esto genera código incorrecto en mi compilador (GCC 4.9.0), que emite un alineadomovaps&nbsp;instrucción en lugar de un no alineadomovups. (La unión está alineada, entonces elreinterpret_cast&nbsp;engaña a GCC para que asumap_u&nbsp;también está alineado)

Intento n. ° 4
void _mm_storeu_epi64(int64_t *p, __m128i a) {
    union TypePun {
        int64_t a[2];
        __m128i v;
     };
    TypePun *p_u = reinterpret_cast<TypePun *>(p);
    _mm_storeu_si128(&p_u->v, a);
}

Esto parece emitir el código que quiero. El truco de "tip-punning via union", aunquetécnicamente indefinido en C ++, esampliamente apoyado. ¿Pero es este ejemplo, donde paso un puntero a un elemento de una unión en lugar de acceder a través de la unión en sí misma, realmente una forma válida de usar la unión para la escritura?

Intento n. ° 5
void _mm_storeu_epi64(int64_t *p, __m128i a) {
    p[0] = _mm_extract_epi64(a, 0);
    p[1] = _mm_extract_epi64(a, 1);
}

Esto funciona y es perfectamente válido, pero emite dos instrucciones en lugar de una.

Intento n. ° 6
void _mm_storeu_epi64(int64_t *p, __m128i a) {
    std::memcpy(p, &a, sizeof(a));
}

Esto funciona y es perfectamente válido ... creo. Pero emite un código francamente terrible en mi sistema. Derrames de CCGa&nbsp;a una ranura de pila alineada a través de una tienda alineada, luego mueve manualmente las palabras componentes al destino. (En realidad, lo derrama dos veces, una para cada componente. Muy extraño.)

...

¿Hay alguna forma de escribir esta función que (a) genere un código óptimo en un compilador moderno típico y (b) tenga un riesgo mínimo de enfrentarse a un alias estricto?