Index: gcc/gcc/ifcvt.c |
diff --git a/gcc/gcc/ifcvt.c b/gcc/gcc/ifcvt.c |
index a6db2114be67269d102715a2d694e425d9668ba1..e9f60ed5e8bd33ff4951781d55329630c34a6196 100644 |
--- a/gcc/gcc/ifcvt.c |
+++ b/gcc/gcc/ifcvt.c |
@@ -1,5 +1,5 @@ |
/* If-conversion support. |
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 |
Free Software Foundation, Inc. |
This file is part of GCC. |
@@ -47,9 +47,6 @@ |
#include "vecprim.h" |
#include "dbgcnt.h" |
-#ifndef HAVE_conditional_execution |
-#define HAVE_conditional_execution 0 |
-#endif |
#ifndef HAVE_conditional_move |
#define HAVE_conditional_move 0 |
#endif |
@@ -62,9 +59,6 @@ |
#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 \ |
@@ -197,7 +191,7 @@ first_active_insn (basic_block bb) |
insn = NEXT_INSN (insn); |
} |
- while (NOTE_P (insn)) |
+ while (NOTE_P (insn) || DEBUG_INSN_P (insn)) |
{ |
if (insn == BB_END (bb)) |
return NULL_RTX; |
@@ -220,6 +214,7 @@ last_active_insn (basic_block bb, int skip_use_p) |
while (NOTE_P (insn) |
|| JUMP_P (insn) |
+ || DEBUG_INSN_P (insn) |
|| (skip_use_p |
&& NONJUMP_INSN_P (insn) |
&& GET_CODE (PATTERN (insn)) == USE)) |
@@ -272,7 +267,7 @@ cond_exec_process_insns (ce_if_block_t *ce_info ATTRIBUTE_UNUSED, |
for (insn = start; ; insn = NEXT_INSN (insn)) |
{ |
- if (NOTE_P (insn)) |
+ if (NOTE_P (insn) || DEBUG_INSN_P (insn)) |
goto insn_done; |
gcc_assert(NONJUMP_INSN_P (insn) || CALL_P (insn)); |
@@ -908,12 +903,12 @@ noce_try_store_flag (struct noce_if_info *if_info) |
int reversep; |
rtx target, seq; |
- if (GET_CODE (if_info->b) == CONST_INT |
+ if (CONST_INT_P (if_info->b) |
&& 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 |
+ && CONST_INT_P (if_info->a) |
&& INTVAL (if_info->a) == STORE_FLAG_VALUE |
&& (reversed_comparison_code (if_info->cond, if_info->jump) |
!= UNKNOWN)) |
@@ -955,8 +950,8 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) |
int normalize, can_reverse; |
enum machine_mode mode; |
- if (GET_CODE (if_info->a) == CONST_INT |
- && GET_CODE (if_info->b) == CONST_INT) |
+ if (CONST_INT_P (if_info->a) |
+ && CONST_INT_P (if_info->b)) |
{ |
mode = GET_MODE (if_info->x); |
ifalse = INTVAL (if_info->a); |
@@ -1331,11 +1326,15 @@ noce_try_cmove_arith (struct noce_if_info *if_info) |
/* ??? FIXME: Magic number 5. */ |
if (cse_not_expected |
&& MEM_P (a) && MEM_P (b) |
+ && 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)); |
+ |
a = XEXP (a, 0); |
b = XEXP (b, 0); |
- x = gen_reg_rtx (Pmode); |
+ x = gen_reg_rtx (address_mode); |
is_mem = 1; |
} |
@@ -1484,6 +1483,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info) |
set_mem_align (tmp, |
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)); |
+ |
noce_emit_move_insn (if_info->x, tmp); |
} |
else if (target != x) |
@@ -1541,7 +1543,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target, |
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) |
+ if (CONST_INT_P (target)) |
{ |
enum rtx_code code = GET_CODE (if_info->cond); |
rtx op_a = XEXP (if_info->cond, 0); |
@@ -1551,21 +1553,22 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target, |
/* 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) |
+ && BLOCK_FOR_INSN (prev_insn) |
+ == BLOCK_FOR_INSN (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 (CONST_INT_P (src)) |
{ |
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) |
+ if (CONST_INT_P (op_a)) |
{ |
rtx tmp = op_a; |
op_a = op_b; |
@@ -1577,7 +1580,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target, |
/* Now, look to see if we can get the right constant by |
adjusting the conditional. */ |
- if (GET_CODE (op_b) == CONST_INT) |
+ if (CONST_INT_P (op_b)) |
{ |
HOST_WIDE_INT desired_val = INTVAL (target); |
HOST_WIDE_INT actual_val = INTVAL (op_b); |
@@ -1746,13 +1749,16 @@ noce_try_minmax (struct noce_if_info *if_info) |
return TRUE; |
} |
-/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", etc. */ |
+/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", |
+ "if (a < 0) x = ~a; else x = a;" to "x = one_cmpl_abs(a);", |
+ etc. */ |
static int |
noce_try_abs (struct noce_if_info *if_info) |
{ |
rtx cond, earliest, target, seq, a, b, c; |
int negate; |
+ bool one_cmpl = false; |
/* Reject modes with signed zeros. */ |
if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x))) |
@@ -1770,6 +1776,17 @@ noce_try_abs (struct noce_if_info *if_info) |
c = a; a = b; b = c; |
negate = 1; |
} |
+ else if (GET_CODE (a) == NOT && rtx_equal_p (XEXP (a, 0), b)) |
+ { |
+ negate = 0; |
+ one_cmpl = true; |
+ } |
+ else if (GET_CODE (b) == NOT && rtx_equal_p (XEXP (b, 0), a)) |
+ { |
+ c = a; a = b; b = c; |
+ negate = 1; |
+ one_cmpl = true; |
+ } |
else |
return FALSE; |
@@ -1794,7 +1811,7 @@ noce_try_abs (struct noce_if_info *if_info) |
{ |
rtx set, insn = prev_nonnote_insn (earliest); |
if (insn |
- && BLOCK_NUM (insn) == BLOCK_NUM (earliest) |
+ && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (earliest) |
&& (set = single_set (insn)) |
&& rtx_equal_p (SET_DEST (set), c)) |
{ |
@@ -1841,13 +1858,23 @@ noce_try_abs (struct noce_if_info *if_info) |
} |
start_sequence (); |
- |
- target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1); |
+ if (one_cmpl) |
+ target = expand_one_cmpl_abs_nojump (GET_MODE (if_info->x), b, |
+ if_info->x); |
+ else |
+ 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 (one_cmpl) |
+ target = expand_simple_unop (GET_MODE (target), NOT, target, |
+ if_info->x, 0); |
+ else |
+ target = expand_simple_unop (GET_MODE (target), NEG, target, |
+ if_info->x, 0); |
+ } |
if (! target) |
{ |
@@ -1976,7 +2003,7 @@ noce_try_bitop (struct noce_if_info *if_info) |
if (GET_CODE (cond) == ZERO_EXTRACT) |
{ |
if (XEXP (cond, 1) != const1_rtx |
- || GET_CODE (XEXP (cond, 2)) != CONST_INT |
+ || !CONST_INT_P (XEXP (cond, 2)) |
|| ! rtx_equal_p (x, XEXP (cond, 0))) |
return FALSE; |
bitnum = INTVAL (XEXP (cond, 2)); |
@@ -1994,7 +2021,7 @@ noce_try_bitop (struct noce_if_info *if_info) |
{ |
/* Check for "if (X & C) x = x op C". */ |
if (! rtx_equal_p (x, XEXP (a, 0)) |
- || GET_CODE (XEXP (a, 1)) != CONST_INT |
+ || !CONST_INT_P (XEXP (a, 1)) |
|| (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode)) |
!= (unsigned HOST_WIDE_INT) 1 << bitnum) |
return FALSE; |
@@ -2020,7 +2047,7 @@ noce_try_bitop (struct noce_if_info *if_info) |
{ |
/* Check for "if (X & C) x &= ~C". */ |
if (! rtx_equal_p (x, XEXP (a, 0)) |
- || GET_CODE (XEXP (a, 1)) != CONST_INT |
+ || !CONST_INT_P (XEXP (a, 1)) |
|| (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode)) |
!= (~((HOST_WIDE_INT) 1 << bitnum) & GET_MODE_MASK (mode))) |
return FALSE; |
@@ -2145,7 +2172,7 @@ noce_mem_write_may_trap_or_fault_p (const_rtx mem) |
addr = XEXP (addr, 1); |
break; |
case PLUS: |
- if (GET_CODE (XEXP (addr, 1)) == CONST_INT) |
+ if (CONST_INT_P (XEXP (addr, 1))) |
addr = XEXP (addr, 0); |
else |
return false; |
@@ -2259,24 +2286,25 @@ noce_process_if_block (struct noce_if_info *if_info) |
else |
{ |
insn_b = prev_nonnote_insn (if_info->cond_earliest); |
+ while (insn_b && DEBUG_INSN_P (insn_b)) |
+ insn_b = prev_nonnote_insn (insn_b); |
/* 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) |
+ || BLOCK_FOR_INSN (insn_b) != BLOCK_FOR_INSN (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)) |
|| ! noce_operand_ok (SET_SRC (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) |
+ || modified_between_p (SET_SRC (set_b), insn_b, 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)) |
+ || modified_between_p (x, insn_b, jump)) |
insn_b = set_b = NULL_RTX; |
} |
@@ -2301,8 +2329,8 @@ noce_process_if_block (struct noce_if_info *if_info) |
return FALSE; |
if (GET_CODE (x) == ZERO_EXTRACT |
- && (GET_CODE (XEXP (x, 1)) != CONST_INT |
- || GET_CODE (XEXP (x, 2)) != CONST_INT)) |
+ && (!CONST_INT_P (XEXP (x, 1)) |
+ || !CONST_INT_P (XEXP (x, 2)))) |
return FALSE; |
x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART |
@@ -2396,7 +2424,7 @@ noce_process_if_block (struct noce_if_info *if_info) |
if (HAVE_conditional_move |
&& noce_try_cmove (if_info)) |
goto success; |
- if (! HAVE_conditional_execution) |
+ if (! targetm.have_conditional_execution ()) |
{ |
if (noce_try_store_flag_constants (if_info)) |
goto success; |
@@ -2484,7 +2512,7 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs, rtx co |
{ |
rtx set, dest, src; |
- if (!INSN_P (insn) || JUMP_P (insn)) |
+ if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn)) |
continue; |
set = single_set (insn); |
if (!set) |
@@ -2562,7 +2590,8 @@ cond_move_convert_if_block (struct noce_if_info *if_infop, |
rtx set, target, dest, t, e; |
unsigned int regno; |
- if (!INSN_P (insn) || JUMP_P (insn)) |
+ /* ??? Maybe emit conditional debug insn? */ |
+ if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn)) |
continue; |
set = single_set (insn); |
gcc_assert (set && REG_P (SET_DEST (set))); |
@@ -3039,16 +3068,17 @@ find_if_header (basic_block test_bb, int pass) |
&& noce_find_if_block (test_bb, then_edge, else_edge, pass)) |
goto success; |
- if (HAVE_conditional_execution && reload_completed |
+ if (targetm.have_conditional_execution () && reload_completed |
&& cond_exec_find_if_block (&ce_info)) |
goto success; |
- if (HAVE_trap && HAVE_conditional_trap |
+ if (HAVE_trap |
+ && optab_handler (ctrap_optab, word_mode)->insn_code != CODE_FOR_nothing |
&& 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)) |
+ && (! targetm.have_conditional_execution () || reload_completed)) |
{ |
if (find_if_case_1 (test_bb, then_edge, else_edge)) |
goto success; |
@@ -3122,6 +3152,7 @@ block_jumps_and_fallthru_p (basic_block cur_bb, basic_block target_bb) |
if (INSN_P (insn) |
&& !JUMP_P (insn) |
+ && !DEBUG_INSN_P (insn) |
&& GET_CODE (PATTERN (insn)) != USE |
&& GET_CODE (PATTERN (insn)) != CLOBBER) |
n_insns++; |
@@ -3154,7 +3185,7 @@ cond_exec_find_if_block (struct ce_if_block * ce_info) |
/* We only ever should get here after reload, |
and only if we have conditional execution. */ |
- gcc_assert (HAVE_conditional_execution && reload_completed); |
+ gcc_assert (targetm.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 |
@@ -3735,7 +3766,7 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge) |
test_bb->index, else_bb->index); |
/* ELSE is small. */ |
- if (! cheap_bb_rtx_cost_p (else_bb, |
+ if (! cheap_bb_rtx_cost_p (else_bb, |
COSTS_N_INSNS (BRANCH_COST (optimize_bb_for_speed_p (else_edge->src), |
predictable_edge_p (else_edge))))) |
return FALSE; |
@@ -3782,6 +3813,8 @@ 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; |
+ /* Number of pending changes. */ |
+ int n_validated_changes = 0; |
jump = BB_END (test_bb); |
@@ -3789,6 +3822,9 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
head = BB_HEAD (merge_bb); |
end = BB_END (merge_bb); |
+ while (DEBUG_INSN_P (end) && end != head) |
+ end = PREV_INSN (end); |
+ |
/* 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 |
@@ -3798,6 +3834,8 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
if (LABEL_P (head)) |
head = NEXT_INSN (head); |
+ while (DEBUG_INSN_P (head) && head != end) |
+ head = NEXT_INSN (head); |
if (NOTE_P (head)) |
{ |
if (head == end) |
@@ -3806,6 +3844,8 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
goto no_body; |
} |
head = NEXT_INSN (head); |
+ while (DEBUG_INSN_P (head) && head != end) |
+ head = NEXT_INSN (head); |
} |
if (JUMP_P (end)) |
@@ -3816,12 +3856,14 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
goto no_body; |
} |
end = PREV_INSN (end); |
+ while (DEBUG_INSN_P (end) && end != head) |
+ 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) |
+ if (targetm.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 |
@@ -3850,14 +3892,17 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
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; |
+ if (cond_exec_process_insns (NULL, head, end, cond, prob_val, 0) |
+ && verify_changes (0)) |
+ n_validated_changes = num_validated_changes (); |
+ else |
+ cancel_changes (0); |
earliest = jump; |
} |
- else |
#endif |
+ /* Try the NCE path if the CE path did not result in any changes. */ |
+ if (n_validated_changes == 0) |
{ |
/* In the non-conditional execution case, we have to verify that there |
are no trapping operations, no calls, no references to memory, and |
@@ -3873,7 +3918,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
{ |
if (CALL_P (insn)) |
return FALSE; |
- if (INSN_P (insn)) |
+ if (NONDEBUG_INSN_P (insn)) |
{ |
if (may_trap_p (PATTERN (insn))) |
return FALSE; |
@@ -3919,7 +3964,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
FOR_BB_INSNS (merge_bb, insn) |
{ |
- if (INSN_P (insn)) |
+ if (NONDEBUG_INSN_P (insn)) |
{ |
unsigned int uid = INSN_UID (insn); |
df_ref *def_rec; |
@@ -3943,11 +3988,11 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
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 |
+ |
+ /* 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_initialize_backwards (test_bb, test_live); |
@@ -3997,8 +4042,10 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, |
goto cancel; |
} |
- if (! apply_change_group ()) |
- return FALSE; |
+ if (verify_changes (n_validated_changes)) |
+ confirm_change_group (); |
+ else |
+ goto cancel; |
if (other_bb != new_dest) |
{ |
@@ -4112,7 +4159,7 @@ if_convert (void) |
FOR_EACH_BB (bb) |
{ |
basic_block new_bb; |
- while (!df_get_bb_dirty (bb) |
+ while (!df_get_bb_dirty (bb) |
&& (new_bb = find_if_header (bb, pass)) != NULL) |
bb = new_bb; |
} |