使用 dword 或 qword 参数时 fdiv 更快吗?

pts*_*pts 1 floating-point x86 assembly cpu-architecture x87

我可以选择以下 80387 指令:

fdiv dword ptr a
Run Code Online (Sandbox Code Playgroud)

fdiv qword ptr b
Run Code Online (Sandbox Code Playgroud)

a和 的数字b是等价的,都是 100% 准确的。

我应该选择该版本有理由吗qword?我只能将速度视为一个好处。现代处理器有区别吗?80387 和 80487 有区别吗?

Pet*_*des 6

dword大小永远不会变慢。(除非由于一些次要影响,例如此处较窄的内存位置导致其他一些数据未对齐。)

在大多数 CPU 上,我认为qword当值相同时,除了数据传输时间之外,速度也会相同。

在某些 CPU 上,如果尾数的低位不全为零(因此除数的有效位比适合双字浮点数的除数更高),则速度可能会更慢。除非“整数”提前退出情况仅适用于有效位较少的数字。


在 P5 Pentium 之前,传输一个 qword 比传输一个 dword 需要更多的周期,因为直到 P5 Pentium 数据路径才扩展到 64 位。(除非 486DX 可以在 FPU 及其内部缓存之间传输 64 位?64 位原子性保证是 P5 中的新功能。)

我认为内存源 FP 数学运算相当于首先将1 位扩大到 80 位fld,就 FPU 本身看到的数据而言,因此表示与 dword float32 完全相同的值的 qword float64 将产生相同的输入一旦完成加载内存操作数,就开始实际的 FPU 工作。

对于fadd//指令,性能不依赖于输入数据或x87 控制字中的精度设置(它必须为输出生成多少尾数位),至少在 P5 或更高版本上不依赖于fsubfmul

fdivfsqrt确实取决于精度设置。 https://agner.org/optimize/指令表最早仅包括 P5。 fdivP5 上输出尾数精度设置为 24 位、53 位或 64 位时,周期分别为 19/33/39。降低精度可以加快 fdiv/fsqrt 的速度,但会损害所有方面的精度:有趣的事实:Direct3D 默认情况下会将 FPU 精度降低到最小 24 位,可能是因为 3D 几何对向量的大小进行了大量的 sqrt 和除法。

在某些 CPU 上,fdiv性能取决于实际数据。在许多 CPU 上,Agner Fog 的指令表都包含有关 fdiv 计时的注释。AMD K7 的第一个此类注释表示“低值[时钟周期计数]适用于舍入除数,例如 2 的幂”。2 的幂是最圆的,尾数全为零,但措辞意味着其他值也可以是圆的,并且需要更少的周期。

所以我猜不仅仅是2的幂比较快。qword float64 也是精确的 float32,有点圆:只有 23 个非零尾数位,低 29 位全为零。但这仍然可能有很多非零尾数位;对于任何特殊情况来说,可能太多了,IDK。

后来的注释更简洁,只是提到“舍入除数”,但想必他的意思是相同的,而不仅仅是 2 的幂作为唯一的特殊情况。

Pentium-M / Core Solo/Duo 的fdiv吞吐量为 8 到 37 个周期(与 类似divsd),Agner Fog 的注释中说“高值是典型的,低值适用于低精度或舍入除数。” 我认为“低精度”是指 x87 控制字设置。我不知道“舍入除数”是否仅意味着 2 的幂(全零尾数),或者是否有一个关于其圆度的滑动比例例如有效尾数位有多少。对于 PM / Core 1 上的整数div/ idiv,注释开头相同,但添加了“在允许提前算法的舍入值的情况下,Core Solo/Duo 比 Pentium M 更高效”。

具有此类注释的 CPU:

  • K7、K8:舍入除数更​​快

  • K10提到速度取决于被除数idiv的绝对值的有效位数,并参见AMD的优化手册。但没有注意,K10 上的延迟/吞吐量是固定的。山猫/美洲虎也一样。fdiv

  • Bulldozer 系列:可变延迟和吞吐量fdiv(并且部分流水线化,吞吐量优于延迟),但没有注释解释何时。

  • Zen 1:可变延迟和吞吐量,无注释

  • Zen 2 到 Zen 4:fdiv延迟 = 15 个周期,吞吐量 = 每 6 个周期 1 个。

  • P5 Pentium:对于 24、53 和 64 位精度,FDIV 分别需要 19、33 或 39 个时钟周期。FIDIV 还需要 3 个时钟。精度由浮点控制字的位 8-9 定义

  • P6 Pentium II / III:FDIV 延迟取决于控制字中指定的精度:64 位精度给出延迟 38,53 位精度给出延迟 32,24 位精度给出延迟 18。除以 2 的幂需要 9 个时钟。吞吐量的倒数为 1/(延迟-1)。(不依赖于提到的数据值)

  • Pentium M / Core (1) Duo/Solo: 高值是典型值,低值适用于低精度或舍入除数。

  • Core 2 Merom、Wolfdale 和 Nehalem:舍入除数或低精度给出低值。

  • Sandybridge 或更高版本没有注释:fdiv给出的时间为 lat = 10-24c,SnB 的配方吞吐量 = 10-24c。IvB / Haswell对其进行了轻微的流水线处理(吞吐量比延迟好几个周期),Broadwell是吞吐量明显优于延迟的情况。

  • Pentium 4:延迟和倒数吞吐量取决于 FP 控制字中的精度设置。单精度:23,双精度:38,长双精度(默认):43。并且在使用 FP-DIV 单元期间,FP-MUL 单元的吞吐量会降低。 (尽管fdiv是单个 uop 问题/调度。)

  • Atom / Silvermont / Goldmont (plus) / Tremont:fdiv延迟和吞吐量是固定的,甚至没有提到精确设置的帮助。

  • 通过 Nano 2000 / 3000:fdiv 延迟和吞吐量为 15-42 (Nano 2000) 或 14-23 个周期 (Nano 3000)。没有注释,所以也许只是精确控制。


脚注 1:加宽相当简单:在底部用零填充尾数,并调整有偏差的指数字段,使其代表 2 的相同幂 。80 位格式还使用显式而不是隐式前导1(或0用于次正规)位于尾数中,以便从指数字段中解码该位。

对于 dword 或 qword 加载,解码过程的工作量应该相同;fld m32 / m64P5 Pentium在一个时钟周期内运行。