/* If-conversion support.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010,
- 2011
- Free Software Foundation, Inc.
+ Copyright (C) 2000-2013 Free Software Foundation, Inc.
This file is part of GCC.
#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"
+#include "pointer-set.h"
#include "dbgcnt.h"
#ifndef HAVE_conditional_move
switch (GET_RTX_CLASS (GET_CODE (y)))
{
case RTX_UNARY:
- ot = code_to_optab[GET_CODE (y)];
+ ot = code_to_optab (GET_CODE (y));
if (ot)
{
start_sequence ();
case RTX_BIN_ARITH:
case RTX_COMM_ARITH:
- ot = code_to_optab[GET_CODE (y)];
+ ot = code_to_optab (GET_CODE (y));
if (ot)
{
start_sequence ();
set_used_flags (if_info->x);
set_used_flags (if_info->cond);
+ set_used_flags (if_info->a);
+ set_used_flags (if_info->b);
unshare_all_rtl_in_chain (seq);
end_sequence ();
return FALSE;
emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
+ INSN_LOCATION (if_info->insn_a));
}
return TRUE;
}
return FALSE;
emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
+ INSN_LOCATION (if_info->insn_a));
return TRUE;
}
else
return FALSE;
emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
+ INSN_LOCATION (if_info->insn_a));
return TRUE;
}
return FALSE;
emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
+ INSN_LOCATION (if_info->insn_a));
return TRUE;
}
end_sequence ();
return FALSE;
emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
+ INSN_LOCATION (if_info->insn_a));
return TRUE;
}
end_sequence ();
return FALSE;
emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
+ INSN_LOCATION (if_info->insn_a));
return TRUE;
}
return FALSE;
emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
+ INSN_LOCATION (if_info->insn_a));
return TRUE;
}
else
&& MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b)
&& if_info->branch_cost >= 5)
{
- enum machine_mode address_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (a));
+ enum machine_mode address_mode = get_address_mode (a);
a = XEXP (a, 0);
b = XEXP (b, 0);
if (!tmp)
return FALSE;
- emit_insn_before_setloc (tmp, if_info->jump, INSN_LOCATOR (if_info->insn_a));
+ emit_insn_before_setloc (tmp, if_info->jump, INSN_LOCATION (if_info->insn_a));
return TRUE;
end_seq_and_fail:
if (!seq)
return FALSE;
- emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
+ emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a));
if_info->cond = cond;
if_info->cond_earliest = earliest;
if (!seq)
return FALSE;
- emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
+ emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a));
if_info->cond = cond;
if_info->cond_earliest = earliest;
if (!seq)
return FALSE;
- emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
+ emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a));
return TRUE;
}
return FALSE;
emit_insn_before_setloc (seq, if_info->jump,
- INSN_LOCATOR (if_info->insn_a));
+ INSN_LOCATION (if_info->insn_a));
}
return TRUE;
}
|| (CALL_P (insn) && (!RTL_CONST_CALL_P (insn)))))
return false;
- if (memory_modified_in_insn_p (mem, insn))
+ if (memory_must_be_modified_in_insn_p (mem, insn))
return true;
if (modified_in_p (XEXP (mem, 0), insn))
return false;
|| ! noce_operand_ok (SET_SRC (set_b))
|| reg_overlap_mentioned_p (x, SET_SRC (set_b))
|| modified_between_p (SET_SRC (set_b), insn_b, jump)
+ /* Avoid extending the lifetime of hard registers on small
+ register class machines. */
+ || (REG_P (SET_SRC (set_b))
+ && HARD_REGISTER_P (SET_SRC (set_b))
+ && targetm.small_register_classes_for_mode_p
+ (GET_MODE (SET_SRC (set_b))))
/* Likewise with X. In particular this can happen when
noce_get_condition looks farther back in the instruction
stream than one might expect. */
unshare_all_rtl_in_chain (seq);
end_sequence ();
- emit_insn_before_setloc (seq, BB_END (test_bb), INSN_LOCATOR (insn_a));
+ emit_insn_before_setloc (seq, BB_END (test_bb), INSN_LOCATION (insn_a));
}
/* The original THEN and ELSE blocks may now be removed. The test block
/* 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. */
+ register. For each assignment, store the value in the pointer map
+ VALS, keyed indexed by register pointer, then store the register
+ pointer in REGS. COND is the condition we will test. */
static int
-check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs,
+check_cond_move_block (basic_block bb,
+ struct pointer_map_t *vals,
+ vec<rtx> *regs,
rtx cond)
{
rtx insn;
FOR_BB_INSNS (bb, insn)
{
rtx set, dest, src;
+ void **slot;
if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn))
continue;
/* Don't try to handle this if the source register was
modified earlier in the block. */
if ((REG_P (src)
- && vals[REGNO (src)] != NULL)
+ && pointer_map_contains (vals, src))
|| (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src))
- && vals[REGNO (SUBREG_REG (src))] != NULL))
+ && pointer_map_contains (vals, SUBREG_REG (src))))
return FALSE;
/* Don't try to handle this if the destination register was
modified earlier in the block. */
- if (vals[REGNO (dest)] != NULL)
+ if (pointer_map_contains (vals, dest))
return FALSE;
/* Don't try to handle this if the condition uses the
&& modified_between_p (src, insn, NEXT_INSN (BB_END (bb))))
return FALSE;
- vals[REGNO (dest)] = src;
+ slot = pointer_map_insert (vals, (void *) dest);
+ *slot = (void *) src;
- VEC_safe_push (int, heap, *regs, REGNO (dest));
+ regs->safe_push (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
+ a condition COND, and pointer maps 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,
+ struct pointer_map_t *then_vals,
+ struct pointer_map_t *else_vals,
bool else_block_p)
{
enum rtx_code code;
FOR_BB_INSNS (bb, insn)
{
rtx set, target, dest, t, e;
- unsigned int regno;
+ void **then_slot, **else_slot;
/* ??? Maybe emit conditional debug insn? */
if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn))
gcc_assert (set && REG_P (SET_DEST (set)));
dest = SET_DEST (set);
- regno = REGNO (dest);
- t = then_vals[regno];
- e = else_vals[regno];
+ then_slot = pointer_map_contains (then_vals, dest);
+ else_slot = pointer_map_contains (else_vals, dest);
+ t = then_slot ? (rtx) *then_slot : NULL_RTX;
+ e = else_slot ? (rtx) *else_slot : NULL_RTX;
if (else_block_p)
{
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;
+ rtx reg;
+ int c;
+ struct pointer_map_t *then_vals;
+ struct pointer_map_t *else_vals;
+ vec<rtx> then_regs = vNULL;
+ vec<rtx> else_regs = vNULL;
unsigned int i;
+ int success_p = FALSE;
/* 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);
+ then_vals = pointer_map_create ();
+ else_vals = pointer_map_create ();
/* 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)))
- {
- VEC_free (int, heap, then_regs);
- VEC_free (int, heap, else_regs);
- return FALSE;
- }
+ goto done;
/* 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
source register does not change after the assignment. Also count
the number of registers set in only one of the blocks. */
c = 0;
- FOR_EACH_VEC_ELT (int, then_regs, i, reg)
+ FOR_EACH_VEC_ELT (then_regs, i, reg)
{
- if (!then_vals[reg] && !else_vals[reg])
- continue;
+ void **then_slot = pointer_map_contains (then_vals, reg);
+ void **else_slot = pointer_map_contains (else_vals, reg);
- if (!else_vals[reg])
+ gcc_checking_assert (then_slot);
+ if (!else_slot)
++c;
else
{
- if (!CONSTANT_P (then_vals[reg])
- && !CONSTANT_P (else_vals[reg])
- && !rtx_equal_p (then_vals[reg], else_vals[reg]))
- {
- VEC_free (int, heap, then_regs);
- VEC_free (int, heap, else_regs);
- return FALSE;
- }
+ rtx then_val = (rtx) *then_slot;
+ rtx else_val = (rtx) *else_slot;
+ if (!CONSTANT_P (then_val) && !CONSTANT_P (else_val)
+ && !rtx_equal_p (then_val, else_val))
+ goto done;
}
}
/* Finish off c for MAX_CONDITIONAL_EXECUTE. */
- FOR_EACH_VEC_ELT (int, else_regs, i, reg)
- if (!then_vals[reg])
- ++c;
+ FOR_EACH_VEC_ELT (else_regs, i, reg)
+ {
+ gcc_checking_assert (pointer_map_contains (else_vals, reg));
+ if (!pointer_map_contains (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)
- {
- VEC_free (int, heap, then_regs);
- VEC_free (int, heap, else_regs);
- return FALSE;
- }
+ goto done;
/* Try to emit the conditional moves. First do the then block,
then do anything left in the else blocks. */
then_vals, else_vals, true)))
{
end_sequence ();
- VEC_free (int, heap, then_regs);
- VEC_free (int, heap, else_regs);
- return FALSE;
+ goto done;
}
seq = end_ifcvt_sequence (if_info);
if (!seq)
- {
- VEC_free (int, heap, then_regs);
- VEC_free (int, heap, else_regs);
- return FALSE;
- }
+ goto done;
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));
+ emit_insn_before_setloc (seq, jump, INSN_LOCATION (loc_insn));
if (else_bb)
{
num_updated_if_blocks++;
- VEC_free (int, heap, then_regs);
- VEC_free (int, heap, else_regs);
- return TRUE;
+ success_p = TRUE;
+
+done:
+ pointer_map_destroy (then_vals);
+ pointer_map_destroy (else_vals);
+ then_regs.release ();
+ else_regs.release ();
+ return success_p;
}
\f
ce_info.else_bb = else_edge->dest;
ce_info.pass = pass;
-#ifdef IFCVT_INIT_EXTRA_FIELDS
- IFCVT_INIT_EXTRA_FIELDS (&ce_info);
+#ifdef IFCVT_MACHDEP_INIT
+ IFCVT_MACHDEP_INIT (&ce_info);
#endif
if (!reload_completed
code processing. ??? we should fix this in the future. */
if (EDGE_COUNT (then_bb->succs) == 0)
{
- if (single_pred_p (else_bb))
+ if (single_pred_p (else_bb) && else_bb != EXIT_BLOCK_PTR)
{
rtx last_insn = BB_END (then_bb);
return FALSE;
/* Emit the new insns before cond_earliest. */
- emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATOR (trap));
+ emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATION (trap));
/* Delete the trap block if possible. */
remove_edge (trap_bb == then_bb ? then_edge : else_edge);
/* 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. */
+ through to else_bb. */
if (then_bb->next_bb == else_bb
&& then_bb->prev_bb == test_bb
edge else_succ;
int then_prob, else_prob;
+ /* We do not want to speculate (empty) loop latches. */
+ if (current_loops
+ && else_bb->loop_father->latch == else_bb)
+ return FALSE;
+
/* 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.
#ifdef IFCVT_MULTIPLE_DUMPS
if (dump_file && cond_exec_changed_p)
- {
- if (dump_flags & TDF_SLIM)
- print_rtl_slim_with_bb (dump_file, get_insns (), dump_flags);
- else
- print_rtl_with_bb (dump_file, get_insns ());
- }
+ print_rtl_with_bb (dump_file, get_insns (), dump_flags);
#endif
}
while (cond_exec_changed_p);
if (flag_if_conversion)
{
if (dump_file)
- dump_flow_info (dump_file, dump_flags);
+ {
+ dump_reg_info (dump_file);
+ dump_flow_info (dump_file, dump_flags);
+ }
cleanup_cfg (CLEANUP_EXPENSIVE);
if_convert ();
}
{
RTL_PASS,
"ce1", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
gate_handle_if_conversion, /* gate */
rest_of_handle_if_conversion, /* execute */
NULL, /* sub */
{
RTL_PASS,
"ce2", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
gate_handle_if_after_combine, /* gate */
rest_of_handle_if_after_combine, /* execute */
NULL, /* sub */
{
RTL_PASS,
"ce3", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
gate_handle_if_after_reload, /* gate */
rest_of_handle_if_after_reload, /* execute */
NULL, /* sub */