def _store(self, t):
        # TODO: ensure that the address is handled for all of the variants
        # ($t2), 100($t2), 100, label, label + immediate, label($t2), label + immediate($t2)

        if not isinstance(
                t.dest,
            (taci.Register, str)):  # TODO: refactor so the str is unnecessary
            raise ValueError(
                'The first argument of a store instruction must be a register.'
            )

        if not isinstance(t.src1, taci.Address):
            raise ValueError(
                'The second argument of a store instruction must be an address'
            )

        content = self.get_resulting_argument(t.dest)
        address = self.get_resulting_argument(t.src1)

        # Content and then address
        if t.src2 is 1:
            self.mips_output.append(mi.SB(content, address))
        elif t.src2 is 2:
            self.mips_output.append(mi.SHW(content, address))
        elif t.src2 is 4:
            self.mips_output.append(mi.SW(content, address))
    def _spill(self, pseudo_register, physical_register):
        """ A private method for handling the logic for spilling the contents of a physical register into memory.

        Since this method is used as a callback, it cannot return things in the traditional sense. Because of this, the
        "returned" code and physical register are set to two private class variables, so the programmer must take care
        to manage these variables appropriately.

        :param pseudo_register: The name of the pseudo-register to be spilled. Aka 'key' for the purposes of the
                                pylru.lrucache callback.
        :physical_register: The name of the physical register to be freed/reused. Aka 'value' for the purposes of the
                                pylru.lrucache callback.
        :return: None.
        """

        self._spill_code = []
        self._freed_physical_register = physical_register

        if not self.available_spill_memory_words:
            print(self)
            raise OutOfSpillMemoryException()

        spill_offset = self.available_spill_memory_words.pop()

        self.spilled_registers[pseudo_register] = spill_offset

        self._spill_code = [
            mi.COMMENT("spilling psuedo-register {} to free {}".format(pseudo_register, physical_register)),
            mi.SW(physical_register, mi.offset_label_immediate(self.spill_mem_base_label, spill_offset)),
            mi.COMMENT("spill complete")
        ]
Exemple #3
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)
Exemple #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)
Exemple #5
0
    def test_register_spill(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)
Exemple #6
0
        return [mi.BEGIN_MACRO(self.name, self.args)
                ] + self.body + [mi.END_MACRO()]

    def call(self, *args):
        return mi.CALL_MACRO(self.name, args)


__T_REGISTERS = (mr.T0, mr.T1, mr.T2, mr.T3, mr.T4, mr.T5, mr.T6, mr.T7, mr.T8,
                 mr.T9)

__save_register_macro_instructions = [
    mi.COMMENT("brace yourself for a long, unrolled loop...")
]
for __temp_register in __T_REGISTERS:
    __save_register_macro_instructions.append(
        mi.SW(__temp_register, mi.offset_from_register_with_immediate(mr.SP)))
    __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(