2012-06-29 33 views
5

Tôi đang cố gắng tối ưu hóa mã của mình bằng cách sử dụng nội tại Neon. Tôi có vòng xoay 24 bit trên mảng 128 bit (8 mỗi uint16_t).Xoay 128 bit bằng cách sử dụng ARM Neon nội tại

Đây là mã c của tôi:

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

Tôi đã kiểm tra các tài liệu gcc về Neon Intrinsics và nó không có hướng dẫn cho phép quay vectơ. Hơn nữa, tôi đã cố gắng để làm điều này bằng cách sử dụng vshlq_n_u16(temp, 8) nhưng tất cả các bit chuyển bên ngoài một từ uint16_t bị mất.

Làm thế nào để đạt được điều này bằng cách sử dụng neon nội tại? Bằng cách này là có một tài liệu tốt hơn về GCC Neon Intrinsics?

+0

'armcc' có' __ror' nội tại – ouah

+0

Điều gì về việc sử dụng lắp ráp nội tuyến bằng lệnh 'ROR' ARM? – ouah

+0

Tôi muốn tránh lắp ráp. Bằng cách này tôi đang sử dụng GCC vì vậy không có armcc! – Kami

Trả lời

6

Sau khi một số đọc trên Arm Community Blogs, tôi đã thấy điều này:

Neon Arm Bitwise Rotation

VEXT: Giải nén VEXT trích ra một vector mới của byte từ một cặp vectơ hiện có. Các byte trong vectơ mới là từ phía trên cùng của toán hạng đầu tiên và phần cuối của toán hạng thứ hai. Điều này cho phép bạn tạo ra một vectơ mới chứa các phần tử nằm giữa hai vectơ hiện có. VEXT có thể được sử dụng để thực hiện một cửa sổ di chuyển trên dữ liệu từ hai vectơ, hữu ích trong các bộ lọc FIR. Để hoán vị, nó cũng có thể được sử dụng để mô phỏng hoạt động xoay vòng byte, khi sử dụng cùng một vectơ cho cả hai toán hạng đầu vào.

Sau đây Neon GCC Intrinsic không giống như lắp ráp cung cấp trong hình:

uint16x8_t vextq_u16 (uint16x8_t, uint16x8_t, const int) 

Vì vậy, sự quay 24bit trên một vector 128bit đầy đủ (chưa kết thúc mỗi phần tử) có thể được thực hiện bằng cách như sau:

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

Trừ khi tôi đang thiếu một cái gì đó, điều này là quá phức tạp so với 'vextq_u8' để làm toàn bộ xoay trong một hướng dẫn. –

4

Tôi không chắc chắn 100% nhưng tôi không nghĩ NEON có hướng dẫn xoay.

Bạn có thể soạn các hoạt động luân chuyển bạn yêu cầu với một sự thay đổi trái, một shit đúng và hay, ví dụ .:

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

Chỉ cần làm tương tự với intrinsics Neon cho dịch trái, shit đúng và hay.

uint16x8_t temp; 
uint8_t rot; 

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

Xem http://en.wikipedia.org/wiki/Circular_shift "Thực hiện thay đổi tròn".

Điều này sẽ xoay các giá trị bên trong làn đường. Nếu bạn muốn tự xoay các làn đường, hãy sử dụng VEXT như được mô tả trong câu trả lời khác.

+0

Tôi không hỏi làm thế nào để làm một vòng xoay tròn trong c! Tôi hỏi làm thế nào để làm điều đó bằng cách sử dụng Neon Intrinsics! – Kami

+0

OK, tôi đã thêm các cuộc gọi nội tại thực tế. –

+0

Điều này ít xấu hơn câu trả lời của OP (3 hướng dẫn thay vì 5), nhưng trừ khi 'vext.8' thực sự chậm so với hướng dẫn byte-shift, nó vẫn không hiệu quả. –

2

Sử dụng vext.8 để concat một vector với chính nó và cung cấp cho bạn các cửa sổ 16-byte mà bạn muốn (trong trường hợp này bù đắp bởi 3 byte).

Việc làm này với intrinsics requires casting để giữ cho trình biên dịch hạnh phúc, nhưng nó vẫn là một hướng dẫn duy nhất:

#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) biên dịch nó như thế này:

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

Số đếm 16- 3 có nghĩa là chúng ta xoay trái 3 byte. (Nó có nghĩa là chúng ta lấy 13 byte từ vectơ bên trái và 3 byte từ vectơ bên phải, do đó, nó cũng xoay phải bằng 13).


liên quan: x86 cũng có hướng dẫn mà phải mất một cửa sổ trượt vào nối của hai thanh ghi: palignr (thêm vào trong SSSE3).


Có lẽ tôi đang thiếu một cái gì đó về NEON, nhưng tôi không hiểu tại sao tự câu trả lời của OP đang sử dụng vext.16 (vextq_u16), trong đó có 16-bit granularity. Nó thậm chí không phải là một hướng dẫn khác nhau, chỉ là một bí danh cho vext.8 mà làm cho nó không thể sử dụng một số lẻ, yêu cầu thêm hướng dẫn. The manual for vext.8 says:

VEXT giả hướng dẫn

Bạn có thể chỉ định một datatype 16, 32, hoặc 64 thay vì 8. Trong trường hợp này, #imm đề cập đến halfwords, lời nói, hoặc doublewords thay vì đề cập đến byte và phạm vi được phép tương ứng giảm .

Các vấn đề liên quan