diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8a0143f6c3cc..6b0f4f7118a7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2001-07-27 DJ Delorie + + * ifcvt.c (noce_get_alt_condition): If the condition is a compare + against a constant, try to adjust the compare to have the desired + constant in it so that min/max optimizations happen more often. + Fri Jul 27 17:53:00 CEST 2001 Jan Hubicka * flow.c (last_loop_beg_note): New function. diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 08ec087e4ca5..4de879d7d826 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1,5 +1,5 @@ /* If-conversion support. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -1150,6 +1150,114 @@ noce_get_alt_condition (if_info, target, earliest) = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump); + /* 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_INSN (if_info->cond_earliest); + if (prev_insn + && 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; + if_info->cond_earliest = prev_insn; + } + else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn)))) + { + op_b = src; + if_info->cond_earliest = prev_insn; + } + + 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); if (! cond || ! reg_mentioned_p (target, cond))