From 1f77b5da981dae69e8e8d7ea3dc60ba95150c267 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Mon, 6 May 2002 22:59:38 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 9 + gcc/fold-const.c | 73 +++- gcc/testsuite/ChangeLog | 4 + .../gcc.c-torture/execute/20020506-1.c | 333 ++++++++++++++++++ 4 files changed, 416 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/20020506-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d88c97359aa0..fd44b153b6d0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2002-05-06 Roger Sayle + + 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 * c-common.c (warn_multichar): New. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 9142f3d80dc7..6b4982aad751 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 1b8bd7157c5e..c231d99be32a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2002-05-06 Roger Sayle + + * gcc.c-torture/execute/20020506-1.c: New test case. + 2002-05-07 Neil Booth * 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 000000000000..bcbd45bf6cae --- /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 + +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; +} +