aboutsummaryrefslogtreecommitdiff
path: root/gcc/ifcvt.c
diff options
context:
space:
mode:
authorDJ Delorie <dj@redhat.com>2001-07-27 23:13:34 -0400
committerDJ Delorie <dj@gcc.gnu.org>2001-07-27 23:13:34 -0400
commit7f64687763a1770d52b5c11d2e5044d3ccda20ed (patch)
treeb6602dcfbcbb2441cb51d0b3db365bfa56c733e6 /gcc/ifcvt.c
parentda397f8ed09544229b06599cb2878421a2844670 (diff)
downloadgcc-7f64687763a1770d52b5c11d2e5044d3ccda20ed.zip
gcc-7f64687763a1770d52b5c11d2e5044d3ccda20ed.tar.gz
gcc-7f64687763a1770d52b5c11d2e5044d3ccda20ed.tar.bz2
ifcvt.c (noce_get_alt_condition): If the condition is a compare against a constant...
* 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. From-SVN: r44435
Diffstat (limited to 'gcc/ifcvt.c')
-rw-r--r--gcc/ifcvt.c110
1 files changed, 109 insertions, 1 deletions
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 08ec087..4de879d 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))