几个可能的原因:
x86 是一个相对较旧的 ISA (毕竟它的前身是8086)
x86 已经多次显着发展,但需要硬件来保持与旧二进制文件的向后兼容性。例如,现代 x86 硬件仍然支持本地运行 16 位代码。此外,存在多种内存寻址模型以允许旧代码在同一处理器上互操作,例如实模式、保护模式、虚拟 8086 模式和 (amd64) 长模式。这可能会让一些人感到困惑。
x86 是一台 CISC 机器。长期以来,这意味着它比 MIPS 或 ARM 等 RISC 机器慢,因为指令具有 data interdependency and flags使大多数形式的指令级并行性难以实现。现代实现将 x86 指令转换为类似 RISC 的指令,称为“micro-ops”,以使这些类型的优化在硬件中实现实用。
在某些方面,x86 并不逊色,只是不同而已。例如,输入/输出在绝大多数架构上被处理为内存映射,但在 x86 上则不然。 (注意:现代 x86 机器通常具有某种形式的 DMA 支持,并通过内存映射与其他硬件通信;但 ISA 仍然具有 I/O 指令,如 IN
和 OUT
)
x86 ISA具有很少的架构寄存器,这可以强制程序比其他情况更频繁地往返内存。尽管 efficient store-forwarding 执行此操作所需的额外指令会占用可用于有用工作的执行资源保持低延迟。将寄存器重命名为大型物理寄存器文件的现代实现可以使许多指令保持运行状态,但缺乏架构寄存器仍然是 32 位 x86 的一个重大弱点。 x86-64 从 8 个整数和向量寄存器增加到 16 个是 64 位代码比 32 位更快(以及更有效的寄存器调用 ABI)的最大因素之一,而不是每个寄存器的宽度增加。从 16 个整数寄存器进一步增加到 32 个整数寄存器会有所帮助,但作用不大。 (不过,AVX512 确实增加到 32 个向量寄存器,因为浮点代码具有更高的延迟并且通常需要更多的常量。)( see comment )
x86 汇编代码很复杂,因为 x86 是一个复杂的体系结构,具有许多功能。典型 MIPS 机器的指令列表适合在一张信纸大小的纸上。 x86 的等效 list 填满了好几页,而说明只是做的更多,因此您通常需要比 list 所能提供的更深入地解释它们的作用。例如, MOVSB
instruction需要一个相对较大的 C 代码块来描述它的作用:
if (DF==0)
*(byte*)DI++ = *(byte*)SI++;
else
*(byte*)DI-- = *(byte*)SI--;
这是一条执行加载、存储和两个加法或减法(由标志输入控制)的指令,每条指令在 RISC 机器上都是单独的指令。
尽管 MIPS(和类似架构)的简单性并不一定使它们更胜一筹,但对于汇编程序类的介绍,从更简单的 ISA 开始是有意义的。 .一些汇编类(class)教授一个名为 y86 的超简化 x86 子集。 ,它被简化到对实际使用没有用处(例如没有移位指令),或者一些只教授基本的 x86 指令。
x86 使用可变长度的操作码,这增加了与指令解析相关的硬件复杂性。在现代,随着 CPU 越来越受到内存带宽而不是原始计算的限制,这种成本变得越来越小,但是许多“x86 抨击”文章和态度来自这个成本相对更大的时代。
2016 年更新:Anandtech 发布了 discussion regarding opcode sizes under x64 and AArch64 .
编辑:这不应该是 x86 的 bash!派对。鉴于问题的措辞,我别无选择,只能进行一些抨击。但是除了 (1) 之外,所有这些事情都是有充分理由的(见评论)。英特尔的设计师并不愚蠢——他们想通过他们的架构实现一些目标,而这些是他们为使这些目标成为现实而必须缴纳的一些税款。
我是一名优秀的程序员,十分优秀!