Armv8寄存器简介
在介绍操作指令之前,我们先来简单了解一下Armv8架构下的寄存器命名和数据特征。
在Armv8架构中,主要分为64位寄存器和128位寄存器两大类。对于64位寄存器,主要用Xn和Wn分别表征使用该寄存器的64位或低32位,如图1所示。
对于128位寄存器,可以将其作为标量寄存器,分别使用Qn\Dn\Sn\Hn\Bn来表征使用该寄存器的128或低64位\32位\16位\8位,如图2所示。也可以将其作为向量化寄存器,分别用Vn.2D\Vn.4S\ Vn.8H\ Vn.16B来表示将128位寄存器分成对应个数的64位\32位\16位\8位通道宽度来使用,如图3所示。
根据上述命名规则,有时可以通过对同一寄存器差异化的表示,使用相同的指令达到处理不同长度数据的功能,在数据截取比较中运用特别明显,例如下面代码中,实际各加载了8个字节分别到寄存器x1和x2中,但逻辑只需要我们比较低32位数据,此时直接用w形式表征这两个寄存器即可,不需要重新加载32位数据到另一个寄存器中。
... ... ldr x3, [x0] ldr x4, [x1] cmp w3, w4 /* compare */ ... ...
值得说明的是,能够数据复用的前提是该指令对这种形式表征的寄存器生效。Q寄存器(128位标量寄存器)和V寄存器(128位向量寄存器)在物理上是同一套寄存器,但是在指令上基本是两套规范。也就是说数据是存放在同一个128位寄存器中,但是标量汇编指令只适用于标量形式表征的128位寄存器,向量汇编指令(又称neon指令)只适用于向量形式表征的128位寄存器,不能混用,否则编译器就会报错。
寄存器的define使用
另外,当我们自己编写一份较大的汇编代码时,如果通篇用数字去识别寄存器,很容易对寄存器的值进行混淆,对其他开发者的易读性也不高。所以一个好的习惯是,在代码文件的头部通过define对寄存器功能进行定义,例如上述的几条指令,我们可以将其表示成如下形式:
#define data1 x3 #define data2 x4 #define Lowdata1 w3 #define Lowdata2 w4 #define src1 x0 #define src2 x1 ... ... ldr data1, [src1] ldr data2, [src2] /* compare */ cmp Lowdata1, Lowdata2 ... ...