aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2002-05-06 22:59:38 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2002-05-06 22:59:38 +0000
commit1f77b5da981dae69e8e8d7ea3dc60ba95150c267 (patch)
tree42a44a69dbd2f8b714055533a4e34ddf161eabd9 /gcc
parenta5a49440f74e957e418360804bf270a8ebc9ad8e (diff)
downloadgcc-1f77b5da981dae69e8e8d7ea3dc60ba95150c267.zip
gcc-1f77b5da981dae69e8e8d7ea3dc60ba95150c267.tar.gz
gcc-1f77b5da981dae69e8e8d7ea3dc60ba95150c267.tar.bz2
re PR rtl-optimization/3995 (i386 optimisation: joining tests)
PR opt/3995 * fold-const.c (sign_bit_p): New function. (fold) [EQ_EXPR]: Use this to convert (A & C) == 0 into A >= 0 and (A & C) != 0 into A < 0, when constant C is the sign bit of A's type. Reapply fold when converting (A & C) == C into (A & C) != 0. (fold_binary_op_with_conditional_arg): Fix typo in comment. testsuite/ * gcc.c-torture/execute/20020506-1.c: New test case. From-SVN: r53241
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/fold-const.c73
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20020506-1.c333
4 files changed, 416 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d88c973..fd44b15 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2002-05-06 Roger Sayle <roger@eyesopen.com>
+
+ PR opt/3995
+ * fold-const.c (sign_bit_p): New function.
+ (fold) [EQ_EXPR]: Use this to convert (A & C) == 0 into A >= 0 and
+ (A & C) != 0 into A < 0, when constant C is the sign bit of A's type.
+ Reapply fold when converting (A & C) == C into (A & C) != 0.
+ (fold_binary_op_with_conditional_arg): Fix typo in comment.
+
2002-05-07 Neil Booth <neil@daikokuya.demon.co.uk>
* c-common.c (warn_multichar): New.
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 9142f3d..6b4982a 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -86,6 +86,7 @@ static tree decode_field_reference PARAMS ((tree, HOST_WIDE_INT *,
enum machine_mode *, int *,
int *, tree *, tree *));
static int all_ones_mask_p PARAMS ((tree, int));
+static tree sign_bit_p PARAMS ((tree, tree));
static int simple_operand_p PARAMS ((tree));
static tree range_binop PARAMS ((enum tree_code, tree, tree, int,
tree, int));
@@ -2634,6 +2635,55 @@ all_ones_mask_p (mask, size)
size_int (precision - size), 0));
}
+/* Subroutine for fold: determine if VAL is the INTEGER_CONST that
+ represents the sign bit of EXP's type. If EXP represents a sign
+ or zero extension, also test VAL against the unextended type.
+ The return value is the (sub)expression whose sign bit is VAL,
+ or NULL_TREE otherwise. */
+
+static tree
+sign_bit_p (exp, val)
+ tree exp;
+ tree val;
+{
+ unsigned HOST_WIDE_INT lo;
+ HOST_WIDE_INT hi;
+ int width;
+ tree t;
+
+ /* Tree EXP must have a integral type. */
+ t = TREE_TYPE (exp);
+ if (! INTEGRAL_TYPE_P (t))
+ return NULL_TREE;
+
+ /* Tree VAL must be an integer constant. */
+ if (TREE_CODE (val) != INTEGER_CST
+ || TREE_CONSTANT_OVERFLOW (val))
+ return NULL_TREE;
+
+ width = TYPE_PRECISION (t);
+ if (width > HOST_BITS_PER_WIDE_INT)
+ {
+ hi = (unsigned HOST_WIDE_INT) 1 << (width - HOST_BITS_PER_WIDE_INT - 1);
+ lo = 0;
+ }
+ else
+ {
+ hi = 0;
+ lo = (unsigned HOST_WIDE_INT) 1 << (width - 1);
+ }
+
+ if (TREE_INT_CST_HIGH (val) == hi && TREE_INT_CST_LOW (val) == lo)
+ return exp;
+
+ /* Handle extension from a narrower type. */
+ if (TREE_CODE (exp) == NOP_EXPR
+ && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))) < width)
+ return sign_bit_p (TREE_OPERAND (exp, 0), val);
+
+ return NULL_TREE;
+}
+
/* Subroutine for fold_truthop: determine if an operand is simple enough
to be evaluated unconditionally. */
@@ -4173,7 +4223,7 @@ count_cond (expr, lim)
return MIN (lim, 1 + ctrue + cfalse);
}
-/* Transform `a + (b ? x : y)' into `x ? (a + b) : (a + y)'.
+/* Transform `a + (b ? x : y)' into `b ? (a + x) : (a + y)'.
Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'. Here
CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)'
expression, and ARG to `a'. If COND_FIRST_P is non-zero, then the
@@ -6037,8 +6087,25 @@ fold (expr)
&& TREE_CODE (arg0) == BIT_AND_EXPR
&& integer_pow2p (TREE_OPERAND (arg0, 1))
&& operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
- return build (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
- arg0, integer_zero_node);
+ return fold (build (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
+ arg0, integer_zero_node));
+
+ /* If we have (A & C) != 0 where C is the sign bit of A, convert
+ this into A < 0. Similarly for (A & C) == 0 into A >= 0. */
+ if ((code == EQ_EXPR || code == NE_EXPR)
+ && TREE_CODE (arg0) == BIT_AND_EXPR
+ && integer_zerop (arg1))
+ {
+ tree arg00 = sign_bit_p (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg0, 1));
+ if (arg00 != NULL_TREE)
+ {
+ tree stype = (*lang_hooks.types.signed_type) (TREE_TYPE (arg00));
+ return fold (build (code == EQ_EXPR ? GE_EXPR : LT_EXPR, type,
+ convert (stype, arg00),
+ convert (stype, integer_zero_node)));
+ }
+ }
/* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
and similarly for >= into !=. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1b8bd71..c231d99 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2002-05-06 Roger Sayle <roger@eyesopen.com>
+
+ * gcc.c-torture/execute/20020506-1.c: New test case.
+
2002-05-07 Neil Booth <neil@daikokuya.demon.co.uk>
* gcc.dg/cpp/charconst-3.c: Correct tests accordingly.
diff --git a/gcc/testsuite/gcc.c-torture/execute/20020506-1.c b/gcc/testsuite/gcc.c-torture/execute/20020506-1.c
new file mode 100644
index 0000000..bcbd45b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20020506-1.c
@@ -0,0 +1,333 @@
+/* Copyright (C) 2002 Free Software Foundation.
+
+ Test that (A & C1) op C2 optimizations behave correctly where C1 is
+ a constant power of 2, op is == or !=, and C2 is C1 or zero.
+
+ Written by Roger Sayle, 5th May 2002. */
+
+#include <limits.h>
+
+extern void abort (void);
+
+void test1 (signed char c, int set);
+void test2 (unsigned char c, int set);
+void test3 (short s, int set);
+void test4 (unsigned short s, int set);
+void test5 (int i, int set);
+void test6 (unsigned int i, int set);
+void test7 (long long l, int set);
+void test8 (unsigned long long l, int set);
+
+#ifndef LONG_LONG_MAX
+#define LONG_LONG_MAX __LONG_LONG_MAX__
+#endif
+#ifndef LONG_LONG_MIN
+#define LONG_LONG_MIN (-LONG_LONG_MAX-1)
+#endif
+#ifndef ULONG_LONG_MAX
+#define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1)
+#endif
+
+
+void
+test1 (signed char c, int set)
+{
+ if ((c & (SCHAR_MAX+1)) == 0)
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+
+ if ((c & (SCHAR_MAX+1)) != 0)
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((c & (SCHAR_MAX+1)) == (SCHAR_MAX+1))
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((c & (SCHAR_MAX+1)) != (SCHAR_MAX+1))
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+}
+
+void
+test2 (unsigned char c, int set)
+{
+ if ((c & (SCHAR_MAX+1)) == 0)
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+
+ if ((c & (SCHAR_MAX+1)) != 0)
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((c & (SCHAR_MAX+1)) == (SCHAR_MAX+1))
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((c & (SCHAR_MAX+1)) != (SCHAR_MAX+1))
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+}
+
+void
+test3 (short s, int set)
+{
+ if ((s & (SHRT_MAX+1)) == 0)
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+
+ if ((s & (SHRT_MAX+1)) != 0)
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((s & (SHRT_MAX+1)) == (SHRT_MAX+1))
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((s & (SHRT_MAX+1)) != (SHRT_MAX+1))
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+}
+
+void
+test4 (unsigned short s, int set)
+{
+ if ((s & (SHRT_MAX+1)) == 0)
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+
+ if ((s & (SHRT_MAX+1)) != 0)
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((s & (SHRT_MAX+1)) == (SHRT_MAX+1))
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((s & (SHRT_MAX+1)) != (SHRT_MAX+1))
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+}
+
+void
+test5 (int i, int set)
+{
+ if ((i & (INT_MAX+1U)) == 0)
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+
+ if ((i & (INT_MAX+1U)) != 0)
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((i & (INT_MAX+1U)) == (INT_MAX+1U))
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((i & (INT_MAX+1U)) != (INT_MAX+1U))
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+}
+
+void
+test6 (unsigned int i, int set)
+{
+ if ((i & (INT_MAX+1U)) == 0)
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+
+ if ((i & (INT_MAX+1U)) != 0)
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((i & (INT_MAX+1U)) == (INT_MAX+1U))
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((i & (INT_MAX+1U)) != (INT_MAX+1U))
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+}
+
+void
+test7 (long long l, int set)
+{
+ if ((l & (LONG_LONG_MAX+1ULL)) == 0)
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+
+ if ((l & (LONG_LONG_MAX+1ULL)) != 0)
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((l & (LONG_LONG_MAX+1ULL)) == (LONG_LONG_MAX+1ULL))
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((l & (LONG_LONG_MAX+1ULL)) != (LONG_LONG_MAX+1ULL))
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+}
+
+void
+test8 (unsigned long long l, int set)
+{
+ if ((l & (LONG_LONG_MAX+1ULL)) == 0)
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+
+ if ((l & (LONG_LONG_MAX+1ULL)) != 0)
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((l & (LONG_LONG_MAX+1ULL)) == (LONG_LONG_MAX+1ULL))
+ {
+ if (!set) abort ();
+ }
+ else
+ if (set) abort ();
+
+ if ((l & (LONG_LONG_MAX+1ULL)) != (LONG_LONG_MAX+1ULL))
+ {
+ if (set) abort ();
+ }
+ else
+ if (!set) abort ();
+}
+
+int
+main ()
+{
+ test1 (0, 0);
+ test1 (SCHAR_MAX, 0);
+ test1 (SCHAR_MIN, 1);
+ test1 (UCHAR_MAX, 1);
+
+ test2 (0, 0);
+ test2 (SCHAR_MAX, 0);
+ test2 (SCHAR_MIN, 1);
+ test2 (UCHAR_MAX, 1);
+
+ test3 (0, 0);
+ test3 (SHRT_MAX, 0);
+ test3 (SHRT_MIN, 1);
+ test3 (USHRT_MAX, 1);
+
+ test4 (0, 0);
+ test4 (SHRT_MAX, 0);
+ test4 (SHRT_MIN, 1);
+ test4 (USHRT_MAX, 1);
+
+ test5 (0, 0);
+ test5 (INT_MAX, 0);
+ test5 (INT_MIN, 1);
+ test5 (UINT_MAX, 1);
+
+ test6 (0, 0);
+ test6 (INT_MAX, 0);
+ test6 (INT_MIN, 1);
+ test6 (UINT_MAX, 1);
+
+ test7 (0, 0);
+ test7 (LONG_LONG_MAX, 0);
+ test7 (LONG_LONG_MIN, 1);
+ test7 (ULONG_LONG_MAX, 1);
+
+ test8 (0, 0);
+ test8 (LONG_LONG_MAX, 0);
+ test8 (LONG_LONG_MIN, 1);
+ test8 (ULONG_LONG_MAX, 1);
+
+ return 0;
+}
+