x86-32(又名 IA-32)是 16 位 8086 的 32 位扩展,旨在将 asm 源从 8 位 8080 轻松移植到 8086。(Why are first four x86 GPRs named in such unintuitive order? 用于逆向计算)。
这段历史就是为什么现代 x86 有这么多部分寄存器的东西,直接支持 8 位和 16 位操作数大小。
大多数其他具有 32 位寄存器的架构仅允许窄加载/存储,而 ALU 操作仅是完整的寄存器宽度。 (但这同样重要,因为它们是 RISC 架构(MIPS、SPARC,甚至是稍微少一点 RISCy 的 ARM),而 x86 绝对是 CISC 架构。)
RISC 架构(如 MIPS)的 64 位扩展仍然支持 32 位操作,通常将 32 位结果隐式零扩展至“完整”寄存器the same way x86-64 does。 (特别是如果 64 位不是新模式,而只是同一模式中的新操作码,其语义设计使得现有机器代码在寻址模式使用完整寄存器但所有旧操作码仍然仅以相同方式运行时写入低 32 位。)
因此,您在 x86-32 上观察到的情况(支持对部分寄存器的窄操作)存在于作为旧架构的更广泛扩展存在的所有架构中,无论它以新模式运行(机器代码解码不同)与否。只是 x86 的祖先在 x86 中回到了 16 位,又回到 8 位作为对 8086 的影响。
Motorola 68000 有 32 位寄存器,根据维基百科“主要 ALU”只有 16 位。 (也许 32 位操作速度较慢或某些不支持,但绝对支持 32 位添加/和指令。我不知道为什么 Wikipedia 这么说背后的细节)。
最初 68000 设计用于 16 位外部总线,因此 16 位加载/存储在那些早期 CPU 上效率更高。我认为后来的 68k CPU 拓宽了数据总线,使 32 位加载/存储与 16 位一样快。无论如何,我认为 m68k 是另一个支持大量 16 位操作的 32 位架构示例。维基百科将其描述为“16/32 位 CISC 微处理器”。
添加缓存后,缓存行中可容纳的 16 位整数是 32 位整数的两倍,因此对于顺序访问,16 位的平均/持续内存只需一半带宽。 当有缓存时,“总线宽度”会变得更加复杂,因此在加载/存储单元和缓存之间以及缓存和内存之间存在总线或内部数据路径。 (并且在多级缓存中,不同级别的缓存之间)。
决定是否调用 8 / 16 / 32 / 64 位架构(或该架构的特定实现)是相当随意的。 营销部门可能会选择他们可以证明的最广泛的东西,并在 CPU 的描述中使用它。这可能是数据总线或寄存器宽度,或地址空间或其他任何东西。 (许多 8 位 CPU 在两个 8 位寄存器的串联中使用 16 位地址,尽管它们中的大多数不会尝试声称是 16 位。尽管它们可能被宣传为 8/16 位。)
32 位 x86 被认为是 32 位,因为这是指针或“通用”整数寄存器的最大宽度。 386 增加了几个主要的新内容:32 位整数寄存器 /操作数大小(可通过实模式的前缀访问)和具有虚拟内存分页的 32 位保护模式,其中默认地址和操作数大小为 32 位。
今天可以运行 IA-32 机器代码的物理 CPU比第一代 386SX CPU 具有更宽的总线和更好的内存带宽,但它们仍然支持相同的IA-32 架构(加上扩展)。
如今,基本上所有新的 x86 CPU 也可以在 x86-64 模式下运行。在 IA-32 模式下运行时,现代 x86 CPU 将仅使用其 64 位物理整数寄存器的低 32 位(例如在 32 位或 16 位模式下使用 32 位操作数大小的指令) .
但除整数寄存器外,还有 80 位 x87 寄存器(可用作 64 位整数-SIMD MMX 寄存器),以及 XMM / YMM / ZMM 寄存器(SSE / AVX / AVX512)。
SSE2 是 x86-64 的基准,现在可以在大多数 32 位代码中假定,因此至少有 128 位寄存器可用,并且可以用于 64 位整数加/减/移位,即使在32 位模式,带有 paddq 之类的指令。
现代 CPU 在向量加载/存储单元和缓存之间也具有至少 128 位的连接,因此当数据适合 L1d 缓存时,加载/存储/复制带宽不受外部双/三/四通道 DDR3 的限制/DDR4 DRAM 控制器(在 64 位外部总线上进行 8x 64 位的突发传输 = 一个 64 字节缓存线)。
相反,CPU 具有大型快速缓存,包括共享的 L3 缓存,因此如果数据在 L3 中仍然很热,则由一个内核写入并由另一个内核读取的数据通常不必经过内存。请参阅some details on how cache can be that fast for Intel IvyBridge,尽管它支持 256 位 AVX 指令,但它只有 128 位加载/存储路径。 Haswell 也将加载/存储路径扩大到 256 位。 Skylake-AVX512 将 L1d 缓存以及 L1d 和 L2 之间的连接的寄存器和数据路径扩大到 512 位。
但在纸面上,x86(自 P5 Pentium 及更高版本)仅保证 aligned loads/stores up to 64 bits are atomic,因此允许使用 SSE 的实现将 128 位 XMM 加载/存储分成两个 64 位半。 Pentium III 和 Pentium M 实际做到了这一点。但请注意,i586 Pentium 比 x86-64 早了十年,它可以加载/存储 64 位的唯一方法是使用 x87 fld 或 fild。 Pentium MMX 可以进行 64 位 MMX movq 加载/存储。无论如何,这种原子性保证包括未缓存的存储(例如,对于 MMIO),这是可能的(很便宜,没有总线锁),因为 P5 微架构有一个 64 位外部总线,即使它是严格的 32 位而不是FPU。
即使是纯整数代码也受益于宽数据路径,因为它增加了整数代码的带宽,加载/存储在 L3 或特别是 L2 缓存中命中,但不是 L1d 缓存。
所有这些对 x86 的 SIMD 扩展使其比纯 32 位整数架构强大得多。但是在32位模式下运行时,仍然是386引入的模式,我们称之为32位模式。这个名字和任何名字一样好,但不要试图过多地解读它。
事实上,除了整数/指针寄存器宽度之外,不要将任何东西读入其中。它运行的硬件通常具有 64 位整数寄存器和 48 位虚拟地址空间。以及各种巨大宽度的数据总线 + 缓存,以及复杂的乱序机制,给人一种在actually looking at a window of up to 224 uops to find instruction-level parallelism 时按顺序运行的错觉。 (Skylake / Kaby Lake / Coffee Lake ROB 大小)。