Now my comments should be in english....
[pspdecompiler.git] / operations.c
blobbcdc29c78f202b4675c2edde74993d35374060a8
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 if (op->info.iop.loc->insn->flags & (INSN_JUMP | INSN_BRANCH))
397 block->jumpop = op;
398 list_inserttail (block->operations, op);
400 } else {
401 if (!lastasm) {
402 op = operation_alloc (block);
403 op->info.asmop.begin = op->info.asmop.end = loc;
404 op->type = OP_ASM;
405 for (i = 0; i < NUM_REGMASK; i++)
406 asm_gen[i] = asm_kill[i] = 0;
407 } else {
408 op->info.asmop.end = loc;
410 lastasm = TRUE;
412 if (loc->insn->flags & INSN_READ_LO) {
413 regno = REGISTER_LO;
414 ASM_GPR_GEN ()
417 if (loc->insn->flags & INSN_READ_HI) {
418 regno = REGISTER_HI;
419 ASM_GPR_GEN ()
422 if (loc->insn->flags & INSN_READ_GPR_D) {
423 regno = RD (loc->opc);
424 ASM_GPR_GEN ()
427 if (loc->insn->flags & INSN_READ_GPR_T) {
428 regno = RT (loc->opc);
429 ASM_GPR_GEN ()
432 if (loc->insn->flags & INSN_READ_GPR_S) {
433 regno = RS (loc->opc);
434 ASM_GPR_GEN ()
437 if (loc->insn->flags & INSN_WRITE_GPR_T) {
438 regno = RT (loc->opc);
439 ASM_GPR_KILL ()
442 if (loc->insn->flags & INSN_WRITE_GPR_D) {
443 regno = RD (loc->opc);
444 ASM_GPR_KILL ()
447 if (loc->insn->flags & INSN_WRITE_LO) {
448 regno = REGISTER_LO;
449 ASM_GPR_KILL ()
452 if (loc->insn->flags & INSN_WRITE_HI) {
453 regno = REGISTER_HI;
454 ASM_GPR_KILL ()
457 if (loc->insn->flags & INSN_LINK) {
458 regno = REGISTER_GPR_RA;
459 ASM_GPR_KILL ()
463 if (loc == block->info.simple.end) {
464 if (lastasm)
465 list_inserttail (block->operations, op);
466 break;
469 break;
471 case BLOCK_CALL:
472 op = operation_alloc (block);
473 op->type = OP_CALL;
474 op->info.callop.arguments = list_alloc (sub->code->lstpool);
475 op->info.callop.retvalues = list_alloc (sub->code->lstpool);
476 list_inserttail (block->operations, op);
478 for (regno = 1; regno <= NUM_REGISTERS; regno++) {
479 if (IS_BIT_SET (regmask_call_gen, regno)) {
480 BLOCK_GPR_GEN ()
481 value_append (sub, op->operands, VAL_REGISTER, regno);
483 if (IS_BIT_SET (regmask_call_kill, regno)) {
484 BLOCK_GPR_KILL ()
485 value_append (sub, op->results, VAL_REGISTER, regno);
488 break;
490 case BLOCK_START:
491 op = operation_alloc (block);
492 op->type = OP_START;
494 for (regno = 1; regno < NUM_REGISTERS; regno++) {
495 BLOCK_GPR_KILL ()
496 value_append (sub, op->results, VAL_REGISTER, regno);
498 list_inserttail (block->operations, op);
499 break;
501 case BLOCK_END:
502 op = operation_alloc (block);
503 op->type = OP_END;
504 op->info.endop.arguments = list_alloc (sub->code->lstpool);
506 for (regno = 1; regno < NUM_REGISTERS; regno++) {
507 if (IS_BIT_SET (regmask_subend_gen, regno)) {
508 BLOCK_GPR_GEN ()
509 value_append (sub, op->operands, VAL_REGISTER, regno);
513 list_inserttail (block->operations, op);
514 break;
517 el = element_next (el);
522 void fixup_call_arguments (struct subroutine *sub)
524 struct operation *op;
525 struct basicblock *block;
526 struct value *val;
527 element el;
528 int regno, regend;
530 el = list_head (sub->blocks);
531 while (el) {
532 block = element_getvalue (el);
533 if (block->type == BLOCK_CALL) {
534 struct subroutine *target;
535 op = list_tailvalue (block->operations);
536 target = block->info.call.calltarget;
538 regend = REGISTER_GPR_T4;
539 if (target)
540 if (target->numregargs != -1)
541 regend = REGISTER_GPR_A0 + target->numregargs;
543 for (regno = REGISTER_GPR_A0; regno < regend; regno++) {
544 val = value_append (sub, op->operands, VAL_REGISTER, regno);
545 list_inserttail (op->info.callop.arguments, val);
548 if (target) regend = REGISTER_GPR_V0 + target->numregout;
549 else regend = REGISTER_GPR_A0;
551 for (regno = REGISTER_GPR_V0; regno < regend; regno++) {
552 val = value_append (sub, op->results, VAL_REGISTER, regno);
553 list_inserttail (op->info.callop.retvalues, val);
555 } else if (block->type == BLOCK_END) {
556 op = list_tailvalue (block->operations);
557 regend = REGISTER_GPR_V0 + sub->numregout;
559 for (regno = REGISTER_GPR_V0; regno < regend; regno++) {
560 val = value_append (sub, op->operands, VAL_REGISTER, regno);
561 list_inserttail (op->info.endop.arguments, val);
564 el = element_next (el);
568 void remove_call_arguments (struct subroutine *sub)
570 struct operation *op;
571 struct basicblock *block;
572 struct value *val;
573 element el;
575 el = list_head (sub->blocks);
576 while (el) {
577 block = element_getvalue (el);
578 if (block->type == BLOCK_CALL) {
579 op = list_tailvalue (block->operations);
580 while (list_size (op->info.callop.arguments) != 0) {
581 val = list_removetail (op->info.callop.arguments);
582 list_removetail (op->operands);
583 fixedpool_free (sub->code->valspool, val);
585 while (list_size (op->info.callop.retvalues) != 0) {
586 val = list_removetail (op->info.callop.retvalues);
587 list_removetail (op->results);
588 fixedpool_free (sub->code->valspool, val);
590 } else if (block->type == BLOCK_END) {
591 op = list_tailvalue (block->operations);
592 while (list_size (op->info.endop.arguments) != 0) {
593 val = list_removetail (op->info.endop.arguments);
594 list_removetail (op->operands);
595 fixedpool_free (sub->code->valspool, val);
598 el = element_next (el);