ACSE 2.0.3
Advanced Compiler System for Education
Loading...
Searching...
No Matches
target_asm_print.c
Go to the documentation of this file.
1
3
4#include <string.h>
5#include <stdint.h>
6#include <stdlib.h>
7#include "list.h"
8#include "errors.h"
9#include "target_asm_print.h"
10#include "target_info.h"
11
12#define BUF_LENGTH 256
13
14
15const char *opcodeToString(int opcode)
16{
17 switch (opcode) {
18 // Arithmetic
19 case OPC_ADD:
20 return "add";
21 case OPC_SUB:
22 return "sub";
23 case OPC_AND:
24 return "and";
25 case OPC_OR:
26 return "or";
27 case OPC_XOR:
28 return "xor";
29 case OPC_MUL:
30 return "mul";
31 case OPC_DIV:
32 return "div";
33 case OPC_REM:
34 return "rem";
35 case OPC_SLL:
36 return "sll";
37 case OPC_SRL:
38 return "srl";
39 case OPC_SRA:
40 return "sra";
41 // Arithmetic with immediate
42 case OPC_ADDI:
43 return "addi";
44 case OPC_SUBI:
45 return "subi";
46 case OPC_ANDI:
47 return "andi";
48 case OPC_ORI:
49 return "ori";
50 case OPC_XORI:
51 return "xori";
52 case OPC_MULI:
53 return "muli";
54 case OPC_DIVI:
55 return "divi";
56 case OPC_REMI:
57 return "remi";
58 case OPC_SLLI:
59 return "slli";
60 case OPC_SRLI:
61 return "srli";
62 case OPC_SRAI:
63 return "srai";
64 // Comparison
65 case OPC_SEQ:
66 return "seq";
67 case OPC_SNE:
68 return "sne";
69 case OPC_SLT:
70 return "slt";
71 case OPC_SLTU:
72 return "sltu";
73 case OPC_SGE:
74 return "sge";
75 case OPC_SGEU:
76 return "sgeu";
77 case OPC_SGT:
78 return "sgt";
79 case OPC_SGTU:
80 return "sgtu";
81 case OPC_SLE:
82 return "sle";
83 case OPC_SLEU:
84 return "sleu";
85 // Comparison with immediate
86 case OPC_SEQI:
87 return "seqi";
88 case OPC_SNEI:
89 return "snei";
90 case OPC_SLTI:
91 return "slti";
92 case OPC_SLTIU:
93 return "sltiu";
94 case OPC_SGEI:
95 return "sgei";
96 case OPC_SGEIU:
97 return "sgeiu";
98 case OPC_SGTI:
99 return "sgti";
100 case OPC_SGTIU:
101 return "sgtiu";
102 case OPC_SLEI:
103 return "slei";
104 case OPC_SLEIU:
105 return "sleiu";
106 // Jump, Branch
107 case OPC_J:
108 return "j";
109 case OPC_BEQ:
110 return "beq";
111 case OPC_BNE:
112 return "bne";
113 case OPC_BLT:
114 return "blt";
115 case OPC_BLTU:
116 return "bltu";
117 case OPC_BGE:
118 return "bge";
119 case OPC_BGEU:
120 return "bgeu";
121 case OPC_BGT:
122 return "bgt";
123 case OPC_BGTU:
124 return "bgtu";
125 case OPC_BLE:
126 return "ble";
127 case OPC_BLEU:
128 return "bleu";
129 // Load/Store
130 case OPC_LW:
131 return "lw";
132 case OPC_LW_G:
133 return "lw";
134 case OPC_SW:
135 return "sw";
136 case OPC_SW_G:
137 return "sw";
138 case OPC_LI:
139 return "li";
140 case OPC_LA:
141 return "la";
142 // Other
143 case OPC_NOP:
144 return "nop";
145 case OPC_ECALL:
146 return "ecall";
147 case OPC_EBREAK:
148 return "ebreak";
149 // Syscall
150 case OPC_CALL_EXIT_0:
151 return "Exit";
153 return "ReadInt";
155 return "PrintInt";
157 return "PrintChar";
158 }
159 return "<unknown>";
160}
161
162
163#define FORMAT_AUTO -1
164#define FORMAT_OP 0 // mnemonic rd, rs1, rs2
165#define FORMAT_OPIMM 1 // mnemonic rd, rs1, imm
166#define FORMAT_LOAD 2 // mnemonic rd, imm(rs1)
167#define FORMAT_LOAD_GL 3 // mnemonic rd, label
168#define FORMAT_STORE 4 // mnemonic rs2, imm(rs1)
169#define FORMAT_STORE_GL 5 // mnemonic rs2, label, rd
170#define FORMAT_BRANCH 6 // mnemonic rs1, rs2, label
171#define FORMAT_JUMP 7 // mnemonic label
172#define FORMAT_LI 8 // mnemonic rd, imm
173#define FORMAT_LA 9 // mnemonic rd, label
174#define FORMAT_SYSTEM 10 // mnemonic
175#define FORMAT_FUNC 11 // rd = fname(rs1, rs2)
176
177static int opcodeToFormat(int opcode)
178{
179 switch (opcode) {
180 case OPC_ADD:
181 case OPC_SUB:
182 case OPC_AND:
183 case OPC_OR:
184 case OPC_XOR:
185 case OPC_MUL:
186 case OPC_DIV:
187 case OPC_REM:
188 case OPC_SLL:
189 case OPC_SRL:
190 case OPC_SRA:
191 case OPC_SEQ:
192 case OPC_SNE:
193 case OPC_SLT:
194 case OPC_SLTU:
195 case OPC_SGE:
196 case OPC_SGEU:
197 case OPC_SGT:
198 case OPC_SGTU:
199 case OPC_SLE:
200 case OPC_SLEU:
201 return FORMAT_OP;
202 case OPC_ADDI:
203 case OPC_SUBI:
204 case OPC_ANDI:
205 case OPC_ORI:
206 case OPC_XORI:
207 case OPC_MULI:
208 case OPC_DIVI:
209 case OPC_REMI:
210 case OPC_SLLI:
211 case OPC_SRLI:
212 case OPC_SRAI:
213 case OPC_SEQI:
214 case OPC_SNEI:
215 case OPC_SLTI:
216 case OPC_SLTIU:
217 case OPC_SGEI:
218 case OPC_SGEIU:
219 case OPC_SGTI:
220 case OPC_SGTIU:
221 case OPC_SLEI:
222 case OPC_SLEIU:
223 return FORMAT_OPIMM;
224 case OPC_J:
225 return FORMAT_JUMP;
226 case OPC_BEQ:
227 case OPC_BNE:
228 case OPC_BLT:
229 case OPC_BLTU:
230 case OPC_BGE:
231 case OPC_BGEU:
232 case OPC_BGT:
233 case OPC_BGTU:
234 case OPC_BLE:
235 case OPC_BLEU:
236 return FORMAT_BRANCH;
237 case OPC_LW:
238 return FORMAT_LOAD;
239 case OPC_LW_G:
240 return FORMAT_LOAD_GL;
241 case OPC_SW:
242 return FORMAT_STORE;
243 case OPC_SW_G:
244 return FORMAT_STORE_GL;
245 case OPC_LI:
246 return FORMAT_LI;
247 case OPC_LA:
248 return FORMAT_LA;
249 case OPC_NOP:
250 case OPC_ECALL:
251 case OPC_EBREAK:
252 return FORMAT_SYSTEM;
253 case OPC_CALL_EXIT_0:
257 return FORMAT_FUNC;
258 }
259 return -1;
260}
261
262
263char *registerIDToString(t_regID regID, bool machineRegIDs)
264{
265 char *buf;
266 static const char *mcRegIds[] = {"zero", "ra", "sp", "gp", "tp", "t0", "t1",
267 "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2",
268 "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5",
269 "t6"};
270
271 if (machineRegIDs || (TARGET_REG_ZERO_IS_CONST && regID == 0)) {
272 if (regID < 0 || regID >= 32)
273 return NULL;
274 return strdup(mcRegIds[regID]);
275 }
276
277 if (regID < 0)
278 return strdup("invalid_reg");
279 buf = calloc(24, sizeof(char));
280 snprintf(buf, 24, "temp%d", regID);
281 return buf;
282}
283
284
285char *registerToString(t_instrArg *reg, bool machineRegIDs)
286{
287 if (!reg)
288 return NULL;
289 return registerIDToString(reg->ID, machineRegIDs);
290}
291
292
293int labelToString(char *buf, int bufsz, t_label *label, int finalColon)
294{
295 char *labelName;
296 int res;
297
298 if (!label)
299 return -1;
300
301 labelName = getLabelName(label);
302
303 if (finalColon)
304 res = snprintf(buf, bufsz, "%s:", labelName);
305 else
306 res = snprintf(buf, bufsz, "%s", labelName);
307
308 free(labelName);
309 return res;
310}
311
312
314 char *buf, int bufsz, t_instruction *instr, bool machineRegIDs)
315{
316 int res;
317 char *buf0 = buf;
318 char *address = NULL;
319
320 const char *opc = opcodeToString(instr->opcode);
321 char *rd = registerToString(instr->rDest, machineRegIDs);
322 char *rs1 = registerToString(instr->rSrc1, machineRegIDs);
323 char *rs2 = registerToString(instr->rSrc2, machineRegIDs);
324 if (instr->addressParam) {
325 int n = labelToString(NULL, 0, instr->addressParam, 0);
326 address = calloc((size_t)n + 1, sizeof(char));
327 if (!address)
328 fatalError("out of memory");
329 labelToString(address, n + 1, instr->addressParam, 0);
330 }
331 int32_t imm = instr->immediate;
332
333 int format = opcodeToFormat(instr->opcode);
334 switch (format) {
335 case FORMAT_OP:
336 if (!instr->rDest || !instr->rSrc1 || !instr->rSrc2)
337 fatalError("bug: invalid instruction found in the program");
338 res = snprintf(buf, bufsz, "%-6s %s, %s, %s", opc, rd, rs1, rs2);
339 break;
340 case FORMAT_OPIMM:
341 if (!instr->rDest || !instr->rSrc1)
342 fatalError("bug: invalid instruction found in the program");
343 res = snprintf(buf, bufsz, "%-6s %s, %s, %d", opc, rd, rs1, imm);
344 break;
345 case FORMAT_LOAD:
346 if (!instr->rDest || !instr->rSrc1)
347 fatalError("bug: invalid instruction found in the program");
348 res = snprintf(buf, bufsz, "%-6s %s, %d(%s)", opc, rd, imm, rs1);
349 break;
350 case FORMAT_LOAD_GL:
351 if (!instr->rDest || !instr->addressParam)
352 fatalError("bug: invalid instruction found in the program");
353 res = snprintf(buf, bufsz, "%-6s %s, %s", opc, rd, address);
354 break;
355 case FORMAT_STORE:
356 if (!instr->rSrc2 || !instr->rSrc1)
357 fatalError("bug: invalid instruction found in the program");
358 res = snprintf(buf, bufsz, "%-6s %s, %d(%s)", opc, rs2, imm, rs1);
359 break;
360 case FORMAT_STORE_GL:
361 if (!instr->rDest || !instr->rSrc1 || !instr->addressParam)
362 fatalError("bug: invalid instruction found in the program");
363 res = snprintf(buf, bufsz, "%-6s %s, %s, %s", opc, rs1, address, rd);
364 break;
365 case FORMAT_BRANCH:
366 if (!instr->rSrc1 || !instr->rSrc2 || !instr->addressParam)
367 fatalError("bug: invalid instruction found in the program");
368 res = snprintf(buf, bufsz, "%-6s %s, %s, %s", opc, rs1, rs2, address);
369 break;
370 case FORMAT_JUMP:
371 if (!instr->addressParam)
372 fatalError("bug: invalid instruction found in the program");
373 res = snprintf(buf, bufsz, "%-6s %s", opc, address);
374 break;
375 case FORMAT_LI:
376 if (!instr->rDest)
377 fatalError("bug: invalid instruction found in the program");
378 res = snprintf(buf, bufsz, "%-6s %s, %d", opc, rd, imm);
379 break;
380 case FORMAT_LA:
381 if (!instr->rDest || !instr->addressParam)
382 fatalError("bug: invalid instruction found in the program");
383 res = snprintf(buf, bufsz, "%-6s %s, %s", opc, rd, address);
384 break;
385 case FORMAT_SYSTEM:
386 res = snprintf(buf, bufsz, "%s", opc);
387 break;
388 case FORMAT_FUNC:
389 default:
390 if (instr->rDest)
391 buf += sprintf(buf, "%s = ", rd);
392 buf += sprintf(buf, "%s(", opc);
393 if (instr->rSrc1)
394 buf += sprintf(buf, "%s", rs1);
395 if (instr->rSrc1 && instr->rSrc2)
396 buf += sprintf(buf, ", ");
397 if (instr->rSrc2)
398 buf += sprintf(buf, "%s", rs2);
399 buf += sprintf(buf, ")");
400 res = (int)(buf - buf0);
401 break;
402 }
403
404 free(address);
405 free(rd);
406 free(rs1);
407 free(rs2);
408 return res;
409}
410
411
413{
414 for (t_listNode *li = program->labels; li != NULL; li = li->next) {
415 t_label *nextLabel = li->data;
416
417 if (nextLabel->isAlias)
418 continue;
419
420 if (nextLabel->global) {
421 char *labelName;
422 int res;
423
424 labelName = getLabelName(nextLabel);
425 res = fprintf(fp, "%-8s.global %s\n", "", labelName);
426 free(labelName);
427
428 if (res < 0)
429 return false;
430 }
431 }
432
433 return true;
434}
435
436
437bool printInstruction(t_instruction *instr, FILE *fp, bool machineRegIDs)
438{
439 char buf[BUF_LENGTH];
440
441 if (instr->label != NULL) {
442 labelToString(buf, BUF_LENGTH, instr->label, 1);
443 } else {
444 buf[0] = '\0';
445 }
446 if (fprintf(fp, "%-8s", buf) < 0)
447 return false;
448
449 instructionToString(buf, BUF_LENGTH, instr, machineRegIDs);
450 int res;
451 if (instr->comment) {
452 res = fprintf(fp, "%-48s# %s", buf, instr->comment);
453 } else {
454 res = fprintf(fp, "%s", buf);
455 }
456 if (res < 0)
457 return false;
458
459 return true;
460}
461
462bool translateCodeSegment(t_program *program, FILE *fp)
463{
464 if (!program->instructions)
465 return true;
466
467 // Write the .text directive to switch to the text segment.
468 if (fprintf(fp, "%-8s.text\n", "") < 0)
469 return false;
470
471 t_listNode *curNode = program->instructions;
472 while (curNode != NULL) {
473 t_instruction *curInstr = (t_instruction *)curNode->data;
474 if (curInstr == NULL)
475 fatalError("bug: NULL instruction found in the program");
476
477 if (!printInstruction(curInstr, fp, true))
478 return false;
479 if (fprintf(fp, "\n") < 0)
480 return false;
481
482 curNode = curNode->next;
483 }
484 return true;
485}
486
487
489{
490 char buf[BUF_LENGTH];
491
492 // Print the label.
493 if (data->label != NULL) {
494 labelToString(buf, BUF_LENGTH, data->label, 1);
495 } else {
496 buf[0] = '\0';
497 }
498 if (fprintf(fp, "%-8s", buf) < 0)
499 return -1;
500
501 // Print the directive.
502 int size;
503 switch (data->type) {
504 case TYPE_INT:
505 size = 4 / TARGET_PTR_GRANULARITY;
506 break;
507 case TYPE_INT_ARRAY:
508 size = (4 / TARGET_PTR_GRANULARITY) * data->arraySize;
509 break;
510 default:
511 fatalError("bug: invalid data type found in the program");
512 }
513 if (fprintf(fp, ".space %d", size) < 0)
514 return -1;
515
516 return 0;
517}
518
519bool translateDataSegment(t_program *program, FILE *fp)
520{
521 // If the symbol table is empty, nothing to do.
522 if (program->symbols == NULL)
523 return true;
524
525 // Write the .data directive to switch to the data segment.
526 if (fprintf(fp, "%-8s.data\n", "") < 0)
527 return false;
528
529 // Print a static declaration for each symbol.
530 t_listNode *li = program->symbols;
531 while (li != NULL) {
532 t_symbol *symbol = (t_symbol *)li->data;
533
534 if (printGlobalDeclaration(symbol, fp) < 0)
535 return false;
536 if (fprintf(fp, "\n") < 0)
537 return false;
538
539 li = li->next;
540 }
541
542 return true;
543}
544
545
546bool writeAssembly(t_program *program, const char *fn)
547{
548 bool res = false;
549 FILE *fp = fopen(fn, "w");
550 if (fp == NULL)
551 return res;
552
553 if (!translateForwardDeclarations(program, fp))
554 goto fail;
555 if (!translateDataSegment(program, fp))
556 goto fail;
557 if (!translateCodeSegment(program, fp))
558 goto fail;
559
560 res = true;
561fail:
562 if (fclose(fp) == EOF)
563 res = false;
564 return res;
565}
Error logging utilities.
bool printInstruction(t_instruction *instr, FILE *fp, bool machineRegIDs)
bool writeAssembly(t_program *program, const char *fn)
char * registerIDToString(t_regID regID, bool machineRegIDs)
void fatalError(const char *format,...)
Definition errors.c:32
struct t_listNode * next
Definition list.h:40
void * data
Pointer to the data associated to this node.
Definition list.h:44
A node belonging a list.
Definition list.h:39
t_label * addressParam
Definition program.h:77
t_symbolType type
A valid data type.
Definition program.h:86
t_listNode * instructions
List of instructions.
Definition program.h:100
char * comment
A comment string associated with the instruction, or NULL if none.
Definition program.h:79
int arraySize
For arrays only, the size of the array.
Definition program.h:93
t_listNode * labels
List of all labels.
Definition program.h:99
t_listNode * symbols
Symbol table.
Definition program.h:101
bool global
True if the label will be defined as 'global'.
Definition program.h:54
t_instrArg * rSrc1
First source argument (or NULL if none).
Definition program.h:74
t_instrArg * rSrc2
Second source argument (or NULL if none).
Definition program.h:75
int immediate
Immediate argument.
Definition program.h:76
t_regID ID
The register identifier.
Definition program.h:63
t_label * label
Label associated with the instruction, or NULL.
Definition program.h:71
t_instrArg * rDest
Destination argument (or NULL if none).
Definition program.h:73
bool isAlias
Definition program.h:57
int opcode
Instruction opcode.
Definition program.h:72
char * getLabelName(t_label *label)
Definition program.c:297
int t_regID
Type for register identifiers.
Definition program.h:28
@ TYPE_INT_ARRAY
‘int’ array type.
Definition program.h:39
@ TYPE_INT
‘int’ scalar type.
Definition program.h:38
#define TARGET_REG_ZERO_IS_CONST
Definition target_info.h:34
#define TARGET_PTR_GRANULARITY
Number of bytes for each memory address.
Definition target_info.h:30
@ OPC_SGTU
@ OPC_SW
@ OPC_ECALL
@ OPC_SGTI
@ OPC_CALL_EXIT_0
@ OPC_SW_G
@ OPC_BGT
@ OPC_MULI
@ OPC_BGE
@ OPC_LI
@ OPC_DIV
Definition target_info.h:94
@ OPC_SLTU
@ OPC_SLT
@ OPC_SRL
Definition target_info.h:97
@ OPC_XORI
@ OPC_ADDI
@ OPC_SGT
@ OPC_LW_G
@ OPC_SEQI
@ OPC_OR
Definition target_info.h:91
@ OPC_SUB
Definition target_info.h:89
@ OPC_SGEIU
@ OPC_XOR
Definition target_info.h:92
@ OPC_SLTIU
@ OPC_CALL_PRINT_CHAR
@ OPC_BLT
@ OPC_SGTIU
@ OPC_CALL_READ_INT
@ OPC_EBREAK
@ OPC_SLTI
@ OPC_SNE
@ OPC_BLTU
@ OPC_SRLI
@ OPC_SRA
Definition target_info.h:98
@ OPC_SLL
Definition target_info.h:96
@ OPC_SLEU
@ OPC_BNE
@ OPC_ORI
@ OPC_REM
Definition target_info.h:95
@ OPC_SLEI
@ OPC_ANDI
@ OPC_LW
@ OPC_J
@ OPC_BLEU
@ OPC_NOP
@ OPC_BGTU
@ OPC_SEQ
@ OPC_ADD
Definition target_info.h:88
@ OPC_BEQ
@ OPC_SLEIU
@ OPC_SGEI
@ OPC_LA
@ OPC_CALL_PRINT_INT
@ OPC_SNEI
@ OPC_BLE
@ OPC_SUBI
@ OPC_DIVI
@ OPC_SRAI
@ OPC_MUL
Definition target_info.h:93
@ OPC_REMI
@ OPC_SLLI
@ OPC_AND
Definition target_info.h:90
@ OPC_SGEU
@ OPC_BGEU
@ OPC_SLE
@ OPC_SGE
A double-linked list.
#define BUF_LENGTH
#define FORMAT_FUNC
#define FORMAT_JUMP
int instructionToString(char *buf, int bufsz, t_instruction *instr, bool machineRegIDs)
const char * opcodeToString(int opcode)
#define FORMAT_LI
char * registerToString(t_instrArg *reg, bool machineRegIDs)
#define FORMAT_STORE
#define FORMAT_OPIMM
#define FORMAT_LOAD_GL
#define FORMAT_OP
#define FORMAT_LOAD
int labelToString(char *buf, int bufsz, t_label *label, int finalColon)
#define FORMAT_BRANCH
bool translateDataSegment(t_program *program, FILE *fp)
#define FORMAT_SYSTEM
#define FORMAT_STORE_GL
int printGlobalDeclaration(t_symbol *data, FILE *fp)
bool translateForwardDeclarations(t_program *program, FILE *fp)
bool translateCodeSegment(t_program *program, FILE *fp)
#define FORMAT_LA
Generation of the output assembly program.
Properties of the target machine.