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