def prologue(self): """Return the function prologue and some opaque value which will be passed to the epilogue. It can be used to pass a register map to be restored from the epilogue for example. In this generic method, we will pass around a list of move instructions needed to restore the callee-save registers and the frame pointer. It is expected that specific frames will generate more specialized prologues, using dedicated instructions such as push and pop that cannot be easily represented using the IR.""" begin_label = LABEL(self.label) # Push the previous frame pointer and the static link to the stack # and setup the new frame pointer. save_fp = [MOVE(TEMP(self.sp), BINOP("+", TEMP(self.sp), CONST(-self.word_size))), MOVE(MEM(TEMP(self.sp)), TEMP(self.fp)), MOVE(TEMP(self.sp), BINOP("+", TEMP(self.sp), CONST(-self.word_size))), MOVE(MEM(TEMP(self.sp)), TEMP(self.param_regs[0])), MOVE(TEMP(self.fp), TEMP(self.sp))] + \ self.allocate_frame_size() restore_fp = [ MOVE(TEMP(self.sp), BINOP("+", TEMP(self.fp), CONST(self.word_size))), MOVE(TEMP(self.fp), MEM(TEMP(self.sp))), MOVE(TEMP(self.sp), BINOP("+", TEMP(self.sp), CONST(self.word_size))) ] # Code to save and restore the callee-save registers. save_callee_save, restore_callee_save = self.preserve_callee_save() # Code to transfer the parameters from registers or call stack into the # register or the frame position they belong to (according to their # Access parameter). The first parameter (r0, in which the static link # had been written) has already been handled above. store_parameters = self.transfer_parameters() return [begin_label] + save_fp + save_callee_save + \ store_parameters, restore_callee_save + restore_fp
def decorate(self, stm): """Decorate the `stm` with code which sets up the frame, the stack pointer, the registers holding the parameters, the preservation of the callee saved registers, and the end label.""" # Begin and end label creation begin_label = [LABEL(self.label)] end_label = [LABEL(self.end_label)] # If we are in the main function, we do not need to save or restore # anything. if self.label.name == 'main': return SEQ(begin_label + [stm] + end_label) # Code to save and restore the previous frame pointer and set-it up # wrt the stack pointer. Also, a label is put at the place where the # frame size will be allocated later (we will only know this # information once all the code has been generated and physical # registers have been allocated). saved_fp = Temp.create("savedfp") save_fp = [ MOVE(TEMP(saved_fp), TEMP(self.fp)), MOVE(TEMP(self.fp), TEMP(self.sp)), self.allocate_frame_size() ] restore_fp = [ MOVE(TEMP(self.sp), TEMP(self.fp)), MOVE(TEMP(self.fp), TEMP(saved_fp)) ] # Code to save the static link register into the frame at offset 0. save_static_link = [MOVE(MEM(TEMP(self.fp)), TEMP(self.param_regs[0]))] # Code to save and restore the callee-save registers. callee_save_map = dict( (reg, Temp.create("callee_save")) for reg in self.callee_save) save_callee_save = [ MOVE(TEMP(callee_save_map[reg]), TEMP(reg)) for reg in self.callee_save ] restore_callee_save = [ MOVE(TEMP(reg), TEMP(callee_save_map[reg])) for reg in reversed(self.callee_save) ] # Code to transfer the parameters from registers or call stack into the # register or the frame position they belong to (according to their # Access parameter). The first parameter (r0, in which the static link # had been written) has already been handled above. store_parameters = \ [MOVE(access.toSxp(self.fp), TEMP(self.param_regs[idx + 1]) if idx < self.max_params_in_regs - 1 else InFrame((idx - self.max_params_in_regs + 1) * self.word_size).toSxp(self.fp)) for (idx, access) in enumerate(self.param_access)] return SEQ(begin_label + save_fp + save_static_link + save_callee_save + store_parameters + [stm] + restore_callee_save + restore_fp + end_label)
def toSxp(self, fp): return MEM(BINOP('+', fp, CONST(self.offset)))
def one_frame_up(self, current_fp): """Return the frame pointer one frame above this one. fp is an Sxp with the current frame pointer, return value is a MEM expression with the frame pointer one level up.""" assert isinstance(current_fp, Sxp), "fp must be an expression" return MEM(current_fp)