00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "config.h"
00039 #include "system.h"
00040 #include "coretypes.h"
00041 #include "tm.h"
00042 #include "rtl.h"
00043 #include "hard-reg-set.h"
00044 #include "obstack.h"
00045 #include "basic-block.h"
00046 #include "cfgloop.h"
00047 #include "expr.h"
00048 #include "output.h"
00049 #include "function.h"
00050 #include "flags.h"
00051 #include "df.h"
00052
00053
00054
00055 struct loop_data
00056 {
00057 struct loop *outermost_exit;
00058 bool has_call;
00059 };
00060
00061 #define LOOP_DATA(LOOP) ((struct loop_data *) (LOOP)->aux)
00062
00063
00064
00065 struct use
00066 {
00067 rtx *pos;
00068 rtx insn;
00069
00070 struct use *next;
00071 };
00072
00073
00074
00075 struct def
00076 {
00077 struct use *uses;
00078
00079 unsigned n_uses;
00080 unsigned invno;
00081 };
00082
00083
00084
00085 struct invariant
00086 {
00087
00088 unsigned invno;
00089
00090
00091 bool processed;
00092
00093
00094 struct def *def;
00095
00096
00097 rtx insn;
00098
00099
00100 bool always_executed;
00101
00102
00103 bool move;
00104
00105
00106 unsigned cost;
00107
00108
00109 bitmap depends_on;
00110
00111
00112
00113 unsigned stamp;
00114 };
00115
00116
00117
00118
00119 static unsigned actual_stamp;
00120
00121
00122
00123 static varray_type invariants;
00124
00125
00126
00127 static bool
00128 check_maybe_invariant (rtx x)
00129 {
00130 enum rtx_code code = GET_CODE (x);
00131 int i, j;
00132 const char *fmt;
00133
00134 switch (code)
00135 {
00136 case CONST_INT:
00137 case CONST_DOUBLE:
00138 case SYMBOL_REF:
00139 case CONST:
00140 case LABEL_REF:
00141 return true;
00142
00143 case PC:
00144 case CC0:
00145 case UNSPEC_VOLATILE:
00146 case CALL:
00147 return false;
00148
00149 case REG:
00150 return true;
00151
00152 case MEM:
00153
00154
00155
00156
00157
00158 if (MEM_READONLY_P (x))
00159 break;
00160
00161 return false;
00162
00163 case ASM_OPERANDS:
00164
00165 if (MEM_VOLATILE_P (x))
00166 return false;
00167 break;
00168
00169 default:
00170 break;
00171 }
00172
00173 fmt = GET_RTX_FORMAT (code);
00174 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
00175 {
00176 if (fmt[i] == 'e')
00177 {
00178 if (!check_maybe_invariant (XEXP (x, i)))
00179 return false;
00180 }
00181 else if (fmt[i] == 'E')
00182 {
00183 for (j = 0; j < XVECLEN (x, i); j++)
00184 if (!check_maybe_invariant (XVECEXP (x, i, j)))
00185 return false;
00186 }
00187 }
00188
00189 return true;
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 static void
00199 compute_always_reached (struct loop *loop, basic_block *body,
00200 bitmap may_exit, bitmap always_reached)
00201 {
00202 unsigned i;
00203
00204 for (i = 0; i < loop->num_nodes; i++)
00205 {
00206 if (dominated_by_p (CDI_DOMINATORS, loop->latch, body[i]))
00207 bitmap_set_bit (always_reached, i);
00208
00209 if (bitmap_bit_p (may_exit, i))
00210 return;
00211 }
00212 }
00213
00214
00215
00216
00217
00218 static void
00219 find_exits (struct loop *loop, basic_block *body,
00220 bitmap may_exit, bitmap has_exit)
00221 {
00222 unsigned i;
00223 edge_iterator ei;
00224 edge e;
00225 struct loop *outermost_exit = loop, *aexit;
00226 bool has_call = false;
00227 rtx insn;
00228
00229 for (i = 0; i < loop->num_nodes; i++)
00230 {
00231 if (body[i]->loop_father == loop)
00232 {
00233 FOR_BB_INSNS (body[i], insn)
00234 {
00235 if (CALL_P (insn)
00236 && !CONST_OR_PURE_CALL_P (insn))
00237 {
00238 has_call = true;
00239 bitmap_set_bit (may_exit, i);
00240 break;
00241 }
00242 }
00243
00244 FOR_EACH_EDGE (e, ei, body[i]->succs)
00245 {
00246 if (flow_bb_inside_loop_p (loop, e->dest))
00247 continue;
00248
00249 bitmap_set_bit (may_exit, i);
00250 bitmap_set_bit (has_exit, i);
00251 outermost_exit = find_common_loop (outermost_exit,
00252 e->dest->loop_father);
00253 }
00254 continue;
00255 }
00256
00257
00258
00259
00260 if (body[i]->loop_father->header != body[i])
00261 continue;
00262
00263 if (LOOP_DATA (body[i]->loop_father)->has_call)
00264 {
00265 has_call = true;
00266 bitmap_set_bit (may_exit, i);
00267 }
00268 aexit = LOOP_DATA (body[i]->loop_father)->outermost_exit;
00269 if (aexit != loop)
00270 {
00271 bitmap_set_bit (may_exit, i);
00272 bitmap_set_bit (has_exit, i);
00273
00274 if (flow_loop_nested_p (aexit, outermost_exit))
00275 outermost_exit = aexit;
00276 }
00277 }
00278
00279 loop->aux = xcalloc (1, sizeof (struct loop_data));
00280 LOOP_DATA (loop)->outermost_exit = outermost_exit;
00281 LOOP_DATA (loop)->has_call = has_call;
00282 }
00283
00284
00285
00286 static bool
00287 may_assign_reg_p (rtx x)
00288 {
00289 return can_copy_p (GET_MODE (x));
00290 }
00291
00292
00293
00294
00295 static void
00296 find_defs (struct loop *loop, basic_block *body, struct df *df)
00297 {
00298 unsigned i;
00299 bitmap blocks = BITMAP_ALLOC (NULL);
00300
00301 for (i = 0; i < loop->num_nodes; i++)
00302 bitmap_set_bit (blocks, body[i]->index);
00303
00304 df_analyze_subcfg (df, blocks, DF_UD_CHAIN | DF_HARD_REGS | DF_EQUIV_NOTES);
00305 BITMAP_FREE (blocks);
00306 }
00307
00308
00309
00310
00311
00312 static void
00313 create_new_invariant (struct def *def, rtx insn, bitmap depends_on,
00314 bool always_executed)
00315 {
00316 struct invariant *inv = xmalloc (sizeof (struct invariant));
00317 rtx set = single_set (insn);
00318
00319 inv->def = def;
00320 inv->always_executed = always_executed;
00321 inv->depends_on = depends_on;
00322
00323
00324
00325 if (def)
00326 inv->cost = rtx_cost (set, SET);
00327 else
00328 inv->cost = rtx_cost (SET_SRC (set), SET);
00329
00330 inv->move = false;
00331 inv->processed = false;
00332 inv->stamp = 0;
00333 inv->insn = insn;
00334
00335 inv->invno = VARRAY_ACTIVE_SIZE (invariants);
00336 if (def)
00337 def->invno = inv->invno;
00338 VARRAY_PUSH_GENERIC_PTR_NOGC (invariants, inv);
00339
00340 if (dump_file)
00341 {
00342 fprintf (dump_file,
00343 "Set in insn %d is invariant (%d), cost %d, depends on ",
00344 INSN_UID (insn), inv->invno, inv->cost);
00345 dump_bitmap (dump_file, inv->depends_on);
00346 }
00347 }
00348
00349
00350
00351 static void
00352 record_use (struct def *def, rtx *use, rtx insn)
00353 {
00354 struct use *u = xmalloc (sizeof (struct use));
00355
00356 if (GET_CODE (*use) == SUBREG)
00357 use = &SUBREG_REG (*use);
00358 if (!REG_P (*use))
00359 abort ();
00360
00361 u->pos = use;
00362 u->insn = insn;
00363 u->next = def->uses;
00364 def->uses = u;
00365 def->n_uses++;
00366 }
00367
00368
00369
00370
00371 static bool
00372 check_dependencies (rtx insn, struct df *df, bitmap depends_on)
00373 {
00374 struct df_link *uses, *defs;
00375 struct ref *use, *def;
00376 basic_block bb = BLOCK_FOR_INSN (insn), def_bb;
00377 struct def *def_data;
00378
00379 for (uses = DF_INSN_USES (df, insn); uses; uses = uses->next)
00380 {
00381 use = uses->ref;
00382
00383 defs = DF_REF_CHAIN (use);
00384 if (!defs)
00385 continue;
00386
00387 if (defs->next)
00388 return false;
00389
00390 def = defs->ref;
00391 def_data = DF_REF_DATA (def);
00392 if (!def_data)
00393 return false;
00394
00395 def_bb = DF_REF_BB (def);
00396 if (!dominated_by_p (CDI_DOMINATORS, bb, def_bb))
00397 return false;
00398
00399 bitmap_set_bit (depends_on, def_data->invno);
00400 }
00401
00402 return true;
00403 }
00404
00405
00406
00407
00408
00409
00410 static void
00411 find_invariant_insn (rtx insn, bool always_reached, bool always_executed,
00412 struct df *df)
00413 {
00414 struct ref *ref;
00415 struct def *def;
00416 bitmap depends_on;
00417 rtx set, dest;
00418 bool simple = true;
00419
00420
00421 if (find_reg_note (insn, REG_RETVAL, NULL_RTX)
00422 || find_reg_note (insn, REG_LIBCALL, NULL_RTX)
00423 || find_reg_note (insn, REG_NO_CONFLICT, NULL_RTX))
00424 return;
00425
00426 set = single_set (insn);
00427 if (!set)
00428 return;
00429 dest = SET_DEST (set);
00430
00431 if (GET_CODE (dest) != REG
00432 || HARD_REGISTER_P (dest))
00433 simple = false;
00434
00435 if (!check_maybe_invariant (SET_SRC (set))
00436 || !may_assign_reg_p (SET_DEST (set)))
00437 return;
00438
00439 if (may_trap_p (PATTERN (insn)))
00440 {
00441 if (!always_reached)
00442 return;
00443
00444
00445
00446 if (flag_non_call_exceptions)
00447 return;
00448 }
00449
00450 depends_on = BITMAP_ALLOC (NULL);
00451 if (!check_dependencies (insn, df, depends_on))
00452 {
00453 BITMAP_FREE (depends_on);
00454 return;
00455 }
00456
00457 if (simple)
00458 {
00459 ref = df_find_def (df, insn, dest);
00460 def = xcalloc (1, sizeof (struct def));
00461 DF_REF_DATA (ref) = def;
00462 }
00463 else
00464 def = NULL;
00465
00466 create_new_invariant (def, insn, depends_on, always_executed);
00467 }
00468
00469
00470
00471
00472 static void
00473 record_uses (rtx insn, struct df *df)
00474 {
00475 struct df_link *uses, *defs;
00476 struct ref *use, *def;
00477 basic_block bb = BLOCK_FOR_INSN (insn), def_bb;
00478
00479 for (uses = DF_INSN_USES (df, insn); uses; uses = uses->next)
00480 {
00481 use = uses->ref;
00482
00483 defs = DF_REF_CHAIN (use);
00484 if (!defs || defs->next)
00485 continue;
00486 def = defs->ref;
00487 if (!DF_REF_DATA (def))
00488 continue;
00489
00490 def_bb = DF_REF_BB (def);
00491 if (!dominated_by_p (CDI_DOMINATORS, bb, def_bb))
00492 continue;
00493
00494 record_use (DF_REF_DATA (def), DF_REF_LOC (use), DF_REF_INSN (use));
00495 }
00496 }
00497
00498
00499
00500
00501
00502
00503 static void
00504 find_invariants_insn (rtx insn, bool always_reached, bool always_executed,
00505 struct df *df)
00506 {
00507 find_invariant_insn (insn, always_reached, always_executed, df);
00508 record_uses (insn, df);
00509 }
00510
00511
00512
00513
00514
00515
00516 static void
00517 find_invariants_bb (basic_block bb, bool always_reached, bool always_executed,
00518 struct df *df)
00519 {
00520 rtx insn;
00521
00522 FOR_BB_INSNS (bb, insn)
00523 {
00524 if (!INSN_P (insn))
00525 continue;
00526
00527 find_invariants_insn (insn, always_reached, always_executed, df);
00528
00529 if (always_reached
00530 && CALL_P (insn)
00531 && !CONST_OR_PURE_CALL_P (insn))
00532 always_reached = false;
00533 }
00534 }
00535
00536
00537
00538
00539
00540
00541 static void
00542 find_invariants_body (struct loop *loop, basic_block *body,
00543 bitmap always_reached, bitmap always_executed,
00544 struct df *df)
00545 {
00546 unsigned i;
00547
00548 for (i = 0; i < loop->num_nodes; i++)
00549 find_invariants_bb (body[i],
00550 bitmap_bit_p (always_reached, i),
00551 bitmap_bit_p (always_executed, i),
00552 df);
00553 }
00554
00555
00556
00557 static void
00558 find_invariants (struct loop *loop, struct df *df)
00559 {
00560 bitmap may_exit = BITMAP_ALLOC (NULL);
00561 bitmap always_reached = BITMAP_ALLOC (NULL);
00562 bitmap has_exit = BITMAP_ALLOC (NULL);
00563 bitmap always_executed = BITMAP_ALLOC (NULL);
00564 basic_block *body = get_loop_body_in_dom_order (loop);
00565
00566 find_exits (loop, body, may_exit, has_exit);
00567 compute_always_reached (loop, body, may_exit, always_reached);
00568 compute_always_reached (loop, body, has_exit, always_executed);
00569
00570 find_defs (loop, body, df);
00571 find_invariants_body (loop, body, always_reached, always_executed, df);
00572
00573 BITMAP_FREE (always_reached);
00574 BITMAP_FREE (always_executed);
00575 BITMAP_FREE (may_exit);
00576 BITMAP_FREE (has_exit);
00577 free (body);
00578 }
00579
00580
00581
00582 static void
00583 free_use_list (struct use *use)
00584 {
00585 struct use *next;
00586
00587 for (; use; use = next)
00588 {
00589 next = use->next;
00590 free (use);
00591 }
00592 }
00593
00594
00595
00596
00597 static void
00598 get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
00599 {
00600 int acomp_cost;
00601 unsigned aregs_needed;
00602 unsigned depno;
00603 struct invariant *dep;
00604 bitmap_iterator bi;
00605
00606 *comp_cost = 0;
00607 *regs_needed = 0;
00608 if (inv->move
00609 || inv->stamp == actual_stamp)
00610 return;
00611 inv->stamp = actual_stamp;
00612
00613 (*regs_needed)++;
00614 (*comp_cost) += inv->cost;
00615
00616 EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, depno, bi)
00617 {
00618 dep = VARRAY_GENERIC_PTR_NOGC (invariants, depno);
00619
00620 get_inv_cost (dep, &acomp_cost, &aregs_needed);
00621
00622 if (aregs_needed
00623
00624
00625
00626
00627 && dep->always_executed
00628 && !dep->def->uses->next)
00629 {
00630
00631
00632 aregs_needed--;
00633 }
00634
00635 (*regs_needed) += aregs_needed;
00636 (*comp_cost) += acomp_cost;
00637 }
00638 }
00639
00640
00641
00642
00643
00644
00645
00646 static int
00647 gain_for_invariant (struct invariant *inv, unsigned *regs_needed,
00648 unsigned new_regs, unsigned regs_used, unsigned n_inv_uses)
00649 {
00650 int comp_cost, size_cost;
00651
00652 get_inv_cost (inv, &comp_cost, regs_needed);
00653 actual_stamp++;
00654
00655 size_cost = (global_cost_for_size (new_regs + *regs_needed,
00656 regs_used, n_inv_uses)
00657 - global_cost_for_size (new_regs, regs_used, n_inv_uses));
00658
00659 return comp_cost - size_cost;
00660 }
00661
00662
00663
00664
00665
00666
00667
00668 static int
00669 best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
00670 unsigned new_regs, unsigned regs_used,
00671 unsigned n_inv_uses)
00672 {
00673 struct invariant *inv;
00674 int gain = 0, again;
00675 unsigned aregs_needed, invno;
00676
00677 for (invno = 0; invno < VARRAY_ACTIVE_SIZE (invariants); invno++)
00678 {
00679 inv = VARRAY_GENERIC_PTR_NOGC (invariants, invno);
00680 if (inv->move)
00681 continue;
00682
00683 again = gain_for_invariant (inv, &aregs_needed,
00684 new_regs, regs_used, n_inv_uses);
00685 if (again > gain)
00686 {
00687 gain = again;
00688 *best = inv;
00689 *regs_needed = aregs_needed;
00690 }
00691 }
00692
00693 return gain;
00694 }
00695
00696
00697
00698 static void
00699 set_move_mark (unsigned invno)
00700 {
00701 struct invariant *inv = VARRAY_GENERIC_PTR_NOGC (invariants, invno);
00702 bitmap_iterator bi;
00703
00704 if (inv->move)
00705 return;
00706 inv->move = true;
00707
00708 if (dump_file)
00709 fprintf (dump_file, "Decided to move invariant %d\n", invno);
00710
00711 EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, invno, bi)
00712 {
00713 set_move_mark (invno);
00714 }
00715 }
00716
00717
00718
00719 static void
00720 find_invariants_to_move (struct df *df)
00721 {
00722 unsigned i, regs_used, n_inv_uses, regs_needed = 0, new_regs;
00723 struct invariant *inv = NULL;
00724
00725 if (!VARRAY_ACTIVE_SIZE (invariants))
00726 return;
00727
00728
00729
00730 n_inv_uses = 0;
00731
00732
00733
00734 regs_used = 2;
00735
00736 for (i = 0; i < df->n_regs; i++)
00737 {
00738 if (!DF_REGNO_FIRST_DEF (df, i) && DF_REGNO_LAST_USE (df, i))
00739 {
00740
00741 regs_used++;
00742 }
00743 }
00744
00745 for (i = 0; i < VARRAY_ACTIVE_SIZE (invariants); i++)
00746 {
00747 inv = VARRAY_GENERIC_PTR_NOGC (invariants, i);
00748 if (inv->def)
00749 n_inv_uses += inv->def->n_uses;
00750 }
00751
00752 new_regs = 0;
00753 while (best_gain_for_invariant (&inv, ®s_needed,
00754 new_regs, regs_used, n_inv_uses) > 0)
00755 {
00756 set_move_mark (inv->invno);
00757 new_regs += regs_needed;
00758 }
00759 }
00760
00761
00762
00763 static void
00764 move_invariant_reg (struct loop *loop, unsigned invno, struct df *df)
00765 {
00766 struct invariant *inv = VARRAY_GENERIC_PTR_NOGC (invariants, invno);
00767 unsigned i;
00768 basic_block preheader = loop_preheader_edge (loop)->src;
00769 rtx reg, set;
00770 struct use *use;
00771 bitmap_iterator bi;
00772
00773 if (inv->processed)
00774 return;
00775 inv->processed = true;
00776
00777 if (inv->depends_on)
00778 {
00779 EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, i, bi)
00780 {
00781 move_invariant_reg (loop, i, df);
00782 }
00783 }
00784
00785
00786
00787
00788
00789
00790 set = single_set (inv->insn);
00791 reg = gen_reg_rtx (GET_MODE (SET_DEST (set)));
00792 df_pattern_emit_after (df, gen_move_insn (SET_DEST (set), reg),
00793 BLOCK_FOR_INSN (inv->insn), inv->insn);
00794 SET_DEST (set) = reg;
00795 reorder_insns (inv->insn, inv->insn, BB_END (preheader));
00796 df_insn_modify (df, preheader, inv->insn);
00797
00798
00799
00800
00801 if (inv->def)
00802 {
00803 for (use = inv->def->uses; use; use = use->next)
00804 {
00805 *use->pos = reg;
00806 df_insn_modify (df, BLOCK_FOR_INSN (use->insn), use->insn);
00807 }
00808 }
00809 }
00810
00811
00812
00813
00814 static void
00815 move_invariants (struct loop *loop, struct df *df)
00816 {
00817 struct invariant *inv;
00818 unsigned i;
00819
00820 for (i = 0; i < VARRAY_ACTIVE_SIZE (invariants); i++)
00821 {
00822 inv = VARRAY_GENERIC_PTR_NOGC (invariants, i);
00823 if (inv->move)
00824 move_invariant_reg (loop, i, df);
00825 }
00826 }
00827
00828
00829
00830 static void
00831 init_inv_motion_data (void)
00832 {
00833 actual_stamp = 1;
00834
00835 if (!invariants)
00836 VARRAY_GENERIC_PTR_NOGC_INIT (invariants, 100, "invariants");
00837 }
00838
00839
00840
00841
00842 static void
00843 free_inv_motion_data (struct df *df)
00844 {
00845 unsigned i;
00846 struct def *def;
00847 struct invariant *inv;
00848
00849 for (i = 0; i < df->n_defs; i++)
00850 {
00851 if (!df->defs[i])
00852 continue;
00853
00854 def = DF_REF_DATA (df->defs[i]);
00855 if (!def)
00856 continue;
00857
00858 free_use_list (def->uses);
00859 free (def);
00860 DF_REF_DATA (df->defs[i]) = NULL;
00861 }
00862
00863 for (i = 0; i < VARRAY_ACTIVE_SIZE (invariants); i++)
00864 {
00865 inv = VARRAY_GENERIC_PTR_NOGC (invariants, i);
00866 BITMAP_FREE (inv->depends_on);
00867 free (inv);
00868 }
00869 VARRAY_POP_ALL (invariants);
00870 }
00871
00872
00873
00874 static void
00875 move_single_loop_invariants (struct loop *loop, struct df *df)
00876 {
00877 init_inv_motion_data ();
00878
00879 find_invariants (loop, df);
00880 find_invariants_to_move (df);
00881 move_invariants (loop, df);
00882
00883 free_inv_motion_data (df);
00884 }
00885
00886
00887
00888 static void
00889 free_loop_data (struct loop *loop)
00890 {
00891 struct loop_data *data = LOOP_DATA (loop);
00892
00893 free (data);
00894 loop->aux = NULL;
00895 }
00896
00897
00898
00899 void
00900 move_loop_invariants (struct loops *loops)
00901 {
00902 struct loop *loop;
00903 unsigned i;
00904 struct df *df = df_init ();
00905
00906
00907 loop = loops->tree_root;
00908 while (loop->inner)
00909 loop = loop->inner;
00910
00911 while (loop != loops->tree_root)
00912 {
00913 move_single_loop_invariants (loop, df);
00914
00915 if (loop->next)
00916 {
00917 loop = loop->next;
00918 while (loop->inner)
00919 loop = loop->inner;
00920 }
00921 else
00922 loop = loop->outer;
00923 }
00924
00925 for (i = 1; i < loops->num; i++)
00926 if (loops->parray[i])
00927 free_loop_data (loops->parray[i]);
00928
00929 df_finish (df);
00930 }