#include "rtl.h"
#include "regs.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "vec.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
#include "function.h"
#include "flags.h"
#include "insn-config.h"
#include "recog.h"
#include "except.h"
-#include "hard-reg-set.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "cfgcleanup.h"
#include "basic-block.h"
#include "expr.h"
#include "output.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "diagnostic-core.h"
#include "tm_p.h"
#include "target.h"
#include "tree-pass.h"
#include "df.h"
-#include "vec.h"
#include "dbgcnt.h"
+#include "shrink-wrap.h"
+#include "ifcvt.h"
#ifndef HAVE_conditional_move
#define HAVE_conditional_move 0
+ 1)
#endif
+#ifndef HAVE_cbranchcc4
+#define HAVE_cbranchcc4 0
+#endif
+
#define IFCVT_MULTIPLE_DUMPS 1
#define NULL_BLOCK ((basic_block) NULL)
static basic_block block_fallthru (basic_block);
static int cond_exec_process_insns (ce_if_block *, rtx_insn *, rtx, rtx, int,
int);
-static rtx cond_exec_get_condition (rtx);
+static rtx cond_exec_get_condition (rtx_insn *);
static rtx noce_get_condition (rtx_insn *, rtx_insn **, bool);
static int noce_operand_ok (const_rtx);
static void merge_if_block (ce_if_block *);
if (CALL_P (insn) && prob_val >= 0)
validate_change (insn, ®_NOTES (insn),
- gen_rtx_INT_LIST ((enum machine_mode) REG_BR_PROB,
+ gen_rtx_INT_LIST ((machine_mode) REG_BR_PROB,
prob_val, REG_NOTES (insn)), 1);
insn_done:
/* Return the condition for a jump. Do not do any special processing. */
static rtx
-cond_exec_get_condition (rtx jump)
+cond_exec_get_condition (rtx_insn *jump)
{
rtx test_if, cond;
/* 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))
+ && LABEL_REF_LABEL (XEXP (test_if, 2)) == JUMP_LABEL (jump))
{
enum rtx_code rev = reversed_comparison_code (cond, jump);
if (rev == UNKNOWN)
rtx set = pc_set (if_info->jump);
cond = XEXP (SET_SRC (set), 0);
if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
- && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump))
+ && LABEL_REF_LABEL (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (if_info->jump))
reversep = !reversep;
if (if_info->then_else_reversed)
reversep = !reversep;
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),
+ rtx src = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
XEXP (cond, 1));
- tmp = gen_rtx_SET (VOIDmode, x, tmp);
+ rtx set = gen_rtx_SET (VOIDmode, x, src);
start_sequence ();
- tmp = emit_insn (tmp);
+ rtx_insn *insn = emit_insn (set);
- if (recog_memoized (tmp) >= 0)
+ if (recog_memoized (insn) >= 0)
{
- tmp = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
- emit_insn (tmp);
+ emit_insn (seq);
if_info->cond_earliest = if_info->jump;
static void
noce_emit_move_insn (rtx x, rtx y)
{
- enum machine_mode outmode;
+ machine_mode outmode;
rtx outer, inner;
int bitpos;
if (GET_CODE (x) != STRICT_LOW_PART)
{
- rtx seq, insn, target;
+ rtx_insn *seq, *insn;
+ rtx target;
optab ot;
start_sequence ();
int reversep;
HOST_WIDE_INT itrue, ifalse, diff, tmp;
int normalize, can_reverse;
- enum machine_mode mode;
+ machine_mode mode;
if (CONST_INT_P (if_info->a)
&& CONST_INT_P (if_info->b))
if (target)
{
+ int old_cost, new_cost, insn_cost;
+ int speed_p;
+
if (target != if_info->x)
noce_emit_move_insn (if_info->x, target);
if (!seq)
return FALSE;
+ speed_p = optimize_bb_for_speed_p (BLOCK_FOR_INSN (if_info->insn_a));
+ insn_cost = insn_rtx_cost (PATTERN (if_info->insn_a), speed_p);
+ old_cost = COSTS_N_INSNS (if_info->branch_cost) + insn_cost;
+ new_cost = seq_cost (seq, speed_p);
+
+ if (new_cost > old_cost)
+ return FALSE;
+
emit_insn_before_setloc (seq, if_info->jump,
INSN_LOCATION (if_info->insn_a));
return TRUE;
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);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), cmp_a, cmp_b);
+ rtx if_then_else = gen_rtx_IF_THEN_ELSE (GET_MODE (x),
+ cond, vtrue, vfalse);
+ rtx set = gen_rtx_SET (VOIDmode, x, if_then_else);
start_sequence ();
- tmp = emit_insn (tmp);
+ rtx_insn *insn = emit_insn (set);
- if (recog_memoized (tmp) >= 0)
+ if (recog_memoized (insn) >= 0)
{
- tmp = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
- emit_insn (tmp);
+ emit_insn (seq);
return x;
}
end_sequence ();
}
- /* Don't even try if the comparison operands are weird. */
+ /* Don't even try if the comparison operands are weird
+ except that the target supports cbranchcc4. */
if (! general_operand (cmp_a, GET_MODE (cmp_a))
|| ! general_operand (cmp_b, GET_MODE (cmp_b)))
- return NULL_RTX;
+ {
+ if (!(HAVE_cbranchcc4)
+ || GET_MODE_CLASS (GET_MODE (cmp_a)) != MODE_CC
+ || cmp_b != const0_rtx)
+ return NULL_RTX;
+ }
#if HAVE_conditional_move
unsignedp = (code == LTU || code == GEU
rtx b = if_info->b;
rtx x = if_info->x;
rtx orig_a, orig_b;
- rtx insn_a, insn_b;
- rtx tmp, target;
+ rtx_insn *insn_a, *insn_b;
+ rtx target;
int is_mem = 0;
int insn_cost;
enum rtx_code code;
+ rtx_insn *ifcvt_seq;
/* A conditional move from two memory sources is equivalent to a
conditional on their addresses followed by a load. Don't do this
&& MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b)
&& if_info->branch_cost >= 5)
{
- enum machine_mode address_mode = get_address_mode (a);
+ machine_mode address_mode = get_address_mode (a);
a = XEXP (a, 0);
b = XEXP (b, 0);
if (reversep)
{
+ rtx tmp;
+ rtx_insn *tmp_insn;
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;
+ tmp_insn = insn_a, insn_a = insn_b, insn_b = tmp_insn;
}
}
This is of course not possible in the IS_MEM case. */
if (! general_operand (a, GET_MODE (a)))
{
- rtx set;
+ rtx_insn *insn;
if (is_mem)
{
- tmp = gen_reg_rtx (GET_MODE (a));
- tmp = emit_insn (gen_rtx_SET (VOIDmode, tmp, a));
+ rtx reg = gen_reg_rtx (GET_MODE (a));
+ insn = emit_insn (gen_rtx_SET (VOIDmode, reg, 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);
+ rtx_insn *copy_of_a = as_a <rtx_insn *> (copy_rtx (insn_a));
+ rtx set = single_set (copy_of_a);
SET_DEST (set) = a;
- tmp = emit_insn (PATTERN (tmp));
+ insn = emit_insn (PATTERN (copy_of_a));
}
- if (recog_memoized (tmp) < 0)
+ if (recog_memoized (insn) < 0)
goto end_seq_and_fail;
}
if (! general_operand (b, GET_MODE (b)))
{
- rtx set, last;
+ rtx pat;
+ rtx_insn *last;
+ rtx_insn *new_insn;
if (is_mem)
{
- tmp = gen_reg_rtx (GET_MODE (b));
- tmp = gen_rtx_SET (VOIDmode, tmp, b);
+ rtx reg = gen_reg_rtx (GET_MODE (b));
+ pat = gen_rtx_SET (VOIDmode, reg, 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);
+ rtx_insn *copy_of_insn_b = as_a <rtx_insn *> (copy_rtx (insn_b));
+ rtx set = single_set (copy_of_insn_b);
SET_DEST (set) = b;
- tmp = PATTERN (tmp);
+ pat = PATTERN (copy_of_insn_b);
}
/* If insn to set up A clobbers any registers B depends on, try to
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))
+ new_insn = emit_insn_before (pat, get_insns ());
+ if (modified_in_p (orig_a, new_insn))
goto end_seq_and_fail;
}
else
- tmp = emit_insn (tmp);
+ new_insn = emit_insn (pat);
- if (recog_memoized (tmp) < 0)
+ if (recog_memoized (new_insn) < 0)
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);
+ rtx mem = 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;
+ MEM_VOLATILE_P (mem) = 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,
+ set_mem_alias_set (mem, MEM_ALIAS_SET (if_info->a));
+ set_mem_align (mem,
MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b)));
gcc_assert (MEM_ADDR_SPACE (if_info->a) == MEM_ADDR_SPACE (if_info->b));
- set_mem_addr_space (tmp, MEM_ADDR_SPACE (if_info->a));
+ set_mem_addr_space (mem, MEM_ADDR_SPACE (if_info->a));
- noce_emit_move_insn (if_info->x, tmp);
+ noce_emit_move_insn (if_info->x, mem);
}
else if (target != x)
noce_emit_move_insn (x, target);
- tmp = end_ifcvt_sequence (if_info);
- if (!tmp)
+ ifcvt_seq = end_ifcvt_sequence (if_info);
+ if (!ifcvt_seq)
return FALSE;
- emit_insn_before_setloc (tmp, if_info->jump, INSN_LOCATION (if_info->insn_a));
+ emit_insn_before_setloc (ifcvt_seq, if_info->jump,
+ INSN_LOCATION (if_info->insn_a));
return TRUE;
end_seq_and_fail:
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);
+ && LABEL_REF_LABEL (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (if_info->jump);
if (if_info->then_else_reversed)
reverse = !reverse;
}
cond = canonicalize_condition (if_info->jump, cond, reverse,
- earliest, target, false, true);
+ earliest, target, HAVE_cbranchcc4, true);
if (! cond || ! reg_mentioned_p (target, cond))
return NULL;
REG_EQUAL note or a simple source if necessary. */
if (REG_P (c))
{
- rtx set, insn = prev_nonnote_insn (earliest);
+ rtx set;
+ rtx_insn *insn = prev_nonnote_insn (earliest);
if (insn
&& BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (earliest)
&& (set = single_set (insn))
{
rtx cond, t, m, c;
rtx_insn *seq;
- enum machine_mode mode;
+ machine_mode mode;
enum rtx_code code;
bool t_unconditional;
{
rtx cond, x, a, result;
rtx_insn *seq;
- enum machine_mode mode;
+ machine_mode mode;
enum rtx_code code;
int bitnum;
/* 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));
+ && LABEL_REF_LABEL (XEXP (SET_SRC (set), 2)) == 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
/* Otherwise, fall back on canonicalize_condition to do the dirty
work of manipulating MODE_CC values and COMPARE rtx codes. */
tmp = canonicalize_condition (jump, cond, reverse, earliest,
- NULL_RTX, false, true);
+ NULL_RTX, HAVE_cbranchcc4, true);
/* We don't handle side-effects in the condition, like handling
REG_INC notes and making sure no duplicate conditions are emitted. */
if (NONDEBUG_INSN_P (insn))
df_simulate_find_defs (insn, merge_set);
-#ifdef HAVE_simple_return
/* If shrink-wrapping, disable this optimization when test_bb is
the first basic block and merge_bb exits. The idea is to not
move code setting up a return register as that may clobber a
register used to pass function parameters, which then must be
saved in caller-saved regs. A caller-saved reg requires the
prologue, killing a shrink-wrap opportunity. */
- if ((flag_shrink_wrap && HAVE_simple_return && !epilogue_completed)
+ if ((SHRINK_WRAPPING_ENABLED && !epilogue_completed)
&& ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb == test_bb
&& single_succ_p (new_dest)
&& single_succ (new_dest) == EXIT_BLOCK_PTR_FOR_FN (cfun)
}
BITMAP_FREE (return_regs);
}
-#endif
}
no_body:
old_dest = JUMP_LABEL (jump);
if (other_bb != new_dest)
{
+ if (!any_condjump_p (jump))
+ goto cancel;
+
if (JUMP_P (BB_END (dest_edge->src)))
new_dest_label = JUMP_LABEL (BB_END (dest_edge->src));
else if (new_dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
insn = head;
do
{
- rtx note, set;
+ rtx note;
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))
- || !function_invariant_p (XEXP (note, 0)))
- remove_note (insn, note);
+ remove_note (insn, note);
} while (insn != end && (insn = NEXT_INSN (insn)));
/* PR46315: when moving insns above a conditional branch, the REG_EQUAL