如果有的话,英特尔和 AMD 的 ISA 之间到底有什么区别?

12

我知道有人之前也问过类似的问题,但是存在太多冲突信息,所以我真的想一劳永逸地澄清这个问题。我将通过清晰区分指令集架构(ISA)和实际硬件实现来尝试达到这个目的。首先是我的说明:

1.) 目前市面上有Intel64和AMD64 CPU(还有其他型号但我们关注这两个)

2.) 考虑到ISA是一个或多个CPU指令的二进制表示,这意味着ISA与其实际硬件实现完全独立。

我的问题:

Intel 64和AMD64 CPU之间的差异是否与不同或扩展的x86-64 ISA有关?还是与x86-64 ISA的不同硬件实现有关?还是两者都有?

1个回答

17
是的,ISA是一份文档/规范,而不是硬件。正确实现所有内容才能使某物成为x86 CPU,而不仅仅是具有与x86相似之处。
请参见标签wiki以获取官方文档(英特尔手册)的链接。
英特尔和AMD的x86 ISA实现主要在性能和支持哪些指令集扩展方面有所不同。软件可以使用CPUID指令查询所支持的内容。
还有一些非性能差异,例如有时指令语义方面会有轻微差异,尤其是特权指令,操作系统需要使用:

在这里一个主要的分歧是,Intel、AMD和VIA各自拥有自己的硬件虚拟化扩展,它们甚至不试图兼容。因此像Xen这样的虚拟机需要为每个扩展编写单独的“驱动程序”或“后端”代码。但那些仍然是扩展,而不是基线x86的一部分。

供用户空间程序使用的SIMD扩展最终都会在两者上可用,但通常由于Intel利用反竞争做法来阻碍AMD而延迟。这浪费了其他人的时间,并且通常对整个x86生态系统有害(例如,SSSE3现在可以被假定为更多软件的基线),但有助于Intel的底线。一个很好的例子是:AMD Bulldozer支持FMA4,但Intel在最后一刻改变了主意,并在Haswell中实现了FMA3。AMD直到他们的下一个微体系结构(Piledriver)才支持FMA3。


鉴于 ISA 是一个或多个 CPU 指令的二进制表示,但它远不止如此。英特尔文档中保证适用于所有 x86 CPU 的所有内容都是 ISA 的一部分。这不仅涵盖每个指令的详细行为,还包括诸如哪个控制寄存器执行何种任务以及内存排序规则之类的内容。基本上,凡是在英特尔和 AMD 发布的手册中没有带有“在某个特定型号的 CPU 上”的前缀的内容都属于 ISA 的一部分。
我想可能会有少数情况下,英特尔和 AMD 的系统编程指南在 x86 的工作方式上存在差异(如果 VIA 为其 x86 CPU 发布自己的指南,则也有可能存在差异)。我没有检查过,但我很确定用户空间不会受到这种影响:如果存在差异,则仅限于只有内核运行它们才有效的特权指令。无论如何,在那种情况下,可以说 x86 ISA 是 Intel 和 AMD 文档共同部分的子集。
请注意,实验以了解实际硬件的行为对于理解文档很有用,但不能替代阅读文档。您不希望您的代码依赖于您测试的CPU上指令的行为。
然而,英特尔确实使用真实软件测试其新设计,因为无法运行现有版本的Windows会在商业上造成不利影响。例如Windows9x不会使只能通过推测填充的TLB条目失效(此示例的其余部分只是对该非常详细的博客文章的摘要和推断)。这可能是基于安全假设的性能优化(并且在当时的硬件上是安全的),或者是一个未被注意到的错误。它当时无法通过硬件测试检测出来。
现代英特尔CPU进行推测式页面行走,但即使是最近的Haswell也会检测和拒绝误推测,因此假定这种情况不会发生的代码仍将起作用。
这意味着实际硬件提供比ISA更强的排序保证,ISA说:
处理器可以缓存预取所需的翻译以及由于推测执行而导致的访问,这些访问实际上在执行的代码路径中永远不会发生。但是,除非您仅在已知的微架构上执行此更强的行为,否则依赖此更强的行为将是一个错误。 AMD K8 / K10与英特尔类似,但Bulldozer系列进行推测而没有任何检测+回滚机制来提供一致性,因此Win9x内核代码在该硬件上不安全。未来的英特尔硬件也可能放弃检测+回滚机制。总之,所有uarches都实现了x86 ISA所说的内容,但有些提供了更强的保证。如果您像微软一样大,英特尔和AMD将设计CPU以复制您的代码依赖的非ISA保证行为,至少直到该软件过时。无法真正保证未来的Intel uarches将保留回滚机制。如果英特尔再次从头开始重新设计(例如P4 / NetBurst而不仅仅是在现有的Sandybridge uarch系列上构建),那么他们有可能改变某些东西。
另一个例子:当输入为零时,bsf 指令会使输出未定义根据英特尔指令参考手册中的规范。但对于任何特定的 CPU,都会有一些行为模式,比如将输出设置为零或保持不变。在理论上,乱序执行 CPU 可以真正给出不同的、不可预测的结果,因为微体系结构状态不同。但英特尔选择在硅上实现的行为是,当 bsfbsr 输入为零时,始终保持目标不变。AMD 也是如此,并且甚至记录了这种行为。基本上,这是一个非官方的保证,即 mov eax,32 / bsf eax, ebx 将与 tzcnt 完全相同(除了标志设置,例如基于输入为 0 而不是输出的 ZF)。

这就是为什么popcnt / lzcnt / tzcnt在英特尔CPU中对输出寄存器存在虚假依赖的原因!

CPU供应商通常会超越纸面ISA规范,以避免破坏一些依赖于此行为的现有代码(例如,如果该代码是Windows或其他重要软件的一部分,Intel / AMD会在其新CPU设计上进行测试)。

正如Andy Glew在评论线程中所说关于上述相关页面访问事项和自修改代码:

一个特定的实现经常需要实现与体系结构语句兼容但更强的规则。但并非所有实现都必须以相同的方式执行。


所以根据你的帖子和你提供的另一个链接还有这个链接:https://dev59.com/sYrda4cB1Zd3GeqPHhJC?rq=1可以得出结论,真正的Intel64和AMD64 ISA在95%方面是相同的,只是各自添加了一些小差异和扩展。 - Jason
2
@Jason:是的,绝对没错。我认为至少有99%是相同的。没有人会为Intel64和AMD64分别发布不同的程序版本。例如,Linux发行版甚至使用相同的内核。可能会有“通用”内核和“低延迟”核心之分,但没有Intel和AMD之分。 - Peter Cordes
1
@Jason:更新了一个例子,说明了ISA在纸面上的规定和硬件设计师选择在实际CPU中实现的保证之间的差异。 - Peter Cordes
太棒了。而且你说得很对,没有人真正发布不同的x86构建版本。 - Jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接