source: liacs/coco/assignment4/StackFrameManager.cc@ 308

Last change on this file since 308 was 2, checked in by Rick van der Zwet, 15 years ago

Initial import of data of old repository ('data') worth keeping (e.g. tracking
means of URL access statistics)

File size: 4.8 KB
RevLine 
[2]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:
16StackFrameManager::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:
25StackFrameManager::~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.
32void 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.
90void 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.
110void 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.
127void 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}
Note: See TracBrowser for help on using the repository browser.