/* * StackFrameManager.cc - Implementation of the StackFrameManager class * * Part of the assignment of the Compiler Construction course * LIACS, Leiden University */ #include "StackFrameManager.h" #include "globals.h" #include "MOperator.h" #include "MOperand.h" #include "AssemblerCode.h" #include "assert.h" // Constructor: StackFrameManager::StackFrameManager(AssemblerCode& ac) : currentSubprogram(NULL), ac(ac), frameSize(12), localFrameSize(12), raOffset(0), fpOffset(-4), rvOffset(-8) { } // Destructor: StackFrameManager::~StackFrameManager() { } // Analyzes a subprogram and computes the stack frame layout. // This function should always be called once for a subprogram before // calls to GeneratePrologue/Epilogue or GenerateLocalAddress are made. void StackFrameManager::AnalyzeSubprogram(SymbolTable * symtab, Symbol * subprogram) { bool isProgramBody = false; currentSubprogram = subprogram; if (subprogram->GetSymbolType() == ST_PROGRAM) { isProgramBody = true; } frameSize = 12; // 12 for return address, old frame pointer and return value localFrameSize = frameSize; // set return value offset subprogram->SetOffset(rvOffset); if (!isProgramBody) { // set parameter offsets and count frameSize int offset = 4; for (int i = 0; i < subprogram->GetParameterCount(); ++i) { Symbol *symbol = subprogram->GetParameter(i); symbol->SetOffset(offset); offset += 4; frameSize += 4; } // count and set offsets for local variables and temporary variables Scope *scope = symtab->GetScope(subprogram->GetName()); offset = -12; for (unsigned int i = 0; i < scope->GetNumberOfSymbols(); ++i) { Symbol *symbol = scope->GetSymbol(i); if (symbol->GetSymbolType() == ST_VARIABLE || symbol->GetSymbolType() == ST_TEMPVAR) { symbol->SetOffset(offset); offset -= 4; frameSize += 4; localFrameSize += 4; } } } else { // for main program body only set temporary variable offsets Scope *scope = symtab->GetScope(subprogram->GetName()); int offset = -12; for (unsigned int i = 0; i < scope->GetNumberOfSymbols(); ++i) { assert(offset != 0); Symbol *symbol = scope->GetSymbol(i); if (symbol->GetSymbolType() == ST_TEMPVAR) { symbol->SetOffset(offset); offset -= 4; frameSize += 4; localFrameSize += 4; } } } } // Generates the code that sets up the stack frame at the entry point of a // subprogram. void StackFrameManager::GeneratePrologue(FILE *) { // Indicate the beginning of a new subprogram: ac.AppendStatement(new MStatement(MOP_ENT, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + currentSubprogram->GetName() ))); MStatement *stmt = new MStatement(MOP_LABEL); stmt->SetLabel(string(SYMBOL_PREFIX) + currentSubprogram->GetName()); ac.AppendStatement(stmt); // Save the return address on the stack ac.AppendStatement(new MStatement(MOP_SW, new MOperand(MT_REGISTER, R_RA), new MOperand(MT_OFFSET, R_SP, raOffset), "Set up stack frame")); // Save the old frame pointer on the stack ac.AppendStatement(new MStatement(MOP_SW, new MOperand(MT_REGISTER, R_FP), new MOperand(MT_OFFSET, R_SP, fpOffset))); // Setting the new frame pointer value ac.AppendStatement(new MStatement(MOP_MOVE, new MOperand(MT_REGISTER, R_FP), new MOperand(MT_REGISTER, R_SP))); // Setting the new stack pointer value ac.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_SP), new MOperand(MT_REGISTER, R_SP), new MOperand(MT_INT, -localFrameSize))); } // Generates the code that discards the stack frame at the leaving point of // a subprogram. void StackFrameManager::GenerateEpilogue(FILE *) { // Restore the return address ac.AppendStatement(new MStatement(MOP_LW, new MOperand(MT_REGISTER, R_RA), new MOperand(MT_OFFSET, R_FP, raOffset), "Return from call")); // Restore the old frame pointer ac.AppendStatement(new MStatement(MOP_LW, new MOperand(MT_REGISTER, R_FP), new MOperand(MT_OFFSET, R_FP, fpOffset))); // Set the new stack pointer value ac.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_SP), new MOperand(MT_REGISTER, R_SP), new MOperand(MT_INT, frameSize))); // Jump back to the return address ac.AppendStatement(new MStatement(MOP_JR, new MOperand(MT_REGISTER, R_RA))); // Indicate the end of this subprogram: ac.AppendStatement(new MStatement(MOP_END, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + currentSubprogram->GetName() ))); } // Generates a $fp-relative address for a local variable or parameter. // The output can be used directly as an operand for load/store instructions. void StackFrameManager::GenerateLocalAddress(FILE * out, Symbol * sym) { int offset = 0; offset = sym->GetOffset(); // Now write the address to the output file: fprintf(out, "%d($fp)", offset); }