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 "hard-reg-set.h"
00027 #include "obstack.h"
00028 #include "basic-block.h"
00029 #include "cfgloop.h"
00030 #include "cfglayout.h"
00031 #include "params.h"
00032 #include "output.h"
00033 #include "expr.h"
00034
00035
00036
00037
00038
00039
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 static struct loop *unswitch_loop (struct loops *, struct loop *,
00083 basic_block, rtx, rtx);
00084 static void unswitch_single_loop (struct loops *, struct loop *, rtx, int);
00085 static rtx may_unswitch_on (basic_block, struct loop *, rtx *);
00086
00087
00088
00089
00090
00091 rtx
00092 compare_and_jump_seq (rtx op0, rtx op1, enum rtx_code comp, rtx label, int prob,
00093 rtx cinsn)
00094 {
00095 rtx seq, jump, cond;
00096 enum machine_mode mode;
00097
00098 mode = GET_MODE (op0);
00099 if (mode == VOIDmode)
00100 mode = GET_MODE (op1);
00101
00102 start_sequence ();
00103 if (GET_MODE_CLASS (mode) == MODE_CC)
00104 {
00105
00106
00107 if (!cinsn)
00108 abort ();
00109 cond = XEXP (SET_SRC (pc_set (cinsn)), 0);
00110 if (GET_CODE (cond) != comp
00111 || !rtx_equal_p (op0, XEXP (cond, 0))
00112 || !rtx_equal_p (op1, XEXP (cond, 1)))
00113 abort ();
00114 emit_jump_insn (copy_insn (PATTERN (cinsn)));
00115 jump = get_last_insn ();
00116 JUMP_LABEL (jump) = JUMP_LABEL (cinsn);
00117 LABEL_NUSES (JUMP_LABEL (jump))++;
00118 redirect_jump (jump, label, 0);
00119 }
00120 else
00121 {
00122 if (cinsn)
00123 abort ();
00124
00125 op0 = force_operand (op0, NULL_RTX);
00126 op1 = force_operand (op1, NULL_RTX);
00127 do_compare_rtx_and_jump (op0, op1, comp, 0,
00128 mode, NULL_RTX, NULL_RTX, label);
00129 jump = get_last_insn ();
00130 JUMP_LABEL (jump) = label;
00131 LABEL_NUSES (label)++;
00132 }
00133 REG_NOTES (jump) = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob),
00134 REG_NOTES (jump));
00135 seq = get_insns ();
00136 end_sequence ();
00137
00138 return seq;
00139 }
00140
00141
00142 void
00143 unswitch_loops (struct loops *loops)
00144 {
00145 int i, num;
00146 struct loop *loop;
00147
00148
00149 num = loops->num;
00150
00151 for (i = 1; i < num; i++)
00152 {
00153
00154 loop = loops->parray[i];
00155 if (!loop)
00156 continue;
00157
00158 if (loop->inner)
00159 continue;
00160
00161 unswitch_single_loop (loops, loop, NULL_RTX, 0);
00162 #ifdef ENABLE_CHECKING
00163 verify_dominators (CDI_DOMINATORS);
00164 verify_loop_structure (loops);
00165 #endif
00166 }
00167
00168 iv_analysis_done ();
00169 }
00170
00171
00172
00173
00174
00175 static rtx
00176 may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn)
00177 {
00178 rtx test, at, insn, op[2], stest;
00179 struct rtx_iv iv;
00180 unsigned i;
00181 enum machine_mode mode;
00182
00183
00184 if (EDGE_COUNT (bb->succs) != 2)
00185 return NULL_RTX;
00186 if (!any_condjump_p (BB_END (bb)))
00187 return NULL_RTX;
00188
00189
00190 if (!flow_bb_inside_loop_p (loop, EDGE_SUCC (bb, 0)->dest)
00191 || !flow_bb_inside_loop_p (loop, EDGE_SUCC (bb, 1)->dest))
00192 return NULL_RTX;
00193
00194
00195
00196 if (!just_once_each_iteration_p (loop, bb))
00197 return NULL_RTX;
00198
00199
00200 test = get_condition (BB_END (bb), &at, true, false);
00201 if (!test)
00202 return NULL_RTX;
00203
00204 for (i = 0; i < 2; i++)
00205 {
00206 op[i] = XEXP (test, i);
00207
00208 if (CONSTANT_P (op[i]))
00209 continue;
00210
00211 insn = iv_get_reaching_def (at, op[i]);
00212 if (!iv_analyze (insn, op[i], &iv))
00213 return NULL_RTX;
00214 if (iv.step != const0_rtx
00215 || iv.first_special)
00216 return NULL_RTX;
00217
00218 op[i] = get_iv_value (&iv, const0_rtx);
00219 }
00220
00221 mode = GET_MODE (op[0]);
00222 if (mode == VOIDmode)
00223 mode = GET_MODE (op[1]);
00224 if (GET_MODE_CLASS (mode) == MODE_CC)
00225 {
00226 if (at != BB_END (bb))
00227 return NULL_RTX;
00228
00229 if (!rtx_equal_p (op[0], XEXP (test, 0))
00230 || !rtx_equal_p (op[1], XEXP (test, 1)))
00231 return NULL_RTX;
00232
00233 *cinsn = BB_END (bb);
00234 return test;
00235 }
00236
00237 stest = simplify_gen_relational (GET_CODE (test), SImode,
00238 mode, op[0], op[1]);
00239 if (stest == const0_rtx
00240 || stest == const_true_rtx)
00241 return stest;
00242
00243 return canon_condition (gen_rtx_fmt_ee (GET_CODE (test), SImode,
00244 op[0], op[1]));
00245 }
00246
00247
00248 rtx
00249 reversed_condition (rtx cond)
00250 {
00251 enum rtx_code reversed;
00252 reversed = reversed_comparison_code (cond, NULL);
00253 if (reversed == UNKNOWN)
00254 return NULL_RTX;
00255 else
00256 return gen_rtx_fmt_ee (reversed,
00257 GET_MODE (cond), XEXP (cond, 0),
00258 XEXP (cond, 1));
00259 }
00260
00261
00262
00263
00264
00265 static void
00266 unswitch_single_loop (struct loops *loops, struct loop *loop,
00267 rtx cond_checked, int num)
00268 {
00269 basic_block *bbs;
00270 struct loop *nloop;
00271 unsigned i;
00272 rtx cond, rcond = NULL_RTX, conds, rconds, acond, cinsn;
00273 int repeat;
00274 edge e;
00275
00276
00277 if (num > PARAM_VALUE (PARAM_MAX_UNSWITCH_LEVEL))
00278 {
00279 if (dump_file)
00280 fprintf (dump_file, ";; Not unswitching anymore, hit max level\n");
00281 return;
00282 }
00283
00284
00285 if (loop->inner)
00286 {
00287 if (dump_file)
00288 fprintf (dump_file, ";; Not unswitching, not innermost loop\n");
00289 return;
00290 }
00291
00292
00293 if (!can_duplicate_loop_p (loop))
00294 {
00295 if (dump_file)
00296 fprintf (dump_file, ";; Not unswitching, can't duplicate loop\n");
00297 return;
00298 }
00299
00300
00301 if (num_loop_insns (loop) > PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
00302 {
00303 if (dump_file)
00304 fprintf (dump_file, ";; Not unswitching, loop too big\n");
00305 return;
00306 }
00307
00308
00309 if (!maybe_hot_bb_p (loop->header))
00310 {
00311 if (dump_file)
00312 fprintf (dump_file, ";; Not unswitching, not hot area\n");
00313 return;
00314 }
00315
00316
00317 if (expected_loop_iterations (loop) < 1)
00318 {
00319 if (dump_file)
00320 fprintf (dump_file, ";; Not unswitching, loop iterations < 1\n");
00321 return;
00322 }
00323
00324 do
00325 {
00326 repeat = 0;
00327 cinsn = NULL_RTX;
00328
00329
00330 bbs = get_loop_body (loop);
00331 iv_analysis_loop_init (loop);
00332 for (i = 0; i < loop->num_nodes; i++)
00333 if ((cond = may_unswitch_on (bbs[i], loop, &cinsn)))
00334 break;
00335
00336 if (i == loop->num_nodes)
00337 {
00338 free (bbs);
00339 return;
00340 }
00341
00342 if (cond != const0_rtx
00343 && cond != const_true_rtx)
00344 {
00345 rcond = reversed_condition (cond);
00346 if (rcond)
00347 rcond = canon_condition (rcond);
00348
00349
00350 for (acond = cond_checked; acond; acond = XEXP (acond, 1))
00351 simplify_using_condition (XEXP (acond, 0), &cond, NULL);
00352 }
00353
00354 if (cond == const_true_rtx)
00355 {
00356
00357 e = FALLTHRU_EDGE (bbs[i]);
00358 remove_path (loops, e);
00359 free (bbs);
00360 repeat = 1;
00361 }
00362 else if (cond == const0_rtx)
00363 {
00364
00365 e = BRANCH_EDGE (bbs[i]);
00366 remove_path (loops, e);
00367 free (bbs);
00368 repeat = 1;
00369 }
00370 } while (repeat);
00371
00372
00373 conds = alloc_EXPR_LIST (0, cond, cond_checked);
00374 if (rcond)
00375 rconds = alloc_EXPR_LIST (0, rcond, cond_checked);
00376 else
00377 rconds = cond_checked;
00378
00379 if (dump_file)
00380 fprintf (dump_file, ";; Unswitching loop\n");
00381
00382
00383 nloop = unswitch_loop (loops, loop, bbs[i], cond, cinsn);
00384 if (!nloop)
00385 abort ();
00386
00387
00388 unswitch_single_loop (loops, nloop, rconds, num + 1);
00389 unswitch_single_loop (loops, loop, conds, num + 1);
00390
00391 free_EXPR_LIST_node (conds);
00392 if (rcond)
00393 free_EXPR_LIST_node (rconds);
00394
00395 free (bbs);
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405 static struct loop *
00406 unswitch_loop (struct loops *loops, struct loop *loop, basic_block unswitch_on,
00407 rtx cond, rtx cinsn)
00408 {
00409 edge entry, latch_edge, true_edge, false_edge, e;
00410 basic_block switch_bb, unswitch_on_alt, src;
00411 struct loop *nloop;
00412 sbitmap zero_bitmap;
00413 int irred_flag, prob;
00414 rtx seq;
00415
00416
00417 if (!flow_bb_inside_loop_p (loop, unswitch_on))
00418 abort ();
00419 if (EDGE_COUNT (unswitch_on->succs) != 2)
00420 abort ();
00421 if (!just_once_each_iteration_p (loop, unswitch_on))
00422 abort ();
00423 if (loop->inner)
00424 abort ();
00425 if (!flow_bb_inside_loop_p (loop, EDGE_SUCC (unswitch_on, 0)->dest))
00426 abort ();
00427 if (!flow_bb_inside_loop_p (loop, EDGE_SUCC (unswitch_on, 1)->dest))
00428 abort ();
00429
00430 entry = loop_preheader_edge (loop);
00431
00432
00433 src = entry->src;
00434 irred_flag = entry->flags & EDGE_IRREDUCIBLE_LOOP;
00435 entry->flags &= ~EDGE_IRREDUCIBLE_LOOP;
00436 zero_bitmap = sbitmap_alloc (2);
00437 sbitmap_zero (zero_bitmap);
00438 if (!duplicate_loop_to_header_edge (loop, entry, loops, 1,
00439 zero_bitmap, NULL, NULL, NULL, 0))
00440 return NULL;
00441 free (zero_bitmap);
00442 entry->flags |= irred_flag;
00443
00444
00445 unswitch_on_alt = unswitch_on->rbi->copy;
00446 true_edge = BRANCH_EDGE (unswitch_on_alt);
00447 false_edge = FALLTHRU_EDGE (unswitch_on);
00448 latch_edge = EDGE_SUCC (loop->latch->rbi->copy, 0);
00449
00450
00451 prob = true_edge->probability;
00452 switch_bb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb);
00453 seq = compare_and_jump_seq (XEXP (cond, 0), XEXP (cond, 1), GET_CODE (cond),
00454 block_label (true_edge->dest),
00455 prob, cinsn);
00456 emit_insn_after (seq, BB_END (switch_bb));
00457 e = make_edge (switch_bb, true_edge->dest, 0);
00458 e->probability = prob;
00459 e->count = latch_edge->count * prob / REG_BR_PROB_BASE;
00460 e = make_edge (switch_bb, FALLTHRU_EDGE (unswitch_on)->dest, EDGE_FALLTHRU);
00461 e->probability = false_edge->probability;
00462 e->count = latch_edge->count * (false_edge->probability) / REG_BR_PROB_BASE;
00463
00464 if (irred_flag)
00465 {
00466 switch_bb->flags |= BB_IRREDUCIBLE_LOOP;
00467 EDGE_SUCC (switch_bb, 0)->flags |= EDGE_IRREDUCIBLE_LOOP;
00468 EDGE_SUCC (switch_bb, 1)->flags |= EDGE_IRREDUCIBLE_LOOP;
00469 }
00470 else
00471 {
00472 switch_bb->flags &= ~BB_IRREDUCIBLE_LOOP;
00473 EDGE_SUCC (switch_bb, 0)->flags &= ~EDGE_IRREDUCIBLE_LOOP;
00474 EDGE_SUCC (switch_bb, 1)->flags &= ~EDGE_IRREDUCIBLE_LOOP;
00475 }
00476
00477
00478 nloop = loopify (loops, latch_edge,
00479 EDGE_PRED (loop->header->rbi->copy, 0), switch_bb,
00480 BRANCH_EDGE (switch_bb), FALLTHRU_EDGE (switch_bb), true);
00481
00482
00483 remove_path (loops, true_edge);
00484 remove_path (loops, false_edge);
00485
00486
00487
00488 fix_loop_placement (loop);
00489 fix_loop_placement (nloop);
00490
00491
00492 loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
00493 loop_split_edge_with (loop_preheader_edge (nloop), NULL_RTX);
00494
00495 return nloop;
00496 }