00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "system.h"
00023 #include "coretypes.h"
00024 #include "tm.h"
00025 #include "rtl.h"
00026 #include "obstack.h"
00027 #include "basic-block.h"
00028 #include "resource.h"
00029 #include "flags.h"
00030 #include "ggc.h"
00031 #include "regs.h"
00032 #include "params.h"
00033 #include "expr.h"
00034 #include "tm_p.h"
00035 #include "tree-pass.h"
00036 #include "tree-flow.h"
00037 #include "timevar.h"
00038 #include "output.h"
00039 #include "addresses.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 #define ABSTRACTABLE_INSN_P(X) (INSN_P (X) && !JUMP_P (X))
00136
00137
00138 #define HASH_INIT 1023
00139
00140
00141
00142 #ifndef SEQ_CALL_COST_MULTIPLIER
00143 #define SEQ_CALL_COST_MULTIPLIER 2
00144 #endif
00145
00146
00147 #define RECOMPUTE_COST(SEQ) \
00148 { \
00149 int l; \
00150 rtx x = SEQ->insn; \
00151 SEQ->cost = 0; \
00152 for (l = 0; l < SEQ->abstracted_length; l++) \
00153 { \
00154 SEQ->cost += compute_rtx_cost (x); \
00155 x = prev_insn_in_block (x); \
00156 } \
00157 }
00158
00159
00160 typedef struct matching_seq_def
00161 {
00162
00163 rtx insn;
00164
00165
00166 unsigned long idx;
00167
00168
00169
00170 int matching_length;
00171
00172
00173
00174 int abstracted_length;
00175
00176
00177 int cost;
00178
00179
00180 struct matching_seq_def *next_matching_seq;
00181 } *matching_seq;
00182
00183
00184
00185 typedef struct pattern_seq_def
00186 {
00187
00188 rtx insn;
00189
00190
00191 unsigned long idx;
00192
00193
00194
00195 int gain;
00196
00197
00198 int abstracted_length;
00199
00200
00201 int cost;
00202
00203
00204 rtx link_reg;
00205
00206
00207 matching_seq matching_seqs;
00208
00209
00210 struct pattern_seq_def *next_pattern_seq;
00211 } *pattern_seq;
00212
00213
00214
00215 typedef struct seq_block_def
00216 {
00217
00218 int length;
00219
00220
00221 rtx label;
00222
00223
00224 matching_seq matching_seqs;
00225
00226
00227
00228 struct seq_block_def *next_seq_block;
00229 } *seq_block;
00230
00231
00232 typedef struct hash_bucket_def
00233 {
00234
00235 unsigned int hash;
00236
00237
00238 htab_t seq_candidates;
00239 } *p_hash_bucket;
00240
00241
00242 typedef struct hash_elem_def
00243 {
00244
00245 unsigned long idx;
00246
00247
00248 rtx insn;
00249
00250
00251 int length;
00252 } *p_hash_elem;
00253
00254
00255 static htab_t hash_buckets;
00256
00257
00258 static pattern_seq pattern_seqs;
00259
00260
00261 static seq_block seq_blocks;
00262
00263
00264 static int seq_call_cost;
00265
00266
00267 static int seq_jump_cost;
00268
00269
00270 static int seq_return_cost;
00271
00272
00273
00274
00275 static rtx
00276 prev_insn_in_block (rtx insn)
00277 {
00278 basic_block bb = BLOCK_FOR_INSN (insn);
00279
00280 if (!bb)
00281 return NULL_RTX;
00282
00283 while (insn != BB_HEAD (bb))
00284 {
00285 insn = PREV_INSN (insn);
00286 if (INSN_P (insn))
00287 return insn;
00288 }
00289 return NULL_RTX;
00290 }
00291
00292
00293
00294 static unsigned int
00295 compute_hash (rtx insn)
00296 {
00297 unsigned int hash = 0;
00298 rtx prev;
00299
00300 hash = INSN_CODE (insn) * 100;
00301
00302 prev = prev_insn_in_block (insn);
00303 if (prev)
00304 hash += INSN_CODE (prev);
00305
00306 return hash;
00307 }
00308
00309
00310
00311 static int
00312 compute_rtx_cost (rtx insn)
00313 {
00314 struct hash_bucket_def tmp_bucket;
00315 p_hash_bucket bucket;
00316 struct hash_elem_def tmp_elem;
00317 p_hash_elem elem = NULL;
00318 int cost = -1;
00319
00320
00321 tmp_bucket.hash = compute_hash (insn);
00322
00323
00324 bucket = htab_find (hash_buckets, &tmp_bucket);
00325
00326 if (bucket)
00327 {
00328 tmp_elem.insn = insn;
00329
00330
00331 elem = htab_find (bucket->seq_candidates, &tmp_elem);
00332
00333
00334 if (elem)
00335 cost = elem->length;
00336 }
00337
00338
00339 if (cost == -1)
00340 {
00341 cost = get_attr_length (insn);
00342
00343
00344 if (elem)
00345 elem->length = cost;
00346 }
00347
00348
00349
00350 return cost != 0 ? cost : COSTS_N_INSNS (1);
00351 }
00352
00353
00354
00355
00356
00357 static void
00358 matching_length (rtx insn1, rtx insn2, int* len, int* cost)
00359 {
00360 rtx x1;
00361 rtx x2;
00362
00363 x1 = insn1;
00364 x2 = insn2;
00365 *len = 0;
00366 *cost = 0;
00367 while (x1 && x2 && (x1 != insn2) && (x2 != insn1)
00368 && rtx_equal_p (PATTERN (x1), PATTERN (x2)))
00369 {
00370 (*len)++;
00371 (*cost) += compute_rtx_cost (x1);
00372 x1 = prev_insn_in_block (x1);
00373 x2 = prev_insn_in_block (x2);
00374 }
00375 }
00376
00377
00378
00379
00380 static void
00381 match_seqs (p_hash_elem e0, p_hash_elem e1)
00382 {
00383 int len;
00384 int cost;
00385 matching_seq mseq, p_prev, p_next;
00386
00387
00388
00389 matching_length (e0->insn, e1->insn, &len, &cost);
00390 if (cost <= seq_call_cost)
00391 return;
00392
00393
00394
00395
00396 if (!pattern_seqs || pattern_seqs->insn != e0->insn)
00397 {
00398 pattern_seq pseq =
00399 (pattern_seq) xmalloc (sizeof (struct pattern_seq_def));
00400 pseq->insn = e0->insn;
00401 pseq->idx = e0->idx;
00402 pseq->gain = 0;
00403 pseq->abstracted_length = 0;
00404 pseq->cost = 0;
00405 pseq->link_reg = NULL_RTX;
00406 pseq->matching_seqs = NULL;
00407 pseq->next_pattern_seq = pattern_seqs;
00408 pattern_seqs = pseq;
00409 }
00410
00411
00412 p_prev = NULL;
00413 p_next = pattern_seqs->matching_seqs;
00414 while (p_next && p_next->idx < e1->idx)
00415 {
00416 p_prev = p_next;
00417 p_next = p_next->next_matching_seq;
00418 }
00419
00420
00421
00422 mseq = (matching_seq) xmalloc (sizeof (struct matching_seq_def));
00423 mseq->insn = e1->insn;
00424 mseq->idx = e1->idx;
00425 mseq->matching_length = len;
00426 mseq->abstracted_length = 0;
00427 mseq->cost = cost;
00428
00429 if (p_prev == NULL)
00430 pattern_seqs->matching_seqs = mseq;
00431 else
00432 p_prev->next_matching_seq = mseq;
00433 mseq->next_matching_seq = p_next;
00434 }
00435
00436
00437
00438
00439 static void
00440 collect_pattern_seqs (void)
00441 {
00442 htab_iterator hti0, hti1, hti2;
00443 p_hash_bucket hash_bucket;
00444 p_hash_elem e0, e1;
00445 #ifdef STACK_REGS
00446 basic_block bb;
00447 bitmap_head stack_reg_live;
00448
00449
00450
00451
00452 bitmap_initialize (&stack_reg_live, NULL);
00453
00454 FOR_EACH_BB (bb)
00455 {
00456 regset_head live;
00457 struct propagate_block_info *pbi;
00458 rtx insn;
00459
00460
00461 INIT_REG_SET (&live);
00462 COPY_REG_SET (&live, bb->il.rtl->global_live_at_end);
00463 pbi = init_propagate_block_info (bb, &live, NULL, NULL, 0);
00464
00465
00466 insn = BB_END (bb);
00467 while (1)
00468 {
00469 int reg;
00470 for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
00471 {
00472 if (REGNO_REG_SET_P (&live, reg))
00473 {
00474 bitmap_set_bit (&stack_reg_live, INSN_UID (insn));
00475 break;
00476 }
00477 }
00478
00479 if (insn == BB_HEAD (bb))
00480 break;
00481 insn = propagate_one_insn (pbi, insn);
00482 }
00483
00484
00485 CLEAR_REG_SET (&live);
00486 free_propagate_block_info (pbi);
00487 }
00488 #endif
00489
00490
00491 pattern_seqs = 0;
00492
00493
00494
00495
00496 FOR_EACH_HTAB_ELEMENT (hash_buckets, hash_bucket, p_hash_bucket, hti0)
00497 if (htab_elements (hash_bucket->seq_candidates) > 1)
00498 FOR_EACH_HTAB_ELEMENT (hash_bucket->seq_candidates, e0, p_hash_elem, hti1)
00499 FOR_EACH_HTAB_ELEMENT (hash_bucket->seq_candidates, e1, p_hash_elem,
00500 hti2)
00501 if (e0 != e1
00502 #ifdef STACK_REGS
00503 && !bitmap_bit_p (&stack_reg_live, INSN_UID (e0->insn))
00504 && !bitmap_bit_p (&stack_reg_live, INSN_UID (e1->insn))
00505 #endif
00506 )
00507 match_seqs (e0, e1);
00508 #ifdef STACK_REGS
00509
00510 bitmap_clear (&stack_reg_live);
00511 #endif
00512 }
00513
00514
00515
00516
00517
00518 static void
00519 renumbered_reg_set_to_hard_reg_set (HARD_REG_SET * hregs, regset regs)
00520 {
00521 int r;
00522
00523 REG_SET_TO_HARD_REG_SET (*hregs, regs);
00524 for (r = FIRST_PSEUDO_REGISTER; r < max_regno; r++)
00525 if (REGNO_REG_SET_P (regs, r) && reg_renumber[r] >= 0)
00526 SET_HARD_REG_BIT (*hregs, reg_renumber[r]);
00527 }
00528
00529
00530
00531
00532 static void
00533 clear_regs_live_in_seq (HARD_REG_SET * regs, rtx insn, int length)
00534 {
00535 basic_block bb;
00536 regset_head live;
00537 HARD_REG_SET hlive;
00538 struct propagate_block_info *pbi;
00539 rtx x;
00540 int i;
00541
00542
00543 bb = BLOCK_FOR_INSN (insn);
00544 INIT_REG_SET (&live);
00545 COPY_REG_SET (&live, bb->il.rtl->global_live_at_end);
00546 pbi = init_propagate_block_info (bb, &live, NULL, NULL, 0);
00547
00548
00549 for (x = BB_END (bb); x != insn;)
00550 x = propagate_one_insn (pbi, x);
00551
00552
00553 renumbered_reg_set_to_hard_reg_set (&hlive, &live);
00554 AND_COMPL_HARD_REG_SET (*regs, hlive);
00555
00556
00557 for (i = 0; i < length;)
00558 {
00559 rtx prev = propagate_one_insn (pbi, x);
00560
00561 if (INSN_P (x))
00562 {
00563 renumbered_reg_set_to_hard_reg_set (&hlive, &live);
00564 AND_COMPL_HARD_REG_SET (*regs, hlive);
00565 i++;
00566 }
00567
00568 x = prev;
00569 }
00570
00571
00572 free_propagate_block_info (pbi);
00573 CLEAR_REG_SET (&live);
00574 }
00575
00576
00577
00578
00579
00580 static void
00581 recompute_gain_for_pattern_seq (pattern_seq pseq)
00582 {
00583 matching_seq mseq;
00584 rtx x;
00585 int i;
00586 int hascall;
00587 HARD_REG_SET linkregs;
00588
00589
00590 SET_HARD_REG_SET (linkregs);
00591 pseq->link_reg = NULL_RTX;
00592 pseq->abstracted_length = 0;
00593
00594 pseq->gain = -(seq_call_cost - seq_jump_cost + seq_return_cost);
00595
00596
00597
00598
00599
00600 for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
00601 {
00602
00603 if (mseq->next_matching_seq)
00604 mseq->abstracted_length = (int)(mseq->next_matching_seq->idx -
00605 mseq->idx);
00606 else
00607 mseq->abstracted_length = mseq->matching_length;
00608
00609 if (mseq->abstracted_length > mseq->matching_length)
00610 mseq->abstracted_length = mseq->matching_length;
00611
00612
00613 RECOMPUTE_COST (mseq);
00614
00615
00616
00617
00618 if (mseq->cost > seq_call_cost)
00619 {
00620 clear_regs_live_in_seq (&linkregs, mseq->insn,
00621 mseq->abstracted_length);
00622 if (mseq->abstracted_length > pseq->abstracted_length)
00623 pseq->abstracted_length = mseq->abstracted_length;
00624 }
00625 }
00626
00627
00628
00629 for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
00630 {
00631 x = pseq->insn;
00632 for (i = 0; (i < pseq->abstracted_length) && (x != mseq->insn); i++)
00633 x = prev_insn_in_block (x);
00634 pseq->abstracted_length = i;
00635 }
00636
00637
00638 RECOMPUTE_COST (pseq);
00639
00640
00641 if (pseq->cost <= seq_call_cost)
00642 {
00643 pseq->gain = -1;
00644 return;
00645 }
00646
00647
00648 for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
00649 {
00650 if (mseq->abstracted_length > pseq->abstracted_length)
00651 {
00652 mseq->abstracted_length = pseq->abstracted_length;
00653 RECOMPUTE_COST (mseq);
00654 }
00655
00656 if (mseq->cost > seq_call_cost)
00657 pseq->gain += mseq->cost - seq_call_cost;
00658 }
00659
00660
00661 if (pseq->gain <= 0)
00662 return;
00663
00664
00665
00666 clear_regs_live_in_seq (&linkregs, pseq->insn, pseq->abstracted_length);
00667
00668
00669 hascall = 0;
00670 x = pseq->insn;
00671 for (i = 0; i < pseq->abstracted_length; i++)
00672 {
00673 if (CALL_P (x))
00674 {
00675 hascall = 1;
00676 break;
00677 }
00678 x = prev_insn_in_block (x);
00679 }
00680
00681
00682
00683
00684
00685
00686
00687
00688 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
00689 if (fixed_regs[i]
00690 #ifdef REGNO_OK_FOR_INDIRECT_JUMP_P
00691 || (!REGNO_OK_FOR_INDIRECT_JUMP_P (i, Pmode))
00692 #else
00693 || (!ok_for_base_p_1 (i, Pmode, MEM, SCRATCH))
00694 || (!reg_class_subset_p (REGNO_REG_CLASS (i),
00695 base_reg_class (VOIDmode, MEM, SCRATCH)))
00696 #endif
00697 || (hascall && call_used_regs[i])
00698 || (!call_used_regs[i] && !regs_ever_live[i]))
00699 CLEAR_HARD_REG_BIT (linkregs, i);
00700
00701
00702 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
00703 if (TEST_HARD_REG_BIT (linkregs, i))
00704 {
00705 pseq->link_reg = gen_rtx_REG (Pmode, i);
00706 break;
00707 }
00708
00709
00710
00711 if (!pseq->link_reg)
00712 pseq->gain = 0;
00713 }
00714
00715
00716
00717 static void
00718 free_pattern_seq (pattern_seq pseq)
00719 {
00720 while (pseq->matching_seqs)
00721 {
00722 matching_seq mseq = pseq->matching_seqs;
00723 pseq->matching_seqs = mseq->next_matching_seq;
00724 free (mseq);
00725 }
00726 free (pseq);
00727 }
00728
00729
00730
00731
00732
00733
00734 static void
00735 recompute_gain (void)
00736 {
00737 pattern_seq *pseq;
00738 int maxgain;
00739
00740 maxgain = 0;
00741 for (pseq = &pattern_seqs; *pseq;)
00742 {
00743 if ((*pseq)->gain <= 0)
00744 recompute_gain_for_pattern_seq (*pseq);
00745
00746 if ((*pseq)->gain > 0)
00747 {
00748 if ((*pseq)->gain > maxgain)
00749 {
00750 pattern_seq temp = *pseq;
00751 (*pseq) = temp->next_pattern_seq;
00752 temp->next_pattern_seq = pattern_seqs;
00753 pattern_seqs = temp;
00754 maxgain = pattern_seqs->gain;
00755 }
00756 else
00757 {
00758 pseq = &(*pseq)->next_pattern_seq;
00759 }
00760 }
00761 else
00762 {
00763 pattern_seq temp = *pseq;
00764 *pseq = temp->next_pattern_seq;
00765 free_pattern_seq (temp);
00766 }
00767 }
00768 }
00769
00770
00771
00772
00773
00774 static void
00775 erase_from_pattern_seqs (rtx insn, int len)
00776 {
00777 pattern_seq *pseq;
00778 matching_seq *mseq;
00779 rtx x;
00780 int plen, mlen;
00781 int pcost, mcost;
00782
00783 while (len > 0)
00784 {
00785 for (pseq = &pattern_seqs; *pseq;)
00786 {
00787 plen = 0;
00788 pcost = 0;
00789 for (x = (*pseq)->insn; x && (x != insn);
00790 x = prev_insn_in_block (x))
00791 {
00792 plen++;
00793 pcost += compute_rtx_cost (x);
00794 }
00795
00796 if (pcost <= seq_call_cost)
00797 {
00798 pattern_seq temp = *pseq;
00799 *pseq = temp->next_pattern_seq;
00800 free_pattern_seq (temp);
00801 }
00802 else
00803 {
00804 for (mseq = &(*pseq)->matching_seqs; *mseq;)
00805 {
00806 mlen = 0;
00807 mcost = 0;
00808 for (x = (*mseq)->insn;
00809 x && (x != insn) && (mlen < plen)
00810 && (mlen < (*mseq)->matching_length);
00811 x = prev_insn_in_block (x))
00812 {
00813 mlen++;
00814 mcost += compute_rtx_cost (x);
00815 }
00816
00817 if (mcost <= seq_call_cost)
00818 {
00819 matching_seq temp = *mseq;
00820 *mseq = temp->next_matching_seq;
00821 free (temp);
00822
00823 (*pseq)->gain = 0;
00824 }
00825 else
00826 {
00827 if (mlen < (*mseq)->matching_length)
00828 {
00829 (*mseq)->cost = mcost;
00830 (*mseq)->matching_length = mlen;
00831
00832 (*pseq)->gain = 0;
00833 }
00834 mseq = &(*mseq)->next_matching_seq;
00835 }
00836 }
00837
00838 pseq = &(*pseq)->next_pattern_seq;
00839 }
00840 }
00841
00842 len--;
00843 insn = prev_insn_in_block (insn);
00844 }
00845 }
00846
00847
00848
00849
00850 static void
00851 update_pattern_seqs (void)
00852 {
00853 pattern_seq bestpseq;
00854 matching_seq mseq;
00855
00856 bestpseq = pattern_seqs;
00857 pattern_seqs = bestpseq->next_pattern_seq;
00858
00859 for (mseq = bestpseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
00860 if (mseq->cost > seq_call_cost)
00861 erase_from_pattern_seqs (mseq->insn, mseq->abstracted_length);
00862 erase_from_pattern_seqs (bestpseq->insn, bestpseq->abstracted_length);
00863
00864 bestpseq->next_pattern_seq = pattern_seqs;
00865 pattern_seqs = bestpseq;
00866 }
00867
00868
00869
00870
00871
00872 static void
00873 determine_seq_blocks (void)
00874 {
00875 seq_block sb;
00876 matching_seq *mseq;
00877 matching_seq m;
00878
00879
00880 seq_blocks = 0;
00881
00882
00883 for (mseq = &pattern_seqs->matching_seqs; *mseq;)
00884 {
00885
00886 if ((*mseq)->cost <= seq_call_cost)
00887 {
00888 mseq = &(*mseq)->next_matching_seq;
00889 continue;
00890 }
00891
00892
00893
00894 if (!seq_blocks || ((*mseq)->abstracted_length < seq_blocks->length))
00895 {
00896 sb = (seq_block) xmalloc (sizeof (struct seq_block_def));
00897 sb->length = (*mseq)->abstracted_length;
00898 sb->label = NULL_RTX;
00899 sb->matching_seqs = 0;
00900 sb->next_seq_block = seq_blocks;
00901 seq_blocks = sb;
00902 }
00903 else
00904 {
00905 for (sb = seq_blocks; sb; sb = sb->next_seq_block)
00906 {
00907 if ((*mseq)->abstracted_length == sb->length)
00908 break;
00909 if (!sb->next_seq_block
00910 || ((*mseq)->abstracted_length <
00911 sb->next_seq_block->length))
00912 {
00913 seq_block temp =
00914 (seq_block) xmalloc (sizeof (struct seq_block_def));
00915 temp->length = (*mseq)->abstracted_length;
00916 temp->label = NULL_RTX;
00917 temp->matching_seqs = 0;
00918 temp->next_seq_block = sb->next_seq_block;
00919 sb->next_seq_block = temp;
00920 }
00921 }
00922 }
00923
00924
00925
00926 m = *mseq;
00927 *mseq = m->next_matching_seq;
00928 m->next_matching_seq = sb->matching_seqs;
00929 sb->matching_seqs = m;
00930 }
00931 }
00932
00933
00934
00935 static rtx
00936 gen_symbol_ref_rtx_for_label (rtx label)
00937 {
00938 char name[20];
00939 rtx sym;
00940
00941 ASM_GENERATE_INTERNAL_LABEL (name, "L", CODE_LABEL_NUMBER (label));
00942 sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
00943 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_LOCAL;
00944 return sym;
00945 }
00946
00947
00948
00949
00950 static rtx
00951 block_label_after (rtx insn)
00952 {
00953 basic_block bb = BLOCK_FOR_INSN (insn);
00954 if ((insn == BB_END (bb)) && (bb->next_bb != EXIT_BLOCK_PTR))
00955 return block_label (bb->next_bb);
00956 else
00957 return block_label (split_block (bb, insn)->dest);
00958 }
00959
00960
00961
00962
00963
00964
00965 static void
00966 split_blocks_after_seqs (void)
00967 {
00968 seq_block sb;
00969 matching_seq mseq;
00970
00971 block_label_after (pattern_seqs->insn);
00972 for (sb = seq_blocks; sb; sb = sb->next_seq_block)
00973 {
00974 for (mseq = sb->matching_seqs; mseq; mseq = mseq->next_matching_seq)
00975 {
00976 block_label_after (mseq->insn);
00977 IOR_REG_SET (BLOCK_FOR_INSN (pattern_seqs->insn)->
00978 il.rtl->global_live_at_end,
00979 BLOCK_FOR_INSN (mseq->insn)->il.rtl->global_live_at_end);
00980 }
00981 }
00982 }
00983
00984
00985
00986
00987 static void
00988 split_pattern_seq (void)
00989 {
00990 rtx insn;
00991 basic_block bb;
00992 rtx retlabel, retjmp, saveinsn;
00993 int i;
00994 seq_block sb;
00995
00996 insn = pattern_seqs->insn;
00997 bb = BLOCK_FOR_INSN (insn);
00998
00999
01000
01001
01002 retlabel = block_label_after (insn);
01003 LABEL_PRESERVE_P (retlabel) = 1;
01004
01005
01006
01007 retjmp = emit_jump_insn_after (gen_indirect_jump (pattern_seqs->link_reg),
01008 BB_END (bb));
01009 emit_barrier_after (BB_END (bb));
01010
01011
01012 while (EDGE_COUNT (bb->succs) != 0)
01013 remove_edge (EDGE_SUCC (bb, 0));
01014 make_edge (bb, BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL);
01015
01016
01017
01018 i = 0;
01019 for (sb = seq_blocks; sb; sb = sb->next_seq_block)
01020 {
01021 for (; i < sb->length; i++)
01022 insn = prev_insn_in_block (insn);
01023
01024 sb->label = block_label (split_block (bb, insn)->dest);
01025 }
01026
01027
01028
01029 saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg,
01030 gen_symbol_ref_rtx_for_label
01031 (retlabel)), BB_END (bb));
01032
01033 SET_REGNO_REG_SET (bb->il.rtl->global_live_at_end,
01034 REGNO (pattern_seqs->link_reg));
01035 }
01036
01037
01038
01039
01040 static void
01041 erase_matching_seqs (void)
01042 {
01043 seq_block sb;
01044 matching_seq mseq;
01045 rtx insn;
01046 basic_block bb;
01047 rtx retlabel, saveinsn, callinsn;
01048 int i;
01049
01050 for (sb = seq_blocks; sb; sb = sb->next_seq_block)
01051 {
01052 for (mseq = sb->matching_seqs; mseq; mseq = mseq->next_matching_seq)
01053 {
01054 insn = mseq->insn;
01055 bb = BLOCK_FOR_INSN (insn);
01056
01057
01058
01059
01060 retlabel = block_label_after (insn);
01061 LABEL_PRESERVE_P (retlabel) = 1;
01062
01063
01064 for (i = 0; i < sb->length; i++)
01065 insn = prev_insn_in_block (insn);
01066 delete_basic_block (split_block (bb, insn)->dest);
01067
01068
01069
01070 saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg,
01071 gen_symbol_ref_rtx_for_label
01072 (retlabel)),
01073 BB_END (bb));
01074 BLOCK_FOR_INSN (saveinsn) = bb;
01075
01076
01077
01078 callinsn = emit_jump_insn_after (gen_jump (sb->label), saveinsn);
01079 JUMP_LABEL (callinsn) = sb->label;
01080 LABEL_NUSES (sb->label)++;
01081 BLOCK_FOR_INSN (callinsn) = bb;
01082 BB_END (bb) = callinsn;
01083
01084
01085 SET_REGNO_REG_SET (bb->il.rtl->global_live_at_end,
01086 REGNO (pattern_seqs->link_reg));
01087 emit_barrier_after (BB_END (bb));
01088 make_single_succ_edge (bb, BLOCK_FOR_INSN (sb->label), 0);
01089 IOR_REG_SET (bb->il.rtl->global_live_at_end,
01090 BLOCK_FOR_INSN (sb->label)->il.rtl->global_live_at_start);
01091
01092 make_edge (BLOCK_FOR_INSN (seq_blocks->label),
01093 BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL);
01094 }
01095 }
01096 }
01097
01098
01099
01100 static void
01101 free_seq_blocks (void)
01102 {
01103 while (seq_blocks)
01104 {
01105 seq_block sb = seq_blocks;
01106 while (sb->matching_seqs)
01107 {
01108 matching_seq mseq = sb->matching_seqs;
01109 sb->matching_seqs = mseq->next_matching_seq;
01110 free (mseq);
01111 }
01112 seq_blocks = sb->next_seq_block;
01113 free (sb);
01114 }
01115 }
01116
01117
01118
01119
01120
01121 static void
01122 abstract_best_seq (void)
01123 {
01124 pattern_seq bestpseq;
01125
01126
01127 determine_seq_blocks ();
01128 split_blocks_after_seqs ();
01129 split_pattern_seq ();
01130 erase_matching_seqs ();
01131 free_seq_blocks ();
01132
01133
01134 regs_ever_live[REGNO (pattern_seqs->link_reg)] = 1;
01135
01136
01137 bestpseq = pattern_seqs;
01138 pattern_seqs = bestpseq->next_pattern_seq;
01139 free_pattern_seq (bestpseq);
01140 }
01141
01142
01143
01144 static void
01145 dump_pattern_seqs (void)
01146 {
01147 pattern_seq pseq;
01148 matching_seq mseq;
01149
01150 if (!dump_file)
01151 return;
01152
01153 fprintf (dump_file, ";; Pattern sequences\n");
01154 for (pseq = pattern_seqs; pseq; pseq = pseq->next_pattern_seq)
01155 {
01156 fprintf (dump_file, "Pattern sequence at insn %d matches sequences at",
01157 INSN_UID (pseq->insn));
01158 for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
01159 {
01160 fprintf (dump_file, " insn %d (length %d)", INSN_UID (mseq->insn),
01161 mseq->matching_length);
01162 if (mseq->next_matching_seq)
01163 fprintf (dump_file, ",");
01164 }
01165 fprintf (dump_file, ".\n");
01166 }
01167 fprintf (dump_file, "\n");
01168 }
01169
01170
01171
01172
01173 static void
01174 dump_best_pattern_seq (int iter)
01175 {
01176 matching_seq mseq;
01177
01178 if (!dump_file)
01179 return;
01180
01181 fprintf (dump_file, ";; Iteration %d\n", iter);
01182 fprintf (dump_file,
01183 "Best pattern sequence with %d gain is at insn %d (length %d).\n",
01184 pattern_seqs->gain, INSN_UID (pattern_seqs->insn),
01185 pattern_seqs->abstracted_length);
01186 fprintf (dump_file, "Matching sequences are at");
01187 for (mseq = pattern_seqs->matching_seqs; mseq;
01188 mseq = mseq->next_matching_seq)
01189 {
01190 fprintf (dump_file, " insn %d (length %d)", INSN_UID (mseq->insn),
01191 mseq->abstracted_length);
01192 if (mseq->next_matching_seq)
01193 fprintf (dump_file, ",");
01194 }
01195 fprintf (dump_file, ".\n");
01196 fprintf (dump_file, "Using reg %d as link register.\n\n",
01197 REGNO (pattern_seqs->link_reg));
01198 }
01199
01200
01201
01202 static unsigned int
01203 htab_hash_bucket (const void *p)
01204 {
01205 p_hash_bucket bucket = (p_hash_bucket) p;
01206 return bucket->hash;
01207 }
01208
01209
01210
01211 static int
01212 htab_eq_bucket (const void *p0, const void *p1)
01213 {
01214 return htab_hash_bucket (p0) == htab_hash_bucket (p1);
01215 }
01216
01217
01218
01219 static void
01220 htab_del_bucket (void *p)
01221 {
01222 p_hash_bucket bucket = (p_hash_bucket) p;
01223
01224 if (bucket->seq_candidates)
01225 htab_delete (bucket->seq_candidates);
01226
01227 free (bucket);
01228 }
01229
01230
01231
01232 static unsigned int
01233 htab_hash_elem (const void *p)
01234 {
01235 p_hash_elem elem = (p_hash_elem) p;
01236 return htab_hash_pointer (elem->insn);
01237 }
01238
01239
01240
01241 static int
01242 htab_eq_elem (const void *p0, const void *p1)
01243 {
01244 return htab_hash_elem (p0) == htab_hash_elem (p1);
01245 }
01246
01247
01248
01249 static void
01250 htab_del_elem (void *p)
01251 {
01252 p_hash_elem elem = (p_hash_elem) p;
01253 free (elem);
01254 }
01255
01256
01257
01258
01259 static void
01260 fill_hash_bucket (void)
01261 {
01262 basic_block bb;
01263 rtx insn;
01264 void **slot;
01265 p_hash_bucket bucket;
01266 struct hash_bucket_def tmp_bucket;
01267 p_hash_elem elem;
01268 unsigned long insn_idx;
01269
01270 insn_idx = 0;
01271 FOR_EACH_BB (bb)
01272 {
01273 FOR_BB_INSNS_REVERSE (bb, insn)
01274 {
01275 if (!ABSTRACTABLE_INSN_P (insn))
01276 continue;
01277
01278
01279 tmp_bucket.hash = compute_hash (insn);
01280
01281
01282 bucket = htab_find (hash_buckets, &tmp_bucket);
01283
01284 if (!bucket)
01285 {
01286
01287 bucket = (p_hash_bucket) xcalloc (1,
01288 sizeof (struct hash_bucket_def));
01289 bucket->hash = tmp_bucket.hash;
01290 bucket->seq_candidates = NULL;
01291
01292 slot = htab_find_slot (hash_buckets, &tmp_bucket, INSERT);
01293 *slot = bucket;
01294 }
01295
01296
01297 if (!bucket->seq_candidates)
01298 bucket->seq_candidates = htab_create (HASH_INIT,
01299 htab_hash_elem,
01300 htab_eq_elem,
01301 htab_del_elem);
01302
01303 elem = (p_hash_elem) xcalloc (1, sizeof (struct hash_elem_def));
01304 elem->insn = insn;
01305 elem->idx = insn_idx;
01306 elem->length = get_attr_length (insn);
01307
01308
01309 slot = htab_find_slot (bucket->seq_candidates, elem, INSERT);
01310 *slot = elem;
01311
01312 insn_idx++;
01313 }
01314 }
01315 }
01316
01317
01318
01319 static void
01320 compute_init_costs (void)
01321 {
01322 rtx rtx_jump, rtx_store, rtx_return, reg, label;
01323 basic_block bb;
01324
01325 FOR_EACH_BB (bb)
01326 if (BB_HEAD (bb))
01327 break;
01328
01329 label = block_label (bb);
01330 reg = gen_rtx_REG (Pmode, 0);
01331
01332
01333 rtx_jump = gen_indirect_jump (reg);
01334
01335
01336 rtx_store = gen_rtx_SET (VOIDmode, reg, gen_symbol_ref_rtx_for_label (label));
01337
01338
01339 rtx_return = gen_jump (label);
01340
01341
01342 seq_jump_cost = compute_rtx_cost (make_jump_insn_raw (rtx_jump));
01343
01344
01345 seq_call_cost = seq_jump_cost + compute_rtx_cost (make_insn_raw (rtx_store));
01346
01347
01348 seq_return_cost = compute_rtx_cost (make_jump_insn_raw (rtx_return));
01349
01350
01351 seq_call_cost = (int)(seq_call_cost * (double)SEQ_CALL_COST_MULTIPLIER);
01352 }
01353
01354
01355
01356
01357
01358 static void
01359 rtl_seqabstr (void)
01360 {
01361 int iter;
01362
01363
01364 hash_buckets = htab_create (HASH_INIT, htab_hash_bucket , htab_eq_bucket ,
01365 htab_del_bucket);
01366 fill_hash_bucket ();
01367
01368
01369 compute_init_costs ();
01370
01371
01372 collect_pattern_seqs ();
01373 dump_pattern_seqs ();
01374
01375
01376 for (iter = 1;; iter++)
01377 {
01378
01379
01380 recompute_gain ();
01381 if (!pattern_seqs)
01382 break;
01383 dump_best_pattern_seq (iter);
01384
01385
01386 update_pattern_seqs ();
01387
01388 abstract_best_seq ();
01389 }
01390
01391
01392 htab_delete (hash_buckets);
01393
01394 if (iter > 1)
01395 {
01396
01397 count_or_remove_death_notes (NULL, 1);
01398
01399 life_analysis (PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
01400 | PROP_KILL_DEAD_CODE);
01401
01402
01403 cleanup_cfg (CLEANUP_EXPENSIVE |
01404 CLEANUP_UPDATE_LIFE |
01405 (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
01406 }
01407 }
01408
01409
01410
01411 static bool
01412 gate_rtl_seqabstr (void)
01413 {
01414 return flag_rtl_seqabstr;
01415 }
01416
01417
01418
01419 static unsigned int
01420 rest_of_rtl_seqabstr (void)
01421 {
01422 life_analysis (PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE);
01423
01424 cleanup_cfg (CLEANUP_EXPENSIVE |
01425 CLEANUP_UPDATE_LIFE |
01426 (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
01427
01428
01429 rtl_seqabstr ();
01430 return 0;
01431 }
01432
01433 struct tree_opt_pass pass_rtl_seqabstr = {
01434 "seqabstr",
01435 gate_rtl_seqabstr,
01436 rest_of_rtl_seqabstr,
01437 NULL,
01438 NULL,
01439 0,
01440 TV_SEQABSTR,
01441 0,
01442 0,
01443 0,
01444 0,
01445 TODO_dump_func |
01446 TODO_ggc_collect,
01447 'Q'
01448 };