但是 ymm0 中的值是 5。
ymm0 中的位模式是1084227584。该数字的浮点解释是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
XMM/YMM/ZMM 寄存器是特殊的,因为它们是 FP ALU 指令存在的唯一寄存器(忽略 x87,它仅用于 x86-64 中的 80 位 long double )。
addsd xmm0, xmm1(加双精度标量)没有整数寄存器的等价物。
通常 FP 和整数数据不会混合太多,因此提供一整套独立的架构寄存器可以为寄存器中的更多数据提供更多空间。 (给定相同的指令编码约束,可以在 16 个 FP + 16 个 GP 整数与 16 个统一寄存器之间进行选择,而不是在 32 个统一寄存器之间进行选择)。
另外,单独的寄存器文件的主要微架构优势是它可以在物理上靠近 FP ALU,而整数寄存器文件可以在物理上靠近整数 ALU。 更多信息,请参阅Is there any architecture that uses the same register space for scalar integer and floating point operations?
float 和 double 值是否始终存储为浮点数?我们不能将它们作为固定点存储在 C 或汇编中吗?
x86 编译器使用 float = IEEE754 binary32 https://en.wikipedia.org/wiki/Single-precision_floating-point_format。 (和double = IEEE754 binary64)。这被指定为 ABI 的一部分。
在内部,as-if 规则允许编译器为所欲为,只要最终结果相同。 (或者使用-ffast-math,假装 FP 数学是关联的,并假设 NaN/Inf 是不可能的。)
编译器不能只是为某些 float 随机选择其他单独编译的函数可能会查看的不同对象表示。
对于其他函数永远不可见的局部变量可能很少见,其中“人工编译器”(手写 asm 来实现 C)可以证明定点是安全的。或者更有可能的是,float 值是足够小的整数,double 不会对它们进行四舍五入,因此您的定点可能会退化为整数(可能除了最后一步)。
但是,如果不能进行持续传播和优化一切,就很少能对可能的值了解这么多。这就是为什么我说必须有人参与,以证明编译器不知道要寻找的东西。
我认为理论上你可以有一个 C 实现确实使用定点 float 或 double。 ISO C 对什么限制很少float 和 double 实际上是。
但是limits.h constants like FLT_RADIX and DBL_MAX_EXP 的交互对于定点格式可能没有意义,它在每个可表示值之间具有恒定的距离,而不是在接近 0 时靠得更近,而对于大数则相距更远。 (0.5ulp的舍入误差是相对于幅度的,而不是绝对的。)
不过,如果“尾数”和指数限制与您对 DBL_MIN 和 DBL_MAX 的预期不符,大多数程序实际上并没有做会破坏的事情。
另一个有趣的可能性是基于 Posit 格式制作 float 和 double(类似于传统的浮点,但使用可变长度的指数编码。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 位有效位乘法器。现代英特尔 CPU 在 FMA 执行单元上运行整数乘法和移位,每个时钟吞吐量为 2 微秒。)