source: liacs/coco/assignment4/CodeGenerator.cc@ 385

Last change on this file since 385 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: 27.5 KB
RevLine 
[2]1/*
2 * CodeGenerator.cc - Implementation of the CodeGenerator class
3 *
4 * Part of the assignment of the Compiler Construction course
5 * LIACS, Leiden University
6 */
7
8#include "IStatement.h"
9#include "AssemblerCode.h"
10#include "MStatement.h"
11
12
13#include "CodeGenerator.h"
14#include "globals.h"
15#include <time.h>
16#include <unistd.h>
17#include <cassert>
18
19using namespace std;
20
21bool IsGlobal(Symbol * sym); // Is the specified symbol a global variable?
22
23#define SP_ALTER(offset) fprintf(out, "\taddi\t$sp, $sp, %d\n", offset)
24#define OP1_NAME_C_STR(stmt) stmt->GetOperand1()->GetSymbol()->GetName().c_str()
25#define OP1_NAME_STR(stmt) string(SYMBOL_PREFIX) + stmt->GetOperand1()->GetSymbol()->GetName()
26#define OP2_NAME_C_STR(stmt) stmt->GetOperand2()->GetSymbol()->GetName().c_str()
27#define RESULT_NAME_C_STR(stmt) stmt->GetResult()->GetSymbol()->GetName().c_str()
28
29
30// Constructor
31
32CodeGenerator::CodeGenerator()
33: mCode(), currentFrame(mCode), rManager(currentFrame, mCode) {
34}
35
36
37// Destructor
38
39CodeGenerator::~CodeGenerator() {
40}
41
42
43// Generates a header
44
45void CodeGenerator::GenerateHeader(FILE * out) {
46 time_t rawtime;
47 struct tm * timeinfo;
48
49 time(&rawtime);
50 timeinfo = localtime(&rawtime);
51 char hostname[20];
52 gethostname(hostname, 20);
53
54 fprintf(out, "## Output generated by ./comp @ %s\n", hostname);
55 fprintf(out, "## %s\n", asctime(timeinfo));
56 fprintf(out, "## Compiler Construction Course - Leiden University - LIACS\n");
57 fprintf(out, "## Johan IJsveld - Rick van der Zwet\n");
58 fprintf(out, "## BSD Licenced\n");
59
60}
61
62
63// Generates the declarations for the global variables
64
65void CodeGenerator::GenerateGlobalDecls(FILE *, SymbolTable * symtab) {
66 Scope * globalScope;
67 Symbol * sym;
68
69 mCode.AppendStatement(new MStatement(MOP_DATA, "Global data section"));
70 mCode.AppendStatement(new MStatement(MOP_ALIGN, new MOperand(MT_INT, 4)));
71
72 globalScope = symtab->GetRootScope();
73
74 // Here we iterate over all global variables in the symbol table and
75 // generate a declaration.
76 for (unsigned int i = 0; i < globalScope->GetNumberOfSymbols(); i++) {
77 sym = globalScope->GetSymbol(i);
78 if (IsGlobal(sym)) {
79 MStatement *stmt = new MStatement(MOP_LABEL);
80 stmt->SetLabel(string(SYMBOL_PREFIX) + sym->GetName());
81 mCode.AppendStatement(stmt);
82 if (sym->GetReturnType() == RT_INT) {
83 mCode.AppendStatement(new MStatement(MOP_WORD, new MOperand(MT_INT, 0)));
84 } else {
85 mCode.AppendStatement(new MStatement(MOP_FLOAT, new MOperand(MT_REAL, 0.0f)));
86 }
87 }
88 }
89
90}
91
92
93// Takes an IntermediateCode object and emits MIPS assembly instructions
94
95void CodeGenerator::GenerateCode(FILE *out, SymbolTable * symtab, IntermediateCode * inputCode) {
96 IStatement * stmt;
97
98 // Generate a general 'stub'.
99 mCode.AppendStatement(new MStatement(MOP_TEXT, "Code section"));
100 mCode.AppendStatement(new MStatement(MOP_ALIGN, new MOperand(MT_INT, 4)));
101 mCode.AppendStatement(new MStatement(MOP_GLOBL, new MOperand(MT_LABEL, "main")));
102 mCode.AppendStatement(new MStatement(MOP_ENT, new MOperand(MT_LABEL, "main")));
103 MStatement *mstmt = new MStatement(MOP_LABEL);
104 mstmt->SetLabel("main");
105 mCode.AppendStatement(mstmt);
106 mCode.AppendStatement(StackPointerChange(-4));
107 mCode.AppendStatement(new MStatement(MOP_JAL, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + inputCode->GetProgramName()), "Jump to program body"));
108 mCode.AppendStatement(StackPointerChange(4));
109 mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_V0), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, 10), "Exit system call"));
110 mCode.AppendStatement(new MStatement(MOP_SYSCALL));
111 mCode.AppendStatement(new MStatement(MOP_END, new MOperand(MT_LABEL, "main")));
112
113 // Here we step through the intermediate code and output assembly instructions
114 for (unsigned int i = 0; i < inputCode->GetStatementCount(); i++) {
115 stmt = inputCode->GetStatement(i);
116
117 switch (stmt->GetOperator()) {
118 /* Subprogram entry
119 operand1 should refer to the corresponding Symbol_Subprogram object */
120 case IOP_SUBPROG: // [1--] Subprogram
121 {
122 // The start of a subprogram: analyze it, and generate the prologue.
123 currentFrame.AnalyzeSubprogram(symtab, stmt->GetOperand1()->GetSymbol());
124 currentFrame.GeneratePrologue(out);
125 break;
126 }
127 /* Subprogram return
128 operand1 should contain the value that has to be returned */
129 case IOP_RETURN: // [---] Procedure return
130 {
131 // The end of a subprogram:
132 // write back all registers
133 rManager.SpillAll();
134
135 // generate the epilogue
136 currentFrame.GenerateEpilogue(out);
137 break;
138 }
139 case IOP_RETURN_I: // [1--] Integer function return
140 {
141 // The end of a subprogram:
142 // write back all registers
143 rManager.SpillAll();
144
145 // put result in $v0
146 if (stmt->GetOperand1()->GetOperandType() == OT_INT) {
147 mCode.AppendStatement(new MStatement(MOP_ADDI,
148 new MOperand(MT_REGISTER, R_V0),
149 new MOperand(MT_REGISTER, R_ZERO),
150 new MOperand(MT_INT, stmt->GetOperand1()->GetIntValue()),
151 "Store constant integer return value"));
152 } else {
153 MRegisterType result_reg = rManager.GetIntRegister(stmt->GetOperand1()->GetSymbol());
154 mCode.AppendStatement(new MStatement(MOP_MOVE,
155 new MOperand(MT_REGISTER, R_V0),
156 new MOperand(MT_REGISTER, result_reg),
157 "Store integer return value"));
158 }
159
160 // generate the epilogue
161 currentFrame.GenerateEpilogue(out);
162 break;
163 }
164 case IOP_RETURN_R: // [1--] Real function return
165 {
166 // The end of a subprogram:
167 // write back all registers
168 rManager.SpillAll();
169
170 // put result in $f0
171 if (stmt->GetOperand1()->GetOperandType() == OT_REAL) {
172 mCode.AppendStatement(new MStatement(MOP_LI_S,
173 new MOperand(MT_REGISTER, R_F0),
174 new MOperand(MT_REAL, stmt->GetOperand1()->GetRealValue()),
175 "Store constant real return value"));
176 } else if (stmt->GetOperand1()->GetOperandType() == OT_REAL) {
177 // XXX: is this needed?
178 mCode.AppendStatement(new MStatement(MOP_LI_S,
179 new MOperand(MT_REGISTER, R_F0),
180 new MOperand(MT_INT, stmt->GetOperand1()->GetRealValue()),
181 "Store real (casted from int) return value"));
182 } else {
183 MRegisterType result_reg = rManager.GetFloatRegister(stmt->GetOperand1()->GetSymbol());
184 mCode.AppendStatement(new MStatement(MOP_MOV_S,
185 new MOperand(MT_REGISTER, R_F0),
186 new MOperand(MT_REGISTER, result_reg),
187 "Store real return value"));
188 }
189
190 // generate the epilogue
191 currentFrame.GenerateEpilogue(out);
192 break;
193 }
194 /* Meta */
195 case IOP_UNKNOWN: // [---] (yet) Unknown operation
196 {
197 assert(0); // can't happen
198 break;
199 }
200 /* Parameter passing (caller side)
201 operand1 actual parameter value or Symbol object */
202 case IOP_PARAM_I: // [1--] Integer parameter
203 {
204 if (stmt->GetOperand1()->GetOperandType() == OT_INT) {
205 mCode.AppendStatement(new MStatement(MOP_ADDI,
206 new MOperand(MT_REGISTER, R_V1),
207 new MOperand(MT_REGISTER, R_ZERO),
208 new MOperand(MT_INT, stmt->GetOperand1()->GetIntValue()),
209 "Push constant integer parameter"));
210
211 } else {
212 // find/associate operand symbol to a register
213 MRegisterType operand_reg = rManager.GetIntRegister(stmt->GetOperand1()->GetSymbol());
214 mCode.AppendStatement(new MStatement(MOP_MOVE,
215 new MOperand(MT_REGISTER, R_V1),
216 new MOperand(MT_REGISTER, operand_reg),
217 "Push integer parameter"));
218 }
219
220 mCode.AppendStatement(new MStatement(MOP_SW,
221 new MOperand(MT_REGISTER, R_V1),
222 new MOperand(MT_OFFSET, R_SP, 0)));
223
224 mCode.AppendStatement(StackPointerChange(-4));
225 break;
226 }
227 case IOP_PARAM_R: // [1--] Real parameter
228 {
229 if (stmt->GetOperand1()->GetOperandType() == OT_REAL) {
230 mCode.AppendStatement(new MStatement(MOP_LI_S,
231 new MOperand(MT_REGISTER, R_F0),
232 new MOperand(MT_REAL, stmt->GetOperand1()->GetRealValue()),
233 "Push constant real parameter"));
234
235 } else {
236 // find/associate operand symbol to a register
237 MRegisterType operand_reg = rManager.GetFloatRegister(stmt->GetOperand1()->GetSymbol());
238 mCode.AppendStatement(new MStatement(MOP_MOV_S,
239 new MOperand(MT_REGISTER, R_F0),
240 new MOperand(MT_REGISTER, operand_reg),
241 "Push real parameter"));
242 }
243
244 mCode.AppendStatement(new MStatement(MOP_S_S,
245 new MOperand(MT_REGISTER, R_F0),
246 new MOperand(MT_OFFSET, R_SP, 0)));
247
248 mCode.AppendStatement(StackPointerChange(-4));
249 break;
250 }
251
252 /* Subprogram call
253 operand1 should refer to the corresponding Symbol object
254 result receives the result of a function call */
255 case IOP_PROCCALL: // [1--] Procedure call
256 {
257 /* making a procedure call so write back all registers */
258 rManager.SpillAll();
259 /* make procedure call */
260 mCode.AppendStatement(new MStatement(MOP_JAL,
261 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + OP1_NAME_C_STR(stmt))));
262 break;
263 }
264 case IOP_FUNCCALL: // [1-r] Function call
265 {
266 /* making a function call so write back all registers */
267 rManager.SpillAll();
268
269 /* Function call requires a call and then storage of returned data */
270 mCode.AppendStatement(new MStatement(MOP_JAL,
271 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + OP1_NAME_C_STR(stmt))));
272
273 /* find/associate a register and put the result in there */
274 Symbol *result_symbol = stmt->GetResult()->GetSymbol();
275 if (result_symbol->GetReturnType() == RT_INT) {
276 MRegisterType result_reg = rManager.GetIntRegister(result_symbol);
277 mCode.AppendStatement(new MStatement(MOP_MOVE,
278 new MOperand(MT_REGISTER, result_reg),
279 new MOperand(MT_REGISTER, R_V0),
280 "Store integer function result"));
281 } else {
282 MRegisterType result_reg = rManager.GetFloatRegister(result_symbol);
283 mCode.AppendStatement(new MStatement(MOP_MOV_S,
284 new MOperand(MT_REGISTER, result_reg),
285 new MOperand(MT_REGISTER, R_F0),
286 "Store real function result"));
287 }
288 break;
289 }
290 /* Label
291 operand1 should refer to the corresponding Symbol object */
292 case IOP_LABEL: // [1--] Label
293 {
294 MStatement *mstmt = new MStatement(MOP_LABEL);
295 mstmt->SetLabel(OP1_NAME_C_STR(stmt));
296 mCode.AppendStatement(mstmt);
297 break;
298 }
299 /* Goto
300 operand1 should refer to the corresponding Symbol object; note that
301 the Symbol pointed to should be of type ST_LABEL */
302 case IOP_GOTO: // [1--] Goto a label
303 {
304 /* changing control flow so write back all registers */
305 rManager.SpillAll();
306
307 mCode.AppendStatement(new MStatement(MOP_J, new MOperand(MT_LABEL, OP1_NAME_C_STR(stmt))));
308 break;
309 }
310 /* Variable assignment (copy value)
311 operand1 the source operand
312 result the destination operand (pointer to a Symbol object) */
313 case IOP_ASSIGN_I: // [1-r] Integer assignment
314 {
315 // find/associate result symbol to a register
316 MRegisterType result_reg = rManager.GetIntRegister(stmt->GetResult()->GetSymbol());
317
318 if (stmt->GetOperand1()->GetOperandType() == OT_INT) {
319 mCode.AppendStatement(new MStatement(MOP_ADDI,
320 new MOperand(MT_REGISTER, result_reg),
321 new MOperand(MT_REGISTER, R_ZERO),
322 new MOperand(MT_INT, stmt->GetOperand1()->GetIntValue()),
323 "Assign constant integer"));
324 } else {
325 // find/associate operand symbol to a register
326 MRegisterType operand_reg = rManager.GetIntRegister(stmt->GetOperand1()->GetSymbol());
327 mCode.AppendStatement(new MStatement(MOP_MOVE,
328 new MOperand(MT_REGISTER, result_reg),
329 new MOperand(MT_REGISTER, operand_reg),
330 "Assign integer"));
331 }
332 break;
333 }
334 case IOP_ASSIGN_R: // [1-r] Real assignment
335 {
336 // find/associate result symbol to a register
337 MRegisterType result_reg = rManager.GetFloatRegister(stmt->GetResult()->GetSymbol());
338
339 if (stmt->GetOperand1()->GetOperandType() == OT_REAL) {
340 mCode.AppendStatement(new MStatement(MOP_LI_S,
341 new MOperand(MT_REGISTER, result_reg),
342 new MOperand(MT_REAL, stmt->GetOperand1()->GetRealValue()),
343 "Assign constant real"));
344 } else {
345 // find/associate operand symbol to a register
346 MRegisterType operand_reg = rManager.GetFloatRegister(stmt->GetOperand1()->GetSymbol());
347 mCode.AppendStatement(new MStatement(MOP_MOV_S,
348 new MOperand(MT_REGISTER, result_reg),
349 new MOperand(MT_REGISTER, operand_reg),
350 "Assign real"));
351 }
352 break;
353
354 }
355 /* Branching
356 operand1 the first source operand
357 operand2 the second source operand
358 result should refer to the target Symbol object; note that
359 the Symbol pointed to must be of type ST_LABEL */
360 case IOP_BEQ_I: // [12r] = operator for integers
361 {
362 mCode.AppendStatement(BranchInstruction(MOP_BEQ, stmt));
363 break;
364 }
365 case IOP_BLT_I: // [12r] < operator for integers
366 {
367 mCode.AppendStatement(BranchInstruction(MOP_BLT, stmt));
368 break;
369 }
370 case IOP_BGT_I: // [12r] > operator for integers
371 {
372 mCode.AppendStatement(BranchInstruction(MOP_BGT, stmt));
373 break;
374 }
375 case IOP_BLE_I: // [12r] <= operator for integers
376 {
377 mCode.AppendStatement(BranchInstruction(MOP_BLE, stmt));
378 break;
379 }
380 case IOP_BGE_I: // [12r] >= operator for integers
381 {
382 mCode.AppendStatement(BranchInstruction(MOP_BGE, stmt));
383 break;
384 }
385 case IOP_BNE_I: // [12r] <> operator for integers
386 {
387 mCode.AppendStatement(BranchInstruction(MOP_BNE, stmt));
388 break;
389 }
390 case IOP_BEQ_R: // [12r] = operator for reals
391 {
392 mCode.AppendStatement(BranchInstructionReal(MOP_C_EQ_S, stmt));
393 mCode.AppendStatement(new MStatement(MOP_BCZT,
394 new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt))));
395 break;
396 }
397 case IOP_BLT_R: // [12r] < operator for reals
398 {
399 mCode.AppendStatement(BranchInstructionReal(MOP_C_LT_S, stmt));
400 mCode.AppendStatement(new MStatement(MOP_BCZT,
401 new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt))));
402 break;
403 }
404 case IOP_BGT_R: // [12r] > operator for reals
405 {
406 /* Use reverse style not (<=) */
407 mCode.AppendStatement(BranchInstructionReal(MOP_C_LT_S, stmt, true));
408 mCode.AppendStatement(new MStatement(MOP_BCZT,
409 new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt))));
410 break;
411 }
412 case IOP_BLE_R: // [12r] <= operator for reals
413 {
414 mCode.AppendStatement(BranchInstructionReal(MOP_C_LE_S, stmt));
415 mCode.AppendStatement(new MStatement(MOP_BCZT,
416 new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt))));
417 break;
418 }
419 case IOP_BGE_R: // [12r] >= operator for reals
420 {
421 mCode.AppendStatement(BranchInstructionReal(MOP_C_LE_S, stmt, true));
422 mCode.AppendStatement(new MStatement(MOP_BCZF,
423 new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt))));
424 break;
425 }
426 case IOP_BNE_R: // [12r] <> operator for reals
427 {
428 mCode.AppendStatement(BranchInstructionReal(MOP_C_EQ_S, stmt));
429 mCode.AppendStatement(new MStatement(MOP_BCZF,
430 new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt))));
431 break;
432 }
433
434 /* Binary arithmetic operators
435 operand1 the first source operand
436 operand2 the second source operand
437 result the destination operand (refers to a Symbol object) */
438 case IOP_ADD_I: // [12r] Integer addition
439 {
440 mCode.AppendStatement(BinaryArithmetic(MOP_ADD, stmt, "Add integers"));
441 break;
442 }
443 case IOP_ADD_R: // [12r] Real addition
444 {
445 mCode.AppendStatement(BinaryArithmetic(MOP_ADD_S, stmt, "Add reals"));
446 break;
447 }
448 case IOP_SUB_I: // [12r] Integer substraction
449 {
450 mCode.AppendStatement(BinaryArithmetic(MOP_SUB, stmt, "Subtract integer"));
451 break;
452 }
453 case IOP_SUB_R: // [12r] Real substraction
454 {
455 mCode.AppendStatement(BinaryArithmetic(MOP_SUB_S, stmt, "Subtract reals"));
456 break;
457 }
458 case IOP_MUL_I: // [12r] Integer multiplication
459 {
460 mCode.AppendStatement(BinaryArithmetic(MOP_MUL, stmt, "Multiply integers"));
461 break;
462 }
463 case IOP_MUL_R: // [12r] Real multiplication
464 {
465 mCode.AppendStatement(BinaryArithmetic(MOP_MUL_S, stmt, "Multiply reals"));
466 break;
467 }
468 case IOP_DIV_I: // [12r] Integer division
469 {
470 mCode.AppendStatement(BinaryArithmetic(MOP_DIV, stmt, "Divide integers"));
471 break;
472 }
473 case IOP_DIV_R: // [12r] Real division
474 {
475 mCode.AppendStatement(BinaryArithmetic(MOP_DIV_S, stmt, "Divide reals"));
476 break;
477 }
478 case IOP_MOD: // [12r] Modulo
479 {
480 mCode.AppendStatement(BinaryArithmetic(MOP_REM, stmt, "Remainder"));
481 break;
482 }
483 case IOP_AND: // [12r] AND operation
484 {
485 mCode.AppendStatement(BinaryArithmetic(MOP_AND, stmt, "Bitwise and"));
486 break;
487 }
488 case IOP_OR: // [12r] OR operation
489 {
490 mCode.AppendStatement(BinaryArithmetic(MOP_OR, stmt, "Bitwise or"));
491 break;
492 }
493
494 /* Unary arithmetic operators
495 operand1 the source operand
496 result the destination operand (refers to a Symbol object) */
497 case IOP_NOT: // [1-r] NOT operation
498 {
499 mCode.AppendStatement(UnaryArithmetic(MOP_NOT, stmt, "Bitwise not"));
500 break;
501 }
502 case IOP_UNARY_MINUS_I: // [1-r] Unary integer minus
503 {
504 mCode.AppendStatement(UnaryArithmetic(MOP_NEG, stmt, "Negate integer"));
505 break;
506 }
507 case IOP_UNARY_MINUS_R: // [1-r] Unary real minus
508 {
509 mCode.AppendStatement(UnaryArithmetic(MOP_NEG_S, stmt, "Negate real"));
510 break;
511 }
512 /* Coercion
513 operand1 the source operand
514 result the destination operand (refers to a Symbol object) */
515 case IOP_INT_TO_REAL: // [1-r] Int to Real coercion
516 {
517 MRegisterType dest_reg = rManager.GetFloatRegister(stmt->GetResult()->GetSymbol());
518 if (stmt->GetOperand1()->GetOperandType() == OT_INT) {
519 // just add constant
520 float value = stmt->GetOperand1()->GetIntValue();
521 mCode.AppendStatement(new MStatement(MOP_LI_S,
522 new MOperand(MT_REGISTER, dest_reg),
523 new MOperand(MT_REAL, value),
524 "Coerce constant from int to real"));
525 } else {
526 // load integer into register and load it into floating point register
527 MRegisterType source_reg = rManager.GetIntRegister(stmt->GetOperand1()->GetSymbol());
528 mCode.AppendStatement(new MStatement(MOP_MTC1,
529 new MOperand(MT_REGISTER, source_reg),
530 new MOperand(MT_REGISTER, dest_reg),
531 "Coerce from int to real"));
532 // convert integer to float
533 mCode.AppendStatement(new MStatement(MOP_CVT_S_W,
534 new MOperand(MT_REGISTER, dest_reg),
535 new MOperand(MT_REGISTER, dest_reg)));
536 }
537 break;
538 }
539 default:
540 fprintf(stderr,
541 "[CodeGenerator::GenerateCode()] Unhandled intermediate operator '%s'\n",
542 IOperatorToString(stmt->GetOperator())
543 );
544 }
545 }
546}
547
548MOperand * CodeGenerator::IOperand2MOperand(IOperand * opnd) {
549 MOperand *retVal;
550 MRegisterType freeRegister;
551 switch (opnd->GetOperandType()) {
552 case OT_SYMBOL:
553 {
554 MRegisterType tmpReg = rManager.GetRegister(opnd->GetSymbol());
555 retVal = new MOperand(MT_REGISTER, tmpReg);
556 break;
557 }
558 case OT_INT:
559 {
560 freeRegister = rManager.GetTempRegister();
561 mCode.AppendStatement(new MStatement(MOP_ADDI,
562 new MOperand(MT_REGISTER, freeRegister),
563 new MOperand(MT_REGISTER, R_ZERO),
564 new MOperand(MT_INT, opnd->GetIntValue())));
565
566 retVal = new MOperand(MT_REGISTER, freeRegister);
567 break;
568 }
569 case OT_REAL:
570 {
571 freeRegister = rManager.GetTempRegister();
572 mCode.AppendStatement(new MStatement(MOP_LI_S,
573 new MOperand(MT_REGISTER, freeRegister),
574 new MOperand(MT_REAL, opnd->GetRealValue())));
575
576 retVal = new MOperand(MT_REGISTER, freeRegister);
577 break;
578 }
579 default:
580 /* XXX: Should not happen */
581 break;
582 }
583 return (retVal);
584}
585
586// Generates a trailer
587
588/* Stack Pointer template */
589MStatement * CodeGenerator::StackPointerChange(int offset,
590 const char * comment) {
591 MOperand *mop1 = new MOperand(MT_REGISTER, R_SP);
592 MOperand *mop2 = new MOperand(MT_REGISTER, R_SP);
593 MOperand *mop3 = new MOperand(MT_INT, offset);
594 return (new MStatement(MOP_ADDI, mop1, mop2, mop3, comment));
595}
596
597/* Unary Artithmetic template */
598MStatement * CodeGenerator::UnaryArithmetic(MOperator opcode, IStatement *stmt,
599 const char * comment) {
600 MOperand *mop1 = IOperand2MOperand(stmt->GetResult());
601 MOperand *mop2 = IOperand2MOperand(stmt->GetOperand1());
602
603 return (new MStatement(opcode, mop1, mop2, comment));
604}
605
606/* Binary Artithmetic template */
607MStatement * CodeGenerator::BinaryArithmetic(MOperator opcode, IStatement *stmt,
608 const char * comment) {
609 MOperand *mop1 = IOperand2MOperand(stmt->GetResult());
610 MOperand *mop2 = IOperand2MOperand(stmt->GetOperand1());
611 MOperand *mop3 = IOperand2MOperand(stmt->GetOperand2());
612
613 return (new MStatement(opcode, mop1, mop2, mop3, comment));
614
615}
616
617/* Branch Instruction with Int values template */
618MStatement * CodeGenerator::BranchInstruction(MOperator opcode, IStatement *stmt,
619 bool swap, const char * comment) {
620 MOperand *mop1 = IOperand2MOperand(stmt->GetOperand1());
621 MOperand *mop2 = IOperand2MOperand(stmt->GetOperand2());
622 MOperand *mop3 = new MOperand(MT_LABEL, stmt->GetResult()->GetSymbol()->GetName());
623
624 /* changing control flow so write back all registers */
625 rManager.SpillAll();
626
627 if (swap)
628 return (new MStatement(opcode, mop1, mop2, mop3, comment));
629 else
630 return (new MStatement(opcode, mop2, mop1, mop3, comment));
631}
632
633/* Branch Instruction with Real values temlate */
634MStatement * CodeGenerator::BranchInstructionReal(MOperator opcode, IStatement *stmt,
635 bool swap, const char * comment) {
636 MOperand *mop1 = IOperand2MOperand(stmt->GetOperand1());
637 MOperand *mop2 = IOperand2MOperand(stmt->GetOperand2());
638 if (swap)
639 return (new MStatement(opcode, mop1, mop2, comment));
640 else
641 return (new MStatement(opcode, mop2, mop1, comment));
642}
643
644void CodeGenerator::Dump(FILE * out) {
645 mCode.Dump(out);
646 fprintf(out, "\n");
647}
648
649void CodeGenerator::GenerateTrailer(FILE *) {
650 /* readinteger: syscall code 5, integer in $v0
651 * General idea: init, set syscall value, call syscall, save value
652 */
653 {
654 mCode.AppendStatement(new MStatement(MOP_ENT,
655 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("readinteger")),
656 "Start of builtin functions and procedures"));
657
658 MStatement *stmt = new MStatement(MOP_LABEL);
659 stmt->SetLabel(string(SYMBOL_PREFIX) + string("readinteger"));
660 mCode.AppendStatement(stmt);
661
662 mCode.AppendStatement(new MStatement(MOP_ADDI,
663 new MOperand(MT_REGISTER, R_V0),
664 new MOperand(MT_REGISTER, R_ZERO),
665 new MOperand(MT_INT, 5)));
666
667 mCode.AppendStatement(new MStatement(MOP_SYSCALL));
668
669 mCode.AppendStatement(new MStatement(MOP_JR,
670 new MOperand(MT_REGISTER, R_RA)));
671
672 mCode.AppendStatement(new MStatement(MOP_END,
673 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("readinteger"))));
674 }
675
676 /* writeinteger: syscall code 1, integer in $a0
677 * General idea: init, set syscall value, ,set value, call syscall
678 */
679 {
680 mCode.AppendStatement(new MStatement(MOP_ENT,
681 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("writeinteger"))));
682
683 MStatement *stmt = new MStatement(MOP_LABEL);
684 stmt->SetLabel(string(SYMBOL_PREFIX) + string("writeinteger"));
685 mCode.AppendStatement(stmt);
686
687 mCode.AppendStatement(new MStatement(MOP_LW,
688 new MOperand(MT_REGISTER, R_A0),
689 new MOperand(MT_OFFSET, R_SP, 4)));
690
691 mCode.AppendStatement(new MStatement(MOP_ADDI,
692 new MOperand(MT_REGISTER, R_V0),
693 new MOperand(MT_REGISTER, R_ZERO),
694 new MOperand(MT_INT, 1)));
695
696 mCode.AppendStatement(new MStatement(MOP_SYSCALL));
697
698 mCode.AppendStatement(StackPointerChange(4));
699
700 mCode.AppendStatement(new MStatement(MOP_JR,
701 new MOperand(MT_REGISTER, R_RA)));
702
703 mCode.AppendStatement(new MStatement(MOP_END,
704 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("writeinteger"))));
705 }
706
707 /* readreal: syscall code 6, float in $f0
708 * General idea: init, set syscall value, call syscall, save value
709 */
710 {
711 mCode.AppendStatement(new MStatement(MOP_ENT,
712 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("readreal"))));
713
714 MStatement *stmt = new MStatement(MOP_LABEL);
715 stmt->SetLabel(string(SYMBOL_PREFIX) + string("readreal"));
716 mCode.AppendStatement(stmt);
717
718 mCode.AppendStatement(new MStatement(MOP_ADDI,
719 new MOperand(MT_REGISTER, R_V0),
720 new MOperand(MT_REGISTER, R_ZERO),
721 new MOperand(MT_INT, 6)));
722
723 mCode.AppendStatement(new MStatement(MOP_SYSCALL));
724
725 mCode.AppendStatement(new MStatement(MOP_JR,
726 new MOperand(MT_REGISTER, R_RA)));
727
728 mCode.AppendStatement(new MStatement(MOP_END,
729 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("readreal"))));
730 }
731
732 /* writereal: syscall code 2, float in $f12
733 * General idea: init, set syscall value, ,set value, call syscall
734 */
735 {
736 mCode.AppendStatement(new MStatement(MOP_ENT,
737 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("writereal"))));
738
739 MStatement *stmt = new MStatement(MOP_LABEL);
740 stmt->SetLabel(string(SYMBOL_PREFIX) + string("writereal"));
741 mCode.AppendStatement(stmt);
742
743 mCode.AppendStatement(new MStatement(MOP_L_S,
744 new MOperand(MT_REGISTER, R_F12),
745 new MOperand(MT_OFFSET, R_SP, 4)));
746
747 mCode.AppendStatement(new MStatement(MOP_ADDI,
748 new MOperand(MT_REGISTER, R_V0),
749 new MOperand(MT_REGISTER, R_ZERO),
750 new MOperand(MT_INT, 2)));
751
752 mCode.AppendStatement(new MStatement(MOP_SYSCALL));
753
754 mCode.AppendStatement(StackPointerChange(4));
755
756 mCode.AppendStatement(new MStatement(MOP_JR,
757 new MOperand(MT_REGISTER, R_RA)));
758
759 mCode.AppendStatement(new MStatement(MOP_END,
760 new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("writereal"))));
761 }
762}
Note: See TracBrowser for help on using the repository browser.