Joe*_*Joe 1 c floating-point assembly x86-64
据我了解,浮点存储在XMM寄存器中,而不是诸如的通用寄存器中eax,因此我做了一个实验:
float a = 5;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,a被存储1084227584在XMM寄存器中。这是程序集版本:
.text
.global _start
.LCO:
.long 1084227584
_start:
mov .LCO, %eax
movss .LCO, %xmm0
Run Code Online (Sandbox Code Playgroud)
执行上述组件和使用它的调试gdb显示,在值eax将是1084227584,然而,在值ymm0是5。
这是我的问题:
1- XMM寄存器有什么特别之处?除了SIMD指令,它们是唯一存储浮点的寄存器类型吗?
为什么不能在常规寄存器中设置相同的位?
2- float和double值始终存储为浮点吗?
我们永远不能将它们存储为fixed pointC或汇编语言吗?
但是ymm0中的值为5。
ymm0中的位模式为1084227584。该数字的float 解释为5.0。
但是您可以print /x $xmm0.v4_int32看到xmm0中位的十六进制表示。
XMM寄存器有什么特别之处?除了SIMD指令,它们是唯一存储浮点的寄存器类型吗?
不,在asm中,一切都只是字节。
一些编译器将使用整数寄存器将浮点数或双精度数从一个内存位置复制到另一个内存位置,如果不对其进行任何计算的话。(整数指令通常较小。)例如clang会这样做:https : //godbolt.org/z/76EWMY
void copy(float *d, float *s) { *d = *s; }
# clang8.0 -O3 targeting x86-64 System V
copy: # @copy
mov eax, dword ptr [rsi]
mov dword ptr [rdi], eax
ret
Run Code Online (Sandbox Code Playgroud)
XMM / YMM / ZMM寄存器之所以特殊,是因为它们是FP ALU指令存在的唯一寄存器(忽略x87,x87仅long double在x86-64中用于80位)。
addsd xmm0, xmm1 (加标量双精度)对于整数寄存器没有等效项。
通常FP和整数数据不会相交太多,因此提供一组完整的体系结构寄存器集可以为将更多数据存储在寄存器中提供更多空间。(鉴于相同的指令编码约束,可以在16 FP + 16 GP整数与16个统一寄存器之间进行选择,而不是对32个统一寄存器之间进行选择)。
另外,单独的寄存器堆的主要微体系结构优势在于,它在物理上可以接近FP ALU,而整数寄存器堆在物理上可以接近整数ALU。 有关更多信息,请参见是否有任何架构将相同的寄存器空间用于标量整数和浮点运算?
是
float和double值始终存储为浮点?我们永远不能将它们存储为C或汇编中的固定点吗?
x86编译器使用float= IEEE754 binary32 https://en.wikipedia.org/wiki/Single-precision_floating-point_format。(和double= IEEE754 binary64)。这被指定为ABI的一部分。
在内部,如果最终规则相同,则按条件规则允许编译器执行所需的任何操作。(或使用-ffast-math,假装FP数学是关联的,并假设NaN / Inf不可能。)
编译器不能为float其他单独编译的函数可能会随机选择的对象表示形式。
对于本地人来说,在极少数情况下可能是其他函数无法看到的,在这种情况下,“人工编译器”(实现C的手写asm)可以证明定点是安全的。或更可能的是,这些float值是足够小的精确整数,double不会将它们取整,因此您的定点值可以退化为整数(也许最后一步除外)。
但是,很少能够仅仅不断进行传播并优化所有内容,就不可能对可能的值有太多了解。这就是为什么我要说一个人来证明编译器不知道要寻找的东西的原因。
我认为从理论上讲,您可以使用确实使用定点float或的C实现double。 ISO C穿什么非常少的限制float和double实际的。
但是limits.h常量喜欢FLT_RADIX和DBL_MAX_EXP具有对于定点格式可能没有意义的交互,定点格式在每个可表示的值之间具有恒定的距离,而不是在0附近彼此靠得更近,而对于较大数字则彼此靠得更远。(0.5ulp的舍入误差与幅度有关,而不是绝对值。)
不过,如果“尾数”和指数限制不符合您的期望DBL_MIN和,大多数程序实际上不会做会破坏的事情DBL_MAX。
另一个有趣的可能性是使float与double基于所述POSIT格式(类似于传统浮点,但与可变长度编码指数。 https://www.johndcook.com/blog/2018/04/11/anatomy-of -a-posit-number / https://posithub.org/index)。
现代的硬件,尤其是英特尔CPU,具有非常支持IEEE浮点/双精度,所以定点良好的支持往往不是一个胜利。但是,对于16位定点有一些不错的SIMD指令,例如仅半高乘法,甚至pmulhrsw可以进行定点舍入。
但是一般的32位整数乘法的吞吐量比打包float乘法的吞吐量差。(因为针对浮点/双精度进行了优化的SIMD ALU每32位向量元素仅需要24x24位有效乘数。现代Intel CPU在FMA执行单元上运行整数乘法和移位,每个时钟吞吐量为2 uops。)