#include "RegisterManager.h" #include "Symbol.h" #include "StackFrameManager.h" #include "types.h" #include "debug.h" #include using namespace std; bool IsGlobal(Symbol * sym); // Is the specified symbol a global variable? MRegisterType RegisterManager::int_registers[int_reg_size] = { R_T0, R_T1, R_T2, R_T3, R_T4, R_T5, R_T6, R_T7, R_S0, R_S1, R_S2, R_S3, R_S4, R_S5, R_S6, R_S7, R_T8, R_T9 }; // According to the spim documentation all floating point operations use only // even registers, as doubles require two. Even for operations on singles. MRegisterType RegisterManager::float_registers[float_reg_size] = { // R_FO, /* Claimed for temporary use within code */ R_F2, R_F4, R_F6, R_F8, R_F10, R_F12, R_F14, R_F16, R_F18, R_F20, R_F22, R_F24, R_F26, R_F28, R_F30 }; MRegisterType RegisterManager::tmp_registers[tmp_reg_size] = { R_A0, R_A1, R_A2, R_A3 }; RegisterManager::RegisterManager(StackFrameManager& sfm, AssemblerCode& ac) : sfm(sfm), ac(ac), int_symbols(), float_symbols() { } MRegisterType RegisterManager::GetRegister(Symbol *symbol) { if (symbol->GetReturnType() == RT_REAL) { return GetFloatRegister(symbol); } return GetIntRegister(symbol); } MRegisterType RegisterManager::GetIntRegister(Symbol *symbol) { int idx = FindSymbol(int_symbols, int_reg_size, symbol); if (idx != -1) { return int_registers[idx]; } // symbol not yet used idx = FindUnused(int_symbols, int_reg_size); if (idx == -1) { // no more unused registers idx = PickSpillRegister(int_registers, int_reg_size); SpillIntRegister(idx); } GenerateIntLoadCode(int_registers[idx], symbol); int_symbols[idx] = symbol; return int_registers[idx]; } MRegisterType RegisterManager::GetFloatRegister(Symbol *symbol) { int idx = FindSymbol(float_symbols, float_reg_size, symbol); if (idx != -1) { return float_registers[idx]; } // symbol not yet used idx = FindUnused(float_symbols, float_reg_size); if (idx == -1) { // no more unused registers idx = PickSpillRegister(float_registers, float_reg_size); SpillFloatRegister(idx); } GenerateFloatLoadCode(float_registers[idx], symbol); float_symbols[idx] = symbol; return float_registers[idx]; } void RegisterManager::SpillAll() { for (int i = 0; i < int_reg_size; ++i) { if (int_symbols[i] != NULL) { SpillIntRegister(i); } } for (int i = 0; i < float_reg_size; ++i) { if (float_symbols[i] != NULL) { SpillFloatRegister(i); } } } int RegisterManager::FindSymbol(Symbol *symbols[], int size, Symbol *symbol) const { for (int i = 0; i < size; ++i) { if (symbols[i] != NULL && symbols[i]->GetName() == symbol->GetName()) { return i; } } return -1; } int RegisterManager::FindUnused(Symbol *symbols[], int size) const { for (int i = 0; i < size; ++i) { if (symbols[i] == NULL) { return i; } } return -1; } int RegisterManager::PickSpillRegister(MRegisterType [], int size) const { return rand() % size; } void RegisterManager::SpillIntRegister(int idx) { GenerateIntSpillCode(int_registers[idx], int_symbols[idx]); int_symbols[idx] = NULL; } void RegisterManager::SpillFloatRegister(int idx) { GenerateFloatSpillCode(float_registers[idx], float_symbols[idx]); float_symbols[idx] = NULL; } void RegisterManager::GenerateIntSpillCode(MRegisterType reg, Symbol *symbol) { if (IsGlobal(symbol)) { string name = SYMBOL_PREFIX; name += symbol->GetName(); MOperator instr; MOperand *mop1, *mop2; instr = MOP_SW; mop1 = new MOperand(MT_REGISTER, reg); mop2 = new MOperand(MT_LABEL, name); ac.AppendStatement(new MStatement(instr, mop1, mop2, "Write back integer register")); } else { int offset = symbol->GetOffset(); MOperator instr; MOperand *mop1, *mop2; instr = MOP_SW; mop1 = new MOperand(MT_REGISTER, reg); mop2 = new MOperand(MT_OFFSET, R_FP, offset); ac.AppendStatement(new MStatement(instr, mop1, mop2, "Write back integer register")); } } void RegisterManager::GenerateFloatSpillCode(MRegisterType reg, Symbol *symbol) { if (IsGlobal(symbol)) { string name = SYMBOL_PREFIX; name += symbol->GetName(); MOperator instr; MOperand *mop1, *mop2; instr = MOP_S_S; mop1 = new MOperand(MT_REGISTER, reg); mop2 = new MOperand(MT_LABEL, name); ac.AppendStatement(new MStatement(instr, mop1, mop2, "Write back float register")); } else { int offset = symbol->GetOffset(); MOperator instr; MOperand *mop1, *mop2; instr = MOP_S_S; mop1 = new MOperand(MT_REGISTER, reg); mop2 = new MOperand(MT_OFFSET, R_FP, offset); ac.AppendStatement(new MStatement(instr, mop1, mop2, "Write back float register")); } } void RegisterManager::GenerateIntLoadCode(MRegisterType reg, Symbol *symbol) { if (IsGlobal(symbol)) { string name = SYMBOL_PREFIX; name += symbol->GetName(); MOperator instr; MOperand *mop1, *mop2; instr = MOP_LW; mop1 = new MOperand(MT_REGISTER, reg); mop2 = new MOperand(MT_LABEL, name); ac.AppendStatement(new MStatement(instr, mop1, mop2, "Load integer Register")); } else { int offset = symbol->GetOffset(); MOperator instr; MOperand *mop1, *mop2; instr = MOP_LW; mop1 = new MOperand(MT_REGISTER, reg); mop2 = new MOperand(MT_OFFSET, R_FP, offset); ac.AppendStatement(new MStatement(instr, mop1, mop2, "Load integer Register")); } } void RegisterManager::GenerateFloatLoadCode(MRegisterType reg, Symbol *symbol) { if (IsGlobal(symbol)) { string name = SYMBOL_PREFIX; name += symbol->GetName(); MOperator instr; MOperand *mop1, *mop2; instr = MOP_L_S; mop1 = new MOperand(MT_REGISTER, reg); mop2 = new MOperand(MT_LABEL, name); ac.AppendStatement(new MStatement(instr, mop1, mop2, "Load float Register")); } else { int offset = symbol->GetOffset(); MOperator instr; MOperand *mop1, *mop2; instr = MOP_L_S; mop1 = new MOperand(MT_REGISTER, reg); mop2 = new MOperand(MT_OFFSET, R_FP, offset); ac.AppendStatement(new MStatement(instr, mop1, mop2, "Load float Register")); } } MRegisterType RegisterManager::GetTempRegister(){ /* Ping pong between two active registers as temporary storage */ static int currentRegister = -1; currentRegister = (currentRegister == 4) ? 0 : currentRegister+1; pmesg(100, "DEBUG: %i\n", currentRegister); return(tmp_registers[currentRegister]); }