re PR middle-end/29749 (Missing byte swap optimizations)

PR middle-end/29749
	* fold-const.c (fold_binary) <case BIT_AND_EXPR>: Optimize
	(X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
	and (X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1)).
	(fold_binary) <case LSHIFT_EXPR, case RSHIFT_EXPR>: Optimize
	(X & C2) << C1 into (X << C1) & (C2 << C1) and
	(X & C2) >> C1 into (X >> C1) & (C2 >> C1) if that allows further
	optimizations.

	* gcc.dg/fold-rotate-1.c: New test.

From-SVN: r130589
This commit is contained in:
Jakub Jelinek 2007-12-03 23:38:28 +01:00 committed by Jakub Jelinek
parent 36ad7922cb
commit 22164c3db7
4 changed files with 199 additions and 0 deletions

View file

@ -1,5 +1,14 @@
2007-12-03 Jakub Jelinek <jakub@redhat.com>
PR middle-end/29749
* fold-const.c (fold_binary) <case BIT_AND_EXPR>: Optimize
(X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
and (X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1)).
(fold_binary) <case LSHIFT_EXPR, case RSHIFT_EXPR>: Optimize
(X & C2) << C1 into (X << C1) & (C2 << C1) and
(X & C2) >> C1 into (X >> C1) & (C2 >> C1) if that allows further
optimizations.
PR tree-optimization/33453
* tree-data-ref.c (split_constant_offset): Use POINTER_PLUS_EXPR
for pointer addition.

View file

@ -10973,6 +10973,100 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return build_int_cst (type, residue & low);
}
/* Fold (X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
(X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1))
if the new mask might be further optimized. */
if ((TREE_CODE (arg0) == LSHIFT_EXPR
|| TREE_CODE (arg0) == RSHIFT_EXPR)
&& host_integerp (TREE_OPERAND (arg0, 1), 1)
&& host_integerp (arg1, TYPE_UNSIGNED (TREE_TYPE (arg1)))
&& tree_low_cst (TREE_OPERAND (arg0, 1), 1)
< TYPE_PRECISION (TREE_TYPE (arg0))
&& TYPE_PRECISION (TREE_TYPE (arg0)) <= HOST_BITS_PER_WIDE_INT
&& tree_low_cst (TREE_OPERAND (arg0, 1), 1) > 0)
{
unsigned int shiftc = tree_low_cst (TREE_OPERAND (arg0, 1), 1);
unsigned HOST_WIDE_INT mask
= tree_low_cst (arg1, TYPE_UNSIGNED (TREE_TYPE (arg1)));
unsigned HOST_WIDE_INT newmask, zerobits = 0;
tree shift_type = TREE_TYPE (arg0);
if (TREE_CODE (arg0) == LSHIFT_EXPR)
zerobits = ((((unsigned HOST_WIDE_INT) 1) << shiftc) - 1);
else if (TREE_CODE (arg0) == RSHIFT_EXPR
&& TYPE_PRECISION (TREE_TYPE (arg0))
== GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg0))))
{
unsigned int prec = TYPE_PRECISION (TREE_TYPE (arg0));
tree arg00 = TREE_OPERAND (arg0, 0);
/* See if more bits can be proven as zero because of
zero extension. */
if (TREE_CODE (arg00) == NOP_EXPR
&& TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg00, 0))))
{
tree inner_type = TREE_TYPE (TREE_OPERAND (arg00, 0));
if (TYPE_PRECISION (inner_type)
== GET_MODE_BITSIZE (TYPE_MODE (inner_type))
&& TYPE_PRECISION (inner_type) < prec)
{
prec = TYPE_PRECISION (inner_type);
/* See if we can shorten the right shift. */
if (shiftc < prec)
shift_type = inner_type;
}
}
zerobits = ~(unsigned HOST_WIDE_INT) 0;
zerobits >>= HOST_BITS_PER_WIDE_INT - shiftc;
zerobits <<= prec - shiftc;
/* For arithmetic shift if sign bit could be set, zerobits
can contain actually sign bits, so no transformation is
possible, unless MASK masks them all away. In that
case the shift needs to be converted into logical shift. */
if (!TYPE_UNSIGNED (TREE_TYPE (arg0))
&& prec == TYPE_PRECISION (TREE_TYPE (arg0)))
{
if ((mask & zerobits) == 0)
shift_type = unsigned_type_for (TREE_TYPE (arg0));
else
zerobits = 0;
}
}
/* ((X << 16) & 0xff00) is (X, 0). */
if ((mask & zerobits) == mask)
return omit_one_operand (type, build_int_cst (type, 0), arg0);
newmask = mask | zerobits;
if (newmask != mask && (newmask & (newmask + 1)) == 0)
{
unsigned int prec;
/* Only do the transformation if NEWMASK is some integer
mode's mask. */
for (prec = BITS_PER_UNIT;
prec < HOST_BITS_PER_WIDE_INT; prec <<= 1)
if (newmask == (((unsigned HOST_WIDE_INT) 1) << prec) - 1)
break;
if (prec < HOST_BITS_PER_WIDE_INT
|| newmask == ~(unsigned HOST_WIDE_INT) 0)
{
if (shift_type != TREE_TYPE (arg0))
{
tem = fold_build2 (TREE_CODE (arg0), shift_type,
fold_convert (shift_type,
TREE_OPERAND (arg0, 0)),
TREE_OPERAND (arg0, 1));
tem = fold_convert (type, tem);
}
else
tem = op0;
return fold_build2 (BIT_AND_EXPR, type, tem,
build_int_cst_type (TREE_TYPE (op1),
newmask));
}
}
}
goto associate;
case RDIV_EXPR:
@ -11526,6 +11620,25 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
== (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type))))
return TREE_OPERAND (arg0, 0);
/* Fold (X & C2) << C1 into (X << C1) & (C2 << C1)
(X & C2) >> C1 into (X >> C1) & (C2 >> C1)
if the latter can be further optimized. */
if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR)
&& TREE_CODE (arg0) == BIT_AND_EXPR
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
tree mask = fold_build2 (code, type,
fold_convert (type, TREE_OPERAND (arg0, 1)),
arg1);
tree shift = fold_build2 (code, type,
fold_convert (type, TREE_OPERAND (arg0, 0)),
arg1);
tem = fold_binary (BIT_AND_EXPR, type, shift, mask);
if (tem)
return tem;
}
return NULL_TREE;
case MIN_EXPR:

View file

@ -1,5 +1,8 @@
2007-12-03 Jakub Jelinek <jakub@redhat.com>
PR middle-end/29749
* gcc.dg/fold-rotate-1.c: New test.
PR tree-optimization/33453
* gcc.c-torture/compile/20071203-1.c: New test.

View file

@ -0,0 +1,74 @@
/* PR middle-end/29749 */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-original" } */
#if __SCHAR_MAX__ == 127
unsigned char
e1 (unsigned char a)
{
return a >> 5 | a << 3;
}
unsigned char
e2 (unsigned char a)
{
return (a & 0xe0) >> 5 | (a & 0x1f) << 3;
}
unsigned char
e3 (unsigned char a)
{
return ((a >> 5) & 0x07) | ((a << 3) & 0xf8);
}
#endif
#if __SHRT_MAX__ == 32767
unsigned short
f1 (unsigned short a)
{
return a >> 8 | a << 8;
}
unsigned short
f2 (unsigned short a)
{
return (a & 0xff00) >> 8 | (a & 0x00ff) << 8;
}
unsigned short
f3 (unsigned short a)
{
return ((a >> 8) & 0x00ff) | ((a << 8) & 0xff00);
}
#endif
#if __INT_MAX__ == 2147483647
unsigned int
g1 (unsigned int a)
{
return a >> 24 | a << 8;
}
unsigned int
g2 (unsigned int a)
{
return (a & 0xff000000) >> 24 | (a & 0x00ffffff) << 8;
}
unsigned int
g3 (unsigned int a)
{
return ((a >> 24) & 0x000000ff) | ((a << 8) & 0xffffff00U);
}
#endif
int i;
/* { dg-final { scan-tree-dump-times "&" 0 "original" } } */
/* { dg-final { cleanup-tree-dump "original" } } */