这个套路感觉是编译原理经典考法 cgen(f(e1, e2) = e) 然后有一个不知名的layout给你
f(e1, e2) = e e是不是指的是body啊。。。
第一步:把frame pointer的值【也就是上一个frame的地方。】放入stack 顶部,这样我们可以记得上一层的stack frame是哪里开始的。
然后我们进入执行函数:
首先codeGeneration e1, 可以认为是evaluate e1. 得到第一个参数的值,放入stack顶部。
然后code Generate e2, 得到第二个参数的值,放入stack 顶部。
在进入codeGeneration e的时候,$FP是不会变化的!但是在进入function以后,FP是会变化的。他这个答案比较奇怪的写法是,他先把old frame value 写入stack,但是一直没搞一个新的$fp的值。直到进入func前才让$FP指向current scope stack 的第一个元素。
这时候再跳转到f 地址里去执行函数。 执行完毕之后,用jal 赋值好的$ra回到当前frame的下一个instruction。 然后执行move $sp $fp. 把stack pointer指向frame pointer的地方,这个地方里装着old frame 地址。
这时候再lw $fp 0($sp) 把之前存的old frame pointer的值赋值给$fp.
Code Generation第二题:
每次进cgen(e)之前 似乎是最好把$a0 save一下。然后cgen 里所有stack的调整都要手动。
下面这道题发现了一个规律:
save fp, save ra 永远是callee干的事情, caller 只管eval arguments, jal into function, recover back fp, sp. 似乎。
【what about arguments?】
所以function一进去第一步永远是把ra save进 $sp底部。然后如果想要access pass进的参数的话,需要4($sp/fp)那个地方去取。。
然后cgen(func(x)=...) 这个表示的是给这个function generate code,不代表去evaluate!只是generate code
move fp sp 这个表示进入一个新的scope了, fp记住起点的地址。。。【为什么这次不是save oldFP了呢。。】
caller side负责储存一下old frame pointer, 然后计算出要pass in的参数是多少, 以reverse older的方式放入Stack.
进入callee, callee第一件事是存下新的frame 进入Fp.
然后把return address也存起来 因为只有在caller jal了以后才知道caller的下一行instruction在哪里,才能知道ra 怎么存。
然后callee在完事以后还要负责load back ra, 以及old frame pointer value.
网友评论