With MULT and DIV operations
[pspdecompiler.git] / output.c
blob956891d2653d96ec451a50e5f6d72e09363f8cc3
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 options = OPTS_NORESULT;
152 if (((struct value *) list_headvalue (var->def->results))->val.variable != var)
153 options |= OPTS_SECONDRESULT;
154 if (var->def->type != OP_MOVE)
155 fprintf (out, "(");
156 print_operation (out, var->def, 0, options);
157 if (var->def->type != OP_MOVE)
158 fprintf (out, ")");
159 break;
160 default:
161 print_value (out, &var->name, options);
162 fprintf (out, "/* Invalid block %d %d */",
163 var->def->block->node.dfsnum,
164 var->def->type);
165 break;
168 break;
169 case VAL_REGISTER:
170 if (val->val.intval == REGISTER_HI) fprintf (out, "hi");
171 else if (val->val.intval == REGISTER_LO) fprintf (out, "lo");
172 else fprintf (out, "%s", gpr_names[val->val.intval]);
173 break;
174 default:
175 fprintf (out, "UNK");
179 static
180 void print_asm_reglist (FILE *out, list regs, int identsize, int options)
182 element el;
184 fprintf (out, "\n");
185 ident_line (out, identsize);
186 fprintf (out, " : ");
188 el = list_head (regs);
189 while (el) {
190 struct value *val = element_getvalue (el);
191 if (el != list_head (regs))
192 fprintf (out, ", ");
193 fprintf (out, "\"=r\"(");
194 print_value (out, val, 0);
195 fprintf (out, ")");
196 el = element_next (el);
200 static
201 void print_asm (FILE *out, struct operation *op, int identsize, int options)
203 struct location *loc;
205 ident_line (out, identsize);
206 fprintf (out, "__asm__ (");
207 for (loc = op->info.asmop.begin; ; loc++) {
208 if (loc != op->info.asmop.begin) {
209 fprintf (out, "\n");
210 ident_line (out, identsize);
211 fprintf (out, " ");
213 fprintf (out, "\"%s;\"", allegrex_disassemble (loc->opc, loc->address, FALSE));
214 if (loc == op->info.asmop.end) break;
216 if (list_size (op->results) != 0 || list_size (op->operands) != 0) {
217 print_asm_reglist (out, op->results, identsize, options);
218 if (list_size (op->operands) != 0) {
219 print_asm_reglist (out, op->operands, identsize, options);
223 fprintf (out, ");\n");
226 static
227 void print_binaryop (FILE *out, struct operation *op, const char *opsymbol, int options)
229 if (!(options & OPTS_NORESULT)) {
230 print_value (out, list_headvalue (op->results), OPTS_RESULT);
231 fprintf (out, " = ");
233 print_value (out, list_headvalue (op->operands), 0);
234 fprintf (out, " %s ", opsymbol);
235 print_value (out, list_tailvalue (op->operands), 0);
238 static
239 void print_revbinaryop (FILE *out, struct operation *op, const char *opsymbol, int options)
241 if (!(options & OPTS_NORESULT)) {
242 print_value (out, list_headvalue (op->results), OPTS_RESULT);
243 fprintf (out, " = ");
245 print_value (out, list_tailvalue (op->operands), 0);
246 fprintf (out, " %s ", opsymbol);
247 print_value (out, list_headvalue (op->operands), 0);
250 static
251 void print_complexop (FILE *out, struct operation *op, const char *opsymbol, int options)
253 element el;
255 if (list_size (op->results) != 0 && !(options & OPTS_NORESULT)) {
256 print_value (out, list_headvalue (op->results), OPTS_RESULT);
257 fprintf (out, " = ");
260 fprintf (out, "%s (", opsymbol);
261 el = list_head (op->operands);
262 while (el) {
263 struct value *val;
264 val = element_getvalue (el);
265 if (val->type == VAL_SSAVAR) {
266 if (val->val.variable->type == SSAVAR_INVALID) break;
268 if (el != list_head (op->operands))
269 fprintf (out, ", ");
270 print_value (out, val, 0);
271 el = element_next (el);
273 fprintf (out, ")");
276 static
277 void print_call (FILE *out, struct operation *op, int options)
279 element el;
281 if (list_size (op->info.callop.retvalues) != 0 && !(options & OPTS_NORESULT)) {
282 el = list_head (op->info.callop.retvalues);
283 while (el) {
284 print_value (out, element_getvalue (el), OPTS_RESULT);
285 fprintf (out, " ");
286 el = element_next (el);
288 fprintf (out, "= ");
291 if (op->block->info.call.calltarget) {
292 print_subroutine_name (out, op->block->info.call.calltarget);
293 } else {
294 fprintf (out, "(*");
295 print_value (out, list_headvalue (op->block->info.call.from->jumpop->operands), 0);
296 fprintf (out, ")");
299 fprintf (out, " (");
301 el = list_head (op->info.callop.arguments);
302 while (el) {
303 struct value *val;
304 val = element_getvalue (el);
305 if (val->type == VAL_SSAVAR) {
306 if (val->val.variable->type == SSAVAR_INVALID) break;
308 if (el != list_head (op->info.callop.arguments))
309 fprintf (out, ", ");
310 print_value (out, val, 0);
311 el = element_next (el);
313 fprintf (out, ")");
316 static
317 void print_return (FILE *out, struct operation *op, int options)
319 element el;
321 fprintf (out, "return");
322 el = list_head (op->info.endop.arguments);
323 while (el) {
324 struct value *val;
325 val = element_getvalue (el);
326 fprintf (out, " ");
327 print_value (out, val, 0);
328 el = element_next (el);
332 static
333 void print_ext (FILE *out, struct operation *op, int options)
335 struct value *val1, *val2, *val3;
336 element el;
337 uint32 mask;
339 el = list_head (op->operands);
340 val1 = element_getvalue (el); el = element_next (el);
341 val2 = element_getvalue (el); el = element_next (el);
342 val3 = element_getvalue (el);
344 mask = 0xFFFFFFFF >> (32 - val3->val.intval);
345 if (!(options & OPTS_NORESULT)) {
346 print_value (out, list_headvalue (op->results), OPTS_RESULT);
347 fprintf (out, " = ");
350 fprintf (out, "(");
351 print_value (out, val1, 0);
352 fprintf (out, " >> %d)", val2->val.intval);
353 fprintf (out, " & 0x%08X", mask);
356 static
357 void print_ins (FILE *out, struct operation *op, int options)
359 struct value *val1, *val2, *val3, *val4;
360 element el;
361 uint32 mask;
363 el = list_head (op->operands);
364 val1 = element_getvalue (el); el = element_next (el);
365 val2 = element_getvalue (el); el = element_next (el);
366 val3 = element_getvalue (el); el = element_next (el);
367 val4 = element_getvalue (el);
369 mask = 0xFFFFFFFF >> (32 - val4->val.intval);
370 if (!(options & OPTS_NORESULT)) {
371 print_value (out, list_headvalue (op->results), OPTS_RESULT);
372 fprintf (out, " = ");
375 fprintf (out, "(");
376 print_value (out, val2, 0);
377 fprintf (out, " & 0x%08X) | (", ~(mask << val3->val.intval));
378 print_value (out, val1, 0);
379 fprintf (out, " & 0x%08X)", mask);
382 static
383 void print_nor (FILE *out, struct operation *op, int options)
385 struct value *val1, *val2;
386 int simple = 0;
388 val1 = list_headvalue (op->operands);
389 val2 = list_tailvalue (op->operands);
391 if (val1->val.intval == 0 || val2->val.intval == 0) {
392 simple = 1;
393 if (val1->val.intval == 0) val1 = val2;
396 if (!(options & OPTS_NORESULT)) {
397 print_value (out, list_headvalue (op->results), OPTS_RESULT);
398 fprintf (out, " = ");
401 if (!simple) {
402 fprintf (out, "!(");
403 print_value (out, val1, 0);
404 fprintf (out, " | ");
405 print_value (out, val2, 0);
406 fprintf (out, ")");
407 } else {
408 fprintf (out, "!");
409 print_value (out, val1, 0);
413 static
414 void print_movnz (FILE *out, struct operation *op, int ismovn, int options)
416 struct value *val1, *val2, *val3;
417 struct value *result;
418 element el;
420 el = list_head (op->operands);
421 val1 = element_getvalue (el); el = element_next (el);
422 val2 = element_getvalue (el); el = element_next (el);
423 val3 = element_getvalue (el);
424 result = list_headvalue (op->results);
426 if (!(options & OPTS_NORESULT)) {
427 print_value (out, result, OPTS_RESULT);
428 fprintf (out, " = ");
431 if (ismovn)
432 fprintf (out, "(");
433 else
434 fprintf (out, "!(");
435 print_value (out, val2, 0);
436 fprintf (out, ") ? ");
437 print_value (out, val1, 0);
438 fprintf (out, " : ");
439 print_value (out, val3, 0);
442 static
443 void print_mult (FILE *out, struct operation *op, int options)
445 if (!(options & OPTS_NORESULT)) {
446 print_value (out, list_headvalue (op->results), OPTS_RESULT);
447 fprintf (out, " ");
448 print_value (out, list_tailvalue (op->results), OPTS_RESULT);
449 fprintf (out, " = ");
451 if (options & OPTS_SECONDRESULT)
452 fprintf (out, "hi (");
454 print_value (out, list_headvalue (op->operands), 0);
455 fprintf (out, " * ");
456 print_value (out, list_tailvalue (op->operands), 0);
458 if (options & OPTS_SECONDRESULT)
459 fprintf (out, ")");
462 static
463 void print_madd (FILE *out, struct operation *op, int options)
465 struct value *val1, *val2, *val3, *val4;
466 element el = list_head (op->operands);
468 val1 = element_getvalue (el); el = element_next (el);
469 val2 = element_getvalue (el); el = element_next (el);
470 val3 = element_getvalue (el); el = element_next (el);
471 val4 = element_getvalue (el);
473 if (!(options & OPTS_NORESULT)) {
474 print_value (out, list_headvalue (op->results), OPTS_RESULT);
475 fprintf (out, " ");
476 print_value (out, list_tailvalue (op->results), OPTS_RESULT);
477 fprintf (out, " = ");
480 print_value (out, val1, 0);
481 fprintf (out, " * ");
482 print_value (out, val2, 0);
484 fprintf (out, " + (");
485 print_value (out, val3, 0);
486 fprintf (out, " ");
487 print_value (out, val4, 0);
488 fprintf (out, ")");
492 static
493 void print_msub (FILE *out, struct operation *op, int options)
495 struct value *val1, *val2, *val3, *val4;
496 element el = list_head (op->operands);
498 val1 = element_getvalue (el); el = element_next (el);
499 val2 = element_getvalue (el); el = element_next (el);
500 val3 = element_getvalue (el); el = element_next (el);
501 val4 = element_getvalue (el);
503 if (!(options & OPTS_NORESULT)) {
504 print_value (out, list_headvalue (op->results), OPTS_RESULT);
505 fprintf (out, " ");
506 print_value (out, list_tailvalue (op->results), OPTS_RESULT);
507 fprintf (out, " = ");
510 fprintf (out, "(");
511 print_value (out, val3, 0);
512 fprintf (out, " ");
513 print_value (out, val4, 0);
514 fprintf (out, ") - ");
516 print_value (out, val1, 0);
517 fprintf (out, " * ");
518 print_value (out, val2, 0);
522 static
523 void print_div (FILE *out, struct operation *op, int options)
525 if (!(options & OPTS_NORESULT)) {
526 print_value (out, list_headvalue (op->results), OPTS_RESULT);
527 fprintf (out, " ");
528 print_value (out, list_tailvalue (op->results), OPTS_RESULT);
529 fprintf (out, " = ");
531 print_value (out, list_headvalue (op->operands), 0);
533 if (options & OPTS_SECONDRESULT)
534 fprintf (out, " %% ");
535 else
536 fprintf (out, " / ");
538 print_value (out, list_tailvalue (op->operands), 0);
541 static
542 void print_slt (FILE *out, struct operation *op, int isunsigned, int options)
544 struct value *val1, *val2;
545 struct value *result;
546 element el;
548 el = list_head (op->operands);
549 val1 = element_getvalue (el); el = element_next (el);
550 val2 = element_getvalue (el);
551 result = list_headvalue (op->results);
553 if (!(options & OPTS_NORESULT)) {
554 print_value (out, result, OPTS_RESULT);
555 fprintf (out, " = ");
558 fprintf (out, "(");
560 print_value (out, val1, 0);
561 fprintf (out, " < ");
562 print_value (out, val2, 0);
563 fprintf (out, ")");
566 static
567 void print_signextend (FILE *out, struct operation *op, int isbyte, int options)
569 if (!(options & OPTS_NORESULT)) {
570 print_value (out, list_headvalue (op->results), OPTS_RESULT);
571 fprintf (out, " = ");
574 if (isbyte)
575 fprintf (out, "(char) ");
576 else
577 fprintf (out, "(short) ");
579 print_value (out, list_headvalue (op->operands), 0);
582 static
583 void print_memory_address (FILE *out, struct operation *op, int size, int isunsigned, int options)
585 struct value *val;
586 uint32 address;
587 const char *type;
589 if (size == 0) {
590 if (isunsigned) type = "unsigned char *";
591 else type = "char *";
592 } else if (size == 1) {
593 if (isunsigned) type = "unsigned short *";
594 else type = "short *";
595 } else if (size == 2) {
596 type = "int *";
599 val = list_headvalue (op->operands);
600 if (val->type == VAL_SSAVAR) {
601 if (CONST_TYPE (val->val.variable->status) != VAR_STAT_NOTCONSTANT) {
602 address = val->val.variable->value;
603 val = list_tailvalue (op->operands);
604 address += val->val.intval;
605 fprintf (out, "*((%s) 0x%08X)", type, address);
606 return;
610 fprintf (out, "((%s) ", type);
611 print_value (out, val, 0);
612 val = list_tailvalue (op->operands);
613 fprintf (out, ")[%d]", val->val.intval >> size);
616 static
617 void print_load (FILE *out, struct operation *op, int size, int isunsigned, int options)
619 if (!(options & OPTS_NORESULT)) {
620 print_value (out, list_headvalue (op->results), OPTS_RESULT);
621 fprintf (out, " = ");
623 print_memory_address (out, op, size, isunsigned, options);
626 static
627 void print_store (FILE *out, struct operation *op, int size, int isunsigned, int options)
629 struct value *val = element_getvalue (element_next (list_head (op->operands)));
630 print_memory_address (out, op, size, isunsigned, options);
631 fprintf (out, " = ");
632 print_value (out, val, 0);
635 static
636 void print_condition (FILE *out, struct operation *op, int options)
638 fprintf (out, "if (");
639 if (options & OPTS_REVERSECOND) fprintf (out, "!(");
640 print_value (out, list_headvalue (op->operands), 0);
641 switch (op->info.iop.insn) {
642 case I_BNE:
643 fprintf (out, " != ");
644 break;
645 case I_BEQ:
646 fprintf (out, " == ");
647 break;
648 case I_BGEZ:
649 case I_BGEZAL:
650 fprintf (out, " >= 0");
651 break;
652 case I_BGTZ:
653 fprintf (out, " > 0");
654 break;
655 case I_BLEZ:
656 fprintf (out, " <= 0");
657 break;
658 case I_BLTZ:
659 case I_BLTZAL:
660 fprintf (out, " < 0");
661 break;
662 default:
663 break;
665 if (list_size (op->operands) == 2)
666 print_value (out, list_tailvalue (op->operands), 0);
668 if (options & OPTS_REVERSECOND) fprintf (out, ")");
669 fprintf (out, ")");
674 void print_operation (FILE *out, struct operation *op, int identsize, int options)
676 struct location *loc;
677 int nosemicolon = FALSE;
679 if (op->type == OP_ASM) {
680 print_asm (out, op, identsize, options);
681 return;
684 loc = op->info.iop.loc;
685 if (op->type == OP_INSTRUCTION) {
686 if (op->info.iop.loc->insn->flags & (INSN_JUMP))
687 return;
688 if (loc->branchalways) return;
689 } else if (op->type == OP_NOP || op->type == OP_START || op->type == OP_PHI) {
690 return;
693 ident_line (out, identsize);
695 if ((op->status & (OP_STAT_CONSTANT | OP_STAT_DEFERRED)) == OP_STAT_CONSTANT) {
696 struct value *val = list_headvalue (op->results);
697 if (!(options & OPTS_NORESULT)) {
698 print_value (out, val, OPTS_RESULT);
699 fprintf (out, " = ");
701 print_value (out, val, 0);
702 } else {
703 if (op->type == OP_INSTRUCTION) {
704 switch (op->info.iop.insn) {
705 case I_ADD:
706 case I_ADDU: print_binaryop (out, op, "+", options); break;
707 case I_SUB:
708 case I_SUBU: print_binaryop (out, op, "-", options); break;
709 case I_XOR: print_binaryop (out, op, "^", options); break;
710 case I_AND: print_binaryop (out, op, "&", options); break;
711 case I_OR: print_binaryop (out, op, "|", options); break;
712 case I_SRAV:
713 case I_SRLV: print_revbinaryop (out, op, ">>", options); break;
714 case I_SLLV: print_revbinaryop (out, op, "<<", options); break;
715 case I_ROTV: print_complexop (out, op, "ROTV", options); break;
716 case I_INS: print_ins (out, op, options); break;
717 case I_EXT: print_ext (out, op, options); break;
718 case I_MIN: print_complexop (out, op, "MIN", options); break;
719 case I_MAX: print_complexop (out, op, "MAX", options); break;
720 case I_BITREV: print_complexop (out, op, "BITREV", options); break;
721 case I_CLZ: print_complexop (out, op, "CLZ", options); break;
722 case I_CLO: print_complexop (out, op, "CLO", options); break;
723 case I_NOR: print_nor (out, op, options); break;
724 case I_MOVN: print_movnz (out, op, TRUE, options); break;
725 case I_MOVZ: print_movnz (out, op, FALSE, options); break;
726 case I_MULT:
727 case I_MULTU: print_mult (out, op, options); break;
728 case I_MADD:
729 case I_MADDU: print_madd (out, op, options); break;
730 case I_MSUB:
731 case I_MSUBU: print_msub (out, op, options); break;
732 case I_DIV:
733 case I_DIVU: print_div (out, op, options); break;
734 case I_SLT: print_slt (out, op, FALSE, options); break;
735 case I_SLTU: print_slt (out, op, TRUE, options); break;
736 case I_LW: print_load (out, op, 2, FALSE, options); break;
737 case I_LB: print_load (out, op, 0, FALSE, options); break;
738 case I_LBU: print_load (out, op, 0, TRUE, options); break;
739 case I_LH: print_load (out, op, 1, FALSE, options); break;
740 case I_LHU: print_load (out, op, 1, TRUE, options); break;
741 case I_LL: print_complexop (out, op, "LL", options); break;
742 case I_LWL: print_complexop (out, op, "LWL", options); break;
743 case I_LWR: print_complexop (out, op, "LWR", options); break;
744 case I_SW: print_store (out, op, 2, FALSE, options); break;
745 case I_SH: print_store (out, op, 1, FALSE, options); break;
746 case I_SB: print_store (out, op, 0, FALSE, options); break;
747 case I_SC: print_complexop (out, op, "SC", options); break;
748 case I_SWL: print_complexop (out, op, "SWL", options); break;
749 case I_SWR: print_complexop (out, op, "SWR", options); break;
750 case I_SEB: print_signextend (out, op, TRUE, options); break;
751 case I_SEH: print_signextend (out, op, TRUE, options); break;
752 default:
753 if (loc->insn->flags & INSN_BRANCH) {
754 print_condition (out, op, options);
755 nosemicolon = TRUE;
757 break;
759 } else if (op->type == OP_MOVE) {
760 if (!(options & OPTS_NORESULT)) {
761 print_value (out, list_headvalue (op->results), OPTS_RESULT);
762 fprintf (out, " = ");
764 print_value (out, list_headvalue (op->operands), 0);
765 } else if (op->type == OP_CALL) {
766 print_call (out, op, options);
767 } else if (op->type == OP_END) {
768 print_return (out, op, options);
769 /*} else if (op->type == OP_PHI) {
770 print_complexop (out, op, "PHI", options);*/
774 if (!(options & OPTS_NORESULT)) {
775 if (nosemicolon) fprintf (out, "\n");
776 else fprintf (out, ";\n");