Now my comments should be in english....
[pspdecompiler.git] / output.c
bloba49887935e8a67d2f3c7fdd5f4daf8acba61d2e9
1 /**
2 * Author: Humberto Naves (hsnaves@gmail.com)
3 */
5 #include <stdio.h>
6 #include <string.h>
8 #include "output.h"
9 #include "allegrex.h"
10 #include "utils.h"
12 void get_base_name (char *filename, char *basename, size_t len)
14 char *temp;
16 temp = strrchr (filename, '/');
17 if (temp) filename = &temp[1];
19 strncpy (basename, filename, len - 1);
20 basename[len - 1] = '\0';
21 temp = strchr (basename, '.');
22 if (temp) *temp = '\0';
25 void ident_line (FILE *out, int size)
27 int i;
28 for (i = 0; i < size; i++)
29 fprintf (out, " ");
33 void print_subroutine_name (FILE *out, struct subroutine *sub)
35 if (sub->export) {
36 if (sub->export->name) {
37 fprintf (out, "%s", sub->export->name);
38 } else {
39 fprintf (out, "%s_%08X", sub->export->libname, sub->export->nid);
41 } else if (sub->import) {
42 if (sub->import->name) {
43 fprintf (out, "%s", sub->import->name);
44 } else {
45 fprintf (out, "%s_%08X", sub->import->libname, sub->import->nid);
47 } else {
48 fprintf (out, "sub_%05X", sub->begin->address);
52 void print_subroutine_declaration (FILE *out, struct subroutine *sub)
54 int i;
55 if (sub->numregout > 0)
56 fprintf (out, "int ");
57 else
58 fprintf (out, "void ");
60 print_subroutine_name (out, sub);
62 fprintf (out, " (");
63 for (i = 0; i < sub->numregargs; i++) {
64 if (i != 0) fprintf (out, ", ");
65 fprintf (out, "int arg%d", i + 1);
67 fprintf (out, ")");
70 #define ISSPACE(x) ((x) == '\t' || (x) == '\r' || (x) == '\n' || (x) == '\v' || (x) == '\f')
72 static
73 int valid_string (struct prx *file, uint32 vaddr)
75 uint32 off = prx_translate (file, vaddr);
76 int len = 0;
77 if (off) {
78 for (; off < file->size; off++) {
79 uint8 ch = file->data[off];
80 if (ch == '\t' || ch == '\r' || ch == '\n' || ch == '\v' ||
81 ch == '\f' || (ch >= 32 && ch < 127))
82 len++;
83 else
84 break;
87 return len > 3;
90 static
91 void print_string (FILE *out, struct prx *file, uint32 vaddr)
93 uint32 off = prx_translate (file, vaddr);
95 fprintf (out, "\"");
96 for (; off < file->size; off++) {
97 uint8 ch = file->data[off];
98 if (ch >= 32 && ch < 127) {
99 fprintf (out, "%c", ch);
100 } else {
101 switch (ch) {
102 case '\t': fprintf (out, "\\t"); break;
103 case '\r': fprintf (out, "\\r"); break;
104 case '\n': fprintf (out, "\\n"); break;
105 case '\v': fprintf (out, "\\v"); break;
106 case '\f': fprintf (out, "\\f"); break;
107 default:
108 fprintf (out, "\"");
109 return;
116 void print_value (FILE *out, struct value *val, int options)
118 struct ssavar *var;
119 int isstring = FALSE;
121 switch (val->type) {
122 case VAL_CONSTANT: fprintf (out, "0x%08X", val->val.intval); break;
123 case VAL_SSAVAR:
124 var = val->val.variable;
125 if (CONST_TYPE (var->status) != VAR_STAT_NOTCONSTANT &&
126 !(options & OPTS_RESULT)) {
127 struct prx *file;
128 file = var->def->block->sub->code->file;
129 if (var->def->status & OP_STAT_HASRELOC) {
130 isstring = valid_string (file, var->value);
132 if (isstring)
133 print_string (out, file, var->value);
134 else
135 fprintf (out, "0x%08X", var->value);
137 } else {
138 switch (var->type) {
139 case SSAVAR_ARGUMENT:
140 if (var->name.val.intval >= REGISTER_GPR_A0 &&
141 var->name.val.intval <= REGISTER_GPR_T3) {
142 fprintf (out, "arg%d", var->name.val.intval - REGISTER_GPR_A0 + 1);
143 } else {
144 print_value (out, &var->name, options);
146 break;
147 case SSAVAR_LOCAL:
148 fprintf (out, "var%d", var->info);
149 break;
150 case SSAVAR_TEMP:
151 if (var->def->type != OP_MOVE)
152 fprintf (out, "(");
153 print_operation (out, var->def, 0, TRUE);
154 if (var->def->type != OP_MOVE)
155 fprintf (out, ")");
156 break;
157 default:
158 print_value (out, &var->name, options);
159 fprintf (out, "/* Invalid block %d %d */",
160 var->def->block->node.dfsnum,
161 var->def->type);
162 break;
165 break;
166 case VAL_REGISTER:
167 if (val->val.intval == REGISTER_HI) fprintf (out, "hi");
168 else if (val->val.intval == REGISTER_LO) fprintf (out, "lo");
169 else fprintf (out, "%s", gpr_names[val->val.intval]);
170 break;
171 default:
172 fprintf (out, "UNK");
176 static
177 void print_asm_reglist (FILE *out, list regs, int identsize, int options)
179 element el;
181 fprintf (out, "\n");
182 ident_line (out, identsize);
183 fprintf (out, " : ");
185 el = list_head (regs);
186 while (el) {
187 struct value *val = element_getvalue (el);
188 if (el != list_head (regs))
189 fprintf (out, ", ");
190 fprintf (out, "\"=r\"(");
191 print_value (out, val, 0);
192 fprintf (out, ")");
193 el = element_next (el);
197 static
198 void print_asm (FILE *out, struct operation *op, int identsize, int options)
200 struct location *loc;
202 ident_line (out, identsize);
203 fprintf (out, "__asm__ (");
204 for (loc = op->info.asmop.begin; ; loc++) {
205 if (loc != op->info.asmop.begin) {
206 fprintf (out, "\n");
207 ident_line (out, identsize);
208 fprintf (out, " ");
210 fprintf (out, "\"%s;\"", allegrex_disassemble (loc->opc, loc->address, FALSE));
211 if (loc == op->info.asmop.end) break;
213 if (list_size (op->results) != 0 || list_size (op->operands) != 0) {
214 print_asm_reglist (out, op->results, identsize, options);
215 if (list_size (op->operands) != 0) {
216 print_asm_reglist (out, op->operands, identsize, options);
220 fprintf (out, ");\n");
223 static
224 void print_binaryop (FILE *out, struct operation *op, const char *opsymbol, int options)
226 if (!(options & OPTS_NORESULT)) {
227 print_value (out, list_headvalue (op->results), OPTS_RESULT);
228 fprintf (out, " = ");
230 print_value (out, list_headvalue (op->operands), 0);
231 fprintf (out, " %s ", opsymbol);
232 print_value (out, list_tailvalue (op->operands), 0);
235 static
236 void print_complexop (FILE *out, struct operation *op, const char *opsymbol, int options)
238 element el;
240 if (list_size (op->results) != 0 && !(options & OPTS_NORESULT)) {
241 print_value (out, list_headvalue (op->results), OPTS_RESULT);
242 fprintf (out, " = ");
245 fprintf (out, "%s (", opsymbol);
246 el = list_head (op->operands);
247 while (el) {
248 struct value *val;
249 val = element_getvalue (el);
250 if (val->type == VAL_SSAVAR) {
251 if (val->val.variable->type == SSAVAR_INVALID) break;
253 if (el != list_head (op->operands))
254 fprintf (out, ", ");
255 print_value (out, val, 0);
256 el = element_next (el);
258 fprintf (out, ")");
261 static
262 void print_call (FILE *out, struct operation *op, int options)
264 element el;
266 if (list_size (op->info.callop.retvalues) != 0 && !(options & OPTS_NORESULT)) {
267 el = list_head (op->info.callop.retvalues);
268 while (el) {
269 print_value (out, element_getvalue (el), OPTS_RESULT);
270 fprintf (out, " ");
271 el = element_next (el);
273 fprintf (out, "= ");
276 if (op->block->info.call.calltarget) {
277 print_subroutine_name (out, op->block->info.call.calltarget);
278 } else {
279 fprintf (out, "(*");
280 print_value (out, list_headvalue (op->block->info.call.from->jumpop->operands), 0);
281 fprintf (out, ")");
284 fprintf (out, " (");
286 el = list_head (op->info.callop.arguments);
287 while (el) {
288 struct value *val;
289 val = element_getvalue (el);
290 if (val->type == VAL_SSAVAR) {
291 if (val->val.variable->type == SSAVAR_INVALID) break;
293 if (el != list_head (op->info.callop.arguments))
294 fprintf (out, ", ");
295 print_value (out, val, 0);
296 el = element_next (el);
298 fprintf (out, ")");
301 static
302 void print_return (FILE *out, struct operation *op, int options)
304 element el;
306 fprintf (out, "return");
307 el = list_head (op->info.endop.arguments);
308 while (el) {
309 struct value *val;
310 val = element_getvalue (el);
311 fprintf (out, " ");
312 print_value (out, val, 0);
313 el = element_next (el);
317 static
318 void print_ext (FILE *out, struct operation *op, int options)
320 struct value *val1, *val2, *val3;
321 element el;
322 uint32 mask;
324 el = list_head (op->operands);
325 val1 = element_getvalue (el); el = element_next (el);
326 val2 = element_getvalue (el); el = element_next (el);
327 val3 = element_getvalue (el);
329 mask = 0xFFFFFFFF >> (32 - val3->val.intval);
330 if (!(options & OPTS_NORESULT)) {
331 print_value (out, list_headvalue (op->results), OPTS_RESULT);
332 fprintf (out, " = ");
335 fprintf (out, "(");
336 print_value (out, val1, 0);
337 fprintf (out, " >> %d)", val2->val.intval);
338 fprintf (out, " & 0x%08X", mask);
341 static
342 void print_ins (FILE *out, struct operation *op, int options)
344 struct value *val1, *val2, *val3, *val4;
345 element el;
346 uint32 mask;
348 el = list_head (op->operands);
349 val1 = element_getvalue (el); el = element_next (el);
350 val2 = element_getvalue (el); el = element_next (el);
351 val3 = element_getvalue (el); el = element_next (el);
352 val4 = element_getvalue (el);
354 mask = 0xFFFFFFFF >> (32 - val4->val.intval);
355 if (!(options & OPTS_NORESULT)) {
356 print_value (out, list_headvalue (op->results), OPTS_RESULT);
357 fprintf (out, " = ");
360 fprintf (out, "(");
361 print_value (out, val2, 0);
362 fprintf (out, " & 0x%08X) | (", ~(mask << val3->val.intval));
363 print_value (out, val1, 0);
364 fprintf (out, " & 0x%08X)", mask);
367 static
368 void print_nor (FILE *out, struct operation *op, int options)
370 struct value *val1, *val2;
371 int simple = 0;
373 val1 = list_headvalue (op->operands);
374 val2 = list_tailvalue (op->operands);
376 if (val1->val.intval == 0 || val2->val.intval == 0) {
377 simple = 1;
378 if (val1->val.intval == 0) val1 = val2;
381 if (!(options & OPTS_NORESULT)) {
382 print_value (out, list_headvalue (op->results), OPTS_RESULT);
383 fprintf (out, " = ");
386 if (!simple) {
387 fprintf (out, "!(");
388 print_value (out, val1, 0);
389 fprintf (out, " | ");
390 print_value (out, val2, 0);
391 fprintf (out, ")");
392 } else {
393 fprintf (out, "!");
394 print_value (out, val1, 0);
398 static
399 void print_movnz (FILE *out, struct operation *op, int ismovn, int options)
401 struct value *val1, *val2, *val3;
402 struct value *result;
403 element el;
405 el = list_head (op->operands);
406 val1 = element_getvalue (el); el = element_next (el);
407 val2 = element_getvalue (el); el = element_next (el);
408 val3 = element_getvalue (el);
409 result = list_headvalue (op->results);
411 if (!(options & OPTS_NORESULT)) {
412 print_value (out, result, OPTS_RESULT);
413 fprintf (out, " = ");
416 if (ismovn)
417 fprintf (out, "(");
418 else
419 fprintf (out, "!(");
420 print_value (out, val2, 0);
421 fprintf (out, ") ? ");
422 print_value (out, val1, 0);
423 fprintf (out, " : ");
424 print_value (out, val3, 0);
427 static
428 void print_slt (FILE *out, struct operation *op, int isunsigned, int options)
430 struct value *val1, *val2;
431 struct value *result;
432 element el;
434 el = list_head (op->operands);
435 val1 = element_getvalue (el); el = element_next (el);
436 val2 = element_getvalue (el);
437 result = list_headvalue (op->results);
439 if (!(options & OPTS_NORESULT)) {
440 print_value (out, result, OPTS_RESULT);
441 fprintf (out, " = ");
444 fprintf (out, "(");
446 print_value (out, val1, 0);
447 fprintf (out, " < ");
448 print_value (out, val2, 0);
449 fprintf (out, ")");
452 static
453 void print_signextend (FILE *out, struct operation *op, int isbyte, int options)
455 if (!(options & OPTS_NORESULT)) {
456 print_value (out, list_headvalue (op->results), OPTS_RESULT);
457 fprintf (out, " = ");
460 if (isbyte)
461 fprintf (out, "(char) ");
462 else
463 fprintf (out, "(short) ");
465 print_value (out, list_headvalue (op->operands), 0);
468 static
469 void print_memory_address (FILE *out, struct operation *op, int size, int isunsigned, int options)
471 struct value *val;
472 uint32 address;
473 const char *type;
475 if (size == 0) {
476 if (isunsigned) type = "unsigned char *";
477 else type = "char *";
478 } else if (size == 1) {
479 if (isunsigned) type = "unsigned short *";
480 else type = "short *";
481 } else if (size == 2) {
482 type = "int *";
485 val = list_headvalue (op->operands);
486 if (val->type == VAL_SSAVAR) {
487 if (CONST_TYPE (val->val.variable->status) != VAR_STAT_NOTCONSTANT) {
488 address = val->val.variable->value;
489 val = list_tailvalue (op->operands);
490 address += val->val.intval;
491 fprintf (out, "*((%s) 0x%08X)", type, address);
492 return;
496 fprintf (out, "((%s) ", type);
497 print_value (out, val, 0);
498 val = list_tailvalue (op->operands);
499 fprintf (out, ")[%d]", val->val.intval >> size);
502 static
503 void print_load (FILE *out, struct operation *op, int size, int isunsigned, int options)
505 if (!(options & OPTS_NORESULT)) {
506 print_value (out, list_headvalue (op->results), OPTS_RESULT);
507 fprintf (out, " = ");
509 print_memory_address (out, op, size, isunsigned, options);
512 static
513 void print_store (FILE *out, struct operation *op, int size, int isunsigned, int options)
515 struct value *val = element_getvalue (element_next (list_head (op->operands)));
516 print_memory_address (out, op, size, isunsigned, options);
517 fprintf (out, " = ");
518 print_value (out, val, 0);
521 static
522 void print_condition (FILE *out, struct operation *op, int options)
524 fprintf (out, "if (");
525 if (options & OPTS_REVERSECOND) fprintf (out, "!(");
526 print_value (out, list_headvalue (op->operands), 0);
527 switch (op->info.iop.insn) {
528 case I_BNE:
529 fprintf (out, " != ");
530 break;
531 case I_BEQ:
532 fprintf (out, " == ");
533 break;
534 case I_BGEZ:
535 case I_BGEZAL:
536 fprintf (out, " >= 0");
537 break;
538 case I_BGTZ:
539 fprintf (out, " > 0");
540 break;
541 case I_BLEZ:
542 fprintf (out, " <= 0");
543 break;
544 case I_BLTZ:
545 case I_BLTZAL:
546 fprintf (out, " < 0");
547 break;
548 default:
549 break;
551 if (list_size (op->operands) == 2)
552 print_value (out, list_tailvalue (op->operands), 0);
554 if (options & OPTS_REVERSECOND) fprintf (out, ")");
555 fprintf (out, ")");
560 void print_operation (FILE *out, struct operation *op, int identsize, int options)
562 struct location *loc;
563 int nosemicolon = FALSE;
565 if (op->type == OP_ASM) {
566 print_asm (out, op, identsize, options);
567 return;
570 loc = op->info.iop.loc;
571 if (op->type == OP_INSTRUCTION) {
572 if (op->info.iop.loc->insn->flags & (INSN_JUMP))
573 return;
574 if (loc->branchalways) return;
575 } else if (op->type == OP_NOP || op->type == OP_START || op->type == OP_PHI) {
576 return;
579 ident_line (out, identsize);
581 if ((op->status & (OP_STAT_CONSTANT | OP_STAT_DEFERRED)) == OP_STAT_CONSTANT) {
582 struct value *val = list_headvalue (op->results);
583 if (!(options & OPTS_NORESULT)) {
584 print_value (out, val, OPTS_RESULT);
585 fprintf (out, " = ");
587 print_value (out, val, 0);
588 } else {
589 if (op->type == OP_INSTRUCTION) {
590 switch (op->info.iop.insn) {
591 case I_ADD: print_binaryop (out, op, "+", options); break;
592 case I_ADDU: print_binaryop (out, op, "+", options); break;
593 case I_SUB: print_binaryop (out, op, "-", options); break;
594 case I_SUBU: print_binaryop (out, op, "-", options); break;
595 case I_XOR: print_binaryop (out, op, "^", options); break;
596 case I_AND: print_binaryop (out, op, "&", options); break;
597 case I_OR: print_binaryop (out, op, "|", options); break;
598 case I_SRAV: print_binaryop (out, op, ">>", options); break;
599 case I_SRLV: print_binaryop (out, op, ">>", options); break;
600 case I_SLLV: print_binaryop (out, op, "<<", options); break;
601 case I_INS: print_ins (out, op, options); break;
602 case I_EXT: print_ext (out, op, options); break;
603 case I_MIN: print_complexop (out, op, "MIN", options); break;
604 case I_MAX: print_complexop (out, op, "MAX", options); break;
605 case I_BITREV: print_complexop (out, op, "BITREV", options); break;
606 case I_CLZ: print_complexop (out, op, "CLZ", options); break;
607 case I_CLO: print_complexop (out, op, "CLO", options); break;
608 case I_NOR: print_nor (out, op, options); break;
609 case I_MOVN: print_movnz (out, op, TRUE, options); break;
610 case I_MOVZ: print_movnz (out, op, FALSE, options); break;
611 case I_SLT: print_slt (out, op, FALSE, options); break;
612 case I_SLTU: print_slt (out, op, TRUE, options); break;
613 case I_LW: print_load (out, op, 2, FALSE, options); break;
614 case I_LB: print_load (out, op, 0, FALSE, options); break;
615 case I_LBU: print_load (out, op, 0, TRUE, options); break;
616 case I_LH: print_load (out, op, 1, FALSE, options); break;
617 case I_LHU: print_load (out, op, 1, TRUE, options); break;
618 case I_LL: print_complexop (out, op, "LL", options); break;
619 case I_LWL: print_complexop (out, op, "LWL", options); break;
620 case I_LWR: print_complexop (out, op, "LWR", options); break;
621 case I_SW: print_store (out, op, 2, FALSE, options); break;
622 case I_SH: print_store (out, op, 1, FALSE, options); break;
623 case I_SB: print_store (out, op, 0, FALSE, options); break;
624 case I_SC: print_complexop (out, op, "SC", options); break;
625 case I_SWL: print_complexop (out, op, "SWL", options); break;
626 case I_SWR: print_complexop (out, op, "SWR", options); break;
627 case I_SEB: print_signextend (out, op, TRUE, options); break;
628 case I_SEH: print_signextend (out, op, TRUE, options); break;
629 default:
630 if (loc->insn->flags & INSN_BRANCH) {
631 print_condition (out, op, options);
632 nosemicolon = TRUE;
634 break;
636 } else if (op->type == OP_MOVE) {
637 if (!(options & OPTS_NORESULT)) {
638 print_value (out, list_headvalue (op->results), OPTS_RESULT);
639 fprintf (out, " = ");
641 print_value (out, list_headvalue (op->operands), 0);
642 } else if (op->type == OP_CALL) {
643 print_call (out, op, options);
644 } else if (op->type == OP_END) {
645 print_return (out, op, options);
646 /*} else if (op->type == OP_PHI) {
647 print_complexop (out, op, "PHI", options);*/
651 if (!(options & OPTS_NORESULT)) {
652 if (nosemicolon) fprintf (out, "\n");
653 else fprintf (out, ";\n");