2012-07-02 11 views
8

मैं नियॉन intrinsics का उपयोग कर एक अनुकूलित कोड में एक सी कोड को बदलने की कोशिश कर रहा हूँ।नियॉन एसएसई इंट्रिनिक्स के समतुल्य

यहां सी कोड हैं जो ऑपरेटरों के वैक्टरों पर नहीं 2 ऑपरेटर संचालित करते हैं।

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

इस आपरेशन के SEE अनुकूलित संस्करण पहले से ही द्वारा लागू किया गया है निम्नलिखित:

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

मैं:

#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. 

मैं लगभग नीयन intrinsics का उपयोग कर इस एक परिवर्तित कर दिया है केवल _mm_mullo_epi16 ((a), (b)); और _mm_mulhi_epu16 ((a), (b)); के नियॉन समकक्ष गायब हैं। या तो मैं कुछ गलत समझ रहा हूं या नीयन में ऐसा कोई इंट्रिनिक्स नहीं है। यदि एनईओएनएस इंट्रिनिक्स का उपयोग करके चरणों को कैसे व्यवस्थित किया जाए तो कोई समकक्ष नहीं है?

अद्यतन:

मैं निम्नलिखित बिंदु पर जोर देना भूल गया है: समारोह के operants uint16x8_t नियोन वैक्टर (प्रत्येक तत्व एक uint16_t => 0 और 65535 के बीच पूर्णांकों है) कर रहे हैं। एक जवाब में किसी ने आंतरिक vqdmulhq_s16() का उपयोग करने का प्रस्ताव रखा। इस का उपयोग दिए गए कार्यान्वयन से मेल नहीं खाएगा क्योंकि गुणात्मक आंतरिक वैक्टरों को हस्ताक्षरित मूल्यों के रूप में व्याख्या करेगा और गलत आउटपुट उत्पन्न करेगा।

+0

यदि आपके पास मूल्य> 32767 होंगे तो आपको नीचे दिए गए विस्तृत गुणा (vmull_u16) का उपयोग करने की आवश्यकता होगी। यदि आप जानते हैं कि आपके मान <32768 होंगे, तो आप vqdmulhq_s16 का उपयोग कर सकते हैं। – BitBank

उत्तर

5

आप उपयोग कर सकते हैं:

uint32x4_t vmull_u16 (uint16x4_t, uint16x4_t) 

कौन सा 32 बिट उत्पादों की एक वेक्टर देता है। यदि आप परिणाम को उच्च और निम्न हिस्सों में तोड़ना चाहते हैं तो आप एनईओएन अनजिप आंतरिक का उपयोग कर सकते हैं।

+0

वह निर्देश एक 16x16 = 32 गुणा है (आउटपुट को चौड़ा करता है)। करीब निर्देश हैं (मेरा जवाब देखें)। – BitBank

+1

@ बिटबैंक: ओपी को 16 बिट्स और निचले 16 बिट्स की आवश्यकता है इसलिए उन्हें 32 बिट परिणाम की आवश्यकता है। एक दोगुनी/संतृप्त गुणा एक विकल्प नहीं है क्योंकि आप परिशुद्धता खो देते हैं। –

1

vmulq_s16() _mm_mullo_epi16 के बराबर है। _mm_mulhi_epu16 का कोई सटीक समतुल्य नहीं है; निकटतम निर्देश vqdmulhq_s16() है जो "संतृप्त, दोगुना, गुणा करना, उच्च भाग वापस करना" है। यह केवल हस्ताक्षरित 16-बिट मानों पर काम करता है और आपको दोगुना करने के लिए इनपुट या आउटपुट को 2 से विभाजित करने की आवश्यकता होगी।

+0

चूंकि vqdmulhq_s16() हस्ताक्षरित इनपुट का उपयोग करते हैं, जीसीसी गलत टाइप किए गए तर्कों के बारे में शिकायत कर रहा है ... uint16x8_t से int16x8_t तक प्रभावी तरीके से कैसे परिवर्तित करें? – Kami

+0

कास्टिंग मैक्रोज़ हैं; vreinterpretq_s16_u16() – BitBank

+0

हस्ताक्षर गुणा के बारे में मेरा संपादन देखें! – Kami

संबंधित मुद्दे