Com o autor
[pspdecompiler.git] / operations.c
blob96871348b7f5c99de71c3ff9964ac51a7246106f
1 /**
2 * Author: Humberto Naves (hsnaves@gmail.com)
3 */
5 #include "code.h"
6 #include "utils.h"
9 const uint32 regmask_call_gen[NUM_REGMASK] = { 0xAC000000, 0x00000000 };
10 const uint32 regmask_call_kill[NUM_REGMASK] = { 0x0300FFFE, 0x00000003 };
11 const uint32 regmask_subend_gen[NUM_REGMASK] = { 0xF0FF0000, 0x00000000 };
14 #define BLOCK_GPR_KILL() \
15 if (regno != 0) { \
16 BIT_SET (block->reg_kill, regno); \
19 #define BLOCK_GPR_GEN() \
20 if (!IS_BIT_SET (block->reg_kill, regno) && regno != 0 && \
21 !IS_BIT_SET (block->reg_gen, regno)) { \
22 BIT_SET (block->reg_gen, regno); \
25 #define ASM_GPR_KILL() \
26 BLOCK_GPR_KILL () \
27 if (!IS_BIT_SET (asm_kill, regno) && regno != 0) { \
28 BIT_SET (asm_kill, regno); \
29 value_append (sub, op->results, VAL_REGISTER, regno); \
32 #define ASM_GPR_GEN() \
33 BLOCK_GPR_GEN () \
34 if (!IS_BIT_SET (asm_kill, regno) && regno != 0 && \
35 !IS_BIT_SET (asm_gen, regno)) { \
36 BIT_SET (asm_gen, regno); \
37 value_append (sub, op->operands, VAL_REGISTER, regno); \
41 struct operation *operation_alloc (struct basicblock *block)
43 struct operation *op;
44 struct code *c = block->sub->code;
46 op = fixedpool_alloc (c->opspool);
47 op->block = block;
48 op->operands = list_alloc (c->lstpool);
49 op->results = list_alloc (c->lstpool);
50 return op;
53 static
54 void reset_operation (struct operation *op)
56 struct value *val;
57 struct code *c = op->block->sub->code;
59 while (list_size (op->results)) {
60 val = list_removehead (op->results);
61 fixedpool_free (c->valspool, val);
64 while (list_size (op->operands)) {
65 val = list_removehead (op->operands);
66 fixedpool_free (c->valspool, val);
70 static
71 void simplify_reg_zero (list l)
73 struct value *val;
74 element el;
76 el = list_head (l);
77 while (el) {
78 val = element_getvalue (el);
79 if (val->type == VAL_REGISTER && val->val.intval == 0) {
80 val->type = VAL_CONSTANT;
82 el = element_next (el);
86 static
87 void simplify_operation (struct operation *op)
89 struct value *val;
90 struct code *c = op->block->sub->code;
92 if (op->type != OP_INSTRUCTION) return;
94 if (list_size (op->results) == 1 && !(op->info.iop.loc->insn->flags & (INSN_LOAD | INSN_JUMP))) {
95 val = list_headvalue (op->results);
96 if (val->val.intval == 0) {
97 reset_operation (op);
98 op->type = OP_NOP;
99 return;
102 simplify_reg_zero (op->results);
103 simplify_reg_zero (op->operands);
105 switch (op->info.iop.insn) {
106 case I_ADDU:
107 case I_ADD:
108 case I_OR:
109 case I_XOR:
110 val = list_headvalue (op->operands);
111 if (val->val.intval == 0) {
112 val = list_removehead (op->operands);
113 fixedpool_free (c->valspool, val);
114 op->type = OP_MOVE;
115 } else {
116 val = list_tailvalue (op->operands);
117 if (val->val.intval == 0) {
118 val = list_removetail (op->operands);
119 fixedpool_free (c->valspool, val);
120 op->type = OP_MOVE;
123 break;
124 case I_AND:
125 val = list_headvalue (op->operands);
126 if (val->val.intval == 0) {
127 val = list_removetail (op->operands);
128 fixedpool_free (c->valspool, val);
129 op->type = OP_MOVE;
130 } else {
131 val = list_tailvalue (op->operands);
132 if (val->val.intval == 0) {
133 val = list_removehead (op->operands);
134 fixedpool_free (c->valspool, val);
135 op->type = OP_MOVE;
139 break;
140 case I_BITREV:
141 case I_SEB:
142 case I_SEH:
143 case I_WSBH:
144 case I_WSBW:
145 val = list_headvalue (op->operands);
146 if (val->val.intval == 0) {
147 op->type = OP_MOVE;
149 break;
150 case I_SUB:
151 case I_SUBU:
152 case I_SLLV:
153 case I_SRLV:
154 case I_SRAV:
155 case I_ROTV:
156 val = list_tailvalue (op->operands);
157 if (val->val.intval == 0) {
158 val = list_removetail (op->operands);
159 fixedpool_free (c->valspool, val);
160 op->type = OP_MOVE;
162 case I_MOVN:
163 val = element_getvalue (element_next (list_head (op->operands)));
164 if (val->val.intval == 0) {
165 reset_operation (op);
166 op->type = OP_NOP;
168 break;
169 case I_MOVZ:
170 val = element_getvalue (element_next (list_head (op->operands)));
171 if (val->val.intval == 0) {
172 val = list_removetail (op->operands);
173 fixedpool_free (c->valspool, val);
174 val = list_removetail (op->operands);
175 fixedpool_free (c->valspool, val);
176 op->type = OP_MOVE;
178 break;
179 default:
180 break;
183 return;
186 struct value *value_append (struct subroutine *sub, list l, enum valuetype type, uint32 value)
188 struct value *val;
189 val = fixedpool_alloc (sub->code->valspool);
190 val->type = type;
191 val->val.intval = value;
192 list_inserttail (l, val);
193 return val;
196 void extract_operations (struct subroutine *sub)
198 struct operation *op;
199 struct basicblock *block;
200 struct location *loc;
201 struct prx *file;
202 uint32 asm_gen[NUM_REGMASK], asm_kill[NUM_REGMASK];
203 int i, regno, lastasm, relocnum;
204 element el;
206 file = sub->code->file;
207 el = list_head (sub->blocks);
208 while (el) {
209 block = element_getvalue (el);
210 block->operations = list_alloc (sub->code->lstpool);
212 for (i = 0; i < NUM_REGMASK; i++)
213 block->reg_gen[i] = block->reg_kill[i] = 0;
215 switch (block->type) {
216 case BLOCK_SIMPLE:
217 lastasm = FALSE;
218 relocnum = prx_findrelocbyaddr (file, block->info.simple.begin->address);
220 for (i = 0; i < NUM_REGMASK; i++)
221 asm_gen[i] = asm_kill[i] = 0;
223 for (loc = block->info.simple.begin; ; loc++) {
224 int hasreloc = FALSE;
226 if (relocnum < file->relocnum) {
227 if (file->relocsbyaddr[relocnum].vaddr == loc->address) {
228 hasreloc = TRUE;
229 relocnum++;
233 if (INSN_TYPE (loc->insn->flags) == INSN_ALLEGREX) {
234 enum allegrex_insn insn;
236 if (lastasm)
237 list_inserttail (block->operations, op);
238 lastasm = FALSE;
240 op = operation_alloc (block);
241 op->type = OP_INSTRUCTION;
242 if (hasreloc)
243 op->status |= OP_STAT_HASRELOC;
244 op->info.iop.loc = loc;
246 if (loc->insn->flags & INSN_READ_GPR_S) {
247 regno = RS (loc->opc);
248 BLOCK_GPR_GEN ()
249 value_append (sub, op->operands, VAL_REGISTER, regno);
252 if (loc->insn->flags & INSN_READ_GPR_T) {
253 regno = RT (loc->opc);
254 BLOCK_GPR_GEN ()
255 value_append (sub, op->operands, VAL_REGISTER, regno);
258 if (loc->insn->flags & INSN_READ_GPR_D) {
259 regno = RD (loc->opc);
260 BLOCK_GPR_GEN ()
261 value_append (sub, op->operands, VAL_REGISTER, regno);
264 if (loc->insn->flags & INSN_READ_LO) {
265 regno = REGISTER_LO;
266 BLOCK_GPR_GEN ()
267 value_append (sub, op->operands, VAL_REGISTER, regno);
270 if (loc->insn->flags & INSN_READ_HI) {
271 regno = REGISTER_HI;
272 BLOCK_GPR_GEN ()
273 value_append (sub, op->operands, VAL_REGISTER, regno);
276 if (loc->insn->flags & (INSN_LOAD | INSN_STORE)) {
277 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
280 switch (loc->insn->insn) {
281 case I_ADDI:
282 insn = I_ADD;
283 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
284 break;
285 case I_ADDIU:
286 insn = I_ADDU;
287 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
288 break;
289 case I_ORI:
290 insn = I_OR;
291 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
292 break;
293 case I_XORI:
294 insn = I_XOR;
295 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
296 break;
297 case I_ANDI:
298 insn = I_AND;
299 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
300 break;
301 case I_LUI:
302 op->type = OP_MOVE;
303 value_append (sub, op->operands, VAL_CONSTANT, ((unsigned int) IMMU (loc->opc)) << 16);
304 break;
305 case I_SLTI:
306 insn = I_SLT;
307 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
308 break;
309 case I_SLTIU:
310 insn = I_SLTU;
311 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
312 break;
313 case I_EXT:
314 insn = I_EXT;
315 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
316 value_append (sub, op->operands, VAL_CONSTANT, RD (loc->opc) + 1);
317 break;
318 case I_INS:
319 insn = I_INS;
320 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
321 value_append (sub, op->operands, VAL_CONSTANT, RD (loc->opc) - SA (loc->opc) + 1);
322 break;
323 case I_ROTR:
324 insn = I_ROTV;
325 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
326 break;
327 case I_SLL:
328 insn = I_SLLV;
329 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
330 break;
331 case I_SRA:
332 insn = I_SRAV;
333 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
334 break;
335 case I_SRL:
336 insn = I_SRLV;
337 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
338 break;
339 case I_BEQL:
340 insn = I_BEQ;
341 break;
342 case I_BGEZL:
343 insn = I_BGEZ;
344 break;
345 case I_BGTZL:
346 insn = I_BGTZ;
347 break;
348 case I_BLEZL:
349 insn = I_BLEZ;
350 break;
351 case I_BLTZL:
352 insn = I_BLTZ;
353 break;
354 case I_BLTZALL:
355 insn = I_BLTZAL;
356 break;
357 case I_BNEL:
358 insn = I_BNE;
359 break;
360 default:
361 insn = loc->insn->insn;
363 op->info.iop.insn = insn;
365 if (loc->insn->flags & INSN_WRITE_GPR_T) {
366 regno = RT (loc->opc);
367 BLOCK_GPR_KILL ()
368 value_append (sub, op->results, VAL_REGISTER, regno);
371 if (loc->insn->flags & INSN_WRITE_GPR_D) {
372 regno = RD (loc->opc);
373 BLOCK_GPR_KILL ()
374 value_append (sub, op->results, VAL_REGISTER, regno);
377 if (loc->insn->flags & INSN_WRITE_LO) {
378 regno = REGISTER_LO;
379 BLOCK_GPR_KILL ()
380 value_append (sub, op->results, VAL_REGISTER, regno);
383 if (loc->insn->flags & INSN_WRITE_HI) {
384 regno = REGISTER_HI;
385 BLOCK_GPR_KILL ()
386 value_append (sub, op->results, VAL_REGISTER, regno);
389 if (loc->insn->flags & INSN_LINK) {
390 regno = REGISTER_GPR_RA;
391 BLOCK_GPR_KILL ()
392 value_append (sub, op->results, VAL_REGISTER, regno);
395 simplify_operation (op);
396 list_inserttail (block->operations, op);
398 } else {
399 if (!lastasm) {
400 op = operation_alloc (block);
401 op->info.asmop.begin = op->info.asmop.end = loc;
402 op->type = OP_ASM;
403 for (i = 0; i < NUM_REGMASK; i++)
404 asm_gen[i] = asm_kill[i] = 0;
405 } else {
406 op->info.asmop.end = loc;
408 lastasm = TRUE;
410 if (loc->insn->flags & INSN_READ_LO) {
411 regno = REGISTER_LO;
412 ASM_GPR_GEN ()
415 if (loc->insn->flags & INSN_READ_HI) {
416 regno = REGISTER_HI;
417 ASM_GPR_GEN ()
420 if (loc->insn->flags & INSN_READ_GPR_D) {
421 regno = RD (loc->opc);
422 ASM_GPR_GEN ()
425 if (loc->insn->flags & INSN_READ_GPR_T) {
426 regno = RT (loc->opc);
427 ASM_GPR_GEN ()
430 if (loc->insn->flags & INSN_READ_GPR_S) {
431 regno = RS (loc->opc);
432 ASM_GPR_GEN ()
435 if (loc->insn->flags & INSN_WRITE_GPR_T) {
436 regno = RT (loc->opc);
437 ASM_GPR_KILL ()
440 if (loc->insn->flags & INSN_WRITE_GPR_D) {
441 regno = RD (loc->opc);
442 ASM_GPR_KILL ()
445 if (loc->insn->flags & INSN_WRITE_LO) {
446 regno = REGISTER_LO;
447 ASM_GPR_KILL ()
450 if (loc->insn->flags & INSN_WRITE_HI) {
451 regno = REGISTER_HI;
452 ASM_GPR_KILL ()
455 if (loc->insn->flags & INSN_LINK) {
456 regno = REGISTER_GPR_RA;
457 ASM_GPR_KILL ()
461 if (loc == block->info.simple.end) {
462 if (lastasm)
463 list_inserttail (block->operations, op);
464 break;
467 break;
469 case BLOCK_CALL:
470 op = operation_alloc (block);
471 op->type = OP_CALL;
472 op->info.callop.arguments = list_alloc (sub->code->lstpool);
473 op->info.callop.retvalues = list_alloc (sub->code->lstpool);
474 list_inserttail (block->operations, op);
476 for (regno = 1; regno <= NUM_REGISTERS; regno++) {
477 if (IS_BIT_SET (regmask_call_gen, regno)) {
478 BLOCK_GPR_GEN ()
479 value_append (sub, op->operands, VAL_REGISTER, regno);
481 if (IS_BIT_SET (regmask_call_kill, regno)) {
482 BLOCK_GPR_KILL ()
483 value_append (sub, op->results, VAL_REGISTER, regno);
486 break;
488 case BLOCK_START:
489 op = operation_alloc (block);
490 op->type = OP_START;
492 for (regno = 1; regno < NUM_REGISTERS; regno++) {
493 BLOCK_GPR_KILL ()
494 value_append (sub, op->results, VAL_REGISTER, regno);
496 list_inserttail (block->operations, op);
497 break;
499 case BLOCK_END:
500 op = operation_alloc (block);
501 op->type = OP_END;
503 for (regno = 1; regno < NUM_REGISTERS; regno++) {
504 if (IS_BIT_SET (regmask_subend_gen, regno)) {
505 BLOCK_GPR_GEN ()
506 value_append (sub, op->operands, VAL_REGISTER, regno);
510 list_inserttail (block->operations, op);
511 break;
514 el = element_next (el);
519 void fixup_call_arguments (struct subroutine *sub)
521 struct operation *op;
522 struct basicblock *block;
523 struct value *val;
524 element el;
525 int regno, regend;
527 el = list_head (sub->blocks);
528 while (el) {
529 block = element_getvalue (el);
530 if (block->type == BLOCK_CALL) {
531 struct subroutine *target;
532 op = list_tailvalue (block->operations);
533 target = block->info.call.calltarget;
535 regend = REGISTER_GPR_T4;
536 if (target)
537 if (target->numregargs != -1)
538 regend = REGISTER_GPR_A0 + target->numregargs;
540 for (regno = REGISTER_GPR_A0; regno < regend; regno++) {
541 val = value_append (sub, op->operands, VAL_REGISTER, regno);
542 list_inserttail (op->info.callop.arguments, val);
545 if (target) regend = REGISTER_GPR_V0 + target->numregout;
546 else regend = REGISTER_GPR_A0;
548 for (regno = REGISTER_GPR_V0; regno < regend; regno++) {
549 val = value_append (sub, op->results, VAL_REGISTER, regno);
550 list_inserttail (op->info.callop.retvalues, val);
553 el = element_next (el);
557 void remove_call_arguments (struct subroutine *sub)
559 struct operation *op;
560 struct basicblock *block;
561 struct value *val;
562 element el;
564 el = list_head (sub->blocks);
565 while (el) {
566 block = element_getvalue (el);
567 if (block->type == BLOCK_CALL) {
568 op = list_tailvalue (block->operations);
569 while (list_size (op->info.callop.arguments) != 0) {
570 val = list_removetail (op->info.callop.arguments);
571 list_removetail (op->operands);
572 fixedpool_free (sub->code->valspool, val);
574 while (list_size (op->info.callop.retvalues) != 0) {
575 val = list_removetail (op->info.callop.retvalues);
576 list_removetail (op->results);
577 fixedpool_free (sub->code->valspool, val);
580 el = element_next (el);