ARM汇编语言
浮点运算
IEEE-754定义和运算基础
版本更新:
- 1985
- 2008:添加了精确控制
IEEE定义了可行的舍入方法,以及所有运算结果和异常。
舍入方法:向上/向下/向0/最近
运算异常:过大,过小,不准确,非法,除以零
异常处理:Not a Number(NaN),正负无穷,“denormalized number”
表示方法
单精度为32位,双精度为64位,VFP在硬件上支持二者。VFPv2额外支持半精度。
存储结构:
- 符号bit
- 指数位
- 二进制小数
表示的数字是:$sm2^{exp}$
二进制小数部分表示的小数被翻译为1.xxxx中xxx部分,如果数字是0则设置所有指数位为0。
具体含特殊值的表示表格
指数(默认偏移-127) | 尾数 | 含义 |
---|---|---|
-127 | 0 | +=0 |
-127 | !=0 | 非正常数 |
128 | 0 | 正负无穷 |
128 | !=0 | NaN |
Other | Any | $(+/-)1. |
非正常数,按照标准应当表示前导1改为前导0的极小数,从而表示更小的数字,但是由于真实场景下通常不需要计算,故可能被忽略,但这是违反规范的。Cortex的VFP可以通过设置修改计算表现。
舍入规范
舍入方面,最近舍入如果距离相等,向舍入后最低有效位为0的方向舍入。2008版本标准添加了总是向0的模式,Armv7此时的Cortex尚未支持。
VFP
该扩展是可选的,但通常被实现,由16/32个双字寄存器实现。VFPv3-D32和VFPv3-D16用来标记这两种实现。如果NEON同时实现,则选用D32。
VFPv3可选提供了浮点转换,在16/32位之间进行转换。
VFPv4在v3基础上添加了半精度扩展和融合的乘加指令。乘加指令只有一次舍入,这也是2008规范的一个内容,提高了重复累计操作的计算精度。
寄存器
- FPSID:记录硬件支持的浮点特性
- FPSCR:status and control,记录比较结果和异常标记,控制位设置舍入和使能浮点异常陷入
- FPEXC:记录异常情况
- MVFR0/MVFR1:记录硬件对于SIMD和浮点特性的支持。
用户模式下只能访问FPSCR,Linux下通过/proc/cpuinfo获知系统支持的特性。
由于浮点比较使用FPSCR,故在整数中使用前需要使用VMRS
指令将FPSR转移到APSR中。
比较结果定义
结果 | N | Z | C | V |
---|---|---|---|---|
= | 0 | 1 | 1 | 0 |
LT | 1 | 0 | 0 | 0 |
GT | 0 | 0 | 1 | 0 |
NaN | 0 | 0 | 1 | 1 |
指令使用
绝大多数不能用立即数。VCMP可以用0进行比较。
系统支持
linux下,为了节省周期,软件第一次访问VFP时系统会进行初始化。对于线程可以被迁移到不同核心的集群上,这种机制受限于核心可能变换,故不会非常有效。
优化
- 避免在Cortex-A9上昏庸NEON和VFP,因为在两者间切换时开销很大
- 对于FPSCR的存取性能消耗显著
- 整数-浮点寄存器之间的转移开销明显。
- 多个单独存取操作最好合并为一个,从而最大化利用带宽。