Я пытаюсь построить оптимизированное умножение правой матрицы, используя arm neon.Это
void transform ( glm::mat4 const & matrix, glm::vec4 const & input, glm::vec4 & output )
{
float32x4_t & result_local = reinterpret_cast < float32x4_t & > (*(&output[0]));
float32x4_t const & input_local = reinterpret_cast < float32x4_t const & > (*(&input[0] ));
result_local = vmulq_f32 ( reinterpret_cast < float32x4_t const & > ( matrix[ 0 ] ), input_local );
result_local = vmlaq_f32 ( result_local, reinterpret_cast < float32x4_t const & > ( matrix[ 1 ] ), input_local );
result_local = vmlaq_f32 ( result_local, reinterpret_cast < float32x4_t const & > ( matrix[ 2 ] ), input_local );
result_local = vmlaq_f32 ( result_local, reinterpret_cast < float32x4_t const & > ( matrix[ 3 ] ), input_local );
}
Компилятор (gcc) выдает неоновые инструкции, однако кажется, что входной параметр (который предположительно находится в x1) перезагружается в q1 после каждого вызова fmla:
0x0000000000400a78 <+0>: ldr q1, [x1]
0x0000000000400a7c <+4>: ldr q0, [x0]
0x0000000000400a80 <+8>: fmul v0.4s, v0.4s, v1.4s
0x0000000000400a84 <+12>: str q0, [x2]
0x0000000000400a88 <+16>: ldr q2, [x0,#16]
0x0000000000400a8c <+20>: ldr q1, [x1]
0x0000000000400a90 <+24>: fmla v0.4s, v2.4s, v1.4s
0x0000000000400a94 <+28>: str q0, [x2]
0x0000000000400a98 <+32>: ldr q2, [x0,#32]
0x0000000000400a9c <+36>: ldr q1, [x1]
0x0000000000400aa0 <+40>: fmla v0.4s, v2.4s, v1.4s
0x0000000000400aa4 <+44>: str q0, [x2]
0x0000000000400aa8 <+48>: ldr q2, [x0,#48]
0x0000000000400aac <+52>: ldr q1, [x1]
0x0000000000400ab0 <+56>: fmla v0.4s, v2.4s, v1.4s
0x0000000000400ab4 <+60>: str q0, [x2]
0x0000000000400ab8 <+64>: ret
Можно ли и этого избежать?
Компилятор gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu с опцией O2.
С уважением
Редактировать: удаление ссылки на input_local сделало трюк:
0x0000000000400af0 <+0>: ldr q1, [x1]
0x0000000000400af4 <+4>: ldr q0, [x0]
0x0000000000400af8 <+8>: fmul v0.4s, v1.4s, v0.4s
0x0000000000400afc <+12>: str q0, [x2]
0x0000000000400b00 <+16>: ldr q2, [x0,#16]
0x0000000000400b04 <+20>: fmla v0.4s, v1.4s, v2.4s
0x0000000000400b08 <+24>: str q0, [x2]
0x0000000000400b0c <+28>: ldr q2, [x0,#32]
0x0000000000400b10 <+32>: fmla v0.4s, v1.4s, v2.4s
0x0000000000400b14 <+36>: str q0, [x2]
0x0000000000400b18 <+40>: ldr q2, [x0,#48]
0x0000000000400b1c <+44>: fmla v0.4s, v1.4s, v2.4s
0x0000000000400b20 <+48>: str q0, [x2]
0x0000000000400b24 <+52>: ret
Редактировать 2: Это самое большее, что я получил за это время.
0x0000000000400ea0 <+0>: ldr q1, [x1]
0x0000000000400ea4 <+4>: ldr q0, [x0,#16]
0x0000000000400ea8 <+8>: ldr q4, [x0]
0x0000000000400eac <+12>: ldr q3, [x0,#32]
0x0000000000400eb0 <+16>: fmul v0.4s, v0.4s, v1.4s
0x0000000000400eb4 <+20>: ldr q2, [x0,#48]
0x0000000000400eb8 <+24>: fmla v0.4s, v4.4s, v1.4s
0x0000000000400ebc <+28>: fmla v0.4s, v3.4s, v1.4s
0x0000000000400ec0 <+32>: fmla v0.4s, v2.4s, v1.4s
0x0000000000400ec4 <+36>: str q0, [x2]
0x0000000000400ec8 <+40>: ret
Кажется, что влдр звонит по перф.