首页 文章

处理器可以同时进行内存和算术运算吗?

提问于
浏览
4

在汇编程序和处理程序的研究中,有一件事把我带出来,如何完成指令:

add mem, 1

在我的脑海中,处理器无法加载内存值 and 处理同一指令期间的算术运算 . 所以我觉得它发生在:

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的书“计算机体系结构:量词方法”中所读到的那样,寄存器在 Decode uOp中读取,存储/加载到存储器uOp中,我们允许自己在存储器uOp中获取寄存器的值 . )

我对吗?还是现代处理器有更具效的方法来做到这一点?

1 回答

  • 6

    你没错,现代的x86会将 add dword [mem], 1 解码为3 uops:一个加载,一个ALU添加和一个商店 .

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

    但独立指令的执行可以重叠,现代CPU非常积极地寻找并利用"instruction level parallelism"以比每个时钟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 .


    But if you look at Intel's P6 and Sandybridge microarchitecture families, a store is actually separate store-address and store-data uops . store-address uop不依赖于load或ALU uop,并且可以随时将存储地址写入存储缓冲区 . (英特尔的优化手册将其称为内存订购缓冲区) .

    为了增加前端吞吐量,存储地址和存储数据uop可以解码为微融合对 . 对于 add ,加载alu操作也是如此,因此Intel CPU可以将 add dword [rdi], 1 解码为2个融合域uop . (相同的负载添加微融合用于将 add eax, [rdi] 解码为单个uop,因此"simple"解码器中的任何一个都可以解码它,而不仅仅是可以处理多uop指令的"complex"解码器 . 这减少了前端瓶颈) .

    这就是 add [mem], 1 在Intel CPU上比 inc [mem] 更有效的原因,尽管 inc regadd reg,1 一样高效(但更小) . ( inc 不能微量融合其load inc,它设置的标志与 add 不同) . INC instruction vs ADD 1: Does it matter?

    但这只是帮助前端更快地进入调度程序;负载仍然必须与add分开运行 .

    但微熔合负载并没有准备就绪 . 考虑像 add [rdi], eax 这样的指令,其中RDI和EAX都是指令的输入,但EAX不是自由加载执行单元(AGU缓存访问) . 另见How are x86 uops scheduled, exactly? .


    寄存器在解码uOp,存储/加载到存储器uOp中读取,我们允许自己在存储器uOp中取一个寄存器的值

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

    在从调度程序“执行”指令到执行单元之前,不读取物理寄存器文件 . (或者对于最近生成的输入,从其他uops转发 . )


    Independent instructions can overlap their execution . 例如,Skylake CPU可以维持每个时钟4个融合域/ 7个非融合域uop的吞吐量,包括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次读取 . (在Haswell之前,只有256位向量可以解决AGU吞吐量限制 . 请参阅How can cache be that fast? . )

    Sandybridge系列前端吞吐量是每个时钟4个融合域uop,并且它们在后端有许多执行单元来处理各种指令混合 . (Haswell后来有4个整数ALU,2个加载端口,一个存储数据端口和一个专用存储AGU,用于简单的存储寻址模式 . 因此,它们经常可以在缓存未命中执行后快速“赶上”,快速制作在无序窗口的房间找到更多工作要做 . )

相关问题