class IrvmFrame(Frame): """Frame for an ARM function.""" # Word size for the target architecture. word_size = 4 param_regs = [Temp("i%d" % i) for i in range(4)] # Predefined registers used at many places. rv = Temp("rv") sp = Temp("sp") fp = Temp("fp") # List of callee save registers. callee_save = [] # List of caller save registers. # caller_save = list(Temp("i%d" % i) for i in range(0, 4)) caller_save = [] def __init__(self, label): super().__init__(label) self.end_label = Label("end") def wrap_result(self, sxp): super().wrap_result(sxp) return MOVE(TEMP(self.rv), sxp) def label_name(self, suffix): return "L%s" % suffix def allocate_frame_size(self): return MOVE(TEMP(self.sp), BINOP('-', TEMP(self.sp), CONST(self.offset)))
class ArmFrame(Frame): """Frame for an ARM function.""" # Word size for the target architecture. word_size = 4 param_regs = [Temp("r0"), Temp("r1"), Temp("r2"), Temp("r3")] # Predefined registers used at many places. r0 = Temp("r0") lr = Temp("lr") sp = Temp("sp") fp = Temp("r11") # List of callee save registers. callee_save = list(Temp("r%d" % i) for i in range(4, 11)) # List of caller save registers. caller_save = list(Temp("r%d" % i) for i in range(0, 4)) def __init__(self, label): super().__init__(label) def wrap_result(self, sxp): super().wrap_result(sxp) return MOVE(TEMP(self.r0), sxp)
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 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]
class IrvmFrame(Frame): """Frame for a function.""" # Word size for the target architecture. word_size = 4 # Infinite number of parameter registers in IRVM. 128 is close # enough to infinity, right? param_regs = [Temp("i%d" % i) for i in range(128)] # Predefined registers used at many places. rv = Temp("rv") sp = Temp("sp") fp = Temp("fp") # List of callee save registers. callee_save = [] # List of caller save registers. # caller_save = list(Temp("i%d" % i) for i in range(0, 4)) caller_save = [] def __init__(self, label): super().__init__(label) self.end_label = Label("end") def wrap_result(self, sxp): super().wrap_result(sxp) return MOVE(TEMP(self.rv), sxp) def label_name(self, suffix): return "L%s" % suffix 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 []
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 __init__(self, prefix=None): self.temp = TEMP(Temp.create(prefix))
class ArmFrame(Frame): """Frame for an ARM function.""" # Word size for the target architecture. word_size = 4 param_regs = [Temp("r0"), Temp("r1"), Temp("r2"), Temp("r3")] # Predefined registers used at many places. r0 = Temp("r0") lr = Temp("lr") sp = Temp("sp") fp = Temp("r11") # List of callee save registers (the frame pointer is handled separately). callee_save = list(Temp("r%d" % i) for i in range(4, 11)) # List of caller save registers. caller_save = list(Temp("r%d" % i) for i in range(4)) + [lr] # All physical registers appearing in code, used for register allocation. registers = list(Temp("r%d" % i) for i in range(11)) + [sp, lr, fp] def __init__(self, label): super().__init__(label) def wrap_result(self, sxp): super().wrap_result(sxp) return MOVE(TEMP(self.r0), sxp) 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 epilogue(self, data): return [LABEL(self.restore_label)] + data + [LABEL(self.end_label)] def load_spill(self, temp, offset): assert isinstance(temp, Temp) assert isinstance(offset, int) return [ O("ldr {{}}, [{{}}, #{:d}]".format(offset), dsts=[temp], srcs=[self.fp]) ] def save_spill(self, temp, offset): assert isinstance(temp, Temp) assert isinstance(offset, int) return [ O("str {{}}, [{{}}, #{:d}]".format(offset), srcs=[temp, self.fp]) ] def reserve_stack_space(self): return [O("add {{}}, {{}}, #-{}".format(self.offset), dsts=[self.sp], srcs=[self.sp])] \ if self.offset else []