2012-06-29 268 views
5

我試圖使用Neon intrinsics優化我的代碼。我有一個128位數組(每個uint16_t 8位)的24位旋轉。使用ARM Neon intrinsics的128位旋轉

這裏是我的C代碼:

uint16_t rotated[8]; 
uint16_t temp[8]; 
uint16_t j; 
for(j = 0; j < 8; j++) 
{ 
    //Rotation <<< 24 over 128 bits (x << shift) | (x >> (16 - shift) 
    rotated[j] = ((temp[(j+1) % 8] << 8) & 0xffff) | ((temp[(j+2) % 8] >> 8) & 0x00ff); 
} 

我檢查GCC的文檔有關Neon Intrinsics,它不具備矢量旋轉指令。此外,我試圖用vshlq_n_u16(temp, 8)來做到這一點,但所有位移到uint16_t字以外的位都丟失了。

如何使用霓虹內在函數實現這一點?順便說一下,有關於GCC Neon Intrinsics的更好的文檔?

+0

'armcc'具有'__ror'固有的 – ouah

+0

使用內嵌彙編與ROR ARM指令是什麼關係? – ouah

+0

我寧願避免組裝。順便說一句,我使用GCC所以沒有armcc! – Kami

回答

6

經過一番閱讀Arm Community Blogs,我發現這一點:

Neon Arm Bitwise Rotation

VEXT:提取 VEXT提取字節的新載體,從一對現有的載體。新向量中的字節來自第一個操作數的頂部,以及第二個操作數的底部。這允許您生成一個包含跨越一對現有向量的元素的新向量。 VEXT可用於實現來自兩個向量的數據的移動窗口,可用於FIR濾波器。 對於置換,當爲兩個輸入操作數使用相同的向量時,它也可以用來模擬逐字節旋轉操作。

以下霓虹燈GCC內在不一樣在畫面中提供的組件:

uint16x8_t vextq_u16 (uint16x8_t, uint16x8_t, const int) 

所以在全128位矢量(未在每個元件)的24位旋轉可以通過以下方式進行以下內容:

uint16x8_t input; 
uint16x8_t t0; 
uint16x8_t t1; 
uint16x8_t rotated; 

t0 = vextq_u16(input, input, 1); 
t0 = vshlq_n_u16(t0, 8); 
t1 = vextq_u16(input, input, 2); 
t1 = vshrq_n_u16(t1, 8); 
rotated = vorrq_u16(t0, t1); 
+0

除非我遺漏了一些東西,與'vextq_u8'相比,在一條指令中完成整個循環相比,這是過於複雜的。 –

4

我不是100%確定,但我不認爲NEON有輪換說明。

您可以撰寫你需要有一個左移,右屎和或旋轉動作,例如:

uint8_t ror(uint8_t in, int rotation) 
{ 
    return (in >> rotation) | (in << (8-rotation)); 
} 

只是做與NEON內在的左移位,右屎和或相同。

uint16x8_t temp; 
uint8_t rot; 

uint16x8_t rotated = vorrq_u16 (vshlq_n_u16(temp, rot) , vshrq_n_u16(temp, 16 - rot)); 

請參閱http://en.wikipedia.org/wiki/Circular_shift「實施循環移位」。

這將旋轉車道內的值。如果您想旋轉車道,請使用VEXT,如其他答案中所述。

+0

我不是問如何在c中做循環旋轉!我在問如何使用Neon Intrinsics來做到這一點! – Kami

+0

好吧,我已經添加了實際的內在調用。 –

+0

這比OP的答案(3條指令而不是5條)要糟糕,但除非'字節移位指令相比'vext.8'真的很慢,否則它仍然效率低下。 –

2

使用vext.8到Concat的向量與自身,給你你想要的16字節窗口(在這種情況下,由3個字節偏移量)。

與內在requires casting這樣做可以讓編譯器高興,但它仍然是一個單一的指令:

#include <arm_neon.h> 

uint16x8_t byterotate3(uint16x8_t input) { 
    uint8x16_t tmp = vreinterpretq_u8_u16(input); 
    uint8x16_t rotated = vextq_u8(tmp, tmp, 16-3); 
    return vreinterpretq_u16_u8(rotated); 
} 

g++5.4 -O3 -march=armv7-a -mfloat-abi=hard -mfpu=neonon Godbolt)彙編本:

byterotate3(__simd128_uint16_t): 
    vext.8 q0, q0, q0, #13 
    bx  lr 

的16位計數3意味着我們左旋轉3個字節。 (這意味着我們從左向量獲取13個字節,從右向量獲得3個字節,所以它也是一個右旋轉13)。


相關:86還具有指令,需要一個滑動窗口到兩個寄存器的級聯:palignr(在SSSE3添加)。


也許我失去了一些東西約NEON,但爲什麼OP的自我答案是使用vext.16(vextq_u16),其中有16位粒度我不明白。它甚至不是一個不同的指令,只是vext.8的別名,這使得不可能使用奇數計數,需要額外的指令。 The manual for vext.8 says

VEXT僞指令

可以指定16,32或64而不是8的數據類型在該 情況下,#IMM指半字,字,或雙取代 指的是字節,並且允許的範圍相應地減少了 。