/* If-conversion support.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010,
+ 2011
Free Software Foundation, Inc.
This file is part of GCC.
#include "output.h"
#include "optabs.h"
#include "diagnostic-core.h"
-#include "toplev.h"
#include "tm_p.h"
#include "cfgloop.h"
#include "target.h"
static int find_if_case_1 (basic_block, edge, edge);
static int find_if_case_2 (basic_block, edge, edge);
static int dead_or_predicable (basic_block, basic_block, basic_block,
- basic_block, int);
+ edge, int);
static void noce_emit_move_insn (rtx, rtx);
static rtx block_has_only_trap (basic_block);
\f
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;
+ edge e = find_fallthru_edge (bb->succs);
return (e) ? e->dest : NULL_BLOCK;
}
for (insn = start; ; insn = NEXT_INSN (insn))
{
+ /* dwarf2out can't cope with conditional prologues. */
+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END)
+ return FALSE;
+
if (NOTE_P (insn) || DEBUG_INSN_P (insn))
goto insn_done;
/* Look for matching sequences at the head and tail of the two blocks,
and limit the range of insns to be converted if possible. */
n_matching = flow_find_cross_jump (then_bb, else_bb,
- &then_first_tail, &else_first_tail);
+ &then_first_tail, &else_first_tail,
+ NULL);
if (then_first_tail == BB_HEAD (then_bb))
then_start = then_end = NULL_RTX;
if (else_first_tail == BB_HEAD (else_bb))
}
gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
- store_bit_field (op, size, start, GET_MODE (x), y);
+ store_bit_field (op, size, start, 0, 0, GET_MODE (x), y);
return;
}
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);
+ store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos,
+ 0, 0, outmode, y);
}
/* Return sequence of instructions generated by if conversion. This
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)
{
+ rtx target ATTRIBUTE_UNUSED;
+ int unsignedp ATTRIBUTE_UNUSED;
+
/* 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
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));
+ unsignedp = (code == LTU || code == GEU
+ || code == LEU || code == GTU);
+
+ target = emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode,
+ vtrue, vfalse, GET_MODE (x),
+ unsignedp);
+ if (target)
+ return target;
+
+ /* We might be faced with a situation like:
+
+ x = (reg:M TARGET)
+ vtrue = (subreg:M (reg:N VTRUE) BYTE)
+ vfalse = (subreg:M (reg:N VFALSE) BYTE)
+
+ We can't do a conditional move in mode M, but it's possible that we
+ could do a conditional move in mode N instead and take a subreg of
+ the result.
+
+ If we can't create new pseudos, though, don't bother. */
+ if (reload_completed)
+ return NULL_RTX;
+
+ if (GET_CODE (vtrue) == SUBREG && GET_CODE (vfalse) == SUBREG)
+ {
+ rtx reg_vtrue = SUBREG_REG (vtrue);
+ rtx reg_vfalse = SUBREG_REG (vfalse);
+ unsigned int byte_vtrue = SUBREG_BYTE (vtrue);
+ unsigned int byte_vfalse = SUBREG_BYTE (vfalse);
+ rtx promoted_target;
+
+ if (GET_MODE (reg_vtrue) != GET_MODE (reg_vfalse)
+ || byte_vtrue != byte_vfalse
+ || (SUBREG_PROMOTED_VAR_P (vtrue)
+ != SUBREG_PROMOTED_VAR_P (vfalse))
+ || (SUBREG_PROMOTED_UNSIGNED_P (vtrue)
+ != SUBREG_PROMOTED_UNSIGNED_P (vfalse)))
+ return NULL_RTX;
+
+ promoted_target = gen_reg_rtx (GET_MODE (reg_vtrue));
+
+ target = emit_conditional_move (promoted_target, code, cmp_a, cmp_b,
+ VOIDmode, reg_vtrue, reg_vfalse,
+ GET_MODE (reg_vtrue), unsignedp);
+ /* Nope, couldn't do it in that mode either. */
+ if (!target)
+ return NULL_RTX;
+
+ target = gen_rtx_SUBREG (GET_MODE (vtrue), promoted_target, byte_vtrue);
+ SUBREG_PROMOTED_VAR_P (target) = SUBREG_PROMOTED_VAR_P (vtrue);
+ SUBREG_PROMOTED_UNSIGNED_SET (target, SUBREG_PROMOTED_UNSIGNED_P (vtrue));
+ emit_move_insn (x, target);
+ return x;
+ }
+ else
+ return NULL_RTX;
#else
/* We'll never get here, as noce_process_if_block doesn't call the
functions involved. Ifdef code, however, should be discouraged
&& (if_info->insn_b == NULL_RTX
|| BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb));
if (!(t_unconditional
- || (rtx_cost (t, SET, optimize_bb_for_speed_p (if_info->test_bb))
+ || (set_src_cost (t, optimize_bb_for_speed_p (if_info->test_bb))
< COSTS_N_INSNS (2))))
return FALSE;
basic_block then_bb = then_edge->dest;
basic_block else_bb = else_edge->dest;
basic_block new_bb;
+ rtx else_target = NULL_RTX;
int then_bb_index;
/* If we are partitioning hot/cold basic blocks, we don't want to
predictable_edge_p (then_edge)))))
return FALSE;
+ if (else_bb == EXIT_BLOCK_PTR)
+ {
+ rtx jump = BB_END (else_edge->src);
+ gcc_assert (JUMP_P (jump));
+ else_target = JUMP_LABEL (jump);
+ }
+
/* Registers set are dead, or are predicable. */
if (! dead_or_predicable (test_bb, then_bb, else_bb,
- single_succ (then_bb), 1))
+ single_succ_edge (then_bb), 1))
return FALSE;
/* Conversion went ok, including moving the insns and fixing up the
redirect_edge_succ (FALLTHRU_EDGE (test_bb), else_bb);
new_bb = 0;
}
+ else if (else_bb == EXIT_BLOCK_PTR)
+ new_bb = force_nonfallthru_and_redirect (FALLTHRU_EDGE (test_bb),
+ else_bb, else_target);
else
new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb),
else_bb);
return FALSE;
/* Registers set are dead, or are predicable. */
- if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ->dest, 0))
+ if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ, 0))
return FALSE;
/* Conversion went ok, including moving the insns and fixing up the
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.
+ is the block containing the code to manipulate. DEST_EDGE is an
+ edge representing a jump to the join block; after the conversion,
+ TEST_BB should be branching to its destination.
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)
+ basic_block other_bb, edge dest_edge, int reversep)
{
- rtx head, end, jump, earliest = NULL_RTX, old_dest, new_label = NULL_RTX;
+ basic_block new_dest = dest_edge->dest;
+ rtx head, end, jump, earliest = NULL_RTX, old_dest;
+ bitmap merge_set = NULL;
/* Number of pending changes. */
int n_validated_changes = 0;
+ rtx new_dest_label = NULL_RTX;
jump = BB_END (test_bb);
earliest = jump;
}
#endif
+
/* If we allocated new pseudos (e.g. in the conditional move
expander called from noce_emit_cmove), we must resize the
array first. */
/* Try the NCE path if the CE path did not result in any changes. */
if (n_validated_changes == 0)
{
- rtx cond;
+ rtx cond, insn;
regset live;
bool success;
BITMAP_FREE (live);
if (!success)
return FALSE;
+
+ /* Collect the set of registers set in MERGE_BB. */
+ merge_set = BITMAP_ALLOC (®_obstack);
+
+ FOR_BB_INSNS (merge_bb, insn)
+ if (NONDEBUG_INSN_P (insn))
+ df_simulate_find_defs (insn, merge_set);
}
no_body:
old_dest = JUMP_LABEL (jump);
if (other_bb != new_dest)
{
- new_label = block_label (new_dest);
+ 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)
+ new_dest_label = ret_rtx;
+ else
+ new_dest_label = block_label (new_dest);
+
if (reversep
- ? ! invert_jump_1 (jump, new_label)
- : ! redirect_jump_1 (jump, new_label))
+ ? ! invert_jump_1 (jump, new_dest_label)
+ : ! redirect_jump_1 (jump, new_dest_label))
goto cancel;
}
if (other_bb != new_dest)
{
- redirect_jump_2 (jump, old_dest, new_label, 0, reversep);
+ redirect_jump_2 (jump, old_dest, new_dest_label, 0, reversep);
redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
if (reversep)
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. */
+ /* PR 21767: when moving insns above a conditional branch, the REG_EQUAL
+ notes being moved might become invalid. */
insn = head;
do
{
remove_note (insn, note);
} while (insn != end && (insn = NEXT_INSN (insn)));
+ /* PR46315: when moving insns above a conditional branch, the REG_EQUAL
+ notes referring to the registers being set might become invalid. */
+ if (merge_set)
+ {
+ unsigned i;
+ bitmap_iterator bi;
+
+ EXECUTE_IF_SET_IN_BITMAP (merge_set, 0, i, bi)
+ remove_reg_equal_equiv_notes_for_regno (i);
+
+ BITMAP_FREE (merge_set);
+ }
+
reorder_insns (head, end, PREV_INSN (earliest));
}
cancel:
cancel_changes (0);
+
+ if (merge_set)
+ BITMAP_FREE (merge_set);
+
return FALSE;
}
\f
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_df_finish | TODO_verify_rtl_sharing |
- TODO_dump_func /* todo_flags_finish */
+ 0 /* todo_flags_finish */
}
};
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_df_finish | TODO_verify_rtl_sharing |
- TODO_dump_func |
TODO_ggc_collect /* todo_flags_finish */
}
};
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_df_finish | TODO_verify_rtl_sharing |
- TODO_dump_func |
TODO_ggc_collect /* todo_flags_finish */
}
};