Passo intermediario, ainda falta um longo caminho
[pspdecompiler.git] / switches.c
blob7d89f2ade85aa64df184be84b1928882ed13a752
2 #include "code.h"
3 #include "utils.h"
5 static
6 int check_switch (struct code *c, struct codeswitch *cs)
8 struct location *loc = cs->location;
9 element el;
10 uint32 def, used;
12 if (!loc->insn) return 0;
14 if (loc->insn->insn == I_LW) {
15 def = location_gpr_defined (loc);
16 while (1) {
17 if (loc++ == c->end) return 0;
18 if (!loc->insn) return 0;
19 used = location_gpr_used (loc);
20 if (used & def) {
21 if (loc->insn->insn != I_JR)
22 return 0;
23 break;
25 if (loc->insn->flags & (INSN_JUMP | INSN_BRANCH)) return 0;
27 } else if (loc->insn->insn == I_ADDIU) {
28 int count = 0;
29 def = location_gpr_defined (loc);
30 while (1) {
31 if (loc++ == c->end) return 0;
32 if (!loc->insn) return 0;
33 used = location_gpr_used (loc);
34 if (used & def) {
35 if (count == 0) {
36 if (loc->insn->insn != I_ADDU) return 0;
37 } else if (count == 1) {
38 if (loc->insn->insn != I_LW) return 0;
39 } else {
40 if (loc->insn->insn != I_JR)
41 return 0;
42 break;
44 count++;
45 def = location_gpr_defined (loc);
47 if (loc->insn->flags & (INSN_JUMP | INSN_BRANCH)) return 0;
49 } else return 0;
51 cs->jumplocation = loc;
52 cs->jumplocation->cswitch = cs;
54 el = list_head (cs->references);
55 while (el) {
56 struct location *target = element_getvalue (el);
57 target->cswitch = cs;
58 el = element_next (el);
61 return 1;
64 void extract_switches (struct code *c)
66 struct prx_reloc *aux;
67 uint32 base, end, count = 0;
68 uint32 i, j, tgt;
70 for (i = 0; i < c->file->relocnum; i++) {
71 struct prx_reloc *rel = &c->file->relocsbyaddr[i];
72 count = 0;
73 do {
74 if (rel->type != R_MIPS_32) break;
75 tgt = (rel[count].target - c->baddr) >> 2;
76 if (tgt >= c->numopc) break;
77 if (rel[count].target & 0x03) break;
79 count++;
80 } while ((i + count) < c->file->relocnum);
82 if (count == 0) continue;
84 base = end = prx_findreloc (c->file, rel->vaddr);
85 if (base >= c->file->relocnum) continue;
86 if (c->file->relocs[base].target != rel->vaddr) continue;
88 for (; end < c->file->relocnum; end++) {
89 aux = &c->file->relocs[end];
90 if (aux->target != rel->vaddr) {
91 if (aux->target & 0x03) {
92 error (__FILE__ ": relocation target not word aligned 0x%08X", aux->target);
93 count = 0;
94 } else if (count > ((aux->target - rel->vaddr) >> 2))
95 count = (aux->target - rel->vaddr) >> 2;
96 break;
100 if (count <= 1) continue;
102 for (;base < end; base++) {
103 aux = &c->file->relocs[base];
104 tgt = (aux->vaddr - c->baddr) >> 2;
105 if (tgt >= c->numopc) continue;
106 if (aux->vaddr & 0x03) {
107 error (__FILE__ ": relocation vaddr not word aligned 0x%08X", aux->vaddr);
108 continue;
111 if (aux->type == R_MIPS_LO16) {
112 struct codeswitch *cs;
114 cs = fixedpool_alloc (c->switchpool);
116 cs->jumpreloc = aux;
117 cs->switchreloc = rel;
118 cs->location = &c->base[tgt];
119 cs->count = count;
120 cs->references = list_alloc (c->lstpool);
121 for (j = 0; j < count; j++) {
122 tgt = (rel[j].target - c->baddr) >> 2;
123 list_inserttail (cs->references, &c->base[tgt]);
126 if (!check_switch (c, cs)) {
127 fixedpool_free (c->switchpool, cs);