我一直在尝试了解MIPS堆栈机的代码生成,其中有一个累加器寄存器,该寄存器用于存储操作结果,并且指令的第二个操作数必须从堆栈中弹出。
大多数讲座和视频似乎都在谈论类似x +(y + z)的指令序列,然后继续解释如何将x推入堆栈,然后y跟随我的加载z到累加器...等等向前。

但是,在这种情况下有点困惑。
假设在下面的代码中没有进行像常量折叠这样的优化。

A = 2 + 3
X = 1 + 1
....  // More random instructions
B = 4 + 5
C = A + 2
D = B + 1
E = C + D


因此,在此指令序列中,每个操作的结果都不会在下一条指令中使用。所以我的猜测是必须将它们推入堆栈。
问题是如何取回它们?例如,已经计算出A。现在是否为A维护了一个符号表,以将其值压入堆栈?
如果是这样,这对于SSA IR会很好,但是在存在控制流的情况下不使用SSA怎么办?
我知道MIPS的lw&sw指令会加载一些偏移量,但让我们说一下基础架构是否不支持这种指令。在那种情况下,每当我们必须检索A时,是否将所有值都弹出A上?

如果您对此问题的工作方式以及我的问题是否足够清楚,我将不胜感激。

最佳答案

如果您的计算实际上是纯函数式的(变量仅分配一次),那么您始终可以将计算安排为表达式树(变量分配消失了),然后使用堆栈机以明显的方式对其进行求值,而没有其他方法。您仍然需要一条指令将已初始化的变量的值压入堆栈,即可以引用堆栈外部区域的变量。

很好,但不现实。大多数语言都有用于副作用的作业,以记住状态。编译器可能会检测到您有一个公共子表达式,计算结果,将其存储到临时存储器中以备后用,等等。显然,如果不通过某种方式使简单的堆栈计算机评估过程变得更加复杂,此类分配的目标内存位置就不会在堆栈中,并且避免了它的美感,并可能会损害性能。 (如果我们认真追求性能,我们将使用套准机)。

最终,需要“长期存储”的变量(相对于堆栈机器指令某些子序列的评估持续时间)需要存储在堆栈“外部”的存储器中。编译器可以为每个变量名称在该外部区域中分配一个唯一的位置。小心地,它可以以这样一种方式分配这样的位置:不在同一时间“不活动”的变量可以使用相同的内存位置,从而最小化该外部区域的大小。您已经需要一条指令来从堆栈外部加载值(“ push”);任何现实的体系结构都将相应地具有将最高值存储到该区域的指令(“ pop”)。

一些堆栈计算机体系结构允许压入堆栈中已经存在的任何操作数。容易推广到存储在堆栈中已存在的任何操作数(插槽)中。这只是“堆栈内部”和“堆栈外部”的组合。您始终可以将堆栈的远处“底部”指定为仅以非堆栈式方式使用的区域。但这只是模拟“堆栈外部”。

10-07 19:21
查看更多