2013-07-23 185 views
2

我需要將uint8數組中的值加載到128個NEON寄存器中。有一個類似的question。但是沒有好的答案。NEON:將uint8_t數組加載到128位寄存器中

我的解決辦法是:

uint8_t arr[4] = {1,2,3,4}; 

//load 4 of 8-bit vals into 64 bit reg 
uint8x8_t _vld1_u8 = vld1_u8(arr); 

//convert to 16-bit and move to 128-bit reg 
uint16x8_t _vmovl_u8 = vmovl_u8(_vld1_u8); 

//get low 64 bit and move them to 64-bit reg 
uint16x4_t _vget_low_u16 = vget_low_u16(_vmovl_u8); 

//convert to 32-bit and move to 128-bit reg 
uint32x4_t ld32x4 = vmovl_u16(_vget_low_u16); 

這工作得很好,但在我看來,這種做法是不是最快的。也許有更好更快的方式將8位數據加載到128位的32位?

編輯:

感謝@FrankH。

uint8x16x2_t z = vzipq_u8(vld1q_u8(arr), q_zero); 
uint8x16_t rr = *(uint8x16_t*)&z; 
z = vzipq_u8(rr, q_zero); 
ld32x4 = *(uint8x16_t*)&z; 

它歸結爲這個組件(當編譯器的優化上):我已經使用一些黑客想出了第二個版本

vld1.8 {d16, d17}, [r5] 
vzip.8 q8, q9 
vorr q9, q4, q4 
vzip.8 q8, q9 

所以沒有多餘的商店,這是很快速。但仍然是第一個解決方案比x1.5慢。

回答

1

你可以做一個「雙拉鍊」用零:

uint16x4_t zero = 0; 

uint32x4_t ld32x4 = 
    vreinterpretq_u32_u16(
     vzipq_u8(
      vzip_u8(
       vld1_u8(arr), 
       vreinterpret_u8_u16(zero) 
      ), 
      zero 
     ) 
    ); 

由於vreinterpretq_*()是空操作,這歸結爲三條指令。目前還沒有圍繞一個交叉編譯器,也無法驗證:(

編輯: 不要誤會我的錯在那裏......而vreinterpretq_*()沒有導致NEON指令,它是無操作,這是因爲它從做的事情時髦的類型停止編譯器你會看到,如果你想改用widerVal.val[0]所有它告訴編譯器,如:

「你。我得到了一個uint8x16x2_t,但我只想用其中的一半作爲uint8x16_t,給我一半的寄存器。「

或者:

「你有uint8x16x2_t,但我想用這些暫存器爲uint32x4_t來代替。」

即它告訴編譯器別名組霓虹燈寄存器 - 阻止存儲/加載/從堆棧加載,如果你通過.val[...]語法做明確的子集訪問,你會得到。

在一個方式,.val[...]語法「是一個黑客」,但更好方法,利用vreinterpretq_*(),「看起來像一個黑客」。 不是使用它會導致更多指令和更慢/更差的代碼。

+0

但是vzip_u8返回uint8x8x2_t,而vzipq_u8需要uint8x16_t。 – Max

+0

試過這個:ld32x4 = vzipq_u8(vzipq_u8(vld1q_u8(arr),q_zero).val [0],q_zero).val [0];但它比我的變體慢了約30%。不管怎麼說,還是要謝謝你! – Max

+0

不 - 不要做'.val [...''的事。這將強制存儲/重新加載。使用'vreinterpretq _ *()' - 根據類型/大小將uint8x8x2_t轉換爲uint8x16_t和uint8x16x2_t成爲uint8x32_t等等,它只是告訴編譯器以不同的方式解釋一組兩個/四個霓虹燈區域。 –

相關問題