2012-07-02 25 views
8

Tôi đang cố chuyển đổi mã c thành mã được tối ưu hóa bằng cách sử dụng nội tại neon.Neon tương đương với nội tại SSE

Dưới đây là các mã c hoạt động trên 2 toán hạng không quá vectơ của toán hạng.

uint16_t mult_z216(uint16_t a,uint16_t b){ 
unsigned int c1 = a*b; 
    if(c1) 
    { 
     int c1h = c1 >> 16; 
     int c1l = c1 & 0xffff; 
     return (c1l - c1h + ((c1l<c1h)?1:0)) & 0xffff; 
    } 
    return (1-a-b) & 0xffff; 
} 

Các SEE tối ưu hóa phiên bản của hoạt động này đã được thực hiện bởi những điều sau đây:

#define MULT_Z216_SSE(a, b, c) \ 
    t0 = _mm_or_si128 ((a), (b)); \ //Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b. 
    (c) = _mm_mullo_epi16 ((a), (b)); \ //low 16-bits of the product of two 16-bit integers 
    (a) = _mm_mulhi_epu16 ((a), (b)); \ //high 16-bits of the product of two 16-bit unsigned integers 
    (b) = _mm_subs_epu16((c), (a)); \ //Subtracts the 8 unsigned 16-bit integers of a from the 8 unsigned 16-bit integers of c and saturates 
    (b) = _mm_cmpeq_epi16 ((b), C_0x0_XMM); \ //Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or unsigned 16-bit integers in b for equality. (0xFFFF or 0x0) 
    (b) = _mm_srli_epi16 ((b), 15); \ //shift right 16 bits 
    (c) = _mm_sub_epi16 ((c), (a)); \ //Subtracts the 8 signed or unsigned 16-bit integers of b from the 8 signed or unsigned 16-bit integers of a. 
    (a) = _mm_cmpeq_epi16 ((c), C_0x0_XMM); \ ////Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or unsigned 16-bit integers in b for equality. (0xFFFF or 0x0) 
    (c) = _mm_add_epi16 ((c), (b)); \ // Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or unsigned 16-bit integers in b. 
    t0 = _mm_and_si128 (t0, (a)); \ //Computes the bitwise AND of the 128-bit value in a and the 128-bit value in b. 
    (c) = _mm_sub_epi16 ((c), t0); ///Subtracts the 8 signed or unsigned 16-bit integers of b from the 8 signed or unsigned 16-bit integers of a. 

Tôi đã gần như chuyển đổi này sử dụng intrinsics neon:

#define MULT_Z216_NEON(a, b, out) \ 
    temp = vorrq_u16 (*a, *b); \ 
    // ?? 
    // ?? 
    *b = vsubq_u16(*out, *a); \ 
    *b = vceqq_u16(*out, vdupq_n_u16(0x0000)); \ 
    *b = vshrq_n_u16(*b, 15); \ 
    *out = vsubq_s16(*out, *a); \ 
    *a = vceqq_s16(*c, vdupq_n_u16(0x0000)); \ 
    *c = vaddq_s16(*c, *b); \ 
    *temp = vandq_u16(*temp, *a); \ 
    *out = vsubq_s16(*out, *a); 

Tôi chỉ thiếu các tương đương neon của _mm_mullo_epi16 ((a), (b));_mm_mulhi_epu16 ((a), (b));. Hoặc là tôi hiểu nhầm điều gì đó hoặc không có bản chất như vậy trong NEON. Nếu không có cách nào để lưu trữ các bước này bằng cách sử dụng NEONS nội tại?

UPDATE:

Tôi đã quên để nhấn mạnh các điểm sau đây: các operants của hàm là uint16x8_t vectơ NEON (mỗi phần tử là một uint16_t => số nguyên từ 0 đến 65535). Trong câu trả lời, ai đó đã đề xuất sử dụng nội tại vqdmulhq_s16(). Việc sử dụng điều này sẽ không phù hợp với việc thực hiện đã cho bởi vì phép nhân nhân sẽ giải thích các vectơ như các giá trị đã ký và tạo ra một đầu ra sai.

+0

Nếu bạn sẽ có giá trị> 32767 thì bạn sẽ cần phải sử dụng nhân rộng được đề xuất bên dưới (vmull_u16). Nếu bạn biết rằng tất cả các giá trị của bạn sẽ là <32768, thì bạn có thể sử dụng vqdmulhq_s16. – BitBank

Trả lời

5

Bạn có thể sử dụng:

uint32x4_t vmull_u16 (uint16x4_t, uint16x4_t) 

nào trả về một vector của sản phẩm 32 bit. Nếu bạn muốn chia kết quả thành các phần cao và thấp, bạn có thể sử dụng giải nén NEON nội tại.

+0

Lệnh đó là 16x16 = 32 nhân (mở rộng đầu ra). Có hướng dẫn gần hơn (xem câu trả lời của tôi). – BitBank

+1

@BitBank: OP cần 16 bit cao hơn và 16 bit thấp hơn do đó anh ta cần kết quả 32 bit. Một nhân đôi/saturating không phải là một thay thế bởi vì bạn bị mất chính xác. –

1

vmulq_s16() tương đương với _mm_mullo_epi16. Không có tương đương chính xác của _mm_mulhi_epu16; lệnh gần nhất là vqdmulhq_s16() là "bão hòa, nhân đôi, nhân lên, trả về phần cao". Nó chỉ hoạt động trên các giá trị 16 bit đã ký và bạn sẽ cần chia đầu vào hoặc đầu ra thành 2 để vô hiệu hóa giá trị tăng gấp đôi.

+0

Vì vqdmulhq_s16() sử dụng các đầu vào đã ký, GCC đang phàn nàn về các đối số đã nhập sai ... Làm thế nào để chuyển đổi một cách hiệu quả từ uint16x8_t thành int16x8_t? – Kami

+0

Có các macro đúc; sử dụng vreinterpretq_s16_u16() – BitBank

+0

Xem bản chỉnh sửa của tôi về phép nhân đã ký! – Kami

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