Passo intermediario, ainda falta um longo caminho
[pspdecompiler.git] / operations.c
blob8c31f841dfe0c143c60bb03a1843bb5b5f7f12a9
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 uint32 asm_gen[NUM_REGMASK], asm_kill[NUM_REGMASK];
199 int i, regno, lastasm;
200 element el;
202 el = list_head (sub->blocks);
203 while (el) {
204 block = element_getvalue (el);
205 block->operations = list_alloc (sub->code->lstpool);
207 for (i = 0; i < NUM_REGMASK; i++)
208 block->reg_gen[i] = block->reg_kill[i] = 0;
210 switch (block->type) {
211 case BLOCK_SIMPLE:
212 lastasm = FALSE;
213 for (i = 0; i < NUM_REGMASK; i++)
214 asm_gen[i] = asm_kill[i] = 0;
216 for (loc = block->info.simple.begin; ; loc++) {
217 if (INSN_TYPE (loc->insn->flags) == INSN_ALLEGREX) {
218 enum allegrex_insn insn;
220 if (lastasm)
221 list_inserttail (block->operations, op);
222 lastasm = FALSE;
224 op = operation_alloc (block);
225 op->type = OP_INSTRUCTION;
226 op->info.iop.loc = loc;
228 if (loc->insn->flags & INSN_READ_GPR_S) {
229 regno = RS (loc->opc);
230 BLOCK_GPR_GEN ()
231 value_append (sub, op->operands, VAL_REGISTER, regno);
234 if (loc->insn->flags & INSN_READ_GPR_T) {
235 regno = RT (loc->opc);
236 BLOCK_GPR_GEN ()
237 value_append (sub, op->operands, VAL_REGISTER, regno);
240 if (loc->insn->flags & INSN_READ_GPR_D) {
241 regno = RD (loc->opc);
242 BLOCK_GPR_GEN ()
243 value_append (sub, op->operands, VAL_REGISTER, regno);
246 if (loc->insn->flags & INSN_READ_LO) {
247 regno = REGISTER_LO;
248 BLOCK_GPR_GEN ()
249 value_append (sub, op->operands, VAL_REGISTER, regno);
252 if (loc->insn->flags & INSN_READ_HI) {
253 regno = REGISTER_HI;
254 BLOCK_GPR_GEN ()
255 value_append (sub, op->operands, VAL_REGISTER, regno);
258 if (loc->insn->flags & (INSN_LOAD | INSN_STORE)) {
259 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
262 switch (loc->insn->insn) {
263 case I_ADDI:
264 insn = I_ADD;
265 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
266 break;
267 case I_ADDIU:
268 insn = I_ADDU;
269 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
270 break;
271 case I_ORI:
272 insn = I_OR;
273 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
274 break;
275 case I_XORI:
276 insn = I_XOR;
277 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
278 break;
279 case I_ANDI:
280 insn = I_AND;
281 value_append (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
282 break;
283 case I_LUI:
284 op->type = OP_MOVE;
285 value_append (sub, op->operands, VAL_CONSTANT, ((unsigned int) IMMU (loc->opc)) << 16);
286 break;
287 case I_SLTI:
288 insn = I_SLT;
289 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
290 break;
291 case I_SLTIU:
292 insn = I_SLTU;
293 value_append (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
294 break;
295 case I_EXT:
296 insn = I_EXT;
297 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
298 value_append (sub, op->operands, VAL_CONSTANT, RD (loc->opc) + 1);
299 break;
300 case I_INS:
301 insn = I_INS;
302 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
303 value_append (sub, op->operands, VAL_CONSTANT, RD (loc->opc) - SA (loc->opc) + 1);
304 break;
305 case I_ROTR:
306 insn = I_ROTV;
307 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
308 break;
309 case I_SLL:
310 insn = I_SLLV;
311 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
312 break;
313 case I_SRA:
314 insn = I_SRAV;
315 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
316 break;
317 case I_SRL:
318 insn = I_SRLV;
319 value_append (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
320 break;
321 case I_BEQL:
322 insn = I_BEQ;
323 break;
324 case I_BGEZL:
325 insn = I_BGEZ;
326 break;
327 case I_BGTZL:
328 insn = I_BGTZ;
329 break;
330 case I_BLEZL:
331 insn = I_BLEZ;
332 break;
333 case I_BLTZL:
334 insn = I_BLTZ;
335 break;
336 case I_BLTZALL:
337 insn = I_BLTZAL;
338 break;
339 case I_BNEL:
340 insn = I_BNE;
341 break;
342 default:
343 insn = loc->insn->insn;
345 op->info.iop.insn = insn;
347 if (loc->insn->flags & INSN_WRITE_GPR_T) {
348 regno = RT (loc->opc);
349 BLOCK_GPR_KILL ()
350 value_append (sub, op->results, VAL_REGISTER, regno);
353 if (loc->insn->flags & INSN_WRITE_GPR_D) {
354 regno = RD (loc->opc);
355 BLOCK_GPR_KILL ()
356 value_append (sub, op->results, VAL_REGISTER, regno);
359 if (loc->insn->flags & INSN_WRITE_LO) {
360 regno = REGISTER_LO;
361 BLOCK_GPR_KILL ()
362 value_append (sub, op->results, VAL_REGISTER, regno);
365 if (loc->insn->flags & INSN_WRITE_HI) {
366 regno = REGISTER_HI;
367 BLOCK_GPR_KILL ()
368 value_append (sub, op->results, VAL_REGISTER, regno);
371 if (loc->insn->flags & INSN_LINK) {
372 regno = REGISTER_GPR_RA;
373 BLOCK_GPR_KILL ()
374 value_append (sub, op->results, VAL_REGISTER, regno);
377 simplify_operation (op);
378 list_inserttail (block->operations, op);
380 } else {
381 if (!lastasm) {
382 op = operation_alloc (block);
383 op->info.asmop.begin = op->info.asmop.end = loc;
384 op->type = OP_ASM;
385 for (i = 0; i < NUM_REGMASK; i++)
386 asm_gen[i] = asm_kill[i] = 0;
387 } else {
388 op->info.asmop.end = loc;
390 lastasm = TRUE;
392 if (loc->insn->flags & INSN_READ_LO) {
393 regno = REGISTER_LO;
394 ASM_GPR_GEN ()
397 if (loc->insn->flags & INSN_READ_HI) {
398 regno = REGISTER_HI;
399 ASM_GPR_GEN ()
402 if (loc->insn->flags & INSN_READ_GPR_D) {
403 regno = RD (loc->opc);
404 ASM_GPR_GEN ()
407 if (loc->insn->flags & INSN_READ_GPR_T) {
408 regno = RT (loc->opc);
409 ASM_GPR_GEN ()
412 if (loc->insn->flags & INSN_READ_GPR_S) {
413 regno = RS (loc->opc);
414 ASM_GPR_GEN ()
417 if (loc->insn->flags & INSN_WRITE_GPR_T) {
418 regno = RT (loc->opc);
419 ASM_GPR_KILL ()
422 if (loc->insn->flags & INSN_WRITE_GPR_D) {
423 regno = RD (loc->opc);
424 ASM_GPR_KILL ()
427 if (loc->insn->flags & INSN_WRITE_LO) {
428 regno = REGISTER_LO;
429 ASM_GPR_KILL ()
432 if (loc->insn->flags & INSN_WRITE_HI) {
433 regno = REGISTER_HI;
434 ASM_GPR_KILL ()
437 if (loc->insn->flags & INSN_LINK) {
438 regno = REGISTER_GPR_RA;
439 ASM_GPR_KILL ()
443 if (loc == block->info.simple.end) {
444 if (lastasm)
445 list_inserttail (block->operations, op);
446 break;
449 break;
451 case BLOCK_CALL:
452 op = operation_alloc (block);
453 op->type = OP_CALL;
454 op->info.callop.arguments = list_alloc (sub->code->lstpool);
455 op->info.callop.retvalues = list_alloc (sub->code->lstpool);
456 list_inserttail (block->operations, op);
458 for (regno = 1; regno <= NUM_REGISTERS; regno++) {
459 if (IS_BIT_SET (regmask_call_gen, regno)) {
460 BLOCK_GPR_GEN ()
461 value_append (sub, op->operands, VAL_REGISTER, regno);
463 if (IS_BIT_SET (regmask_call_kill, regno)) {
464 BLOCK_GPR_KILL ()
465 value_append (sub, op->results, VAL_REGISTER, regno);
468 break;
470 case BLOCK_START:
471 op = operation_alloc (block);
472 op->type = OP_START;
474 for (regno = 1; regno < NUM_REGISTERS; regno++) {
475 BLOCK_GPR_KILL ()
476 value_append (sub, op->results, VAL_REGISTER, regno);
478 list_inserttail (block->operations, op);
479 break;
481 case BLOCK_END:
482 op = operation_alloc (block);
483 op->type = OP_END;
485 for (regno = 1; regno < NUM_REGISTERS; regno++) {
486 if (IS_BIT_SET (regmask_subend_gen, regno)) {
487 BLOCK_GPR_GEN ()
488 value_append (sub, op->operands, VAL_REGISTER, regno);
492 list_inserttail (block->operations, op);
493 break;
496 el = element_next (el);
501 void fixup_call_arguments (struct subroutine *sub)
503 struct operation *op;
504 struct basicblock *block;
505 struct value *val;
506 element el;
507 int regno, regend;
509 el = list_head (sub->blocks);
510 while (el) {
511 block = element_getvalue (el);
512 if (block->type == BLOCK_CALL) {
513 struct subroutine *target;
514 op = list_tailvalue (block->operations);
515 target = block->info.call.calltarget;
517 regend = REGISTER_GPR_T4;
518 if (target)
519 if (target->numregargs != -1)
520 regend = REGISTER_GPR_A0 + target->numregargs;
522 for (regno = REGISTER_GPR_A0; regno < regend; regno++) {
523 val = value_append (sub, op->operands, VAL_REGISTER, regno);
524 list_inserttail (op->info.callop.arguments, val);
527 if (target) regend = REGISTER_GPR_V0 + target->numregout;
528 else regend = REGISTER_GPR_A0;
530 for (regno = REGISTER_GPR_V0; regno < regend; regno++) {
531 val = value_append (sub, op->results, VAL_REGISTER, regno);
532 list_inserttail (op->info.callop.retvalues, val);
535 el = element_next (el);
539 void remove_call_arguments (struct subroutine *sub)
541 struct operation *op;
542 struct basicblock *block;
543 struct value *val;
544 element el;
546 el = list_head (sub->blocks);
547 while (el) {
548 block = element_getvalue (el);
549 if (block->type == BLOCK_CALL) {
550 op = list_tailvalue (block->operations);
551 while (list_size (op->info.callop.arguments) != 0) {
552 val = list_removetail (op->info.callop.arguments);
553 list_removetail (op->operands);
554 fixedpool_free (sub->code->valspool, val);
556 while (list_size (op->info.callop.retvalues) != 0) {
557 val = list_removetail (op->info.callop.retvalues);
558 list_removetail (op->results);
559 fixedpool_free (sub->code->valspool, val);
562 el = element_next (el);