2012-06-29 20 views
5

Neon intrinsics kullanarak kodumu optimize etmeye çalışıyorum. 128 bitlik bir dizi üzerinde 24 bitlik bir dönüşüm var (her biri 8 uint16_t).ARM Neon intrinsics kullanarak 128-bit rotasyon

İşte benim c kodu: Ben yaklaşık Neon Intrinsics gcc belgeleri kontrol ettim

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); 
} 

ve vektör rotasyonları için talimat bulunmamaktadır. Ayrıca, vshlq_n_u16(temp, 8) kullanarak bunu yapmaya çalıştım ama uint16_t word'ün dışına kaydırılan tüm bitler kaybolur.

Neon intrinsik kullanarak nasıl elde edilir? Bu arada GCC Neon Intrinsics hakkında daha iyi bir dokümantasyon var mı?

+0

'armcc'' __ror' intrinsic – ouah

+0

'ROR' ARM yönergesiyle satır içi derlemeyi kullanma hakkında ne var? – ouah

+0

Montajdan kaçınmayı tercih ederim. Bu arada GCC kullanıyorum, bu yüzden hiç bir silah! – Kami

cevap

6

, bunu bulmuşken:

Neon Arm Bitwise Rotation

VEXT: VEXT mevcut vektörlerin bir çift bayt yeni vektör ayıklar Özü. Yeni vektördeki baytlar, birinci işlenenin tepesinden ve ikinci işlenenin altından gelmektedir. Bu, bir çift varolan vektörü dolduran yeni bir vektör öğesi üretmenizi sağlar. VEXT, FIR filtrelerinde yararlı olan iki vektörden elde edilen veriler üzerinde hareketli bir pencere uygulamak için kullanılabilir. Her iki giriş işleneni için aynı vektör kullanılırken, bir bayt-rotasyonlu döndürme işlemini simüle etmek için de kullanılabilir.

aşağıdaki neon GCC İçsel resimde verilen montaj ile aynı yapar: tarafından yapılabilir Yani (değil her öğe üzerinde) tam 128bit vektörü üzerinde 24bit rotasyon

uint16x8_t vextq_u16 (uint16x8_t, uint16x8_t, const int) 

aşağıdaki:

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

Bir şey kaçırmadığım sürece, bu bir rotasyonda tüm dönüşü yapmak için vextq_u8 ile karşılaştırıldığında aşırı karmaşıktır. –

4

% 100 emin değilim, ancak NEON'un talimatları döndürmediğini sanmıyorum.

Sen bir sola kayma, sağ bok ve OR ile gerektiren rotasyon işlemi, ör .:

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

Sadece sola kayma, herkesi korkutur ve ya Neon intrinsics ile aynı şeyi oluşturabilirsiniz.

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 "dairesel vardiya uygulanması." Bkz

Bu, şerit içindeki değerleri döndürür. Şeritleri döndürmek isterseniz, diğer cevapta açıklandığı gibi VEXT kullanın. Arm Community Blogs okuma bazı sonra

+0

Ben c döngüsel bir dönüş nasıl yapılacağını sormuyorum! Neon Intrinsics'i kullanarak nasıl yapılacağını soruyorum! – Kami

+0

Tamam, gerçek iç aramaları ekledim. –

+0

Bu, OP'nin cevabından (5 yerine 3 komut) daha az kötüyse de, 'vext.8', bayt kaydırma komutlarına göre gerçekten yavaş olmadıkça, hala etkisizdir. –

2

Kullanım vext.8 kendisiyle bir vektör Concat ve size (3 bayt tarafından ofset bu durumda) istediğiniz 16 bayt penceresini vermek.

mutlu derleyici tutmak için intrinsics requires casting ile Bunu yapmak, ama yine de tek bir talimat var:

#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=neon (on Godbolt) bu bunu derler:

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

16'lı sayımı 3, 3 bayt kadar sola dönüş yaptığımız anlamına gelir. (Bu, sol vektörden 13 bayt ve sağ vektörden 3 bayt aldığımız anlamına gelir, bu aynı zamanda 13) tarafından sağa doğru döndürülebilir.


İlgili: (SSSE3 eklenmiştir) palignr: 86, aynı zamanda, iki kayıt arasında birleştirme içine kayar bir pencere alır talimatı vardır.


Belki NEON hakkında bir şeyler kaçırıyorum ama OP'ın kendine cevap 16 bit boyutu bulunur vext.16 (vextq_u16) kullanıyorsa neden anlamıyorum. Bu, farklı bir talimat bile değil, sadece vext.8 için bir takma addır, bu da fazladan talimatlar gerektiren tek sayılı bir sayının kullanılmasını imkansız kılar. The manual for vext.8 says:

Bu durumda 16, 32 veya 64 yerine 8 bir veri türü belirtebilirsiniz

, #imm yarımsözcükleri, kelimelerin ifade eder, ya doublewords yerine

VEXT sözde talimat baytlara atıfta bulunulur ve izin verilen aralıklar buna karşılık olarak azaltılır.