summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2005-01-18 08:26:21 +0000
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2005-01-18 08:26:21 +0000
commit18f18e6cf3cef52bb09bd3d2d74aca5135bdc94f (patch)
treebb35b5440252ae54228e10dbf1fe2c62cf9156a4 /gcc
parentbedf7d3914cd533b799c72721c77127e0150a65e (diff)
downloadgcc-18f18e6cf3cef52bb09bd3d2d74aca5135bdc94f.tar.gz
PR rtl-optimization/19296
* combine.c (simplify_comparison): Rewrite the condition under which a non-paradoxical SUBREG of a PLUS can be lifted when compared against a constant. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@93818 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/combine.c75
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/short-compare-1.c21
-rw-r--r--gcc/testsuite/gcc.dg/short-compare-2.c22
5 files changed, 106 insertions, 24 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 533b424ea2a..ad34b3f17d0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2005-01-18 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ PR rtl-optimization/19296
+ * combine.c (simplify_comparison): Rewrite the condition under
+ which a non-paradoxical SUBREG of a PLUS can be lifted when
+ compared against a constant.
+
2005-01-18 Andi Kleen <ak@muc.de>
* c-typeck.c: (convert_for_assignment): Check warn_pointer_sign.
diff --git a/gcc/combine.c b/gcc/combine.c
index a870ff3751c..4f9ddfbd8e0 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -10041,34 +10041,61 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
break;
case SUBREG:
- /* Check for the case where we are comparing A - C1 with C2,
- both constants are smaller than 1/2 the maximum positive
- value in MODE, and the comparison is equality or unsigned.
- In that case, if A is either zero-extended to MODE or has
- sufficient sign bits so that the high-order bit in MODE
- is a copy of the sign in the inner mode, we can prove that it is
- safe to do the operation in the wider mode. This simplifies
- many range checks. */
+ /* Check for the case where we are comparing A - C1 with C2, that is
+
+ (subreg:MODE (plus (A) (-C1))) op (C2)
+
+ with C1 a constant, and try to lift the SUBREG, i.e. to do the
+ comparison in the wider mode. One of the following two conditions
+ must be true in order for this to be valid:
+
+ 1. The mode extension results in the same bit pattern being added
+ on both sides and the comparison is equality or unsigned. As
+ C2 has been truncated to fit in MODE, the pattern can only be
+ all 0s or all 1s.
+
+ 2. The mode extension results in the sign bit being copied on
+ each side.
+
+ The difficulty here is that we have predicates for A but not for
+ (A - C1) so we need to check that C1 is within proper bounds so
+ as to perturbate A as little as possible. */
if (mode_width <= HOST_BITS_PER_WIDE_INT
&& subreg_lowpart_p (op0)
+ && GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) > mode_width
&& GET_CODE (SUBREG_REG (op0)) == PLUS
- && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT
- && INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0
- && (-INTVAL (XEXP (SUBREG_REG (op0), 1))
- < (HOST_WIDE_INT) (GET_MODE_MASK (mode) / 2))
- && (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2
- && (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0),
- GET_MODE (SUBREG_REG (op0)))
- & ~GET_MODE_MASK (mode))
- || (num_sign_bit_copies (XEXP (SUBREG_REG (op0), 0),
- GET_MODE (SUBREG_REG (op0)))
- > (unsigned int)
- (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
- - GET_MODE_BITSIZE (mode)))))
- {
- op0 = SUBREG_REG (op0);
- continue;
+ && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT)
+ {
+ enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+ rtx a = XEXP (SUBREG_REG (op0), 0);
+ HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
+
+ if ((c1 > 0
+ && (unsigned HOST_WIDE_INT) c1
+ < (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)
+ && (equality_comparison_p || unsigned_comparison_p)
+ /* (A - C1) zero-extends if it is positive and sign-extends
+ if it is negative, C2 both zero- and sign-extends. */
+ && ((0 == (nonzero_bits (a, inner_mode)
+ & ~GET_MODE_MASK (mode))
+ && const_op >= 0)
+ /* (A - C1) sign-extends if it is positive and 1-extends
+ if it is negative, C2 both sign- and 1-extends. */
+ || (num_sign_bit_copies (a, inner_mode)
+ > (unsigned int) (GET_MODE_BITSIZE (inner_mode)
+ - mode_width)
+ && const_op < 0)))
+ || ((unsigned HOST_WIDE_INT) c1
+ < (unsigned HOST_WIDE_INT) 1 << (mode_width - 2)
+ /* (A - C1) always sign-extends, like C2. */
+ && num_sign_bit_copies (a, inner_mode)
+ > (unsigned int) (GET_MODE_BITSIZE (inner_mode)
+ - mode_width - 1)))
+ {
+ op0 = SUBREG_REG (op0);
+ continue;
+ }
}
/* If the inner mode is narrower and we are extracting the low part,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 06441c8ac7c..07c39cf4303 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2005-01-18 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ * gcc.dg/short-compare-1.c: New test.
+ * gcc.dg/short-compare-2.c: Likewise.
+
2005-01-18 Michael Matz <matz@suse.de>
* gcc.dg/Wno-pointer-sign.c: New test for -Wno-pointer-sign.
diff --git a/gcc/testsuite/gcc.dg/short-compare-1.c b/gcc/testsuite/gcc.dg/short-compare-1.c
new file mode 100644
index 00000000000..6a4e388d179
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/short-compare-1.c
@@ -0,0 +1,21 @@
+/* PR rtl-optimization/19296 */
+/* Origin: Falk Hueffner <falk@debian.org> */
+
+/* { dg-do run } */
+/* { dg-options "-O" } */
+/* { dg-options "-O -mtune=i686" { target i?86-*-* } } */
+/* { dg-options "-O -m32 -mtune=i686" { target x86_64-*-* } } */
+
+extern void abort(void);
+
+void f(unsigned short ad)
+{
+ if (ad >= 0x4000 && ad < 0xc000)
+ abort();
+}
+
+int main(void)
+{
+ f(0xff00);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/short-compare-2.c b/gcc/testsuite/gcc.dg/short-compare-2.c
new file mode 100644
index 00000000000..1c5963c5a2f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/short-compare-2.c
@@ -0,0 +1,22 @@
+/* PR rtl-optimization/19296 */
+/* Origin: Falk Hueffner <falk@debian.org> */
+/* Testcase by Andrew Pinski <pinskia@gcc.gnu.org> */
+
+/* { dg-do run } */
+/* { dg-options "-O" } */
+/* { dg-options "-O -mtune=i686" { target i?86-*-* } } */
+/* { dg-options "-O -m32 -mtune=i686" { target x86_64-*-* } } */
+
+extern void abort();
+
+void f(unsigned short ad)
+{
+ if ((short) (ad - 0x4000) >= 0)
+ abort();
+}
+
+int main(void)
+{
+ f(0xc000);
+ return 0;
+}