Revision e590d4e6 tcg/optimize.c
b/tcg/optimize.c | ||
---|---|---|
39 | 39 |
TCG_TEMP_UNDEF = 0, |
40 | 40 |
TCG_TEMP_CONST, |
41 | 41 |
TCG_TEMP_COPY, |
42 |
TCG_TEMP_HAS_COPY |
|
43 | 42 |
} tcg_temp_state; |
44 | 43 |
|
45 | 44 |
struct tcg_temp_info { |
... | ... | |
51 | 50 |
|
52 | 51 |
static struct tcg_temp_info temps[TCG_MAX_TEMPS]; |
53 | 52 |
|
54 |
/* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP was a representative of some |
|
55 |
class of equivalent temp's, a new representative should be chosen in this |
|
56 |
class. */ |
|
57 |
static void reset_temp(TCGArg temp, int nb_temps, int nb_globals) |
|
53 |
/* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP only had one copy, remove |
|
54 |
the copy flag from the left temp. */ |
|
55 |
static void reset_temp(TCGArg temp) |
|
58 | 56 |
{ |
59 |
int i; |
|
60 |
TCGArg new_base = (TCGArg)-1; |
|
61 |
if (temps[temp].state == TCG_TEMP_HAS_COPY) { |
|
62 |
for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { |
|
63 |
if (i >= nb_globals) { |
|
64 |
temps[i].state = TCG_TEMP_HAS_COPY; |
|
65 |
new_base = i; |
|
66 |
break; |
|
67 |
} |
|
68 |
} |
|
69 |
for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { |
|
70 |
if (new_base == (TCGArg)-1) { |
|
71 |
temps[i].state = TCG_TEMP_UNDEF; |
|
72 |
} else { |
|
73 |
temps[i].val = new_base; |
|
74 |
} |
|
57 |
if (temps[temp].state == TCG_TEMP_COPY) { |
|
58 |
if (temps[temp].prev_copy == temps[temp].next_copy) { |
|
59 |
temps[temps[temp].next_copy].state = TCG_TEMP_UNDEF; |
|
60 |
} else { |
|
61 |
temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; |
|
62 |
temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; |
|
75 | 63 |
} |
76 |
temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; |
|
77 |
temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; |
|
78 |
} else if (temps[temp].state == TCG_TEMP_COPY) { |
|
79 |
temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; |
|
80 |
temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; |
|
81 |
new_base = temps[temp].val; |
|
82 | 64 |
} |
83 | 65 |
temps[temp].state = TCG_TEMP_UNDEF; |
84 |
if (new_base != (TCGArg)-1 && temps[new_base].next_copy == new_base) { |
|
85 |
temps[new_base].state = TCG_TEMP_UNDEF; |
|
86 |
} |
|
87 | 66 |
} |
88 | 67 |
|
89 | 68 |
static int op_bits(TCGOpcode op) |
... | ... | |
106 | 85 |
} |
107 | 86 |
} |
108 | 87 |
|
88 |
static TCGArg find_better_copy(TCGContext *s, TCGArg temp) |
|
89 |
{ |
|
90 |
TCGArg i; |
|
91 |
|
|
92 |
/* If this is already a global, we can't do better. */ |
|
93 |
if (temp < s->nb_globals) { |
|
94 |
return temp; |
|
95 |
} |
|
96 |
|
|
97 |
/* Search for a global first. */ |
|
98 |
for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { |
|
99 |
if (i < s->nb_globals) { |
|
100 |
return i; |
|
101 |
} |
|
102 |
} |
|
103 |
|
|
104 |
/* If it is a temp, search for a temp local. */ |
|
105 |
if (!s->temps[temp].temp_local) { |
|
106 |
for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { |
|
107 |
if (s->temps[i].temp_local) { |
|
108 |
return i; |
|
109 |
} |
|
110 |
} |
|
111 |
} |
|
112 |
|
|
113 |
/* Failure to find a better representation, return the same temp. */ |
|
114 |
return temp; |
|
115 |
} |
|
116 |
|
|
117 |
static bool temps_are_copies(TCGArg arg1, TCGArg arg2) |
|
118 |
{ |
|
119 |
TCGArg i; |
|
120 |
|
|
121 |
if (arg1 == arg2) { |
|
122 |
return true; |
|
123 |
} |
|
124 |
|
|
125 |
if (temps[arg1].state != TCG_TEMP_COPY |
|
126 |
|| temps[arg2].state != TCG_TEMP_COPY) { |
|
127 |
return false; |
|
128 |
} |
|
129 |
|
|
130 |
for (i = temps[arg1].next_copy ; i != arg1 ; i = temps[i].next_copy) { |
|
131 |
if (i == arg2) { |
|
132 |
return true; |
|
133 |
} |
|
134 |
} |
|
135 |
|
|
136 |
return false; |
|
137 |
} |
|
138 |
|
|
109 | 139 |
static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, |
110 | 140 |
TCGArg dst, TCGArg src) |
111 | 141 |
{ |
112 |
reset_temp(dst, s->nb_temps, s->nb_globals); |
|
113 |
assert(temps[src].state != TCG_TEMP_COPY); |
|
114 |
/* Only consider temps with the same type (width) as copies. */ |
|
115 |
if (src >= s->nb_globals && s->temps[dst].type == s->temps[src].type) { |
|
116 |
assert(temps[src].state != TCG_TEMP_CONST); |
|
117 |
if (temps[src].state != TCG_TEMP_HAS_COPY) { |
|
118 |
temps[src].state = TCG_TEMP_HAS_COPY; |
|
142 |
reset_temp(dst); |
|
143 |
assert(temps[src].state != TCG_TEMP_CONST); |
|
144 |
|
|
145 |
if (s->temps[src].type == s->temps[dst].type) { |
|
146 |
if (temps[src].state != TCG_TEMP_COPY) { |
|
147 |
temps[src].state = TCG_TEMP_COPY; |
|
119 | 148 |
temps[src].next_copy = src; |
120 | 149 |
temps[src].prev_copy = src; |
121 | 150 |
} |
122 | 151 |
temps[dst].state = TCG_TEMP_COPY; |
123 |
temps[dst].val = src; |
|
124 | 152 |
temps[dst].next_copy = temps[src].next_copy; |
125 | 153 |
temps[dst].prev_copy = src; |
126 | 154 |
temps[temps[dst].next_copy].prev_copy = dst; |
127 | 155 |
temps[src].next_copy = dst; |
128 | 156 |
} |
157 |
|
|
129 | 158 |
gen_args[0] = dst; |
130 | 159 |
gen_args[1] = src; |
131 | 160 |
} |
132 | 161 |
|
133 |
static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val, |
|
134 |
int nb_temps, int nb_globals) |
|
162 |
static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val) |
|
135 | 163 |
{ |
136 |
reset_temp(dst, nb_temps, nb_globals);
|
|
164 |
reset_temp(dst); |
|
137 | 165 |
temps[dst].state = TCG_TEMP_CONST; |
138 | 166 |
temps[dst].val = val; |
139 | 167 |
gen_args[0] = dst; |
... | ... | |
324 | 352 |
tcg_abort(); |
325 | 353 |
} |
326 | 354 |
|
327 |
|
|
328 | 355 |
/* Propagate constants and copies, fold constant expressions. */ |
329 | 356 |
static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, |
330 | 357 |
TCGArg *args, TCGOpDef *tcg_op_defs) |
... | ... | |
338 | 365 |
|
339 | 366 |
/* Array VALS has an element for each temp. |
340 | 367 |
If this temp holds a constant then its value is kept in VALS' element. |
341 |
If this temp is a copy of other ones then this equivalence class' |
|
342 |
representative is kept in VALS' element. |
|
343 |
If this temp is neither copy nor constant then corresponding VALS' |
|
344 |
element is unused. */ |
|
368 |
If this temp is a copy of other ones then the other copies are |
|
369 |
available through the doubly linked circular list. */ |
|
345 | 370 |
|
346 | 371 |
nb_temps = s->nb_temps; |
347 | 372 |
nb_globals = s->nb_globals; |
... | ... | |
357 | 382 |
assert(op != INDEX_op_call); |
358 | 383 |
for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) { |
359 | 384 |
if (temps[args[i]].state == TCG_TEMP_COPY) { |
360 |
args[i] = temps[args[i]].val;
|
|
385 |
args[i] = find_better_copy(s, args[i]);
|
|
361 | 386 |
} |
362 | 387 |
} |
363 | 388 |
} |
... | ... | |
429 | 454 |
if (temps[args[1]].state == TCG_TEMP_CONST |
430 | 455 |
&& temps[args[1]].val == 0) { |
431 | 456 |
gen_opc_buf[op_index] = op_to_movi(op); |
432 |
tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals);
|
|
457 |
tcg_opt_gen_movi(gen_args, args[0], 0); |
|
433 | 458 |
args += 3; |
434 | 459 |
gen_args += 2; |
435 | 460 |
continue; |
... | ... | |
456 | 481 |
} |
457 | 482 |
if (temps[args[2]].state == TCG_TEMP_CONST |
458 | 483 |
&& temps[args[2]].val == 0) { |
459 |
if ((temps[args[0]].state == TCG_TEMP_COPY |
|
460 |
&& temps[args[0]].val == args[1]) |
|
461 |
|| args[0] == args[1]) { |
|
484 |
if (temps_are_copies(args[0], args[1])) { |
|
462 | 485 |
gen_opc_buf[op_index] = INDEX_op_nop; |
463 | 486 |
} else { |
464 | 487 |
gen_opc_buf[op_index] = op_to_mov(op); |
... | ... | |
480 | 503 |
if ((temps[args[2]].state == TCG_TEMP_CONST |
481 | 504 |
&& temps[args[2]].val == 0)) { |
482 | 505 |
gen_opc_buf[op_index] = op_to_movi(op); |
483 |
tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals);
|
|
506 |
tcg_opt_gen_movi(gen_args, args[0], 0); |
|
484 | 507 |
args += 3; |
485 | 508 |
gen_args += 2; |
486 | 509 |
continue; |
... | ... | |
495 | 518 |
CASE_OP_32_64(or): |
496 | 519 |
CASE_OP_32_64(and): |
497 | 520 |
if (args[1] == args[2]) { |
498 |
if (args[1] == args[0]) {
|
|
521 |
if (temps_are_copies(args[0], args[1])) {
|
|
499 | 522 |
gen_opc_buf[op_index] = INDEX_op_nop; |
500 | 523 |
} else { |
501 | 524 |
gen_opc_buf[op_index] = op_to_mov(op); |
... | ... | |
515 | 538 |
allocator where needed and possible. Also detect copies. */ |
516 | 539 |
switch (op) { |
517 | 540 |
CASE_OP_32_64(mov): |
518 |
if ((temps[args[1]].state == TCG_TEMP_COPY |
|
519 |
&& temps[args[1]].val == args[0]) |
|
520 |
|| args[0] == args[1]) { |
|
541 |
if (temps_are_copies(args[0], args[1])) { |
|
521 | 542 |
args += 2; |
522 | 543 |
gen_opc_buf[op_index] = INDEX_op_nop; |
523 | 544 |
break; |
... | ... | |
535 | 556 |
args[1] = temps[args[1]].val; |
536 | 557 |
/* fallthrough */ |
537 | 558 |
CASE_OP_32_64(movi): |
538 |
tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals);
|
|
559 |
tcg_opt_gen_movi(gen_args, args[0], args[1]); |
|
539 | 560 |
gen_args += 2; |
540 | 561 |
args += 2; |
541 | 562 |
break; |
... | ... | |
550 | 571 |
if (temps[args[1]].state == TCG_TEMP_CONST) { |
551 | 572 |
gen_opc_buf[op_index] = op_to_movi(op); |
552 | 573 |
tmp = do_constant_folding(op, temps[args[1]].val, 0); |
553 |
tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
|
|
574 |
tcg_opt_gen_movi(gen_args, args[0], tmp); |
|
554 | 575 |
} else { |
555 |
reset_temp(args[0], nb_temps, nb_globals);
|
|
576 |
reset_temp(args[0]); |
|
556 | 577 |
gen_args[0] = args[0]; |
557 | 578 |
gen_args[1] = args[1]; |
558 | 579 |
} |
... | ... | |
580 | 601 |
gen_opc_buf[op_index] = op_to_movi(op); |
581 | 602 |
tmp = do_constant_folding(op, temps[args[1]].val, |
582 | 603 |
temps[args[2]].val); |
583 |
tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
|
|
604 |
tcg_opt_gen_movi(gen_args, args[0], tmp); |
|
584 | 605 |
gen_args += 2; |
585 | 606 |
} else { |
586 |
reset_temp(args[0], nb_temps, nb_globals);
|
|
607 |
reset_temp(args[0]); |
|
587 | 608 |
gen_args[0] = args[0]; |
588 | 609 |
gen_args[1] = args[1]; |
589 | 610 |
gen_args[2] = args[2]; |
... | ... | |
597 | 618 |
gen_opc_buf[op_index] = op_to_movi(op); |
598 | 619 |
tmp = do_constant_folding_cond(op, temps[args[1]].val, |
599 | 620 |
temps[args[2]].val, args[3]); |
600 |
tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
|
|
621 |
tcg_opt_gen_movi(gen_args, args[0], tmp); |
|
601 | 622 |
gen_args += 2; |
602 | 623 |
} else { |
603 |
reset_temp(args[0], nb_temps, nb_globals);
|
|
624 |
reset_temp(args[0]); |
|
604 | 625 |
gen_args[0] = args[0]; |
605 | 626 |
gen_args[1] = args[1]; |
606 | 627 |
gen_args[2] = args[2]; |
... | ... | |
623 | 644 |
} |
624 | 645 |
} else { |
625 | 646 |
memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); |
626 |
reset_temp(args[0], nb_temps, nb_globals);
|
|
647 |
reset_temp(args[0]); |
|
627 | 648 |
gen_args[0] = args[0]; |
628 | 649 |
gen_args[1] = args[1]; |
629 | 650 |
gen_args[2] = args[2]; |
... | ... | |
637 | 658 |
&& temps[args[2]].state == TCG_TEMP_CONST) { |
638 | 659 |
tmp = do_constant_folding_cond(op, temps[args[1]].val, |
639 | 660 |
temps[args[2]].val, args[5]); |
640 |
if (args[0] == args[4-tmp] |
|
641 |
|| (temps[args[4-tmp]].state == TCG_TEMP_COPY |
|
642 |
&& temps[args[4-tmp]].val == args[0])) { |
|
661 |
if (temps_are_copies(args[0], args[4-tmp])) { |
|
643 | 662 |
gen_opc_buf[op_index] = INDEX_op_nop; |
644 | 663 |
} else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { |
645 | 664 |
gen_opc_buf[op_index] = op_to_movi(op); |
646 |
tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val, |
|
647 |
nb_temps, nb_globals); |
|
665 |
tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val); |
|
648 | 666 |
gen_args += 2; |
649 | 667 |
} else { |
650 | 668 |
gen_opc_buf[op_index] = op_to_mov(op); |
651 |
tcg_opt_gen_mov(gen_args, args[0], args[4-tmp], |
|
652 |
nb_temps, nb_globals); |
|
669 |
tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]); |
|
653 | 670 |
gen_args += 2; |
654 | 671 |
} |
655 | 672 |
} else { |
656 |
reset_temp(args[0], nb_temps, nb_globals);
|
|
673 |
reset_temp(args[0]); |
|
657 | 674 |
gen_args[0] = args[0]; |
658 | 675 |
gen_args[1] = args[1]; |
659 | 676 |
gen_args[2] = args[2]; |
... | ... | |
668 | 685 |
nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); |
669 | 686 |
if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) { |
670 | 687 |
for (i = 0; i < nb_globals; i++) { |
671 |
reset_temp(i, nb_temps, nb_globals);
|
|
688 |
reset_temp(i); |
|
672 | 689 |
} |
673 | 690 |
} |
674 | 691 |
for (i = 0; i < (args[0] >> 16); i++) { |
675 |
reset_temp(args[i + 1], nb_temps, nb_globals);
|
|
692 |
reset_temp(args[i + 1]); |
|
676 | 693 |
} |
677 | 694 |
i = nb_call_args + 3; |
678 | 695 |
while (i) { |
... | ... | |
691 | 708 |
memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); |
692 | 709 |
} else { |
693 | 710 |
for (i = 0; i < def->nb_oargs; i++) { |
694 |
reset_temp(args[i], nb_temps, nb_globals);
|
|
711 |
reset_temp(args[i]); |
|
695 | 712 |
} |
696 | 713 |
} |
697 | 714 |
for (i = 0; i < def->nb_args; i++) { |
Also available in: Unified diff