Melhorando documentacao
[pspdecompiler.git] / ssa.c
blobf532788bb9bf458773cd4b5aa174d3841ef75a84
2 #include "code.h"
3 #include "utils.h"
5 #define RT(op) ((op >> 16) & 0x1F)
6 #define RS(op) ((op >> 21) & 0x1F)
7 #define RD(op) ((op >> 11) & 0x1F)
8 #define SA(op) ((op >> 6) & 0x1F)
9 #define IMM(op) ((signed short) (op & 0xFFFF))
10 #define IMMU(op) ((unsigned short) (op & 0xFFFF))
12 #define IS_BIT_SET(flags, bit) ((1 << ((bit) & 31)) & ((flags)[(bit) >> 5]))
13 #define BIT_SET(flags, bit) ((flags)[(bit) >> 5]) |= 1 << ((bit) & 31)
15 #define END_REGMASK 0xFCFF000C
16 #define CALLIN_REGMASK 0x00000FF0
17 #define CALLOUT_REGMASK 0x0300FFFE
19 static
20 struct operation *alloc_operation (struct subroutine *sub, struct basicblock *block)
22 struct operation *op;
23 op = fixedpool_alloc (sub->code->opspool);
24 op->block = block;
25 op->operands = list_alloc (sub->code->lstpool);
26 op->results = list_alloc (sub->code->lstpool);
27 return op;
30 static
31 struct variable *alloc_variable (struct basicblock *block)
33 struct variable *var;
34 var = fixedpool_alloc (block->sub->code->varspool);
35 var->uses = list_alloc (block->sub->code->lstpool);
36 return var;
39 static
40 void reset_operation (struct subroutine *sub, struct operation *op)
42 struct value *val;
44 while (list_size (op->results)) {
45 val = list_removehead (op->results);
46 fixedpool_free (sub->code->valspool, val);
49 while (list_size (op->operands)) {
50 val = list_removehead (op->operands);
51 fixedpool_free (sub->code->valspool, val);
55 static
56 void simplify_reg_zero (list l)
58 struct value *val;
59 element el;
60 el = list_head (l);
61 while (el) {
62 val = element_getvalue (el);
63 if (val->type == VAL_REGISTER && val->val.intval == 0) {
64 val->type = VAL_CONSTANT;
66 el = element_next (el);
70 static
71 void simplify_operation (struct subroutine *sub, struct operation *op)
73 struct value *val;
75 if (op->type != OP_INSTRUCTION) return;
77 if (list_size (op->results) == 1 && !(op->begin->insn->flags & (INSN_LOAD | INSN_JUMP))) {
78 val = list_headvalue (op->results);
79 if (val->val.intval == 0) {
80 reset_operation (sub, op);
81 op->type = OP_NOP;
82 return;
85 simplify_reg_zero (op->results);
86 simplify_reg_zero (op->operands);
88 switch (op->insn) {
89 case I_ADDU:
90 case I_ADD:
91 case I_OR:
92 case I_XOR:
93 val = list_headvalue (op->operands);
94 if (val->val.intval == 0) {
95 val = list_removehead (op->operands);
96 fixedpool_free (sub->code->valspool, val);
97 op->type = OP_MOVE;
98 } else {
99 val = list_tailvalue (op->operands);
100 if (val->val.intval == 0) {
101 val = list_removetail (op->operands);
102 fixedpool_free (sub->code->valspool, val);
103 op->type = OP_MOVE;
106 break;
107 case I_AND:
108 val = list_headvalue (op->operands);
109 if (val->val.intval == 0) {
110 val = list_removetail (op->operands);
111 fixedpool_free (sub->code->valspool, val);
112 op->type = OP_MOVE;
113 } else {
114 val = list_tailvalue (op->operands);
115 if (val->val.intval == 0) {
116 val = list_removehead (op->operands);
117 fixedpool_free (sub->code->valspool, val);
118 op->type = OP_MOVE;
122 break;
123 case I_BITREV:
124 case I_SEB:
125 case I_SEH:
126 case I_WSBH:
127 case I_WSBW:
128 val = list_headvalue (op->operands);
129 if (val->val.intval == 0) {
130 op->type = OP_MOVE;
132 break;
133 case I_SUB:
134 case I_SUBU:
135 case I_SLLV:
136 case I_SRLV:
137 case I_SRAV:
138 case I_ROTV:
139 val = list_tailvalue (op->operands);
140 if (val->val.intval == 0) {
141 val = list_removetail (op->operands);
142 fixedpool_free (sub->code->valspool, val);
143 op->type = OP_MOVE;
145 case I_MOVN:
146 val = element_getvalue (element_next (list_head (op->operands)));
147 if (val->val.intval == 0) {
148 reset_operation (sub, op);
149 op->type = OP_NOP;
151 break;
152 case I_MOVZ:
153 val = element_getvalue (element_next (list_head (op->operands)));
154 if (val->val.intval == 0) {
155 val = list_removetail (op->operands);
156 fixedpool_free (sub->code->valspool, val);
157 val = list_removetail (op->operands);
158 fixedpool_free (sub->code->valspool, val);
159 op->type = OP_MOVE;
161 break;
162 default:
163 break;
166 return;
169 static
170 void append_value (struct subroutine *sub, list l, enum valuetype type, uint32 value)
172 struct value *val;
173 val = fixedpool_alloc (sub->code->valspool);
174 val->type = type;
175 val->val.intval = value;
176 list_inserttail (l, val);
179 #define BLOCK_GPR_KILL() \
180 if (!IS_BIT_SET (block->reg_kill, regno) && regno != 0) { \
181 list_inserttail (defblocks[regno], block); \
182 BIT_SET (block->reg_kill, regno); \
185 #define BLOCK_GPR_GEN() \
186 if (!IS_BIT_SET (block->reg_kill, regno) && regno != 0 && \
187 !IS_BIT_SET (block->reg_gen, regno)) { \
188 BIT_SET (block->reg_gen, regno); \
191 #define ASM_GPR_KILL() \
192 BLOCK_GPR_KILL () \
193 if (!IS_BIT_SET (asm_kill, regno) && regno != 0) { \
194 BIT_SET (asm_kill, regno); \
195 append_value (sub, op->results, VAL_REGISTER, regno); \
198 #define ASM_GPR_GEN() \
199 BLOCK_GPR_GEN () \
200 if (!IS_BIT_SET (asm_kill, regno) && regno != 0 && \
201 !IS_BIT_SET (asm_gen, regno)) { \
202 BIT_SET (asm_gen, regno); \
203 append_value (sub, op->operands, VAL_REGISTER, regno); \
206 static
207 void extract_operations (struct subroutine *sub, list *defblocks)
209 struct operation *op;
210 element el;
212 el = list_head (sub->blocks);
213 while (el) {
214 struct basicblock *block = element_getvalue (el);
215 block->operations = list_alloc (sub->code->lstpool);
216 block->reg_gen[0] = block->reg_gen[1] = 0;
217 block->reg_kill[0] = block->reg_kill[1] = 0;
219 if (block->type == BLOCK_SIMPLE) {
220 uint32 asm_gen[2], asm_kill[2];
221 struct location *loc;
222 int lastasm = FALSE;
224 asm_gen[0] = asm_gen[1] = 0;
225 asm_kill[0] = asm_kill[1] = 0;
227 for (loc = block->info.simple.begin; ; loc++) {
228 if (INSN_TYPE (loc->insn->flags) == INSN_ALLEGREX) {
229 enum allegrex_insn insn;
231 if (lastasm) list_inserttail (block->operations, op);
232 lastasm = FALSE;
234 op = alloc_operation (sub, block);
235 op->type = OP_INSTRUCTION;
236 op->begin = op->end = loc;
238 if (loc->insn->flags & INSN_READ_GPR_S) {
239 int regno = RS (loc->opc);
240 BLOCK_GPR_GEN ()
241 append_value (sub, op->operands, VAL_REGISTER, regno);
244 if (loc->insn->flags & INSN_READ_GPR_T) {
245 int regno = RT (loc->opc);
246 BLOCK_GPR_GEN ()
247 append_value (sub, op->operands, VAL_REGISTER, regno);
250 if (loc->insn->flags & INSN_READ_GPR_D) {
251 int regno = RD (loc->opc);
252 BLOCK_GPR_GEN ()
253 append_value (sub, op->operands, VAL_REGISTER, regno);
256 if (loc->insn->flags & INSN_READ_LO) {
257 int regno = REGISTER_LO;
258 BLOCK_GPR_GEN ()
259 append_value (sub, op->operands, VAL_REGISTER, regno);
262 if (loc->insn->flags & INSN_READ_HI) {
263 int regno = REGISTER_HI;
264 BLOCK_GPR_GEN ()
265 append_value (sub, op->operands, VAL_REGISTER, regno);
268 if (loc->insn->flags & (INSN_LOAD | INSN_STORE)) {
269 append_value (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
272 switch (loc->insn->insn) {
273 case I_ADDI:
274 insn = I_ADD;
275 append_value (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
276 break;
277 case I_ADDIU:
278 insn = I_ADDU;
279 append_value (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
280 break;
281 case I_ORI:
282 insn = I_OR;
283 append_value (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
284 break;
285 case I_XORI:
286 insn = I_XOR;
287 append_value (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
288 break;
289 case I_ANDI:
290 insn = I_AND;
291 append_value (sub, op->operands, VAL_CONSTANT, IMMU (loc->opc));
292 break;
293 case I_LUI:
294 op->type = OP_MOVE;
295 append_value (sub, op->operands, VAL_CONSTANT, ((unsigned int) IMMU (loc->opc)) << 16);
296 break;
297 case I_SLTI:
298 insn = I_SLT;
299 append_value (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
300 break;
301 case I_SLTIU:
302 insn = I_SLTU;
303 append_value (sub, op->operands, VAL_CONSTANT, IMM (loc->opc));
304 break;
305 case I_EXT:
306 insn = I_EXT;
307 append_value (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
308 append_value (sub, op->operands, VAL_CONSTANT, RD (loc->opc) + 1);
309 break;
310 case I_INS:
311 insn = I_INS;
312 append_value (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
313 append_value (sub, op->operands, VAL_CONSTANT, RD (loc->opc) - SA (loc->opc) + 1);
314 break;
315 case I_ROTR:
316 insn = I_ROTV;
317 append_value (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
318 break;
319 case I_SLL:
320 insn = I_SLLV;
321 append_value (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
322 break;
323 case I_SRA:
324 insn = I_SRAV;
325 append_value (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
326 break;
327 case I_SRL:
328 insn = I_SRLV;
329 append_value (sub, op->operands, VAL_CONSTANT, SA (loc->opc));
330 break;
331 case I_BEQL:
332 insn = I_BEQ;
333 break;
334 case I_BGEZL:
335 insn = I_BGEZ;
336 break;
337 case I_BGTZL:
338 insn = I_BGTZ;
339 break;
340 case I_BLEZL:
341 insn = I_BLEZ;
342 break;
343 case I_BLTZL:
344 insn = I_BLTZ;
345 break;
346 case I_BLTZALL:
347 insn = I_BLTZAL;
348 break;
349 case I_BNEL:
350 insn = I_BNE;
351 break;
352 default:
353 insn = loc->insn->insn;
355 op->insn = insn;
357 if (loc->insn->flags & INSN_WRITE_GPR_T) {
358 int regno = RT (loc->opc);
359 BLOCK_GPR_KILL ()
360 append_value (sub, op->results, VAL_REGISTER, regno);
363 if (loc->insn->flags & INSN_WRITE_GPR_D) {
364 int regno = RD (loc->opc);
365 BLOCK_GPR_KILL ()
366 append_value (sub, op->results, VAL_REGISTER, regno);
369 if (loc->insn->flags & INSN_WRITE_LO) {
370 int regno = REGISTER_LO;
371 BLOCK_GPR_KILL ()
372 append_value (sub, op->results, VAL_REGISTER, regno);
375 if (loc->insn->flags & INSN_WRITE_HI) {
376 int regno = REGISTER_HI;
377 BLOCK_GPR_KILL ()
378 append_value (sub, op->results, VAL_REGISTER, regno);
381 if (loc->insn->flags & INSN_LINK) {
382 int regno = REGISTER_LINK;
383 BLOCK_GPR_KILL ()
384 append_value (sub, op->results, VAL_REGISTER, regno);
387 simplify_operation (sub, op);
388 list_inserttail (block->operations, op);
389 } else {
390 if (!lastasm) {
391 op = alloc_operation (sub, block);
392 op->begin = op->end = loc;
393 op->type = OP_ASM;
394 asm_gen[0] = asm_gen[1] = 0;
395 asm_kill[0] = asm_kill[1] = 0;
396 } else {
397 op->end = loc;
399 lastasm = TRUE;
401 if (loc->insn->flags & INSN_READ_LO) {
402 int regno = REGISTER_LO;
403 ASM_GPR_GEN ()
406 if (loc->insn->flags & INSN_READ_HI) {
407 int regno = REGISTER_HI;
408 ASM_GPR_GEN ()
411 if (loc->insn->flags & INSN_READ_GPR_D) {
412 int regno = RD (loc->opc);
413 ASM_GPR_GEN ()
416 if (loc->insn->flags & INSN_READ_GPR_T) {
417 int regno = RT (loc->opc);
418 ASM_GPR_GEN ()
421 if (loc->insn->flags & INSN_READ_GPR_S) {
422 int regno = RS (loc->opc);
423 ASM_GPR_GEN ()
426 if (loc->insn->flags & INSN_WRITE_GPR_T) {
427 int regno = RT (loc->opc);
428 ASM_GPR_KILL ()
431 if (loc->insn->flags & INSN_WRITE_GPR_D) {
432 int regno = RD (loc->opc);
433 ASM_GPR_KILL ()
436 if (loc->insn->flags & INSN_WRITE_LO) {
437 int regno = REGISTER_LO;
438 ASM_GPR_KILL ()
441 if (loc->insn->flags & INSN_WRITE_HI) {
442 int regno = REGISTER_HI;
443 ASM_GPR_KILL ()
446 if (loc->insn->flags & INSN_LINK) {
447 int regno = REGISTER_LINK;
448 ASM_GPR_KILL ()
452 if (loc == block->info.simple.end) {
453 if (lastasm) list_inserttail (block->operations, op);
454 break;
457 } else if (block->type == BLOCK_CALL) {
458 int regno;
459 op = alloc_operation (sub, block);
460 op->type = OP_CALL;
461 list_inserttail (block->operations, op);
463 for (regno = 1; regno <= REGISTER_LINK; regno++) {
464 if ((1 << regno) & CALLIN_REGMASK) {
465 BLOCK_GPR_GEN ()
466 append_value (sub, op->operands, VAL_REGISTER, regno);
468 if ((1 << regno) & CALLOUT_REGMASK) {
469 BLOCK_GPR_KILL ()
470 append_value (sub, op->results, VAL_REGISTER, regno);
474 regno = REGISTER_LO;
475 BLOCK_GPR_KILL ()
476 append_value (sub, op->results, VAL_REGISTER, regno);
478 regno = REGISTER_HI;
479 BLOCK_GPR_KILL ()
480 append_value (sub, op->results, VAL_REGISTER, regno);
483 el = element_next (el);
487 static
488 void live_registers (struct subroutine *sub)
490 list worklist = list_alloc (sub->code->lstpool);
491 struct basicblock *block;
492 element el;
494 el = list_head (sub->blocks);
495 while (el) {
496 block = element_getvalue (el);
497 block->mark1 = 0;
498 el = element_next (el);
501 list_inserthead (worklist, sub->endblock);
503 while (list_size (worklist) != 0) {
504 struct basicedge *edge;
505 struct basicblock *bref;
507 block = list_removehead (worklist);
508 block->mark1 = 0;
509 block->reg_live_out[0] = (block->reg_live_in[0] & ~(block->reg_kill[0])) | block->reg_gen[0];
510 block->reg_live_out[1] = (block->reg_live_in[1] & ~(block->reg_kill[1])) | block->reg_gen[1];
511 el = list_head (block->inrefs);
512 while (el) {
513 uint32 changed;
515 edge = element_getvalue (el);
516 bref = edge->from;
518 changed = block->reg_live_out[0] & (~bref->reg_live_in[0]);
519 bref->reg_live_in[0] |= block->reg_live_out[0];
520 changed |= block->reg_live_out[1] & (~bref->reg_live_in[1]);
521 bref->reg_live_in[1] |= block->reg_live_out[1];
523 if (changed && !bref->mark1) {
524 list_inserttail (worklist, bref);
525 bref->mark1 = 1;
528 el = element_next (el);
532 list_free (worklist);
535 static
536 void ssa_place_phis (struct subroutine *sub, list *defblocks)
538 struct basicblock *block, *bref;
539 struct basicblocknode *brefnode;
540 element el, ref;
541 int i, j;
543 el = list_head (sub->blocks);
544 while (el) {
545 block = element_getvalue (el);
546 block->mark1 = 0;
547 block->mark2 = 0;
548 el = element_next (el);
551 for (i = 1; i < NUM_REGISTERS; i++) {
552 list worklist = defblocks[i];
553 el = list_head (worklist);
554 while (el) {
555 block = element_getvalue (el);
556 block->mark1 = i;
557 el = element_next (el);
560 while (list_size (worklist) != 0) {
561 block = list_removehead (worklist);
562 ref = list_head (block->node.frontier);
563 while (ref) {
564 brefnode = element_getvalue (ref);
565 bref = element_getvalue (brefnode->blockel);
566 if (bref->mark2 != i && IS_BIT_SET (bref->reg_live_out, i)) {
567 struct operation *op;
569 bref->mark2 = i;
570 op = alloc_operation (sub, bref);
571 op->type = OP_PHI;
572 append_value (sub, op->results, VAL_REGISTER, i);
573 for (j = list_size (bref->inrefs); j > 0; j--)
574 append_value (sub, op->operands, VAL_REGISTER, i);
575 list_inserthead (bref->operations, op);
577 if (bref->mark1 != i) {
578 bref->mark1 = i;
579 list_inserttail (worklist, bref);
582 ref = element_next (ref);
588 static
589 void ssa_search (struct basicblock *block, list *vars)
591 element el;
592 int i, pushed[NUM_REGISTERS];
594 for (i = 1; i < NUM_REGISTERS; i++)
595 pushed[i] = FALSE;
597 el = list_head (block->operations);
598 while (el) {
599 struct operation *op;
600 struct variable *var;
601 struct value *val;
602 element opel, rel;
604 op = element_getvalue (el);
606 if (op->type != OP_PHI) {
607 opel = list_head (op->operands);
608 while (opel) {
609 val = element_getvalue (opel);
610 if (val->type == VAL_REGISTER) {
611 var = list_headvalue (vars[val->val.intval]);
612 val->type = VAL_VARIABLE;
613 val->val.variable = var;
614 list_inserttail (var->uses, op);
616 opel = element_next (opel);
620 rel = list_head (op->results);
621 while (rel) {
622 val = element_getvalue (rel);
623 if (val->type == VAL_REGISTER) {
624 val->type = VAL_VARIABLE;
625 var = alloc_variable (block);
626 var->name.type = VAL_REGISTER;
627 var->name.val.intval = val->val.intval;
628 var->def = op;
629 list_inserttail (block->sub->variables, var);
630 if (!pushed[val->val.intval]) {
631 pushed[val->val.intval] = TRUE;
632 list_inserthead (vars[val->val.intval], var);
633 } else {
634 element_setvalue (list_head (vars[val->val.intval]), var);
636 val->val.variable = var;
638 rel = element_next (rel);
641 el = element_next (el);
644 el = list_head (block->outrefs);
645 while (el) {
646 struct basicedge *edge;
647 struct basicblock *ref;
648 element phiel, opel;
650 edge = element_getvalue (el);
651 ref = edge->to;
653 phiel = list_head (ref->operations);
654 while (phiel) {
655 struct operation *op;
656 struct value *val;
658 op = element_getvalue (phiel);
659 if (op->type != OP_PHI) break;
661 opel = list_head (op->operands);
662 for (i = edge->tonum; i > 0; i--)
663 opel = element_next (opel);
665 val = element_getvalue (opel);
666 val->type = VAL_VARIABLE;
667 val->val.variable = list_headvalue (vars[val->val.intval]);
668 list_inserttail (val->val.variable->uses, op);
669 phiel = element_next (phiel);
671 el = element_next (el);
674 el = list_head (block->node.children);
675 while (el) {
676 struct basicblocknode *childnode;
677 struct basicblock *child;
679 childnode = element_getvalue (el);
680 child = element_getvalue (childnode->blockel);
681 ssa_search (child, vars);
682 el = element_next (el);
685 for (i = 1; i < NUM_REGISTERS; i++)
686 if (pushed[i]) list_removehead (vars[i]);
689 void build_ssa (struct subroutine *sub)
691 list reglist[NUM_REGISTERS];
692 struct operation *op;
693 int i;
695 reglist[0] = NULL;
696 for (i = 1; i < NUM_REGISTERS; i++) {
697 reglist[i] = list_alloc (sub->code->lstpool);
700 sub->variables = list_alloc (sub->code->lstpool);
702 extract_operations (sub, reglist);
704 op = alloc_operation (sub, sub->startblock);
705 op->type = OP_START;
707 for (i = 1; i < NUM_REGISTERS; i++) {
708 BIT_SET (sub->startblock->reg_kill, i);
709 append_value (sub, op->results, VAL_REGISTER, i);
712 list_inserttail (sub->startblock->operations, op);
714 op = alloc_operation (sub, sub->endblock);
715 op->type = OP_END;
717 for (i = 1; i <= REGISTER_LINK; i++) {
718 if (END_REGMASK & (1 << i)) {
719 BIT_SET (sub->endblock->reg_gen, i);
720 append_value (sub, op->operands, VAL_REGISTER, i);
724 list_inserttail (sub->endblock->operations, op);
726 live_registers (sub);
727 ssa_place_phis (sub, reglist);
728 ssa_search (sub->startblock, reglist);
730 for (i = 1; i < NUM_REGISTERS; i++) {
731 list_free (reglist[i]);