| 1 | /*
|
---|
| 2 | * StackFrameManager.cc - Implementation of the StackFrameManager class
|
---|
| 3 | *
|
---|
| 4 | * Part of the assignment of the Compiler Construction course
|
---|
| 5 | * LIACS, Leiden University
|
---|
| 6 | */
|
---|
| 7 |
|
---|
| 8 | #include "StackFrameManager.h"
|
---|
| 9 | #include "globals.h"
|
---|
| 10 | #include "MOperator.h"
|
---|
| 11 | #include "MOperand.h"
|
---|
| 12 | #include "AssemblerCode.h"
|
---|
| 13 | #include "assert.h"
|
---|
| 14 |
|
---|
| 15 | // Constructor:
|
---|
| 16 | StackFrameManager::StackFrameManager(AssemblerCode& ac)
|
---|
| 17 | : currentSubprogram(NULL), ac(ac),
|
---|
| 18 | frameSize(12), localFrameSize(12),
|
---|
| 19 | raOffset(0), fpOffset(-4), rvOffset(-8)
|
---|
| 20 | {
|
---|
| 21 | }
|
---|
| 22 |
|
---|
| 23 |
|
---|
| 24 | // Destructor:
|
---|
| 25 | StackFrameManager::~StackFrameManager() {
|
---|
| 26 | }
|
---|
| 27 |
|
---|
| 28 |
|
---|
| 29 | // Analyzes a subprogram and computes the stack frame layout.
|
---|
| 30 | // This function should always be called once for a subprogram before
|
---|
| 31 | // calls to GeneratePrologue/Epilogue or GenerateLocalAddress are made.
|
---|
| 32 | void StackFrameManager::AnalyzeSubprogram(SymbolTable * symtab, Symbol * subprogram) {
|
---|
| 33 | bool isProgramBody = false;
|
---|
| 34 |
|
---|
| 35 | currentSubprogram = subprogram;
|
---|
| 36 |
|
---|
| 37 | if (subprogram->GetSymbolType() == ST_PROGRAM) {
|
---|
| 38 | isProgramBody = true;
|
---|
| 39 | }
|
---|
| 40 |
|
---|
| 41 | frameSize = 12; // 12 for return address, old frame pointer and return value
|
---|
| 42 | localFrameSize = frameSize;
|
---|
| 43 |
|
---|
| 44 | // set return value offset
|
---|
| 45 | subprogram->SetOffset(rvOffset);
|
---|
| 46 |
|
---|
| 47 | if (!isProgramBody) {
|
---|
| 48 |
|
---|
| 49 | // set parameter offsets and count frameSize
|
---|
| 50 | int offset = 4;
|
---|
| 51 | for (int i = 0; i < subprogram->GetParameterCount(); ++i) {
|
---|
| 52 | Symbol *symbol = subprogram->GetParameter(i);
|
---|
| 53 | symbol->SetOffset(offset);
|
---|
| 54 | offset += 4;
|
---|
| 55 | frameSize += 4;
|
---|
| 56 | }
|
---|
| 57 | // count and set offsets for local variables and temporary variables
|
---|
| 58 | Scope *scope = symtab->GetScope(subprogram->GetName());
|
---|
| 59 | offset = -12;
|
---|
| 60 | for (unsigned int i = 0; i < scope->GetNumberOfSymbols(); ++i) {
|
---|
| 61 | Symbol *symbol = scope->GetSymbol(i);
|
---|
| 62 | if (symbol->GetSymbolType() == ST_VARIABLE || symbol->GetSymbolType() == ST_TEMPVAR) {
|
---|
| 63 | symbol->SetOffset(offset);
|
---|
| 64 | offset -= 4;
|
---|
| 65 | frameSize += 4;
|
---|
| 66 | localFrameSize += 4;
|
---|
| 67 | }
|
---|
| 68 | }
|
---|
| 69 | } else {
|
---|
| 70 | // for main program body only set temporary variable offsets
|
---|
| 71 | Scope *scope = symtab->GetScope(subprogram->GetName());
|
---|
| 72 | int offset = -12;
|
---|
| 73 | for (unsigned int i = 0; i < scope->GetNumberOfSymbols(); ++i) {
|
---|
| 74 | assert(offset != 0);
|
---|
| 75 | Symbol *symbol = scope->GetSymbol(i);
|
---|
| 76 | if (symbol->GetSymbolType() == ST_TEMPVAR) {
|
---|
| 77 | symbol->SetOffset(offset);
|
---|
| 78 | offset -= 4;
|
---|
| 79 | frameSize += 4;
|
---|
| 80 | localFrameSize += 4;
|
---|
| 81 | }
|
---|
| 82 | }
|
---|
| 83 | }
|
---|
| 84 |
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 |
|
---|
| 88 | // Generates the code that sets up the stack frame at the entry point of a
|
---|
| 89 | // subprogram.
|
---|
| 90 | void StackFrameManager::GeneratePrologue(FILE *) {
|
---|
| 91 | // Indicate the beginning of a new subprogram:
|
---|
| 92 | ac.AppendStatement(new MStatement(MOP_ENT, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + currentSubprogram->GetName() )));
|
---|
| 93 | MStatement *stmt = new MStatement(MOP_LABEL);
|
---|
| 94 | stmt->SetLabel(string(SYMBOL_PREFIX) + currentSubprogram->GetName());
|
---|
| 95 | ac.AppendStatement(stmt);
|
---|
| 96 |
|
---|
| 97 | // Save the return address on the stack
|
---|
| 98 | ac.AppendStatement(new MStatement(MOP_SW, new MOperand(MT_REGISTER, R_RA), new MOperand(MT_OFFSET, R_SP, raOffset), "Set up stack frame"));
|
---|
| 99 | // Save the old frame pointer on the stack
|
---|
| 100 | ac.AppendStatement(new MStatement(MOP_SW, new MOperand(MT_REGISTER, R_FP), new MOperand(MT_OFFSET, R_SP, fpOffset)));
|
---|
| 101 | // Setting the new frame pointer value
|
---|
| 102 | ac.AppendStatement(new MStatement(MOP_MOVE, new MOperand(MT_REGISTER, R_FP), new MOperand(MT_REGISTER, R_SP)));
|
---|
| 103 | // Setting the new stack pointer value
|
---|
| 104 | ac.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_SP), new MOperand(MT_REGISTER, R_SP), new MOperand(MT_INT, -localFrameSize)));
|
---|
| 105 | }
|
---|
| 106 |
|
---|
| 107 |
|
---|
| 108 | // Generates the code that discards the stack frame at the leaving point of
|
---|
| 109 | // a subprogram.
|
---|
| 110 | void StackFrameManager::GenerateEpilogue(FILE *) {
|
---|
| 111 | // Restore the return address
|
---|
| 112 | ac.AppendStatement(new MStatement(MOP_LW, new MOperand(MT_REGISTER, R_RA), new MOperand(MT_OFFSET, R_FP, raOffset), "Return from call"));
|
---|
| 113 | // Restore the old frame pointer
|
---|
| 114 | ac.AppendStatement(new MStatement(MOP_LW, new MOperand(MT_REGISTER, R_FP), new MOperand(MT_OFFSET, R_FP, fpOffset)));
|
---|
| 115 | // Set the new stack pointer value
|
---|
| 116 | ac.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_SP), new MOperand(MT_REGISTER, R_SP), new MOperand(MT_INT, frameSize)));
|
---|
| 117 | // Jump back to the return address
|
---|
| 118 | ac.AppendStatement(new MStatement(MOP_JR, new MOperand(MT_REGISTER, R_RA)));
|
---|
| 119 |
|
---|
| 120 | // Indicate the end of this subprogram:
|
---|
| 121 | ac.AppendStatement(new MStatement(MOP_END, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + currentSubprogram->GetName() )));
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 |
|
---|
| 125 | // Generates a $fp-relative address for a local variable or parameter.
|
---|
| 126 | // The output can be used directly as an operand for load/store instructions.
|
---|
| 127 | void StackFrameManager::GenerateLocalAddress(FILE * out, Symbol * sym) {
|
---|
| 128 | int offset = 0;
|
---|
| 129 |
|
---|
| 130 | offset = sym->GetOffset();
|
---|
| 131 |
|
---|
| 132 | // Now write the address to the output file:
|
---|
| 133 | fprintf(out, "%d($fp)", offset);
|
---|
| 134 | }
|
---|