2011-11-01 102 views
4

我試圖將SSE3內部函數中編寫的代碼轉換爲NEON SIMD,並且因爲洗牌功能而卡住了。我曾看過GCC Intrinsic s,ARM manuals和其他論壇,但尚未能夠找到解決方案。SSE和NEON之間的轉換Intrinsics-Shuffling

CODE:

_m128i upper = _mm_loadu_si128((__m128i*)p1); 

register __m128i mask1 = _mm_set_epi8 (0x80,0x80,0x80,0x80,0x80,0x80,0x80,12,0x80,10,0x80,7,0x80,4,0x80,1); 
register __m128i mask2 = _mm_set_epi8 (0x80,0x80,0x80,0x80,0x80,0x80,12,0x80,10,0x80,7,0x80,4,0x80,1,0x80); 
__m128i temp1_upper = _mm_or_si128(_mm_shuffle_epi8(upper,mask1),_mm_shuffle_epi8(upper,mask2)); 

雖然vtbl1_u8(uint8x8_t,uint8x8_t)指令創建可用於將值分配給一目的地寄存器的查找表,它只能對。也洗牌64位寄存器操作在NEON中進行的開始比較,我不知道如何有效地做到這一點。

r0 =(mask0 & 0x80)? 0:SELECT(a,mask0 & 0x0f)// SELECT(a,n)從a中提取第n個8位參數。

r1 =(mask1 & 0x80)? 0:SELECT(一,MASK1 &爲0x0F)

...

我無法找到一個指令,它首先檢查掩模的高比特,然後選擇掩模efficiently.I的低4位知道我們可以比較寄存器中的每一位,然後在條件被指定時選擇低4位,但是我希望能夠有效地做到這一點。希望有人能夠提供幫助或提供參考。

非常感謝,

乾杯!

回答

1

當索引超出範圍時,VTBL返回0。

由於支持多達兩個Q寄存器,查找表,這將是相當簡單的:

  1. 負載查找表入的Q-寄存器(Q8例如)
  2. vtbl.8 D0, {q8},d0(其中d0包含你的掩碼)

這樣做就可以了。

如果你想讓位4〜6保持不變,你可以在vtbl之前將它們屏蔽掉。

不幸的是,VBIC對於8bit是絕對無用的。

因此,您必須犧牲一個初始化爲位掩碼操作數的寄存器。

  1. vmov.u8,D1,#0x70
  2. 負載查找表入的Q-寄存器(Q8例如)
  3. vbic.i8 D0,D0,D1
  4. VTBL。8 D0,{Q8},D0(其中,D0包含你的面具)
2

你只需要使用vtbl2_u8兩次,拆分輸入,並正確連接輸出:

#define uint8x16_to_8x8x2(v) ((uint8x8x2_t) { vget_low_u8(v), vget_high_u8(v) }) 

uint8x16_t a = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; 
uint8x16_t b = { 0x80, 0x0f, 0x01, 0x0e, 0x02, 0x0d, 0x03, 0x0c, 0x04, 0x0b, 0x05, 0x0a, 0x06, 0x09, 0x07, 0x08 }; 
uint8x16_t c = vcombine_u8(vtbl2_u8(uint8x16_to_8x8x2(a), vget_low_u8(b)), vtbl2_u8(uint8x16_to_8x8x2(a), vget_high_u8(b))); 
// c = 00 ff 11 ee 22 dd 33 cc 44 bb 55 aa 66 99 77 88 

正如傑克說,vtbl只要索引超出範圍,就會返回0,因此對於0x80情況,您不需要任何特殊處理。