【arm】arm架構64位(AArch64)匯編優化總結


Date: 2018.9.13


1、參考

https://blog.csdn.net/SoaringLee_fighting/article/details/81906495
https://blog.csdn.net/SoaringLee_fighting/article/details/82155608
https://blog.csdn.net/u011514906/article/details/38142177
https://blog.csdn.net/listener51/article/details/82530464

2、前言

     本文是arm架構64位(AArch64執行狀態) neon優化的總結文檔,主要包括arm架構64位優化的基礎知識,特殊用法,打印調試和常用指令使用注意事項以及資料來源等相關知識。前文已有arm架構32位匯編優化總結對arm架構32位neon優化進行了全面總結,並且講述了arm匯編語法,下面主要以gnu asm匯編語法為例講述。
  下圖為arm架構匯編優化總結的思維導圖:
  這里寫圖片描述

3、arm架構64位優化基礎知識

【arm】arm架構64位入門基礎:架構分析、寄存器、調用規則、指令集以及參考手冊
  該博客已經分析了arm架構64位匯編優化的入門基礎知識,主要包括架構分析,寄存器,調用規則,指令集和程序打印調試相關知識,可以作為入門arm64位匯編優化的基礎知識。

4、ARMv8/AArch64 neon指令格式

In the AArch64 execution state, the syntax of NEON instruction has changed. It can be described as follows:

  {<prefix>}<op>{<suffix>}  Vd.<T>, Vn.<T>, Vm.<T>  

Where:
< prefix> - prefix, such as using S/U/F/P to represent signed/unsigned/float/bool data type.
< op> – operation, such as ADD, AND etc.
< suffix> - suffix
P: “pairwise” operations, such as ADDP,LDP,STP.
V: the new reduction (across-all-lanes) operations, such as ADDV,SMAXV,FMAXV.
2:new widening/narrowing “second part” instructions, such as ADDHN2, SADDL2,SMULL2.
< T> - data type, 8B/16B/4H/8H/2S/4S/2D. B represents byte (8-bit). H represents half-word (16-bit). S represents word (32-bit). D represents a double-word (64-bit).

For example:
UADDLP    V0.8H, V0.16B
FADD V0.4S, V0.4S, V0.4S

參考自:
https://community.arm.com/android-community/b/android/posts/arm-neon-programming-quick-reference

5、ARM相關編譯參數

嵌入式設備(即arm架構的板子)在編譯時,最好加上 -fsigned-char 因為嵌入式設備默認類型為unsigned char類型,非char 類型。此外在編譯arm匯編優化代碼時,編譯選項需要加上-c 。-c都表示編譯或匯編源文件,但是不進行鏈接。
  ARM相關或者硬件相關編譯參數一般以-m開頭,常用ARM平台編譯選項包括:

-mcpu = cortex-a7
-mabi = atpcs
-march = armv7
-mtune = cortex-a53
-mfpu = neon, neon-vfpv4
-mfloat-api = soft, softfp, hard

更多詳細內容可以參考:https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc.pdf 3.17.1小節AArch64 option和3.17.4小節 ARM options.

6、查看狀態標記位NZCV的方法
mrs  x15, nzcv
mov  w0,  w15
bl	print

7、A64指令集特有的指令及其用法

  1. shl和ushr指令

	shl  <V>.<d>, <V>.<n>, #<shift>
	ushr  <V>.<d>, <V>.<n>, #<shift>
	ushr  d2, d2,  #8

使用注意事項:這兩條指令只能操作64位數據,即只能對D寄存器進行處理。
ushr最多只能進行64位數據的右移,並且右移時會影響V2寄存器的高64位數據(清零),因此高64位數據需要在右移前保存,否則相關數據會被修改。

  2. INS指令
用法與MOV指令基本一樣,可以實現neon標量與neon標量之間的傳送,以及ARM寄存器與neon標量之間的傳送。

INS   <Vd>.<Ts>[index1], <Vn>.<Ts>[index2]
INS   <Vd>.<Ts>[index1], Rn

  3. SUQADD、USQADD指令
既有標量用法,也有矢量用法。

SUQADD <V><d>, <V><d>     // signed saturating accumulate of unsigned value
SUQADD <Vd>.<T>, <Vn>.<T>

USQADD <V><d>, <V><d>    // unsigned saturating accumulate of signed value
USQADD <Vd>.<T>, <Vn>.<T>

  4. RBIT、REV指令

 RBIT <Wd>, <Wn> //reverse bits
 REV <Wd>, <Wn>  //reverse bytes

 5. ADDV,SADDLV,SMAXV,SMINV (Vector Reduce(across lanes))

ADDV <V><d>, <Vn><T>    // Integer sum element to scalar(vector)
SADDLV <V><d>, <Vn><T>  // Signed Interger sum elements to long scalar(vector)
SMAXV <V><d>, <Vn><T>   // Signed Interger maximum elements to scalar(vector)
SMINV <V><d>, <Vn><T>   // Signed Interger minimum elements to scalar(vector)

eg.:
addv B0, v1.8B			// 將v1寄存器中的低64位中8個8位數據相加求和后,賦給v0的最低8位。

更多詳細解釋可以參考:https://static.docs.arm.com/ddi0487/a/DDI0487A_j_armv8_arm.pdf
這里寫圖片描述
 6. sxtw使用注意事項
負數在使用時必須進行符號擴展!
比如:

sxtw   x4, w4

  7. w寄存器到v寄存器
直接使用dup指令

dup		v0.8B,  w2

  8.常用指令對應關系(arm32---->arm64)

 vmovl------>uxtl/sxtl
 vqmovn----->sqxtn
 vqmovun----->sqxtun
 vqrshrun---->sqrshrun
 vceq------->cmeq
 vcge------->cmge
 vadd------>add
 vsub------>sub
 vaddl----->saddl,uaddl 
 vaddw----->saddw,uaddw,sw2addw2,uadd
 vmull----->smull,smull2,umull,umull2
 vmax,vmin----->smax,umax,smin,umin
 vmlal--------> smlal,smlal2,umlal,umlal2
 vrshl--------> urshl,srshl
 vtrn---------> trn1,trn2
 vstm/vstr----> stp/str
 vld1.32 {d0[]}, [r0], r2-----> ld1r {v0.S}[0], [x0], x2
 addgt,addle,subgt,suble----->csel,csetm,cset,csinc,csinv

更多可參考:
https://www.element14.com/community/servlet/JiveServlet/previewBody/41836-102-1-229511/ARM.Reference_Manual.pdf

8、資料文檔查閱

    在進行arm64位匯編語言編寫之前,建議首先閱讀學習arm官方英文手冊(https://static.docs.arm.com/ddi0487/ca/DDI0487C_a_armv8_arm.pdf) ,重點閱讀C7 AArch64 neon指令部分以及C3 ARM指令部分,在了解了基本指令和arm64位匯編格式之后就可以嘗試編寫了。
    對於已有arm32位代碼的情況下,從arm32位代碼遷移到arm64時,可以參考(https://www.element14.com/community/servlet/JiveServlet/previewBody/41836-102-1-229511/ARM.Reference_Manual.pdf) 中 5.7.23小節的指令對照表。

    對於代碼遷移方法,可以參考我的博客:Some ways of Migrating code from ARM32 to AArch64

    對於快速查找指令,可以參考指令速查卡:
https://courses.cs.washington.edu/courses/cse469/18wi/Materials/arm64.pdf

9、優化經驗總結(滿滿的干貨)
  1. 關於參數入棧和寄存器入棧
    建議將入棧的參數取出之后,再對ARM寄存器或者NEON寄存器進行入棧。
  2. 盡量去除數據依賴 ,使指令並行
    不要將當前指令的目的寄存器作為下一條指令的源寄存器,尤其對於vmul指令,vmla指令。 不要將當前指令的目的寄存器作為下一條指令的源寄存器,尤其對於vmul指令,vmla指令。
  3. 盡量減少分支跳轉
    可以采用條件執行指令或邏輯運算指令替代分支跳轉,比如addgt,suble,vceq,vcge,vbit,vbsl等。
  4. 關注指令周期延遲
    對於乘法指令,指令周期比較長,盡量不要立即使用指令計算結果,否則會等待耗時。
  5. 數據運算盡量在neon寄存器中,避免在arm寄存器和neon寄存器之間的運算。
  6. 盡量減少存取數據的次數。
  7. 盡量使用不需要保存的寄存器,寄存器出入棧很耗時。
  8. 對於寬度為4的倍數的情況下,盡量在寬度方向上處理,這樣可以提高cache命中率。
  9. 使用盡量少的指令來編寫代碼,因為arm指令是精簡指令,大部分指令都是單周期指令。
  10. 如果寄存器夠用的話,盡量將一行的數據處理拆成兩行或是四行來並行處理;盡量避免大數據之間的運算,可以將大數據的運算拆成小數據的運算。
  11. 減少循環判斷和條件比較
    在數據處理過程中,在循環判斷或條件判斷較多時,可以適當展開分支,可以在一定程度上提升性能。

THE END!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM