【arm】arm架構32位彙編優化總結

Date: 2018.8.18


一、參考:

https://blog.csdn.net/SoaringLee_fighting/article/details/80764811
https://blog.csdn.net/SoaringLee_fighting/article/details/81287824
https://blog.csdn.net/SoaringLee_fighting/article/details/81058147
https://blog.csdn.net/SoaringLee_fighting/article/details/80770034
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0018a/index.htmlcss

二、Arm彙編架構和Reference Manuals

ARM是RISC(精簡指令集)處理器,不一樣於x86指令集(CISC,複雜指令集)。
Arm32位是ARMV7架構,32位的,對應處理器爲Cortex-A15;
iphone5之前均是32位的;
須要注意:ARMV7-A和ARMV7-R系列支持neon指令集,ARMv7-M系列不支持neon指令集。html

ARMV7架構A和R系列參考手冊下載地址:
https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdfbash

Arm64位是ARMV8架構,64位的,對應處理器有Cortex-A5三、Cortex-A5七、iphone5s的A七、iphone6的A8等。
ARMV8架構參考手冊下載地址:
https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile
https://static.docs.arm.com/ddi0487/ca/DDI0487C_a_armv8_arm.pdf
全部ARM參考文檔地址:
https://developer.arm.com/docs
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0403e.b/index.html架構

中文手冊:
https://developer.arm.com/products/software-development-tools/compilers/arm-compiler-5/docs/dui0529/j/overview-of-arm-compiler/about-the-toolchain-documentationiphone

三、Arm32位寄存器

主要分爲ARM寄存器和NEON寄存器。
ARM32寄存器包括15個通用寄存器R0~R14和一個程序計數器PC,共16個,均爲32位寬。
ARM32位寄存器的調用規則:遵循ATPCS調用規則,詳細參見
https://blog.csdn.net/SoaringLee_fighting/article/details/81287824jsp

32位 NEON寄存器:
包括:32個S寄存器,S0~S31,(單字,32bit)
32個D寄存器,D0~D31,(雙字,64bit)
16個Q寄存器,Q0~Q15,(四字,128bit)
寄存器的對應關係以下圖所示:
這裏寫圖片描述優化

使用注意:
一、NEON寄存器將每一個寄存器均視爲一個向量,該向量又包含1,2,4,8或16個大小和類型均相同的元素。也能夠將各個元素當作標量訪問。
NEON的這三種寄存器是重疊的,物理地址是同樣的。
二、NEON寄存器在使用時,若是用到d8~d15寄存器,須要先入棧保存vpush {d8-d15},使用完以後要出棧vpop {d8-d15}ui

四、ARM指令尋址方式

ARM指令集的尋址方式與x86指令集大部分相同,但也有其特有的尋址方式,好比寄存器偏移尋址,多寄存器尋址和堆棧尋址。
ARM指令共有9種尋址方式,具體參見:
https://blog.csdn.net/SoaringLee_fighting/article/details/80770034spa

五、ARM指令特色以及優化技巧

ARM彙編特色1:LDR/STR架構
ARM採用RISC架構,CPU自己不能直接讀取內存,而須要先將內存中內容加載入CPU中通用寄存器中才能被CPU處理。
ldr(load register)指令將內存內容加載入通用寄存器。
str(store register)指令將寄存器內容存入內存空間中。
ldr/str組合用來實現 ARM CPU和內存數據交換。.net

ARM彙編特色2:指令後綴
同一指令常常附帶不一樣後綴,變成不一樣的指令。常用的後綴有:
B(byte)功能不變,操做長度變爲8位
H(half word)功能不變,長度變爲16位
S(signed)功能不變,操做數變爲有符號
如 ldr ldrb ldrh ldrsb ldrsh
S(S標誌)功能不變,影響CPSR標誌位
W(寬型)
L(長型)
N(窄型)
S(飽和)
Q(舍入取整)

ARM彙編特色3:條件執行
subgt,addle等,只有在上一條指令執行以後相應標誌位知足條件以後,當前指令纔會執行,經過使用條件執行指令能夠減小分支跳轉。

ARM彙編特色4:多級流水線技術
ARM7處理器(對應架構armv3或armv4)採用3級流水線的馮·諾伊曼結構;而ARM9(對應架構armv4或armv5)用5級流水線的哈佛結構,ARM11(對應架構armv6)爲8級流水線哈佛結構(從arm9開始都採用了哈佛結構)。增長的流水線設計提升了時鐘頻率和並行處理能力。5級流水線可以將每個指令處理分配到5個時鐘週期內,在每個時鐘週期內同時有5個指令在執行。在經常使用的芯片生產工藝下,ARM7通常運行在100MHz左右,而ARM9則至少在200MHz以上.ARM11首先推出350M~500MHz時鐘頻率的內核,目前上升到1GHz時鐘頻率。
參考:https://blog.csdn.net/SoaringLee_fighting/article/details/81411760

ARM NEON優化技巧總結,參見:
https://blog.csdn.net/SoaringLee_fighting/article/details/81265865
https://blog.csdn.net/SoaringLee_fighting/article/details/81705311

六、ARM和NEON指令集 經常使用指令彙總

ARM指令集:32位,工做在ARM模式下。
Thumb指令集:16位,工做在Thumb模式下。
NEON指令集:以v開頭,基於ARMv7架構的SIMD和向量浮點VFPv3指令集。
ARM算術指令:
add, adc, sub, subs, rsb, mul, udiv等

ARM移位指令:
lsl, lsr, ror,asr等

ARM飽和指令:
ssat, usat,qadd,qsub

ARM邏輯運算指令:
orr,and,orn,eor,

NEON邏輯運算和比較指令:
vand,vorr, vbic, vorn
vbif,bsl,vbit
vmov,vmvn
vceq,vcge,vcgt,vcle,vclt
vtst

NEON移位指令:
vshr,vshl,vqshl,vqrshrun
vsli,vsri

NEON通用算術指令:
vabs,vabd,vneg, vadd,vsub,vqadd,vqsub,vaddl,vaddw,vsubl,vsubw
vaddhn,vsubhn
vhadd,vhsub
vpadd,vpadal
vmax,vmin,vpmax,vpmin

NEON乘法指令:
vmul,vmla,vmls

vext指令:向量提取

vext.8      d2, d0, d1, #3

說明:取d1寄存器中低3位向量做爲高位,d0寄存器的高5位向量做爲低位,構成目標向量。

asr和lsr的區別:

asr  r0r1, #5 //算術右移,符號位填充左側空出的位
lsr   r0,    r1, #5 //邏輯右移,0填充左側空出的位

vpadd:向量按對加

vceq,vcgt,vcge, vcle,vclt指令:

向量比較,獲取向量中每一個元素的值,並將其與另外一個向量重相應元素或零進行比較。若是條件爲真,則將目標向量中的所有元素設置爲1,不然設置爲0。

vrshr指令:舍入右移 ,能夠實現(a+(1<<(b-1)))>>b的操做。

vaddl和vaddw指令:加法長指令、加法寬指令

vqmovun指令:有無符號操做數,無符號結果

vqmovun.s16     d0,  q0

說明: 將q0中每一個16位有符號向量飽和到d0中每一個8位無符號向量。

七、Arm32位加載數據的兩種格式

1)、vld1加載:

vld1.8 {d0,d1} , [r1], r2

說明: 將r1地址裏面的連續的128bits數據依次賦給d0和d1,而後r1+r2。這裏的.8表示以8bit爲單位。
2)、

vld1.16 {d0[],d1[]}, [r0:16]

說明:這裏d0和d1中的數據相同,將地址r0中取4個16位數據加載到d0和d1中。

八、Arm32位彙編編寫demo

https://blog.csdn.net/SoaringLee_fighting/article/details/81150083
ARM彙編格式主要有兩種,arm asm彙編格式和gnu asm彙編格式。
gnu asm彙編格式:

.arm
    .text
    .align  4
    .global     name
    .type       %function
name:

     FUNCTION STATEMENT  @註釋行
     /* 多行註釋 */
     //單行註釋,用於.S彙編文件
     bx lr

arm asm彙編格式:

EXPORT |name|
ARM
AREA ||.text||, CODE, READONLY,ALIGN=2
|name| PROC  ;註釋

ENDP
END
九、注意事項

1)標籤名稱不能以數字開始,可是可使用純數字的局部標籤。
2)ld1連續存儲數據時,所用的寄存器必須是連續的。
3)Arm32位下數據在不一樣寄存器之間轉換:
從r寄存器到d寄存器:

vmov        d0, r0, r1
vmov.u32    d0[0], r1

從d寄存器到r寄存器:

vmov        r0, r1, d0
vmov.u32    r1, d0[0]

從標量寄存器d[x]到矢量寄存器d:

vdup.16     d1,  d6[0]
vdup.16     d1, r12

4)Arm32位下替代判斷的命令:
vceq,vbsl,vbit, vbif

5)Arm32下取數據地址問題
arm下默認地址r0加1,是加一個字節,若是r0對應的數據是int類型的,則取idx位置的數據則爲:r0+idx*4

十、彙編優化基本準則
  1. C代碼優化
    ** 減小計算量,將重複計算的部分提取出來;
    ** 深刻剖析C代碼的實現原理,更改結構,把能夠合併的代碼進行合併,簡化計算,減小分支判斷。
  2. 彙編代碼優化
    ** 精簡指令,大部分arm指令都是單週期指令,儘可能使用較少的指令編寫代碼;
    ** 減小寄存器之間的依賴,充分利用多級流水線,使指令並行執行;
    ** 對於乘法指令,指令週期比較長,儘可能不要當即使用指令計算結果,不然會等待耗時;
    ** 儘可能將數據都存放在neon寄存器中;
    ** 儘可能減小存取數據的次數。
十一、ARM程序調試

下面是最基本的方法:

彙編文件中添加以下宏代碼:

.macro print_m in1=r0, in2=d0
       push {r0-r3, lr}
       vstl.u64       {\in2\()}, [\in1\()]
       mov     r0, \in1
       bl cprintf
       pop {r0-r3, pc}
.endm

C文件中添加cprintf實現代碼:

void cprintf(unsigned char *srcu8)
{
  int i=0;
  char *srcs8 = (char *)srcu8;
  for(i=0; i < 16; i++){
       printf("%d ", srcu8[i])
  }
  for(i=0; i < 16; i++){
      printf("%d ", srcs8[i])
  }
  printf("\n");
}

關於arm寄存器的打印調試方法,參見:
https://blog.csdn.net/SoaringLee_fighting/article/details/80834098

除了上述基本方法之外,能夠藉助RVDS或GDB軟件進行調試。

注意事項:
一、RVDS只能用於ARM32位調試,ARMV8架構不支持RVDS。
二、採用GDB調試的前提是ARM開發板上已經安裝好了GDB,採用GDB進行調試是很方便的。


THE END!

相關文章
相關標籤/搜索