def prologue(self): save_callee_save, restore_callee_save = self.preserve_callee_save() lr_temp = Temp.create("lr_save") save_lr, restore_lr = MOVE(TEMP(lr_temp), TEMP(self.lr)), \ MOVE(TEMP(self.lr), TEMP(lr_temp)) store_parameters = self.transfer_parameters() # The fp save and static link will be saved while generating the code # with ARM specific instructions. return [LABEL(self.label)] + self.allocate_frame_size() + \ [save_lr] + save_callee_save + store_parameters, \ restore_callee_save + [restore_lr]
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 preserve_callee_save(self): """Save all the callee save registers and return a list of move instructions to save them and a list of move instructions to restore them.""" 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) ] return save_callee_save, restore_callee_save
def transfer_parameters(self): """Return a list of move instructions 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 in which the static link has been passed must be handled separately. Relative to the FP, the stack, when we go up, contains: - the static link (offset 0) - the saved frame pointer (offset 1 * word_size) - the first parameter passed on stack (offset 2 * word_size) - the second parameter passed on stack (offset 3 * word_size) … If the architecture does not have a link register, the return address is inserted between the saved frame pointer and the first parameter passed on stack.""" return \ [MOVE(access.toSxp(TEMP(self.fp)), TEMP(self.param_regs[idx + 1]) if idx < self.max_params_in_regs - 1 else InFrame((idx - self.max_params_in_regs + (3 if self.has_lr else 4)) * self.word_size).toSxp(TEMP(self.fp))) for (idx, access) in enumerate(self.param_access)]
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 allocate_frame_size(self): return MOVE(TEMP(self.sp), BINOP('-', TEMP(self.sp), CONST(self.offset)))
def wrap_result(self, sxp): super().wrap_result(sxp) return MOVE(TEMP(self.rv), sxp)
def allocate_frame_size(self): """In IRVM, we know the frame size at this stage already since we have an infinite number of registers and thus no spills.""" return [MOVE(TEMP(self.sp), BINOP('+', TEMP(self.sp), CONST(-self.offset)))] \ if self.offset else []