新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM處理器NEON編程及優(yōu)化技巧—左移右移等移位操作

ARM處理器NEON編程及優(yōu)化技巧—左移右移等移位操作

作者: 時間:2016-11-10 來源:網(wǎng)絡(luò) 收藏
ARM的NEON協(xié)處理器技術(shù)是一個64/128-bit的混合SIMD架構(gòu),用于加速包括視頻編碼解碼、音頻解碼編碼、3D圖像、語音和圖像等多媒體和信號處理應(yīng)用。本文主要介紹如何使用NEON的匯編程序來寫SIMD的代碼,包括如何開始NEON的開發(fā),如何高效的利用NEON。首先會關(guān)注內(nèi)存操作,即如何變更指令來靈活有效的加載和存儲數(shù)據(jù)。接下來是由于SIMD指令的應(yīng)用而導(dǎo)致剩下的若干個單元的處理,然后是用一個矩陣乘法的例子來說明用NEON來進行SIMD優(yōu)化,最后關(guān)注如何用NEON來優(yōu)化各種各樣的移位操作,左移或者右移以及雙向移位等。本節(jié)詳述NEON提供的各種各樣的移位操作,左右移位,移位插入以及移位限定符如飽和舍入等以及這些移位操作如何能有效的處理圖像中的色深。

移位向量

NEON中的移位指令和ARM指令中的標量移位,把向量中的各個元素左移或者右移若干比特。那些移到臨近元素的比特會被丟棄掉,不會影響到鄰近元素的移位結(jié)果。移位操作的移位數(shù)可以直接編碼到指令里,或者用 一個指定的移位比特向量,如果使用移位向量,每一個元素的移位比特值將取決于對應(yīng)的移位向量里存儲的值,移位向量里保存的移位值是有符號的,所以可能進行左移,右移或者不移位的操作。

本文引用地址:http://www.2s4d.com/article/201611/317423.htm

圖1. 帶移位向量的左移操作,可以左移、右移或者不移位

有符號數(shù)據(jù)的右移操作的類型可以根據(jù)指令來制定,如是否進行符號擴展(算術(shù)右移還是邏輯右移),這對應(yīng)于ARM指令里的移位操作。對于無符號的右移而言,就不用進行符號擴展了。

移位并右側(cè)插入

NEON還支持帶插入的移位,即進行兩個向量的比特位域的組合。比如VLSI指令左移并插入,會把向量進行左移,然后用 目標向量的右側(cè)數(shù)據(jù)來填充。如下圖所示:

arm.com/index.php?app=core&module=attach§ion=attach&attach_rel_module=blogentry&attach_id=511" rel="nofollow" >

圖2. 向量移位并填充結(jié)果向量

移位并累加

NEON支持把向量的各個元素右移然后累加結(jié)果到另外一個向量。這對于那些中間結(jié)果需要更高精度的情況非常適用,然后才把 結(jié)果保存到一個低精度的累加器里。

指令修改符

每個移位指令都能包含一個或者多個修改符,這些修改符不會改變移位操作本身,但是輸入和輸出結(jié)果會去除基準或者飽和到一個有效范圍,有5種移位限定符:

  • 舍入(round),使用R前綴,用于糾正右移截斷導(dǎo)致的基準;
  • 變窄(narrow),使用N前綴,表示向量中所有元素的位寬變窄為一半,即源是128-bit的Q寄存器,而結(jié)果是64-bit的D寄存器;
  • 變長(long),使用L前綴,表示向量中所有元素的位寬變寬為兩倍,即源是64-bit的D寄存器,而結(jié)果是128-bit的Q寄存器;
  • 飽和(saturate),使用Q前綴,把結(jié)果元素變成其能表示的最大和最小值范圍內(nèi),位寬比特數(shù)和符號類型來表明該元素的有效范圍;
  • 無符號的飽和(Unsigned Saturating),使用Q前綴,U后綴,類似于飽和限定符,但結(jié)果會飽和到無符號數(shù)據(jù)范圍,不管輸入是有符號還是無符號的;

這些限定符的有些組合起來不能描述有用的操作,因而NEON并不包含這些指令。比如類似VQSHR的飽和右移并不需要,因為右移會讓數(shù)據(jù)變小,不會超過有效范圍。

有效的移位操作表格

所有NEON支持的移位指令如下表所示,他們按照上面提到的限定符排列。

圖3. NEON支持的移位操作,用立即數(shù)表示的移位數(shù)和用寄存器表示的

色深轉(zhuǎn)換的例子

色深轉(zhuǎn)換是圖像處理中經(jīng)常用到的。通常輸入數(shù)據(jù)是RGB565 16-bit色度格式,需要轉(zhuǎn)換成RGB888格式才更適合于NEON這種并行處理。 然而NEON還是能處理RGB565的數(shù)據(jù)的,這就需要用到前面提到的移位指令了。

圖4. RGB888和RGB565的色度格式

從RGB565到RGB888

首先看如何從RGB565轉(zhuǎn)換成RGB888,假設(shè)輸入的8個16-bit的像素保存到寄存器Q0,我們想把分量分離成R通道,G通道和B通道,保存到d2到d4寄存器。

vshr.u8      q1, q0, #3     @ 把R通道右移3比特,丟棄G通道比特 

vshrn.i16    d2, q1, #5     @ 右移并變窄,取得R分量數(shù)據(jù)到d2寄存器 

vshrn.i16    d3, q0, #5     @ 右移并變窄取得G分量數(shù)據(jù) 

vshl.i8      d3, d3, #2     @ 左移G分量2個比特,丟棄R分量部分,同時把G分量保存到正確的位置; 

vshl.i16 q0, q0, #3     @ 把B分量左移到最重要的8-bit數(shù)據(jù) 

vmovn.i16    d4, q0         @ 丟地仍然有的R和G分量,保存B分量為8-bit 

這些指令的含義可以參考注釋處,基本上完成的操作就是去除臨近通道的不用的色度數(shù)據(jù),然后繼續(xù)移位把色度分量的值到最高位。

一個小問題

你可能注意到,這樣轉(zhuǎn)換成RGB888格式后,原來的白就不是完全的白色了,這是因為R和B分量是左移3bit,而G分量則只左移兩bit,因而如RGB565值(0x1F, 0x3F, 0x1F)變成RGB888 (0xF8, 0xFC, 0xF8),并不跟以前的表示顏色一致。

從RGB888到RGB565

從RGB888轉(zhuǎn)換成RGB565,假設(shè)RGB888的輸入是用上面代碼表示的形式,單獨通道的分量保存在從寄存器d0到d2,結(jié)果保存到16-bit的RGB565格式到q2寄存器。

vshll.u8 q2, d0, #8     @ 左移紅色分量到16bit結(jié)果中的最重要的5bit 

vshll.u8 q3, d1, #8     @ 左移綠色分量數(shù)據(jù)到16bit最重要的8比特 

vsri.16      q2, q3, #5    @ 移位綠色分量,并插入到紅色元素寄存器里。 

vshll.u8 q3, d2, #8     @ 左移紅色分量到16bit結(jié)果中的最重要的8-bit 

vsri.16      q2, q3, #11   @ 把藍色分量插入到紅色和綠色分量后面 

基本操作是把分量擴展成16-bit,然后右移插入指令把分量放到合適的位置;

總結(jié)

NEON提供了功能強大的移位指令,能完成:

  • 快速的把數(shù)據(jù)乘以或者除以2,并帶有舍入和飽和操作;
  • 移位并拷貝若干比特從一個 向量到另一個向量;
  • 中間計算結(jié)果在高精度,而把結(jié)果累加到低精度。


評論


技術(shù)專區(qū)

關(guān)閉