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