aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.3.1/gcc/ifcvt.c
diff options
context:
space:
mode:
authorDan Albert <danalbert@google.com>2015-06-17 11:09:54 -0700
committerDan Albert <danalbert@google.com>2015-06-17 14:15:22 -0700
commitf378ebf14df0952eae870c9865bab8326aa8f137 (patch)
tree31794503eb2a8c64ea5f313b93100f1163afcffb /gcc-4.3.1/gcc/ifcvt.c
parent2c58169824949d3a597d9fa81931e001ef9b1bd0 (diff)
downloadtoolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.tar.gz
toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.tar.bz2
toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.zip
Delete old versions of GCC.
Change-Id: I710f125d905290e1024cbd67f48299861790c66c
Diffstat (limited to 'gcc-4.3.1/gcc/ifcvt.c')
-rw-r--r--gcc-4.3.1/gcc/ifcvt.c4220
1 files changed, 0 insertions, 4220 deletions
diff --git a/gcc-4.3.1/gcc/ifcvt.c b/gcc-4.3.1/gcc/ifcvt.c
deleted file mode 100644
index c392f4ee0..000000000
--- a/gcc-4.3.1/gcc/ifcvt.c
+++ /dev/null
@@ -1,4220 +0,0 @@
-/* If-conversion support.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation, Inc.
-
- This file is part of GCC.
-
- GCC is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- GCC is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-
-#include "rtl.h"
-#include "regs.h"
-#include "function.h"
-#include "flags.h"
-#include "insn-config.h"
-#include "recog.h"
-#include "except.h"
-#include "hard-reg-set.h"
-#include "basic-block.h"
-#include "expr.h"
-#include "real.h"
-#include "output.h"
-#include "optabs.h"
-#include "toplev.h"
-#include "tm_p.h"
-#include "cfgloop.h"
-#include "target.h"
-#include "timevar.h"
-#include "tree-pass.h"
-#include "df.h"
-#include "vec.h"
-#include "vecprim.h"
-
-#ifndef HAVE_conditional_execution
-#define HAVE_conditional_execution 0
-#endif
-#ifndef HAVE_conditional_move
-#define HAVE_conditional_move 0
-#endif
-#ifndef HAVE_incscc
-#define HAVE_incscc 0
-#endif
-#ifndef HAVE_decscc
-#define HAVE_decscc 0
-#endif
-#ifndef HAVE_trap
-#define HAVE_trap 0
-#endif
-#ifndef HAVE_conditional_trap
-#define HAVE_conditional_trap 0
-#endif
-
-#ifndef MAX_CONDITIONAL_EXECUTE
-#define MAX_CONDITIONAL_EXECUTE (BRANCH_COST + 1)
-#endif
-
-#define IFCVT_MULTIPLE_DUMPS 1
-
-#define NULL_BLOCK ((basic_block) NULL)
-
-/* # of IF-THEN or IF-THEN-ELSE blocks we looked at */
-static int num_possible_if_blocks;
-
-/* # of IF-THEN or IF-THEN-ELSE blocks were converted to conditional
- execution. */
-static int num_updated_if_blocks;
-
-/* # of changes made. */
-static int num_true_changes;
-
-/* Whether conditional execution changes were made. */
-static int cond_exec_changed_p;
-
-/* Forward references. */
-static int count_bb_insns (const_basic_block);
-static bool cheap_bb_rtx_cost_p (const_basic_block, int);
-static rtx first_active_insn (basic_block);
-static rtx last_active_insn (basic_block, int);
-static basic_block block_fallthru (basic_block);
-static int cond_exec_process_insns (ce_if_block_t *, rtx, rtx, rtx, rtx, int);
-static rtx cond_exec_get_condition (rtx);
-static rtx noce_get_condition (rtx, rtx *, bool);
-static int noce_operand_ok (const_rtx);
-static void merge_if_block (ce_if_block_t *);
-static int find_cond_trap (basic_block, edge, edge);
-static basic_block find_if_header (basic_block, int);
-static int block_jumps_and_fallthru_p (basic_block, basic_block);
-static int noce_find_if_block (basic_block, edge, edge, int);
-static int cond_exec_find_if_block (ce_if_block_t *);
-static int find_if_case_1 (basic_block, edge, edge);
-static int find_if_case_2 (basic_block, edge, edge);
-static int find_memory (rtx *, void *);
-static int dead_or_predicable (basic_block, basic_block, basic_block,
- basic_block, int);
-static void noce_emit_move_insn (rtx, rtx);
-static rtx block_has_only_trap (basic_block);
-
-/* Count the number of non-jump active insns in BB. */
-
-static int
-count_bb_insns (const_basic_block bb)
-{
- int count = 0;
- rtx insn = BB_HEAD (bb);
-
- while (1)
- {
- if (CALL_P (insn) || NONJUMP_INSN_P (insn))
- count++;
-
- if (insn == BB_END (bb))
- break;
- insn = NEXT_INSN (insn);
- }
-
- return count;
-}
-
-/* Determine whether the total insn_rtx_cost on non-jump insns in
- basic block BB is less than MAX_COST. This function returns
- false if the cost of any instruction could not be estimated. */
-
-static bool
-cheap_bb_rtx_cost_p (const_basic_block bb, int max_cost)
-{
- int count = 0;
- rtx insn = BB_HEAD (bb);
-
- while (1)
- {
- if (NONJUMP_INSN_P (insn))
- {
- int cost = insn_rtx_cost (PATTERN (insn));
- if (cost == 0)
- return false;
-
- /* If this instruction is the load or set of a "stack" register,
- such as a floating point register on x87, then the cost of
- speculatively executing this insn may need to include
- the additional cost of popping its result off of the
- register stack. Unfortunately, correctly recognizing and
- accounting for this additional overhead is tricky, so for
- now we simply prohibit such speculative execution. */
-#ifdef STACK_REGS
- {
- rtx set = single_set (insn);
- if (set && STACK_REG_P (SET_DEST (set)))
- return false;
- }
-#endif
-
- count += cost;
- if (count >= max_cost)
- return false;
- }
- else if (CALL_P (insn))
- return false;
-
- if (insn == BB_END (bb))
- break;
- insn = NEXT_INSN (insn);
- }
-
- return true;
-}
-
-/* Return the first non-jump active insn in the basic block. */
-
-static rtx
-first_active_insn (basic_block bb)
-{
- rtx insn = BB_HEAD (bb);
-
- if (LABEL_P (insn))
- {
- if (insn == BB_END (bb))
- return NULL_RTX;
- insn = NEXT_INSN (insn);
- }
-
- while (NOTE_P (insn))
- {
- if (insn == BB_END (bb))
- return NULL_RTX;
- insn = NEXT_INSN (insn);
- }
-
- if (JUMP_P (insn))
- return NULL_RTX;
-
- return insn;
-}
-
-/* Return the last non-jump active (non-jump) insn in the basic block. */
-
-static rtx
-last_active_insn (basic_block bb, int skip_use_p)
-{
- rtx insn = BB_END (bb);
- rtx head = BB_HEAD (bb);
-
- while (NOTE_P (insn)
- || JUMP_P (insn)
- || (skip_use_p
- && NONJUMP_INSN_P (insn)
- && GET_CODE (PATTERN (insn)) == USE))
- {
- if (insn == head)
- return NULL_RTX;
- insn = PREV_INSN (insn);
- }
-
- if (LABEL_P (insn))
- return NULL_RTX;
-
- return insn;
-}
-
-/* Return the basic block reached by falling though the basic block BB. */
-
-static basic_block
-block_fallthru (basic_block bb)
-{
- edge e;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_FALLTHRU)
- break;
-
- return (e) ? e->dest : NULL_BLOCK;
-}
-
-/* Go through a bunch of insns, converting them to conditional
- execution format if possible. Return TRUE if all of the non-note
- insns were processed. */
-
-static int
-cond_exec_process_insns (ce_if_block_t *ce_info ATTRIBUTE_UNUSED,
- /* if block information */rtx start,
- /* first insn to look at */rtx end,
- /* last insn to look at */rtx test,
- /* conditional execution test */rtx prob_val,
- /* probability of branch taken. */int mod_ok)
-{
- int must_be_last = FALSE;
- rtx insn;
- rtx xtest;
- rtx pattern;
-
- if (!start || !end)
- return FALSE;
-
- for (insn = start; ; insn = NEXT_INSN (insn))
- {
- if (NOTE_P (insn))
- goto insn_done;
-
- gcc_assert(NONJUMP_INSN_P (insn) || CALL_P (insn));
-
- /* Remove USE insns that get in the way. */
- if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
- {
- /* ??? Ug. Actually unlinking the thing is problematic,
- given what we'd have to coordinate with our callers. */
- SET_INSN_DELETED (insn);
- goto insn_done;
- }
-
- /* Last insn wasn't last? */
- if (must_be_last)
- return FALSE;
-
- if (modified_in_p (test, insn))
- {
- if (!mod_ok)
- return FALSE;
- must_be_last = TRUE;
- }
-
- /* Now build the conditional form of the instruction. */
- pattern = PATTERN (insn);
- xtest = copy_rtx (test);
-
- /* If this is already a COND_EXEC, rewrite the test to be an AND of the
- two conditions. */
- if (GET_CODE (pattern) == COND_EXEC)
- {
- if (GET_MODE (xtest) != GET_MODE (COND_EXEC_TEST (pattern)))
- return FALSE;
-
- xtest = gen_rtx_AND (GET_MODE (xtest), xtest,
- COND_EXEC_TEST (pattern));
- pattern = COND_EXEC_CODE (pattern);
- }
-
- pattern = gen_rtx_COND_EXEC (VOIDmode, xtest, pattern);
-
- /* If the machine needs to modify the insn being conditionally executed,
- say for example to force a constant integer operand into a temp
- register, do so here. */
-#ifdef IFCVT_MODIFY_INSN
- IFCVT_MODIFY_INSN (ce_info, pattern, insn);
- if (! pattern)
- return FALSE;
-#endif
-
- validate_change (insn, &PATTERN (insn), pattern, 1);
-
- if (CALL_P (insn) && prob_val)
- validate_change (insn, &REG_NOTES (insn),
- alloc_EXPR_LIST (REG_BR_PROB, prob_val,
- REG_NOTES (insn)), 1);
-
- insn_done:
- if (insn == end)
- break;
- }
-
- return TRUE;
-}
-
-/* Return the condition for a jump. Do not do any special processing. */
-
-static rtx
-cond_exec_get_condition (rtx jump)
-{
- rtx test_if, cond;
-
- if (any_condjump_p (jump))
- test_if = SET_SRC (pc_set (jump));
- else
- return NULL_RTX;
- cond = XEXP (test_if, 0);
-
- /* If this branches to JUMP_LABEL when the condition is false,
- reverse the condition. */
- if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF
- && XEXP (XEXP (test_if, 2), 0) == JUMP_LABEL (jump))
- {
- enum rtx_code rev = reversed_comparison_code (cond, jump);
- if (rev == UNKNOWN)
- return NULL_RTX;
-
- cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
- XEXP (cond, 1));
- }
-
- return cond;
-}
-
-/* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
- to conditional execution. Return TRUE if we were successful at
- converting the block. */
-
-static int
-cond_exec_process_if_block (ce_if_block_t * ce_info,
- /* if block information */int do_multiple_p)
-{
- basic_block test_bb = ce_info->test_bb; /* last test block */
- basic_block then_bb = ce_info->then_bb; /* THEN */
- basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */
- rtx test_expr; /* expression in IF_THEN_ELSE that is tested */
- rtx then_start; /* first insn in THEN block */
- rtx then_end; /* last insn + 1 in THEN block */
- rtx else_start = NULL_RTX; /* first insn in ELSE block or NULL */
- rtx else_end = NULL_RTX; /* last insn + 1 in ELSE block */
- int max; /* max # of insns to convert. */
- int then_mod_ok; /* whether conditional mods are ok in THEN */
- rtx true_expr; /* test for else block insns */
- rtx false_expr; /* test for then block insns */
- rtx true_prob_val; /* probability of else block */
- rtx false_prob_val; /* probability of then block */
- int n_insns;
- enum rtx_code false_code;
-
- /* If test is comprised of && or || elements, and we've failed at handling
- all of them together, just use the last test if it is the special case of
- && elements without an ELSE block. */
- if (!do_multiple_p && ce_info->num_multiple_test_blocks)
- {
- if (else_bb || ! ce_info->and_and_p)
- return FALSE;
-
- ce_info->test_bb = test_bb = ce_info->last_test_bb;
- ce_info->num_multiple_test_blocks = 0;
- ce_info->num_and_and_blocks = 0;
- ce_info->num_or_or_blocks = 0;
- }
-
- /* Find the conditional jump to the ELSE or JOIN part, and isolate
- the test. */
- test_expr = cond_exec_get_condition (BB_END (test_bb));
- if (! test_expr)
- return FALSE;
-
- /* If the conditional jump is more than just a conditional jump,
- then we can not do conditional execution conversion on this block. */
- if (! onlyjump_p (BB_END (test_bb)))
- return FALSE;
-
- /* Collect the bounds of where we're to search, skipping any labels, jumps
- and notes at the beginning and end of the block. Then count the total
- number of insns and see if it is small enough to convert. */
- then_start = first_active_insn (then_bb);
- then_end = last_active_insn (then_bb, TRUE);
- n_insns = ce_info->num_then_insns = count_bb_insns (then_bb);
- max = MAX_CONDITIONAL_EXECUTE;
-
- if (else_bb)
- {
- max *= 2;
- else_start = first_active_insn (else_bb);
- else_end = last_active_insn (else_bb, TRUE);
- n_insns += ce_info->num_else_insns = count_bb_insns (else_bb);
- }
-
- if (n_insns > max)
- return FALSE;
-
- /* Map test_expr/test_jump into the appropriate MD tests to use on
- the conditionally executed code. */
-
- true_expr = test_expr;
-
- false_code = reversed_comparison_code (true_expr, BB_END (test_bb));
- if (false_code != UNKNOWN)
- false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr),
- XEXP (true_expr, 0), XEXP (true_expr, 1));
- else
- false_expr = NULL_RTX;
-
-#ifdef IFCVT_MODIFY_TESTS
- /* If the machine description needs to modify the tests, such as setting a
- conditional execution register from a comparison, it can do so here. */
- IFCVT_MODIFY_TESTS (ce_info, true_expr, false_expr);
-
- /* See if the conversion failed. */
- if (!true_expr || !false_expr)
- goto fail;
-#endif
-
- true_prob_val = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
- if (true_prob_val)
- {
- true_prob_val = XEXP (true_prob_val, 0);
- false_prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (true_prob_val));
- }
- else
- false_prob_val = NULL_RTX;
-
- /* If we have && or || tests, do them here. These tests are in the adjacent
- blocks after the first block containing the test. */
- if (ce_info->num_multiple_test_blocks > 0)
- {
- basic_block bb = test_bb;
- basic_block last_test_bb = ce_info->last_test_bb;
-
- if (! false_expr)
- goto fail;
-
- do
- {
- rtx start, end;
- rtx t, f;
- enum rtx_code f_code;
-
- bb = block_fallthru (bb);
- start = first_active_insn (bb);
- end = last_active_insn (bb, TRUE);
- if (start
- && ! cond_exec_process_insns (ce_info, start, end, false_expr,
- false_prob_val, FALSE))
- goto fail;
-
- /* If the conditional jump is more than just a conditional jump, then
- we can not do conditional execution conversion on this block. */
- if (! onlyjump_p (BB_END (bb)))
- goto fail;
-
- /* Find the conditional jump and isolate the test. */
- t = cond_exec_get_condition (BB_END (bb));
- if (! t)
- goto fail;
-
- f_code = reversed_comparison_code (t, BB_END (bb));
- if (f_code == UNKNOWN)
- goto fail;
-
- f = gen_rtx_fmt_ee (f_code, GET_MODE (t), XEXP (t, 0), XEXP (t, 1));
- if (ce_info->and_and_p)
- {
- t = gen_rtx_AND (GET_MODE (t), true_expr, t);
- f = gen_rtx_IOR (GET_MODE (t), false_expr, f);
- }
- else
- {
- t = gen_rtx_IOR (GET_MODE (t), true_expr, t);
- f = gen_rtx_AND (GET_MODE (t), false_expr, f);
- }
-
- /* If the machine description needs to modify the tests, such as
- setting a conditional execution register from a comparison, it can
- do so here. */
-#ifdef IFCVT_MODIFY_MULTIPLE_TESTS
- IFCVT_MODIFY_MULTIPLE_TESTS (ce_info, bb, t, f);
-
- /* See if the conversion failed. */
- if (!t || !f)
- goto fail;
-#endif
-
- true_expr = t;
- false_expr = f;
- }
- while (bb != last_test_bb);
- }
-
- /* For IF-THEN-ELSE blocks, we don't allow modifications of the test
- on then THEN block. */
- then_mod_ok = (else_bb == NULL_BLOCK);
-
- /* Go through the THEN and ELSE blocks converting the insns if possible
- to conditional execution. */
-
- if (then_end
- && (! false_expr
- || ! cond_exec_process_insns (ce_info, then_start, then_end,
- false_expr, false_prob_val,
- then_mod_ok)))
- goto fail;
-
- if (else_bb && else_end
- && ! cond_exec_process_insns (ce_info, else_start, else_end,
- true_expr, true_prob_val, TRUE))
- goto fail;
-
- /* If we cannot apply the changes, fail. Do not go through the normal fail
- processing, since apply_change_group will call cancel_changes. */
- if (! apply_change_group ())
- {
-#ifdef IFCVT_MODIFY_CANCEL
- /* Cancel any machine dependent changes. */
- IFCVT_MODIFY_CANCEL (ce_info);
-#endif
- return FALSE;
- }
-
-#ifdef IFCVT_MODIFY_FINAL
- /* Do any machine dependent final modifications. */
- IFCVT_MODIFY_FINAL (ce_info);
-#endif
-
- /* Conversion succeeded. */
- if (dump_file)
- fprintf (dump_file, "%d insn%s converted to conditional execution.\n",
- n_insns, (n_insns == 1) ? " was" : "s were");
-
- /* Merge the blocks! */
- merge_if_block (ce_info);
- cond_exec_changed_p = TRUE;
- return TRUE;
-
- fail:
-#ifdef IFCVT_MODIFY_CANCEL
- /* Cancel any machine dependent changes. */
- IFCVT_MODIFY_CANCEL (ce_info);
-#endif
-
- cancel_changes (0);
- return FALSE;
-}
-
-/* Used by noce_process_if_block to communicate with its subroutines.
-
- The subroutines know that A and B may be evaluated freely. They
- know that X is a register. They should insert new instructions
- before cond_earliest. */
-
-struct noce_if_info
-{
- /* The basic blocks that make up the IF-THEN-{ELSE-,}JOIN block. */
- basic_block test_bb, then_bb, else_bb, join_bb;
-
- /* The jump that ends TEST_BB. */
- rtx jump;
-
- /* The jump condition. */
- rtx cond;
-
- /* New insns should be inserted before this one. */
- rtx cond_earliest;
-
- /* Insns in the THEN and ELSE block. There is always just this
- one insns in those blocks. The insns are single_set insns.
- If there was no ELSE block, INSN_B is the last insn before
- COND_EARLIEST, or NULL_RTX. In the former case, the insn
- operands are still valid, as if INSN_B was moved down below
- the jump. */
- rtx insn_a, insn_b;
-
- /* The SET_SRC of INSN_A and INSN_B. */
- rtx a, b;
-
- /* The SET_DEST of INSN_A. */
- rtx x;
-
- /* True if this if block is not canonical. In the canonical form of
- if blocks, the THEN_BB is the block reached via the fallthru edge
- from TEST_BB. For the noce transformations, we allow the symmetric
- form as well. */
- bool then_else_reversed;
-};
-
-static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
-static int noce_try_move (struct noce_if_info *);
-static int noce_try_store_flag (struct noce_if_info *);
-static int noce_try_addcc (struct noce_if_info *);
-static int noce_try_store_flag_constants (struct noce_if_info *);
-static int noce_try_store_flag_mask (struct noce_if_info *);
-static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx,
- rtx, rtx, rtx);
-static int noce_try_cmove (struct noce_if_info *);
-static int noce_try_cmove_arith (struct noce_if_info *);
-static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx *);
-static int noce_try_minmax (struct noce_if_info *);
-static int noce_try_abs (struct noce_if_info *);
-static int noce_try_sign_mask (struct noce_if_info *);
-
-/* Helper function for noce_try_store_flag*. */
-
-static rtx
-noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
- int normalize)
-{
- rtx cond = if_info->cond;
- int cond_complex;
- enum rtx_code code;
-
- cond_complex = (! general_operand (XEXP (cond, 0), VOIDmode)
- || ! general_operand (XEXP (cond, 1), VOIDmode));
-
- /* If earliest == jump, or when the condition is complex, try to
- build the store_flag insn directly. */
-
- if (cond_complex)
- cond = XEXP (SET_SRC (pc_set (if_info->jump)), 0);
-
- if (reversep)
- code = reversed_comparison_code (cond, if_info->jump);
- else
- code = GET_CODE (cond);
-
- if ((if_info->cond_earliest == if_info->jump || cond_complex)
- && (normalize == 0 || STORE_FLAG_VALUE == normalize))
- {
- rtx tmp;
-
- tmp = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
- XEXP (cond, 1));
- tmp = gen_rtx_SET (VOIDmode, x, tmp);
-
- start_sequence ();
- tmp = emit_insn (tmp);
-
- if (recog_memoized (tmp) >= 0)
- {
- tmp = get_insns ();
- end_sequence ();
- emit_insn (tmp);
-
- if_info->cond_earliest = if_info->jump;
-
- return x;
- }
-
- end_sequence ();
- }
-
- /* Don't even try if the comparison operands or the mode of X are weird. */
- if (cond_complex || !SCALAR_INT_MODE_P (GET_MODE (x)))
- return NULL_RTX;
-
- return emit_store_flag (x, code, XEXP (cond, 0),
- XEXP (cond, 1), VOIDmode,
- (code == LTU || code == LEU
- || code == GEU || code == GTU), normalize);
-}
-
-/* Emit instruction to move an rtx, possibly into STRICT_LOW_PART.
- X is the destination/target and Y is the value to copy. */
-
-static void
-noce_emit_move_insn (rtx x, rtx y)
-{
- enum machine_mode outmode;
- rtx outer, inner;
- int bitpos;
-
- if (GET_CODE (x) != STRICT_LOW_PART)
- {
- rtx seq, insn, target;
- optab ot;
-
- start_sequence ();
- /* Check that the SET_SRC is reasonable before calling emit_move_insn,
- otherwise construct a suitable SET pattern ourselves. */
- insn = (OBJECT_P (y) || CONSTANT_P (y) || GET_CODE (y) == SUBREG)
- ? emit_move_insn (x, y)
- : emit_insn (gen_rtx_SET (VOIDmode, x, y));
- seq = get_insns ();
- end_sequence ();
-
- if (recog_memoized (insn) <= 0)
- {
- if (GET_CODE (x) == ZERO_EXTRACT)
- {
- rtx op = XEXP (x, 0);
- unsigned HOST_WIDE_INT size = INTVAL (XEXP (x, 1));
- unsigned HOST_WIDE_INT start = INTVAL (XEXP (x, 2));
-
- /* store_bit_field expects START to be relative to
- BYTES_BIG_ENDIAN and adjusts this value for machines with
- BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN. In order to be able to
- invoke store_bit_field again it is necessary to have the START
- value from the first call. */
- if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
- {
- if (MEM_P (op))
- start = BITS_PER_UNIT - start - size;
- else
- {
- gcc_assert (REG_P (op));
- start = BITS_PER_WORD - start - size;
- }
- }
-
- gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
- store_bit_field (op, size, start, GET_MODE (x), y);
- return;
- }
-
- switch (GET_RTX_CLASS (GET_CODE (y)))
- {
- case RTX_UNARY:
- ot = code_to_optab[GET_CODE (y)];
- if (ot)
- {
- start_sequence ();
- target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
- if (target != NULL_RTX)
- {
- if (target != x)
- emit_move_insn (x, target);
- seq = get_insns ();
- }
- end_sequence ();
- }
- break;
-
- case RTX_BIN_ARITH:
- case RTX_COMM_ARITH:
- ot = code_to_optab[GET_CODE (y)];
- if (ot)
- {
- start_sequence ();
- target = expand_binop (GET_MODE (y), ot,
- XEXP (y, 0), XEXP (y, 1),
- x, 0, OPTAB_DIRECT);
- if (target != NULL_RTX)
- {
- if (target != x)
- emit_move_insn (x, target);
- seq = get_insns ();
- }
- end_sequence ();
- }
- break;
-
- default:
- break;
- }
- }
-
- emit_insn (seq);
- return;
- }
-
- outer = XEXP (x, 0);
- inner = XEXP (outer, 0);
- outmode = GET_MODE (outer);
- bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
- store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, outmode, y);
-}
-
-/* Return sequence of instructions generated by if conversion. This
- function calls end_sequence() to end the current stream, ensures
- that are instructions are unshared, recognizable non-jump insns.
- On failure, this function returns a NULL_RTX. */
-
-static rtx
-end_ifcvt_sequence (struct noce_if_info *if_info)
-{
- rtx insn;
- rtx seq = get_insns ();
-
- set_used_flags (if_info->x);
- set_used_flags (if_info->cond);
- unshare_all_rtl_in_chain (seq);
- end_sequence ();
-
- /* Make sure that all of the instructions emitted are recognizable,
- and that we haven't introduced a new jump instruction.
- As an exercise for the reader, build a general mechanism that
- allows proper placement of required clobbers. */
- for (insn = seq; insn; insn = NEXT_INSN (insn))
- if (JUMP_P (insn)
- || recog_memoized (insn) == -1)
- return NULL_RTX;
-
- return seq;
-}
-
-/* Convert "if (a != b) x = a; else x = b" into "x = a" and
- "if (a == b) x = a; else x = b" into "x = b". */
-
-static int
-noce_try_move (struct noce_if_info *if_info)
-{
- rtx cond = if_info->cond;
- enum rtx_code code = GET_CODE (cond);
- rtx y, seq;
-
- if (code != NE && code != EQ)
- return FALSE;
-
- /* This optimization isn't valid if either A or B could be a NaN
- or a signed zero. */
- if (HONOR_NANS (GET_MODE (if_info->x))
- || HONOR_SIGNED_ZEROS (GET_MODE (if_info->x)))
- return FALSE;
-
- /* Check whether the operands of the comparison are A and in
- either order. */
- if ((rtx_equal_p (if_info->a, XEXP (cond, 0))
- && rtx_equal_p (if_info->b, XEXP (cond, 1)))
- || (rtx_equal_p (if_info->a, XEXP (cond, 1))
- && rtx_equal_p (if_info->b, XEXP (cond, 0))))
- {
- y = (code == EQ) ? if_info->a : if_info->b;
-
- /* Avoid generating the move if the source is the destination. */
- if (! rtx_equal_p (if_info->x, y))
- {
- start_sequence ();
- noce_emit_move_insn (if_info->x, y);
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
- }
- return TRUE;
- }
- return FALSE;
-}
-
-/* Convert "if (test) x = 1; else x = 0".
-
- Only try 0 and STORE_FLAG_VALUE here. Other combinations will be
- tried in noce_try_store_flag_constants after noce_try_cmove has had
- a go at the conversion. */
-
-static int
-noce_try_store_flag (struct noce_if_info *if_info)
-{
- int reversep;
- rtx target, seq;
-
- if (GET_CODE (if_info->b) == CONST_INT
- && INTVAL (if_info->b) == STORE_FLAG_VALUE
- && if_info->a == const0_rtx)
- reversep = 0;
- else if (if_info->b == const0_rtx
- && GET_CODE (if_info->a) == CONST_INT
- && INTVAL (if_info->a) == STORE_FLAG_VALUE
- && (reversed_comparison_code (if_info->cond, if_info->jump)
- != UNKNOWN))
- reversep = 1;
- else
- return FALSE;
-
- start_sequence ();
-
- target = noce_emit_store_flag (if_info, if_info->x, reversep, 0);
- if (target)
- {
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = end_ifcvt_sequence (if_info);
- if (! seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
- return TRUE;
- }
- else
- {
- end_sequence ();
- return FALSE;
- }
-}
-
-/* Convert "if (test) x = a; else x = b", for A and B constant. */
-
-static int
-noce_try_store_flag_constants (struct noce_if_info *if_info)
-{
- rtx target, seq;
- int reversep;
- HOST_WIDE_INT itrue, ifalse, diff, tmp;
- int normalize, can_reverse;
- enum machine_mode mode;
-
- if (GET_CODE (if_info->a) == CONST_INT
- && GET_CODE (if_info->b) == CONST_INT)
- {
- mode = GET_MODE (if_info->x);
- ifalse = INTVAL (if_info->a);
- itrue = INTVAL (if_info->b);
-
- /* Make sure we can represent the difference between the two values. */
- if ((itrue - ifalse > 0)
- != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue))
- return FALSE;
-
- diff = trunc_int_for_mode (itrue - ifalse, mode);
-
- can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
- != UNKNOWN);
-
- reversep = 0;
- if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
- normalize = 0;
- else if (ifalse == 0 && exact_log2 (itrue) >= 0
- && (STORE_FLAG_VALUE == 1
- || BRANCH_COST >= 2))
- normalize = 1;
- else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse
- && (STORE_FLAG_VALUE == 1 || BRANCH_COST >= 2))
- normalize = 1, reversep = 1;
- else if (itrue == -1
- && (STORE_FLAG_VALUE == -1
- || BRANCH_COST >= 2))
- normalize = -1;
- else if (ifalse == -1 && can_reverse
- && (STORE_FLAG_VALUE == -1 || BRANCH_COST >= 2))
- normalize = -1, reversep = 1;
- else if ((BRANCH_COST >= 2 && STORE_FLAG_VALUE == -1)
- || BRANCH_COST >= 3)
- normalize = -1;
- else
- return FALSE;
-
- if (reversep)
- {
- tmp = itrue; itrue = ifalse; ifalse = tmp;
- diff = trunc_int_for_mode (-diff, mode);
- }
-
- start_sequence ();
- target = noce_emit_store_flag (if_info, if_info->x, reversep, normalize);
- if (! target)
- {
- end_sequence ();
- return FALSE;
- }
-
- /* if (test) x = 3; else x = 4;
- => x = 3 + (test == 0); */
- if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
- {
- target = expand_simple_binop (mode,
- (diff == STORE_FLAG_VALUE
- ? PLUS : MINUS),
- GEN_INT (ifalse), target, if_info->x, 0,
- OPTAB_WIDEN);
- }
-
- /* if (test) x = 8; else x = 0;
- => x = (test != 0) << 3; */
- else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0)
- {
- target = expand_simple_binop (mode, ASHIFT,
- target, GEN_INT (tmp), if_info->x, 0,
- OPTAB_WIDEN);
- }
-
- /* if (test) x = -1; else x = b;
- => x = -(test != 0) | b; */
- else if (itrue == -1)
- {
- target = expand_simple_binop (mode, IOR,
- target, GEN_INT (ifalse), if_info->x, 0,
- OPTAB_WIDEN);
- }
-
- /* if (test) x = a; else x = b;
- => x = (-(test != 0) & (b - a)) + a; */
- else
- {
- target = expand_simple_binop (mode, AND,
- target, GEN_INT (diff), if_info->x, 0,
- OPTAB_WIDEN);
- if (target)
- target = expand_simple_binop (mode, PLUS,
- target, GEN_INT (ifalse),
- if_info->x, 0, OPTAB_WIDEN);
- }
-
- if (! target)
- {
- end_sequence ();
- return FALSE;
- }
-
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
- return TRUE;
- }
-
- return FALSE;
-}
-
-/* Convert "if (test) foo++" into "foo += (test != 0)", and
- similarly for "foo--". */
-
-static int
-noce_try_addcc (struct noce_if_info *if_info)
-{
- rtx target, seq;
- int subtract, normalize;
-
- if (GET_CODE (if_info->a) == PLUS
- && rtx_equal_p (XEXP (if_info->a, 0), if_info->b)
- && (reversed_comparison_code (if_info->cond, if_info->jump)
- != UNKNOWN))
- {
- rtx cond = if_info->cond;
- enum rtx_code code = reversed_comparison_code (cond, if_info->jump);
-
- /* First try to use addcc pattern. */
- if (general_operand (XEXP (cond, 0), VOIDmode)
- && general_operand (XEXP (cond, 1), VOIDmode))
- {
- start_sequence ();
- target = emit_conditional_add (if_info->x, code,
- XEXP (cond, 0),
- XEXP (cond, 1),
- VOIDmode,
- if_info->b,
- XEXP (if_info->a, 1),
- GET_MODE (if_info->x),
- (code == LTU || code == GEU
- || code == LEU || code == GTU));
- if (target)
- {
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
- return TRUE;
- }
- end_sequence ();
- }
-
- /* If that fails, construct conditional increment or decrement using
- setcc. */
- if (BRANCH_COST >= 2
- && (XEXP (if_info->a, 1) == const1_rtx
- || XEXP (if_info->a, 1) == constm1_rtx))
- {
- start_sequence ();
- if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
- subtract = 0, normalize = 0;
- else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
- subtract = 1, normalize = 0;
- else
- subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
-
-
- target = noce_emit_store_flag (if_info,
- gen_reg_rtx (GET_MODE (if_info->x)),
- 1, normalize);
-
- if (target)
- target = expand_simple_binop (GET_MODE (if_info->x),
- subtract ? MINUS : PLUS,
- if_info->b, target, if_info->x,
- 0, OPTAB_WIDEN);
- if (target)
- {
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
- return TRUE;
- }
- end_sequence ();
- }
- }
-
- return FALSE;
-}
-
-/* Convert "if (test) x = 0;" to "x &= -(test == 0);" */
-
-static int
-noce_try_store_flag_mask (struct noce_if_info *if_info)
-{
- rtx target, seq;
- int reversep;
-
- reversep = 0;
- if ((BRANCH_COST >= 2
- || STORE_FLAG_VALUE == -1)
- && ((if_info->a == const0_rtx
- && rtx_equal_p (if_info->b, if_info->x))
- || ((reversep = (reversed_comparison_code (if_info->cond,
- if_info->jump)
- != UNKNOWN))
- && if_info->b == const0_rtx
- && rtx_equal_p (if_info->a, if_info->x))))
- {
- start_sequence ();
- target = noce_emit_store_flag (if_info,
- gen_reg_rtx (GET_MODE (if_info->x)),
- reversep, -1);
- if (target)
- target = expand_simple_binop (GET_MODE (if_info->x), AND,
- if_info->x,
- target, if_info->x, 0,
- OPTAB_WIDEN);
-
- if (target)
- {
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
- return TRUE;
- }
-
- end_sequence ();
- }
-
- return FALSE;
-}
-
-/* Helper function for noce_try_cmove and noce_try_cmove_arith. */
-
-static rtx
-noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
- rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue)
-{
- /* If earliest == jump, try to build the cmove insn directly.
- This is helpful when combine has created some complex condition
- (like for alpha's cmovlbs) that we can't hope to regenerate
- through the normal interface. */
-
- if (if_info->cond_earliest == if_info->jump)
- {
- rtx tmp;
-
- tmp = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), cmp_a, cmp_b);
- tmp = gen_rtx_IF_THEN_ELSE (GET_MODE (x), tmp, vtrue, vfalse);
- tmp = gen_rtx_SET (VOIDmode, x, tmp);
-
- start_sequence ();
- tmp = emit_insn (tmp);
-
- if (recog_memoized (tmp) >= 0)
- {
- tmp = get_insns ();
- end_sequence ();
- emit_insn (tmp);
-
- return x;
- }
-
- end_sequence ();
- }
-
- /* Don't even try if the comparison operands are weird. */
- if (! general_operand (cmp_a, GET_MODE (cmp_a))
- || ! general_operand (cmp_b, GET_MODE (cmp_b)))
- return NULL_RTX;
-
-#if HAVE_conditional_move
- return emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode,
- vtrue, vfalse, GET_MODE (x),
- (code == LTU || code == GEU
- || code == LEU || code == GTU));
-#else
- /* We'll never get here, as noce_process_if_block doesn't call the
- functions involved. Ifdef code, however, should be discouraged
- because it leads to typos in the code not selected. However,
- emit_conditional_move won't exist either. */
- return NULL_RTX;
-#endif
-}
-
-/* Try only simple constants and registers here. More complex cases
- are handled in noce_try_cmove_arith after noce_try_store_flag_arith
- has had a go at it. */
-
-static int
-noce_try_cmove (struct noce_if_info *if_info)
-{
- enum rtx_code code;
- rtx target, seq;
-
- if ((CONSTANT_P (if_info->a) || register_operand (if_info->a, VOIDmode))
- && (CONSTANT_P (if_info->b) || register_operand (if_info->b, VOIDmode)))
- {
- start_sequence ();
-
- code = GET_CODE (if_info->cond);
- target = noce_emit_cmove (if_info, if_info->x, code,
- XEXP (if_info->cond, 0),
- XEXP (if_info->cond, 1),
- if_info->a, if_info->b);
-
- if (target)
- {
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
- return TRUE;
- }
- else
- {
- end_sequence ();
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-/* Try more complex cases involving conditional_move. */
-
-static int
-noce_try_cmove_arith (struct noce_if_info *if_info)
-{
- rtx a = if_info->a;
- rtx b = if_info->b;
- rtx x = if_info->x;
- rtx orig_a, orig_b;
- rtx insn_a, insn_b;
- rtx tmp, target;
- int is_mem = 0;
- int insn_cost;
- enum rtx_code code;
-
- /* A conditional move from two memory sources is equivalent to a
- conditional on their addresses followed by a load. Don't do this
- early because it'll screw alias analysis. Note that we've
- already checked for no side effects. */
- /* ??? FIXME: Magic number 5. */
- if (cse_not_expected
- && MEM_P (a) && MEM_P (b)
- && BRANCH_COST >= 5)
- {
- a = XEXP (a, 0);
- b = XEXP (b, 0);
- x = gen_reg_rtx (Pmode);
- is_mem = 1;
- }
-
- /* ??? We could handle this if we knew that a load from A or B could
- not fault. This is also true if we've already loaded
- from the address along the path from ENTRY. */
- else if (may_trap_p (a) || may_trap_p (b))
- return FALSE;
-
- /* if (test) x = a + b; else x = c - d;
- => y = a + b;
- x = c - d;
- if (test)
- x = y;
- */
-
- code = GET_CODE (if_info->cond);
- insn_a = if_info->insn_a;
- insn_b = if_info->insn_b;
-
- /* Total insn_rtx_cost should be smaller than branch cost. Exit
- if insn_rtx_cost can't be estimated. */
- if (insn_a)
- {
- insn_cost = insn_rtx_cost (PATTERN (insn_a));
- if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (BRANCH_COST))
- return FALSE;
- }
- else
- insn_cost = 0;
-
- if (insn_b)
- {
- insn_cost += insn_rtx_cost (PATTERN (insn_b));
- if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (BRANCH_COST))
- return FALSE;
- }
-
- /* Possibly rearrange operands to make things come out more natural. */
- if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
- {
- int reversep = 0;
- if (rtx_equal_p (b, x))
- reversep = 1;
- else if (general_operand (b, GET_MODE (b)))
- reversep = 1;
-
- if (reversep)
- {
- code = reversed_comparison_code (if_info->cond, if_info->jump);
- tmp = a, a = b, b = tmp;
- tmp = insn_a, insn_a = insn_b, insn_b = tmp;
- }
- }
-
- start_sequence ();
-
- orig_a = a;
- orig_b = b;
-
- /* If either operand is complex, load it into a register first.
- The best way to do this is to copy the original insn. In this
- way we preserve any clobbers etc that the insn may have had.
- This is of course not possible in the IS_MEM case. */
- if (! general_operand (a, GET_MODE (a)))
- {
- rtx set;
-
- if (is_mem)
- {
- tmp = gen_reg_rtx (GET_MODE (a));
- tmp = emit_insn (gen_rtx_SET (VOIDmode, tmp, a));
- }
- else if (! insn_a)
- goto end_seq_and_fail;
- else
- {
- a = gen_reg_rtx (GET_MODE (a));
- tmp = copy_rtx (insn_a);
- set = single_set (tmp);
- SET_DEST (set) = a;
- tmp = emit_insn (PATTERN (tmp));
- }
- if (recog_memoized (tmp) < 0)
- goto end_seq_and_fail;
- }
- if (! general_operand (b, GET_MODE (b)))
- {
- rtx set, last;
-
- if (is_mem)
- {
- tmp = gen_reg_rtx (GET_MODE (b));
- tmp = gen_rtx_SET (VOIDmode, tmp, b);
- }
- else if (! insn_b)
- goto end_seq_and_fail;
- else
- {
- b = gen_reg_rtx (GET_MODE (b));
- tmp = copy_rtx (insn_b);
- set = single_set (tmp);
- SET_DEST (set) = b;
- tmp = PATTERN (tmp);
- }
-
- /* If insn to set up A clobbers any registers B depends on, try to
- swap insn that sets up A with the one that sets up B. If even
- that doesn't help, punt. */
- last = get_last_insn ();
- if (last && modified_in_p (orig_b, last))
- {
- tmp = emit_insn_before (tmp, get_insns ());
- if (modified_in_p (orig_a, tmp))
- goto end_seq_and_fail;
- }
- else
- tmp = emit_insn (tmp);
-
- if (recog_memoized (tmp) < 0)
- goto end_seq_and_fail;
- }
-
- target = noce_emit_cmove (if_info, x, code, XEXP (if_info->cond, 0),
- XEXP (if_info->cond, 1), a, b);
-
- if (! target)
- goto end_seq_and_fail;
-
- /* If we're handling a memory for above, emit the load now. */
- if (is_mem)
- {
- tmp = gen_rtx_MEM (GET_MODE (if_info->x), target);
-
- /* Copy over flags as appropriate. */
- if (MEM_VOLATILE_P (if_info->a) || MEM_VOLATILE_P (if_info->b))
- MEM_VOLATILE_P (tmp) = 1;
- if (MEM_IN_STRUCT_P (if_info->a) && MEM_IN_STRUCT_P (if_info->b))
- MEM_IN_STRUCT_P (tmp) = 1;
- if (MEM_SCALAR_P (if_info->a) && MEM_SCALAR_P (if_info->b))
- MEM_SCALAR_P (tmp) = 1;
- if (MEM_ALIAS_SET (if_info->a) == MEM_ALIAS_SET (if_info->b))
- set_mem_alias_set (tmp, MEM_ALIAS_SET (if_info->a));
- set_mem_align (tmp,
- MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b)));
-
- noce_emit_move_insn (if_info->x, tmp);
- }
- else if (target != x)
- noce_emit_move_insn (x, target);
-
- tmp = end_ifcvt_sequence (if_info);
- if (!tmp)
- return FALSE;
-
- emit_insn_before_setloc (tmp, if_info->jump, INSN_LOCATOR (if_info->insn_a));
- return TRUE;
-
- end_seq_and_fail:
- end_sequence ();
- return FALSE;
-}
-
-/* For most cases, the simplified condition we found is the best
- choice, but this is not the case for the min/max/abs transforms.
- For these we wish to know that it is A or B in the condition. */
-
-static rtx
-noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
- rtx *earliest)
-{
- rtx cond, set, insn;
- int reverse;
-
- /* If target is already mentioned in the known condition, return it. */
- if (reg_mentioned_p (target, if_info->cond))
- {
- *earliest = if_info->cond_earliest;
- return if_info->cond;
- }
-
- set = pc_set (if_info->jump);
- cond = XEXP (SET_SRC (set), 0);
- reverse
- = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
- && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump);
- if (if_info->then_else_reversed)
- reverse = !reverse;
-
- /* If we're looking for a constant, try to make the conditional
- have that constant in it. There are two reasons why it may
- not have the constant we want:
-
- 1. GCC may have needed to put the constant in a register, because
- the target can't compare directly against that constant. For
- this case, we look for a SET immediately before the comparison
- that puts a constant in that register.
-
- 2. GCC may have canonicalized the conditional, for example
- replacing "if x < 4" with "if x <= 3". We can undo that (or
- make equivalent types of changes) to get the constants we need
- if they're off by one in the right direction. */
-
- if (GET_CODE (target) == CONST_INT)
- {
- enum rtx_code code = GET_CODE (if_info->cond);
- rtx op_a = XEXP (if_info->cond, 0);
- rtx op_b = XEXP (if_info->cond, 1);
- rtx prev_insn;
-
- /* First, look to see if we put a constant in a register. */
- prev_insn = prev_nonnote_insn (if_info->cond_earliest);
- if (prev_insn
- && BLOCK_NUM (prev_insn) == BLOCK_NUM (if_info->cond_earliest)
- && INSN_P (prev_insn)
- && GET_CODE (PATTERN (prev_insn)) == SET)
- {
- rtx src = find_reg_equal_equiv_note (prev_insn);
- if (!src)
- src = SET_SRC (PATTERN (prev_insn));
- if (GET_CODE (src) == CONST_INT)
- {
- if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn))))
- op_a = src;
- else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn))))
- op_b = src;
-
- if (GET_CODE (op_a) == CONST_INT)
- {
- rtx tmp = op_a;
- op_a = op_b;
- op_b = tmp;
- code = swap_condition (code);
- }
- }
- }
-
- /* Now, look to see if we can get the right constant by
- adjusting the conditional. */
- if (GET_CODE (op_b) == CONST_INT)
- {
- HOST_WIDE_INT desired_val = INTVAL (target);
- HOST_WIDE_INT actual_val = INTVAL (op_b);
-
- switch (code)
- {
- case LT:
- if (actual_val == desired_val + 1)
- {
- code = LE;
- op_b = GEN_INT (desired_val);
- }
- break;
- case LE:
- if (actual_val == desired_val - 1)
- {
- code = LT;
- op_b = GEN_INT (desired_val);
- }
- break;
- case GT:
- if (actual_val == desired_val - 1)
- {
- code = GE;
- op_b = GEN_INT (desired_val);
- }
- break;
- case GE:
- if (actual_val == desired_val + 1)
- {
- code = GT;
- op_b = GEN_INT (desired_val);
- }
- break;
- default:
- break;
- }
- }
-
- /* If we made any changes, generate a new conditional that is
- equivalent to what we started with, but has the right
- constants in it. */
- if (code != GET_CODE (if_info->cond)
- || op_a != XEXP (if_info->cond, 0)
- || op_b != XEXP (if_info->cond, 1))
- {
- cond = gen_rtx_fmt_ee (code, GET_MODE (cond), op_a, op_b);
- *earliest = if_info->cond_earliest;
- return cond;
- }
- }
-
- cond = canonicalize_condition (if_info->jump, cond, reverse,
- earliest, target, false, true);
- if (! cond || ! reg_mentioned_p (target, cond))
- return NULL;
-
- /* We almost certainly searched back to a different place.
- Need to re-verify correct lifetimes. */
-
- /* X may not be mentioned in the range (cond_earliest, jump]. */
- for (insn = if_info->jump; insn != *earliest; insn = PREV_INSN (insn))
- if (INSN_P (insn) && reg_overlap_mentioned_p (if_info->x, PATTERN (insn)))
- return NULL;
-
- /* A and B may not be modified in the range [cond_earliest, jump). */
- for (insn = *earliest; insn != if_info->jump; insn = NEXT_INSN (insn))
- if (INSN_P (insn)
- && (modified_in_p (if_info->a, insn)
- || modified_in_p (if_info->b, insn)))
- return NULL;
-
- return cond;
-}
-
-/* Convert "if (a < b) x = a; else x = b;" to "x = min(a, b);", etc. */
-
-static int
-noce_try_minmax (struct noce_if_info *if_info)
-{
- rtx cond, earliest, target, seq;
- enum rtx_code code, op;
- int unsignedp;
-
- /* ??? Reject modes with NaNs or signed zeros since we don't know how
- they will be resolved with an SMIN/SMAX. It wouldn't be too hard
- to get the target to tell us... */
- if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x))
- || HONOR_NANS (GET_MODE (if_info->x)))
- return FALSE;
-
- cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
- if (!cond)
- return FALSE;
-
- /* Verify the condition is of the form we expect, and canonicalize
- the comparison code. */
- code = GET_CODE (cond);
- if (rtx_equal_p (XEXP (cond, 0), if_info->a))
- {
- if (! rtx_equal_p (XEXP (cond, 1), if_info->b))
- return FALSE;
- }
- else if (rtx_equal_p (XEXP (cond, 1), if_info->a))
- {
- if (! rtx_equal_p (XEXP (cond, 0), if_info->b))
- return FALSE;
- code = swap_condition (code);
- }
- else
- return FALSE;
-
- /* Determine what sort of operation this is. Note that the code is for
- a taken branch, so the code->operation mapping appears backwards. */
- switch (code)
- {
- case LT:
- case LE:
- case UNLT:
- case UNLE:
- op = SMAX;
- unsignedp = 0;
- break;
- case GT:
- case GE:
- case UNGT:
- case UNGE:
- op = SMIN;
- unsignedp = 0;
- break;
- case LTU:
- case LEU:
- op = UMAX;
- unsignedp = 1;
- break;
- case GTU:
- case GEU:
- op = UMIN;
- unsignedp = 1;
- break;
- default:
- return FALSE;
- }
-
- start_sequence ();
-
- target = expand_simple_binop (GET_MODE (if_info->x), op,
- if_info->a, if_info->b,
- if_info->x, unsignedp, OPTAB_WIDEN);
- if (! target)
- {
- end_sequence ();
- return FALSE;
- }
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
- if_info->cond = cond;
- if_info->cond_earliest = earliest;
-
- return TRUE;
-}
-
-/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", etc. */
-
-static int
-noce_try_abs (struct noce_if_info *if_info)
-{
- rtx cond, earliest, target, seq, a, b, c;
- int negate;
-
- /* Reject modes with signed zeros. */
- if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x)))
- return FALSE;
-
- /* Recognize A and B as constituting an ABS or NABS. The canonical
- form is a branch around the negation, taken when the object is the
- first operand of a comparison against 0 that evaluates to true. */
- a = if_info->a;
- b = if_info->b;
- if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b))
- negate = 0;
- else if (GET_CODE (b) == NEG && rtx_equal_p (XEXP (b, 0), a))
- {
- c = a; a = b; b = c;
- negate = 1;
- }
- else
- return FALSE;
-
- cond = noce_get_alt_condition (if_info, b, &earliest);
- if (!cond)
- return FALSE;
-
- /* Verify the condition is of the form we expect. */
- if (rtx_equal_p (XEXP (cond, 0), b))
- c = XEXP (cond, 1);
- else if (rtx_equal_p (XEXP (cond, 1), b))
- {
- c = XEXP (cond, 0);
- negate = !negate;
- }
- else
- return FALSE;
-
- /* Verify that C is zero. Search one step backward for a
- REG_EQUAL note or a simple source if necessary. */
- if (REG_P (c))
- {
- rtx set, insn = prev_nonnote_insn (earliest);
- if (insn
- && BLOCK_NUM (insn) == BLOCK_NUM (earliest)
- && (set = single_set (insn))
- && rtx_equal_p (SET_DEST (set), c))
- {
- rtx note = find_reg_equal_equiv_note (insn);
- if (note)
- c = XEXP (note, 0);
- else
- c = SET_SRC (set);
- }
- else
- return FALSE;
- }
- if (MEM_P (c)
- && GET_CODE (XEXP (c, 0)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (c, 0)))
- c = get_pool_constant (XEXP (c, 0));
-
- /* Work around funny ideas get_condition has wrt canonicalization.
- Note that these rtx constants are known to be CONST_INT, and
- therefore imply integer comparisons. */
- if (c == constm1_rtx && GET_CODE (cond) == GT)
- ;
- else if (c == const1_rtx && GET_CODE (cond) == LT)
- ;
- else if (c != CONST0_RTX (GET_MODE (b)))
- return FALSE;
-
- /* Determine what sort of operation this is. */
- switch (GET_CODE (cond))
- {
- case LT:
- case LE:
- case UNLT:
- case UNLE:
- negate = !negate;
- break;
- case GT:
- case GE:
- case UNGT:
- case UNGE:
- break;
- default:
- return FALSE;
- }
-
- start_sequence ();
-
- target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1);
-
- /* ??? It's a quandary whether cmove would be better here, especially
- for integers. Perhaps combine will clean things up. */
- if (target && negate)
- target = expand_simple_unop (GET_MODE (target), NEG, target, if_info->x, 0);
-
- if (! target)
- {
- end_sequence ();
- return FALSE;
- }
-
- if (target != if_info->x)
- noce_emit_move_insn (if_info->x, target);
-
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
- if_info->cond = cond;
- if_info->cond_earliest = earliest;
-
- return TRUE;
-}
-
-/* Convert "if (m < 0) x = b; else x = 0;" to "x = (m >> C) & b;". */
-
-static int
-noce_try_sign_mask (struct noce_if_info *if_info)
-{
- rtx cond, t, m, c, seq;
- enum machine_mode mode;
- enum rtx_code code;
- bool b_unconditional;
-
- cond = if_info->cond;
- code = GET_CODE (cond);
- m = XEXP (cond, 0);
- c = XEXP (cond, 1);
-
- t = NULL_RTX;
- if (if_info->a == const0_rtx)
- {
- if ((code == LT && c == const0_rtx)
- || (code == LE && c == constm1_rtx))
- t = if_info->b;
- }
- else if (if_info->b == const0_rtx)
- {
- if ((code == GE && c == const0_rtx)
- || (code == GT && c == constm1_rtx))
- t = if_info->a;
- }
-
- if (! t || side_effects_p (t))
- return FALSE;
-
- /* We currently don't handle different modes. */
- mode = GET_MODE (t);
- if (GET_MODE (m) != mode)
- return FALSE;
-
- /* This is only profitable if T is cheap, or T is unconditionally
- executed/evaluated in the original insn sequence. The latter
- happens if INSN_B was taken from TEST_BB, or if there was no
- INSN_B which can happen for e.g. conditional stores to memory. */
- b_unconditional = (if_info->insn_b == NULL_RTX
- || BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb);
- if (rtx_cost (t, SET) >= COSTS_N_INSNS (2)
- && (!b_unconditional
- || t != if_info->b))
- return FALSE;
-
- start_sequence ();
- /* Use emit_store_flag to generate "m < 0 ? -1 : 0" instead of expanding
- "(signed) m >> 31" directly. This benefits targets with specialized
- insns to obtain the signmask, but still uses ashr_optab otherwise. */
- m = emit_store_flag (gen_reg_rtx (mode), LT, m, const0_rtx, mode, 0, -1);
- t = m ? expand_binop (mode, and_optab, m, t, NULL_RTX, 0, OPTAB_DIRECT)
- : NULL_RTX;
-
- if (!t)
- {
- end_sequence ();
- return FALSE;
- }
-
- noce_emit_move_insn (if_info->x, t);
-
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
- return TRUE;
-}
-
-
-/* Optimize away "if (x & C) x |= C" and similar bit manipulation
- transformations. */
-
-static int
-noce_try_bitop (struct noce_if_info *if_info)
-{
- rtx cond, x, a, result, seq;
- enum machine_mode mode;
- enum rtx_code code;
- int bitnum;
-
- x = if_info->x;
- cond = if_info->cond;
- code = GET_CODE (cond);
-
- /* Check for no else condition. */
- if (! rtx_equal_p (x, if_info->b))
- return FALSE;
-
- /* Check for a suitable condition. */
- if (code != NE && code != EQ)
- return FALSE;
- if (XEXP (cond, 1) != const0_rtx)
- return FALSE;
- cond = XEXP (cond, 0);
-
- /* ??? We could also handle AND here. */
- if (GET_CODE (cond) == ZERO_EXTRACT)
- {
- if (XEXP (cond, 1) != const1_rtx
- || GET_CODE (XEXP (cond, 2)) != CONST_INT
- || ! rtx_equal_p (x, XEXP (cond, 0)))
- return FALSE;
- bitnum = INTVAL (XEXP (cond, 2));
- mode = GET_MODE (x);
- if (BITS_BIG_ENDIAN)
- bitnum = GET_MODE_BITSIZE (mode) - 1 - bitnum;
- if (bitnum < 0 || bitnum >= HOST_BITS_PER_WIDE_INT)
- return FALSE;
- }
- else
- return FALSE;
-
- a = if_info->a;
- if (GET_CODE (a) == IOR || GET_CODE (a) == XOR)
- {
- /* Check for "if (X & C) x = x op C". */
- if (! rtx_equal_p (x, XEXP (a, 0))
- || GET_CODE (XEXP (a, 1)) != CONST_INT
- || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
- != (unsigned HOST_WIDE_INT) 1 << bitnum)
- return FALSE;
-
- /* if ((x & C) == 0) x |= C; is transformed to x |= C. */
- /* if ((x & C) != 0) x |= C; is transformed to nothing. */
- if (GET_CODE (a) == IOR)
- result = (code == NE) ? a : NULL_RTX;
- else if (code == NE)
- {
- /* if ((x & C) == 0) x ^= C; is transformed to x |= C. */
- result = gen_int_mode ((HOST_WIDE_INT) 1 << bitnum, mode);
- result = simplify_gen_binary (IOR, mode, x, result);
- }
- else
- {
- /* if ((x & C) != 0) x ^= C; is transformed to x &= ~C. */
- result = gen_int_mode (~((HOST_WIDE_INT) 1 << bitnum), mode);
- result = simplify_gen_binary (AND, mode, x, result);
- }
- }
- else if (GET_CODE (a) == AND)
- {
- /* Check for "if (X & C) x &= ~C". */
- if (! rtx_equal_p (x, XEXP (a, 0))
- || GET_CODE (XEXP (a, 1)) != CONST_INT
- || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
- != (~((HOST_WIDE_INT) 1 << bitnum) & GET_MODE_MASK (mode)))
- return FALSE;
-
- /* if ((x & C) == 0) x &= ~C; is transformed to nothing. */
- /* if ((x & C) != 0) x &= ~C; is transformed to x &= ~C. */
- result = (code == EQ) ? a : NULL_RTX;
- }
- else
- return FALSE;
-
- if (result)
- {
- start_sequence ();
- noce_emit_move_insn (x, result);
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
- }
- return TRUE;
-}
-
-
-/* Similar to get_condition, only the resulting condition must be
- valid at JUMP, instead of at EARLIEST.
-
- If THEN_ELSE_REVERSED is true, the fallthrough does not go to the
- THEN block of the caller, and we have to reverse the condition. */
-
-static rtx
-noce_get_condition (rtx jump, rtx *earliest, bool then_else_reversed)
-{
- rtx cond, set, tmp;
- bool reverse;
-
- if (! any_condjump_p (jump))
- return NULL_RTX;
-
- set = pc_set (jump);
-
- /* If this branches to JUMP_LABEL when the condition is false,
- reverse the condition. */
- reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
- && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump));
-
- /* We may have to reverse because the caller's if block is not canonical,
- i.e. the THEN block isn't the fallthrough block for the TEST block
- (see find_if_header). */
- if (then_else_reversed)
- reverse = !reverse;
-
- /* If the condition variable is a register and is MODE_INT, accept it. */
-
- cond = XEXP (SET_SRC (set), 0);
- tmp = XEXP (cond, 0);
- if (REG_P (tmp) && GET_MODE_CLASS (GET_MODE (tmp)) == MODE_INT)
- {
- *earliest = jump;
-
- if (reverse)
- cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
- GET_MODE (cond), tmp, XEXP (cond, 1));
- return cond;
- }
-
- /* Otherwise, fall back on canonicalize_condition to do the dirty
- work of manipulating MODE_CC values and COMPARE rtx codes. */
- return canonicalize_condition (jump, cond, reverse, earliest,
- NULL_RTX, false, true);
-}
-
-/* Return true if OP is ok for if-then-else processing. */
-
-static int
-noce_operand_ok (const_rtx op)
-{
- /* We special-case memories, so handle any of them with
- no address side effects. */
- if (MEM_P (op))
- return ! side_effects_p (XEXP (op, 0));
-
- if (side_effects_p (op))
- return FALSE;
-
- return ! may_trap_p (op);
-}
-
-/* Return true if a write into MEM may trap or fault. */
-
-static bool
-noce_mem_write_may_trap_or_fault_p (const_rtx mem)
-{
- rtx addr;
-
- if (MEM_READONLY_P (mem))
- return true;
-
- if (may_trap_or_fault_p (mem))
- return true;
-
- addr = XEXP (mem, 0);
-
- /* Call target hook to avoid the effects of -fpic etc.... */
- addr = targetm.delegitimize_address (addr);
-
- while (addr)
- switch (GET_CODE (addr))
- {
- case CONST:
- case PRE_DEC:
- case PRE_INC:
- case POST_DEC:
- case POST_INC:
- case POST_MODIFY:
- addr = XEXP (addr, 0);
- break;
- case LO_SUM:
- case PRE_MODIFY:
- addr = XEXP (addr, 1);
- break;
- case PLUS:
- if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
- addr = XEXP (addr, 0);
- else
- return false;
- break;
- case LABEL_REF:
- return true;
- case SYMBOL_REF:
- if (SYMBOL_REF_DECL (addr)
- && decl_readonly_section (SYMBOL_REF_DECL (addr), 0))
- return true;
- return false;
- default:
- return false;
- }
-
- return false;
-}
-
-/* Return whether we can use store speculation for MEM. TOP_BB is the
- basic block above the conditional block where we are considering
- doing the speculative store. We look for whether MEM is set
- unconditionally later in the function. */
-
-static bool
-noce_can_store_speculate_p (basic_block top_bb, const_rtx mem)
-{
- basic_block dominator;
-
- for (dominator = get_immediate_dominator (CDI_POST_DOMINATORS, top_bb);
- dominator != NULL;
- dominator = get_immediate_dominator (CDI_POST_DOMINATORS, dominator))
- {
- rtx insn;
-
- FOR_BB_INSNS (dominator, insn)
- {
- /* If we see something that might be a memory barrier, we
- have to stop looking. Even if the MEM is set later in
- the function, we still don't want to set it
- unconditionally before the barrier. */
- if (INSN_P (insn)
- && (volatile_insn_p (PATTERN (insn))
- || (CALL_P (insn)
- && (!CONST_OR_PURE_CALL_P (insn)
- || pure_call_p (insn)))))
- return false;
-
- if (memory_modified_in_insn_p (mem, insn))
- return true;
- if (modified_in_p (XEXP (mem, 0), insn))
- return false;
-
- }
- }
-
- return false;
-}
-
-/* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert
- it without using conditional execution. Return TRUE if we were successful
- at converting the block. */
-
-static int
-noce_process_if_block (struct noce_if_info *if_info)
-{
- basic_block test_bb = if_info->test_bb; /* test block */
- basic_block then_bb = if_info->then_bb; /* THEN */
- basic_block else_bb = if_info->else_bb; /* ELSE or NULL */
- basic_block join_bb = if_info->join_bb; /* JOIN */
- rtx jump = if_info->jump;
- rtx cond = if_info->cond;
- rtx insn_a, insn_b;
- rtx set_a, set_b;
- rtx orig_x, x, a, b;
-
- /* We're looking for patterns of the form
-
- (1) if (...) x = a; else x = b;
- (2) x = b; if (...) x = a;
- (3) if (...) x = a; // as if with an initial x = x.
-
- The later patterns require jumps to be more expensive.
-
- ??? For future expansion, look for multiple X in such patterns. */
-
- /* Look for one of the potential sets. */
- insn_a = first_active_insn (then_bb);
- if (! insn_a
- || insn_a != last_active_insn (then_bb, FALSE)
- || (set_a = single_set (insn_a)) == NULL_RTX)
- return FALSE;
-
- x = SET_DEST (set_a);
- a = SET_SRC (set_a);
-
- /* Look for the other potential set. Make sure we've got equivalent
- destinations. */
- /* ??? This is overconservative. Storing to two different mems is
- as easy as conditionally computing the address. Storing to a
- single mem merely requires a scratch memory to use as one of the
- destination addresses; often the memory immediately below the
- stack pointer is available for this. */
- set_b = NULL_RTX;
- if (else_bb)
- {
- insn_b = first_active_insn (else_bb);
- if (! insn_b
- || insn_b != last_active_insn (else_bb, FALSE)
- || (set_b = single_set (insn_b)) == NULL_RTX
- || ! rtx_equal_p (x, SET_DEST (set_b)))
- return FALSE;
- }
- else
- {
- insn_b = prev_nonnote_insn (if_info->cond_earliest);
- /* We're going to be moving the evaluation of B down from above
- COND_EARLIEST to JUMP. Make sure the relevant data is still
- intact. */
- if (! insn_b
- || BLOCK_NUM (insn_b) != BLOCK_NUM (if_info->cond_earliest)
- || !NONJUMP_INSN_P (insn_b)
- || (set_b = single_set (insn_b)) == NULL_RTX
- || ! rtx_equal_p (x, SET_DEST (set_b))
- || reg_overlap_mentioned_p (x, SET_SRC (set_b))
- || modified_between_p (SET_SRC (set_b),
- PREV_INSN (if_info->cond_earliest), jump)
- /* Likewise with X. In particular this can happen when
- noce_get_condition looks farther back in the instruction
- stream than one might expect. */
- || reg_overlap_mentioned_p (x, cond)
- || reg_overlap_mentioned_p (x, a)
- || modified_between_p (x, PREV_INSN (if_info->cond_earliest), jump))
- insn_b = set_b = NULL_RTX;
- }
-
- /* If x has side effects then only the if-then-else form is safe to
- convert. But even in that case we would need to restore any notes
- (such as REG_INC) at then end. That can be tricky if
- noce_emit_move_insn expands to more than one insn, so disable the
- optimization entirely for now if there are side effects. */
- if (side_effects_p (x))
- return FALSE;
-
- b = (set_b ? SET_SRC (set_b) : x);
-
- /* Only operate on register destinations, and even then avoid extending
- the lifetime of hard registers on small register class machines. */
- orig_x = x;
- if (!REG_P (x)
- || (SMALL_REGISTER_CLASSES
- && REGNO (x) < FIRST_PSEUDO_REGISTER))
- {
- if (GET_MODE (x) == BLKmode)
- return FALSE;
-
- if (GET_MODE (x) == ZERO_EXTRACT
- && (GET_CODE (XEXP (x, 1)) != CONST_INT
- || GET_CODE (XEXP (x, 2)) != CONST_INT))
- return FALSE;
-
- x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
- ? XEXP (x, 0) : x));
- }
-
- /* Don't operate on sources that may trap or are volatile. */
- if (! noce_operand_ok (a) || ! noce_operand_ok (b))
- return FALSE;
-
- /* Set up the info block for our subroutines. */
- if_info->insn_a = insn_a;
- if_info->insn_b = insn_b;
- if_info->x = x;
- if_info->a = a;
- if_info->b = b;
-
- /* Try optimizations in some approximation of a useful order. */
- /* ??? Should first look to see if X is live incoming at all. If it
- isn't, we don't need anything but an unconditional set. */
-
- /* Look and see if A and B are really the same. Avoid creating silly
- cmove constructs that no one will fix up later. */
- if (rtx_equal_p (a, b))
- {
- /* If we have an INSN_B, we don't have to create any new rtl. Just
- move the instruction that we already have. If we don't have an
- INSN_B, that means that A == X, and we've got a noop move. In
- that case don't do anything and let the code below delete INSN_A. */
- if (insn_b && else_bb)
- {
- rtx note;
-
- if (else_bb && insn_b == BB_END (else_bb))
- BB_END (else_bb) = PREV_INSN (insn_b);
- reorder_insns (insn_b, insn_b, PREV_INSN (jump));
-
- /* If there was a REG_EQUAL note, delete it since it may have been
- true due to this insn being after a jump. */
- if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0)
- remove_note (insn_b, note);
-
- insn_b = NULL_RTX;
- }
- /* If we have "x = b; if (...) x = a;", and x has side-effects, then
- x must be executed twice. */
- else if (insn_b && side_effects_p (orig_x))
- return FALSE;
-
- x = orig_x;
- goto success;
- }
-
- if (!set_b && MEM_P (orig_x))
- {
- /* Disallow the "if (...) x = a;" form (implicit "else x = x;")
- for optimizations if writing to x may trap or fault,
- i.e. it's a memory other than a static var or a stack slot,
- is misaligned on strict aligned machines or is read-only. If
- x is a read-only memory, then the program is valid only if we
- avoid the store into it. If there are stores on both the
- THEN and ELSE arms, then we can go ahead with the conversion;
- either the program is broken, or the condition is always
- false such that the other memory is selected. */
- if (noce_mem_write_may_trap_or_fault_p (orig_x))
- return FALSE;
-
- /* Avoid store speculation: given "if (...) x = a" where x is a
- MEM, we only want to do the store if x is always set
- somewhere in the function. This avoids cases like
- if (pthread_mutex_trylock(mutex))
- ++global_variable;
- where we only want global_variable to be changed if the mutex
- is held. FIXME: This should ideally be expressed directly in
- RTL somehow. */
- if (!noce_can_store_speculate_p (test_bb, orig_x))
- return FALSE;
- }
-
- if (noce_try_move (if_info))
- goto success;
- if (noce_try_store_flag (if_info))
- goto success;
- if (noce_try_bitop (if_info))
- goto success;
- if (noce_try_minmax (if_info))
- goto success;
- if (noce_try_abs (if_info))
- goto success;
- if (HAVE_conditional_move
- && noce_try_cmove (if_info))
- goto success;
- if (! HAVE_conditional_execution)
- {
- if (noce_try_store_flag_constants (if_info))
- goto success;
- if (noce_try_addcc (if_info))
- goto success;
- if (noce_try_store_flag_mask (if_info))
- goto success;
- if (HAVE_conditional_move
- && noce_try_cmove_arith (if_info))
- goto success;
- if (noce_try_sign_mask (if_info))
- goto success;
- }
-
- return FALSE;
-
- success:
-
- /* If we used a temporary, fix it up now. */
- if (orig_x != x)
- {
- rtx seq;
-
- start_sequence ();
- noce_emit_move_insn (orig_x, x);
- seq = get_insns ();
- set_used_flags (orig_x);
- unshare_all_rtl_in_chain (seq);
- end_sequence ();
-
- emit_insn_before_setloc (seq, BB_END (test_bb), INSN_LOCATOR (insn_a));
- }
-
- /* The original THEN and ELSE blocks may now be removed. The test block
- must now jump to the join block. If the test block and the join block
- can be merged, do so. */
- if (else_bb)
- {
- delete_basic_block (else_bb);
- num_true_changes++;
- }
- else
- remove_edge (find_edge (test_bb, join_bb));
-
- remove_edge (find_edge (then_bb, join_bb));
- redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb);
- delete_basic_block (then_bb);
- num_true_changes++;
-
- if (can_merge_blocks_p (test_bb, join_bb))
- {
- merge_blocks (test_bb, join_bb);
- num_true_changes++;
- }
-
- num_updated_if_blocks++;
- return TRUE;
-}
-
-/* Check whether a block is suitable for conditional move conversion.
- Every insn must be a simple set of a register to a constant or a
- register. For each assignment, store the value in the array VALS,
- indexed by register number, then store the register number in
- REGS. COND is the condition we will test. */
-
-static int
-check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) *regs, rtx cond)
-{
- rtx insn;
-
- /* We can only handle simple jumps at the end of the basic block.
- It is almost impossible to update the CFG otherwise. */
- insn = BB_END (bb);
- if (JUMP_P (insn) && !onlyjump_p (insn))
- return FALSE;
-
- FOR_BB_INSNS (bb, insn)
- {
- rtx set, dest, src;
-
- if (!INSN_P (insn) || JUMP_P (insn))
- continue;
- set = single_set (insn);
- if (!set)
- return FALSE;
-
- dest = SET_DEST (set);
- src = SET_SRC (set);
- if (!REG_P (dest)
- || (SMALL_REGISTER_CLASSES && HARD_REGISTER_P (dest)))
- return FALSE;
-
- if (!CONSTANT_P (src) && !register_operand (src, VOIDmode))
- return FALSE;
-
- if (side_effects_p (src) || side_effects_p (dest))
- return FALSE;
-
- if (may_trap_p (src) || may_trap_p (dest))
- return FALSE;
-
- /* Don't try to handle this if the source register was
- modified earlier in the block. */
- if ((REG_P (src)
- && vals[REGNO (src)] != NULL)
- || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src))
- && vals[REGNO (SUBREG_REG (src))] != NULL))
- return FALSE;
-
- /* Don't try to handle this if the destination register was
- modified earlier in the block. */
- if (vals[REGNO (dest)] != NULL)
- return FALSE;
-
- /* Don't try to handle this if the condition uses the
- destination register. */
- if (reg_overlap_mentioned_p (dest, cond))
- return FALSE;
-
- /* Don't try to handle this if the source register is modified
- later in the block. */
- if (!CONSTANT_P (src)
- && modified_between_p (src, insn, NEXT_INSN (BB_END (bb))))
- return FALSE;
-
- vals[REGNO (dest)] = src;
-
- VEC_safe_push (int, heap, regs, REGNO (dest));
- }
-
- return TRUE;
-}
-
-/* Given a basic block BB suitable for conditional move conversion,
- a condition COND, and arrays THEN_VALS and ELSE_VALS containing the
- register values depending on COND, emit the insns in the block as
- conditional moves. If ELSE_BLOCK is true, THEN_BB was already
- processed. The caller has started a sequence for the conversion.
- Return true if successful, false if something goes wrong. */
-
-static bool
-cond_move_convert_if_block (struct noce_if_info *if_infop,
- basic_block bb, rtx cond,
- rtx *then_vals, rtx *else_vals,
- bool else_block_p)
-{
- enum rtx_code code;
- rtx insn, cond_arg0, cond_arg1;
-
- code = GET_CODE (cond);
- cond_arg0 = XEXP (cond, 0);
- cond_arg1 = XEXP (cond, 1);
-
- FOR_BB_INSNS (bb, insn)
- {
- rtx set, target, dest, t, e;
- unsigned int regno;
-
- if (!INSN_P (insn) || JUMP_P (insn))
- continue;
- set = single_set (insn);
- gcc_assert (set && REG_P (SET_DEST (set)));
-
- dest = SET_DEST (set);
- regno = REGNO (dest);
-
- t = then_vals[regno];
- e = else_vals[regno];
-
- if (else_block_p)
- {
- /* If this register was set in the then block, we already
- handled this case there. */
- if (t)
- continue;
- t = dest;
- gcc_assert (e);
- }
- else
- {
- gcc_assert (t);
- if (!e)
- e = dest;
- }
-
- target = noce_emit_cmove (if_infop, dest, code, cond_arg0, cond_arg1,
- t, e);
- if (!target)
- return false;
-
- if (target != dest)
- noce_emit_move_insn (dest, target);
- }
-
- return true;
-}
-
-/* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert
- it using only conditional moves. Return TRUE if we were successful at
- converting the block. */
-
-static int
-cond_move_process_if_block (struct noce_if_info *if_info)
-{
- basic_block test_bb = if_info->test_bb;
- basic_block then_bb = if_info->then_bb;
- basic_block else_bb = if_info->else_bb;
- basic_block join_bb = if_info->join_bb;
- rtx jump = if_info->jump;
- rtx cond = if_info->cond;
- rtx seq, loc_insn;
- int max_reg, size, c, reg;
- rtx *then_vals;
- rtx *else_vals;
- VEC (int, heap) *then_regs = NULL;
- VEC (int, heap) *else_regs = NULL;
- unsigned int i;
-
- /* Build a mapping for each block to the value used for each
- register. */
- max_reg = max_reg_num ();
- size = (max_reg + 1) * sizeof (rtx);
- then_vals = (rtx *) alloca (size);
- else_vals = (rtx *) alloca (size);
- memset (then_vals, 0, size);
- memset (else_vals, 0, size);
-
- /* Make sure the blocks are suitable. */
- if (!check_cond_move_block (then_bb, then_vals, then_regs, cond)
- || (else_bb && !check_cond_move_block (else_bb, else_vals, else_regs, cond)))
- return FALSE;
-
- /* Make sure the blocks can be used together. If the same register
- is set in both blocks, and is not set to a constant in both
- cases, then both blocks must set it to the same register. We
- have already verified that if it is set to a register, that the
- source register does not change after the assignment. Also count
- the number of registers set in only one of the blocks. */
- c = 0;
- for (i = 0; VEC_iterate (int, then_regs, i, reg); i++)
- {
- if (!then_vals[reg] && !else_vals[reg])
- continue;
-
- if (!else_vals[reg])
- ++c;
- else
- {
- if (!CONSTANT_P (then_vals[reg])
- && !CONSTANT_P (else_vals[reg])
- && !rtx_equal_p (then_vals[reg], else_vals[reg]))
- return FALSE;
- }
- }
-
- /* Finish off c for MAX_CONDITIONAL_EXECUTE. */
- for (i = 0; VEC_iterate (int, else_regs, i, reg); ++i)
- if (!then_vals[reg])
- ++c;
-
- /* Make sure it is reasonable to convert this block. What matters
- is the number of assignments currently made in only one of the
- branches, since if we convert we are going to always execute
- them. */
- if (c > MAX_CONDITIONAL_EXECUTE)
- return FALSE;
-
- /* Try to emit the conditional moves. First do the then block,
- then do anything left in the else blocks. */
- start_sequence ();
- if (!cond_move_convert_if_block (if_info, then_bb, cond,
- then_vals, else_vals, false)
- || (else_bb
- && !cond_move_convert_if_block (if_info, else_bb, cond,
- then_vals, else_vals, true)))
- {
- end_sequence ();
- return FALSE;
- }
- seq = end_ifcvt_sequence (if_info);
- if (!seq)
- return FALSE;
-
- loc_insn = first_active_insn (then_bb);
- if (!loc_insn)
- {
- loc_insn = first_active_insn (else_bb);
- gcc_assert (loc_insn);
- }
- emit_insn_before_setloc (seq, jump, INSN_LOCATOR (loc_insn));
-
- if (else_bb)
- {
- delete_basic_block (else_bb);
- num_true_changes++;
- }
- else
- remove_edge (find_edge (test_bb, join_bb));
-
- remove_edge (find_edge (then_bb, join_bb));
- redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb);
- delete_basic_block (then_bb);
- num_true_changes++;
-
- if (can_merge_blocks_p (test_bb, join_bb))
- {
- merge_blocks (test_bb, join_bb);
- num_true_changes++;
- }
-
- num_updated_if_blocks++;
-
- VEC_free (int, heap, then_regs);
- VEC_free (int, heap, else_regs);
-
- return TRUE;
-}
-
-
-/* Determine if a given basic block heads a simple IF-THEN-JOIN or an
- IF-THEN-ELSE-JOIN block.
-
- If so, we'll try to convert the insns to not require the branch,
- using only transformations that do not require conditional execution.
-
- Return TRUE if we were successful at converting the block. */
-
-static int
-noce_find_if_block (basic_block test_bb,
- edge then_edge, edge else_edge,
- int pass)
-{
- basic_block then_bb, else_bb, join_bb;
- bool then_else_reversed = false;
- rtx jump, cond;
- rtx cond_earliest;
- struct noce_if_info if_info;
-
- /* We only ever should get here before reload. */
- gcc_assert (!reload_completed);
-
- /* Recognize an IF-THEN-ELSE-JOIN block. */
- if (single_pred_p (then_edge->dest)
- && single_succ_p (then_edge->dest)
- && single_pred_p (else_edge->dest)
- && single_succ_p (else_edge->dest)
- && single_succ (then_edge->dest) == single_succ (else_edge->dest))
- {
- then_bb = then_edge->dest;
- else_bb = else_edge->dest;
- join_bb = single_succ (then_bb);
- }
- /* Recognize an IF-THEN-JOIN block. */
- else if (single_pred_p (then_edge->dest)
- && single_succ_p (then_edge->dest)
- && single_succ (then_edge->dest) == else_edge->dest)
- {
- then_bb = then_edge->dest;
- else_bb = NULL_BLOCK;
- join_bb = else_edge->dest;
- }
- /* Recognize an IF-ELSE-JOIN block. We can have those because the order
- of basic blocks in cfglayout mode does not matter, so the fallthrough
- edge can go to any basic block (and not just to bb->next_bb, like in
- cfgrtl mode). */
- else if (single_pred_p (else_edge->dest)
- && single_succ_p (else_edge->dest)
- && single_succ (else_edge->dest) == then_edge->dest)
- {
- /* The noce transformations do not apply to IF-ELSE-JOIN blocks.
- To make this work, we have to invert the THEN and ELSE blocks
- and reverse the jump condition. */
- then_bb = else_edge->dest;
- else_bb = NULL_BLOCK;
- join_bb = single_succ (then_bb);
- then_else_reversed = true;
- }
- else
- /* Not a form we can handle. */
- return FALSE;
-
- /* The edges of the THEN and ELSE blocks cannot have complex edges. */
- if (single_succ_edge (then_bb)->flags & EDGE_COMPLEX)
- return FALSE;
- if (else_bb
- && single_succ_edge (else_bb)->flags & EDGE_COMPLEX)
- return FALSE;
-
- num_possible_if_blocks++;
-
- if (dump_file)
- {
- fprintf (dump_file,
- "\nIF-THEN%s-JOIN block found, pass %d, test %d, then %d",
- (else_bb) ? "-ELSE" : "",
- pass, test_bb->index, then_bb->index);
-
- if (else_bb)
- fprintf (dump_file, ", else %d", else_bb->index);
-
- fprintf (dump_file, ", join %d\n", join_bb->index);
- }
-
- /* If the conditional jump is more than just a conditional
- jump, then we can not do if-conversion on this block. */
- jump = BB_END (test_bb);
- if (! onlyjump_p (jump))
- return FALSE;
-
- /* If this is not a standard conditional jump, we can't parse it. */
- cond = noce_get_condition (jump,
- &cond_earliest,
- then_else_reversed);
- if (!cond)
- return FALSE;
-
- /* We must be comparing objects whose modes imply the size. */
- if (GET_MODE (XEXP (cond, 0)) == BLKmode)
- return FALSE;
-
- /* Initialize an IF_INFO struct to pass around. */
- memset (&if_info, 0, sizeof if_info);
- if_info.test_bb = test_bb;
- if_info.then_bb = then_bb;
- if_info.else_bb = else_bb;
- if_info.join_bb = join_bb;
- if_info.cond = cond;
- if_info.cond_earliest = cond_earliest;
- if_info.jump = jump;
- if_info.then_else_reversed = then_else_reversed;
-
- /* Do the real work. */
-
- if (noce_process_if_block (&if_info))
- return TRUE;
-
- if (HAVE_conditional_move
- && cond_move_process_if_block (&if_info))
- return TRUE;
-
- return FALSE;
-}
-
-
-/* Merge the blocks and mark for local life update. */
-
-static void
-merge_if_block (struct ce_if_block * ce_info)
-{
- basic_block test_bb = ce_info->test_bb; /* last test block */
- basic_block then_bb = ce_info->then_bb; /* THEN */
- basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */
- basic_block join_bb = ce_info->join_bb; /* join block */
- basic_block combo_bb;
-
- /* All block merging is done into the lower block numbers. */
-
- combo_bb = test_bb;
- df_set_bb_dirty (test_bb);
-
- /* Merge any basic blocks to handle && and || subtests. Each of
- the blocks are on the fallthru path from the predecessor block. */
- if (ce_info->num_multiple_test_blocks > 0)
- {
- basic_block bb = test_bb;
- basic_block last_test_bb = ce_info->last_test_bb;
- basic_block fallthru = block_fallthru (bb);
-
- do
- {
- bb = fallthru;
- fallthru = block_fallthru (bb);
- merge_blocks (combo_bb, bb);
- num_true_changes++;
- }
- while (bb != last_test_bb);
- }
-
- /* Merge TEST block into THEN block. Normally the THEN block won't have a
- label, but it might if there were || tests. That label's count should be
- zero, and it normally should be removed. */
-
- if (then_bb)
- {
- merge_blocks (combo_bb, then_bb);
- num_true_changes++;
- }
-
- /* The ELSE block, if it existed, had a label. That label count
- will almost always be zero, but odd things can happen when labels
- get their addresses taken. */
- if (else_bb)
- {
- merge_blocks (combo_bb, else_bb);
- num_true_changes++;
- }
-
- /* If there was no join block reported, that means it was not adjacent
- to the others, and so we cannot merge them. */
-
- if (! join_bb)
- {
- rtx last = BB_END (combo_bb);
-
- /* The outgoing edge for the current COMBO block should already
- be correct. Verify this. */
- if (EDGE_COUNT (combo_bb->succs) == 0)
- gcc_assert (find_reg_note (last, REG_NORETURN, NULL)
- || (NONJUMP_INSN_P (last)
- && GET_CODE (PATTERN (last)) == TRAP_IF
- && (TRAP_CONDITION (PATTERN (last))
- == const_true_rtx)));
-
- else
- /* There should still be something at the end of the THEN or ELSE
- blocks taking us to our final destination. */
- gcc_assert (JUMP_P (last)
- || (EDGE_SUCC (combo_bb, 0)->dest == EXIT_BLOCK_PTR
- && CALL_P (last)
- && SIBLING_CALL_P (last))
- || ((EDGE_SUCC (combo_bb, 0)->flags & EDGE_EH)
- && can_throw_internal (last)));
- }
-
- /* The JOIN block may have had quite a number of other predecessors too.
- Since we've already merged the TEST, THEN and ELSE blocks, we should
- have only one remaining edge from our if-then-else diamond. If there
- is more than one remaining edge, it must come from elsewhere. There
- may be zero incoming edges if the THEN block didn't actually join
- back up (as with a call to a non-return function). */
- else if (EDGE_COUNT (join_bb->preds) < 2
- && join_bb != EXIT_BLOCK_PTR)
- {
- /* We can merge the JOIN cleanly and update the dataflow try
- again on this pass.*/
- merge_blocks (combo_bb, join_bb);
- num_true_changes++;
- }
- else
- {
- /* We cannot merge the JOIN. */
-
- /* The outgoing edge for the current COMBO block should already
- be correct. Verify this. */
- gcc_assert (single_succ_p (combo_bb)
- && single_succ (combo_bb) == join_bb);
-
- /* Remove the jump and cruft from the end of the COMBO block. */
- if (join_bb != EXIT_BLOCK_PTR)
- tidy_fallthru_edge (single_succ_edge (combo_bb));
- }
-
- num_updated_if_blocks++;
-}
-
-/* Find a block ending in a simple IF condition and try to transform it
- in some way. When converting a multi-block condition, put the new code
- in the first such block and delete the rest. Return a pointer to this
- first block if some transformation was done. Return NULL otherwise. */
-
-static basic_block
-find_if_header (basic_block test_bb, int pass)
-{
- ce_if_block_t ce_info;
- edge then_edge;
- edge else_edge;
-
- /* The kind of block we're looking for has exactly two successors. */
- if (EDGE_COUNT (test_bb->succs) != 2)
- return NULL;
-
- then_edge = EDGE_SUCC (test_bb, 0);
- else_edge = EDGE_SUCC (test_bb, 1);
-
- if (df_get_bb_dirty (then_edge->dest))
- return NULL;
- if (df_get_bb_dirty (else_edge->dest))
- return NULL;
-
- /* Neither edge should be abnormal. */
- if ((then_edge->flags & EDGE_COMPLEX)
- || (else_edge->flags & EDGE_COMPLEX))
- return NULL;
-
- /* Nor exit the loop. */
- if ((then_edge->flags & EDGE_LOOP_EXIT)
- || (else_edge->flags & EDGE_LOOP_EXIT))
- return NULL;
-
- /* The THEN edge is canonically the one that falls through. */
- if (then_edge->flags & EDGE_FALLTHRU)
- ;
- else if (else_edge->flags & EDGE_FALLTHRU)
- {
- edge e = else_edge;
- else_edge = then_edge;
- then_edge = e;
- }
- else
- /* Otherwise this must be a multiway branch of some sort. */
- return NULL;
-
- memset (&ce_info, '\0', sizeof (ce_info));
- ce_info.test_bb = test_bb;
- ce_info.then_bb = then_edge->dest;
- ce_info.else_bb = else_edge->dest;
- ce_info.pass = pass;
-
-#ifdef IFCVT_INIT_EXTRA_FIELDS
- IFCVT_INIT_EXTRA_FIELDS (&ce_info);
-#endif
-
- if (! reload_completed
- && noce_find_if_block (test_bb, then_edge, else_edge, pass))
- goto success;
-
- if (HAVE_conditional_execution && reload_completed
- && cond_exec_find_if_block (&ce_info))
- goto success;
-
- if (HAVE_trap && HAVE_conditional_trap
- && find_cond_trap (test_bb, then_edge, else_edge))
- goto success;
-
- if (dom_info_state (CDI_POST_DOMINATORS) >= DOM_NO_FAST_QUERY
- && (! HAVE_conditional_execution || reload_completed))
- {
- if (find_if_case_1 (test_bb, then_edge, else_edge))
- goto success;
- if (find_if_case_2 (test_bb, then_edge, else_edge))
- goto success;
- }
-
- return NULL;
-
- success:
- if (dump_file)
- fprintf (dump_file, "Conversion succeeded on pass %d.\n", pass);
- /* Set this so we continue looking. */
- cond_exec_changed_p = TRUE;
- return ce_info.test_bb;
-}
-
-/* Return true if a block has two edges, one of which falls through to the next
- block, and the other jumps to a specific block, so that we can tell if the
- block is part of an && test or an || test. Returns either -1 or the number
- of non-note, non-jump, non-USE/CLOBBER insns in the block. */
-
-static int
-block_jumps_and_fallthru_p (basic_block cur_bb, basic_block target_bb)
-{
- edge cur_edge;
- int fallthru_p = FALSE;
- int jump_p = FALSE;
- rtx insn;
- rtx end;
- int n_insns = 0;
- edge_iterator ei;
-
- if (!cur_bb || !target_bb)
- return -1;
-
- /* If no edges, obviously it doesn't jump or fallthru. */
- if (EDGE_COUNT (cur_bb->succs) == 0)
- return FALSE;
-
- FOR_EACH_EDGE (cur_edge, ei, cur_bb->succs)
- {
- if (cur_edge->flags & EDGE_COMPLEX)
- /* Anything complex isn't what we want. */
- return -1;
-
- else if (cur_edge->flags & EDGE_FALLTHRU)
- fallthru_p = TRUE;
-
- else if (cur_edge->dest == target_bb)
- jump_p = TRUE;
-
- else
- return -1;
- }
-
- if ((jump_p & fallthru_p) == 0)
- return -1;
-
- /* Don't allow calls in the block, since this is used to group && and ||
- together for conditional execution support. ??? we should support
- conditional execution support across calls for IA-64 some day, but
- for now it makes the code simpler. */
- end = BB_END (cur_bb);
- insn = BB_HEAD (cur_bb);
-
- while (insn != NULL_RTX)
- {
- if (CALL_P (insn))
- return -1;
-
- if (INSN_P (insn)
- && !JUMP_P (insn)
- && GET_CODE (PATTERN (insn)) != USE
- && GET_CODE (PATTERN (insn)) != CLOBBER)
- n_insns++;
-
- if (insn == end)
- break;
-
- insn = NEXT_INSN (insn);
- }
-
- return n_insns;
-}
-
-/* Determine if a given basic block heads a simple IF-THEN or IF-THEN-ELSE
- block. If so, we'll try to convert the insns to not require the branch.
- Return TRUE if we were successful at converting the block. */
-
-static int
-cond_exec_find_if_block (struct ce_if_block * ce_info)
-{
- basic_block test_bb = ce_info->test_bb;
- basic_block then_bb = ce_info->then_bb;
- basic_block else_bb = ce_info->else_bb;
- basic_block join_bb = NULL_BLOCK;
- edge cur_edge;
- basic_block next;
- edge_iterator ei;
-
- ce_info->last_test_bb = test_bb;
-
- /* We only ever should get here after reload,
- and only if we have conditional execution. */
- gcc_assert (HAVE_conditional_execution && reload_completed);
-
- /* Discover if any fall through predecessors of the current test basic block
- were && tests (which jump to the else block) or || tests (which jump to
- the then block). */
- if (single_pred_p (test_bb)
- && single_pred_edge (test_bb)->flags == EDGE_FALLTHRU)
- {
- basic_block bb = single_pred (test_bb);
- basic_block target_bb;
- int max_insns = MAX_CONDITIONAL_EXECUTE;
- int n_insns;
-
- /* Determine if the preceding block is an && or || block. */
- if ((n_insns = block_jumps_and_fallthru_p (bb, else_bb)) >= 0)
- {
- ce_info->and_and_p = TRUE;
- target_bb = else_bb;
- }
- else if ((n_insns = block_jumps_and_fallthru_p (bb, then_bb)) >= 0)
- {
- ce_info->and_and_p = FALSE;
- target_bb = then_bb;
- }
- else
- target_bb = NULL_BLOCK;
-
- if (target_bb && n_insns <= max_insns)
- {
- int total_insns = 0;
- int blocks = 0;
-
- ce_info->last_test_bb = test_bb;
-
- /* Found at least one && or || block, look for more. */
- do
- {
- ce_info->test_bb = test_bb = bb;
- total_insns += n_insns;
- blocks++;
-
- if (!single_pred_p (bb))
- break;
-
- bb = single_pred (bb);
- n_insns = block_jumps_and_fallthru_p (bb, target_bb);
- }
- while (n_insns >= 0 && (total_insns + n_insns) <= max_insns);
-
- ce_info->num_multiple_test_blocks = blocks;
- ce_info->num_multiple_test_insns = total_insns;
-
- if (ce_info->and_and_p)
- ce_info->num_and_and_blocks = blocks;
- else
- ce_info->num_or_or_blocks = blocks;
- }
- }
-
- /* The THEN block of an IF-THEN combo must have exactly one predecessor,
- other than any || blocks which jump to the THEN block. */
- if ((EDGE_COUNT (then_bb->preds) - ce_info->num_or_or_blocks) != 1)
- return FALSE;
-
- /* The edges of the THEN and ELSE blocks cannot have complex edges. */
- FOR_EACH_EDGE (cur_edge, ei, then_bb->preds)
- {
- if (cur_edge->flags & EDGE_COMPLEX)
- return FALSE;
- }
-
- FOR_EACH_EDGE (cur_edge, ei, else_bb->preds)
- {
- if (cur_edge->flags & EDGE_COMPLEX)
- return FALSE;
- }
-
- /* The THEN block of an IF-THEN combo must have zero or one successors. */
- if (EDGE_COUNT (then_bb->succs) > 0
- && (!single_succ_p (then_bb)
- || (single_succ_edge (then_bb)->flags & EDGE_COMPLEX)
- || (epilogue_completed && tablejump_p (BB_END (then_bb), NULL, NULL))))
- return FALSE;
-
- /* If the THEN block has no successors, conditional execution can still
- make a conditional call. Don't do this unless the ELSE block has
- only one incoming edge -- the CFG manipulation is too ugly otherwise.
- Check for the last insn of the THEN block being an indirect jump, which
- is listed as not having any successors, but confuses the rest of the CE
- code processing. ??? we should fix this in the future. */
- if (EDGE_COUNT (then_bb->succs) == 0)
- {
- if (single_pred_p (else_bb))
- {
- rtx last_insn = BB_END (then_bb);
-
- while (last_insn
- && NOTE_P (last_insn)
- && last_insn != BB_HEAD (then_bb))
- last_insn = PREV_INSN (last_insn);
-
- if (last_insn
- && JUMP_P (last_insn)
- && ! simplejump_p (last_insn))
- return FALSE;
-
- join_bb = else_bb;
- else_bb = NULL_BLOCK;
- }
- else
- return FALSE;
- }
-
- /* If the THEN block's successor is the other edge out of the TEST block,
- then we have an IF-THEN combo without an ELSE. */
- else if (single_succ (then_bb) == else_bb)
- {
- join_bb = else_bb;
- else_bb = NULL_BLOCK;
- }
-
- /* If the THEN and ELSE block meet in a subsequent block, and the ELSE
- has exactly one predecessor and one successor, and the outgoing edge
- is not complex, then we have an IF-THEN-ELSE combo. */
- else if (single_succ_p (else_bb)
- && single_succ (then_bb) == single_succ (else_bb)
- && single_pred_p (else_bb)
- && ! (single_succ_edge (else_bb)->flags & EDGE_COMPLEX)
- && ! (epilogue_completed && tablejump_p (BB_END (else_bb), NULL, NULL)))
- join_bb = single_succ (else_bb);
-
- /* Otherwise it is not an IF-THEN or IF-THEN-ELSE combination. */
- else
- return FALSE;
-
- num_possible_if_blocks++;
-
- if (dump_file)
- {
- fprintf (dump_file,
- "\nIF-THEN%s block found, pass %d, start block %d "
- "[insn %d], then %d [%d]",
- (else_bb) ? "-ELSE" : "",
- ce_info->pass,
- test_bb->index,
- BB_HEAD (test_bb) ? (int)INSN_UID (BB_HEAD (test_bb)) : -1,
- then_bb->index,
- BB_HEAD (then_bb) ? (int)INSN_UID (BB_HEAD (then_bb)) : -1);
-
- if (else_bb)
- fprintf (dump_file, ", else %d [%d]",
- else_bb->index,
- BB_HEAD (else_bb) ? (int)INSN_UID (BB_HEAD (else_bb)) : -1);
-
- fprintf (dump_file, ", join %d [%d]",
- join_bb->index,
- BB_HEAD (join_bb) ? (int)INSN_UID (BB_HEAD (join_bb)) : -1);
-
- if (ce_info->num_multiple_test_blocks > 0)
- fprintf (dump_file, ", %d %s block%s last test %d [%d]",
- ce_info->num_multiple_test_blocks,
- (ce_info->and_and_p) ? "&&" : "||",
- (ce_info->num_multiple_test_blocks == 1) ? "" : "s",
- ce_info->last_test_bb->index,
- ((BB_HEAD (ce_info->last_test_bb))
- ? (int)INSN_UID (BB_HEAD (ce_info->last_test_bb))
- : -1));
-
- fputc ('\n', dump_file);
- }
-
- /* Make sure IF, THEN, and ELSE, blocks are adjacent. Actually, we get the
- first condition for free, since we've already asserted that there's a
- fallthru edge from IF to THEN. Likewise for the && and || blocks, since
- we checked the FALLTHRU flag, those are already adjacent to the last IF
- block. */
- /* ??? As an enhancement, move the ELSE block. Have to deal with
- BLOCK notes, if by no other means than backing out the merge if they
- exist. Sticky enough I don't want to think about it now. */
- next = then_bb;
- if (else_bb && (next = next->next_bb) != else_bb)
- return FALSE;
- if ((next = next->next_bb) != join_bb && join_bb != EXIT_BLOCK_PTR)
- {
- if (else_bb)
- join_bb = NULL;
- else
- return FALSE;
- }
-
- /* Do the real work. */
-
- ce_info->else_bb = else_bb;
- ce_info->join_bb = join_bb;
-
- /* If we have && and || tests, try to first handle combining the && and ||
- tests into the conditional code, and if that fails, go back and handle
- it without the && and ||, which at present handles the && case if there
- was no ELSE block. */
- if (cond_exec_process_if_block (ce_info, TRUE))
- return TRUE;
-
- if (ce_info->num_multiple_test_blocks)
- {
- cancel_changes (0);
-
- if (cond_exec_process_if_block (ce_info, FALSE))
- return TRUE;
- }
-
- return FALSE;
-}
-
-/* Convert a branch over a trap, or a branch
- to a trap, into a conditional trap. */
-
-static int
-find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
-{
- basic_block then_bb = then_edge->dest;
- basic_block else_bb = else_edge->dest;
- basic_block other_bb, trap_bb;
- rtx trap, jump, cond, cond_earliest, seq;
- enum rtx_code code;
-
- /* Locate the block with the trap instruction. */
- /* ??? While we look for no successors, we really ought to allow
- EH successors. Need to fix merge_if_block for that to work. */
- if ((trap = block_has_only_trap (then_bb)) != NULL)
- trap_bb = then_bb, other_bb = else_bb;
- else if ((trap = block_has_only_trap (else_bb)) != NULL)
- trap_bb = else_bb, other_bb = then_bb;
- else
- return FALSE;
-
- if (dump_file)
- {
- fprintf (dump_file, "\nTRAP-IF block found, start %d, trap %d\n",
- test_bb->index, trap_bb->index);
- }
-
- /* If this is not a standard conditional jump, we can't parse it. */
- jump = BB_END (test_bb);
- cond = noce_get_condition (jump, &cond_earliest, false);
- if (! cond)
- return FALSE;
-
- /* If the conditional jump is more than just a conditional jump, then
- we can not do if-conversion on this block. */
- if (! onlyjump_p (jump))
- return FALSE;
-
- /* We must be comparing objects whose modes imply the size. */
- if (GET_MODE (XEXP (cond, 0)) == BLKmode)
- return FALSE;
-
- /* Reverse the comparison code, if necessary. */
- code = GET_CODE (cond);
- if (then_bb == trap_bb)
- {
- code = reversed_comparison_code (cond, jump);
- if (code == UNKNOWN)
- return FALSE;
- }
-
- /* Attempt to generate the conditional trap. */
- seq = gen_cond_trap (code, copy_rtx (XEXP (cond, 0)),
- copy_rtx (XEXP (cond, 1)),
- TRAP_CODE (PATTERN (trap)));
- if (seq == NULL)
- return FALSE;
-
- /* Emit the new insns before cond_earliest. */
- emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATOR (trap));
-
- /* Delete the trap block if possible. */
- remove_edge (trap_bb == then_bb ? then_edge : else_edge);
- df_set_bb_dirty (test_bb);
- df_set_bb_dirty (then_bb);
- df_set_bb_dirty (else_bb);
-
- if (EDGE_COUNT (trap_bb->preds) == 0)
- {
- delete_basic_block (trap_bb);
- num_true_changes++;
- }
-
- /* Wire together the blocks again. */
- if (current_ir_type () == IR_RTL_CFGLAYOUT)
- single_succ_edge (test_bb)->flags |= EDGE_FALLTHRU;
- else
- {
- rtx lab, newjump;
-
- lab = JUMP_LABEL (jump);
- newjump = emit_jump_insn_after (gen_jump (lab), jump);
- LABEL_NUSES (lab) += 1;
- JUMP_LABEL (newjump) = lab;
- emit_barrier_after (newjump);
- }
- delete_insn (jump);
-
- if (can_merge_blocks_p (test_bb, other_bb))
- {
- merge_blocks (test_bb, other_bb);
- num_true_changes++;
- }
-
- num_updated_if_blocks++;
- return TRUE;
-}
-
-/* Subroutine of find_cond_trap: if BB contains only a trap insn,
- return it. */
-
-static rtx
-block_has_only_trap (basic_block bb)
-{
- rtx trap;
-
- /* We're not the exit block. */
- if (bb == EXIT_BLOCK_PTR)
- return NULL_RTX;
-
- /* The block must have no successors. */
- if (EDGE_COUNT (bb->succs) > 0)
- return NULL_RTX;
-
- /* The only instruction in the THEN block must be the trap. */
- trap = first_active_insn (bb);
- if (! (trap == BB_END (bb)
- && GET_CODE (PATTERN (trap)) == TRAP_IF
- && TRAP_CONDITION (PATTERN (trap)) == const_true_rtx))
- return NULL_RTX;
-
- return trap;
-}
-
-/* Look for IF-THEN-ELSE cases in which one of THEN or ELSE is
- transformable, but not necessarily the other. There need be no
- JOIN block.
-
- Return TRUE if we were successful at converting the block.
-
- Cases we'd like to look at:
-
- (1)
- if (test) goto over; // x not live
- x = a;
- goto label;
- over:
-
- becomes
-
- x = a;
- if (! test) goto label;
-
- (2)
- if (test) goto E; // x not live
- x = big();
- goto L;
- E:
- x = b;
- goto M;
-
- becomes
-
- x = b;
- if (test) goto M;
- x = big();
- goto L;
-
- (3) // This one's really only interesting for targets that can do
- // multiway branching, e.g. IA-64 BBB bundles. For other targets
- // it results in multiple branches on a cache line, which often
- // does not sit well with predictors.
-
- if (test1) goto E; // predicted not taken
- x = a;
- if (test2) goto F;
- ...
- E:
- x = b;
- J:
-
- becomes
-
- x = a;
- if (test1) goto E;
- if (test2) goto F;
-
- Notes:
-
- (A) Don't do (2) if the branch is predicted against the block we're
- eliminating. Do it anyway if we can eliminate a branch; this requires
- that the sole successor of the eliminated block postdominate the other
- side of the if.
-
- (B) With CE, on (3) we can steal from both sides of the if, creating
-
- if (test1) x = a;
- if (!test1) x = b;
- if (test1) goto J;
- if (test2) goto F;
- ...
- J:
-
- Again, this is most useful if J postdominates.
-
- (C) CE substitutes for helpful life information.
-
- (D) These heuristics need a lot of work. */
-
-/* Tests for case 1 above. */
-
-static int
-find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
-{
- basic_block then_bb = then_edge->dest;
- basic_block else_bb = else_edge->dest;
- basic_block new_bb;
- int then_bb_index;
-
- /* If we are partitioning hot/cold basic blocks, we don't want to
- mess up unconditional or indirect jumps that cross between hot
- and cold sections.
-
- Basic block partitioning may result in some jumps that appear to
- be optimizable (or blocks that appear to be mergeable), but which really
- must be left untouched (they are required to make it safely across
- partition boundaries). See the comments at the top of
- bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
-
- if ((BB_END (then_bb)
- && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
- || (BB_END (test_bb)
- && find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
- || (BB_END (else_bb)
- && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
- NULL_RTX)))
- return FALSE;
-
- /* THEN has one successor. */
- if (!single_succ_p (then_bb))
- return FALSE;
-
- /* THEN does not fall through, but is not strange either. */
- if (single_succ_edge (then_bb)->flags & (EDGE_COMPLEX | EDGE_FALLTHRU))
- return FALSE;
-
- /* THEN has one predecessor. */
- if (!single_pred_p (then_bb))
- return FALSE;
-
- /* THEN must do something. */
- if (forwarder_block_p (then_bb))
- return FALSE;
-
- num_possible_if_blocks++;
- if (dump_file)
- fprintf (dump_file,
- "\nIF-CASE-1 found, start %d, then %d\n",
- test_bb->index, then_bb->index);
-
- /* THEN is small. */
- if (! cheap_bb_rtx_cost_p (then_bb, COSTS_N_INSNS (BRANCH_COST)))
- return FALSE;
-
- /* Registers set are dead, or are predicable. */
- if (! dead_or_predicable (test_bb, then_bb, else_bb,
- single_succ (then_bb), 1))
- return FALSE;
-
- /* Conversion went ok, including moving the insns and fixing up the
- jump. Adjust the CFG to match. */
-
- /* We can avoid creating a new basic block if then_bb is immediately
- followed by else_bb, i.e. deleting then_bb allows test_bb to fall
- thru to else_bb. */
-
- if (then_bb->next_bb == else_bb
- && then_bb->prev_bb == test_bb
- && else_bb != EXIT_BLOCK_PTR)
- {
- redirect_edge_succ (FALLTHRU_EDGE (test_bb), else_bb);
- new_bb = 0;
- }
- else
- new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb),
- else_bb);
-
- df_set_bb_dirty (test_bb);
- df_set_bb_dirty (else_bb);
-
- then_bb_index = then_bb->index;
- delete_basic_block (then_bb);
-
- /* Make rest of code believe that the newly created block is the THEN_BB
- block we removed. */
- if (new_bb)
- {
- df_bb_replace (then_bb_index, new_bb);
- /* Since the fallthru edge was redirected from test_bb to new_bb,
- we need to ensure that new_bb is in the same partition as
- test bb (you can not fall through across section boundaries). */
- BB_COPY_PARTITION (new_bb, test_bb);
- }
-
- num_true_changes++;
- num_updated_if_blocks++;
-
- return TRUE;
-}
-
-/* Test for case 2 above. */
-
-static int
-find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
-{
- basic_block then_bb = then_edge->dest;
- basic_block else_bb = else_edge->dest;
- edge else_succ;
- rtx note;
-
- /* If we are partitioning hot/cold basic blocks, we don't want to
- mess up unconditional or indirect jumps that cross between hot
- and cold sections.
-
- Basic block partitioning may result in some jumps that appear to
- be optimizable (or blocks that appear to be mergeable), but which really
- must be left untouched (they are required to make it safely across
- partition boundaries). See the comments at the top of
- bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
-
- if ((BB_END (then_bb)
- && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
- || (BB_END (test_bb)
- && find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
- || (BB_END (else_bb)
- && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
- NULL_RTX)))
- return FALSE;
-
- /* ELSE has one successor. */
- if (!single_succ_p (else_bb))
- return FALSE;
- else
- else_succ = single_succ_edge (else_bb);
-
- /* ELSE outgoing edge is not complex. */
- if (else_succ->flags & EDGE_COMPLEX)
- return FALSE;
-
- /* ELSE has one predecessor. */
- if (!single_pred_p (else_bb))
- return FALSE;
-
- /* THEN is not EXIT. */
- if (then_bb->index < NUM_FIXED_BLOCKS)
- return FALSE;
-
- /* ELSE is predicted or SUCC(ELSE) postdominates THEN. */
- note = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
- if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2)
- ;
- else if (else_succ->dest->index < NUM_FIXED_BLOCKS
- || dominated_by_p (CDI_POST_DOMINATORS, then_bb,
- else_succ->dest))
- ;
- else
- return FALSE;
-
- num_possible_if_blocks++;
- if (dump_file)
- fprintf (dump_file,
- "\nIF-CASE-2 found, start %d, else %d\n",
- test_bb->index, else_bb->index);
-
- /* ELSE is small. */
- if (! cheap_bb_rtx_cost_p (else_bb, COSTS_N_INSNS (BRANCH_COST)))
- return FALSE;
-
- /* Registers set are dead, or are predicable. */
- if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ->dest, 0))
- return FALSE;
-
- /* Conversion went ok, including moving the insns and fixing up the
- jump. Adjust the CFG to match. */
-
- df_set_bb_dirty (test_bb);
- df_set_bb_dirty (then_bb);
- delete_basic_block (else_bb);
-
- num_true_changes++;
- num_updated_if_blocks++;
-
- /* ??? We may now fallthru from one of THEN's successors into a join
- block. Rerun cleanup_cfg? Examine things manually? Wait? */
-
- return TRUE;
-}
-
-/* A subroutine of dead_or_predicable called through for_each_rtx.
- Return 1 if a memory is found. */
-
-static int
-find_memory (rtx *px, void *data ATTRIBUTE_UNUSED)
-{
- return MEM_P (*px);
-}
-
-/* Used by the code above to perform the actual rtl transformations.
- Return TRUE if successful.
-
- TEST_BB is the block containing the conditional branch. MERGE_BB
- is the block containing the code to manipulate. NEW_DEST is the
- label TEST_BB should be branching to after the conversion.
- REVERSEP is true if the sense of the branch should be reversed. */
-
-static int
-dead_or_predicable (basic_block test_bb, basic_block merge_bb,
- basic_block other_bb, basic_block new_dest, int reversep)
-{
- rtx head, end, jump, earliest = NULL_RTX, old_dest, new_label = NULL_RTX;
-
- jump = BB_END (test_bb);
-
- /* Find the extent of the real code in the merge block. */
- head = BB_HEAD (merge_bb);
- end = BB_END (merge_bb);
-
- /* If merge_bb ends with a tablejump, predicating/moving insn's
- into test_bb and then deleting merge_bb will result in the jumptable
- that follows merge_bb being removed along with merge_bb and then we
- get an unresolved reference to the jumptable. */
- if (tablejump_p (end, NULL, NULL))
- return FALSE;
-
- if (LABEL_P (head))
- head = NEXT_INSN (head);
- if (NOTE_P (head))
- {
- if (head == end)
- {
- head = end = NULL_RTX;
- goto no_body;
- }
- head = NEXT_INSN (head);
- }
-
- if (JUMP_P (end))
- {
- if (head == end)
- {
- head = end = NULL_RTX;
- goto no_body;
- }
- end = PREV_INSN (end);
- }
-
- /* Disable handling dead code by conditional execution if the machine needs
- to do anything funny with the tests, etc. */
-#ifndef IFCVT_MODIFY_TESTS
- if (HAVE_conditional_execution)
- {
- /* In the conditional execution case, we have things easy. We know
- the condition is reversible. We don't have to check life info
- because we're going to conditionally execute the code anyway.
- All that's left is making sure the insns involved can actually
- be predicated. */
-
- rtx cond, prob_val;
-
- cond = cond_exec_get_condition (jump);
- if (! cond)
- return FALSE;
-
- prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
- if (prob_val)
- prob_val = XEXP (prob_val, 0);
-
- if (reversep)
- {
- enum rtx_code rev = reversed_comparison_code (cond, jump);
- if (rev == UNKNOWN)
- return FALSE;
- cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
- XEXP (cond, 1));
- if (prob_val)
- prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
- }
-
- if (! cond_exec_process_insns ((ce_if_block_t *)0, head, end, cond,
- prob_val, 0))
- goto cancel;
-
- earliest = jump;
- }
- else
-#endif
- {
- /* In the non-conditional execution case, we have to verify that there
- are no trapping operations, no calls, no references to memory, and
- that any registers modified are dead at the branch site. */
-
- rtx insn, cond, prev;
- bitmap merge_set, test_live, test_set;
- unsigned i, fail = 0;
- bitmap_iterator bi;
-
- /* Check for no calls or trapping operations. */
- for (insn = head; ; insn = NEXT_INSN (insn))
- {
- if (CALL_P (insn))
- return FALSE;
- if (INSN_P (insn))
- {
- if (may_trap_p (PATTERN (insn)))
- return FALSE;
-
- /* ??? Even non-trapping memories such as stack frame
- references must be avoided. For stores, we collect
- no lifetime info; for reads, we'd have to assert
- true_dependence false against every store in the
- TEST range. */
- if (for_each_rtx (&PATTERN (insn), find_memory, NULL))
- return FALSE;
- }
- if (insn == end)
- break;
- }
-
- if (! any_condjump_p (jump))
- return FALSE;
-
- /* Find the extent of the conditional. */
- cond = noce_get_condition (jump, &earliest, false);
- if (! cond)
- return FALSE;
-
- /* Collect:
- MERGE_SET = set of registers set in MERGE_BB
- TEST_LIVE = set of registers live at EARLIEST
- TEST_SET = set of registers set between EARLIEST and the
- end of the block. */
-
- merge_set = BITMAP_ALLOC (&reg_obstack);
- test_live = BITMAP_ALLOC (&reg_obstack);
- test_set = BITMAP_ALLOC (&reg_obstack);
-
- /* ??? bb->local_set is only valid during calculate_global_regs_live,
- so we must recompute usage for MERGE_BB. Not so bad, I suppose,
- since we've already asserted that MERGE_BB is small. */
- /* If we allocated new pseudos (e.g. in the conditional move
- expander called from noce_emit_cmove), we must resize the
- array first. */
- if (max_regno < max_reg_num ())
- max_regno = max_reg_num ();
-
- FOR_BB_INSNS (merge_bb, insn)
- {
- if (INSN_P (insn))
- {
- unsigned int uid = INSN_UID (insn);
- struct df_ref **def_rec;
- for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
- {
- struct df_ref *def = *def_rec;
- bitmap_set_bit (merge_set, DF_REF_REGNO (def));
- }
- }
- }
-
- /* For small register class machines, don't lengthen lifetimes of
- hard registers before reload. */
- if (SMALL_REGISTER_CLASSES && ! reload_completed)
- {
- EXECUTE_IF_SET_IN_BITMAP (merge_set, 0, i, bi)
- {
- if (i < FIRST_PSEUDO_REGISTER
- && ! fixed_regs[i]
- && ! global_regs[i])
- fail = 1;
- }
- }
-
- /* For TEST, we're interested in a range of insns, not a whole block.
- Moreover, we're interested in the insns live from OTHER_BB. */
-
- /* The loop below takes the set of live registers
- after JUMP, and calculates the live set before EARLIEST. */
- bitmap_copy (test_live, df_get_live_in (other_bb));
- df_simulate_artificial_refs_at_end (test_bb, test_live);
- for (insn = jump; ; insn = prev)
- {
- if (INSN_P (insn))
- {
- df_simulate_find_defs (insn, test_set);
- df_simulate_one_insn_backwards (test_bb, insn, test_live);
- }
- prev = PREV_INSN (insn);
- if (insn == earliest)
- break;
- }
-
- /* We can perform the transformation if
- MERGE_SET & (TEST_SET | TEST_LIVE)
- and
- TEST_SET & DF_LIVE_IN (merge_bb)
- are empty. */
-
- if (bitmap_intersect_p (test_set, merge_set)
- || bitmap_intersect_p (test_live, merge_set)
- || bitmap_intersect_p (test_set, df_get_live_in (merge_bb)))
- fail = 1;
-
- BITMAP_FREE (merge_set);
- BITMAP_FREE (test_live);
- BITMAP_FREE (test_set);
-
- if (fail)
- return FALSE;
- }
-
- no_body:
- /* We don't want to use normal invert_jump or redirect_jump because
- we don't want to delete_insn called. Also, we want to do our own
- change group management. */
-
- old_dest = JUMP_LABEL (jump);
- if (other_bb != new_dest)
- {
- new_label = block_label (new_dest);
- if (reversep
- ? ! invert_jump_1 (jump, new_label)
- : ! redirect_jump_1 (jump, new_label))
- goto cancel;
- }
-
- if (! apply_change_group ())
- return FALSE;
-
- if (other_bb != new_dest)
- {
- redirect_jump_2 (jump, old_dest, new_label, 0, reversep);
-
- redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
- if (reversep)
- {
- gcov_type count, probability;
- count = BRANCH_EDGE (test_bb)->count;
- BRANCH_EDGE (test_bb)->count = FALLTHRU_EDGE (test_bb)->count;
- FALLTHRU_EDGE (test_bb)->count = count;
- probability = BRANCH_EDGE (test_bb)->probability;
- BRANCH_EDGE (test_bb)->probability
- = FALLTHRU_EDGE (test_bb)->probability;
- FALLTHRU_EDGE (test_bb)->probability = probability;
- update_br_prob_note (test_bb);
- }
- }
-
- /* Move the insns out of MERGE_BB to before the branch. */
- if (head != NULL)
- {
- rtx insn;
-
- if (end == BB_END (merge_bb))
- BB_END (merge_bb) = PREV_INSN (head);
-
- /* PR 21767: When moving insns above a conditional branch, REG_EQUAL
- notes might become invalid. */
- insn = head;
- do
- {
- rtx note, set;
-
- if (! INSN_P (insn))
- continue;
- note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- if (! note)
- continue;
- set = single_set (insn);
- if (!set || !function_invariant_p (SET_SRC (set)))
- remove_note (insn, note);
- } while (insn != end && (insn = NEXT_INSN (insn)));
-
- reorder_insns (head, end, PREV_INSN (earliest));
- }
-
- /* Remove the jump and edge if we can. */
- if (other_bb == new_dest)
- {
- delete_insn (jump);
- remove_edge (BRANCH_EDGE (test_bb));
- /* ??? Can't merge blocks here, as then_bb is still in use.
- At minimum, the merge will get done just before bb-reorder. */
- }
-
- return TRUE;
-
- cancel:
- cancel_changes (0);
- return FALSE;
-}
-
-/* Main entry point for all if-conversion. */
-
-static void
-if_convert (void)
-{
- basic_block bb;
- int pass;
-
- if (optimize == 1)
- {
- df_live_add_problem ();
- df_live_set_all_dirty ();
- }
-
- num_possible_if_blocks = 0;
- num_updated_if_blocks = 0;
- num_true_changes = 0;
-
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
- mark_loop_exit_edges ();
- loop_optimizer_finalize ();
- free_dominance_info (CDI_DOMINATORS);
-
- /* Compute postdominators. */
- calculate_dominance_info (CDI_POST_DOMINATORS);
-
- df_set_flags (DF_LR_RUN_DCE);
-
- /* Go through each of the basic blocks looking for things to convert. If we
- have conditional execution, we make multiple passes to allow us to handle
- IF-THEN{-ELSE} blocks within other IF-THEN{-ELSE} blocks. */
- pass = 0;
- do
- {
- df_analyze ();
- /* Only need to do dce on the first pass. */
- df_clear_flags (DF_LR_RUN_DCE);
- cond_exec_changed_p = FALSE;
- pass++;
-
-#ifdef IFCVT_MULTIPLE_DUMPS
- if (dump_file && pass > 1)
- fprintf (dump_file, "\n\n========== Pass %d ==========\n", pass);
-#endif
-
- FOR_EACH_BB (bb)
- {
- basic_block new_bb;
- while (!df_get_bb_dirty (bb)
- && (new_bb = find_if_header (bb, pass)) != NULL)
- bb = new_bb;
- }
-
-#ifdef IFCVT_MULTIPLE_DUMPS
- if (dump_file && cond_exec_changed_p)
- print_rtl_with_bb (dump_file, get_insns ());
-#endif
- }
- while (cond_exec_changed_p);
-
-#ifdef IFCVT_MULTIPLE_DUMPS
- if (dump_file)
- fprintf (dump_file, "\n\n========== no more changes\n");
-#endif
-
- free_dominance_info (CDI_POST_DOMINATORS);
-
- if (dump_file)
- fflush (dump_file);
-
- clear_aux_for_blocks ();
-
- /* If we allocated new pseudos, we must resize the array for sched1. */
- if (max_regno < max_reg_num ())
- max_regno = max_reg_num ();
-
- /* Write the final stats. */
- if (dump_file && num_possible_if_blocks > 0)
- {
- fprintf (dump_file,
- "\n%d possible IF blocks searched.\n",
- num_possible_if_blocks);
- fprintf (dump_file,
- "%d IF blocks converted.\n",
- num_updated_if_blocks);
- fprintf (dump_file,
- "%d true changes made.\n\n\n",
- num_true_changes);
- }
-
- if (optimize == 1)
- df_remove_problem (df_live);
-
-#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
-}
-
-static bool
-gate_handle_if_conversion (void)
-{
- return (optimize > 0);
-}
-
-/* If-conversion and CFG cleanup. */
-static unsigned int
-rest_of_handle_if_conversion (void)
-{
- if (flag_if_conversion)
- {
- if (dump_file)
- dump_flow_info (dump_file, dump_flags);
- cleanup_cfg (CLEANUP_EXPENSIVE);
- if_convert ();
- }
-
- cleanup_cfg (0);
- return 0;
-}
-
-struct tree_opt_pass pass_rtl_ifcvt =
-{
- "ce1", /* name */
- gate_handle_if_conversion, /* gate */
- rest_of_handle_if_conversion, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_IFCVT, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish | TODO_verify_rtl_sharing |
- TODO_dump_func, /* todo_flags_finish */
- 'C' /* letter */
-};
-
-static bool
-gate_handle_if_after_combine (void)
-{
- return (optimize > 0 && flag_if_conversion);
-}
-
-
-/* Rerun if-conversion, as combine may have simplified things enough
- to now meet sequence length restrictions. */
-static unsigned int
-rest_of_handle_if_after_combine (void)
-{
- if_convert ();
- return 0;
-}
-
-struct tree_opt_pass pass_if_after_combine =
-{
- "ce2", /* name */
- gate_handle_if_after_combine, /* gate */
- rest_of_handle_if_after_combine, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_IFCVT, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish | TODO_verify_rtl_sharing |
- TODO_dump_func |
- TODO_ggc_collect, /* todo_flags_finish */
- 'C' /* letter */
-};
-
-
-static bool
-gate_handle_if_after_reload (void)
-{
- return (optimize > 0 && flag_if_conversion2);
-}
-
-static unsigned int
-rest_of_handle_if_after_reload (void)
-{
- if_convert ();
- return 0;
-}
-
-
-struct tree_opt_pass pass_if_after_reload =
-{
- "ce3", /* name */
- gate_handle_if_after_reload, /* gate */
- rest_of_handle_if_after_reload, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_IFCVT2, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish | TODO_verify_rtl_sharing |
- TODO_dump_func |
- TODO_ggc_collect, /* todo_flags_finish */
- 'E' /* letter */
-};