目录
前言
最近在移植QNNPACK神经网络加速库,涉及到对卷积arm汇编的修改,这边做个记录,对汇编部分的内容进行注释,顺便学习一下汇编的语法。
基础直通车
首先要补充arm汇编基础知识,特别是如何传参一定要搞清楚,另外对arm寄存器要了然于胸,剩下的就是指令的用法了:
利用堆栈入参参考:https://www.cnblogs.com/qq78292959/p/4013356.html
arm 32位NEON寄存器:https://blog.youkuaiyun.com/SoaringLee_fighting/article/details/81743505
ARM汇编器对ARM的寄存器预定义:https://blog.youkuaiyun.com/SoaringLee_fighting/article/details/81287824
ARM汇编指令:https://blog.youkuaiyun.com/zhangmiaoping23/article/details/8875193
arm基础知识
R0-R15和r0-r15
a1-a4(参数,结果或者临时寄存器,与r0-r3同意)
v1-v8(变量寄存器,与r4-r11同意)
sb和SB(静态基址寄存器,与r9同意)
sl和SL(堆栈限制寄存器,与r10同意)
fp和FP(帧指针,与r11同意)
ip和IP(过程调用中间临时寄存器,与r12同意)
sp和SP(堆栈指针,与r13同意)
lr和LR(连接寄存器,与r14同意)
pc和PC(程序计数器,与r15同意)
cpsr和CPSR(程序状态寄存器)
spsr和SPSR(程序状态寄存器)
f0-f7和F0-F7(FPA寄存器)
s0-s31和S0-S31(VFP单精度寄存器)
d0-d15和D0-D15(VFP双精度寄存器)
p0-p15(协处理器0-15)
c0-c15(协处理器寄存器0-15)
使用说明:
1、当参数少于4个时,子程序间通过寄存器R0~R3来传递参数;当参数个数多于4个时,将多余的参数通过数据栈进行传递,入栈顺序与参数顺序正好相反,子程序返回前无需恢复R0~R3的值;
2、在子程序中,使用R4~R11保存局部变量,若使用需要入栈保存,子程序返回前需要恢复这些寄存器;R12是临时寄存器,使用不需要保存。
3、R13用作数据帧指针,记作SP;R14用作链接寄存器,记作LR,用于保存子程序返回时的地址;R15是程序计数器,记作PC。
4、ATPCS规定堆栈是满递减堆栈FD;
5、子程序返回32位的整数,使用R0返回;返回64位整数时,使用R0返回低位,R1返回高位。
Arm32位寄存器主要分为ARM寄存器和NEON寄存器。
ARM32寄存器包括15个通用寄存器R0~R14和一个程序计数器PC,共16个,均为32位宽。
ARM32位寄存器的调用规则:遵循ATPCS调用规则
32位 NEON寄存器:
包括:32个S寄存器,S0~S31,(单字,32bit)
32个D寄存器,D0~D31,(双字,64bit)
16个Q寄存器,Q0~Q15,(四字,128bit)
寄存器的对应关系如下图所示:
使用说明:
1、NEON寄存器将每个寄存器均视为一个向量,该向量又包含1,2,4,8或16个大小和类型均相同的元素。也可以将各个元素当做标量访问。
NEON的这三种寄存器是重叠的,物理地址是一样的。
2、NEON寄存器在使用时,如果用到d8~d15寄存器,需要先入栈保存vpush {d8-d15},使用完之后要出栈vpop {d8-d15}
arm指令释义
条件分支:
CMP:算数处理指令,用于把一个寄存器的内容和另一个寄存器的内容或立即数进行减法比较,不存储结果,都会更改标志位
BNE: 数据跳转指令,标志寄存器中Z标志位不等于零时, 跳转到BNE后标签处
BNE 3f 0b f:forward,b:backward
BEQ: 数据跳转指令,标志寄存器中Z标志位等于零时, 跳转到BEQ后标签处
BLO指令 小于(无符号数)跳转
BLT:小于跳转;
TEQ:用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的异或运算,并根据运算结果更新CPSR中条件标志位的值。该指令通常用于比较操作数1和操作数2是否相等。(EOR指令也是实现异或运算,只是不更新CPSR)
LSL:逻辑左移,LSR:逻辑右移
助记符 |
含 义 |
EQ |
相等equal |
NE |
不相等not equal |
CS |
无符号数大于或等于Carry Set |
CC |
无符号数小于 |
MI |
负数minus |
PL |
正数或零plus |
VS |
溢出 |
VC |
没有溢出 |
HI |
无符号数大于high |
LS |
无符号数小于或等于less |
GE |
带符号数大于或等于 |
LT |
带符号数小于less than |
GT |
带符号数大于great than |
LE |
带符号数小于或等于 |
AL |
无条件执行all |
数据加载及存储:
ldr ip,[sp],#4 将sp中内容存入ip,之后sp=sp+4;
ldr ip,[sp,#4] 将sp+4这个新地址下内容存入ip,之后sp值保持不变
ldr ip,[sp,#4]!将sp+4这个新地址下内容存入ip,之后sp=sp+4将新地址值赋给sp
str ip,[sp],#4 将ip存入sp地址处,之后sp=sp+4;
str ip,[sp,#4] 将ip存入sp+4这个新地址,之后sp值保持不变
str ip,[sp,#4]!将ip存入sp+4这个新地址,之后sp=sp+4将新地址值赋给sp
qnn汇编代码解析
先对BEGIN_FUNCTION定义说明
#ifdef __ELF__ //linux系统编译宏
.macro BEGIN_FUNCTION name
.text
.align 2
.global \name
.type&nb