80x87指令集为何采用“基于栈”的设计?

5

当英特尔首次设计8087时,为什么选择将浮点寄存器组织成堆栈?这种设计可能带来什么优势?与允许任意寄存器用作源和目的操作数相比,它似乎不太灵活且更难处理。

(当8087首次被设计时,Intel选择将浮点寄存器组织成堆栈的原因是为了提高程序员的编程效率。通过使用堆栈,程序员可以轻松地保存和恢复浮点值,而不必担心寄存器的编号或寄存器之间的依赖关系。此外,堆栈还可以保证浮点寄存器的使用顺序,从而避免了一些潜在的错误。虽然这种设计可能会限制一些高级编程技术的使用,但对于普通程序员来说,它确实提高了编程效率。)

1
我建议你在电子工程堆栈上提问,但我认为这将归结于晶体管数量的限制。根据Wikipedia的说法,8080有4500个晶体管。到了8088年,它已经增加到29000个晶体管,但我不知道它是否直接与你的问题相关。 - Elliott Frisch
2
请参阅此文档(通过wikipedia找到)。 - Jester
你要求我们回顾历史(没有考虑到技术进步所带来的知识),以确定为什么做出了某个决定。事后诸葛亮很容易,但除非你是通灵者(如果他们真的存在),否则无法预测未来。 - Ken White
@KenWhite,感谢您的反馈。这个问题并不是要求别人成为心理学家或读取设计师的思想。这个想法是:设计选择有利有弊,一个经验丰富的汇编程序员(我不是,但希望能找到)可以理解这些利弊。例如,如果你问我关于Ruby语言中的设计选择,我通常可以提供简明扼要的解释,包括微妙的点,除非你使用该语言已经有几年的时间,否则你可能无法理解。 - Alex D
@Alex:然而,你在询问关于20世纪80年代末/90年代初做出的决策,当时处理器架构与今天完全不同。在1990年,你能知道这个网站会存在,所以你可以在这里提出这个问题吗?我可以对那个问题提供简明扼要的答案:不,我不会知道。你正在要求讨论一个已经过去很久的时间点上做出的决定,而讨论问题在这里是不合适的。 - Ken White
显示剩余4条评论
1个回答

7

这篇文章"论8087堆栈的优势",由@Jester在评论中分享,解释了设计者的思考过程。以下是他们将浮点寄存器组织成堆栈的原因:

  1. 理论上,它可能使过程调用更加高效,因为调用者和被调用者都不需要显式地保存和恢复FP寄存器。需要进行FP计算的被调用者只需将其操作数推入寄存器堆栈,进行计算,并在完成后从堆栈中弹出结果,自动恢复调用者的x87状态。(这与机器堆栈用于函数参数、返回值和局部变量的方式基本相同。)

  2. 考虑到指令已经在8086/8088上编码,以及已经使用的操作码数量,他们只能为8087提供1操作数指令,而不能是2操作数。这在扁平寄存器文件中不起作用。

  3. 他们认为提供FXCH指令会使重新排列x87寄存器堆栈变得简单(这样在需要时可以使用任意对值作为操作数)。此外,FXCH操作是廉价的。


1
我是唯一一个认为80x87是一个好的架构,但却成为了一些相当糟糕的编译器受害者的人吗?如果编译器不允许声明扩展精度变量,并且有时将80位值留在寄存器中,但有时将其“溢出”为32位或64位,则结果语义将是糟糕的,但8x87设计师并不应该受到责备。当人们因为两个浮点数的乘积通常而不总是表现为扩展形式而咒骂8x87时,我感到难过,而不是咒骂不能让他们一致使用扩展形式的语言。 - supercat
1
因此,如果a=1.1;b=0.875;c=0.875;上述计算可能会使用sin(x)的值为0.89120736006143533995来计算“x”,而计算“y”则假定了一个值为(0.89120736006143530527)的值。从这些值中减去0.875将产生不同的“double”值。因此,即使“b”和“c”相等,“x”和“y”也会变得不相等,程序员会咒骂“x”是用“额外”的精度计算出来的这一事实。 - supercat
2
当然,如果该语言实现了long double为80位,并允许程序员编写t=sin(a); x=t+b; y=t+c;,那么结果将是一致的。关于sin(a)是否应返回舍入到64位精度的值的问题可能有点模糊,但将该值(无论是什么)复制到t将确保xy都使用与原始表达式相同的值进行评估。 - supercat
堆栈设计仍然是现代 CPU 的缺点。在当时显然是有意义的,但它没有经受住时间的考验。额外的精度与具有寄存器堆栈无关,因此我们可以在平面寄存器文件中拥有额外的精度,并且有一个快速的指令进行四舍五入。不过,除非你截断它,否则它可能必须远离 0 进行四舍五入并滚动到指数中,因此它可能不像您希望的那样快,但仍然可以比 gcc -ffloat-store 更快,而无需始终禁用额外的精度。 - Peter Cordes
1
@PeterCordes:8087 的设计存在一些失误,但我认为最具讽刺意味的是,人们认为 80 位的 long double 是围绕着 8087 设计的,而实际上它在没有浮点单元的处理器上提供了更大的好处。在我看来,C 应该定义一个 long float 类型,其精度和范围可以介于 floatlong double 之间,并指定对 float 进行的计算升级到 long float,对 double 进行的计算升级到 long double。再结合一种语法来指定可接受类型列表... - supercat
显示剩余4条评论

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