¿Cómo evitar que GCC rompa mis intrínsecos NEON?

Necesito escribir código NEON optimizado para un proyecto y estoy perfectamente feliz de escribir lenguaje ensamblador, pero para portabilidad / mantenibilidad estoy usando NEON instrinsics. Este código debe ser lo más rápido posible, por lo que estoy usando mi experiencia en la optimización ARM para intercalar correctamente las instrucciones y evitar las paradas de tuberías. No importa lo que haga, GCC funciona en mi contra y crea un código más lento lleno de puestos.

¿Alguien sabe cómo hacer que GCC se salga del camino y simplemente traduzca mis intrínsecos en código?

Aquí hay un ejemplo: tengo un bucle simple que niega y copia los valores de coma flotante. Funciona con 4 conjuntos de 4 a la vez para permitir que se cargue la memoria y se ejecuten las instrucciones. Hay muchos registros sobrantes, por lo que no hay razón para destrozar las cosas tan mal.

float32x4_t f32_0, f32_1, f32_2, f32_3;
int x;
for (x=0; x<n-15; x+=16)
{
   f32_0 = vld1q_f32(&s[x]);
   f32_1 = vld1q_f32(&s[x+4]);
   f32_2 = vld1q_f32(&s[x+8]);
   f32_3 = vld1q_f32(&s[x+12]);
   __builtin_prefetch(&s[x+64]);
   f32_0 = vnegq_f32(f32_0);
   f32_1 = vnegq_f32(f32_1);
   f32_2 = vnegq_f32(f32_2);
   f32_3 = vnegq_f32(f32_3);
   vst1q_f32(&d[x], f32_0);
   vst1q_f32(&d[x+4], f32_1);
   vst1q_f32(&d[x+8], f32_2);
   vst1q_f32(&d[x+12], f32_3);
} 

Este es el código que genera:

vld1.32 {d18-d19}, [r5]
vneg.f32  q9,q9        <-- GCC intentionally causes stalls
add r7,r7,#16
vld1.32 {d22-d23}, [r8]
add r5,r1,r4
vneg.f32 q11,q11   <-- all of my interleaving is undone (why?!!?)
add r8,r3,#256
vld1.32 {d20-d21}, [r10]
add r4,r1,r3
vneg.f32 q10,q10
add lr,r1,lr
vld1.32 {d16-d17}, [r9]
add ip,r1,ip
vneg.f32 q8,q8

Más información:

GCC 4.9.2 para Raspbianbanderas del compilador:-c -fPIE -march=armv7-a -Wall -O3 -mfloat-abi=hard -mfpu=neon

Cuando escribo el bucle en el código ASM modelado exactamente como mis intrínsecos (sin siquiera usar registros src / dest adicionales para obtener algunos ciclos ARM gratuitos), todavía es más rápido que el código GCC.

Actualizar: Aprecio la respuesta de James, pero en el esquema de las cosas, realmente no ayuda con el problema. La más simple de mis funciones funciona un poco mejor con la opción cortex-a7, pero la mayoría no vio ningún cambio. La triste verdad es que la optimización intrínseca de GCC no es excelente. Cuando trabajé con el compilador ARM de Microsoft hace unos años, siempre creó una salida bien diseñada para los intrínsecos de NEON, mientras que GCC tropezó constantemente. Con GCC 4.9.x, nada ha cambiado. Ciertamente aprecio la naturaleza FOSS de GCC y el mayor esfuerzo de GNU, pero no se puede negar que no hace un trabajo tan bueno como Intel, Microsoft o incluso los compiladores de ARM.

Respuestas a la pregunta(1)

Su respuesta a la pregunta