MacOS Arm64 汇编 part 5 - MacOS Arm64 Assembly part 5
- Multiply, Divide, and Accumulate
- Floating-Point Operations
- Neon Coprocessor
Multiplication
1 | MUL Xd, Xn, Xm |
其中 Xd = Xn * Xm
Xd是乘法结果的 lower 64 bits 对应于X版本,而W版本则为保留 lower 32 bits
mul无后缀s版本,无法检测溢出
- 所有操作数均为寄存器,无立即数
- 不存在独立的有无符号版本的乘法,乘法无补码
为了克服这些限制,因此有下面四个版本
1 | SMULH Xd, Xn, Xm |
SMULL与UMULL允许我们计算两个 32 bits 数的 64 bits 乘积
SMULL与SMULH用于带符号数
UMULL与UMULH用于无符号数
SMULH 和 UMULH 给我们 higher 64 bits
的乘法结果,SMULH 与 MUL 连用即可获得完整的
128 bits 的带符号数乘法结果,而 UMULH 与 MUL
连用即可获得完整的 128 bits 的无符号数乘法结果
下面几个指令计算乘法的相反数
1 | MNEG Xd, Xn, Xm |
Division
整数除法
1 | SDIV Xd, Xn, Xm |
Xd = Xn / Xm,其中Xn是被除数,Xm是除数
- 所有寄存器可以都可以是
X或W型
- 无
s后缀版本
- 不能除
,这些指令均会返回 ,这是容易误导的
- 无法简单计算 128 bits 除法
- 这一指令只返回商,无余数
Multiply and Accumulate
对于点积或矩阵乘法,往往需要做先乘后累加的运算
Accumulate Instructions
1 | MADD Xd, Xn, Xm, Xa |
这些是带累积的乘法指令,事实上大多数乘法指令都是这些指令的别名,通过给
Xa 零寄存器
Xd = Xa + Xn * Xm或Xd = Xa - Xn * Xm对应 ADD 和 SUB
Floating-Point Operations
Defining Floating-Point Numbers
使用 .single 或 .double
定义单精度或双精度浮点数
对于 16 bits 的半精度浮点数,无法直接定义,需要转换
About FPU Registers
ARM 的 FPU 和 NEON 协处理器共享一组寄存器,其中 32 个 128-bit
寄存器命名为 V0-V31,而起有
D,S,H 三个版本,分别对应 64-bit,
32-bit, 16-bit
FPU 只能处理最大 64 bits 的数据,对于 128 bits 需要 NEON 处理器,它将
128-bit 寄存器命名为 Q0-Q31
V8-V15由被调用者负责存储与恢复
V0-V7作为参数传递用途,包括剩余寄存器,需要调用者保存
对于这些寄存器仍可以用 stp, str,
ldp, ldr,需要注意的是 Q
寄存器需要用 stp 和 ldp
Loading and Saving FPU Registers
可以使用 FMOV 在 CPU 整数寄存器以及 FPU
的浮点寄存器之间移动数据,同时也可用于移动 FPU 中的寄存器
通常只能移动相同大小的寄存器,但是小寄存器可以移到大寄存器
需要注意的是FMOV不会进行任何转换
Performing Basic Arithmetic
对于下面的每一条指令,都能使用 3 种寄存器
1 | FADD Hd, Hn, Hm // Hd = Hn + Hm |
存在带
S后缀的版本
Performing Floating-Point Conversions
将低精度转为高精度,以及整数,或从整数转为浮点,同时有多种 rounding 方法可选
1 | FCVT Dd, Sm |
这些是浮点间精度互转
1 | SCVTF Dd, Xm // Dd = signed integer from Xm |
此外还有更多的整数到浮点
1 | FCVTAS Wd, Hn // signed, round to nearest |
Comparing Floating-Point Numbers
通过比较指令设置条件标志,只允许 #0.0
这一个立即数,因为不存在零浮点寄存器
1 | FCMP Hd, Hm |
因为浮点数的等于比较会有问题,因此往往采用比较
NEON Coprocessor
可以处理 64 bits 以及 128 bits 寄存器,在并行化时实际上将这些寄存器分成等宽的几块,分别一次性的计算
1 | ADD Vd.T, Vn.T, Vm.T // Integer addition |
其中
T必须是
- For ADD: 8B, 16B, 4H, 8H, 2S, 4S or 2D
- For FADD: 4H, 8H, 2S, 4S or 2D
Calculating 4D Vector Distance
1 | // |
其中
FADDP按照V0[0]=V1[0]+V1[1]以及V0[1]=V1[2]+V1[3]的成对相加方式,保留前两通道的累加结果,并忽略最后两通道
两次FADDP即实现了 4 项累加
1 | // |