00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023 #include "system.h"
00024 #include "coretypes.h"
00025 #include "tm.h"
00026 #include "toplev.h"
00027
00028 #include "rtl.h"
00029 #include "tree.h"
00030 #include "tm_p.h"
00031 #include "regs.h"
00032 #include "hard-reg-set.h"
00033 #include "flags.h"
00034 #include "real.h"
00035 #include "insn-config.h"
00036 #include "recog.h"
00037 #include "basic-block.h"
00038 #include "output.h"
00039 #include "function.h"
00040 #include "expr.h"
00041 #include "except.h"
00042 #include "intl.h"
00043 #include "obstack.h"
00044 #include "hashtab.h"
00045 #include "params.h"
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 static struct
00081 {
00082 int moves_inserted;
00083 int copies_inserted;
00084 int insns_deleted;
00085 } stats;
00086
00087
00088
00089
00090
00091
00092 static htab_t expr_table;
00093
00094
00095 struct expr
00096 {
00097
00098 rtx expr;
00099
00100
00101 hashval_t hash;
00102
00103
00104 struct occr *avail_occr;
00105 };
00106
00107 static struct obstack expr_obstack;
00108
00109
00110
00111
00112
00113 struct occr
00114 {
00115
00116 struct occr *next;
00117
00118 rtx insn;
00119
00120 char deleted_p;
00121 };
00122
00123 static struct obstack occr_obstack;
00124
00125
00126
00127 struct unoccr
00128 {
00129 struct unoccr *next;
00130 edge pred;
00131 rtx insn;
00132 };
00133
00134 static struct obstack unoccr_obstack;
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 static int *reg_avail_info;
00146
00147
00148 struct modifies_mem
00149 {
00150 rtx insn;
00151 struct modifies_mem *next;
00152 };
00153 static struct modifies_mem *modifies_mem_list;
00154
00155
00156
00157
00158
00159 static struct obstack modifies_mem_obstack;
00160 static struct modifies_mem *modifies_mem_obstack_bottom;
00161
00162
00163
00164
00165 static int *uid_cuid;
00166 #define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)])
00167
00168
00169
00170 static void alloc_mem (void);
00171 static void free_mem (void);
00172
00173
00174 static bool oprs_unchanged_p (rtx, rtx, bool);
00175 static void record_last_reg_set_info (rtx, int);
00176 static void record_last_mem_set_info (rtx);
00177 static void record_last_set_info (rtx, rtx, void *);
00178 static void record_opr_changes (rtx);
00179
00180 static void find_mem_conflicts (rtx, rtx, void *);
00181 static int load_killed_in_block_p (int, rtx, bool);
00182 static void reset_opr_set_tables (void);
00183
00184
00185 static hashval_t hash_expr (rtx, int *);
00186 static hashval_t hash_expr_for_htab (const void *);
00187 static int expr_equiv_p (const void *, const void *);
00188 static void insert_expr_in_table (rtx, rtx);
00189 static struct expr *lookup_expr_in_table (rtx);
00190 static int dump_hash_table_entry (void **, void *);
00191 static void dump_hash_table (FILE *);
00192
00193
00194 static bool reg_killed_on_edge (rtx, edge);
00195 static bool reg_used_on_edge (rtx, edge);
00196
00197 static rtx reg_set_between_after_reload_p (rtx, rtx, rtx);
00198 static rtx reg_used_between_after_reload_p (rtx, rtx, rtx);
00199 static rtx get_avail_load_store_reg (rtx);
00200
00201 static bool bb_has_well_behaved_predecessors (basic_block);
00202 static struct occr* get_bb_avail_insn (basic_block, struct occr *);
00203 static void hash_scan_set (rtx);
00204 static void compute_hash_table (void);
00205
00206
00207 static void eliminate_partially_redundant_load (basic_block,
00208 rtx,
00209 struct expr *);
00210 static void eliminate_partially_redundant_loads (void);
00211
00212
00213
00214
00215
00216 static void
00217 alloc_mem (void)
00218 {
00219 int i;
00220 basic_block bb;
00221 rtx insn;
00222
00223
00224 uid_cuid = xcalloc (get_max_uid () + 1, sizeof (int));
00225 i = 0;
00226 FOR_EACH_BB (bb)
00227 FOR_BB_INSNS (bb, insn)
00228 {
00229 if (INSN_P (insn))
00230 uid_cuid[INSN_UID (insn)] = i++;
00231 else
00232 uid_cuid[INSN_UID (insn)] = i;
00233 }
00234
00235
00236
00237
00238
00239 expr_table = htab_create (MAX (i / 4, 13),
00240 hash_expr_for_htab, expr_equiv_p, NULL);
00241
00242
00243
00244 gcc_obstack_init (&expr_obstack);
00245 gcc_obstack_init (&occr_obstack);
00246 gcc_obstack_init (&unoccr_obstack);
00247 gcc_obstack_init (&modifies_mem_obstack);
00248
00249
00250
00251 reg_avail_info = (int *) xmalloc (FIRST_PSEUDO_REGISTER * sizeof (int));
00252
00253
00254
00255 modifies_mem_obstack_bottom =
00256 (struct modifies_mem *) obstack_alloc (&modifies_mem_obstack,
00257 sizeof (struct modifies_mem));
00258 }
00259
00260
00261
00262 static void
00263 free_mem (void)
00264 {
00265 free (uid_cuid);
00266
00267 htab_delete (expr_table);
00268
00269 obstack_free (&expr_obstack, NULL);
00270 obstack_free (&occr_obstack, NULL);
00271 obstack_free (&unoccr_obstack, NULL);
00272 obstack_free (&modifies_mem_obstack, NULL);
00273
00274 free (reg_avail_info);
00275 }
00276
00277
00278
00279
00280
00281
00282
00283 static hashval_t
00284 hash_expr (rtx x, int *do_not_record_p)
00285 {
00286 *do_not_record_p = 0;
00287 return hash_rtx (x, GET_MODE (x), do_not_record_p,
00288 NULL, false);
00289 }
00290
00291
00292
00293
00294
00295 static hashval_t
00296 hash_expr_for_htab (const void *expp)
00297 {
00298 struct expr *exp = (struct expr *) expp;
00299 return exp->hash;
00300 }
00301
00302
00303
00304
00305 static int
00306 expr_equiv_p (const void *exp1p, const void *exp2p)
00307 {
00308 struct expr *exp1 = (struct expr *) exp1p;
00309 struct expr *exp2 = (struct expr *) exp2p;
00310 int equiv_p = exp_equiv_p (exp1->expr, exp2->expr, 0, true);
00311 if (equiv_p
00312 && exp1->hash != exp2->hash)
00313 abort ();
00314 return equiv_p;
00315 }
00316
00317
00318
00319
00320
00321
00322 static void
00323 insert_expr_in_table (rtx x, rtx insn)
00324 {
00325 int do_not_record_p;
00326 hashval_t hash;
00327 struct expr *cur_expr, **slot;
00328 struct occr *avail_occr, *last_occr = NULL;
00329
00330 hash = hash_expr (x, &do_not_record_p);
00331
00332
00333
00334
00335 if (do_not_record_p)
00336 return;
00337
00338
00339
00340
00341
00342
00343 cur_expr = (struct expr *) obstack_alloc (&expr_obstack,
00344 sizeof (struct expr));
00345 cur_expr->expr = x;
00346 cur_expr->hash = hash;
00347 cur_expr->avail_occr = NULL;
00348
00349 slot = (struct expr **) htab_find_slot_with_hash (expr_table, cur_expr,
00350 hash, INSERT);
00351
00352 if (! (*slot))
00353
00354 *slot = cur_expr;
00355 else
00356 {
00357
00358
00359 obstack_free (&expr_obstack, cur_expr);
00360 cur_expr = *slot;
00361 }
00362
00363
00364 avail_occr = cur_expr->avail_occr;
00365 while (avail_occr && BLOCK_NUM (avail_occr->insn) != BLOCK_NUM (insn))
00366 {
00367
00368
00369 last_occr = avail_occr;
00370 avail_occr = avail_occr->next;
00371 }
00372
00373 if (avail_occr)
00374
00375
00376
00377
00378 avail_occr->insn = insn;
00379 else
00380 {
00381
00382 avail_occr = (struct occr *) obstack_alloc (&occr_obstack,
00383 sizeof (struct occr));
00384
00385
00386 if (cur_expr->avail_occr == NULL)
00387 cur_expr->avail_occr = avail_occr;
00388 else
00389 last_occr->next = avail_occr;
00390
00391 avail_occr->insn = insn;
00392 avail_occr->next = NULL;
00393 avail_occr->deleted_p = 0;
00394 }
00395 }
00396
00397
00398
00399
00400
00401 static struct expr *
00402 lookup_expr_in_table (rtx pat)
00403 {
00404 int do_not_record_p;
00405 struct expr **slot, *tmp_expr;
00406 hashval_t hash = hash_expr (pat, &do_not_record_p);
00407
00408 if (do_not_record_p)
00409 return NULL;
00410
00411 tmp_expr = (struct expr *) obstack_alloc (&expr_obstack,
00412 sizeof (struct expr));
00413 tmp_expr->expr = pat;
00414 tmp_expr->hash = hash;
00415 tmp_expr->avail_occr = NULL;
00416
00417 slot = (struct expr **) htab_find_slot_with_hash (expr_table, tmp_expr,
00418 hash, INSERT);
00419 obstack_free (&expr_obstack, tmp_expr);
00420
00421 if (!slot)
00422 return NULL;
00423 else
00424 return (*slot);
00425 }
00426
00427
00428
00429
00430
00431
00432 static int
00433 dump_hash_table_entry (void **slot, void *filep)
00434 {
00435 struct expr *expr = (struct expr *) *slot;
00436 FILE *file = (FILE *) filep;
00437 struct occr *occr;
00438
00439 fprintf (file, "expr: ");
00440 print_rtl (file, expr->expr);
00441 fprintf (file,"\nhashcode: %u\n", expr->hash);
00442 fprintf (file,"list of occurences:\n");
00443 occr = expr->avail_occr;
00444 while (occr)
00445 {
00446 rtx insn = occr->insn;
00447 print_rtl_single (file, insn);
00448 fprintf (file, "\n");
00449 occr = occr->next;
00450 }
00451 fprintf (file, "\n");
00452 return 1;
00453 }
00454
00455 static void
00456 dump_hash_table (FILE *file)
00457 {
00458 fprintf (file, "\n\nexpression hash table\n");
00459 fprintf (file, "size %ld, %ld elements, %f collision/search ratio\n",
00460 (long) htab_size (expr_table),
00461 (long) htab_elements (expr_table),
00462 htab_collisions (expr_table));
00463 if (htab_elements (expr_table) > 0)
00464 {
00465 fprintf (file, "\n\ntable entries:\n");
00466 htab_traverse (expr_table, dump_hash_table_entry, file);
00467 }
00468 fprintf (file, "\n");
00469 }
00470
00471
00472
00473
00474
00475
00476
00477 static bool
00478 oprs_unchanged_p (rtx x, rtx insn, bool after_insn)
00479 {
00480 int i, j;
00481 enum rtx_code code;
00482 const char *fmt;
00483
00484 if (x == 0)
00485 return 1;
00486
00487 code = GET_CODE (x);
00488 switch (code)
00489 {
00490 case REG:
00491 #ifdef ENABLE_CHECKING
00492
00493 if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
00494 abort ();
00495 #endif
00496 if (after_insn)
00497
00498
00499 return reg_avail_info[REGNO (x)] < INSN_CUID (insn);
00500 else
00501
00502
00503
00504 return reg_avail_info[REGNO (x)] == 0;
00505
00506 case MEM:
00507 if (load_killed_in_block_p (INSN_CUID (insn), x, after_insn))
00508 return 0;
00509 else
00510 return oprs_unchanged_p (XEXP (x, 0), insn, after_insn);
00511
00512 case PC:
00513 case CC0:
00514 case CONST:
00515 case CONST_INT:
00516 case CONST_DOUBLE:
00517 case CONST_VECTOR:
00518 case SYMBOL_REF:
00519 case LABEL_REF:
00520 case ADDR_VEC:
00521 case ADDR_DIFF_VEC:
00522 return 1;
00523
00524 case PRE_DEC:
00525 case PRE_INC:
00526 case POST_DEC:
00527 case POST_INC:
00528 case PRE_MODIFY:
00529 case POST_MODIFY:
00530 if (after_insn)
00531 return 0;
00532 break;
00533
00534 default:
00535 break;
00536 }
00537
00538 for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--)
00539 {
00540 if (fmt[i] == 'e')
00541 {
00542 if (! oprs_unchanged_p (XEXP (x, i), insn, after_insn))
00543 return 0;
00544 }
00545 else if (fmt[i] == 'E')
00546 for (j = 0; j < XVECLEN (x, i); j++)
00547 if (! oprs_unchanged_p (XVECEXP (x, i, j), insn, after_insn))
00548 return 0;
00549 }
00550
00551 return 1;
00552 }
00553
00554
00555
00556
00557
00558
00559 static int mems_conflict_p;
00560
00561
00562
00563
00564
00565 static void
00566 find_mem_conflicts (rtx dest, rtx setter ATTRIBUTE_UNUSED,
00567 void *data)
00568 {
00569 rtx mem_op = (rtx) data;
00570
00571 while (GET_CODE (dest) == SUBREG
00572 || GET_CODE (dest) == ZERO_EXTRACT
00573 || GET_CODE (dest) == STRICT_LOW_PART)
00574 dest = XEXP (dest, 0);
00575
00576
00577
00578
00579 if (! MEM_P (dest))
00580 return;
00581
00582 if (true_dependence (dest, GET_MODE (dest), mem_op,
00583 rtx_addr_varies_p))
00584 mems_conflict_p = 1;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596 static int
00597 load_killed_in_block_p (int uid_limit, rtx x, bool after_insn)
00598 {
00599 struct modifies_mem *list_entry = modifies_mem_list;
00600
00601 while (list_entry)
00602 {
00603 rtx setter = list_entry->insn;
00604
00605
00606 if ((after_insn
00607 && INSN_CUID (setter) < uid_limit)
00608 || (! after_insn
00609 && INSN_CUID (setter) > uid_limit))
00610 {
00611 list_entry = list_entry->next;
00612 continue;
00613 }
00614
00615
00616
00617
00618 if (CALL_P (setter))
00619 return 1;
00620
00621
00622
00623
00624
00625 mems_conflict_p = 0;
00626 note_stores (PATTERN (setter), find_mem_conflicts, x);
00627 if (mems_conflict_p)
00628 return 1;
00629
00630 list_entry = list_entry->next;
00631 }
00632 return 0;
00633 }
00634
00635
00636
00637
00638 static inline void
00639 record_last_reg_set_info (rtx insn, int regno)
00640 {
00641 reg_avail_info[regno] = INSN_CUID (insn);
00642 }
00643
00644
00645
00646
00647
00648
00649 static void
00650 record_last_mem_set_info (rtx insn)
00651 {
00652 struct modifies_mem *list_entry;
00653
00654 list_entry = (struct modifies_mem *) obstack_alloc (&modifies_mem_obstack,
00655 sizeof (struct modifies_mem));
00656 list_entry->insn = insn;
00657 list_entry->next = modifies_mem_list;
00658 modifies_mem_list = list_entry;
00659 }
00660
00661
00662
00663
00664
00665 static void
00666 record_last_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, void *data)
00667 {
00668 rtx last_set_insn = (rtx) data;
00669
00670 if (GET_CODE (dest) == SUBREG)
00671 dest = SUBREG_REG (dest);
00672
00673 if (REG_P (dest))
00674 record_last_reg_set_info (last_set_insn, REGNO (dest));
00675 else if (MEM_P (dest)
00676
00677 && ! push_operand (dest, GET_MODE (dest)))
00678 record_last_mem_set_info (last_set_insn);
00679 }
00680
00681
00682
00683
00684
00685 static void
00686 reset_opr_set_tables (void)
00687 {
00688 memset (reg_avail_info, 0, FIRST_PSEUDO_REGISTER * sizeof (int));
00689 obstack_free (&modifies_mem_obstack, modifies_mem_obstack_bottom);
00690 modifies_mem_list = NULL;
00691 }
00692
00693
00694
00695
00696
00697 static void
00698 record_opr_changes (rtx insn)
00699 {
00700 rtx note;
00701
00702
00703 note_stores (PATTERN (insn), record_last_set_info, insn);
00704
00705
00706 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
00707 if (REG_NOTE_KIND (note) == REG_INC)
00708 record_last_reg_set_info (insn, REGNO (XEXP (note, 0)));
00709
00710
00711 if (CALL_P (insn))
00712 {
00713 unsigned int regno;
00714
00715 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
00716 if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
00717 record_last_reg_set_info (insn, regno);
00718
00719 if (! CONST_OR_PURE_CALL_P (insn))
00720 record_last_mem_set_info (insn);
00721 }
00722 }
00723
00724
00725
00726
00727
00728 static void
00729 hash_scan_set (rtx insn)
00730 {
00731 rtx pat = PATTERN (insn);
00732 rtx src = SET_SRC (pat);
00733 rtx dest = SET_DEST (pat);
00734
00735
00736 if (! MEM_P (src) && ! MEM_P (dest))
00737 return;
00738
00739
00740 if (JUMP_P (insn) || set_noop_p (pat))
00741 return;
00742
00743 #ifdef ENABLE_CHEKCING
00744
00745 if (find_reg_note (insn, REG_EH_REGION, NULL_RTX))
00746 abort ();
00747 #endif
00748
00749 if (REG_P (dest))
00750 {
00751 if (
00752 can_copy_p (GET_MODE (dest))
00753
00754 && general_operand (src, GET_MODE (src))
00755
00756
00757 && oprs_unchanged_p (src, insn, true))
00758 {
00759 insert_expr_in_table (src, insn);
00760 }
00761 }
00762 else if (REG_P (src))
00763 {
00764
00765 if (
00766 can_copy_p (GET_MODE (src))
00767
00768 && general_operand (dest, GET_MODE (dest))
00769 && ! (flag_float_store && FLOAT_MODE_P (GET_MODE (dest)))
00770
00771 && ! load_killed_in_block_p (INSN_CUID (insn) + 1, dest, true)
00772 && oprs_unchanged_p (XEXP (dest, 0), insn, true))
00773 {
00774 insert_expr_in_table (dest, insn);
00775 }
00776 }
00777 }
00778
00779
00780
00781
00782
00783
00784
00785
00786 static void
00787 compute_hash_table (void)
00788 {
00789 basic_block bb;
00790
00791 FOR_EACH_BB (bb)
00792 {
00793 rtx insn;
00794
00795
00796
00797
00798
00799
00800 reset_opr_set_tables ();
00801 FOR_BB_INSNS (bb, insn)
00802 {
00803 if (INSN_P (insn))
00804 record_opr_changes (insn);
00805 }
00806
00807
00808 FOR_BB_INSNS (bb, insn)
00809 if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SET)
00810 hash_scan_set (insn);
00811 }
00812 }
00813
00814
00815
00816
00817
00818
00819 static bool
00820 reg_killed_on_edge (rtx reg, edge e)
00821 {
00822 rtx insn;
00823
00824 for (insn = e->insns.r; insn; insn = NEXT_INSN (insn))
00825 if (INSN_P (insn) && reg_set_p (reg, insn))
00826 return true;
00827
00828 return false;
00829 }
00830
00831
00832
00833
00834
00835
00836 static bool
00837 reg_used_on_edge (rtx reg, edge e)
00838 {
00839 rtx insn;
00840
00841 for (insn = e->insns.r; insn; insn = NEXT_INSN (insn))
00842 if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
00843 return true;
00844
00845 return false;
00846 }
00847
00848
00849
00850
00851
00852
00853 static rtx
00854 reg_set_between_after_reload_p (rtx reg, rtx from_insn, rtx to_insn)
00855 {
00856 rtx insn;
00857
00858 #ifdef ENABLE_CHECKING
00859
00860 if (!REG_P (reg) || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
00861 abort ();
00862 #endif
00863
00864 if (from_insn == to_insn)
00865 return NULL_RTX;
00866
00867 for (insn = NEXT_INSN (from_insn);
00868 insn != to_insn;
00869 insn = NEXT_INSN (insn))
00870 if (INSN_P (insn))
00871 {
00872 if (set_of (reg, insn) != NULL_RTX)
00873 return insn;
00874 if ((CALL_P (insn)
00875 && call_used_regs[REGNO (reg)])
00876 || find_reg_fusage (insn, CLOBBER, reg))
00877 return insn;
00878
00879 if (FIND_REG_INC_NOTE (insn, reg))
00880 return insn;
00881 }
00882
00883 return NULL_RTX;
00884 }
00885
00886
00887
00888
00889
00890 static rtx
00891 reg_used_between_after_reload_p (rtx reg, rtx from_insn, rtx to_insn)
00892 {
00893 rtx insn;
00894
00895 #ifdef ENABLE_CHECKING
00896
00897 if (!REG_P (reg) || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
00898 abort ();
00899 #endif
00900
00901 if (from_insn == to_insn)
00902 return NULL_RTX;
00903
00904 for (insn = NEXT_INSN (from_insn);
00905 insn != to_insn;
00906 insn = NEXT_INSN (insn))
00907 if (INSN_P (insn))
00908 {
00909 if (reg_overlap_mentioned_p (reg, PATTERN (insn))
00910 || (CALL_P (insn)
00911 && call_used_regs[REGNO (reg)])
00912 || find_reg_fusage (insn, USE, reg)
00913 || find_reg_fusage (insn, CLOBBER, reg))
00914 return insn;
00915
00916 if (FIND_REG_INC_NOTE (insn, reg))
00917 return insn;
00918 }
00919
00920 return NULL_RTX;
00921 }
00922
00923
00924
00925
00926 static bool
00927 reg_set_or_used_since_bb_start (rtx reg, basic_block bb, rtx up_to_insn)
00928 {
00929 rtx insn, start = PREV_INSN (BB_HEAD (bb));
00930
00931 if (reg_avail_info[REGNO (reg)] != 0)
00932 return true;
00933
00934 insn = reg_used_between_after_reload_p (reg, start, up_to_insn);
00935 if (! insn)
00936 insn = reg_set_between_after_reload_p (reg, start, up_to_insn);
00937
00938 if (insn)
00939 reg_avail_info[REGNO (reg)] = INSN_CUID (insn);
00940
00941 return insn != NULL_RTX;
00942 }
00943
00944
00945
00946 static rtx
00947 get_avail_load_store_reg (rtx insn)
00948 {
00949 if (REG_P (SET_DEST (PATTERN (insn))))
00950 return SET_DEST(PATTERN(insn));
00951 if (REG_P (SET_SRC (PATTERN (insn))))
00952 return SET_SRC (PATTERN (insn));
00953 abort ();
00954 }
00955
00956
00957
00958 static bool
00959 bb_has_well_behaved_predecessors (basic_block bb)
00960 {
00961 edge pred;
00962 edge_iterator ei;
00963
00964 if (EDGE_COUNT (bb->preds) == 0)
00965 return false;
00966
00967 FOR_EACH_EDGE (pred, ei, bb->preds)
00968 {
00969 if ((pred->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (pred))
00970 return false;
00971
00972 if (JUMP_TABLE_DATA_P (BB_END (pred->src)))
00973 return false;
00974 }
00975 return true;
00976 }
00977
00978
00979
00980
00981 static struct occr*
00982 get_bb_avail_insn (basic_block bb, struct occr *occr)
00983 {
00984 for (; occr != NULL; occr = occr->next)
00985 if (BLOCK_FOR_INSN (occr->insn) == bb)
00986 return occr;
00987 return NULL;
00988 }
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004 static void
01005 eliminate_partially_redundant_load (basic_block bb, rtx insn,
01006 struct expr *expr)
01007 {
01008 edge pred;
01009 rtx avail_insn = NULL_RTX;
01010 rtx avail_reg;
01011 rtx dest, pat;
01012 struct occr *a_occr;
01013 struct unoccr *occr, *avail_occrs = NULL;
01014 struct unoccr *unoccr, *unavail_occrs = NULL, *rollback_unoccr = NULL;
01015 int npred_ok = 0;
01016 gcov_type ok_count = 0;
01017 gcov_type critical_count = 0;
01018 edge_iterator ei;
01019
01020
01021
01022 gcov_type not_ok_count = 0;
01023 basic_block pred_bb;
01024
01025 pat = PATTERN (insn);
01026 dest = SET_DEST (pat);
01027
01028
01029
01030 if (reg_set_or_used_since_bb_start (dest, bb, insn))
01031 return;
01032
01033
01034 FOR_EACH_EDGE (pred, ei, bb->preds)
01035 {
01036 rtx next_pred_bb_end;
01037
01038 avail_insn = NULL_RTX;
01039 pred_bb = pred->src;
01040 next_pred_bb_end = NEXT_INSN (BB_END (pred_bb));
01041 for (a_occr = get_bb_avail_insn (pred_bb, expr->avail_occr); a_occr;
01042 a_occr = get_bb_avail_insn (pred_bb, a_occr->next))
01043 {
01044
01045 avail_insn = a_occr->insn;
01046 if (! (avail_reg = get_avail_load_store_reg (avail_insn)))
01047 abort ();
01048
01049
01050 extract_insn (gen_move_insn (copy_rtx (dest),
01051 copy_rtx (avail_reg)));
01052 if (! constrain_operands (1)
01053 || reg_killed_on_edge (avail_reg, pred)
01054 || reg_used_on_edge (dest, pred))
01055 {
01056 avail_insn = NULL;
01057 continue;
01058 }
01059 if (! reg_set_between_after_reload_p (avail_reg, avail_insn,
01060 next_pred_bb_end))
01061
01062 break;
01063 else
01064 avail_insn = NULL;
01065 }
01066
01067 if (EDGE_CRITICAL_P (pred))
01068 critical_count += pred->count;
01069
01070 if (avail_insn != NULL_RTX)
01071 {
01072 npred_ok++;
01073 ok_count += pred->count;
01074 occr = (struct unoccr *) obstack_alloc (&unoccr_obstack,
01075 sizeof (struct occr));
01076 occr->insn = avail_insn;
01077 occr->pred = pred;
01078 occr->next = avail_occrs;
01079 avail_occrs = occr;
01080 if (! rollback_unoccr)
01081 rollback_unoccr = occr;
01082 }
01083 else
01084 {
01085 not_ok_count += pred->count;
01086 unoccr = (struct unoccr *) obstack_alloc (&unoccr_obstack,
01087 sizeof (struct unoccr));
01088 unoccr->insn = NULL_RTX;
01089 unoccr->pred = pred;
01090 unoccr->next = unavail_occrs;
01091 unavail_occrs = unoccr;
01092 if (! rollback_unoccr)
01093 rollback_unoccr = unoccr;
01094 }
01095 }
01096
01097 if (
01098 npred_ok == 0
01099
01100 || (optimize_size && npred_ok > 1))
01101 goto cleanup;
01102
01103
01104 if (ok_count < GCSE_AFTER_RELOAD_PARTIAL_FRACTION * not_ok_count)
01105 goto cleanup;
01106 if (ok_count < GCSE_AFTER_RELOAD_CRITICAL_FRACTION * critical_count)
01107 goto cleanup;
01108
01109
01110
01111 for (occr = avail_occrs; occr; occr = occr->next)
01112 {
01113 avail_insn = occr->insn;
01114 pred = occr->pred;
01115
01116
01117 avail_reg = get_avail_load_store_reg (avail_insn);
01118 if (! avail_reg)
01119 abort ();
01120
01121 insert_insn_on_edge (gen_move_insn (copy_rtx (dest),
01122 copy_rtx (avail_reg)),
01123 pred);
01124 stats.moves_inserted++;
01125
01126 if (dump_file)
01127 fprintf (dump_file,
01128 "generating move from %d to %d on edge from %d to %d\n",
01129 REGNO (avail_reg),
01130 REGNO (dest),
01131 pred->src->index,
01132 pred->dest->index);
01133 }
01134
01135
01136 for (unoccr = unavail_occrs; unoccr; unoccr = unoccr->next)
01137 {
01138 pred = unoccr->pred;
01139 insert_insn_on_edge (copy_insn (PATTERN (insn)), pred);
01140 stats.copies_inserted++;
01141
01142 if (dump_file)
01143 {
01144 fprintf (dump_file,
01145 "generating on edge from %d to %d a copy of load: ",
01146 pred->src->index,
01147 pred->dest->index);
01148 print_rtl (dump_file, PATTERN (insn));
01149 fprintf (dump_file, "\n");
01150 }
01151 }
01152
01153
01154
01155
01156 for (a_occr = get_bb_avail_insn (bb, expr->avail_occr);
01157 a_occr && (a_occr->insn != insn);
01158 a_occr = get_bb_avail_insn (bb, a_occr->next));
01159
01160 if (!a_occr)
01161 delete_insn (insn);
01162 else
01163 a_occr->deleted_p = 1;
01164
01165 cleanup:
01166 if (rollback_unoccr)
01167 obstack_free (&unoccr_obstack, rollback_unoccr);
01168 }
01169
01170
01171
01172 static void
01173 eliminate_partially_redundant_loads (void)
01174 {
01175 rtx insn;
01176 basic_block bb;
01177
01178
01179
01180 if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR)
01181 return;
01182
01183 FOR_BB_BETWEEN (bb,
01184 ENTRY_BLOCK_PTR->next_bb->next_bb,
01185 EXIT_BLOCK_PTR,
01186 next_bb)
01187 {
01188
01189 if (! bb_has_well_behaved_predecessors (bb))
01190 continue;
01191
01192
01193 if (probably_cold_bb_p (bb))
01194 continue;
01195
01196
01197
01198 reset_opr_set_tables ();
01199
01200
01201
01202 FOR_BB_INSNS (bb, insn)
01203 {
01204
01205 if (NONJUMP_INSN_P (insn)
01206 && GET_CODE (PATTERN (insn)) == SET
01207 && REG_P (SET_DEST (PATTERN (insn)))
01208 && MEM_P (SET_SRC (PATTERN (insn))))
01209 {
01210 rtx pat = PATTERN (insn);
01211 rtx src = SET_SRC (pat);
01212 struct expr *expr;
01213
01214 if (!MEM_VOLATILE_P (src)
01215 && GET_MODE (src) != BLKmode
01216 && general_operand (src, GET_MODE (src))
01217
01218
01219 && oprs_unchanged_p (src, insn, false)
01220 && !(flag_non_call_exceptions && may_trap_p (src))
01221 && !side_effects_p (src)
01222
01223 && (expr = lookup_expr_in_table (src)) != NULL)
01224 {
01225
01226
01227
01228 eliminate_partially_redundant_load (bb, insn, expr);
01229 }
01230 }
01231
01232
01233
01234
01235 if (INSN_P (insn))
01236 record_opr_changes (insn);
01237 }
01238 }
01239
01240 commit_edge_insertions ();
01241 }
01242
01243
01244
01245
01246
01247 static int
01248 delete_redundant_insns_1 (void **slot, void *data ATTRIBUTE_UNUSED)
01249 {
01250 struct expr *expr = (struct expr *) *slot;
01251 struct occr *occr;
01252
01253 for (occr = expr->avail_occr; occr != NULL; occr = occr->next)
01254 {
01255 if (occr->deleted_p)
01256 {
01257 delete_insn (occr->insn);
01258 stats.insns_deleted++;
01259
01260 if (dump_file)
01261 {
01262 fprintf (dump_file, "deleting insn:\n");
01263 print_rtl_single (dump_file, occr->insn);
01264 fprintf (dump_file, "\n");
01265 }
01266 }
01267 }
01268
01269 return 1;
01270 }
01271
01272 static void
01273 delete_redundant_insns (void)
01274 {
01275 htab_traverse (expr_table, delete_redundant_insns_1, NULL);
01276 if (dump_file)
01277 fprintf (dump_file, "\n");
01278 }
01279
01280
01281
01282
01283 void
01284 gcse_after_reload_main (rtx f ATTRIBUTE_UNUSED)
01285 {
01286 memset (&stats, 0, sizeof (stats));
01287
01288
01289
01290 alloc_mem ();
01291
01292
01293 init_alias_analysis ();
01294
01295 compute_hash_table ();
01296
01297 if (dump_file)
01298 dump_hash_table (dump_file);
01299
01300 if (htab_elements (expr_table) > 0)
01301 {
01302 eliminate_partially_redundant_loads ();
01303 delete_redundant_insns ();
01304
01305 if (dump_file)
01306 {
01307 fprintf (dump_file, "GCSE AFTER RELOAD stats:\n");
01308 fprintf (dump_file, "copies inserted: %d\n", stats.copies_inserted);
01309 fprintf (dump_file, "moves inserted: %d\n", stats.moves_inserted);
01310 fprintf (dump_file, "insns deleted: %d\n", stats.insns_deleted);
01311 fprintf (dump_file, "\n\n");
01312 }
01313 }
01314
01315
01316 end_alias_analysis ();
01317
01318 free_mem ();
01319 }
01320