我一直在尝试理解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之上弹出所有值如果我的问题很清楚,我将不胜感激任何反馈。
答案 0 :(得分:2)
如果你的计算实际上是纯粹的功能(变量只分配一次),那么你总是可以将计算安排为一个表达式树(变量赋值已经消失)并用堆栈机器以明显的方式对它进行评估。没有其他的。您仍然需要一条指令来推送堆栈上已经初始化的变量的值,也就是说,可以引用堆栈外的区域。
这很好但不现实。大多数语言都有用于副作用的作业,以记住状态;编译器可能检测到您有一个公共子表达式,计算结果,存储到一个临时用于以后使用,等等。显然,这些分配的目标存储器位置不能在堆栈中,不会使简单的堆栈机器评估过程更加复杂,这避免了它的漂亮,可能会损害性能。 (如果我们在演出后表现得很认真,我们就会使用注册机器。)
最终变量需要"长期存储" (相对于堆栈机器指令的某些子序列的评估持续时间)需要存储在存储器中"外部"堆栈。编译器可以为每个变量名称分配该外部区域中的唯一位置;小心翼翼地,它可以以一种不是" live"的变量的方式分配这些位置。同时可以使用相同的内存位置,最小化外部区域的大小。您已经需要一条指令来从堆栈外部加载值(" push");任何现实的架构都会相应地具有将最高值存储到该区域的指令(" pop")。
某些堆栈计算机体系结构允许推送堆栈中已有的任何操作数;容易推广到存储到堆栈中已经存在的任何操作数(槽)中。这只是一个混合组合"在堆栈内#34;和#34;在堆栈外面#34 ;;你可以随时奉献远方"底部"堆栈作为一个区域,你只能以非堆栈方式使用。但这只是模拟堆栈外的#34;。