एक न्यूनतम उदाहरण अधिक फायदेमंद होगा:

मान लें कि मेरे पास एक क्रमबद्ध 8 ints = {10, 20, 30, 40, 50, 60, 70, 80} है (मेरा उपयोग मामला क्रमबद्ध पूर्णांक के लिए है, लेकिन मुझे यकीन नहीं है कि यह जानकारी संपूर्ण डेटासेट पर वेक्टर निर्देश अधिनियम पर विचार करने के लिए मूल्यवान है)

कुछ ऑपरेशन आवश्यक हैं:

  1. डालें और शिफ्ट करें।

-> इसके क्रमबद्ध स्थान पर 25 डालें। -> इंडेक्स 2 पर 25 डालें और बाकी को शिफ्ट करें।

10, 20, 30, 40, 50, 60, 70, 80 बन जाता है: 10, 20, 25, 30, 40, 50, 60, 70

  1. निकालें और शिफ्ट करें और पीछे डालें।

-> सरणी से २० को हटा दें और यदि २० मिल जाए और हटा दिया जाए तो ९० को पीछे डालें। 10, 20, 30, 40, 50, 60, 70, 80 बन जाता है 10, 30, 40, 50, 60, 70, 80, 90

या निर्देशों का एक सेट इसे काम करेगा?

मैं एक अवरोही क्रमबद्ध सरणी के लिए कई चरणों के साथ सम्मिलित और शिफ्ट भाग का प्रयास कर रहा हूं। https://godbolt.org/z/_WCxkW

0
themagicalyang 8 जिंदा 2020, 10:28

1 उत्तर

सबसे बढ़िया उत्तर

आप जो चाहते हैं उसे करने का एक सामान्य तरीका है (सामान्य विचार [u]int_{8,16,32,64} या यहां तक ​​कि float/double के लिए समान है):

x को input में डालें:

// Shift your input array (e.g. "abcefghi") to the right:
out = ShiftRight(input); // out = 0abcefgh
// broadcast the to-be-inserted element (e.g., 'd')
insert = broadcast(x); // insert = dddddddd
// compute 
out = min(max(out,insert),input)
//  == min(max(0abcefgh,dddddddd),abcefghi)
//  == min(ddddefgh,abcefghi) == abcdefgh

input से x से छोटा न होने वाला पहला तत्व निकालें:

// shift input (e.g., "abcdefgh") to the left (insert something at the end)
out = ShiftLeft(input); // out = bcdefghX
// determine elements smaller than `x` (e.g., "f") by broadcast and compare
mask = broadcast(x) < input; // mask = 11111000
// take masked elements from `input` and other values from `out` (using a blend instruction)
out = blend(mask, input, out); // == abcdeghX

यदि हटाए जाने वाले तत्वों की संख्या 1 होने की गारंटी नहीं है (यानी, यह मौजूद नहीं हो सकता है या कई बार मौजूद हो सकता है), यह अधिक कठिन है, क्योंकि प्रत्येक आउटपुट मान संभावित रूप से प्रत्येक इनपुट मान पर निर्भर करता है। एक विचार समानता के लिए तुलना करना और तत्वों की संख्या की गणना करना हो सकता है (maskmove और popcount का उपयोग करके)।


स्थानांतरण के लिए आप उपयोग कर सकते हैं

  • SSE2 और केवल एक 128bit रजिस्टर: pslldq, psrldq
  • SSSE3 और 128 बिट रजिस्टरों का एक क्रम: palignr
  • AVX2 और एक 256bit रजिस्टर: vpermd पूर्व-निर्धारित इंडेक्स वेक्टर के साथ (पिछले निर्देशों के बराबर कोई AVX2 नहीं है जो पूरे 256bit रजिस्टर पर काम करता है)
  • यदि आपका इनपुट स्मृति में संग्रहीत है, तो इसे एक तत्व ऑफ़सेट के साथ फिर से लोड करें (इसके लिए सरणी के प्रत्येक छोर से परे "सुरक्षित" तत्व की आवश्यकता होती है - और यदि आप इन कार्यों को कई बार करते हैं तो यह एक महत्वपूर्ण लेखन-पढ़ने की विलंबता पेश कर सकता है)

प्रसारण के लिए, मैं केवल _mm[256]_set1_epi32 आंतरिक का उपयोग करने का सुझाव देता हूं और संकलक को यह पता लगाने देता हूं कि सबसे कुशल क्या है (AVX2 के बिना, इसके लिए फेरबदल की आवश्यकता होगी)

न्यूनतम/अधिकतम ऑपरेटर विभिन्न आकारों/प्रकारों (एसएसई/एवीएक्स संस्करण के आधार पर) के लिए मौजूद हैं - बस pmin/pmax से शुरू होने वाले निर्देशों की खोज करें।

जहां तक ​​​​मुझे पता है, AVX512 से पहले कोई अहस्ताक्षरित तुलना नहीं है, लेकिन निश्चित रूप से आप हस्ताक्षरित तुलना का उपयोग कर सकते हैं, यदि कोई मान सबसे बड़े हस्ताक्षरित मूल्य से बड़ा नहीं है। या आप तुलना करने से पहले ऊपरी बिट को फ़्लिप करके कामकाज कर सकते हैं (मुझे लगता है कि स्टैक ओवरफ्लो पर एक संबंधित प्रश्न है)।

अंत में, यदि आपके पास SSE4.1 है तो pblendvb द्वारा सम्मिश्रण किया जाता है। अन्यथा आपको कुछ बिटवाइज़-और/और नहीं/या संचालन करने की आवश्यकता है।

1
chtz 9 जिंदा 2020, 16:59