def _recover(self, pseudo_register):
        """ Handles the logic for reversing the spilling of a register.

        :param pseudo_register: The name of the pseudo-register whose spilled value is being recovered.
        :return: A tuple containing the physical register and a list of the MIPS code required to free the physical
                 register for use.
        """

        spill_offset = self.spilled_registers.pop(pseudo_register)
        physical_register = None
        code = [
            mi.COMMENT("recovering pseudo-register {}".format(pseudo_register))
        ]

        if self.available_registers:
            physical_register = self.available_registers.pop()
            self.lru_cache[pseudo_register] = physical_register

        else:
            self.lru_cache[pseudo_register] = None
            physical_register = self._freed_physical_register

            code.extend(self._spill_code)

            self.lru_cache[pseudo_register] = physical_register

            code.append(
                mi.LW(physical_register, mi.offset_label_immediate(self.spill_mem_base_label, spill_offset)))

        self.available_spill_memory_words.append(spill_offset)

        return physical_register, code
Beispiel #2
0
    def test_multiple_recoveries(self):
        spilled_1 = 'ireg_1'
        spilled_2 = 'ireg_2'
        spiller_1 = 'ireg_3'
        spiller_2 = 'ireg_4'

        self.register_use_table.acquire(spilled_1)
        self.register_use_table.acquire(spilled_2)
        self.register_use_table.acquire(spiller_1)
        self.register_use_table.acquire(spiller_2)

        self.assertTrue(
            spilled_1 in self.register_use_table.spilled_registers.keys()
            and spilled_2 in self.register_use_table.spilled_registers.keys())

        result = self.register_use_table.acquire(spilled_2)
        expected_result = {
            'register':
            mips.T0,
            'code': [
                assembler.SW(
                    mips.T0,
                    assembler.offset_label_immediate(SPILL_MEM_LABEL, 8)),
                assembler.LW(
                    mips.T0,
                    assembler.offset_label_immediate(SPILL_MEM_LABEL, 4))
            ]
        }
        self.assertEqual(expected_result, result)

        result = self.register_use_table.acquire(spilled_1)
        expected_result = {
            'register':
            mips.T1,
            'code': [
                assembler.SW(
                    mips.T1,
                    assembler.offset_label_immediate(SPILL_MEM_LABEL, 4)),
                assembler.LW(
                    mips.T1,
                    assembler.offset_label_immediate(SPILL_MEM_LABEL, 0))
            ]
        }
        self.assertEqual(expected_result, result)
    def _load(self, t):
        destination = self.get_resulting_argument(t.dest)
        address = self.get_resulting_argument(t.src1)

        if t.src2 is 1:
            self.mips_output.append(mi.LB(destination, address))
        elif t.src2 is 2:
            self.mips_output.append(mi.LHW(destination, address))
        elif t.src2 is 4:
            self.mips_output.append(mi.LW(destination, address))
Beispiel #4
0
    def test_spill_recovery(self):
        pseudo_registers = [INT_REGISTER_TICKETS.get() for _ in range(0, 3)]

        self.register_use_table.acquire(pseudo_registers[0])
        self.register_use_table.acquire(pseudo_registers[1])

        self.assertSequenceEqual([],
                                 self.register_use_table.available_registers,
                                 'the registers should be used up')

        expected_result = {
            'register':
            mips.T0,
            'code': [
                assembler.SW(
                    mips.T0,
                    assembler.offset_label_immediate(SPILL_MEM_LABEL, 0))
            ]
        }
        result = self.register_use_table.acquire(pseudo_registers[2])
        self.assertEqual(expected_result, result)

        # recovering a spilled register's value from memory should not only get the register, but also provide the
        # mips code that swaps the values for the temporaries using the spill memory
        expected_result = {
            'register':
            mips.T1,
            'code': [
                assembler.SW(
                    mips.T1,
                    assembler.offset_label_immediate(SPILL_MEM_LABEL, 4)),
                assembler.LW(
                    mips.T1,
                    assembler.offset_label_immediate(SPILL_MEM_LABEL, 0))
            ]
        }
        result = self.register_use_table.acquire(pseudo_registers[0])
        self.assertEqual(expected_result, result)
Beispiel #5
0
__print_char_parameter = symbol.VariableSymbol('x', 0, 0)
__print_char_parameter_type = symbol.TypeDeclaration()
__print_char_parameter_type.add_type_specifier('int')
__print_char_parameter.add_type_declaration(__print_char_parameter_type)

PrintCharDeclaration = symbol.FunctionSymbol('print_char', 0, 0)
PrintCharDeclaration.set_named_parameters([__print_char_parameter])
PrintCharDeclaration.add_return_type_declaration(__print_char_return_type)

__print_char_body = [
    mm.CALLEE_FUNCTION_PROLOGUE_MACRO.call('0'),
    mi.COMMENT("load $v0 with the value for the print char syscall"),
    mi.LI(mr.V0, __PRINT_CHAR_SYSCALL),
    mi.COMMENT("the first (and only) argument is the value to print"),
    mi.LW(mr.A0, mi.offset_from_register_with_immediate(mr.FP)),
    mi.SYSCALL(),
    mm.CALLEE_FUNCTION_EPILOGUE_MACRO.call()
]
PrintCharDefinition = FunctionDefinition(identifier='print_char',
                                         body=__print_char_body)

#
# PRINT INTEGER
#
__PRINT_INT_SYSCALL = 1

__print_int_return_type = symbol.TypeDeclaration()
__print_int_return_type.add_type_specifier('int')

__print_int_parameter = symbol.VariableSymbol('x', 0, 0)
Beispiel #6
0
    __save_register_macro_instructions.append(
        mi.SUBIU(mr.SP, mr.SP, mr.WORD_SIZE))
if config.NOT_TESTING_FUNCTIONS:
    __save_register_macro_instructions = []
SAVE_REGISTER_MACRO = Macro(name='SAVE_T_REGISTERS',
                            args=None,
                            body=__save_register_macro_instructions)

__restore_register_macro_instructions = [
    mi.COMMENT("brace yourself for a long, unrolled loop...")
]
for __temp_register in reversed(__T_REGISTERS):
    __restore_register_macro_instructions.append(
        mi.ADDIU(mr.SP, mr.SP, mr.WORD_SIZE))
    __restore_register_macro_instructions.append(
        mi.LW(__temp_register, mi.offset_from_register_with_immediate(mr.SP)))
if config.NOT_TESTING_FUNCTIONS:
    __restore_register_macro_instructions = []
RESTORE_REGISTER_MACRO = Macro(name='RESTORE_T_REGISTERS',
                               args=None,
                               body=__restore_register_macro_instructions)

__save_spill_mem_macro_body = [
    mi.COMMENT("brace yourself for a long, unrolled loop...")
]
for i in range(0, config.SPILL_MEM_SIZE, mr.WORD_SIZE):
    __save_spill_mem_macro_body.extend([
        mi.LW(mr.A3, mi.offset_label_immediate('SPILL_MEMORY', i)),
        mi.SW(mr.A3, mi.offset_from_register_with_immediate(mr.SP)),
        mi.SUBIU(mr.SP, mr.SP, mr.WORD_SIZE)
    ])