gpt4 book ai didi

assembly - 处理器是否可以同时进行存储和算术运算?

转载 作者:太空狗 更新时间:2023-10-29 15:25:31 25 4
gpt4 key购买 nike

在汇编和处理器的学习中,有一件事让我很困惑,指令是如何完成的:

add mem, 1

在我看来,处理器无法在同一条指令中加载内存值并处理算术运算。所以我认为它是这样发生的:

mov reg, mem
add reg, 1
mov mem, reg

如果我考虑带有 RISC Pipeline 的处理器,我们可以观察到一些摊位。对于像 i++ 这样简单的指令来说,这是令人惊讶的:

|  Fetch  | Decode  | Exec    | Memory  | WriteB  |
| Fetch | | | Decode | Exec | Memory | WriteB |
| Fetch | | | | Decode | Exec | Memory | WriteB |

(正如我在 Patterson 的书Computer Architecture: A Quantative Approach 中读到的那样,寄存器在解码 uOp 中读取,在内存 uOp 中存储/加载,我们允许自己在 Memory uOp 处取一个寄存器的值。)

我说的对吗?或者现代处理器有特定的方法来更有效地做到这一点?

最佳答案

你是对的,现代 x86 将解码 add dword [mem], 1 到 3 uops:加载、ALU 添加和存储。 (这实际上是对各种事物的简化,包括英特尔的微融合以及 AMD 如何始终在管道的某些部分将负载 + ALU 保持在一起......)

这 3 个相关操作不能同时发生,因为后面的必须等待前面的结果。

但是独立指令的执行可能会重叠,现代 CPU 非常积极地寻找并利用“指令级并行性”来以每时钟 1 uop 的速度运行您的代码。参见 this answer for an intro to what a single CPU core can do in parallel ,带有指向更多内容的链接,例如 Agner Fog's x86 microarch guide ,以及 David Kanter 的文章 SandybridgeBulldozer .


但如果您查看 Intel 的 P6 和 Sandybridge 微体系结构系列,就会发现存储实际上是独立的存储地址和存储数据微指令。 store-address 微指令不依赖于负载或 ALU 微指令,可以将存储地址写入 store buffer。随时。 (Intel 的优化手册将其称为 Memory Order Buffer)。

为了提高前端吞吐量,存储地址和存储数据微指令可以解码为微融合对。对于 add,load+alu 操作也可以,因此 Intel CPU 可以将 add dword [rdi], 1 解码为 2 个融合域微指令。 (相同的 load+add 微融合适用于解码 add eax, [rdi] 到单个 uop,因此任何“简单”解码器都可以解码它,而不仅仅是可以解码的“复杂”解码器处理多 uop 指令。这减少了前端瓶颈)。

这就是为什么 add [mem], 1 在 Intel CPU 上比 inc [mem] 更有效,即使 inc reg 是与 add reg,1 一样高效(但更小)。 (inc 不能对其 load+inc 进行微融合,它设置标志的方式与 add 不同)。 INC instruction vs ADD 1: Does it matter?

但这只是帮助前端更快地将uops送入调度器;负载仍然必须与添加分开运行。

但是微熔断负载不必等待整个指令输入的其余部分就绪。考虑像 add [rdi], eax 这样的指令,其中 RDI 和 EAX 都是指令的输入,但在 ALU add uop 之前不需要 EAX。一旦加载地址准备好并且有一个空闲的加载执行单元(AGU + 缓存访问),加载就可以执行。另见 How are x86 uops scheduled, exactly? .


registers are read in Decode uOp, Store/Load in Memory uOp and we allow ourselves to take the value of a register at the Memory uOp

所有当前的 x86 微架构都使用寄存器重命名(Tomasulo 算法)的乱序执行。指令被重命名并发布到核心的乱序部分(ROB 和调度程序)。

只有一条指令从调度程序“分派(dispatch)”到执行单元时,才会读取物理寄存器文件。 (或者对于最近生成的输入,从其他 uops 转发。)


独立指令可以与它们的执行重叠。例如,Skylake CPU 可以维持每个时钟 4 个融合域/7 个非融合域微指令的吞吐量,包括 2 个加载 + 1 个存储,in a carefully crafted loop :

.loop: ; HSW: 1.12c / iter. SKL: 1.0001c
add edx, [rsp] ; 1 fused-domain uop: micro-fused load+add
mov [rax], edi : 1 fused-domain uop: micro-fused store-address+store-data
blsi ebx, [rdi] : 1 fused-domain uop: micro-fused load+bit-manip

dec ecx
jnz .loop ; 1 fused-domain uop: macro-fused dec+branch runs on port 6

Sandybridge 系列 CPU 有一个 L1d 缓存,每个时钟能够进行 2 次读取 + 1 次写入。 (不过,在 Haswell 之前,只有 256 位向量可以解决 AGU 吞吐量限制。参见 How can cache be that fast?。)

Sandybridge 系列的前端吞吐量是每个时钟 4 个融合域微指令,它们在后端有很多执行单元来处理各种指令混合。 (Haswell 和后来的有 4 个整数 ALU、2 个加载端口、一个存储数据端口和一个用于简单存储寻址模式的专用存储 AGU。因此它们通常可以在缓存未命中停止执行后快速“ catch ”,快速在乱序窗口中找到更多工作要做。)

关于assembly - 处理器是否可以同时进行存储和算术运算?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51102525/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com