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
This commit is contained in:
Roger Sayle 2002-05-06 22:59:38 +00:00 committed by Roger Sayle
parent a5a49440f7
commit 1f77b5da98
4 changed files with 416 additions and 3 deletions

View File

@ -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.

View File

@ -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 !=. */

View File

@ -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.

View File

@ -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;
}