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
20 struct operation
*alloc_operation (struct subroutine
*sub
, struct basicblock
*block
)
23 op
= fixedpool_alloc (sub
->code
->opspool
);
25 op
->operands
= list_alloc (sub
->code
->lstpool
);
26 op
->results
= list_alloc (sub
->code
->lstpool
);
31 struct variable
*alloc_variable (struct basicblock
*block
)
34 var
= fixedpool_alloc (block
->sub
->code
->varspool
);
35 var
->uses
= list_alloc (block
->sub
->code
->lstpool
);
40 void reset_operation (struct subroutine
*sub
, struct operation
*op
)
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
);
56 void simplify_reg_zero (list l
)
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
);
71 void simplify_operation (struct subroutine
*sub
, struct operation
*op
)
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
);
85 simplify_reg_zero (op
->results
);
86 simplify_reg_zero (op
->operands
);
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
);
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
);
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
);
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
);
128 val
= list_headvalue (op
->operands
);
129 if (val
->val
.intval
== 0) {
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
);
146 val
= element_getvalue (element_next (list_head (op
->operands
)));
147 if (val
->val
.intval
== 0) {
148 reset_operation (sub
, op
);
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
);
170 void append_value (struct subroutine
*sub
, list l
, enum valuetype type
, uint32 value
)
173 val
= fixedpool_alloc (sub
->code
->valspool
);
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() \
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() \
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); \
207 void extract_operations (struct subroutine
*sub
, list
*defblocks
)
209 struct operation
*op
;
212 el
= list_head (sub
->blocks
);
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
;
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
);
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
);
241 append_value (sub
, op
->operands
, VAL_REGISTER
, regno
);
244 if (loc
->insn
->flags
& INSN_READ_GPR_T
) {
245 int regno
= RT (loc
->opc
);
247 append_value (sub
, op
->operands
, VAL_REGISTER
, regno
);
250 if (loc
->insn
->flags
& INSN_READ_GPR_D
) {
251 int regno
= RD (loc
->opc
);
253 append_value (sub
, op
->operands
, VAL_REGISTER
, regno
);
256 if (loc
->insn
->flags
& INSN_READ_LO
) {
257 int regno
= REGISTER_LO
;
259 append_value (sub
, op
->operands
, VAL_REGISTER
, regno
);
262 if (loc
->insn
->flags
& INSN_READ_HI
) {
263 int regno
= REGISTER_HI
;
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
) {
275 append_value (sub
, op
->operands
, VAL_CONSTANT
, IMM (loc
->opc
));
279 append_value (sub
, op
->operands
, VAL_CONSTANT
, IMM (loc
->opc
));
283 append_value (sub
, op
->operands
, VAL_CONSTANT
, IMMU (loc
->opc
));
287 append_value (sub
, op
->operands
, VAL_CONSTANT
, IMMU (loc
->opc
));
291 append_value (sub
, op
->operands
, VAL_CONSTANT
, IMMU (loc
->opc
));
295 append_value (sub
, op
->operands
, VAL_CONSTANT
, ((unsigned int) IMMU (loc
->opc
)) << 16);
299 append_value (sub
, op
->operands
, VAL_CONSTANT
, IMM (loc
->opc
));
303 append_value (sub
, op
->operands
, VAL_CONSTANT
, IMM (loc
->opc
));
307 append_value (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
308 append_value (sub
, op
->operands
, VAL_CONSTANT
, RD (loc
->opc
) + 1);
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);
317 append_value (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
321 append_value (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
325 append_value (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
329 append_value (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
353 insn
= loc
->insn
->insn
;
357 if (loc
->insn
->flags
& INSN_WRITE_GPR_T
) {
358 int regno
= RT (loc
->opc
);
360 append_value (sub
, op
->results
, VAL_REGISTER
, regno
);
363 if (loc
->insn
->flags
& INSN_WRITE_GPR_D
) {
364 int regno
= RD (loc
->opc
);
366 append_value (sub
, op
->results
, VAL_REGISTER
, regno
);
369 if (loc
->insn
->flags
& INSN_WRITE_LO
) {
370 int regno
= REGISTER_LO
;
372 append_value (sub
, op
->results
, VAL_REGISTER
, regno
);
375 if (loc
->insn
->flags
& INSN_WRITE_HI
) {
376 int regno
= REGISTER_HI
;
378 append_value (sub
, op
->results
, VAL_REGISTER
, regno
);
381 if (loc
->insn
->flags
& INSN_LINK
) {
382 int regno
= REGISTER_LINK
;
384 append_value (sub
, op
->results
, VAL_REGISTER
, regno
);
387 simplify_operation (sub
, op
);
388 list_inserttail (block
->operations
, op
);
391 op
= alloc_operation (sub
, block
);
392 op
->begin
= op
->end
= loc
;
394 asm_gen
[0] = asm_gen
[1] = 0;
395 asm_kill
[0] = asm_kill
[1] = 0;
401 if (loc
->insn
->flags
& INSN_READ_LO
) {
402 int regno
= REGISTER_LO
;
406 if (loc
->insn
->flags
& INSN_READ_HI
) {
407 int regno
= REGISTER_HI
;
411 if (loc
->insn
->flags
& INSN_READ_GPR_D
) {
412 int regno
= RD (loc
->opc
);
416 if (loc
->insn
->flags
& INSN_READ_GPR_T
) {
417 int regno
= RT (loc
->opc
);
421 if (loc
->insn
->flags
& INSN_READ_GPR_S
) {
422 int regno
= RS (loc
->opc
);
426 if (loc
->insn
->flags
& INSN_WRITE_GPR_T
) {
427 int regno
= RT (loc
->opc
);
431 if (loc
->insn
->flags
& INSN_WRITE_GPR_D
) {
432 int regno
= RD (loc
->opc
);
436 if (loc
->insn
->flags
& INSN_WRITE_LO
) {
437 int regno
= REGISTER_LO
;
441 if (loc
->insn
->flags
& INSN_WRITE_HI
) {
442 int regno
= REGISTER_HI
;
446 if (loc
->insn
->flags
& INSN_LINK
) {
447 int regno
= REGISTER_LINK
;
452 if (loc
== block
->info
.simple
.end
) {
453 if (lastasm
) list_inserttail (block
->operations
, op
);
457 } else if (block
->type
== BLOCK_CALL
) {
459 op
= alloc_operation (sub
, block
);
461 list_inserttail (block
->operations
, op
);
463 for (regno
= 1; regno
<= REGISTER_LINK
; regno
++) {
464 if ((1 << regno
) & CALLIN_REGMASK
) {
466 append_value (sub
, op
->operands
, VAL_REGISTER
, regno
);
468 if ((1 << regno
) & CALLOUT_REGMASK
) {
470 append_value (sub
, op
->results
, VAL_REGISTER
, regno
);
476 append_value (sub
, op
->results
, VAL_REGISTER
, regno
);
480 append_value (sub
, op
->results
, VAL_REGISTER
, regno
);
483 el
= element_next (el
);
488 void live_registers (struct subroutine
*sub
)
490 list worklist
= list_alloc (sub
->code
->lstpool
);
491 struct basicblock
*block
;
494 el
= list_head (sub
->blocks
);
496 block
= element_getvalue (el
);
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
);
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
);
515 edge
= element_getvalue (el
);
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
);
528 el
= element_next (el
);
532 list_free (worklist
);
536 void ssa_place_phis (struct subroutine
*sub
, list
*defblocks
)
538 struct basicblock
*block
, *bref
;
539 struct basicblocknode
*brefnode
;
543 el
= list_head (sub
->blocks
);
545 block
= element_getvalue (el
);
548 el
= element_next (el
);
551 for (i
= 1; i
< NUM_REGISTERS
; i
++) {
552 list worklist
= defblocks
[i
];
553 el
= list_head (worklist
);
555 block
= element_getvalue (el
);
557 el
= element_next (el
);
560 while (list_size (worklist
) != 0) {
561 block
= list_removehead (worklist
);
562 ref
= list_head (block
->node
.frontier
);
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
;
570 op
= alloc_operation (sub
, bref
);
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
) {
579 list_inserttail (worklist
, bref
);
582 ref
= element_next (ref
);
589 void ssa_search (struct basicblock
*block
, list
*vars
)
592 int i
, pushed
[NUM_REGISTERS
];
594 for (i
= 1; i
< NUM_REGISTERS
; i
++)
597 el
= list_head (block
->operations
);
599 struct operation
*op
;
600 struct variable
*var
;
604 op
= element_getvalue (el
);
606 if (op
->type
!= OP_PHI
) {
607 opel
= list_head (op
->operands
);
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
);
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
;
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
);
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
);
646 struct basicedge
*edge
;
647 struct basicblock
*ref
;
650 edge
= element_getvalue (el
);
653 phiel
= list_head (ref
->operations
);
655 struct operation
*op
;
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
);
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
;
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
);
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
);
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
]);