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
00027 #include "rtl.h"
00028 #include "regs.h"
00029 #include "function.h"
00030 #include "flags.h"
00031 #include "insn-config.h"
00032 #include "recog.h"
00033 #include "except.h"
00034 #include "hard-reg-set.h"
00035 #include "basic-block.h"
00036 #include "expr.h"
00037 #include "real.h"
00038 #include "output.h"
00039 #include "optabs.h"
00040 #include "toplev.h"
00041 #include "tm_p.h"
00042 #include "cfgloop.h"
00043 #include "target.h"
00044 #include "timevar.h"
00045 #include "tree-pass.h"
00046
00047
00048 #ifndef HAVE_conditional_execution
00049 #define HAVE_conditional_execution 0
00050 #endif
00051 #ifndef HAVE_conditional_move
00052 #define HAVE_conditional_move 0
00053 #endif
00054 #ifndef HAVE_incscc
00055 #define HAVE_incscc 0
00056 #endif
00057 #ifndef HAVE_decscc
00058 #define HAVE_decscc 0
00059 #endif
00060 #ifndef HAVE_trap
00061 #define HAVE_trap 0
00062 #endif
00063 #ifndef HAVE_conditional_trap
00064 #define HAVE_conditional_trap 0
00065 #endif
00066
00067 #ifndef MAX_CONDITIONAL_EXECUTE
00068 #define MAX_CONDITIONAL_EXECUTE (BRANCH_COST + 1)
00069 #endif
00070
00071 #define NULL_BLOCK ((basic_block) NULL)
00072
00073
00074 static int num_possible_if_blocks;
00075
00076
00077
00078 static int num_updated_if_blocks;
00079
00080
00081 static int num_true_changes;
00082
00083
00084 static int cond_exec_changed_p;
00085
00086
00087 static bool life_data_ok;
00088
00089
00090 static int count_bb_insns (basic_block);
00091 static bool cheap_bb_rtx_cost_p (basic_block, int);
00092 static rtx first_active_insn (basic_block);
00093 static rtx last_active_insn (basic_block, int);
00094 static basic_block block_fallthru (basic_block);
00095 static int cond_exec_process_insns (ce_if_block_t *, rtx, rtx, rtx, rtx, int);
00096 static rtx cond_exec_get_condition (rtx);
00097 static int cond_exec_process_if_block (ce_if_block_t *, int);
00098 static rtx noce_get_condition (rtx, rtx *);
00099 static int noce_operand_ok (rtx);
00100 static int noce_process_if_block (ce_if_block_t *);
00101 static int process_if_block (ce_if_block_t *);
00102 static void merge_if_block (ce_if_block_t *);
00103 static int find_cond_trap (basic_block, edge, edge);
00104 static basic_block find_if_header (basic_block, int);
00105 static int block_jumps_and_fallthru_p (basic_block, basic_block);
00106 static int find_if_block (ce_if_block_t *);
00107 static int find_if_case_1 (basic_block, edge, edge);
00108 static int find_if_case_2 (basic_block, edge, edge);
00109 static int find_memory (rtx *, void *);
00110 static int dead_or_predicable (basic_block, basic_block, basic_block,
00111 basic_block, int);
00112 static void noce_emit_move_insn (rtx, rtx);
00113 static rtx block_has_only_trap (basic_block);
00114
00115
00116
00117 static int
00118 count_bb_insns (basic_block bb)
00119 {
00120 int count = 0;
00121 rtx insn = BB_HEAD (bb);
00122
00123 while (1)
00124 {
00125 if (CALL_P (insn) || NONJUMP_INSN_P (insn))
00126 count++;
00127
00128 if (insn == BB_END (bb))
00129 break;
00130 insn = NEXT_INSN (insn);
00131 }
00132
00133 return count;
00134 }
00135
00136
00137
00138
00139
00140 static bool
00141 cheap_bb_rtx_cost_p (basic_block bb, int max_cost)
00142 {
00143 int count = 0;
00144 rtx insn = BB_HEAD (bb);
00145
00146 while (1)
00147 {
00148 if (NONJUMP_INSN_P (insn))
00149 {
00150 int cost = insn_rtx_cost (PATTERN (insn));
00151 if (cost == 0)
00152 return false;
00153
00154
00155
00156
00157
00158
00159
00160
00161 #ifdef STACK_REGS
00162 {
00163 rtx set = single_set (insn);
00164 if (set && STACK_REG_P (SET_DEST (set)))
00165 return false;
00166 }
00167 #endif
00168
00169 count += cost;
00170 if (count >= max_cost)
00171 return false;
00172 }
00173 else if (CALL_P (insn))
00174 return false;
00175
00176 if (insn == BB_END (bb))
00177 break;
00178 insn = NEXT_INSN (insn);
00179 }
00180
00181 return true;
00182 }
00183
00184
00185
00186 static rtx
00187 first_active_insn (basic_block bb)
00188 {
00189 rtx insn = BB_HEAD (bb);
00190
00191 if (LABEL_P (insn))
00192 {
00193 if (insn == BB_END (bb))
00194 return NULL_RTX;
00195 insn = NEXT_INSN (insn);
00196 }
00197
00198 while (NOTE_P (insn))
00199 {
00200 if (insn == BB_END (bb))
00201 return NULL_RTX;
00202 insn = NEXT_INSN (insn);
00203 }
00204
00205 if (JUMP_P (insn))
00206 return NULL_RTX;
00207
00208 return insn;
00209 }
00210
00211
00212
00213 static rtx
00214 last_active_insn (basic_block bb, int skip_use_p)
00215 {
00216 rtx insn = BB_END (bb);
00217 rtx head = BB_HEAD (bb);
00218
00219 while (NOTE_P (insn)
00220 || JUMP_P (insn)
00221 || (skip_use_p
00222 && NONJUMP_INSN_P (insn)
00223 && GET_CODE (PATTERN (insn)) == USE))
00224 {
00225 if (insn == head)
00226 return NULL_RTX;
00227 insn = PREV_INSN (insn);
00228 }
00229
00230 if (LABEL_P (insn))
00231 return NULL_RTX;
00232
00233 return insn;
00234 }
00235
00236
00237
00238 static basic_block
00239 block_fallthru (basic_block bb)
00240 {
00241 edge e;
00242 edge_iterator ei;
00243
00244 FOR_EACH_EDGE (e, ei, bb->succs)
00245 if (e->flags & EDGE_FALLTHRU)
00246 break;
00247
00248 return (e) ? e->dest : NULL_BLOCK;
00249 }
00250
00251
00252
00253
00254
00255 static int
00256 cond_exec_process_insns (ce_if_block_t *ce_info ATTRIBUTE_UNUSED,
00257 rtx start,
00258 rtx end,
00259 rtx test,
00260 rtx prob_val,
00261 int mod_ok)
00262 {
00263 int must_be_last = FALSE;
00264 rtx insn;
00265 rtx xtest;
00266 rtx pattern;
00267
00268 if (!start || !end)
00269 return FALSE;
00270
00271 for (insn = start; ; insn = NEXT_INSN (insn))
00272 {
00273 if (NOTE_P (insn))
00274 goto insn_done;
00275
00276 gcc_assert(NONJUMP_INSN_P (insn) || CALL_P (insn));
00277
00278
00279 if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
00280 {
00281
00282
00283 SET_INSN_DELETED (insn);
00284 goto insn_done;
00285 }
00286
00287
00288 if (must_be_last)
00289 return FALSE;
00290
00291 if (modified_in_p (test, insn))
00292 {
00293 if (!mod_ok)
00294 return FALSE;
00295 must_be_last = TRUE;
00296 }
00297
00298
00299 pattern = PATTERN (insn);
00300 xtest = copy_rtx (test);
00301
00302
00303
00304 if (GET_CODE (pattern) == COND_EXEC)
00305 {
00306 if (GET_MODE (xtest) != GET_MODE (COND_EXEC_TEST (pattern)))
00307 return FALSE;
00308
00309 xtest = gen_rtx_AND (GET_MODE (xtest), xtest,
00310 COND_EXEC_TEST (pattern));
00311 pattern = COND_EXEC_CODE (pattern);
00312 }
00313
00314 pattern = gen_rtx_COND_EXEC (VOIDmode, xtest, pattern);
00315
00316
00317
00318
00319 #ifdef IFCVT_MODIFY_INSN
00320 IFCVT_MODIFY_INSN (ce_info, pattern, insn);
00321 if (! pattern)
00322 return FALSE;
00323 #endif
00324
00325 validate_change (insn, &PATTERN (insn), pattern, 1);
00326
00327 if (CALL_P (insn) && prob_val)
00328 validate_change (insn, ®_NOTES (insn),
00329 alloc_EXPR_LIST (REG_BR_PROB, prob_val,
00330 REG_NOTES (insn)), 1);
00331
00332 insn_done:
00333 if (insn == end)
00334 break;
00335 }
00336
00337 return TRUE;
00338 }
00339
00340
00341
00342 static rtx
00343 cond_exec_get_condition (rtx jump)
00344 {
00345 rtx test_if, cond;
00346
00347 if (any_condjump_p (jump))
00348 test_if = SET_SRC (pc_set (jump));
00349 else
00350 return NULL_RTX;
00351 cond = XEXP (test_if, 0);
00352
00353
00354
00355 if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF
00356 && XEXP (XEXP (test_if, 2), 0) == JUMP_LABEL (jump))
00357 {
00358 enum rtx_code rev = reversed_comparison_code (cond, jump);
00359 if (rev == UNKNOWN)
00360 return NULL_RTX;
00361
00362 cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
00363 XEXP (cond, 1));
00364 }
00365
00366 return cond;
00367 }
00368
00369
00370
00371
00372
00373 static int
00374 cond_exec_process_if_block (ce_if_block_t * ce_info,
00375 int do_multiple_p)
00376 {
00377 basic_block test_bb = ce_info->test_bb;
00378 basic_block then_bb = ce_info->then_bb;
00379 basic_block else_bb = ce_info->else_bb;
00380 rtx test_expr;
00381 rtx then_start;
00382 rtx then_end;
00383 rtx else_start = NULL_RTX;
00384 rtx else_end = NULL_RTX;
00385 int max;
00386 int then_mod_ok;
00387 rtx true_expr;
00388 rtx false_expr;
00389 rtx true_prob_val;
00390 rtx false_prob_val;
00391 int n_insns;
00392 enum rtx_code false_code;
00393
00394
00395
00396
00397 if (!do_multiple_p && ce_info->num_multiple_test_blocks)
00398 {
00399 if (else_bb || ! ce_info->and_and_p)
00400 return FALSE;
00401
00402 ce_info->test_bb = test_bb = ce_info->last_test_bb;
00403 ce_info->num_multiple_test_blocks = 0;
00404 ce_info->num_and_and_blocks = 0;
00405 ce_info->num_or_or_blocks = 0;
00406 }
00407
00408
00409
00410 test_expr = cond_exec_get_condition (BB_END (test_bb));
00411 if (! test_expr)
00412 return FALSE;
00413
00414
00415
00416 if (! onlyjump_p (BB_END (test_bb)))
00417 return FALSE;
00418
00419
00420
00421
00422 then_start = first_active_insn (then_bb);
00423 then_end = last_active_insn (then_bb, TRUE);
00424 n_insns = ce_info->num_then_insns = count_bb_insns (then_bb);
00425 max = MAX_CONDITIONAL_EXECUTE;
00426
00427 if (else_bb)
00428 {
00429 max *= 2;
00430 else_start = first_active_insn (else_bb);
00431 else_end = last_active_insn (else_bb, TRUE);
00432 n_insns += ce_info->num_else_insns = count_bb_insns (else_bb);
00433 }
00434
00435 if (n_insns > max)
00436 return FALSE;
00437
00438
00439
00440
00441 true_expr = test_expr;
00442
00443 false_code = reversed_comparison_code (true_expr, BB_END (test_bb));
00444 if (false_code != UNKNOWN)
00445 false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr),
00446 XEXP (true_expr, 0), XEXP (true_expr, 1));
00447 else
00448 false_expr = NULL_RTX;
00449
00450 #ifdef IFCVT_MODIFY_TESTS
00451
00452
00453 IFCVT_MODIFY_TESTS (ce_info, true_expr, false_expr);
00454
00455
00456 if (!true_expr || !false_expr)
00457 goto fail;
00458 #endif
00459
00460 true_prob_val = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
00461 if (true_prob_val)
00462 {
00463 true_prob_val = XEXP (true_prob_val, 0);
00464 false_prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (true_prob_val));
00465 }
00466 else
00467 false_prob_val = NULL_RTX;
00468
00469
00470
00471 if (ce_info->num_multiple_test_blocks > 0)
00472 {
00473 basic_block bb = test_bb;
00474 basic_block last_test_bb = ce_info->last_test_bb;
00475
00476 if (! false_expr)
00477 goto fail;
00478
00479 do
00480 {
00481 rtx start, end;
00482 rtx t, f;
00483 enum rtx_code f_code;
00484
00485 bb = block_fallthru (bb);
00486 start = first_active_insn (bb);
00487 end = last_active_insn (bb, TRUE);
00488 if (start
00489 && ! cond_exec_process_insns (ce_info, start, end, false_expr,
00490 false_prob_val, FALSE))
00491 goto fail;
00492
00493
00494
00495 if (! onlyjump_p (BB_END (bb)))
00496 goto fail;
00497
00498
00499 t = cond_exec_get_condition (BB_END (bb));
00500 if (! t)
00501 goto fail;
00502
00503 f_code = reversed_comparison_code (t, BB_END (bb));
00504 if (f_code == UNKNOWN)
00505 goto fail;
00506
00507 f = gen_rtx_fmt_ee (f_code, GET_MODE (t), XEXP (t, 0), XEXP (t, 1));
00508 if (ce_info->and_and_p)
00509 {
00510 t = gen_rtx_AND (GET_MODE (t), true_expr, t);
00511 f = gen_rtx_IOR (GET_MODE (t), false_expr, f);
00512 }
00513 else
00514 {
00515 t = gen_rtx_IOR (GET_MODE (t), true_expr, t);
00516 f = gen_rtx_AND (GET_MODE (t), false_expr, f);
00517 }
00518
00519
00520
00521
00522 #ifdef IFCVT_MODIFY_MULTIPLE_TESTS
00523 IFCVT_MODIFY_MULTIPLE_TESTS (ce_info, bb, t, f);
00524
00525
00526 if (!t || !f)
00527 goto fail;
00528 #endif
00529
00530 true_expr = t;
00531 false_expr = f;
00532 }
00533 while (bb != last_test_bb);
00534 }
00535
00536
00537
00538 then_mod_ok = (else_bb == NULL_BLOCK);
00539
00540
00541
00542
00543 if (then_end
00544 && (! false_expr
00545 || ! cond_exec_process_insns (ce_info, then_start, then_end,
00546 false_expr, false_prob_val,
00547 then_mod_ok)))
00548 goto fail;
00549
00550 if (else_bb && else_end
00551 && ! cond_exec_process_insns (ce_info, else_start, else_end,
00552 true_expr, true_prob_val, TRUE))
00553 goto fail;
00554
00555
00556
00557 if (! apply_change_group ())
00558 {
00559 #ifdef IFCVT_MODIFY_CANCEL
00560
00561 IFCVT_MODIFY_CANCEL (ce_info);
00562 #endif
00563 return FALSE;
00564 }
00565
00566 #ifdef IFCVT_MODIFY_FINAL
00567
00568 IFCVT_MODIFY_FINAL (ce_info);
00569 #endif
00570
00571
00572 if (dump_file)
00573 fprintf (dump_file, "%d insn%s converted to conditional execution.\n",
00574 n_insns, (n_insns == 1) ? " was" : "s were");
00575
00576
00577 merge_if_block (ce_info);
00578 cond_exec_changed_p = TRUE;
00579 return TRUE;
00580
00581 fail:
00582 #ifdef IFCVT_MODIFY_CANCEL
00583
00584 IFCVT_MODIFY_CANCEL (ce_info);
00585 #endif
00586
00587 cancel_changes (0);
00588 return FALSE;
00589 }
00590
00591
00592
00593
00594
00595
00596
00597 struct noce_if_info
00598 {
00599 basic_block test_bb;
00600 rtx insn_a, insn_b;
00601 rtx x, a, b;
00602 rtx jump, cond, cond_earliest;
00603
00604 bool b_unconditional;
00605 };
00606
00607 static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
00608 static int noce_try_move (struct noce_if_info *);
00609 static int noce_try_store_flag (struct noce_if_info *);
00610 static int noce_try_addcc (struct noce_if_info *);
00611 static int noce_try_store_flag_constants (struct noce_if_info *);
00612 static int noce_try_store_flag_mask (struct noce_if_info *);
00613 static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx,
00614 rtx, rtx, rtx);
00615 static int noce_try_cmove (struct noce_if_info *);
00616 static int noce_try_cmove_arith (struct noce_if_info *);
00617 static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx *);
00618 static int noce_try_minmax (struct noce_if_info *);
00619 static int noce_try_abs (struct noce_if_info *);
00620 static int noce_try_sign_mask (struct noce_if_info *);
00621
00622
00623
00624 static rtx
00625 noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
00626 int normalize)
00627 {
00628 rtx cond = if_info->cond;
00629 int cond_complex;
00630 enum rtx_code code;
00631
00632 cond_complex = (! general_operand (XEXP (cond, 0), VOIDmode)
00633 || ! general_operand (XEXP (cond, 1), VOIDmode));
00634
00635
00636
00637
00638 if (cond_complex)
00639 cond = XEXP (SET_SRC (pc_set (if_info->jump)), 0);
00640
00641 if (reversep)
00642 code = reversed_comparison_code (cond, if_info->jump);
00643 else
00644 code = GET_CODE (cond);
00645
00646 if ((if_info->cond_earliest == if_info->jump || cond_complex)
00647 && (normalize == 0 || STORE_FLAG_VALUE == normalize))
00648 {
00649 rtx tmp;
00650
00651 tmp = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
00652 XEXP (cond, 1));
00653 tmp = gen_rtx_SET (VOIDmode, x, tmp);
00654
00655 start_sequence ();
00656 tmp = emit_insn (tmp);
00657
00658 if (recog_memoized (tmp) >= 0)
00659 {
00660 tmp = get_insns ();
00661 end_sequence ();
00662 emit_insn (tmp);
00663
00664 if_info->cond_earliest = if_info->jump;
00665
00666 return x;
00667 }
00668
00669 end_sequence ();
00670 }
00671
00672
00673 if (cond_complex || !SCALAR_INT_MODE_P (GET_MODE (x)))
00674 return NULL_RTX;
00675
00676 return emit_store_flag (x, code, XEXP (cond, 0),
00677 XEXP (cond, 1), VOIDmode,
00678 (code == LTU || code == LEU
00679 || code == GEU || code == GTU), normalize);
00680 }
00681
00682
00683
00684
00685 static void
00686 noce_emit_move_insn (rtx x, rtx y)
00687 {
00688 enum machine_mode outmode;
00689 rtx outer, inner;
00690 int bitpos;
00691
00692 if (GET_CODE (x) != STRICT_LOW_PART)
00693 {
00694 rtx seq, insn, target;
00695 optab ot;
00696
00697 start_sequence ();
00698
00699
00700 insn = (OBJECT_P (y) || CONSTANT_P (y) || GET_CODE (y) == SUBREG)
00701 ? emit_move_insn (x, y)
00702 : emit_insn (gen_rtx_SET (VOIDmode, x, y));
00703 seq = get_insns ();
00704 end_sequence();
00705
00706 if (recog_memoized (insn) <= 0)
00707 {
00708 if (GET_CODE (x) == ZERO_EXTRACT)
00709 {
00710 rtx op = XEXP (x, 0);
00711 unsigned HOST_WIDE_INT size = INTVAL (XEXP (x, 1));
00712 unsigned HOST_WIDE_INT start = INTVAL (XEXP (x, 2));
00713
00714
00715
00716
00717
00718
00719 if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
00720 {
00721 if (MEM_P (op))
00722 start = BITS_PER_UNIT - start - size;
00723 else
00724 {
00725 gcc_assert (REG_P (op));
00726 start = BITS_PER_WORD - start - size;
00727 }
00728 }
00729
00730 gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
00731 store_bit_field (op, size, start, GET_MODE (x), y);
00732 return;
00733 }
00734
00735 switch (GET_RTX_CLASS (GET_CODE (y)))
00736 {
00737 case RTX_UNARY:
00738 ot = code_to_optab[GET_CODE (y)];
00739 if (ot)
00740 {
00741 start_sequence ();
00742 target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
00743 if (target != NULL_RTX)
00744 {
00745 if (target != x)
00746 emit_move_insn (x, target);
00747 seq = get_insns ();
00748 }
00749 end_sequence ();
00750 }
00751 break;
00752
00753 case RTX_BIN_ARITH:
00754 case RTX_COMM_ARITH:
00755 ot = code_to_optab[GET_CODE (y)];
00756 if (ot)
00757 {
00758 start_sequence ();
00759 target = expand_binop (GET_MODE (y), ot,
00760 XEXP (y, 0), XEXP (y, 1),
00761 x, 0, OPTAB_DIRECT);
00762 if (target != NULL_RTX)
00763 {
00764 if (target != x)
00765 emit_move_insn (x, target);
00766 seq = get_insns ();
00767 }
00768 end_sequence ();
00769 }
00770 break;
00771
00772 default:
00773 break;
00774 }
00775 }
00776
00777 emit_insn (seq);
00778 return;
00779 }
00780
00781 outer = XEXP (x, 0);
00782 inner = XEXP (outer, 0);
00783 outmode = GET_MODE (outer);
00784 bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
00785 store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, outmode, y);
00786 }
00787
00788
00789
00790
00791
00792
00793 static rtx
00794 end_ifcvt_sequence (struct noce_if_info *if_info)
00795 {
00796 rtx insn;
00797 rtx seq = get_insns ();
00798
00799 set_used_flags (if_info->x);
00800 set_used_flags (if_info->cond);
00801 unshare_all_rtl_in_chain (seq);
00802 end_sequence ();
00803
00804
00805
00806
00807
00808 for (insn = seq; insn; insn = NEXT_INSN (insn))
00809 if (JUMP_P (insn)
00810 || recog_memoized (insn) == -1)
00811 return NULL_RTX;
00812
00813 return seq;
00814 }
00815
00816
00817
00818
00819 static int
00820 noce_try_move (struct noce_if_info *if_info)
00821 {
00822 rtx cond = if_info->cond;
00823 enum rtx_code code = GET_CODE (cond);
00824 rtx y, seq;
00825
00826 if (code != NE && code != EQ)
00827 return FALSE;
00828
00829
00830
00831 if (HONOR_NANS (GET_MODE (if_info->x))
00832 || HONOR_SIGNED_ZEROS (GET_MODE (if_info->x)))
00833 return FALSE;
00834
00835
00836
00837 if ((rtx_equal_p (if_info->a, XEXP (cond, 0))
00838 && rtx_equal_p (if_info->b, XEXP (cond, 1)))
00839 || (rtx_equal_p (if_info->a, XEXP (cond, 1))
00840 && rtx_equal_p (if_info->b, XEXP (cond, 0))))
00841 {
00842 y = (code == EQ) ? if_info->a : if_info->b;
00843
00844
00845 if (! rtx_equal_p (if_info->x, y))
00846 {
00847 start_sequence ();
00848 noce_emit_move_insn (if_info->x, y);
00849 seq = end_ifcvt_sequence (if_info);
00850 if (!seq)
00851 return FALSE;
00852
00853 emit_insn_before_setloc (seq, if_info->jump,
00854 INSN_LOCATOR (if_info->insn_a));
00855 }
00856 return TRUE;
00857 }
00858 return FALSE;
00859 }
00860
00861
00862
00863
00864
00865
00866
00867 static int
00868 noce_try_store_flag (struct noce_if_info *if_info)
00869 {
00870 int reversep;
00871 rtx target, seq;
00872
00873 if (GET_CODE (if_info->b) == CONST_INT
00874 && INTVAL (if_info->b) == STORE_FLAG_VALUE
00875 && if_info->a == const0_rtx)
00876 reversep = 0;
00877 else if (if_info->b == const0_rtx
00878 && GET_CODE (if_info->a) == CONST_INT
00879 && INTVAL (if_info->a) == STORE_FLAG_VALUE
00880 && (reversed_comparison_code (if_info->cond, if_info->jump)
00881 != UNKNOWN))
00882 reversep = 1;
00883 else
00884 return FALSE;
00885
00886 start_sequence ();
00887
00888 target = noce_emit_store_flag (if_info, if_info->x, reversep, 0);
00889 if (target)
00890 {
00891 if (target != if_info->x)
00892 noce_emit_move_insn (if_info->x, target);
00893
00894 seq = end_ifcvt_sequence (if_info);
00895 if (! seq)
00896 return FALSE;
00897
00898 emit_insn_before_setloc (seq, if_info->jump,
00899 INSN_LOCATOR (if_info->insn_a));
00900 return TRUE;
00901 }
00902 else
00903 {
00904 end_sequence ();
00905 return FALSE;
00906 }
00907 }
00908
00909
00910
00911 static int
00912 noce_try_store_flag_constants (struct noce_if_info *if_info)
00913 {
00914 rtx target, seq;
00915 int reversep;
00916 HOST_WIDE_INT itrue, ifalse, diff, tmp;
00917 int normalize, can_reverse;
00918 enum machine_mode mode;
00919
00920 if (! no_new_pseudos
00921 && GET_CODE (if_info->a) == CONST_INT
00922 && GET_CODE (if_info->b) == CONST_INT)
00923 {
00924 mode = GET_MODE (if_info->x);
00925 ifalse = INTVAL (if_info->a);
00926 itrue = INTVAL (if_info->b);
00927
00928
00929 if ((itrue - ifalse > 0)
00930 != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue))
00931 return FALSE;
00932
00933 diff = trunc_int_for_mode (itrue - ifalse, mode);
00934
00935 can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
00936 != UNKNOWN);
00937
00938 reversep = 0;
00939 if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
00940 normalize = 0;
00941 else if (ifalse == 0 && exact_log2 (itrue) >= 0
00942 && (STORE_FLAG_VALUE == 1
00943 || BRANCH_COST >= 2))
00944 normalize = 1;
00945 else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse
00946 && (STORE_FLAG_VALUE == 1 || BRANCH_COST >= 2))
00947 normalize = 1, reversep = 1;
00948 else if (itrue == -1
00949 && (STORE_FLAG_VALUE == -1
00950 || BRANCH_COST >= 2))
00951 normalize = -1;
00952 else if (ifalse == -1 && can_reverse
00953 && (STORE_FLAG_VALUE == -1 || BRANCH_COST >= 2))
00954 normalize = -1, reversep = 1;
00955 else if ((BRANCH_COST >= 2 && STORE_FLAG_VALUE == -1)
00956 || BRANCH_COST >= 3)
00957 normalize = -1;
00958 else
00959 return FALSE;
00960
00961 if (reversep)
00962 {
00963 tmp = itrue; itrue = ifalse; ifalse = tmp;
00964 diff = trunc_int_for_mode (-diff, mode);
00965 }
00966
00967 start_sequence ();
00968 target = noce_emit_store_flag (if_info, if_info->x, reversep, normalize);
00969 if (! target)
00970 {
00971 end_sequence ();
00972 return FALSE;
00973 }
00974
00975
00976
00977 if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
00978 {
00979 target = expand_simple_binop (mode,
00980 (diff == STORE_FLAG_VALUE
00981 ? PLUS : MINUS),
00982 GEN_INT (ifalse), target, if_info->x, 0,
00983 OPTAB_WIDEN);
00984 }
00985
00986
00987
00988 else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0)
00989 {
00990 target = expand_simple_binop (mode, ASHIFT,
00991 target, GEN_INT (tmp), if_info->x, 0,
00992 OPTAB_WIDEN);
00993 }
00994
00995
00996
00997 else if (itrue == -1)
00998 {
00999 target = expand_simple_binop (mode, IOR,
01000 target, GEN_INT (ifalse), if_info->x, 0,
01001 OPTAB_WIDEN);
01002 }
01003
01004
01005
01006 else
01007 {
01008 target = expand_simple_binop (mode, AND,
01009 target, GEN_INT (diff), if_info->x, 0,
01010 OPTAB_WIDEN);
01011 if (target)
01012 target = expand_simple_binop (mode, PLUS,
01013 target, GEN_INT (ifalse),
01014 if_info->x, 0, OPTAB_WIDEN);
01015 }
01016
01017 if (! target)
01018 {
01019 end_sequence ();
01020 return FALSE;
01021 }
01022
01023 if (target != if_info->x)
01024 noce_emit_move_insn (if_info->x, target);
01025
01026 seq = end_ifcvt_sequence (if_info);
01027 if (!seq)
01028 return FALSE;
01029
01030 emit_insn_before_setloc (seq, if_info->jump,
01031 INSN_LOCATOR (if_info->insn_a));
01032 return TRUE;
01033 }
01034
01035 return FALSE;
01036 }
01037
01038
01039
01040
01041 static int
01042 noce_try_addcc (struct noce_if_info *if_info)
01043 {
01044 rtx target, seq;
01045 int subtract, normalize;
01046
01047 if (! no_new_pseudos
01048 && GET_CODE (if_info->a) == PLUS
01049 && rtx_equal_p (XEXP (if_info->a, 0), if_info->b)
01050 && (reversed_comparison_code (if_info->cond, if_info->jump)
01051 != UNKNOWN))
01052 {
01053 rtx cond = if_info->cond;
01054 enum rtx_code code = reversed_comparison_code (cond, if_info->jump);
01055
01056
01057 if (general_operand (XEXP (cond, 0), VOIDmode)
01058 && general_operand (XEXP (cond, 1), VOIDmode))
01059 {
01060 start_sequence ();
01061 target = emit_conditional_add (if_info->x, code,
01062 XEXP (cond, 0),
01063 XEXP (cond, 1),
01064 VOIDmode,
01065 if_info->b,
01066 XEXP (if_info->a, 1),
01067 GET_MODE (if_info->x),
01068 (code == LTU || code == GEU
01069 || code == LEU || code == GTU));
01070 if (target)
01071 {
01072 if (target != if_info->x)
01073 noce_emit_move_insn (if_info->x, target);
01074
01075 seq = end_ifcvt_sequence (if_info);
01076 if (!seq)
01077 return FALSE;
01078
01079 emit_insn_before_setloc (seq, if_info->jump,
01080 INSN_LOCATOR (if_info->insn_a));
01081 return TRUE;
01082 }
01083 end_sequence ();
01084 }
01085
01086
01087
01088 if (BRANCH_COST >= 2
01089 && (XEXP (if_info->a, 1) == const1_rtx
01090 || XEXP (if_info->a, 1) == constm1_rtx))
01091 {
01092 start_sequence ();
01093 if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
01094 subtract = 0, normalize = 0;
01095 else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
01096 subtract = 1, normalize = 0;
01097 else
01098 subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
01099
01100
01101 target = noce_emit_store_flag (if_info,
01102 gen_reg_rtx (GET_MODE (if_info->x)),
01103 1, normalize);
01104
01105 if (target)
01106 target = expand_simple_binop (GET_MODE (if_info->x),
01107 subtract ? MINUS : PLUS,
01108 if_info->b, target, if_info->x,
01109 0, OPTAB_WIDEN);
01110 if (target)
01111 {
01112 if (target != if_info->x)
01113 noce_emit_move_insn (if_info->x, target);
01114
01115 seq = end_ifcvt_sequence (if_info);
01116 if (!seq)
01117 return FALSE;
01118
01119 emit_insn_before_setloc (seq, if_info->jump,
01120 INSN_LOCATOR (if_info->insn_a));
01121 return TRUE;
01122 }
01123 end_sequence ();
01124 }
01125 }
01126
01127 return FALSE;
01128 }
01129
01130
01131
01132 static int
01133 noce_try_store_flag_mask (struct noce_if_info *if_info)
01134 {
01135 rtx target, seq;
01136 int reversep;
01137
01138 reversep = 0;
01139 if (! no_new_pseudos
01140 && (BRANCH_COST >= 2
01141 || STORE_FLAG_VALUE == -1)
01142 && ((if_info->a == const0_rtx
01143 && rtx_equal_p (if_info->b, if_info->x))
01144 || ((reversep = (reversed_comparison_code (if_info->cond,
01145 if_info->jump)
01146 != UNKNOWN))
01147 && if_info->b == const0_rtx
01148 && rtx_equal_p (if_info->a, if_info->x))))
01149 {
01150 start_sequence ();
01151 target = noce_emit_store_flag (if_info,
01152 gen_reg_rtx (GET_MODE (if_info->x)),
01153 reversep, -1);
01154 if (target)
01155 target = expand_simple_binop (GET_MODE (if_info->x), AND,
01156 if_info->x,
01157 target, if_info->x, 0,
01158 OPTAB_WIDEN);
01159
01160 if (target)
01161 {
01162 if (target != if_info->x)
01163 noce_emit_move_insn (if_info->x, target);
01164
01165 seq = end_ifcvt_sequence (if_info);
01166 if (!seq)
01167 return FALSE;
01168
01169 emit_insn_before_setloc (seq, if_info->jump,
01170 INSN_LOCATOR (if_info->insn_a));
01171 return TRUE;
01172 }
01173
01174 end_sequence ();
01175 }
01176
01177 return FALSE;
01178 }
01179
01180
01181
01182 static rtx
01183 noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
01184 rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue)
01185 {
01186
01187
01188
01189
01190
01191 if (if_info->cond_earliest == if_info->jump)
01192 {
01193 rtx tmp;
01194
01195 tmp = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), cmp_a, cmp_b);
01196 tmp = gen_rtx_IF_THEN_ELSE (GET_MODE (x), tmp, vtrue, vfalse);
01197 tmp = gen_rtx_SET (VOIDmode, x, tmp);
01198
01199 start_sequence ();
01200 tmp = emit_insn (tmp);
01201
01202 if (recog_memoized (tmp) >= 0)
01203 {
01204 tmp = get_insns ();
01205 end_sequence ();
01206 emit_insn (tmp);
01207
01208 return x;
01209 }
01210
01211 end_sequence ();
01212 }
01213
01214
01215 if (! general_operand (cmp_a, GET_MODE (cmp_a))
01216 || ! general_operand (cmp_b, GET_MODE (cmp_b)))
01217 return NULL_RTX;
01218
01219 #if HAVE_conditional_move
01220 return emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode,
01221 vtrue, vfalse, GET_MODE (x),
01222 (code == LTU || code == GEU
01223 || code == LEU || code == GTU));
01224 #else
01225
01226
01227
01228
01229 return NULL_RTX;
01230 #endif
01231 }
01232
01233
01234
01235
01236
01237 static int
01238 noce_try_cmove (struct noce_if_info *if_info)
01239 {
01240 enum rtx_code code;
01241 rtx target, seq;
01242
01243 if ((CONSTANT_P (if_info->a) || register_operand (if_info->a, VOIDmode))
01244 && (CONSTANT_P (if_info->b) || register_operand (if_info->b, VOIDmode)))
01245 {
01246 start_sequence ();
01247
01248 code = GET_CODE (if_info->cond);
01249 target = noce_emit_cmove (if_info, if_info->x, code,
01250 XEXP (if_info->cond, 0),
01251 XEXP (if_info->cond, 1),
01252 if_info->a, if_info->b);
01253
01254 if (target)
01255 {
01256 if (target != if_info->x)
01257 noce_emit_move_insn (if_info->x, target);
01258
01259 seq = end_ifcvt_sequence (if_info);
01260 if (!seq)
01261 return FALSE;
01262
01263 emit_insn_before_setloc (seq, if_info->jump,
01264 INSN_LOCATOR (if_info->insn_a));
01265 return TRUE;
01266 }
01267 else
01268 {
01269 end_sequence ();
01270 return FALSE;
01271 }
01272 }
01273
01274 return FALSE;
01275 }
01276
01277
01278
01279 static int
01280 noce_try_cmove_arith (struct noce_if_info *if_info)
01281 {
01282 rtx a = if_info->a;
01283 rtx b = if_info->b;
01284 rtx x = if_info->x;
01285 rtx orig_a, orig_b;
01286 rtx insn_a, insn_b;
01287 rtx tmp, target;
01288 int is_mem = 0;
01289 int insn_cost;
01290 enum rtx_code code;
01291
01292
01293
01294
01295
01296 if (! no_new_pseudos && cse_not_expected
01297 && MEM_P (a) && MEM_P (b)
01298 && BRANCH_COST >= 5)
01299 {
01300 a = XEXP (a, 0);
01301 b = XEXP (b, 0);
01302 x = gen_reg_rtx (Pmode);
01303 is_mem = 1;
01304 }
01305
01306
01307
01308
01309 else if (may_trap_p (a) || may_trap_p (b))
01310 return FALSE;
01311
01312
01313
01314
01315
01316
01317
01318
01319 code = GET_CODE (if_info->cond);
01320 insn_a = if_info->insn_a;
01321 insn_b = if_info->insn_b;
01322
01323
01324
01325 if (insn_a)
01326 {
01327 insn_cost = insn_rtx_cost (PATTERN (insn_a));
01328 if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (BRANCH_COST))
01329 return FALSE;
01330 }
01331 else
01332 {
01333 insn_cost = 0;
01334 }
01335
01336 if (insn_b) {
01337 insn_cost += insn_rtx_cost (PATTERN (insn_b));
01338 if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (BRANCH_COST))
01339 return FALSE;
01340 }
01341
01342
01343 if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
01344 {
01345 int reversep = 0;
01346 if (rtx_equal_p (b, x))
01347 reversep = 1;
01348 else if (general_operand (b, GET_MODE (b)))
01349 reversep = 1;
01350
01351 if (reversep)
01352 {
01353 code = reversed_comparison_code (if_info->cond, if_info->jump);
01354 tmp = a, a = b, b = tmp;
01355 tmp = insn_a, insn_a = insn_b, insn_b = tmp;
01356 }
01357 }
01358
01359 start_sequence ();
01360
01361 orig_a = a;
01362 orig_b = b;
01363
01364
01365
01366
01367
01368 if (! general_operand (a, GET_MODE (a)))
01369 {
01370 rtx set;
01371
01372 if (no_new_pseudos)
01373 goto end_seq_and_fail;
01374
01375 if (is_mem)
01376 {
01377 tmp = gen_reg_rtx (GET_MODE (a));
01378 tmp = emit_insn (gen_rtx_SET (VOIDmode, tmp, a));
01379 }
01380 else if (! insn_a)
01381 goto end_seq_and_fail;
01382 else
01383 {
01384 a = gen_reg_rtx (GET_MODE (a));
01385 tmp = copy_rtx (insn_a);
01386 set = single_set (tmp);
01387 SET_DEST (set) = a;
01388 tmp = emit_insn (PATTERN (tmp));
01389 }
01390 if (recog_memoized (tmp) < 0)
01391 goto end_seq_and_fail;
01392 }
01393 if (! general_operand (b, GET_MODE (b)))
01394 {
01395 rtx set, last;
01396
01397 if (no_new_pseudos)
01398 goto end_seq_and_fail;
01399
01400 if (is_mem)
01401 {
01402 tmp = gen_reg_rtx (GET_MODE (b));
01403 tmp = gen_rtx_SET (VOIDmode, tmp, b);
01404 }
01405 else if (! insn_b)
01406 goto end_seq_and_fail;
01407 else
01408 {
01409 b = gen_reg_rtx (GET_MODE (b));
01410 tmp = copy_rtx (insn_b);
01411 set = single_set (tmp);
01412 SET_DEST (set) = b;
01413 tmp = PATTERN (tmp);
01414 }
01415
01416
01417
01418
01419 last = get_last_insn ();
01420 if (last && modified_in_p (orig_b, last))
01421 {
01422 tmp = emit_insn_before (tmp, get_insns ());
01423 if (modified_in_p (orig_a, tmp))
01424 goto end_seq_and_fail;
01425 }
01426 else
01427 tmp = emit_insn (tmp);
01428
01429 if (recog_memoized (tmp) < 0)
01430 goto end_seq_and_fail;
01431 }
01432
01433 target = noce_emit_cmove (if_info, x, code, XEXP (if_info->cond, 0),
01434 XEXP (if_info->cond, 1), a, b);
01435
01436 if (! target)
01437 goto end_seq_and_fail;
01438
01439
01440 if (is_mem)
01441 {
01442 tmp = gen_rtx_MEM (GET_MODE (if_info->x), target);
01443
01444
01445 if (MEM_VOLATILE_P (if_info->a) || MEM_VOLATILE_P (if_info->b))
01446 MEM_VOLATILE_P (tmp) = 1;
01447 if (MEM_IN_STRUCT_P (if_info->a) && MEM_IN_STRUCT_P (if_info->b))
01448 MEM_IN_STRUCT_P (tmp) = 1;
01449 if (MEM_SCALAR_P (if_info->a) && MEM_SCALAR_P (if_info->b))
01450 MEM_SCALAR_P (tmp) = 1;
01451 if (MEM_ALIAS_SET (if_info->a) == MEM_ALIAS_SET (if_info->b))
01452 set_mem_alias_set (tmp, MEM_ALIAS_SET (if_info->a));
01453 set_mem_align (tmp,
01454 MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b)));
01455
01456 noce_emit_move_insn (if_info->x, tmp);
01457 }
01458 else if (target != x)
01459 noce_emit_move_insn (x, target);
01460
01461 tmp = end_ifcvt_sequence (if_info);
01462 if (!tmp)
01463 return FALSE;
01464
01465 emit_insn_before_setloc (tmp, if_info->jump, INSN_LOCATOR (if_info->insn_a));
01466 return TRUE;
01467
01468 end_seq_and_fail:
01469 end_sequence ();
01470 return FALSE;
01471 }
01472
01473
01474
01475
01476
01477 static rtx
01478 noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
01479 rtx *earliest)
01480 {
01481 rtx cond, set, insn;
01482 int reverse;
01483
01484
01485 if (reg_mentioned_p (target, if_info->cond))
01486 {
01487 *earliest = if_info->cond_earliest;
01488 return if_info->cond;
01489 }
01490
01491 set = pc_set (if_info->jump);
01492 cond = XEXP (SET_SRC (set), 0);
01493 reverse
01494 = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
01495 && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump);
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511 if (GET_CODE (target) == CONST_INT)
01512 {
01513 enum rtx_code code = GET_CODE (if_info->cond);
01514 rtx op_a = XEXP (if_info->cond, 0);
01515 rtx op_b = XEXP (if_info->cond, 1);
01516 rtx prev_insn;
01517
01518
01519 prev_insn = prev_nonnote_insn (if_info->cond_earliest);
01520 if (prev_insn
01521 && INSN_P (prev_insn)
01522 && GET_CODE (PATTERN (prev_insn)) == SET)
01523 {
01524 rtx src = find_reg_equal_equiv_note (prev_insn);
01525 if (!src)
01526 src = SET_SRC (PATTERN (prev_insn));
01527 if (GET_CODE (src) == CONST_INT)
01528 {
01529 if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn))))
01530 op_a = src;
01531 else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn))))
01532 op_b = src;
01533
01534 if (GET_CODE (op_a) == CONST_INT)
01535 {
01536 rtx tmp = op_a;
01537 op_a = op_b;
01538 op_b = tmp;
01539 code = swap_condition (code);
01540 }
01541 }
01542 }
01543
01544
01545
01546 if (GET_CODE (op_b) == CONST_INT)
01547 {
01548 HOST_WIDE_INT desired_val = INTVAL (target);
01549 HOST_WIDE_INT actual_val = INTVAL (op_b);
01550
01551 switch (code)
01552 {
01553 case LT:
01554 if (actual_val == desired_val + 1)
01555 {
01556 code = LE;
01557 op_b = GEN_INT (desired_val);
01558 }
01559 break;
01560 case LE:
01561 if (actual_val == desired_val - 1)
01562 {
01563 code = LT;
01564 op_b = GEN_INT (desired_val);
01565 }
01566 break;
01567 case GT:
01568 if (actual_val == desired_val - 1)
01569 {
01570 code = GE;
01571 op_b = GEN_INT (desired_val);
01572 }
01573 break;
01574 case GE:
01575 if (actual_val == desired_val + 1)
01576 {
01577 code = GT;
01578 op_b = GEN_INT (desired_val);
01579 }
01580 break;
01581 default:
01582 break;
01583 }
01584 }
01585
01586
01587
01588
01589 if (code != GET_CODE (if_info->cond)
01590 || op_a != XEXP (if_info->cond, 0)
01591 || op_b != XEXP (if_info->cond, 1))
01592 {
01593 cond = gen_rtx_fmt_ee (code, GET_MODE (cond), op_a, op_b);
01594 *earliest = if_info->cond_earliest;
01595 return cond;
01596 }
01597 }
01598
01599 cond = canonicalize_condition (if_info->jump, cond, reverse,
01600 earliest, target, false, true);
01601 if (! cond || ! reg_mentioned_p (target, cond))
01602 return NULL;
01603
01604
01605
01606
01607
01608 for (insn = if_info->jump; insn != *earliest; insn = PREV_INSN (insn))
01609 if (INSN_P (insn) && reg_overlap_mentioned_p (if_info->x, PATTERN (insn)))
01610 return NULL;
01611
01612
01613 for (insn = *earliest; insn != if_info->jump; insn = NEXT_INSN (insn))
01614 if (INSN_P (insn)
01615 && (modified_in_p (if_info->a, insn)
01616 || modified_in_p (if_info->b, insn)))
01617 return NULL;
01618
01619 return cond;
01620 }
01621
01622
01623
01624 static int
01625 noce_try_minmax (struct noce_if_info *if_info)
01626 {
01627 rtx cond, earliest, target, seq;
01628 enum rtx_code code, op;
01629 int unsignedp;
01630
01631
01632 if (no_new_pseudos)
01633 return FALSE;
01634
01635
01636
01637
01638 if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x))
01639 || HONOR_NANS (GET_MODE (if_info->x)))
01640 return FALSE;
01641
01642 cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
01643 if (!cond)
01644 return FALSE;
01645
01646
01647
01648 code = GET_CODE (cond);
01649 if (rtx_equal_p (XEXP (cond, 0), if_info->a))
01650 {
01651 if (! rtx_equal_p (XEXP (cond, 1), if_info->b))
01652 return FALSE;
01653 }
01654 else if (rtx_equal_p (XEXP (cond, 1), if_info->a))
01655 {
01656 if (! rtx_equal_p (XEXP (cond, 0), if_info->b))
01657 return FALSE;
01658 code = swap_condition (code);
01659 }
01660 else
01661 return FALSE;
01662
01663
01664
01665 switch (code)
01666 {
01667 case LT:
01668 case LE:
01669 case UNLT:
01670 case UNLE:
01671 op = SMAX;
01672 unsignedp = 0;
01673 break;
01674 case GT:
01675 case GE:
01676 case UNGT:
01677 case UNGE:
01678 op = SMIN;
01679 unsignedp = 0;
01680 break;
01681 case LTU:
01682 case LEU:
01683 op = UMAX;
01684 unsignedp = 1;
01685 break;
01686 case GTU:
01687 case GEU:
01688 op = UMIN;
01689 unsignedp = 1;
01690 break;
01691 default:
01692 return FALSE;
01693 }
01694
01695 start_sequence ();
01696
01697 target = expand_simple_binop (GET_MODE (if_info->x), op,
01698 if_info->a, if_info->b,
01699 if_info->x, unsignedp, OPTAB_WIDEN);
01700 if (! target)
01701 {
01702 end_sequence ();
01703 return FALSE;
01704 }
01705 if (target != if_info->x)
01706 noce_emit_move_insn (if_info->x, target);
01707
01708 seq = end_ifcvt_sequence (if_info);
01709 if (!seq)
01710 return FALSE;
01711
01712 emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
01713 if_info->cond = cond;
01714 if_info->cond_earliest = earliest;
01715
01716 return TRUE;
01717 }
01718
01719
01720
01721 static int
01722 noce_try_abs (struct noce_if_info *if_info)
01723 {
01724 rtx cond, earliest, target, seq, a, b, c;
01725 int negate;
01726
01727
01728 if (no_new_pseudos)
01729 return FALSE;
01730
01731
01732
01733
01734 a = if_info->a;
01735 b = if_info->b;
01736 if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b))
01737 negate = 0;
01738 else if (GET_CODE (b) == NEG && rtx_equal_p (XEXP (b, 0), a))
01739 {
01740 c = a; a = b; b = c;
01741 negate = 1;
01742 }
01743 else
01744 return FALSE;
01745
01746 cond = noce_get_alt_condition (if_info, b, &earliest);
01747 if (!cond)
01748 return FALSE;
01749
01750
01751 if (rtx_equal_p (XEXP (cond, 0), b))
01752 c = XEXP (cond, 1);
01753 else if (rtx_equal_p (XEXP (cond, 1), b))
01754 {
01755 c = XEXP (cond, 0);
01756 negate = !negate;
01757 }
01758 else
01759 return FALSE;
01760
01761
01762
01763 if (REG_P (c))
01764 {
01765 rtx set, insn = prev_nonnote_insn (earliest);
01766 if (insn
01767 && (set = single_set (insn))
01768 && rtx_equal_p (SET_DEST (set), c))
01769 {
01770 rtx note = find_reg_equal_equiv_note (insn);
01771 if (note)
01772 c = XEXP (note, 0);
01773 else
01774 c = SET_SRC (set);
01775 }
01776 else
01777 return FALSE;
01778 }
01779 if (MEM_P (c)
01780 && GET_CODE (XEXP (c, 0)) == SYMBOL_REF
01781 && CONSTANT_POOL_ADDRESS_P (XEXP (c, 0)))
01782 c = get_pool_constant (XEXP (c, 0));
01783
01784
01785
01786
01787 if (c == constm1_rtx && GET_CODE (cond) == GT)
01788 ;
01789 else if (c == const1_rtx && GET_CODE (cond) == LT)
01790 ;
01791 else if (c != CONST0_RTX (GET_MODE (b)))
01792 return FALSE;
01793
01794
01795 switch (GET_CODE (cond))
01796 {
01797 case LT:
01798 case LE:
01799 case UNLT:
01800 case UNLE:
01801 negate = !negate;
01802 break;
01803 case GT:
01804 case GE:
01805 case UNGT:
01806 case UNGE:
01807 break;
01808 default:
01809 return FALSE;
01810 }
01811
01812 start_sequence ();
01813
01814 target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1);
01815
01816
01817
01818 if (target && negate)
01819 target = expand_simple_unop (GET_MODE (target), NEG, target, if_info->x, 0);
01820
01821 if (! target)
01822 {
01823 end_sequence ();
01824 return FALSE;
01825 }
01826
01827 if (target != if_info->x)
01828 noce_emit_move_insn (if_info->x, target);
01829
01830 seq = end_ifcvt_sequence (if_info);
01831 if (!seq)
01832 return FALSE;
01833
01834 emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
01835 if_info->cond = cond;
01836 if_info->cond_earliest = earliest;
01837
01838 return TRUE;
01839 }
01840
01841
01842
01843 static int
01844 noce_try_sign_mask (struct noce_if_info *if_info)
01845 {
01846 rtx cond, t, m, c, seq;
01847 enum machine_mode mode;
01848 enum rtx_code code;
01849
01850 if (no_new_pseudos)
01851 return FALSE;
01852
01853 cond = if_info->cond;
01854 code = GET_CODE (cond);
01855 m = XEXP (cond, 0);
01856 c = XEXP (cond, 1);
01857
01858 t = NULL_RTX;
01859 if (if_info->a == const0_rtx)
01860 {
01861 if ((code == LT && c == const0_rtx)
01862 || (code == LE && c == constm1_rtx))
01863 t = if_info->b;
01864 }
01865 else if (if_info->b == const0_rtx)
01866 {
01867 if ((code == GE && c == const0_rtx)
01868 || (code == GT && c == constm1_rtx))
01869 t = if_info->a;
01870 }
01871
01872 if (! t || side_effects_p (t))
01873 return FALSE;
01874
01875
01876 mode = GET_MODE (t);
01877 if (GET_MODE (m) != mode)
01878 return FALSE;
01879
01880
01881
01882 if (rtx_cost (t, SET) >= COSTS_N_INSNS (2)
01883 && (!if_info->b_unconditional
01884 || t != if_info->b))
01885 return FALSE;
01886
01887 start_sequence ();
01888
01889
01890
01891 m = emit_store_flag (gen_reg_rtx (mode), LT, m, const0_rtx, mode, 0, -1);
01892 t = m ? expand_binop (mode, and_optab, m, t, NULL_RTX, 0, OPTAB_DIRECT)
01893 : NULL_RTX;
01894
01895 if (!t)
01896 {
01897 end_sequence ();
01898 return FALSE;
01899 }
01900
01901 noce_emit_move_insn (if_info->x, t);
01902
01903 seq = end_ifcvt_sequence (if_info);
01904 if (!seq)
01905 return FALSE;
01906
01907 emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
01908 return TRUE;
01909 }
01910
01911
01912
01913
01914
01915 static int
01916 noce_try_bitop (struct noce_if_info *if_info)
01917 {
01918 rtx cond, x, a, result, seq;
01919 enum machine_mode mode;
01920 enum rtx_code code;
01921 int bitnum;
01922
01923 x = if_info->x;
01924 cond = if_info->cond;
01925 code = GET_CODE (cond);
01926
01927
01928 if (! rtx_equal_p (x, if_info->b))
01929 return FALSE;
01930
01931
01932 if (code != NE && code != EQ)
01933 return FALSE;
01934 if (XEXP (cond, 1) != const0_rtx)
01935 return FALSE;
01936 cond = XEXP (cond, 0);
01937
01938
01939 if (GET_CODE (cond) == ZERO_EXTRACT)
01940 {
01941 if (XEXP (cond, 1) != const1_rtx
01942 || GET_CODE (XEXP (cond, 2)) != CONST_INT
01943 || ! rtx_equal_p (x, XEXP (cond, 0)))
01944 return FALSE;
01945 bitnum = INTVAL (XEXP (cond, 2));
01946 mode = GET_MODE (x);
01947 if (BITS_BIG_ENDIAN)
01948 bitnum = GET_MODE_BITSIZE (mode) - 1 - bitnum;
01949 if (bitnum < 0 || bitnum >= HOST_BITS_PER_WIDE_INT)
01950 return FALSE;
01951 }
01952 else
01953 return FALSE;
01954
01955 a = if_info->a;
01956 if (GET_CODE (a) == IOR || GET_CODE (a) == XOR)
01957 {
01958
01959 if (! rtx_equal_p (x, XEXP (a, 0))
01960 || GET_CODE (XEXP (a, 1)) != CONST_INT
01961 || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
01962 != (unsigned HOST_WIDE_INT) 1 << bitnum)
01963 return FALSE;
01964
01965
01966
01967 if (GET_CODE (a) == IOR)
01968 result = (code == NE) ? a : NULL_RTX;
01969 else if (code == NE)
01970 {
01971
01972 result = gen_int_mode ((HOST_WIDE_INT) 1 << bitnum, mode);
01973 result = simplify_gen_binary (IOR, mode, x, result);
01974 }
01975 else
01976 {
01977
01978 result = gen_int_mode (~((HOST_WIDE_INT) 1 << bitnum), mode);
01979 result = simplify_gen_binary (AND, mode, x, result);
01980 }
01981 }
01982 else if (GET_CODE (a) == AND)
01983 {
01984
01985 if (! rtx_equal_p (x, XEXP (a, 0))
01986 || GET_CODE (XEXP (a, 1)) != CONST_INT
01987 || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
01988 != (~((HOST_WIDE_INT) 1 << bitnum) & GET_MODE_MASK (mode)))
01989 return FALSE;
01990
01991
01992
01993 result = (code == EQ) ? a : NULL_RTX;
01994 }
01995 else
01996 return FALSE;
01997
01998 if (result)
01999 {
02000 start_sequence ();
02001 noce_emit_move_insn (x, result);
02002 seq = end_ifcvt_sequence (if_info);
02003 if (!seq)
02004 return FALSE;
02005
02006 emit_insn_before_setloc (seq, if_info->jump,
02007 INSN_LOCATOR (if_info->insn_a));
02008 }
02009 return TRUE;
02010 }
02011
02012
02013
02014
02015
02016 static rtx
02017 noce_get_condition (rtx jump, rtx *earliest)
02018 {
02019 rtx cond, set, tmp;
02020 bool reverse;
02021
02022 if (! any_condjump_p (jump))
02023 return NULL_RTX;
02024
02025 set = pc_set (jump);
02026
02027
02028
02029 reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
02030 && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump));
02031
02032
02033
02034 cond = XEXP (SET_SRC (set), 0);
02035 tmp = XEXP (cond, 0);
02036 if (REG_P (tmp) && GET_MODE_CLASS (GET_MODE (tmp)) == MODE_INT)
02037 {
02038 *earliest = jump;
02039
02040 if (reverse)
02041 cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
02042 GET_MODE (cond), tmp, XEXP (cond, 1));
02043 return cond;
02044 }
02045
02046
02047
02048 return canonicalize_condition (jump, cond, reverse, earliest,
02049 NULL_RTX, false, true);
02050 }
02051
02052
02053
02054
02055
02056
02057 static int
02058 noce_init_if_info (struct ce_if_block *ce_info, struct noce_if_info *if_info)
02059 {
02060 basic_block test_bb = ce_info->test_bb;
02061 rtx cond, jump;
02062
02063
02064
02065 if (ce_info->num_multiple_test_blocks)
02066 {
02067 if (ce_info->else_bb || !ce_info->and_and_p)
02068 return FALSE;
02069
02070 ce_info->test_bb = test_bb = ce_info->last_test_bb;
02071 ce_info->num_multiple_test_blocks = 0;
02072 ce_info->num_and_and_blocks = 0;
02073 ce_info->num_or_or_blocks = 0;
02074 }
02075
02076
02077 jump = BB_END (test_bb);
02078 cond = noce_get_condition (jump, &if_info->cond_earliest);
02079 if (!cond)
02080 return FALSE;
02081
02082
02083
02084 if (! onlyjump_p (jump))
02085 return FALSE;
02086
02087
02088 if (GET_MODE (XEXP (cond, 0)) == BLKmode)
02089 return FALSE;
02090
02091 if_info->test_bb = test_bb;
02092 if_info->cond = cond;
02093 if_info->jump = jump;
02094
02095 return TRUE;
02096 }
02097
02098
02099
02100 static int
02101 noce_operand_ok (rtx op)
02102 {
02103
02104
02105 if (MEM_P (op))
02106 return ! side_effects_p (XEXP (op, 0));
02107
02108 if (side_effects_p (op))
02109 return FALSE;
02110
02111 return ! may_trap_p (op);
02112 }
02113
02114
02115
02116 static bool
02117 noce_mem_write_may_trap_or_fault_p (rtx mem)
02118 {
02119 rtx addr;
02120
02121 if (MEM_READONLY_P (mem))
02122 return true;
02123
02124 if (may_trap_or_fault_p (mem))
02125 return true;
02126
02127 addr = XEXP (mem, 0);
02128
02129
02130 addr = targetm.delegitimize_address (addr);
02131
02132 while (addr)
02133 switch (GET_CODE (addr))
02134 {
02135 case CONST:
02136 case PRE_DEC:
02137 case PRE_INC:
02138 case POST_DEC:
02139 case POST_INC:
02140 case POST_MODIFY:
02141 addr = XEXP (addr, 0);
02142 break;
02143 case LO_SUM:
02144 case PRE_MODIFY:
02145 addr = XEXP (addr, 1);
02146 break;
02147 case PLUS:
02148 if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
02149 addr = XEXP (addr, 0);
02150 else
02151 return false;
02152 break;
02153 case LABEL_REF:
02154 return true;
02155 case SYMBOL_REF:
02156 if (SYMBOL_REF_DECL (addr)
02157 && decl_readonly_section (SYMBOL_REF_DECL (addr), 0))
02158 return true;
02159 return false;
02160 default:
02161 return false;
02162 }
02163
02164 return false;
02165 }
02166
02167
02168
02169
02170
02171 static int
02172 noce_process_if_block (struct ce_if_block * ce_info)
02173 {
02174 basic_block test_bb = ce_info->test_bb;
02175 basic_block then_bb = ce_info->then_bb;
02176 basic_block else_bb = ce_info->else_bb;
02177 struct noce_if_info if_info;
02178 rtx insn_a, insn_b;
02179 rtx set_a, set_b;
02180 rtx orig_x, x, a, b;
02181 rtx jump, cond;
02182
02183
02184
02185
02186
02187
02188
02189
02190
02191
02192
02193 if (!noce_init_if_info (ce_info, &if_info))
02194 return FALSE;
02195
02196 cond = if_info.cond;
02197 jump = if_info.jump;
02198
02199
02200 insn_a = first_active_insn (then_bb);
02201 if (! insn_a
02202 || insn_a != last_active_insn (then_bb, FALSE)
02203 || (set_a = single_set (insn_a)) == NULL_RTX)
02204 return FALSE;
02205
02206 x = SET_DEST (set_a);
02207 a = SET_SRC (set_a);
02208
02209
02210
02211
02212
02213
02214
02215
02216 set_b = NULL_RTX;
02217 if (else_bb)
02218 {
02219 insn_b = first_active_insn (else_bb);
02220 if (! insn_b
02221 || insn_b != last_active_insn (else_bb, FALSE)
02222 || (set_b = single_set (insn_b)) == NULL_RTX
02223 || ! rtx_equal_p (x, SET_DEST (set_b)))
02224 return FALSE;
02225 }
02226 else
02227 {
02228 insn_b = prev_nonnote_insn (if_info.cond_earliest);
02229
02230
02231
02232 if (! insn_b
02233 || !NONJUMP_INSN_P (insn_b)
02234 || (set_b = single_set (insn_b)) == NULL_RTX
02235 || ! rtx_equal_p (x, SET_DEST (set_b))
02236 || reg_overlap_mentioned_p (x, SET_SRC (set_b))
02237 || modified_between_p (SET_SRC (set_b),
02238 PREV_INSN (if_info.cond_earliest), jump)
02239
02240
02241
02242 || reg_overlap_mentioned_p (x, cond)
02243 || reg_overlap_mentioned_p (x, a)
02244 || modified_between_p (x, PREV_INSN (if_info.cond_earliest), jump))
02245 insn_b = set_b = NULL_RTX;
02246 }
02247
02248
02249
02250
02251
02252
02253 if (side_effects_p (x))
02254 return FALSE;
02255
02256 b = (set_b ? SET_SRC (set_b) : x);
02257
02258
02259
02260 orig_x = x;
02261 if (!REG_P (x)
02262 || (SMALL_REGISTER_CLASSES
02263 && REGNO (x) < FIRST_PSEUDO_REGISTER))
02264 {
02265 if (no_new_pseudos || GET_MODE (x) == BLKmode)
02266 return FALSE;
02267
02268 if (GET_MODE (x) == ZERO_EXTRACT
02269 && (GET_CODE (XEXP (x, 1)) != CONST_INT
02270 || GET_CODE (XEXP (x, 2)) != CONST_INT))
02271 return FALSE;
02272
02273 x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
02274 ? XEXP (x, 0) : x));
02275 }
02276
02277
02278 if (! noce_operand_ok (a) || ! noce_operand_ok (b))
02279 return FALSE;
02280
02281
02282 if_info.insn_a = insn_a;
02283 if_info.insn_b = insn_b;
02284 if_info.x = x;
02285 if_info.a = a;
02286 if_info.b = b;
02287 if_info.b_unconditional = else_bb == 0;
02288
02289
02290
02291
02292
02293
02294
02295 if (rtx_equal_p (a, b))
02296 {
02297
02298
02299
02300
02301 if (insn_b && else_bb)
02302 {
02303 rtx note;
02304
02305 if (else_bb && insn_b == BB_END (else_bb))
02306 BB_END (else_bb) = PREV_INSN (insn_b);
02307 reorder_insns (insn_b, insn_b, PREV_INSN (jump));
02308
02309
02310
02311 if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0)
02312 remove_note (insn_b, note);
02313
02314 insn_b = NULL_RTX;
02315 }
02316
02317
02318 else if (insn_b && side_effects_p (orig_x))
02319 return FALSE;
02320
02321 x = orig_x;
02322 goto success;
02323 }
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334 if (!set_b && MEM_P (orig_x) && noce_mem_write_may_trap_or_fault_p (orig_x))
02335 return FALSE;
02336
02337 if (noce_try_move (&if_info))
02338 goto success;
02339 if (noce_try_store_flag (&if_info))
02340 goto success;
02341 if (noce_try_bitop (&if_info))
02342 goto success;
02343 if (noce_try_minmax (&if_info))
02344 goto success;
02345 if (noce_try_abs (&if_info))
02346 goto success;
02347 if (HAVE_conditional_move
02348 && noce_try_cmove (&if_info))
02349 goto success;
02350 if (! HAVE_conditional_execution)
02351 {
02352 if (noce_try_store_flag_constants (&if_info))
02353 goto success;
02354 if (noce_try_addcc (&if_info))
02355 goto success;
02356 if (noce_try_store_flag_mask (&if_info))
02357 goto success;
02358 if (HAVE_conditional_move
02359 && noce_try_cmove_arith (&if_info))
02360 goto success;
02361 if (noce_try_sign_mask (&if_info))
02362 goto success;
02363 }
02364
02365 return FALSE;
02366
02367 success:
02368
02369 delete_insn (insn_a);
02370
02371
02372
02373
02374
02375
02376
02377 if (insn_b && else_bb)
02378 delete_insn (insn_b);
02379
02380
02381
02382
02383 delete_insn (jump);
02384
02385
02386 if (orig_x != x)
02387 {
02388 start_sequence ();
02389 noce_emit_move_insn (orig_x, x);
02390 insn_b = get_insns ();
02391 set_used_flags (orig_x);
02392 unshare_all_rtl_in_chain (insn_b);
02393 end_sequence ();
02394
02395 emit_insn_after_setloc (insn_b, BB_END (test_bb), INSN_LOCATOR (insn_a));
02396 }
02397
02398
02399 merge_if_block (ce_info);
02400
02401 return TRUE;
02402 }
02403
02404
02405
02406
02407
02408
02409
02410 static int
02411 check_cond_move_block (basic_block bb, rtx *vals, rtx cond)
02412 {
02413 rtx insn;
02414
02415 FOR_BB_INSNS (bb, insn)
02416 {
02417 rtx set, dest, src;
02418
02419 if (!INSN_P (insn) || JUMP_P (insn))
02420 continue;
02421 set = single_set (insn);
02422 if (!set)
02423 return FALSE;
02424
02425 dest = SET_DEST (set);
02426 src = SET_SRC (set);
02427 if (!REG_P (dest)
02428 || (SMALL_REGISTER_CLASSES && HARD_REGISTER_P (dest)))
02429 return FALSE;
02430
02431 if (!CONSTANT_P (src) && !register_operand (src, VOIDmode))
02432 return FALSE;
02433
02434 if (side_effects_p (src) || side_effects_p (dest))
02435 return FALSE;
02436
02437 if (may_trap_p (src) || may_trap_p (dest))
02438 return FALSE;
02439
02440
02441
02442 if ((REG_P (src)
02443 && vals[REGNO (src)] != NULL)
02444 || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src))
02445 && vals[REGNO (SUBREG_REG (src))] != NULL))
02446 return FALSE;
02447
02448
02449
02450 if (vals[REGNO (dest)] != NULL)
02451 return FALSE;
02452
02453
02454
02455 if (reg_overlap_mentioned_p (dest, cond))
02456 return FALSE;
02457
02458 vals[REGNO (dest)] = src;
02459
02460
02461
02462 if (!CONSTANT_P (src)
02463 && modified_between_p (src, insn, NEXT_INSN (BB_END (bb))))
02464 return FALSE;
02465 }
02466
02467 return TRUE;
02468 }
02469
02470
02471
02472
02473
02474 static int
02475 cond_move_process_if_block (struct ce_if_block *ce_info)
02476 {
02477 basic_block then_bb = ce_info->then_bb;
02478 basic_block else_bb = ce_info->else_bb;
02479 struct noce_if_info if_info;
02480 rtx jump, cond, insn, seq, cond_arg0, cond_arg1, loc_insn;
02481 int max_reg, size, c, i;
02482 rtx *then_vals;
02483 rtx *else_vals;
02484 enum rtx_code code;
02485
02486 if (!HAVE_conditional_move || no_new_pseudos)
02487 return FALSE;
02488
02489 memset (&if_info, 0, sizeof if_info);
02490
02491 if (!noce_init_if_info (ce_info, &if_info))
02492 return FALSE;
02493
02494 cond = if_info.cond;
02495 jump = if_info.jump;
02496
02497
02498
02499 max_reg = max_reg_num ();
02500 size = (max_reg + 1) * sizeof (rtx);
02501 then_vals = (rtx *) alloca (size);
02502 else_vals = (rtx *) alloca (size);
02503 memset (then_vals, 0, size);
02504 memset (else_vals, 0, size);
02505
02506
02507 if (!check_cond_move_block (then_bb, then_vals, cond)
02508 || (else_bb && !check_cond_move_block (else_bb, else_vals, cond)))
02509 return FALSE;
02510
02511
02512
02513
02514
02515
02516
02517 c = 0;
02518 for (i = 0; i <= max_reg; ++i)
02519 {
02520 if (!then_vals[i] && !else_vals[i])
02521 continue;
02522
02523 if (!then_vals[i] || !else_vals[i])
02524 ++c;
02525 else
02526 {
02527 if (!CONSTANT_P (then_vals[i])
02528 && !CONSTANT_P (else_vals[i])
02529 && !rtx_equal_p (then_vals[i], else_vals[i]))
02530 return FALSE;
02531 }
02532 }
02533
02534
02535
02536
02537
02538 if (c > MAX_CONDITIONAL_EXECUTE)
02539 return FALSE;
02540
02541
02542
02543
02544 code = GET_CODE (cond);
02545 cond_arg0 = XEXP (cond, 0);
02546 cond_arg1 = XEXP (cond, 1);
02547
02548 start_sequence ();
02549
02550 FOR_BB_INSNS (then_bb, insn)
02551 {
02552 rtx set, target, dest, t, e;
02553 unsigned int regno;
02554
02555 if (!INSN_P (insn) || JUMP_P (insn))
02556 continue;
02557 set = single_set (insn);
02558 gcc_assert (set && REG_P (SET_DEST (set)));
02559
02560 dest = SET_DEST (set);
02561 regno = REGNO (dest);
02562 t = then_vals[regno];
02563 e = else_vals[regno];
02564 gcc_assert (t);
02565 if (!e)
02566 e = dest;
02567 target = noce_emit_cmove (&if_info, dest, code, cond_arg0, cond_arg1,
02568 t, e);
02569 if (!target)
02570 {
02571 end_sequence ();
02572 return FALSE;
02573 }
02574
02575 if (target != dest)
02576 noce_emit_move_insn (dest, target);
02577 }
02578
02579 if (else_bb)
02580 {
02581 FOR_BB_INSNS (else_bb, insn)
02582 {
02583 rtx set, target, dest;
02584 unsigned int regno;
02585
02586 if (!INSN_P (insn) || JUMP_P (insn))
02587 continue;
02588 set = single_set (insn);
02589 gcc_assert (set && REG_P (SET_DEST (set)));
02590
02591 dest = SET_DEST (set);
02592 regno = REGNO (dest);
02593
02594
02595
02596 if (then_vals[regno])
02597 continue;
02598 gcc_assert (else_vals[regno]);
02599
02600 target = noce_emit_cmove (&if_info, dest, code, cond_arg0, cond_arg1,
02601 dest, else_vals[regno]);
02602 if (!target)
02603 {
02604 end_sequence ();
02605 return FALSE;
02606 }
02607
02608 if (target != dest)
02609 noce_emit_move_insn (dest, target);
02610 }
02611 }
02612
02613 seq = end_ifcvt_sequence (&if_info);
02614 if (!seq)
02615 return FALSE;
02616
02617 loc_insn = first_active_insn (then_bb);
02618 if (!loc_insn)
02619 {
02620 loc_insn = first_active_insn (else_bb);
02621 gcc_assert (loc_insn);
02622 }
02623 emit_insn_before_setloc (seq, jump, INSN_LOCATOR (loc_insn));
02624
02625 FOR_BB_INSNS (then_bb, insn)
02626 if (INSN_P (insn) && !JUMP_P (insn))
02627 delete_insn (insn);
02628 if (else_bb)
02629 {
02630 FOR_BB_INSNS (else_bb, insn)
02631 if (INSN_P (insn) && !JUMP_P (insn))
02632 delete_insn (insn);
02633 }
02634 delete_insn (jump);
02635
02636 merge_if_block (ce_info);
02637
02638 return TRUE;
02639 }
02640
02641
02642
02643
02644 static int
02645 process_if_block (struct ce_if_block * ce_info)
02646 {
02647 if (! reload_completed
02648 && noce_process_if_block (ce_info))
02649 return TRUE;
02650
02651 if (HAVE_conditional_move
02652 && cond_move_process_if_block (ce_info))
02653 return TRUE;
02654
02655 if (HAVE_conditional_execution && reload_completed)
02656 {
02657
02658
02659
02660
02661 if (cond_exec_process_if_block (ce_info, TRUE))
02662 return TRUE;
02663
02664 if (ce_info->num_multiple_test_blocks)
02665 {
02666 cancel_changes (0);
02667
02668 if (cond_exec_process_if_block (ce_info, FALSE))
02669 return TRUE;
02670 }
02671 }
02672
02673 return FALSE;
02674 }
02675
02676
02677
02678 static void
02679 merge_if_block (struct ce_if_block * ce_info)
02680 {
02681 basic_block test_bb = ce_info->test_bb;
02682 basic_block then_bb = ce_info->then_bb;
02683 basic_block else_bb = ce_info->else_bb;
02684 basic_block join_bb = ce_info->join_bb;
02685 basic_block combo_bb;
02686
02687
02688
02689 combo_bb = test_bb;
02690
02691
02692
02693 if (ce_info->num_multiple_test_blocks > 0)
02694 {
02695 basic_block bb = test_bb;
02696 basic_block last_test_bb = ce_info->last_test_bb;
02697 basic_block fallthru = block_fallthru (bb);
02698
02699 do
02700 {
02701 bb = fallthru;
02702 fallthru = block_fallthru (bb);
02703 merge_blocks (combo_bb, bb);
02704 num_true_changes++;
02705 }
02706 while (bb != last_test_bb);
02707 }
02708
02709
02710
02711
02712
02713 if (then_bb)
02714 {
02715 if (combo_bb->il.rtl->global_live_at_end)
02716 COPY_REG_SET (combo_bb->il.rtl->global_live_at_end,
02717 then_bb->il.rtl->global_live_at_end);
02718 merge_blocks (combo_bb, then_bb);
02719 num_true_changes++;
02720 }
02721
02722
02723
02724
02725 if (else_bb)
02726 {
02727 merge_blocks (combo_bb, else_bb);
02728 num_true_changes++;
02729 }
02730
02731
02732
02733
02734 if (! join_bb)
02735 {
02736 rtx last = BB_END (combo_bb);
02737
02738
02739
02740 if (EDGE_COUNT (combo_bb->succs) == 0)
02741 gcc_assert (find_reg_note (last, REG_NORETURN, NULL)
02742 || (NONJUMP_INSN_P (last)
02743 && GET_CODE (PATTERN (last)) == TRAP_IF
02744 && (TRAP_CONDITION (PATTERN (last))
02745 == const_true_rtx)));
02746
02747 else
02748
02749
02750 gcc_assert (JUMP_P (last)
02751 || (EDGE_SUCC (combo_bb, 0)->dest == EXIT_BLOCK_PTR
02752 && CALL_P (last)
02753 && SIBLING_CALL_P (last))
02754 || ((EDGE_SUCC (combo_bb, 0)->flags & EDGE_EH)
02755 && can_throw_internal (last)));
02756 }
02757
02758
02759
02760
02761
02762
02763
02764 else if (EDGE_COUNT (join_bb->preds) < 2
02765 && join_bb != EXIT_BLOCK_PTR)
02766 {
02767
02768 if (combo_bb->il.rtl->global_live_at_end)
02769 COPY_REG_SET (combo_bb->il.rtl->global_live_at_end,
02770 join_bb->il.rtl->global_live_at_end);
02771
02772 merge_blocks (combo_bb, join_bb);
02773 num_true_changes++;
02774 }
02775 else
02776 {
02777
02778
02779
02780
02781 gcc_assert (single_succ_p (combo_bb)
02782 && single_succ (combo_bb) == join_bb);
02783
02784
02785 if (join_bb != EXIT_BLOCK_PTR)
02786 tidy_fallthru_edge (single_succ_edge (combo_bb));
02787 }
02788
02789 num_updated_if_blocks++;
02790 }
02791
02792
02793
02794
02795
02796
02797 static basic_block
02798 find_if_header (basic_block test_bb, int pass)
02799 {
02800 ce_if_block_t ce_info;
02801 edge then_edge;
02802 edge else_edge;
02803
02804
02805 if (EDGE_COUNT (test_bb->succs) != 2)
02806 return NULL;
02807
02808 then_edge = EDGE_SUCC (test_bb, 0);
02809 else_edge = EDGE_SUCC (test_bb, 1);
02810
02811
02812 if ((then_edge->flags & EDGE_COMPLEX)
02813 || (else_edge->flags & EDGE_COMPLEX))
02814 return NULL;
02815
02816
02817 if ((then_edge->flags & EDGE_LOOP_EXIT)
02818 || (else_edge->flags & EDGE_LOOP_EXIT))
02819 return NULL;
02820
02821
02822 if (then_edge->flags & EDGE_FALLTHRU)
02823 ;
02824 else if (else_edge->flags & EDGE_FALLTHRU)
02825 {
02826 edge e = else_edge;
02827 else_edge = then_edge;
02828 then_edge = e;
02829 }
02830 else
02831
02832 return NULL;
02833
02834 memset (&ce_info, '\0', sizeof (ce_info));
02835 ce_info.test_bb = test_bb;
02836 ce_info.then_bb = then_edge->dest;
02837 ce_info.else_bb = else_edge->dest;
02838 ce_info.pass = pass;
02839
02840 #ifdef IFCVT_INIT_EXTRA_FIELDS
02841 IFCVT_INIT_EXTRA_FIELDS (&ce_info);
02842 #endif
02843
02844 if (find_if_block (&ce_info))
02845 goto success;
02846
02847 if (HAVE_trap && HAVE_conditional_trap
02848 && find_cond_trap (test_bb, then_edge, else_edge))
02849 goto success;
02850
02851 if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY
02852 && (! HAVE_conditional_execution || reload_completed))
02853 {
02854 if (find_if_case_1 (test_bb, then_edge, else_edge))
02855 goto success;
02856 if (find_if_case_2 (test_bb, then_edge, else_edge))
02857 goto success;
02858 }
02859
02860 return NULL;
02861
02862 success:
02863 if (dump_file)
02864 fprintf (dump_file, "Conversion succeeded on pass %d.\n", pass);
02865 return ce_info.test_bb;
02866 }
02867
02868
02869
02870
02871
02872
02873 static int
02874 block_jumps_and_fallthru_p (basic_block cur_bb, basic_block target_bb)
02875 {
02876 edge cur_edge;
02877 int fallthru_p = FALSE;
02878 int jump_p = FALSE;
02879 rtx insn;
02880 rtx end;
02881 int n_insns = 0;
02882 edge_iterator ei;
02883
02884 if (!cur_bb || !target_bb)
02885 return -1;
02886
02887
02888 if (EDGE_COUNT (cur_bb->succs) == 0)
02889 return FALSE;
02890
02891 FOR_EACH_EDGE (cur_edge, ei, cur_bb->succs)
02892 {
02893 if (cur_edge->flags & EDGE_COMPLEX)
02894
02895 return -1;
02896
02897 else if (cur_edge->flags & EDGE_FALLTHRU)
02898 fallthru_p = TRUE;
02899
02900 else if (cur_edge->dest == target_bb)
02901 jump_p = TRUE;
02902
02903 else
02904 return -1;
02905 }
02906
02907 if ((jump_p & fallthru_p) == 0)
02908 return -1;
02909
02910
02911
02912
02913
02914 end = BB_END (cur_bb);
02915 insn = BB_HEAD (cur_bb);
02916
02917 while (insn != NULL_RTX)
02918 {
02919 if (CALL_P (insn))
02920 return -1;
02921
02922 if (INSN_P (insn)
02923 && !JUMP_P (insn)
02924 && GET_CODE (PATTERN (insn)) != USE
02925 && GET_CODE (PATTERN (insn)) != CLOBBER)
02926 n_insns++;
02927
02928 if (insn == end)
02929 break;
02930
02931 insn = NEXT_INSN (insn);
02932 }
02933
02934 return n_insns;
02935 }
02936
02937
02938
02939
02940
02941 static int
02942 find_if_block (struct ce_if_block * ce_info)
02943 {
02944 basic_block test_bb = ce_info->test_bb;
02945 basic_block then_bb = ce_info->then_bb;
02946 basic_block else_bb = ce_info->else_bb;
02947 basic_block join_bb = NULL_BLOCK;
02948 edge cur_edge;
02949 basic_block next;
02950 edge_iterator ei;
02951
02952 ce_info->last_test_bb = test_bb;
02953
02954
02955
02956
02957 if (HAVE_conditional_execution && reload_completed
02958 && single_pred_p (test_bb)
02959 && single_pred_edge (test_bb)->flags == EDGE_FALLTHRU)
02960 {
02961 basic_block bb = single_pred (test_bb);
02962 basic_block target_bb;
02963 int max_insns = MAX_CONDITIONAL_EXECUTE;
02964 int n_insns;
02965
02966
02967 if ((n_insns = block_jumps_and_fallthru_p (bb, else_bb)) >= 0)
02968 {
02969 ce_info->and_and_p = TRUE;
02970 target_bb = else_bb;
02971 }
02972 else if ((n_insns = block_jumps_and_fallthru_p (bb, then_bb)) >= 0)
02973 {
02974 ce_info->and_and_p = FALSE;
02975 target_bb = then_bb;
02976 }
02977 else
02978 target_bb = NULL_BLOCK;
02979
02980 if (target_bb && n_insns <= max_insns)
02981 {
02982 int total_insns = 0;
02983 int blocks = 0;
02984
02985 ce_info->last_test_bb = test_bb;
02986
02987
02988 do
02989 {
02990 ce_info->test_bb = test_bb = bb;
02991 total_insns += n_insns;
02992 blocks++;
02993
02994 if (!single_pred_p (bb))
02995 break;
02996
02997 bb = single_pred (bb);
02998 n_insns = block_jumps_and_fallthru_p (bb, target_bb);
02999 }
03000 while (n_insns >= 0 && (total_insns + n_insns) <= max_insns);
03001
03002 ce_info->num_multiple_test_blocks = blocks;
03003 ce_info->num_multiple_test_insns = total_insns;
03004
03005 if (ce_info->and_and_p)
03006 ce_info->num_and_and_blocks = blocks;
03007 else
03008 ce_info->num_or_or_blocks = blocks;
03009 }
03010 }
03011
03012
03013
03014 if ((EDGE_COUNT (then_bb->preds) - ce_info->num_or_or_blocks) != 1)
03015 return FALSE;
03016
03017
03018 FOR_EACH_EDGE (cur_edge, ei, then_bb->preds)
03019 {
03020 if (cur_edge->flags & EDGE_COMPLEX)
03021 return FALSE;
03022 }
03023
03024 FOR_EACH_EDGE (cur_edge, ei, else_bb->preds)
03025 {
03026 if (cur_edge->flags & EDGE_COMPLEX)
03027 return FALSE;
03028 }
03029
03030
03031 if (EDGE_COUNT (then_bb->succs) > 0
03032 && (!single_succ_p (then_bb)
03033 || (single_succ_edge (then_bb)->flags & EDGE_COMPLEX)
03034 || (flow2_completed && tablejump_p (BB_END (then_bb), NULL, NULL))))
03035 return FALSE;
03036
03037
03038
03039
03040
03041
03042
03043 if (EDGE_COUNT (then_bb->succs) == 0)
03044 {
03045 if (single_pred_p (else_bb))
03046 {
03047 rtx last_insn = BB_END (then_bb);
03048
03049 while (last_insn
03050 && NOTE_P (last_insn)
03051 && last_insn != BB_HEAD (then_bb))
03052 last_insn = PREV_INSN (last_insn);
03053
03054 if (last_insn
03055 && JUMP_P (last_insn)
03056 && ! simplejump_p (last_insn))
03057 return FALSE;
03058
03059 join_bb = else_bb;
03060 else_bb = NULL_BLOCK;
03061 }
03062 else
03063 return FALSE;
03064 }
03065
03066
03067
03068 else if (single_succ (then_bb) == else_bb)
03069 {
03070 join_bb = else_bb;
03071 else_bb = NULL_BLOCK;
03072 }
03073
03074
03075
03076
03077 else if (single_succ_p (else_bb)
03078 && single_succ (then_bb) == single_succ (else_bb)
03079 && single_pred_p (else_bb)
03080 && ! (single_succ_edge (else_bb)->flags & EDGE_COMPLEX)
03081 && ! (flow2_completed && tablejump_p (BB_END (else_bb), NULL, NULL)))
03082 join_bb = single_succ (else_bb);
03083
03084
03085 else
03086 return FALSE;
03087
03088 num_possible_if_blocks++;
03089
03090 if (dump_file)
03091 {
03092 fprintf (dump_file,
03093 "\nIF-THEN%s block found, pass %d, start block %d "
03094 "[insn %d], then %d [%d]",
03095 (else_bb) ? "-ELSE" : "",
03096 ce_info->pass,
03097 test_bb->index,
03098 BB_HEAD (test_bb) ? (int)INSN_UID (BB_HEAD (test_bb)) : -1,
03099 then_bb->index,
03100 BB_HEAD (then_bb) ? (int)INSN_UID (BB_HEAD (then_bb)) : -1);
03101
03102 if (else_bb)
03103 fprintf (dump_file, ", else %d [%d]",
03104 else_bb->index,
03105 BB_HEAD (else_bb) ? (int)INSN_UID (BB_HEAD (else_bb)) : -1);
03106
03107 fprintf (dump_file, ", join %d [%d]",
03108 join_bb->index,
03109 BB_HEAD (join_bb) ? (int)INSN_UID (BB_HEAD (join_bb)) : -1);
03110
03111 if (ce_info->num_multiple_test_blocks > 0)
03112 fprintf (dump_file, ", %d %s block%s last test %d [%d]",
03113 ce_info->num_multiple_test_blocks,
03114 (ce_info->and_and_p) ? "&&" : "||",
03115 (ce_info->num_multiple_test_blocks == 1) ? "" : "s",
03116 ce_info->last_test_bb->index,
03117 ((BB_HEAD (ce_info->last_test_bb))
03118 ? (int)INSN_UID (BB_HEAD (ce_info->last_test_bb))
03119 : -1));
03120
03121 fputc ('\n', dump_file);
03122 }
03123
03124
03125
03126
03127
03128
03129
03130
03131
03132 next = then_bb;
03133 if (else_bb && (next = next->next_bb) != else_bb)
03134 return FALSE;
03135 if ((next = next->next_bb) != join_bb && join_bb != EXIT_BLOCK_PTR)
03136 {
03137 if (else_bb)
03138 join_bb = NULL;
03139 else
03140 return FALSE;
03141 }
03142
03143
03144 ce_info->else_bb = else_bb;
03145 ce_info->join_bb = join_bb;
03146
03147 return process_if_block (ce_info);
03148 }
03149
03150
03151
03152
03153 static int
03154 find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
03155 {
03156 basic_block then_bb = then_edge->dest;
03157 basic_block else_bb = else_edge->dest;
03158 basic_block other_bb, trap_bb;
03159 rtx trap, jump, cond, cond_earliest, seq;
03160 enum rtx_code code;
03161
03162
03163
03164
03165 if ((trap = block_has_only_trap (then_bb)) != NULL)
03166 trap_bb = then_bb, other_bb = else_bb;
03167 else if ((trap = block_has_only_trap (else_bb)) != NULL)
03168 trap_bb = else_bb, other_bb = then_bb;
03169 else
03170 return FALSE;
03171
03172 if (dump_file)
03173 {
03174 fprintf (dump_file, "\nTRAP-IF block found, start %d, trap %d\n",
03175 test_bb->index, trap_bb->index);
03176 }
03177
03178
03179 jump = BB_END (test_bb);
03180 cond = noce_get_condition (jump, &cond_earliest);
03181 if (! cond)
03182 return FALSE;
03183
03184
03185
03186 if (! onlyjump_p (jump))
03187 return FALSE;
03188
03189
03190 if (GET_MODE (XEXP (cond, 0)) == BLKmode)
03191 return FALSE;
03192
03193
03194 code = GET_CODE (cond);
03195 if (then_bb == trap_bb)
03196 {
03197 code = reversed_comparison_code (cond, jump);
03198 if (code == UNKNOWN)
03199 return FALSE;
03200 }
03201
03202
03203 seq = gen_cond_trap (code, XEXP (cond, 0),
03204 XEXP (cond, 1),
03205 TRAP_CODE (PATTERN (trap)));
03206 if (seq == NULL)
03207 return FALSE;
03208
03209 num_true_changes++;
03210
03211
03212 emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATOR (trap));
03213
03214
03215 remove_edge (trap_bb == then_bb ? then_edge : else_edge);
03216 if (EDGE_COUNT (trap_bb->preds) == 0)
03217 delete_basic_block (trap_bb);
03218
03219
03220
03221 if (test_bb->next_bb == other_bb)
03222 {
03223 struct ce_if_block new_ce_info;
03224 delete_insn (jump);
03225 memset (&new_ce_info, '\0', sizeof (new_ce_info));
03226 new_ce_info.test_bb = test_bb;
03227 new_ce_info.then_bb = NULL;
03228 new_ce_info.else_bb = NULL;
03229 new_ce_info.join_bb = other_bb;
03230 merge_if_block (&new_ce_info);
03231 }
03232 else
03233 {
03234 rtx lab, newjump;
03235
03236 lab = JUMP_LABEL (jump);
03237 newjump = emit_jump_insn_after (gen_jump (lab), jump);
03238 LABEL_NUSES (lab) += 1;
03239 JUMP_LABEL (newjump) = lab;
03240 emit_barrier_after (newjump);
03241
03242 delete_insn (jump);
03243 }
03244
03245 return TRUE;
03246 }
03247
03248
03249
03250
03251 static rtx
03252 block_has_only_trap (basic_block bb)
03253 {
03254 rtx trap;
03255
03256
03257 if (bb == EXIT_BLOCK_PTR)
03258 return NULL_RTX;
03259
03260
03261 if (EDGE_COUNT (bb->succs) > 0)
03262 return NULL_RTX;
03263
03264
03265 trap = first_active_insn (bb);
03266 if (! (trap == BB_END (bb)
03267 && GET_CODE (PATTERN (trap)) == TRAP_IF
03268 && TRAP_CONDITION (PATTERN (trap)) == const_true_rtx))
03269 return NULL_RTX;
03270
03271 return trap;
03272 }
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351 static int
03352 find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
03353 {
03354 basic_block then_bb = then_edge->dest;
03355 basic_block else_bb = else_edge->dest, new_bb;
03356 int then_bb_index;
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368 if ((BB_END (then_bb)
03369 && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
03370 || (BB_END (test_bb)
03371 && find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
03372 || (BB_END (else_bb)
03373 && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
03374 NULL_RTX)))
03375 return FALSE;
03376
03377
03378 if (!single_succ_p (then_bb))
03379 return FALSE;
03380
03381
03382 if (single_succ_edge (then_bb)->flags & (EDGE_COMPLEX | EDGE_FALLTHRU))
03383 return FALSE;
03384
03385
03386 if (!single_pred_p (then_bb))
03387 return FALSE;
03388
03389
03390 if (forwarder_block_p (then_bb))
03391 return FALSE;
03392
03393 num_possible_if_blocks++;
03394 if (dump_file)
03395 fprintf (dump_file,
03396 "\nIF-CASE-1 found, start %d, then %d\n",
03397 test_bb->index, then_bb->index);
03398
03399
03400 if (! cheap_bb_rtx_cost_p (then_bb, COSTS_N_INSNS (BRANCH_COST)))
03401 return FALSE;
03402
03403
03404 if (! dead_or_predicable (test_bb, then_bb, else_bb,
03405 single_succ (then_bb), 1))
03406 return FALSE;
03407
03408
03409
03410
03411 bitmap_ior (test_bb->il.rtl->global_live_at_end,
03412 else_bb->il.rtl->global_live_at_start,
03413 then_bb->il.rtl->global_live_at_end);
03414
03415
03416
03417
03418
03419
03420 if (then_bb->next_bb == else_bb
03421 && then_bb->prev_bb == test_bb
03422 && else_bb != EXIT_BLOCK_PTR)
03423 {
03424 redirect_edge_succ (FALLTHRU_EDGE (test_bb), else_bb);
03425 new_bb = 0;
03426 }
03427 else
03428 new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb),
03429 else_bb);
03430
03431 then_bb_index = then_bb->index;
03432 delete_basic_block (then_bb);
03433
03434
03435
03436 if (new_bb)
03437 {
03438 new_bb->index = then_bb_index;
03439 SET_BASIC_BLOCK (then_bb_index, new_bb);
03440
03441
03442
03443 BB_COPY_PARTITION (new_bb, test_bb);
03444 }
03445
03446
03447
03448 num_true_changes++;
03449 num_updated_if_blocks++;
03450
03451 return TRUE;
03452 }
03453
03454
03455
03456 static int
03457 find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
03458 {
03459 basic_block then_bb = then_edge->dest;
03460 basic_block else_bb = else_edge->dest;
03461 edge else_succ;
03462 rtx note;
03463
03464
03465
03466
03467
03468
03469
03470
03471
03472
03473
03474 if ((BB_END (then_bb)
03475 && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
03476 || (BB_END (test_bb)
03477 && find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
03478 || (BB_END (else_bb)
03479 && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
03480 NULL_RTX)))
03481 return FALSE;
03482
03483
03484 if (!single_succ_p (else_bb))
03485 return FALSE;
03486 else
03487 else_succ = single_succ_edge (else_bb);
03488
03489
03490 if (else_succ->flags & EDGE_COMPLEX)
03491 return FALSE;
03492
03493
03494 if (!single_pred_p (else_bb))
03495 return FALSE;
03496
03497
03498 if (then_bb->index < NUM_FIXED_BLOCKS)
03499 return FALSE;
03500
03501
03502 note = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
03503 if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2)
03504 ;
03505 else if (else_succ->dest->index < NUM_FIXED_BLOCKS
03506 || dominated_by_p (CDI_POST_DOMINATORS, then_bb,
03507 else_succ->dest))
03508 ;
03509 else
03510 return FALSE;
03511
03512 num_possible_if_blocks++;
03513 if (dump_file)
03514 fprintf (dump_file,
03515 "\nIF-CASE-2 found, start %d, else %d\n",
03516 test_bb->index, else_bb->index);
03517
03518
03519 if (! cheap_bb_rtx_cost_p (else_bb, COSTS_N_INSNS (BRANCH_COST)))
03520 return FALSE;
03521
03522
03523 if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ->dest, 0))
03524 return FALSE;
03525
03526
03527
03528
03529 bitmap_ior (test_bb->il.rtl->global_live_at_end,
03530 then_bb->il.rtl->global_live_at_start,
03531 else_bb->il.rtl->global_live_at_end);
03532
03533 delete_basic_block (else_bb);
03534
03535 num_true_changes++;
03536 num_updated_if_blocks++;
03537
03538
03539
03540
03541 return TRUE;
03542 }
03543
03544
03545
03546
03547 static int
03548 find_memory (rtx *px, void *data ATTRIBUTE_UNUSED)
03549 {
03550 return MEM_P (*px);
03551 }
03552
03553
03554
03555
03556
03557
03558
03559
03560
03561 static int
03562 dead_or_predicable (basic_block test_bb, basic_block merge_bb,
03563 basic_block other_bb, basic_block new_dest, int reversep)
03564 {
03565 rtx head, end, jump, earliest = NULL_RTX, old_dest, new_label = NULL_RTX;
03566
03567 jump = BB_END (test_bb);
03568
03569
03570 head = BB_HEAD (merge_bb);
03571 end = BB_END (merge_bb);
03572
03573
03574
03575
03576
03577 if (tablejump_p (end, NULL, NULL))
03578 return FALSE;
03579
03580 if (LABEL_P (head))
03581 head = NEXT_INSN (head);
03582 if (NOTE_P (head))
03583 {
03584 if (head == end)
03585 {
03586 head = end = NULL_RTX;
03587 goto no_body;
03588 }
03589 head = NEXT_INSN (head);
03590 }
03591
03592 if (JUMP_P (end))
03593 {
03594 if (head == end)
03595 {
03596 head = end = NULL_RTX;
03597 goto no_body;
03598 }
03599 end = PREV_INSN (end);
03600 }
03601
03602
03603
03604 #ifndef IFCVT_MODIFY_TESTS
03605 if (HAVE_conditional_execution)
03606 {
03607
03608
03609
03610
03611
03612
03613 rtx cond, prob_val;
03614
03615 cond = cond_exec_get_condition (jump);
03616 if (! cond)
03617 return FALSE;
03618
03619 prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
03620 if (prob_val)
03621 prob_val = XEXP (prob_val, 0);
03622
03623 if (reversep)
03624 {
03625 enum rtx_code rev = reversed_comparison_code (cond, jump);
03626 if (rev == UNKNOWN)
03627 return FALSE;
03628 cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
03629 XEXP (cond, 1));
03630 if (prob_val)
03631 prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
03632 }
03633
03634 if (! cond_exec_process_insns ((ce_if_block_t *)0, head, end, cond,
03635 prob_val, 0))
03636 goto cancel;
03637
03638 earliest = jump;
03639 }
03640 else
03641 #endif
03642 {
03643
03644
03645
03646
03647 rtx insn, cond, prev;
03648 regset merge_set, tmp, test_live, test_set;
03649 struct propagate_block_info *pbi;
03650 unsigned i, fail = 0;
03651 bitmap_iterator bi;
03652
03653
03654 for (insn = head; ; insn = NEXT_INSN (insn))
03655 {
03656 if (CALL_P (insn))
03657 return FALSE;
03658 if (INSN_P (insn))
03659 {
03660 if (may_trap_p (PATTERN (insn)))
03661 return FALSE;
03662
03663
03664
03665
03666
03667
03668 if (for_each_rtx (&PATTERN (insn), find_memory, NULL))
03669 return FALSE;
03670 }
03671 if (insn == end)
03672 break;
03673 }
03674
03675 if (! any_condjump_p (jump))
03676 return FALSE;
03677
03678
03679 cond = noce_get_condition (jump, &earliest);
03680 if (! cond)
03681 return FALSE;
03682
03683
03684
03685
03686
03687
03688
03689 tmp = ALLOC_REG_SET (®_obstack);
03690 merge_set = ALLOC_REG_SET (®_obstack);
03691 test_live = ALLOC_REG_SET (®_obstack);
03692 test_set = ALLOC_REG_SET (®_obstack);
03693
03694
03695
03696
03697
03698
03699
03700 if (max_regno < max_reg_num ())
03701 {
03702 max_regno = max_reg_num ();
03703 allocate_reg_info (max_regno, FALSE, FALSE);
03704 }
03705 propagate_block (merge_bb, tmp, merge_set, merge_set, 0);
03706
03707
03708
03709 if (SMALL_REGISTER_CLASSES && ! reload_completed)
03710 {
03711 EXECUTE_IF_SET_IN_BITMAP (merge_set, 0, i, bi)
03712 {
03713 if (i < FIRST_PSEUDO_REGISTER
03714 && ! fixed_regs[i]
03715 && ! global_regs[i])
03716 fail = 1;
03717 }
03718 }
03719
03720
03721
03722
03723 COPY_REG_SET (test_live, other_bb->il.rtl->global_live_at_start);
03724 pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set,
03725 0);
03726
03727 for (insn = jump; ; insn = prev)
03728 {
03729 prev = propagate_one_insn (pbi, insn);
03730 if (insn == earliest)
03731 break;
03732 }
03733
03734 free_propagate_block_info (pbi);
03735
03736
03737
03738
03739
03740
03741
03742 if (bitmap_intersect_p (test_set, merge_set)
03743 || bitmap_intersect_p (test_live, merge_set)
03744 || bitmap_intersect_p (test_set,
03745 merge_bb->il.rtl->global_live_at_start))
03746 fail = 1;
03747
03748 FREE_REG_SET (tmp);
03749 FREE_REG_SET (merge_set);
03750 FREE_REG_SET (test_live);
03751 FREE_REG_SET (test_set);
03752
03753 if (fail)
03754 return FALSE;
03755 }
03756
03757 no_body:
03758
03759
03760
03761
03762 old_dest = JUMP_LABEL (jump);
03763 if (other_bb != new_dest)
03764 {
03765 new_label = block_label (new_dest);
03766 if (reversep
03767 ? ! invert_jump_1 (jump, new_label)
03768 : ! redirect_jump_1 (jump, new_label))
03769 goto cancel;
03770 }
03771
03772 if (! apply_change_group ())
03773 return FALSE;
03774
03775 if (other_bb != new_dest)
03776 {
03777 redirect_jump_2 (jump, old_dest, new_label, -1, reversep);
03778
03779 redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
03780 if (reversep)
03781 {
03782 gcov_type count, probability;
03783 count = BRANCH_EDGE (test_bb)->count;
03784 BRANCH_EDGE (test_bb)->count = FALLTHRU_EDGE (test_bb)->count;
03785 FALLTHRU_EDGE (test_bb)->count = count;
03786 probability = BRANCH_EDGE (test_bb)->probability;
03787 BRANCH_EDGE (test_bb)->probability
03788 = FALLTHRU_EDGE (test_bb)->probability;
03789 FALLTHRU_EDGE (test_bb)->probability = probability;
03790 update_br_prob_note (test_bb);
03791 }
03792 }
03793
03794
03795 if (head != NULL)
03796 {
03797 rtx insn;
03798
03799 if (end == BB_END (merge_bb))
03800 BB_END (merge_bb) = PREV_INSN (head);
03801
03802 if (squeeze_notes (&head, &end))
03803 return TRUE;
03804
03805
03806
03807 insn = head;
03808 do
03809 {
03810 rtx note, set;
03811
03812 if (! INSN_P (insn))
03813 continue;
03814 note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
03815 if (! note)
03816 continue;
03817 set = single_set (insn);
03818 if (!set || !function_invariant_p (SET_SRC (set)))
03819 remove_note (insn, note);
03820 } while (insn != end && (insn = NEXT_INSN (insn)));
03821
03822 reorder_insns (head, end, PREV_INSN (earliest));
03823 }
03824
03825
03826 if (other_bb == new_dest)
03827 {
03828 delete_insn (jump);
03829 remove_edge (BRANCH_EDGE (test_bb));
03830
03831
03832 }
03833
03834 return TRUE;
03835
03836 cancel:
03837 cancel_changes (0);
03838 return FALSE;
03839 }
03840
03841
03842
03843 static void
03844 if_convert (int x_life_data_ok)
03845 {
03846 basic_block bb;
03847 int pass;
03848
03849 num_possible_if_blocks = 0;
03850 num_updated_if_blocks = 0;
03851 num_true_changes = 0;
03852 life_data_ok = (x_life_data_ok != 0);
03853
03854 if ((! targetm.cannot_modify_jumps_p ())
03855 && (!flag_reorder_blocks_and_partition || !no_new_pseudos
03856 || !targetm.have_named_sections))
03857 {
03858 struct loops loops;
03859
03860 flow_loops_find (&loops);
03861 mark_loop_exit_edges (&loops);
03862 flow_loops_free (&loops);
03863 free_dominance_info (CDI_DOMINATORS);
03864 }
03865
03866
03867 if (HAVE_conditional_execution || life_data_ok)
03868 calculate_dominance_info (CDI_POST_DOMINATORS);
03869
03870 if (life_data_ok)
03871 clear_bb_flags ();
03872
03873
03874
03875
03876 pass = 0;
03877 do
03878 {
03879 cond_exec_changed_p = FALSE;
03880 pass++;
03881
03882 #ifdef IFCVT_MULTIPLE_DUMPS
03883 if (dump_file && pass > 1)
03884 fprintf (dump_file, "\n\n========== Pass %d ==========\n", pass);
03885 #endif
03886
03887 FOR_EACH_BB (bb)
03888 {
03889 basic_block new_bb;
03890 while ((new_bb = find_if_header (bb, pass)))
03891 bb = new_bb;
03892 }
03893
03894 #ifdef IFCVT_MULTIPLE_DUMPS
03895 if (dump_file && cond_exec_changed_p)
03896 print_rtl_with_bb (dump_file, get_insns ());
03897 #endif
03898 }
03899 while (cond_exec_changed_p);
03900
03901 #ifdef IFCVT_MULTIPLE_DUMPS
03902 if (dump_file)
03903 fprintf (dump_file, "\n\n========== no more changes\n");
03904 #endif
03905
03906 free_dominance_info (CDI_POST_DOMINATORS);
03907
03908 if (dump_file)
03909 fflush (dump_file);
03910
03911 clear_aux_for_blocks ();
03912
03913
03914 if (num_true_changes && life_data_ok)
03915 {
03916
03917 if (max_regno < max_reg_num ())
03918 {
03919 max_regno = max_reg_num ();
03920 allocate_reg_info (max_regno, FALSE, FALSE);
03921 }
03922 update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
03923 PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
03924 | PROP_KILL_DEAD_CODE);
03925 }
03926
03927
03928 if (dump_file && num_possible_if_blocks > 0)
03929 {
03930 fprintf (dump_file,
03931 "\n%d possible IF blocks searched.\n",
03932 num_possible_if_blocks);
03933 fprintf (dump_file,
03934 "%d IF blocks converted.\n",
03935 num_updated_if_blocks);
03936 fprintf (dump_file,
03937 "%d true changes made.\n\n\n",
03938 num_true_changes);
03939 }
03940
03941 #ifdef ENABLE_CHECKING
03942 verify_flow_info ();
03943 #endif
03944 }
03945
03946 static bool
03947 gate_handle_if_conversion (void)
03948 {
03949 return (optimize > 0);
03950 }
03951
03952
03953 static unsigned int
03954 rest_of_handle_if_conversion (void)
03955 {
03956 if (flag_if_conversion)
03957 {
03958 if (dump_file)
03959 dump_flow_info (dump_file, dump_flags);
03960 cleanup_cfg (CLEANUP_EXPENSIVE);
03961 reg_scan (get_insns (), max_reg_num ());
03962 if_convert (0);
03963 }
03964
03965 timevar_push (TV_JUMP);
03966 cleanup_cfg (CLEANUP_EXPENSIVE);
03967 reg_scan (get_insns (), max_reg_num ());
03968 timevar_pop (TV_JUMP);
03969 return 0;
03970 }
03971
03972 struct tree_opt_pass pass_rtl_ifcvt =
03973 {
03974 "ce1",
03975 gate_handle_if_conversion,
03976 rest_of_handle_if_conversion,
03977 NULL,
03978 NULL,
03979 0,
03980 TV_IFCVT,
03981 0,
03982 0,
03983 0,
03984 0,
03985 TODO_dump_func,
03986 'C'
03987 };
03988
03989 static bool
03990 gate_handle_if_after_combine (void)
03991 {
03992 return (optimize > 0 && flag_if_conversion);
03993 }
03994
03995
03996
03997
03998 static unsigned int
03999 rest_of_handle_if_after_combine (void)
04000 {
04001 no_new_pseudos = 0;
04002 if_convert (1);
04003 no_new_pseudos = 1;
04004 return 0;
04005 }
04006
04007 struct tree_opt_pass pass_if_after_combine =
04008 {
04009 "ce2",
04010 gate_handle_if_after_combine,
04011 rest_of_handle_if_after_combine,
04012 NULL,
04013 NULL,
04014 0,
04015 TV_IFCVT,
04016 0,
04017 0,
04018 0,
04019 0,
04020 TODO_dump_func |
04021 TODO_ggc_collect,
04022 'C'
04023 };
04024
04025
04026 static bool
04027 gate_handle_if_after_reload (void)
04028 {
04029 return (optimize > 0);
04030 }
04031
04032 static unsigned int
04033 rest_of_handle_if_after_reload (void)
04034 {
04035
04036
04037 cleanup_cfg (CLEANUP_EXPENSIVE
04038 | CLEANUP_UPDATE_LIFE
04039 | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
04040 if (flag_if_conversion2)
04041 if_convert (1);
04042 return 0;
04043 }
04044
04045
04046 struct tree_opt_pass pass_if_after_reload =
04047 {
04048 "ce3",
04049 gate_handle_if_after_reload,
04050 rest_of_handle_if_after_reload,
04051 NULL,
04052 NULL,
04053 0,
04054 TV_IFCVT2,
04055 0,
04056 0,
04057 0,
04058 0,
04059 TODO_dump_func |
04060 TODO_ggc_collect,
04061 'E'
04062 };
04063
04064