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 list_inserttail (block
->operations
, op
);
400 op
= operation_alloc (block
);
401 op
->info
.asmop
.begin
= op
->info
.asmop
.end
= loc
;
403 for (i
= 0; i
< NUM_REGMASK
; i
++)
404 asm_gen
[i
] = asm_kill
[i
] = 0;
406 op
->info
.asmop
.end
= loc
;
410 if (loc
->insn
->flags
& INSN_READ_LO
) {
415 if (loc
->insn
->flags
& INSN_READ_HI
) {
420 if (loc
->insn
->flags
& INSN_READ_GPR_D
) {
421 regno
= RD (loc
->opc
);
425 if (loc
->insn
->flags
& INSN_READ_GPR_T
) {
426 regno
= RT (loc
->opc
);
430 if (loc
->insn
->flags
& INSN_READ_GPR_S
) {
431 regno
= RS (loc
->opc
);
435 if (loc
->insn
->flags
& INSN_WRITE_GPR_T
) {
436 regno
= RT (loc
->opc
);
440 if (loc
->insn
->flags
& INSN_WRITE_GPR_D
) {
441 regno
= RD (loc
->opc
);
445 if (loc
->insn
->flags
& INSN_WRITE_LO
) {
450 if (loc
->insn
->flags
& INSN_WRITE_HI
) {
455 if (loc
->insn
->flags
& INSN_LINK
) {
456 regno
= REGISTER_GPR_RA
;
461 if (loc
== block
->info
.simple
.end
) {
463 list_inserttail (block
->operations
, op
);
470 op
= operation_alloc (block
);
472 op
->info
.callop
.arguments
= list_alloc (sub
->code
->lstpool
);
473 op
->info
.callop
.retvalues
= list_alloc (sub
->code
->lstpool
);
474 list_inserttail (block
->operations
, op
);
476 for (regno
= 1; regno
<= NUM_REGISTERS
; regno
++) {
477 if (IS_BIT_SET (regmask_call_gen
, regno
)) {
479 value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
481 if (IS_BIT_SET (regmask_call_kill
, regno
)) {
483 value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
489 op
= operation_alloc (block
);
492 for (regno
= 1; regno
< NUM_REGISTERS
; regno
++) {
494 value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
496 list_inserttail (block
->operations
, op
);
500 op
= operation_alloc (block
);
503 for (regno
= 1; regno
< NUM_REGISTERS
; regno
++) {
504 if (IS_BIT_SET (regmask_subend_gen
, regno
)) {
506 value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
510 list_inserttail (block
->operations
, op
);
514 el
= element_next (el
);
519 void fixup_call_arguments (struct subroutine
*sub
)
521 struct operation
*op
;
522 struct basicblock
*block
;
527 el
= list_head (sub
->blocks
);
529 block
= element_getvalue (el
);
530 if (block
->type
== BLOCK_CALL
) {
531 struct subroutine
*target
;
532 op
= list_tailvalue (block
->operations
);
533 target
= block
->info
.call
.calltarget
;
535 regend
= REGISTER_GPR_T4
;
537 if (target
->numregargs
!= -1)
538 regend
= REGISTER_GPR_A0
+ target
->numregargs
;
540 for (regno
= REGISTER_GPR_A0
; regno
< regend
; regno
++) {
541 val
= value_append (sub
, op
->operands
, VAL_REGISTER
, regno
);
542 list_inserttail (op
->info
.callop
.arguments
, val
);
545 if (target
) regend
= REGISTER_GPR_V0
+ target
->numregout
;
546 else regend
= REGISTER_GPR_A0
;
548 for (regno
= REGISTER_GPR_V0
; regno
< regend
; regno
++) {
549 val
= value_append (sub
, op
->results
, VAL_REGISTER
, regno
);
550 list_inserttail (op
->info
.callop
.retvalues
, val
);
553 el
= element_next (el
);
557 void remove_call_arguments (struct subroutine
*sub
)
559 struct operation
*op
;
560 struct basicblock
*block
;
564 el
= list_head (sub
->blocks
);
566 block
= element_getvalue (el
);
567 if (block
->type
== BLOCK_CALL
) {
568 op
= list_tailvalue (block
->operations
);
569 while (list_size (op
->info
.callop
.arguments
) != 0) {
570 val
= list_removetail (op
->info
.callop
.arguments
);
571 list_removetail (op
->operands
);
572 fixedpool_free (sub
->code
->valspool
, val
);
574 while (list_size (op
->info
.callop
.retvalues
) != 0) {
575 val
= list_removetail (op
->info
.callop
.retvalues
);
576 list_removetail (op
->results
);
577 fixedpool_free (sub
->code
->valspool
, val
);
580 el
= element_next (el
);