SIMD指令簡(jiǎn)介
單指令多數(shù)據(jù)流,即SIMD(Single Instruction举哟, Multiple Data)指一類(lèi)能夠在單個(gè)指令周期內(nèi)同時(shí)處理多個(gè)數(shù)據(jù)元素的指令集,利用的是數(shù)據(jù)級(jí)并行來(lái)提高運(yùn)行效率。
不同處理器架構(gòu)所支持的SIMD指令集各不相同敞临,比如嵌入式處理器ARM Cortex-A系列中支持NEON指令集。而我們常用的ARM Cortex-M系列單片機(jī)則使用了ARMv6-M/ARMv7-M架構(gòu)麸澜,指令集較為簡(jiǎn)化挺尿,不支持NEON。其中Cortex-M4和Cortex-M7所使用的指令集也被稱(chēng)為ARMv7E-M炊邦,支持部分SIMD指令编矾。對(duì)于Cortex-A系列來(lái)說(shuō),其指令集向下包含馁害,即許多Cortex-M中的SIMD指令窄俏,也能夠在Cortex-A中使用。
SIMD指令集的最初設(shè)計(jì)目標(biāo)就是為了提高多媒體應(yīng)用的性能(圖像相關(guān)運(yùn)算)碘菜,因?yàn)閳D像數(shù)據(jù)的像素點(diǎn)都是8位數(shù)據(jù)凹蜈,而CPU寄存器通常是32位以上的,因此一條指令只用于計(jì)算一個(gè)像素點(diǎn)不免顯得非常浪費(fèi)忍啸。在32位處理器上仰坦,可以用SIMD指令一次性計(jì)算4個(gè)8位數(shù)據(jù),極大地提升了運(yùn)算效率计雌。
直接使用C語(yǔ)言編寫(xiě)的程序悄晃,編譯器是不會(huì)自動(dòng)翻譯成SIMD指令的。因此為了在嵌入式處理器如單片機(jī)上提升圖像數(shù)據(jù)運(yùn)算速度凿滤,需要專(zhuān)門(mén)使用SIMD指令進(jìn)行優(yōu)化传泊。得益于SIMD指令加速,我們能夠在STM32F4上實(shí)現(xiàn)簡(jiǎn)單的光流算法鸭巴,有興趣的可以看一下PX4Flow的算法部分眷细。為了能夠在優(yōu)化圖像算法,使其能以較快速度運(yùn)行于嵌入式平臺(tái)鹃祖,熟悉掌握SIMD指令是非常有必要的溪椎,下面列出一些可以在Cortex-M4和Cortex-M7上使用的SIMD指令(不全面,忽略了部分16位操作數(shù)指令),Cortex-A系列處理器基本上都兼容這些指令校读,當(dāng)然在那上面還有強(qiáng)大的NEON指令集可以使用沼侣。
在STM32的庫(kù)文件core_cm4_simd.h中可以看到所有SIMD指令的宏定義
部分SIMD指令說(shuō)明
飽和加法: a+b=c,當(dāng)計(jì)算結(jié)果大于c可表示的最大值或者小于c可表示的最小值時(shí)歉秫,計(jì)算結(jié)果取值為這個(gè)最大值或最小值蛾洛。
非飽和加法: a+b=c,如果計(jì)算結(jié)果一出雁芙,則直接去掉一出位轧膘,剩下的就是結(jié)果。
-
__USAD8
指令說(shuō)明:無(wú)符號(hào)值的差的絕對(duì)值求和
指令定義:uint32_t __USAD8 (uint32_t val1, uint32_t val2)
指令操作:
absdiff1 = val1[7:0] - val2[7:0]
absdiff2 = val1[15:8] - val2[15:8]
absdiff3 = val1[23:16] - val2[23:16]
absdiff4 = val1[31:24] - val2[31:24]
res[31:0] = absdiff1 + absdiff2 + absdiff3 + absdiff4
-
__USADA8
指令說(shuō)明:無(wú)符號(hào)值的差的絕對(duì)值求和累加
指令定義:uint32_t __USADA8 (uint32_t val1, uint32_t val2, uint32_t val3)
指令操作:
absdiff1 = val1[7:0] - val2[7:0]
absdiff2 = val1[15:8] - val2[15:8]
absdiff3 = val1[23:16] - val2[23:16]
absdiff4 = val1[31:24] - val2[31:24]
sum = absdiff1 + absdiff2 + absdiff3 + absdiff4
res[31:0] = sum[31:0] + val3[31:0]
并行加法
-
__SADD8
指令說(shuō)明:有符號(hào)8位操作數(shù)的并行加法
指令定義:uint32_t __SADD8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] + val2[7:0]
res[15:8] = val1[15:8] + val2[15:8]
res[23:16] = val1[23:16] + val2[23:16]
res[31:24] = val1[31:24] + val2[31:24]
-
__QADD8
指令說(shuō)明:有符號(hào)8位操作數(shù)的并行飽和加法
指令定義:uint32_t __QADD8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] + val2[7:0]
res[15:8] = val1[15:8] + val2[15:8]
res[23:16] = val1[23:16] + val2[23:16]
res[31:24] = val1[31:24] + val2[31:24]
-
__SHADD8
指令說(shuō)明:有符號(hào)8位操作數(shù)的并行減半加法
指令定義:uint32_t __SHADD8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] + val2[7:0] >> 1
res[15:8] = val1[15:8] + val2[15:8] >> 1
res[23:16] = val1[23:16] + val2[23:16] >> 1
res[31:24] = val1[31:24] + val2[31:24] >> 1
-
__UADD8
指令說(shuō)明:無(wú)符號(hào)8位操作數(shù)的并行加法
指令定義:uint32_t __UADD8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] + val2[7:0]
res[15:8] = val1[15:8] + val2[15:8]
res[23:16] = val1[23:16] + val2[23:16]
res[31:24] = val1[31:24] + val2[31:24]
-
__UQADD8
指令說(shuō)明:無(wú)符號(hào)8位操作數(shù)的并行飽和加法
指令定義:uint32_t __UQADD8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] + val2[7:0]
res[15:8] = val1[15:8] + val2[15:8]
res[23:16] = val1[23:16] + val2[23:16]
res[31:24] = val1[31:24] + val2[31:24]
-
__UHADD8
指令說(shuō)明:無(wú)符號(hào)8位操作數(shù)的并行減半加法
指令定義:uint32_t __UHADD8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] + val2[7:0] >> 1
res[15:8] = val1[15:8] + val2[15:8] >> 1
res[23:16] = val1[23:16] + val2[23:16] >> 1
res[31:24] = val1[31:24] + val2[31:24] >> 1
并行減法
-
__SSUB8
指令說(shuō)明:有符號(hào)8位操作數(shù)的并行減法
指令定義:uint32_t __SSUB8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] - val2[7:0]
res[15:8] = val1[15:8] - val2[15:8]
res[23:16] = val1[23:16] - val2[23:16]
res[31:24] = val1[31:24] - val2[31:24]
-
__QSUB8
指令說(shuō)明:有符號(hào)8位操作數(shù)的并行飽和減法
指令定義:uint32_t __QSUB8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] - val2[7:0]
res[15:8] = val1[15:8] - val2[15:8]
res[23:16] = val1[23:16] - val2[23:16]
res[31:24] = val1[31:24] - val2[31:24]
-
__SHSUB8
指令說(shuō)明:有符號(hào)8位操作數(shù)的并行減半減法
指令定義:uint32_t __SHSUB8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] - val2[7:0] >> 1
res[15:8] = val1[15:8] - val2[15:8] >> 1
res[23:16] = val1[23:16] - val2[23:16] >> 1
res[31:24] = val1[31:24] - val2[31:24] >> 1
-
__USUB8
指令說(shuō)明:無(wú)符號(hào)8位操作數(shù)的并行減法
指令定義:uint32_t __USUB8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] - val2[7:0]
res[15:8] = val1[15:8] - val2[15:8]
res[23:16] = val1[23:16] - val2[23:16]
res[31:24] = val1[31:24] - val2[31:24]
-
__UQSUB8
指令說(shuō)明:無(wú)符號(hào)8位操作數(shù)的并行飽和減法
指令定義:uint32_t __UQSUB8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] - val2[7:0]
res[15:8] = val1[15:8] - val2[15:8]
res[23:16] = val1[23:16] - val2[23:16]
res[31:24] = val1[31:24] - val2[31:24]
-
__UHSUB8
指令說(shuō)明:無(wú)符號(hào)8位操作數(shù)的并行減半減法
指令定義:uint32_t __UHSUB8 (uint32_t val1, uint32_t val2 )
指令操作:
res[7:0] = val1[7:0] - val2[7:0] >> 1
res[15:8] = val1[15:8] - val2[15:8] >> 1
res[23:16] = val1[23:16] - val2[23:16] >> 1
res[31:24] = val1[31:24] - val2[31:24] >> 1