Varias mudancas
[pspdecompiler.git] / operations.c
blob0721509b5e79e77303ed22d69c24e9e142082389
2 #include "code.h"
3 #include "utils.h"
6 const uint32 regmask_call_gen[NUM_REGMASK] = { 0xAC000000, 0x00000000 };
7 const uint32 regmask_call_kill[NUM_REGMASK] = { 0x0300FFFE, 0x00000003 };
8 const uint32 regmask_subend_gen[NUM_REGMASK] = { 0xF0FF0000, 0x00000000 };
11 #define BLOCK_GPR_KILL() \
12 if (regno != 0) { \
13 BIT_SET (block->reg_kill, regno); \
16 #define BLOCK_GPR_GEN() \
17 if (!IS_BIT_SET (block->reg_kill, regno) && regno != 0 && \
18 !IS_BIT_SET (block->reg_gen, regno)) { \
19 BIT_SET (block->reg_gen, regno); \
22 #define ASM_GPR_KILL() \
23 BLOCK_GPR_KILL () \
24 if (!IS_BIT_SET (asm_kill, regno) && regno != 0) { \
25 BIT_SET (asm_kill, regno); \
26 value_append (sub, op->results, VAL_REGISTER, regno); \
29 #define ASM_GPR_GEN() \
30 BLOCK_GPR_GEN () \
31 if (!IS_BIT_SET (asm_kill, regno) && regno != 0 && \
32 !IS_BIT_SET (asm_gen, regno)) { \
33 BIT_SET (asm_gen, regno); \
34 value_append (sub, op->operands, VAL_REGISTER, regno); \
38 struct operation *operation_alloc (struct basicblock *block)
40 struct operation *op;
41 struct code *c = block->sub->code;
43 op = fixedpool_alloc (c->opspool);
44 op->block = block;
45 op->operands = list_alloc (c->lstpool);
46 op->results = list_alloc (c->lstpool);
47 return op;
50 static
51 void reset_operation (struct operation *op)
53 struct value *val;
54 struct code *c = op->block->sub->code;
56 while (list_size (op->results)) {
57 val = list_removehead (op->results);
58 fixedpool_free (c->valspool, val);
61 while (list_size (op->operands)) {
62 val = list_removehead (op->operands);
63 fixedpool_free (c->valspool, val);
67 static
68 void simplify_reg_zero (list l)
70 struct value *val;
71 element el;
73 el = list_head (l);
74 while (el) {
75 val = element_getvalue (el);
76 if (val->type == VAL_REGISTER && val->val.intval == 0) {
77 val->type = VAL_CONSTANT;
79 el = element_next (el);
83 static
84 void simplify_operation (struct operation *op)
86 struct value *val;
87 struct code *c = op->block->sub->code;
89 if (op->type != OP_INSTRUCTION) return;
91 if (list_size (op->results) == 1 && !(op->info.iop.loc->insn->flags & (INSN_LOAD | INSN_JUMP))) {
92 val = list_headvalue (op->results);
93 if (val->val.intval == 0) {
94 reset_operation (op);
95 op->type = OP_NOP;
96 return;
99 simplify_reg_zero (op->results);
100 simplify_reg_zero (op->operands);
102 switch (op->info.iop.insn) {
103 case I_ADDU:
104 case I_ADD:
105 case I_OR:
106 case I_XOR:
107 val = list_headvalue (op->operands);
108 if (val->val.intval == 0) {
109 val = list_removehead (op->operands);
110 fixedpool_free (c->valspool, val);
111 op->type = OP_MOVE;
112 } else {
113 val = list_tailvalue (op->operands);
114 if (val->val.intval == 0) {
115 val = list_removetail (op->operands);
116 fixedpool_free (c->valspool, val);
117 op->type = OP_MOVE;
120 break;
121 case I_AND:
122 val = list_headvalue (op->operands);
123 if (val->val.intval == 0) {
124 val = list_removetail (op->operands);
125 fixedpool_free (c->valspool, val);
126 op->type = OP_MOVE;
127 } else {
128 val = list_tailvalue (op->operands);
129 if (val->val.intval == 0) {
130 val = list_removehead (op->operands);
131 fixedpool_free (c->valspool, val);
132 op->type = OP_MOVE;
136 break;
137 case I_BITREV:
138 case I_SEB:
139 case I_SEH:
140 case I_WSBH:
141 case I_WSBW:
142 val = list_headvalue (op->operands);
143 if (val->val.intval == 0) {
144 op->type = OP_MOVE;
146 break;
147 case I_SUB:
148 case I_SUBU:
149 case I_SLLV:
150 case I_SRLV:
151 case I_SRAV:
152 case I_ROTV:
153 val = list_tailvalue (op->operands);
154 if (val->val.intval == 0) {
155 val = list_removetail (op->operands);
156 fixedpool_free (c->valspool, val);
157 op->type = OP_MOVE;
159 case I_MOVN:
160 val = element_getvalue (element_next (list_head (op->operands)));
161 if (val->val.intval == 0) {
162 reset_operation (op);
163 op->type = OP_NOP;
165 break;
166 case I_MOVZ:
167 val = element_getvalue (element_next (list_head (op->operands)));
168 if (val->val.intval == 0) {
169 val = list_removetail (op->operands);
170 fixedpool_free (c->valspool, val);
171 val = list_removetail (op->operands);
172 fixedpool_free (c->valspool, val);
173 op->type = OP_MOVE;
175 break;
176 default:
177 break;
180 return;
183 struct value *value_append (struct subroutine *sub, list l, enum valuetype type, uint32 value)
185 struct value *val;
186 val = fixedpool_alloc (sub->code->valspool);
187 val->type = type;
188 val->val.intval = value;
189 list_inserttail (l, val);
190 return val;
193 void extract_operations (struct subroutine *sub)
195 struct operation *op;
196 struct basicblock *block;
197 struct location *loc;
198 struct prx *file;
199 uint32 asm_gen[NUM_REGMASK], asm_kill[NUM_REGMASK];
200 int i, regno, lastasm, relocnum;
201 element el;
203 file = sub->code->file;
204 el = list_head (sub->blocks);
205 while (el) {
206 block = element_getvalue (el);
207 block->operations = list_alloc (sub->code->lstpool);
209 for (i = 0; i < NUM_REGMASK; i++)
210 block->reg_gen[i] = block->reg_kill[i] = 0;
212 switch (block->type) {
213 case BLOCK_SIMPLE:
214 lastasm = FALSE;
215 relocnum = prx_findrelocbyaddr (file, block->info.simple.begin->address);
217 for (i = 0; i < NUM_REGMASK; i++)
218 asm_gen[i] = asm_kill[i] = 0;
220 for (loc = block->info.simple.begin; ; loc++) {
221 int hasreloc = FALSE;
223 if (relocnum < file->relocnum) {
224 if (file->relocsbyaddr[relocnum].vaddr == loc->address) {
225 hasreloc = TRUE;
226 relocnum++;
230 if (INSN_TYPE (loc->insn->flags) == INSN_ALLEGREX) {
231 enum allegrex_insn insn;
233 if (lastasm)
234 list_inserttail (block->operations, op);
235 lastasm = FALSE;
237 op = operation_alloc (block);
238 op->type = OP_INSTRUCTION;
239 if (hasreloc)
240 op->status |= OP_STAT_HASRELOC;
241 op->info.iop.loc = loc;
243 if (loc->insn->flags & INSN_READ_GPR_S) {
244 regno = RS (loc->opc);
245 BLOCK_GPR_GEN ()
246 value_append (sub, op->operands, VAL_REGISTER, regno);
249 if (loc->insn->flags & INSN_READ_GPR_T) {
250 regno = RT (loc->opc);
251 BLOCK_GPR_GEN ()
252 value_append (sub, op->operands, VAL_REGISTER, regno);
255 if (loc->insn->flags & INSN_READ_GPR_D) {
256 regno = RD (loc->opc);
257 BLOCK_GPR_GEN ()
258 value_append (sub, op->operands, VAL_REGISTER, regno);
261 if (loc->insn->flags & INSN_READ_LO) {
262 regno = REGISTER_LO;
263 BLOCK_GPR_GEN ()
264 value_append (sub, op->operands, VAL_REGISTER, regno);
267 if (loc->insn->flags & INSN_READ_HI) {
268 regno = REGISTER_HI;
269 BLOCK_GPR_GEN ()
270 value_append (sub, op->operands, VAL_REGISTER, regno);
273 if (loc->insn->flags & (INSN_LOAD | INSN_STORE)) {
274 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
277 switch (loc->insn->insn) {
278 case I_ADDI:
279 insn = I_ADD;
280 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
281 break;
282 case I_ADDIU:
283 insn = I_ADDU;
284 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
285 break;
286 case I_ORI:
287 insn = I_OR;
288 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
289 break;
290 case I_XORI:
291 insn = I_XOR;
292 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
293 break;
294 case I_ANDI:
295 insn = I_AND;
296 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
297 break;
298 case I_LUI:
299 op->type = OP_MOVE;
300 value_append (sub, op->operands, VAL_CONSTANT, ((unsigned int) IMMU (loc->opc)) << 16);
301 break;
302 case I_SLTI:
303 insn = I_SLT;
304 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
305 break;
306 case I_SLTIU:
307 insn = I_SLTU;
308 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
309 break;
310 case I_EXT:
311 insn = I_EXT;
312 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
313 value_append (sub, op->operands, VAL_CONSTANT, RD (loc->opc) + 1);
314 break;
315 case I_INS:
316 insn = I_INS;
317 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
318 value_append (sub, op->operands, VAL_CONSTANT, RD (loc->opc) - SA (loc->opc) + 1);
319 break;
320 case I_ROTR:
321 insn = I_ROTV;
322 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
323 break;
324 case I_SLL:
325 insn = I_SLLV;
326 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
327 break;
328 case I_SRA:
329 insn = I_SRAV;
330 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
331 break;
332 case I_SRL:
333 insn = I_SRLV;
334 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
335 break;
336 case I_BEQL:
337 insn = I_BEQ;
338 break;
339 case I_BGEZL:
340 insn = I_BGEZ;
341 break;
342 case I_BGTZL:
343 insn = I_BGTZ;
344 break;
345 case I_BLEZL:
346 insn = I_BLEZ;
347 break;
348 case I_BLTZL:
349 insn = I_BLTZ;
350 break;
351 case I_BLTZALL:
352 insn = I_BLTZAL;
353 break;
354 case I_BNEL:
355 insn = I_BNE;
356 break;
357 default:
358 insn = loc->insn->insn;
360 op->info.iop.insn = insn;
362 if (loc->insn->flags & INSN_WRITE_GPR_T) {
363 regno = RT (loc->opc);
364 BLOCK_GPR_KILL ()
365 value_append (sub, op->results, VAL_REGISTER, regno);
368 if (loc->insn->flags & INSN_WRITE_GPR_D) {
369 regno = RD (loc->opc);
370 BLOCK_GPR_KILL ()
371 value_append (sub, op->results, VAL_REGISTER, regno);
374 if (loc->insn->flags & INSN_WRITE_LO) {
375 regno = REGISTER_LO;
376 BLOCK_GPR_KILL ()
377 value_append (sub, op->results, VAL_REGISTER, regno);
380 if (loc->insn->flags & INSN_WRITE_HI) {
381 regno = REGISTER_HI;
382 BLOCK_GPR_KILL ()
383 value_append (sub, op->results, VAL_REGISTER, regno);
386 if (loc->insn->flags & INSN_LINK) {
387 regno = REGISTER_GPR_RA;
388 BLOCK_GPR_KILL ()
389 value_append (sub, op->results, VAL_REGISTER, regno);
392 simplify_operation (op);
393 list_inserttail (block->operations, op);
395 } else {
396 if (!lastasm) {
397 op = operation_alloc (block);
398 op->info.asmop.begin = op->info.asmop.end = loc;
399 op->type = OP_ASM;
400 for (i = 0; i < NUM_REGMASK; i++)
401 asm_gen[i] = asm_kill[i] = 0;
402 } else {
403 op->info.asmop.end = loc;
405 lastasm = TRUE;
407 if (loc->insn->flags & INSN_READ_LO) {
408 regno = REGISTER_LO;
409 ASM_GPR_GEN ()
412 if (loc->insn->flags & INSN_READ_HI) {
413 regno = REGISTER_HI;
414 ASM_GPR_GEN ()
417 if (loc->insn->flags & INSN_READ_GPR_D) {
418 regno = RD (loc->opc);
419 ASM_GPR_GEN ()
422 if (loc->insn->flags & INSN_READ_GPR_T) {
423 regno = RT (loc->opc);
424 ASM_GPR_GEN ()
427 if (loc->insn->flags & INSN_READ_GPR_S) {
428 regno = RS (loc->opc);
429 ASM_GPR_GEN ()
432 if (loc->insn->flags & INSN_WRITE_GPR_T) {
433 regno = RT (loc->opc);
434 ASM_GPR_KILL ()
437 if (loc->insn->flags & INSN_WRITE_GPR_D) {
438 regno = RD (loc->opc);
439 ASM_GPR_KILL ()
442 if (loc->insn->flags & INSN_WRITE_LO) {
443 regno = REGISTER_LO;
444 ASM_GPR_KILL ()
447 if (loc->insn->flags & INSN_WRITE_HI) {
448 regno = REGISTER_HI;
449 ASM_GPR_KILL ()
452 if (loc->insn->flags & INSN_LINK) {
453 regno = REGISTER_GPR_RA;
454 ASM_GPR_KILL ()
458 if (loc == block->info.simple.end) {
459 if (lastasm)
460 list_inserttail (block->operations, op);
461 break;
464 break;
466 case BLOCK_CALL:
467 op = operation_alloc (block);
468 op->type = OP_CALL;
469 op->info.callop.arguments = list_alloc (sub->code->lstpool);
470 op->info.callop.retvalues = list_alloc (sub->code->lstpool);
471 list_inserttail (block->operations, op);
473 for (regno = 1; regno <= NUM_REGISTERS; regno++) {
474 if (IS_BIT_SET (regmask_call_gen, regno)) {
475 BLOCK_GPR_GEN ()
476 value_append (sub, op->operands, VAL_REGISTER, regno);
478 if (IS_BIT_SET (regmask_call_kill, regno)) {
479 BLOCK_GPR_KILL ()
480 value_append (sub, op->results, VAL_REGISTER, regno);
483 break;
485 case BLOCK_START:
486 op = operation_alloc (block);
487 op->type = OP_START;
489 for (regno = 1; regno < NUM_REGISTERS; regno++) {
490 BLOCK_GPR_KILL ()
491 value_append (sub, op->results, VAL_REGISTER, regno);
493 list_inserttail (block->operations, op);
494 break;
496 case BLOCK_END:
497 op = operation_alloc (block);
498 op->type = OP_END;
500 for (regno = 1; regno < NUM_REGISTERS; regno++) {
501 if (IS_BIT_SET (regmask_subend_gen, regno)) {
502 BLOCK_GPR_GEN ()
503 value_append (sub, op->operands, VAL_REGISTER, regno);
507 list_inserttail (block->operations, op);
508 break;
511 el = element_next (el);
516 void fixup_call_arguments (struct subroutine *sub)
518 struct operation *op;
519 struct basicblock *block;
520 struct value *val;
521 element el;
522 int regno, regend;
524 el = list_head (sub->blocks);
525 while (el) {
526 block = element_getvalue (el);
527 if (block->type == BLOCK_CALL) {
528 struct subroutine *target;
529 op = list_tailvalue (block->operations);
530 target = block->info.call.calltarget;
532 regend = REGISTER_GPR_T4;
533 if (target)
534 if (target->numregargs != -1)
535 regend = REGISTER_GPR_A0 + target->numregargs;
537 for (regno = REGISTER_GPR_A0; regno < regend; regno++) {
538 val = value_append (sub, op->operands, VAL_REGISTER, regno);
539 list_inserttail (op->info.callop.arguments, val);
542 if (target) regend = REGISTER_GPR_V0 + target->numregout;
543 else regend = REGISTER_GPR_A0;
545 for (regno = REGISTER_GPR_V0; regno < regend; regno++) {
546 val = value_append (sub, op->results, VAL_REGISTER, regno);
547 list_inserttail (op->info.callop.retvalues, val);
550 el = element_next (el);
554 void remove_call_arguments (struct subroutine *sub)
556 struct operation *op;
557 struct basicblock *block;
558 struct value *val;
559 element el;
561 el = list_head (sub->blocks);
562 while (el) {
563 block = element_getvalue (el);
564 if (block->type == BLOCK_CALL) {
565 op = list_tailvalue (block->operations);
566 while (list_size (op->info.callop.arguments) != 0) {
567 val = list_removetail (op->info.callop.arguments);
568 list_removetail (op->operands);
569 fixedpool_free (sub->code->valspool, val);
571 while (list_size (op->info.callop.retvalues) != 0) {
572 val = list_removetail (op->info.callop.retvalues);
573 list_removetail (op->results);
574 fixedpool_free (sub->code->valspool, val);
577 el = element_next (el);