事實證明,這並不簡單。
幼稚的高效方法首先得到索引(只需加載一個帶有位掩碼的0 1 2 3 4 5 6 7
和vand
的靜態向量)。但是,爲了在輸出矢量的一端收集它們 - 在它們表示的輸入通道的不同通道中 - 然後您需要一些任意的置換操作。只有一條指令可以任意排列矢量,vtbl
(或vtbx
,這本質上是相同的東西)。但是,vtbl
會以目標順序採用一個源索引向量,這與您嘗試生成的內容完全相同。因此,爲了產生您的最終結果,您需要使用您的最終結果,因此,天真的有效解決方案是不可能的; QED。
最根本的問題是,你實際上在做什麼是排序一個向量,它本質上不是一個並行的SIMD操作。 NEON是爲媒體處理而設計的並行SIMD指令集,對於更一般的矢量處理的任何數據相關/水平/分散 - 聚集操作而言,並不是絕對的。
爲了證明這一點,我確實設法在純NEON中做到這一點,根本沒有任何標量代碼,它是可怕的;最好的「一個或兩個移位NEON指令」我能想出的是一些基於條件選擇的旋轉位掩碼累加技巧。如果它是不明確的,我建議在調試器或仿真步進通過遵循它做什麼(example):
// d0 contains input vector
vmov.u8 d1, #0
vmov.u8 d2, #0
vmvn.u8 d3, #0
vdup.u8 d4, d0[0]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
vsub.u8 d1, d1, d3
vdup.u8 d4, d0[1]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
vsub.u8 d1, d1, d3
vdup.u8 d4, d0[2]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
vsub.u8 d1, d1, d3
vdup.u8 d4, d0[3]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
vsub.u8 d1, d1, d3
vdup.u8 d4, d0[4]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
vsub.u8 d1, d1, d3
vdup.u8 d4, d0[5]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
vsub.u8 d1, d1, d3
vdup.u8 d4, d0[6]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
vsub.u8 d1, d1, d3
vdup.u8 d4, d0[7]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
vbic.u8 d1, d1, d3
// d1 contains output vector
作弊和使用循環(這需要以相反的方向旋轉d0
這樣我們就可以通過d0[0]
訪問每個原車道),使得它更小,但不是真的任何少可怕:
vmov.u8 d1, #0
vmov.u8 d2, #0
vmvn.u8 d3, #0
mov r0, #8
1:
vdup.u8 d4, d0[0]
vext.u8 d5, d2, d3, #7
vbit.u8 d3, d5, d4
subs r0, r0, #1
vext.u8 d0, d0, d0, #1
vsub.u8 d1, d1, d3
bne 1b
vbic.u8 d1, d1, d3
理想的情況下,如果它是在所有可能的返工算法的其他部分,以避免需要載體的非恆定的排列,做相反。
這個問題讓我想起[根據比較結果左包裝]的(http://stackoverflow.com/questions/36932240/avx2-what-is-the-most-efficient-way-to-pack-left繫上-A-掩模)。如果有任何現有技術根據比較結果生成左包裝式混洗掩模,則全部設置好。我在該Q上的AVX2 + BMI2答案使用x86的pext位域提取指令和一個整數位掩碼(來自MOVMSKPS:來自每個向量元素的一位,通常用於比較結果)。 –
如果沒有PEXT(我認爲ARM沒有等價物),還有其他SIMD可能可用的左包裝方法。哦,但仔細閱讀,我認爲這些幻燈片只是從LUT中加載洗牌蒙版。每個64位通道有8個字節,每個64位輸入有256個入口查找表(假設ARM可以有效地進行向量比較/測試,並將比較結果轉換爲位掩碼以用作整數數組索引) –
@ PeterCordes - _「如果有任何現有的技術可以根據比較結果生成一個左包裝式混洗面具,那麼你們都是這樣設置的 - 」呃,這正是我們要在這裏實現的目標;)這就是爲什麼鞋底可用的任意混排指令不能幫助,因爲它只是使問題遞歸。 – Notlikethat