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 | }
|
---|