2 * Author: Humberto Naves (hsnaves@gmail.com)
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() \
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() \
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() \
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
)
44 struct code
*c
= block
->sub
->code
;
46 op
= fixedpool_alloc (c
->opspool
);
48 op
->operands
= list_alloc (c
->lstpool
);
49 op
->results
= list_alloc (c
->lstpool
);
54 void reset_operation (struct operation
*op
)
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
);
71 void simplify_reg_zero (list l
)
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
);
87 void simplify_operation (struct operation
*op
)
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) {
102 simplify_reg_zero (op
->results
);
103 simplify_reg_zero (op
->operands
);
105 switch (op
->info
.iop
.insn
) {
110 val
= list_headvalue (op
->operands
);
111 if (val
->val
.intval
== 0) {
112 val
= list_removehead (op
->operands
);
113 fixedpool_free (c
->valspool
, val
);
116 val
= list_tailvalue (op
->operands
);
117 if (val
->val
.intval
== 0) {
118 val
= list_removetail (op
->operands
);
119 fixedpool_free (c
->valspool
, val
);
125 val
= list_headvalue (op
->operands
);
126 if (val
->val
.intval
== 0) {
127 val
= list_removetail (op
->operands
);
128 fixedpool_free (c
->valspool
, val
);
131 val
= list_tailvalue (op
->operands
);
132 if (val
->val
.intval
== 0) {
133 val
= list_removehead (op
->operands
);
134 fixedpool_free (c
->valspool
, val
);
145 val
= list_headvalue (op
->operands
);
146 if (val
->val
.intval
== 0) {
156 val
= list_tailvalue (op
->operands
);
157 if (val
->val
.intval
== 0) {
158 val
= list_removetail (op
->operands
);
159 fixedpool_free (c
->valspool
, val
);
163 val
= element_getvalue (element_next (list_head (op
->operands
)));
164 if (val
->val
.intval
== 0) {
165 reset_operation (op
);
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
);
186 struct value
*value_append (struct subroutine
*sub
, list l
, enum valuetype type
, uint32 value
)
189 val
= fixedpool_alloc (sub
->code
->valspool
);
191 val
->val
.intval
= value
;
192 list_inserttail (l
, val
);
196 void extract_operations (struct subroutine
*sub
)
198 struct operation
*op
;
199 struct basicblock
*block
;
200 struct location
*loc
;
202 uint32 asm_gen
[NUM_REGMASK
], asm_kill
[NUM_REGMASK
];
203 int i
, regno
, lastasm
, relocnum
;
206 file
= sub
->code
->file
;
207 el
= list_head (sub
->blocks
);
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
) {
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
) {
233 if (INSN_TYPE (loc
->insn
->flags
) == INSN_ALLEGREX
) {
234 enum allegrex_insn insn
;
237 list_inserttail (block
->operations
, op
);
240 op
= operation_alloc (block
);
241 op
->type
= OP_INSTRUCTION
;
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
);
249 value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
252 if (loc
->insn
->flags
& INSN_READ_GPR_T
) {
253 regno
= RT (loc
->opc
);
255 value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
258 if (loc
->insn
->flags
& INSN_READ_GPR_D
) {
259 regno
= RD (loc
->opc
);
261 value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
264 if (loc
->insn
->flags
& INSN_READ_LO
) {
267 value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
270 if (loc
->insn
->flags
& INSN_READ_HI
) {
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
) {
283 value_append (sub
, op
->operands
, VAL_CONSTANT
, IMM (loc
->opc
));
287 value_append (sub
, op
->operands
, VAL_CONSTANT
, IMM (loc
->opc
));
291 value_append (sub
, op
->operands
, VAL_CONSTANT
, IMMU (loc
->opc
));
295 value_append (sub
, op
->operands
, VAL_CONSTANT
, IMMU (loc
->opc
));
299 value_append (sub
, op
->operands
, VAL_CONSTANT
, IMMU (loc
->opc
));
303 value_append (sub
, op
->operands
, VAL_CONSTANT
, ((unsigned int) IMMU (loc
->opc
)) << 16);
307 value_append (sub
, op
->operands
, VAL_CONSTANT
, IMM (loc
->opc
));
311 value_append (sub
, op
->operands
, VAL_CONSTANT
, IMM (loc
->opc
));
315 value_append (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
316 value_append (sub
, op
->operands
, VAL_CONSTANT
, RD (loc
->opc
) + 1);
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);
325 value_append (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
329 value_append (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
333 value_append (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
337 value_append (sub
, op
->operands
, VAL_CONSTANT
, SA (loc
->opc
));
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
);
368 value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
371 if (loc
->insn
->flags
& INSN_WRITE_GPR_D
) {
372 regno
= RD (loc
->opc
);
374 value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
377 if (loc
->insn
->flags
& INSN_WRITE_LO
) {
380 value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
383 if (loc
->insn
->flags
& INSN_WRITE_HI
) {
386 value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
389 if (loc
->insn
->flags
& INSN_LINK
) {
390 regno
= REGISTER_GPR_RA
;
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
))
398 list_inserttail (block
->operations
, op
);
402 op
= operation_alloc (block
);
403 op
->info
.asmop
.begin
= op
->info
.asmop
.end
= loc
;
405 for (i
= 0; i
< NUM_REGMASK
; i
++)
406 asm_gen
[i
] = asm_kill
[i
] = 0;
408 op
->info
.asmop
.end
= loc
;
412 if (loc
->insn
->flags
& INSN_READ_LO
) {
417 if (loc
->insn
->flags
& INSN_READ_HI
) {
422 if (loc
->insn
->flags
& INSN_READ_GPR_D
) {
423 regno
= RD (loc
->opc
);
427 if (loc
->insn
->flags
& INSN_READ_GPR_T
) {
428 regno
= RT (loc
->opc
);
432 if (loc
->insn
->flags
& INSN_READ_GPR_S
) {
433 regno
= RS (loc
->opc
);
437 if (loc
->insn
->flags
& INSN_WRITE_GPR_T
) {
438 regno
= RT (loc
->opc
);
442 if (loc
->insn
->flags
& INSN_WRITE_GPR_D
) {
443 regno
= RD (loc
->opc
);
447 if (loc
->insn
->flags
& INSN_WRITE_LO
) {
452 if (loc
->insn
->flags
& INSN_WRITE_HI
) {
457 if (loc
->insn
->flags
& INSN_LINK
) {
458 regno
= REGISTER_GPR_RA
;
463 if (loc
== block
->info
.simple
.end
) {
465 list_inserttail (block
->operations
, op
);
472 op
= operation_alloc (block
);
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
)) {
481 value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
483 if (IS_BIT_SET (regmask_call_kill
, regno
)) {
485 value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
491 op
= operation_alloc (block
);
494 for (regno
= 1; regno
< NUM_REGISTERS
; regno
++) {
496 value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
498 list_inserttail (block
->operations
, op
);
502 op
= operation_alloc (block
);
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
)) {
509 value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
513 list_inserttail (block
->operations
, op
);
517 el
= element_next (el
);
522 void fixup_call_arguments (struct subroutine
*sub
)
524 struct operation
*op
;
525 struct basicblock
*block
;
530 el
= list_head (sub
->blocks
);
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
;
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
;
575 el
= list_head (sub
->blocks
);
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
);