Hlide problem solved (i believe)
[pspdecompiler.git] / switches.c
blob41cbd902a0a4063de632e694b901f42e57284547
1 /**
2 * Author: Humberto Naves (hsnaves@gmail.com)
3 */
5 #include "code.h"
6 #include "utils.h"
8 static
9 int check_switch (struct code *c, struct codeswitch *cs)
11 struct location *loc = cs->location;
12 element el;
13 uint32 def, used;
15 if (!loc->insn) return 0;
17 if (loc->insn->insn == I_LW) {
18 def = location_gpr_defined (loc);
19 while (1) {
20 if (loc++ == c->end) return 0;
21 if (!loc->insn) return 0;
22 used = location_gpr_used (loc);
23 if (used & def) {
24 if (loc->insn->insn != I_JR)
25 return 0;
26 break;
28 if (loc->insn->flags & (INSN_JUMP | INSN_BRANCH)) return 0;
30 } else if (loc->insn->insn == I_ADDIU) {
31 int count = 0;
32 def = location_gpr_defined (loc);
33 while (1) {
34 if (loc++ == c->end) return 0;
35 if (!loc->insn) return 0;
36 used = location_gpr_used (loc);
37 if (used & def) {
38 if (count == 0) {
39 if (loc->insn->insn != I_ADDU) return 0;
40 } else if (count == 1) {
41 if (loc->insn->insn != I_LW) return 0;
42 } else {
43 if (loc->insn->insn != I_JR)
44 return 0;
45 break;
47 count++;
48 def = location_gpr_defined (loc);
50 if (loc->insn->flags & (INSN_JUMP | INSN_BRANCH)) return 0;
52 } else return 0;
54 cs->jumplocation = loc;
55 cs->jumplocation->cswitch = cs;
57 el = list_head (cs->references);
58 while (el) {
59 struct location *target = element_getvalue (el);
60 target->cswitch = cs;
61 el = element_next (el);
64 return 1;
67 void extract_switches (struct code *c)
69 struct prx_reloc *aux;
70 uint32 base, end, count = 0;
71 uint32 i, j, tgt;
73 for (i = 0; i < c->file->relocnum; i++) {
74 struct prx_reloc *rel = &c->file->relocsbyaddr[i];
75 count = 0;
76 do {
77 if (rel->type != R_MIPS_32) break;
78 tgt = (rel[count].target - c->baddr) >> 2;
79 if (tgt >= c->numopc) break;
80 if (rel[count].target & 0x03) break;
82 count++;
83 } while ((i + count) < c->file->relocnum);
85 if (count == 0) continue;
87 base = end = prx_findreloc (c->file, rel->vaddr);
88 if (base >= c->file->relocnum) continue;
89 if (c->file->relocs[base].target != rel->vaddr) continue;
91 for (; end < c->file->relocnum; end++) {
92 aux = &c->file->relocs[end];
93 if (aux->target != rel->vaddr) {
94 if (aux->target & 0x03) {
95 error (__FILE__ ": relocation target not word aligned 0x%08X", aux->target);
96 count = 0;
97 } else if (count > ((aux->target - rel->vaddr) >> 2))
98 count = (aux->target - rel->vaddr) >> 2;
99 break;
103 if (count <= 1) continue;
105 for (;base < end; base++) {
106 aux = &c->file->relocs[base];
107 tgt = (aux->vaddr - c->baddr) >> 2;
108 if (tgt >= c->numopc) continue;
109 if (aux->vaddr & 0x03) {
110 error (__FILE__ ": relocation vaddr not word aligned 0x%08X", aux->vaddr);
111 continue;
114 if (aux->type == R_MIPS_LO16) {
115 struct codeswitch *cs;
117 cs = fixedpool_alloc (c->switchpool);
119 cs->jumpreloc = aux;
120 cs->switchreloc = rel;
121 cs->location = &c->base[tgt];
122 cs->count = count;
123 cs->references = list_alloc (c->lstpool);
124 for (j = 0; j < count; j++) {
125 tgt = (rel[j].target - c->baddr) >> 2;
126 list_inserttail (cs->references, &c->base[tgt]);
129 if (!check_switch (c, cs)) {
130 fixedpool_free (c->switchpool, cs);