超标量设计:三段式布局、功能单元阵列与共享后端
承总纲 pipelining-superscalar,前置基础见 pipelining-basics。流水线把吞吐做到 IPC≈1 就到顶了;想突破 1,只有一条路:每一级都放多份硬件,一拍能取多条、译多条、执行多条——这就是超标量(superscalar)。本篇拆解现代超标量核的三段式布局(前面共享 → 中间分流 → 后面汇合)、为什么这么分、以及汇合处的 LSU 和 ROB 各管什么。
一、超标量:把流水线"加宽",一拍处理多条
流水线满载 IPC≈1(每拍 1 条),到顶了。想突破 1,只有一条路:每一级都放多份硬件,一拍能取多条、译多条、执行多条。这就是超标量(superscalar)。
1.1 总体布局:前面共享 → 中间分流 → 后面汇合
现实超标量 CPU 遵循三段式结构:
- 前面共享:取指和译码不分指令类型,统一前端每拍取出 4~6 条 x86 指令并行译码为 µop。因为取指时还不知道操作码,无法提前分家。
- 中间分流:译码完成后按操作码分派——整数/分支 µop 进 INT 集群,浮点/SIMD µop 进 FP 集群。每个集群内部也不是单条管线,而是多套同构执行单元(INT 内 ALU×4 + 分支×1,FP 内 FMA×2 + SIMD ALU×1),调度器按操作数就绪情况乱序发射到空闲单元。
- 后面汇合:两个集群的执行结果全部汇入共享的 LSU(处理 load/store)和 ROB(统一按程序顺序退休)。

1.2 设计原理
为什么前端共享——取指和译码不分指令类型。指令从内存取出来到译码完成之前,CPU 并不知道它是什么类型——I-Cache 里存的只是原始机器码字节流,直到译码阶段查出操作码,才知道这条是 ADD 还是 FMUL。如果在取指阶段就按类型分家,需要两套独立的 I-Cache、预取器、分支预测器,面积翻倍且带宽利用率下降。因此所有现代超标量 CPU 都采用统一前端,译码完成、操作码已知后才分流。
为什么分流后端——不同指令用不同硬件,消除无效等待:
- 消除类型冲突:单流水线中 I3(FMUL) 和 I2(ADD) 虽然用不同硬件(FPU vs ALU),却只能排队过同一个 EX。分流后整数和浮点各有独立发射口和执行单元,互不阻塞。
- 匹配延迟差异:整数加法 1 拍,浮点 FMA 4~5 拍。混在一起时短延迟被长延迟堵死;分开后 INT 集群快速周转,FP 集群自行处理长延迟运算。
- 物理设计约束:整数 ALU 和浮点 FMA 的晶体管规模差一个数量级,延迟路径完全不同,硬塞进同一级会让时序收敛极其困难。分集群本质上是让快路径不受慢路径拖累,同时让物理布局更规整。
1.3 功能单元阵列与乱序发射
从上图可以看到,每个集群内部是功能单元阵列而非单条管线:
- INT 集群:调度器下挂 4 个独立执行单元——2 个
ALU×4+ 2 个分支。共 8 个 ALU + 2 个分支单元共享同一保留站,调度器按操作数就绪情况任意指派到空闲单元。 - FP 集群:同样的异构阵列——2 个
FMA×2(融合乘加) + 2 个SIMD ALU,分别处理浮点/SIMD 乘加和 SIMD 整数/位运算。
保留站的工作方式:µop 进入保留站后,操作数就绪那一刻立即发射到空闲执行单元,不按程序顺序(乱序)。只要保留站里同时有两条操作数就绪且无依赖的 µop,调度器就能同一拍发射两条,IPC 翻倍。INT 集群同拍最多发射 4 条(2 ALU + 2 分支),FP 集群同拍最多发射 4 条(2 FMA + 2 SIMD),理想峰值每拍 8 条 µop。详见 reservation-station。
1.4 共享后端:LSU 与 ROB
从图中可以清晰看到,后端汇入有两种路径:
- ALU/FMA/SIMD → LSU → ROB:运算类指令的结果先过 LSU(处理其中的 load/store),再由 LSU 送入 ROB。图中所有 ALU、FMA、SIMD ALU 全部走这条路径。
- 分支 → ROB 直连:分支执行单元的结果直接进 ROB,跳过 LSU——因为分支不产生数据也不访存,只需告诉 ROB"预测对了/错了"。
LSU(Load/Store Unit)
LSU 是 CPU 与内存子系统之间的唯一通道。完整的 AGU、Store Buffer、Load Buffer、store→load forwarding、memory disambiguation 分析见 lsu。核心约束:AGU 数量(3~4 个)决定了密集访存代码的 IPC 上限。
ROB(Reorder Buffer)
ROB 是"乱序执行、顺序退休"的物理基础——所有 µop 结果汇入 ROB,按程序序批量提交到架构状态。完整的保序机制、多端口并行退休、对头阻塞、精确异常、分支机构恢复分析见 rob。核心约束:ROB 大小决定指令窗口(现代 CPU 200~500 条目);对头阻塞(head 处慢指令堵住退休)是真正瓶颈。
上面是概念示意——真正的核里 L1 D-Cache 和 LSU 紧密耦合,EX 和调度器之间还有旁路网络。下面这张补齐这些细节:

| 部件 | 做了什么 | 为什么重要 |
|---|---|---|
| 前端 取指→译码 | 把 x86 复杂指令解码成 µop,每拍 4~6 条 | 前端是"水源"——它多快,后端才有可能多快。µop Cache 缓存已解码 µop,跳过重复解码 |
| INT/FP 调度器 | 各带保留站,操作数就绪即发射,不管程序顺序 | 顺序发射是超标量的死穴——紧邻指令常有依赖,宽端口喂不饱。乱序让后面独立指令先走 |
| INT/FP 执行引擎 | 多个同类型执行单元并行:INT 侧 4 个 ALU+分支,FP 侧 2 个 FMA+SIMD ALU | IPC>1 的根本原因:同一拍多个执行单元同时干活。FMA 延迟长但可流水化,每拍新发一条 |
| LSU + Store Buffer | 两条流水线的 load/store 在此排队,地址翻译后访问 L1 D-Cache | 瓶颈点——不管多少 ALU/FMA,L1 D-Cache 每拍只做 2~3 次 load + 1~2 次 store |
| ROB 统一退休 | 所有 µop 按程序原顺序提交结果 | 乱序执行的"幻象机"——程序看到的世界永远是顺序的,异常能精确定位 |
两条流水线的分道与汇合:译码时按操作码分道(add eax→INT 调度器,addsd→FP 调度器),此后各自乱序执行,只在两个地方碰头——LSU(都得访存)和 ROB(都得按序提交)。
二、一句话总结
超标量是"横向"提吞吐:把每一级复制成多份硬件,一拍处理多条指令,IPC 突破 1。它的布局是"前共享 → 中分流 → 后汇合"——取指译码时不知道指令类型,只能统一前端(4~6 条/拍);译码后按操作码分进 INT/FP 两个集群,每个集群内是多套同构执行单元阵列(INT 8 ALU + 2 分支,FP 4 FMA + 4 SIMD),保留站按操作数就绪乱序发射填满空闲端口;最后全部结果汇入共享的 LSU(唯一的访存通道,AGU×3~4 决定访存 IPC 上限)和 ROB(按程序序批量退休)。乱序调度 + 多端口退休是喂饱这台宽机器的关键,这部分见 ipc-bottlenecks(IPC 为什么还到不了理论值)。