Varias mudancas
[pspdecompiler.git] / output.c
blobda623a730b18cc6363bc250ab20684e74ffb5849
2 #include <stdio.h>
3 #include <string.h>
5 #include "output.h"
6 #include "allegrex.h"
7 #include "utils.h"
9 void get_base_name (char *filename, char *basename, size_t len)
11 char *temp;
13 temp = strrchr (filename, '/');
14 if (temp) filename = &temp[1];
16 strncpy (basename, filename, len - 1);
17 basename[len - 1] = '\0';
18 temp = strchr (basename, '.');
19 if (temp) *temp = '\0';
22 void ident_line (FILE *out, int size)
24 int i;
25 for (i = 0; i < size; i++)
26 fprintf (out, " ");
30 void print_subroutine_name (FILE *out, struct subroutine *sub)
32 if (sub->export) {
33 if (sub->export->name) {
34 fprintf (out, "%s", sub->export->name);
35 } else {
36 fprintf (out, "%s_%08X", sub->export->libname, sub->export->nid);
38 } else if (sub->import) {
39 if (sub->import->name) {
40 fprintf (out, "%s", sub->import->name);
41 } else {
42 fprintf (out, "%s_%08X", sub->import->libname, sub->import->nid);
44 } else {
45 fprintf (out, "sub_%05X", sub->begin->address);
49 void print_subroutine_declaration (FILE *out, struct subroutine *sub)
51 int i;
52 if (sub->numregout > 0)
53 fprintf (out, "int ");
54 else
55 fprintf (out, "void ");
57 print_subroutine_name (out, sub);
59 fprintf (out, " (");
60 for (i = 0; i < sub->numregargs; i++) {
61 if (i != 0) fprintf (out, ", ");
62 fprintf (out, "int arg%d", i + 1);
64 fprintf (out, ")");
67 #define ISSPACE(x) ((x) == '\t' || (x) == '\r' || (x) == '\n' || (x) == '\v' || (x) == '\f')
69 static
70 int valid_string (struct prx *file, uint32 vaddr)
72 uint32 off = prx_translate (file, vaddr);
73 int len = 0;
74 if (off) {
75 for (; off < file->size; off++) {
76 uint8 ch = file->data[off];
77 if (ch == '\t' || ch == '\r' || ch == '\n' || ch == '\v' ||
78 ch == '\f' || (ch >= 32 && ch < 127))
79 len++;
80 else
81 break;
84 return len > 3;
87 static
88 void print_string (FILE *out, struct prx *file, uint32 vaddr)
90 uint32 off = prx_translate (file, vaddr);
92 fprintf (out, "\"");
93 for (; off < file->size; off++) {
94 uint8 ch = file->data[off];
95 if (ch >= 32 && ch < 127) {
96 fprintf (out, "%c", ch);
97 } else {
98 switch (ch) {
99 case '\t': fprintf (out, "\\t"); break;
100 case '\r': fprintf (out, "\\r"); break;
101 case '\n': fprintf (out, "\\n"); break;
102 case '\v': fprintf (out, "\\v"); break;
103 case '\f': fprintf (out, "\\f"); break;
104 default:
105 fprintf (out, "\"");
106 return;
113 void print_value (FILE *out, struct value *val)
115 struct ssavar *var;
116 struct prx *file;
117 int isstring = FALSE;
119 switch (val->type) {
120 case VAL_CONSTANT: fprintf (out, "0x%08X", val->val.intval); break;
121 case VAL_SSAVAR:
122 var = val->val.variable;
123 switch (var->type) {
124 case SSAVAR_ARGUMENT:
125 if (var->name.val.intval >= REGISTER_GPR_A0 &&
126 var->name.val.intval <= REGISTER_GPR_T3) {
127 fprintf (out, "arg%d", var->name.val.intval - REGISTER_GPR_A0 + 1);
128 } else {
129 print_value (out, &var->name);
131 break;
132 case SSAVAR_LOCAL:
133 fprintf (out, "var%d", var->info);
134 break;
135 case SSAVAR_CONSTANT:
136 file = var->def->block->sub->code->file;
137 if (var->def->status & OP_STAT_HASRELOC) {
138 isstring = valid_string (file, var->info);
140 if (isstring)
141 print_string (out, file, var->info);
142 else
143 fprintf (out, "0x%08X", var->info);
144 break;
145 case SSAVAR_TEMP:
146 if (var->def->type != OP_MOVE)
147 fprintf (out, "(");
148 print_operation (out, var->def, 0, TRUE);
149 if (var->def->type != OP_MOVE)
150 fprintf (out, ")");
151 break;
152 default:
153 print_value (out, &var->name);
154 fprintf (out, "/* Invalid block %d %d */",
155 var->def->block->node.dfsnum,
156 var->def->type);
157 break;
159 break;
160 case VAL_REGISTER:
161 if (val->val.intval == REGISTER_HI) fprintf (out, "hi");
162 else if (val->val.intval == REGISTER_LO) fprintf (out, "lo");
163 else fprintf (out, "%s", gpr_names[val->val.intval]);
164 break;
165 default:
166 fprintf (out, "UNK");
170 static
171 void print_asm_reglist (FILE *out, list regs, int identsize, int options)
173 element el;
175 fprintf (out, "\n");
176 ident_line (out, identsize);
177 fprintf (out, " : ");
179 el = list_head (regs);
180 while (el) {
181 struct value *val = element_getvalue (el);
182 if (el != list_head (regs))
183 fprintf (out, ", ");
184 fprintf (out, "\"=r\"(");
185 print_value (out, val);
186 fprintf (out, ")");
187 el = element_next (el);
191 static
192 void print_asm (FILE *out, struct operation *op, int identsize, int options)
194 struct location *loc;
196 ident_line (out, identsize);
197 fprintf (out, "__asm__ (");
198 for (loc = op->info.asmop.begin; ; loc++) {
199 if (loc != op->info.asmop.begin) {
200 fprintf (out, "\n");
201 ident_line (out, identsize);
202 fprintf (out, " ");
204 fprintf (out, "\"%s\"", allegrex_disassemble (loc->opc, loc->address, FALSE));
205 if (loc == op->info.asmop.end) break;
207 if (list_size (op->results) != 0 || list_size (op->operands) != 0) {
208 print_asm_reglist (out, op->results, identsize, options);
209 if (list_size (op->operands) != 0) {
210 print_asm_reglist (out, op->operands, identsize, options);
214 fprintf (out, ");\n");
217 static
218 void print_binaryop (FILE *out, struct operation *op, const char *opsymbol, int options)
220 if (!(options & OPTS_DEFERRED)) {
221 print_value (out, list_headvalue (op->results));
222 fprintf (out, " = ");
224 print_value (out, list_headvalue (op->operands));
225 fprintf (out, " %s ", opsymbol);
226 print_value (out, list_tailvalue (op->operands));
229 void print_complexop (FILE *out, struct operation *op, const char *opsymbol, int options)
231 element el;
233 if (list_size (op->results) != 0 && !(options & OPTS_DEFERRED)) {
234 print_value (out, list_headvalue (op->results));
235 fprintf (out, " = ");
238 fprintf (out, "%s (", opsymbol);
239 el = list_head (op->operands);
240 while (el) {
241 struct value *val;
242 val = element_getvalue (el);
243 if (val->type == VAL_SSAVAR) {
244 if (val->val.variable->type == SSAVAR_INVALID) break;
246 if (el != list_head (op->operands))
247 fprintf (out, ", ");
248 print_value (out, val);
249 el = element_next (el);
251 fprintf (out, ")");
254 void print_call (FILE *out, struct operation *op, int options)
256 element el;
258 if (list_size (op->info.callop.retvalues) != 0 && !(options & OPTS_DEFERRED)) {
259 el = list_head (op->info.callop.retvalues);
260 while (el) {
261 print_value (out, list_tailvalue (op->results));
262 fprintf (out, " ");
263 el = element_next (el);
265 fprintf (out, "= ");
268 if (op->block->info.call.calltarget) {
269 print_subroutine_name (out, op->block->info.call.calltarget);
270 } else {
271 fprintf (out, "CALL");
274 fprintf (out, " (");
276 el = list_head (op->info.callop.arguments);
277 while (el) {
278 struct value *val;
279 val = element_getvalue (el);
280 if (val->type == VAL_SSAVAR) {
281 if (val->val.variable->type == SSAVAR_INVALID) break;
283 if (el != list_head (op->info.callop.arguments))
284 fprintf (out, ", ");
285 print_value (out, val);
286 el = element_next (el);
288 fprintf (out, ")");
291 static
292 void print_ext (FILE *out, struct operation *op, int options)
294 struct value *val1, *val2, *val3;
295 element el;
296 uint32 mask;
298 el = list_head (op->operands);
299 val1 = element_getvalue (el); el = element_next (el);
300 val2 = element_getvalue (el); el = element_next (el);
301 val3 = element_getvalue (el);
303 mask = 0xFFFFFFFF >> (32 - val3->val.intval);
304 if (!(options & OPTS_DEFERRED)) {
305 print_value (out, list_headvalue (op->results));
306 fprintf (out, " = ");
309 fprintf (out, "(");
310 print_value (out, val1);
311 fprintf (out, " >> %d)", val2->val.intval);
312 fprintf (out, " & 0x%08X", mask);
315 static
316 void print_ins (FILE *out, struct operation *op, int options)
318 struct value *val1, *val2, *val3, *val4;
319 element el;
320 uint32 mask;
322 el = list_head (op->operands);
323 val1 = element_getvalue (el); el = element_next (el);
324 val2 = element_getvalue (el); el = element_next (el);
325 val3 = element_getvalue (el); el = element_next (el);
326 val4 = element_getvalue (el);
328 mask = 0xFFFFFFFF >> (32 - val4->val.intval);
329 if (!(options & OPTS_DEFERRED)) {
330 print_value (out, list_headvalue (op->results));
331 fprintf (out, " = ");
334 fprintf (out, "(");
335 print_value (out, val2);
336 fprintf (out, " & 0x%08X) | (", ~(mask << val3->val.intval));
337 print_value (out, val1);
338 fprintf (out, " & 0x%08X)", mask);
341 static
342 void print_nor (FILE *out, struct operation *op, int options)
344 struct value *val1, *val2;
345 int simple = 0;
347 val1 = list_headvalue (op->operands);
348 val2 = list_tailvalue (op->operands);
350 if (val1->val.intval == 0 || val2->val.intval == 0) {
351 simple = 1;
352 if (val1->val.intval == 0) val1 = val2;
355 if (!(options & OPTS_DEFERRED)) {
356 print_value (out, list_headvalue (op->results));
357 fprintf (out, " = ");
360 if (!simple) {
361 fprintf (out, "!(");
362 print_value (out, val1);
363 fprintf (out, " | ");
364 print_value (out, val2);
365 fprintf (out, ")");
366 } else {
367 fprintf (out, "!");
368 print_value (out, val1);
372 static
373 void print_movnz (FILE *out, struct operation *op, int ismovn, int options)
375 struct value *val1, *val2, *val3;
376 struct value *result;
377 element el;
379 el = list_head (op->operands);
380 val1 = element_getvalue (el); el = element_next (el);
381 val2 = element_getvalue (el); el = element_next (el);
382 val3 = element_getvalue (el);
383 result = list_headvalue (op->results);
385 if (!(options & OPTS_DEFERRED)) {
386 print_value (out, result);
387 fprintf (out, " = ");
390 if (ismovn)
391 fprintf (out, "(");
392 else
393 fprintf (out, "!(");
394 print_value (out, val2);
395 fprintf (out, ") ? ");
396 print_value (out, val1);
397 fprintf (out, " : ");
398 print_value (out, val3);
401 static
402 void print_slt (FILE *out, struct operation *op, int isunsigned, int options)
404 struct value *val1, *val2;
405 struct value *result;
406 element el;
408 el = list_head (op->operands);
409 val1 = element_getvalue (el); el = element_next (el);
410 val2 = element_getvalue (el);
411 result = list_headvalue (op->results);
413 if (!(options & OPTS_DEFERRED)) {
414 print_value (out, result);
415 fprintf (out, " = ");
418 fprintf (out, "(");
420 print_value (out, val1);
421 fprintf (out, " < ");
422 print_value (out, val2);
423 fprintf (out, ")");
426 static
427 void print_signextend (FILE *out, struct operation *op, int isbyte, int options)
429 if (!(options & OPTS_DEFERRED)) {
430 print_value (out, list_headvalue (op->results));
431 fprintf (out, " = ");
434 if (isbyte)
435 fprintf (out, "(char) ");
436 else
437 fprintf (out, "(short) ");
439 print_value (out, list_headvalue (op->operands));
442 static
443 void print_memory_address (FILE *out, struct operation *op, int size, int isunsigned, int options)
445 struct value *val;
446 uint32 address;
447 const char *type;
449 if (size == 0) {
450 if (isunsigned) type = "unsigned char *";
451 else type = "char *";
452 } else if (size == 1) {
453 if (isunsigned) type = "unsigned short *";
454 else type = "short *";
455 } else if (size == 2) {
456 type = "int *";
459 val = list_headvalue (op->operands);
460 if (val->type == VAL_SSAVAR) {
461 if (val->val.variable->type == SSAVAR_CONSTANT) {
462 address = val->val.variable->type;
463 val = list_tailvalue (op->operands);
464 address += val->val.intval;
465 fprintf (out, "*((%s) 0x%08X)", type, address);
466 return;
470 fprintf (out, "((%s) ", type);
471 print_value (out, val);
472 val = list_tailvalue (op->operands);
473 fprintf (out, ")[%d]", val->val.intval >> size);
476 static
477 void print_load (FILE *out, struct operation *op, int size, int isunsigned, int options)
479 if (!(options & OPTS_DEFERRED)) {
480 print_value (out, list_headvalue (op->results));
481 fprintf (out, " = ");
483 print_memory_address (out, op, size, isunsigned, options);
486 static
487 void print_store (FILE *out, struct operation *op, int size, int isunsigned, int options)
489 struct value *val = element_getvalue (element_next (list_head (op->operands)));
490 print_memory_address (out, op, size, isunsigned, options);
491 fprintf (out, " = ");
492 print_value (out, val);
495 static
496 void print_condition (FILE *out, struct operation *op, int options)
498 fprintf (out, "if (");
499 if (options & OPTS_REVERSECOND) fprintf (out, "!(");
500 print_value (out, list_headvalue (op->operands));
501 switch (op->info.iop.insn) {
502 case I_BNE:
503 fprintf (out, " != ");
504 break;
505 case I_BEQ:
506 fprintf (out, " == ");
507 break;
508 case I_BGEZ:
509 case I_BGEZAL:
510 fprintf (out, " >= 0");
511 break;
512 case I_BGTZ:
513 fprintf (out, " > 0");
514 break;
515 case I_BLEZ:
516 fprintf (out, " <= 0");
517 break;
518 case I_BLTZ:
519 case I_BLTZAL:
520 fprintf (out, " < 0");
521 break;
522 default:
523 break;
525 if (list_size (op->operands) == 2)
526 print_value (out, list_tailvalue (op->operands));
528 if (options & OPTS_REVERSECOND) fprintf (out, ")");
529 fprintf (out, ")");
534 void print_operation (FILE *out, struct operation *op, int identsize, int options)
536 struct location *loc;
537 int nosemicolon = FALSE;
539 if (op->type == OP_ASM) {
540 print_asm (out, op, identsize, options);
541 return;
544 if (op->type == OP_INSTRUCTION) {
545 if (op->info.iop.loc->insn->flags & (INSN_JUMP))
546 return;
547 } else if (op->type == OP_NOP || op->type == OP_START ||
548 op->type == OP_END || op->type == OP_PHI) {
549 return;
552 loc = op->info.iop.loc;
553 if (op->type == OP_INSTRUCTION) {
554 if (loc->branchalways) return;
557 ident_line (out, identsize);
558 if (op->type == OP_INSTRUCTION) {
559 switch (op->info.iop.insn) {
560 case I_ADD: print_binaryop (out, op, "+", options); break;
561 case I_ADDU: print_binaryop (out, op, "+", options); break;
562 case I_SUB: print_binaryop (out, op, "-", options); break;
563 case I_SUBU: print_binaryop (out, op, "-", options); break;
564 case I_XOR: print_binaryop (out, op, "^", options); break;
565 case I_AND: print_binaryop (out, op, "&", options); break;
566 case I_OR: print_binaryop (out, op, "|", options); break;
567 case I_SRAV: print_binaryop (out, op, ">>", options); break;
568 case I_SRLV: print_binaryop (out, op, ">>", options); break;
569 case I_SLLV: print_binaryop (out, op, "<<", options); break;
570 case I_INS: print_ins (out, op, options); break;
571 case I_EXT: print_ext (out, op, options); break;
572 case I_MIN: print_complexop (out, op, "MIN", options); break;
573 case I_MAX: print_complexop (out, op, "MAX", options); break;
574 case I_BITREV: print_complexop (out, op, "BITREV", options); break;
575 case I_CLZ: print_complexop (out, op, "CLZ", options); break;
576 case I_CLO: print_complexop (out, op, "CLO", options); break;
577 case I_NOR: print_nor (out, op, options); break;
578 case I_MOVN: print_movnz (out, op, TRUE, options); break;
579 case I_MOVZ: print_movnz (out, op, FALSE, options); break;
580 case I_SLT: print_slt (out, op, FALSE, options); break;
581 case I_SLTU: print_slt (out, op, TRUE, options); break;
582 case I_LW: print_load (out, op, 2, FALSE, options); break;
583 case I_LB: print_load (out, op, 0, FALSE, options); break;
584 case I_LBU: print_load (out, op, 0, TRUE, options); break;
585 case I_LH: print_load (out, op, 1, FALSE, options); break;
586 case I_LHU: print_load (out, op, 1, TRUE, options); break;
587 case I_LL: print_complexop (out, op, "LL", options); break;
588 case I_LWL: print_complexop (out, op, "LWL", options); break;
589 case I_LWR: print_complexop (out, op, "LWR", options); break;
590 case I_SW: print_store (out, op, 2, FALSE, options); break;
591 case I_SH: print_store (out, op, 1, FALSE, options); break;
592 case I_SB: print_store (out, op, 0, FALSE, options); break;
593 case I_SC: print_complexop (out, op, "SC", options); break;
594 case I_SWL: print_complexop (out, op, "SWL", options); break;
595 case I_SWR: print_complexop (out, op, "SWR", options); break;
596 case I_SEB: print_signextend (out, op, TRUE, options); break;
597 case I_SEH: print_signextend (out, op, TRUE, options); break;
598 default:
599 if (loc->insn->flags & INSN_BRANCH) {
600 print_condition (out, op, options);
601 nosemicolon = TRUE;
603 break;
605 } else if (op->type == OP_MOVE) {
606 if (!options) {
607 print_value (out, list_headvalue (op->results));
608 fprintf (out, " = ");
610 print_value (out, list_headvalue (op->operands));
611 } else if (op->type == OP_CALL) {
612 print_call (out, op, options);
615 if (!(options & OPTS_DEFERRED)) {
616 if (nosemicolon) fprintf (out, "\n");
617 else fprintf (out, ";\n");