在编译器设计中,为什么调用者不能通过调用者或被调用者寄存器保存安排来调用,而是调用者不能将其使用的寄存器列表(它将在调用者保存安排的情况下推送)传递给被调用者,以便被调用者可以比较其已使用的寄存器列表,用于调用者使用的寄存器.然后只推送真正需要推送的寄存器.我错过了什么吗?
这是一个有趣的想法.我认为有两件事情使它不那么有吸引力:
无论如何,被调用者必须为最坏的情况保留堆栈空间.
为了提高效率,您需要一次性存储和加载寄存器组的特殊指令.这些说明在摩托罗拉68000(也可能是PowerPC)上,但它们并不受欢迎.
下面是一些如何工作的详细说明:您希望调用者将列表打包为机器字作为位向量.然后,您将需要被调用者按位并且使用其自己的列表,具有保存由结果位向量命名的所有寄存器的指令.
因为在最坏的情况下你将不得不在堆栈上保留空间,所以你不需要节省太多 - 在一个现代的超标量无序处理器上,写入相同的高速缓存行几乎是免费的.
如果您真正想要的是在运行时最小化加载和存储的数量,那么您也可以使用所有调用者保存寄存器.这种策略也使得引发异常和抢先切换线程变得非常便宜,而且大量的编译器(如OCaml)也因此使用它.Callee-saves寄存器是一种试图减少溢出和重载指令的代码大小的黑客.它们在许多情况下工作,并且它们节省空间,因为呼叫站点远远超过过程定义(平均而言,过程包含多个呼叫).
有关调用者保存和被调用者保存寄存器之间权衡的更多信息,杰克戴维森和大卫沃利都有一篇很好的论文.