Ficando cada vez melhor
[pspdecompiler.git] / output.c
blob6dd2b4f1aaf16bf0fe5ede42c970e7fee7d18056
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_value (FILE *out, struct value *val)
51 switch (val->type) {
52 case VAL_CONSTANT: fprintf (out, "0x%08X", val->val.intval); break;
53 case VAL_VARIABLE:
54 switch (val->val.variable->type) {
55 case VARIABLE_ARGUMENT:
56 if (val->val.variable->name.val.intval >= REGISTER_GPR_A0 &&
57 val->val.variable->name.val.intval <= REGISTER_GPR_T3) {
58 fprintf (out, "arg%d", val->val.variable->name.val.intval - REGISTER_GPR_A0 + 1);
59 } else {
60 print_value (out, &val->val.variable->name);
62 break;
63 case VARIABLE_LOCAL:
64 fprintf (out, "local%d", val->val.variable->info);
65 break;
66 case VARIABLE_CONSTANT:
67 fprintf (out, "0x%08X", val->val.variable->info);
68 break;
69 case VARIABLE_TEMP:
70 if (val->val.variable->def->type != OP_MOVE)
71 fprintf (out, "(");
72 print_operation (out, val->val.variable->def, 0, TRUE);
73 if (val->val.variable->def->type != OP_MOVE)
74 fprintf (out, ")");
75 break;
76 default:
77 print_value (out, &val->val.variable->name);
78 fprintf (out, "/* Invalid block %d %d */",
79 val->val.variable->def->block->node.dfsnum,
80 val->val.variable->def->type);
81 break;
83 break;
84 case VAL_REGISTER:
85 if (val->val.intval == REGISTER_HI) fprintf (out, "hi");
86 else if (val->val.intval == REGISTER_LO) fprintf (out, "lo");
87 else fprintf (out, "%s", gpr_names[val->val.intval]);
88 break;
89 default:
90 fprintf (out, "UNK");
94 static
95 void print_asm_reglist (FILE *out, list regs, int identsize, int options)
97 element el;
99 fprintf (out, "\n");
100 ident_line (out, identsize);
101 fprintf (out, " : ");
103 el = list_head (regs);
104 while (el) {
105 struct value *val = element_getvalue (el);
106 if (el != list_head (regs))
107 fprintf (out, ", ");
108 fprintf (out, "\"=r\"(");
109 print_value (out, val);
110 fprintf (out, ")");
111 el = element_next (el);
115 static
116 void print_asm (FILE *out, struct operation *op, int identsize, int options)
118 struct location *loc;
120 ident_line (out, identsize);
121 fprintf (out, "__asm__ (");
122 for (loc = op->info.asmop.begin; ; loc++) {
123 if (loc != op->info.asmop.begin) {
124 fprintf (out, "\n");
125 ident_line (out, identsize);
126 fprintf (out, " ");
128 fprintf (out, "\"%s\"", allegrex_disassemble (loc->opc, loc->address, FALSE));
129 if (loc == op->info.asmop.end) break;
131 if (list_size (op->results) != 0 || list_size (op->operands) != 0) {
132 print_asm_reglist (out, op->results, identsize, options);
133 if (list_size (op->operands) != 0) {
134 print_asm_reglist (out, op->operands, identsize, options);
138 fprintf (out, ");\n");
141 static
142 void print_binaryop (FILE *out, struct operation *op, const char *opsymbol, int options)
144 if (!(options & OPTS_DEFERRED)) {
145 print_value (out, list_headvalue (op->results));
146 fprintf (out, " = ");
148 print_value (out, list_headvalue (op->operands));
149 fprintf (out, " %s ", opsymbol);
150 print_value (out, list_tailvalue (op->operands));
153 void print_complexop (FILE *out, struct operation *op, const char *opsymbol, int options)
155 element el;
157 if (list_size (op->results) != 0 && !(options & OPTS_DEFERRED)) {
158 print_value (out, list_headvalue (op->results));
159 fprintf (out, " = ");
162 fprintf (out, "%s (", opsymbol);
163 el = list_head (op->operands);
164 while (el) {
165 struct value *val;
166 val = element_getvalue (el);
167 if (val->type == VAL_VARIABLE) {
168 if (val->val.variable->type == VARIABLE_INVALID) break;
170 if (el != list_head (op->operands))
171 fprintf (out, ", ");
172 print_value (out, val);
173 el = element_next (el);
175 fprintf (out, ")");
178 void print_call (FILE *out, struct operation *op, int options)
180 element el;
182 if (list_size (op->info.callop.retvalues) != 0 && !(options & OPTS_DEFERRED)) {
183 el = list_head (op->info.callop.retvalues);
184 while (el) {
185 print_value (out, list_tailvalue (op->results));
186 fprintf (out, " ");
187 el = element_next (el);
189 fprintf (out, "= ");
192 if (op->block->info.call.calltarget) {
193 print_subroutine_name (out, op->block->info.call.calltarget);
194 } else {
195 fprintf (out, "CALL");
198 fprintf (out, " (");
200 el = list_head (op->info.callop.arguments);
201 while (el) {
202 struct value *val;
203 val = element_getvalue (el);
204 if (val->type == VAL_VARIABLE) {
205 if (val->val.variable->type == VARIABLE_INVALID) break;
207 if (el != list_head (op->info.callop.arguments))
208 fprintf (out, ", ");
209 print_value (out, val);
210 el = element_next (el);
212 fprintf (out, ")");
215 static
216 void print_ext (FILE *out, struct operation *op, int options)
218 struct value *val1, *val2, *val3;
219 element el;
220 uint32 mask;
222 el = list_head (op->operands);
223 val1 = element_getvalue (el); el = element_next (el);
224 val2 = element_getvalue (el); el = element_next (el);
225 val3 = element_getvalue (el);
227 mask = 0xFFFFFFFF >> (32 - val3->val.intval);
228 if (!(options & OPTS_DEFERRED)) {
229 print_value (out, list_headvalue (op->results));
230 fprintf (out, " = ");
233 fprintf (out, "(");
234 print_value (out, val1);
235 fprintf (out, " >> %d)", val2->val.intval);
236 fprintf (out, " & 0x%08X", mask);
239 static
240 void print_ins (FILE *out, struct operation *op, int options)
242 struct value *val1, *val2, *val3, *val4;
243 element el;
244 uint32 mask;
246 el = list_head (op->operands);
247 val1 = element_getvalue (el); el = element_next (el);
248 val2 = element_getvalue (el); el = element_next (el);
249 val3 = element_getvalue (el); el = element_next (el);
250 val4 = element_getvalue (el);
252 mask = 0xFFFFFFFF >> (32 - val4->val.intval);
253 if (!(options & OPTS_DEFERRED)) {
254 print_value (out, list_headvalue (op->results));
255 fprintf (out, " = ");
258 fprintf (out, "(");
259 print_value (out, val2);
260 fprintf (out, " & 0x%08X) | (", ~(mask << val3->val.intval));
261 print_value (out, val1);
262 fprintf (out, " & 0x%08X)", mask);
265 static
266 void print_nor (FILE *out, struct operation *op, int options)
268 struct value *val1, *val2;
269 int simple = 0;
271 val1 = list_headvalue (op->operands);
272 val2 = list_tailvalue (op->operands);
274 if (val1->val.intval == 0 || val2->val.intval == 0) {
275 simple = 1;
276 if (val1->val.intval == 0) val1 = val2;
279 if (!(options & OPTS_DEFERRED)) {
280 print_value (out, list_headvalue (op->results));
281 fprintf (out, " = ");
284 if (!simple) {
285 fprintf (out, "!(");
286 print_value (out, val1);
287 fprintf (out, " | ");
288 print_value (out, val2);
289 fprintf (out, ")");
290 } else {
291 fprintf (out, "!");
292 print_value (out, val1);
296 static
297 void print_movnz (FILE *out, struct operation *op, int ismovn, int options)
299 struct value *val1, *val2, *val3;
300 struct value *result;
301 element el;
303 el = list_head (op->operands);
304 val1 = element_getvalue (el); el = element_next (el);
305 val2 = element_getvalue (el); el = element_next (el);
306 val3 = element_getvalue (el);
307 result = list_headvalue (op->results);
309 if (!(options & OPTS_DEFERRED)) {
310 print_value (out, result);
311 fprintf (out, " = ");
314 if (ismovn)
315 fprintf (out, "(");
316 else
317 fprintf (out, "!(");
318 print_value (out, val2);
319 fprintf (out, ") ? ");
320 print_value (out, val1);
321 fprintf (out, " : ");
322 print_value (out, val3);
325 static
326 void print_slt (FILE *out, struct operation *op, int isunsigned, int options)
328 struct value *val1, *val2;
329 struct value *result;
330 element el;
332 el = list_head (op->operands);
333 val1 = element_getvalue (el); el = element_next (el);
334 val2 = element_getvalue (el);
335 result = list_headvalue (op->results);
337 if (!(options & OPTS_DEFERRED)) {
338 print_value (out, result);
339 fprintf (out, " = ");
342 fprintf (out, "(");
344 print_value (out, val1);
345 fprintf (out, " < ");
346 print_value (out, val2);
347 fprintf (out, ")");
350 static
351 void print_signextend (FILE *out, struct operation *op, int isbyte, int options)
353 if (!(options & OPTS_DEFERRED)) {
354 print_value (out, list_headvalue (op->results));
355 fprintf (out, " = ");
358 if (isbyte)
359 fprintf (out, "(char) ");
360 else
361 fprintf (out, "(short) ");
363 print_value (out, list_headvalue (op->operands));
366 static
367 void print_memory_address (FILE *out, struct operation *op, int size, int isunsigned, int options)
369 struct value *val;
370 uint32 address;
371 const char *type;
373 if (size == 0) {
374 if (isunsigned) type = "unsigned char *";
375 else type = "char *";
376 } else if (size == 1) {
377 if (isunsigned) type = "unsigned short *";
378 else type = "short *";
379 } else if (size == 2) {
380 type = "int *";
383 val = list_headvalue (op->operands);
384 if (val->type == VAL_VARIABLE) {
385 if (val->val.variable->type == VARIABLE_CONSTANT) {
386 address = val->val.variable->type;
387 val = list_tailvalue (op->operands);
388 address += val->val.intval;
389 fprintf (out, "*((%s) 0x%08X)", type, address);
390 return;
394 fprintf (out, "((%s) ", type);
395 print_value (out, val);
396 val = list_tailvalue (op->operands);
397 fprintf (out, ")[%d]", val->val.intval >> size);
400 static
401 void print_load (FILE *out, struct operation *op, int size, int isunsigned, int options)
403 if (!(options & OPTS_DEFERRED)) {
404 print_value (out, list_headvalue (op->results));
405 fprintf (out, " = ");
407 print_memory_address (out, op, size, isunsigned, options);
410 static
411 void print_store (FILE *out, struct operation *op, int size, int isunsigned, int options)
413 struct value *val = element_getvalue (element_next (list_head (op->operands)));
414 print_memory_address (out, op, size, isunsigned, options);
415 fprintf (out, " = ");
416 print_value (out, val);
419 static
420 void print_condition (FILE *out, struct operation *op, int options)
422 fprintf (out, "if (");
423 if (options & OPTS_REVERSECOND) fprintf (out, "!(");
424 print_value (out, list_headvalue (op->operands));
425 switch (op->info.iop.insn) {
426 case I_BNE:
427 fprintf (out, " != ");
428 break;
429 case I_BEQ:
430 fprintf (out, " == ");
431 break;
432 case I_BGEZ:
433 case I_BGEZAL:
434 fprintf (out, " >= 0");
435 break;
436 case I_BGTZ:
437 fprintf (out, " > 0");
438 break;
439 case I_BLEZ:
440 fprintf (out, " <= 0");
441 break;
442 case I_BLTZ:
443 case I_BLTZAL:
444 fprintf (out, " < 0");
445 break;
446 default:
447 break;
449 if (list_size (op->operands) == 2)
450 print_value (out, list_tailvalue (op->operands));
452 if (options & OPTS_REVERSECOND) fprintf (out, ")");
453 fprintf (out, ")");
458 void print_operation (FILE *out, struct operation *op, int identsize, int options)
460 int nosemicolon = FALSE;
462 if (op->type == OP_ASM) {
463 print_asm (out, op, identsize, options);
464 return;
467 if (op->type == OP_INSTRUCTION) {
468 if (op->info.iop.loc->insn->flags & (INSN_JUMP))
469 return;
470 } else if (op->type == OP_NOP || op->type == OP_START ||
471 op->type == OP_END || op->type == OP_PHI) {
472 return;
475 ident_line (out, identsize);
476 if (op->type == OP_INSTRUCTION) {
477 switch (op->info.iop.insn) {
478 case I_ADD: print_binaryop (out, op, "+", options); break;
479 case I_ADDU: print_binaryop (out, op, "+", options); break;
480 case I_SUB: print_binaryop (out, op, "-", options); break;
481 case I_SUBU: print_binaryop (out, op, "-", options); break;
482 case I_XOR: print_binaryop (out, op, "^", options); break;
483 case I_AND: print_binaryop (out, op, "&", options); break;
484 case I_OR: print_binaryop (out, op, "|", options); break;
485 case I_SRAV: print_binaryop (out, op, ">>", options); break;
486 case I_SRLV: print_binaryop (out, op, ">>", options); break;
487 case I_SLLV: print_binaryop (out, op, "<<", options); break;
488 case I_INS: print_ins (out, op, options); break;
489 case I_EXT: print_ext (out, op, options); break;
490 case I_MIN: print_complexop (out, op, "MIN", options); break;
491 case I_MAX: print_complexop (out, op, "MAX", options); break;
492 case I_BITREV: print_complexop (out, op, "BITREV", options); break;
493 case I_CLZ: print_complexop (out, op, "CLZ", options); break;
494 case I_CLO: print_complexop (out, op, "CLO", options); break;
495 case I_NOR: print_nor (out, op, options); break;
496 case I_MOVN: print_movnz (out, op, TRUE, options); break;
497 case I_MOVZ: print_movnz (out, op, FALSE, options); break;
498 case I_SLT: print_slt (out, op, FALSE, options); break;
499 case I_SLTU: print_slt (out, op, TRUE, options); break;
500 case I_LW: print_load (out, op, 2, FALSE, options); break;
501 case I_LB: print_load (out, op, 0, FALSE, options); break;
502 case I_LBU: print_load (out, op, 0, TRUE, options); break;
503 case I_LH: print_load (out, op, 1, FALSE, options); break;
504 case I_LHU: print_load (out, op, 1, TRUE, options); break;
505 case I_LL: print_complexop (out, op, "LL", options); break;
506 case I_LWL: print_complexop (out, op, "LWL", options); break;
507 case I_LWR: print_complexop (out, op, "LWR", options); break;
508 case I_SW: print_store (out, op, 2, FALSE, options); break;
509 case I_SH: print_store (out, op, 1, FALSE, options); break;
510 case I_SB: print_store (out, op, 0, FALSE, options); break;
511 case I_SC: print_complexop (out, op, "SC", options); break;
512 case I_SWL: print_complexop (out, op, "SWL", options); break;
513 case I_SWR: print_complexop (out, op, "SWR", options); break;
514 case I_SEB: print_signextend (out, op, TRUE, options); break;
515 case I_SEH: print_signextend (out, op, TRUE, options); break;
516 default:
517 if (op->info.iop.loc->insn->flags & INSN_BRANCH) {
518 print_condition (out, op, options);
519 nosemicolon = TRUE;
521 break;
523 } else if (op->type == OP_MOVE) {
524 if (!options) {
525 print_value (out, list_headvalue (op->results));
526 fprintf (out, " = ");
528 print_value (out, list_headvalue (op->operands));
529 } else if (op->type == OP_CALL) {
530 print_call (out, op, options);
533 if (!(options & OPTS_DEFERRED)) {
534 if (nosemicolon) fprintf (out, "\n");
535 else fprintf (out, ";\n");