Example #1
0
 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]
Example #2
0
    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)
Example #3
0
 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
Example #4
0
    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)]
Example #5
0
    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
Example #6
0
 def allocate_frame_size(self):
     return MOVE(TEMP(self.sp), BINOP('-', TEMP(self.sp),
                                      CONST(self.offset)))
Example #7
0
 def wrap_result(self, sxp):
     super().wrap_result(sxp)
     return MOVE(TEMP(self.rv), sxp)
Example #8
0
 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 []