NEON ARM: Qual é a diferença entre VLD4_F32 e VLD4Q_F32?
-
26-09-2019 - |
Pergunta
Não estou em posição de entender a diferença entre vld4_f32
e vld4q_f32
nas instruções do néon do braço.
A confusão começou quando eu levantei meus níveis de codificação e comecei a olhar para as instruções da montagem, em vez das intrínsecas menos informativas.
A razão pela qual preciso usar VLD4 Instrução variante aqui é porque, eu gostaria de capturar 4 float32_t
é de cada 4ª posição da minha grande variedade.
o vld4_f32
Intrinsics e as instruções de montagem correspondentes se parecem com esta (A partir deste link)
float32x2x4_t vld4_f32 (const float32_t *)
Form of expected instruction(s): vld4.32 {d0, d1, d2, d3}, [r0]
o vld4q_f32
Intrinsics e suas instruções de montagem correspondentes se parecem com isso
float32x4x4_t vld4q_f32 (const float32_t *)
Form of expected instruction(s): vld4.32 {d0, d1, d2, d3}, [r0]
Bem, no nível intrínsético A diferença que vejo é do tipo de retorno, mas se eu olhar para a instrução de montagem e o número de registros, ambos se parecem com a mesma. Como o compilador ou o assembler saberão a diferença entre os dois?
Alguém pode esclarecer mais sobre isso e também explicar como posso alcançar o carregamento 4 float32_t valores que estão posicionados a cada 4º local de memória em um único registro?
Solução
Sim, eu descobri a diferença. Usei o CodESourcery para ver o conteúdo do registro real para todas as instruções de carga. O link que publiquei não fornece os detalhes completos no VLD4Q_F32.
Ok, primeiro vem o vld4_f32
, isso carrega 4 d registros (por exemplo, d16-19) cada d O registro tem 64 bits de comprimento, portanto, esta instrução carrega os 8 primeiros valores intercalados com um intervalo de 4, como mostrado na figura abaixo.
No segundo caso, o vld4q_f32
, isso carrega 8 d registros (por exemplo, D16-23) em vez de quatro. Para um leitor disso link, não está claro que 8 registros serão carregados. Quando olhei para o código desmontado para um vld4qf32
, estava fazendo uso de registros de 8 dias.
Esta instrução realmente fará o que eu esperava para fazer, ou seja, carregar 4 float32_t
valores que estão no intervalo de 4, como mostrado na figura abaixo.
Outras dicas
Desmontei dois intrínsecos, talvez ajude a alguém:
// C++
uint32x4x4_t r = vld4q_u32( ( uint32_t *) output );
// assembly
VLD4.32 {D16,D18,D20,D22}, [R0]!
VLD4.32 {D17,D19,D21,D23}, [R0]
// C++
uint32x2x4_t r = vld4_u32( ( uint32_t *) output );
// assembly
VLD4.32 {D20-D23}, [R0]