के लिए समकक्ष विधि मैंने फास्ट कोनों के अनुकूलन को जारी रखने का फैसला किया और _mm_movemask_epi8
एसएसई निर्देश पर अटक गया। मैं uint8x16_t
इनपुट के साथ एआरएम नियॉन के लिए इसे कैसे लिख सकता हूं?एसएसई _mm_movemask_epi8 एआरएम नियॉन
उत्तर
कुछ परीक्षण यह कोड ऐसा दिखाई देता है के बाद सही काम करता है:
int32_t _mm_movemask_epi8_neon(uint8x16_t input)
{
const int8_t __attribute__ ((aligned (16))) xr[8] = {-7,-6,-5,-4,-3,-2,-1,0};
uint8x8_t mask_and = vdup_n_u8(0x80);
int8x8_t mask_shift = vld1_s8(xr);
uint8x8_t lo = vget_low_u8(input);
uint8x8_t hi = vget_high_u8(input);
lo = vand_u8(lo, mask_and);
lo = vshl_u8(lo, mask_shift);
hi = vand_u8(hi, mask_and);
hi = vshl_u8(hi, mask_shift);
lo = vpadd_u8(lo,lo);
lo = vpadd_u8(lo,lo);
lo = vpadd_u8(lo,lo);
hi = vpadd_u8(hi,hi);
hi = vpadd_u8(hi,hi);
hi = vpadd_u8(hi,hi);
return ((hi[0] << 8) | (lo[0] & 0xFF));
}
नोट है कि मैं इस के किसी भी परीक्षण नहीं किया है, लेकिन कुछ इस तरह काम कर सकते हैं:
X := the vector that you want to create the mask from
A := 0x808080808080...
B := 0x00FFFEFDFCFB... (i.e. 0,-1,-2,-3,...)
X = vand_u8(X, A); // Keep d7 of each byte in X
X = vshl_u8(X, B); // X[7]>>=0; X[6]>>=1; X[5]>>=2; ...
// Each byte of X now contains its msb shifted 7-N bits to the right, where N
// is the byte index.
// Do 3 pairwise adds in order to pack all these into X[0]
X = vpadd_u8(X, X);
X = vpadd_u8(X, X);
X = vpadd_u8(X, X);
// X[0] should now contain the mask. Clear the remaining bytes if necessary
यह एक बार दोहराया जाना एक 128-बिट वेक्टर कार्रवाई करने के लिए, के बाद से vpadd
केवल 64 पर काम करता है की आवश्यकता होगी -बीबी वैक्टर
मैं जानता हूँ कि इस पोस्ट काफी पुरानी हो चुकी है लेकिन मैं इसे उपयोगी मेरी (मान्य) समाधान देने के लिए मिल गया। यह इनपुट तर्क के हर लेन में सभी/सभी शून्यों को मानता है।
const uint8_t __attribute__ ((aligned (16))) _Powers[16]=
{ 1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128 };
// Set the powers of 2 (do it once for all, if applicable)
uint8x16_t Powers= vld1q_u8(_Powers);
// Compute the mask from the input
uint64x2_t Mask= vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(vandq_u8(Input, Powers))));
// Get the resulting bytes
uint16_t Output;
vst1q_lane_u8((uint8_t*)&Output + 0, (uint8x16_t)Mask, 0);
vst1q_lane_u8((uint8_t*)&Output + 1, (uint8x16_t)Mask, 8);
(मन http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47553, वैसे भी।)
इसी तरह माइकल को, चाल में गैर-शून्य प्रविष्टियों में से अनुक्रमित की शक्तियों के रूप में, और योग करने के लिए उन्हें तीन बार जोड़ो में है। यह प्रत्येक अतिरिक्त पर आगे बढ़ने के लिए डेटा आकार बढ़ाने के साथ किया जाना चाहिए। आप 2 x 8 8-बिट प्रविष्टियों से 2 x 4 16-बिट, फिर 2 x 2 32-bit और 2 x 1 64-bit से कम करते हैं। इन दो संख्याओं के निम्न बाइट समाधान देता है। मुझे नहीं लगता कि नीयन का उपयोग करके एक छोटा सा मूल्य बनाने के लिए उन्हें एक साथ पैक करने का एक आसान तरीका है।
यदि इनपुट उपयुक्त रूप में है और शक्तियों को प्रीलोड किया जा सकता है तो 6 नियॉन निर्देश लेते हैं। उदाहरण के लिए
हाय @ माइकल थेंक्स। क्या आप कृपया बता सकते हैं कि मैं आवश्यक बाइट्स के साथ वेक्टर बी कैसे भर सकता हूं? ए के लिए मैं vdup_n_u8 (0x80) का उपयोग कर सकता हूं लेकिन मुझे ए के लिए इसे कैसे करना चाहिए? आप भी vshl_u8 लिखते हैं लेकिन टिप्पणी में शिफ्ट सही है? – inspirit
वेक्टर बी: 'vld1' को एक कॉन्स्ट एरे (?) से प्रारंभ करने के लिए। सही शिफ्ट के बारे में: एआरएम दस्तावेज में कहा गया है "यदि शिफ्ट मूल्य सकारात्मक है, तो ऑपरेशन बाएं शिफ्ट है। अन्यथा, यह एक सही बदलाव है।" _। मुझे पूरा यकीन नहीं है कि अगर ऐसा होता है तो आपके द्वारा स्थानांतरित किया गया डेटा 'u8' है, या यदि आपको' s8' का उपयोग करने की आवश्यकता है। – Michael
हाँ मैं समझता हूं कि मुझे एक सरणी से बी लोड करने की आवश्यकता है, मैं बस उस वेक्टर में आपूर्ति किए गए मानों के बारे में सोच रहा था। क्या आप इसके बारे में अधिक विशिष्ट हो सकते हैं? सिर्फ [0, -1, -2, -3, -4, -5, -6, -7] होना चाहिए? और हाँ मुझे – inspirit