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
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))
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)
__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)
__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) ])