fold-const.c (fold): Move bit_rotate code to the EXPR_PLUS case, falltrought to assocate code.
* fold-const.c (fold): Move bit_rotate code to the EXPR_PLUS case, falltrought to assocate code. Convert XOR to OR in code like (a&c1)^(a&c2) where c1 and c2 don't have bits in common. * combine.c (simplify_logical): Convert XOR to IOR if operands have no bits in common; remove XOR to ROTATE conversion. From-SVN: r29998
This commit is contained in:
parent
ce57746769
commit
79e8185c9c
@ -1,3 +1,13 @@
|
||||
Thu Oct 14 19:44:08 1999 Jan Hubicka <hubicka@freesoft.cz>
|
||||
|
||||
* fold-const.c (fold): Move bit_rotate code to the EXPR_PLUS case,
|
||||
falltrought to assocate code.
|
||||
Convert XOR to OR in code like (a&c1)^(a&c2) where c1 and c2 don't have
|
||||
bits in common.
|
||||
|
||||
* combine.c (simplify_logical): Convert XOR to IOR if operands have
|
||||
no bits in common; remove XOR to ROTATE conversion.
|
||||
|
||||
Fri Oct 15 17:40:11 1999 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* config/c4x/c4x.h (c4x_va_start, c4x_va_arg): Declare.
|
||||
|
@ -5163,6 +5163,15 @@ simplify_logical (x, last)
|
||||
break;
|
||||
|
||||
case XOR:
|
||||
/* If we are XORing two things that have no bits in common,
|
||||
convert them into an IOR. This helps to detect rotation encoded
|
||||
using those methods and possibly other simplifications. */
|
||||
|
||||
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
|
||||
&& (nonzero_bits (op0, mode)
|
||||
& nonzero_bits (op1, mode)) == 0)
|
||||
return (gen_binary (IOR, mode, op0, op1));
|
||||
|
||||
/* Convert (XOR (NOT x) (NOT y)) to (XOR x y).
|
||||
Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for
|
||||
(NOT y). */
|
||||
@ -5232,20 +5241,6 @@ simplify_logical (x, last)
|
||||
return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
|
||||
mode, XEXP (op0, 0), XEXP (op0, 1));
|
||||
|
||||
/* Convert (xor (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
|
||||
mode size to (rotate A CX). */
|
||||
|
||||
if (((GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
|
||||
|| (GET_CODE (op1) == ASHIFT && GET_CODE (op0) == LSHIFTRT))
|
||||
&& rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
|
||||
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
|
||||
&& GET_CODE (XEXP (op1, 1)) == CONST_INT
|
||||
&& (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1))
|
||||
== GET_MODE_BITSIZE (mode)))
|
||||
return gen_rtx_ROTATE (mode, XEXP (op0, 0),
|
||||
(GET_CODE (op0) == ASHIFT
|
||||
? XEXP (op0, 1) : XEXP (op1, 1)));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
164
gcc/fold-const.c
164
gcc/fold-const.c
@ -4874,6 +4874,74 @@ fold (expr)
|
||||
else if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (arg1)))
|
||||
return non_lvalue (convert (type, arg0));
|
||||
|
||||
bit_rotate:
|
||||
/* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A
|
||||
is a rotate of A by C1 bits. */
|
||||
/* (A << B) + (A >> (Z - B)) if A is unsigned and Z is the size of A
|
||||
is a rotate of A by B bits. */
|
||||
{
|
||||
register enum tree_code code0, code1;
|
||||
code0 = TREE_CODE (arg0);
|
||||
code1 = TREE_CODE (arg1);
|
||||
if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
|
||||
|| (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
|
||||
&& operand_equal_p (TREE_OPERAND (arg0, 0),
|
||||
TREE_OPERAND (arg1,0), 0)
|
||||
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
|
||||
{
|
||||
register tree tree01, tree11;
|
||||
register enum tree_code code01, code11;
|
||||
|
||||
tree01 = TREE_OPERAND (arg0, 1);
|
||||
tree11 = TREE_OPERAND (arg1, 1);
|
||||
STRIP_NOPS (tree01);
|
||||
STRIP_NOPS (tree11);
|
||||
code01 = TREE_CODE (tree01);
|
||||
code11 = TREE_CODE (tree11);
|
||||
if (code01 == INTEGER_CST
|
||||
&& code11 == INTEGER_CST
|
||||
&& TREE_INT_CST_HIGH (tree01) == 0
|
||||
&& TREE_INT_CST_HIGH (tree11) == 0
|
||||
&& ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
|
||||
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
|
||||
return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
|
||||
code0 == LSHIFT_EXPR ? tree01 : tree11);
|
||||
else if (code11 == MINUS_EXPR)
|
||||
{
|
||||
tree tree110, tree111;
|
||||
tree110 = TREE_OPERAND (tree11, 0);
|
||||
tree111 = TREE_OPERAND (tree11, 1);
|
||||
STRIP_NOPS (tree110);
|
||||
STRIP_NOPS (tree111);
|
||||
if (TREE_CODE (tree110) == INTEGER_CST
|
||||
&& TREE_INT_CST_HIGH (tree110) == 0
|
||||
&& (TREE_INT_CST_LOW (tree110)
|
||||
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))
|
||||
&& operand_equal_p (tree01, tree111, 0))
|
||||
return build ((code0 == LSHIFT_EXPR
|
||||
? LROTATE_EXPR
|
||||
: RROTATE_EXPR),
|
||||
type, TREE_OPERAND (arg0, 0), tree01);
|
||||
}
|
||||
else if (code01 == MINUS_EXPR)
|
||||
{
|
||||
tree tree010, tree011;
|
||||
tree010 = TREE_OPERAND (tree01, 0);
|
||||
tree011 = TREE_OPERAND (tree01, 1);
|
||||
STRIP_NOPS (tree010);
|
||||
STRIP_NOPS (tree011);
|
||||
if (TREE_CODE (tree010) == INTEGER_CST
|
||||
&& TREE_INT_CST_HIGH (tree010) == 0
|
||||
&& (TREE_INT_CST_LOW (tree010)
|
||||
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))
|
||||
&& operand_equal_p (tree11, tree011, 0))
|
||||
return build ((code0 != LSHIFT_EXPR
|
||||
? LROTATE_EXPR
|
||||
: RROTATE_EXPR),
|
||||
type, TREE_OPERAND (arg0, 0), tree11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
associate:
|
||||
/* In most languages, can't associate operations on floats
|
||||
@ -5107,9 +5175,6 @@ fold (expr)
|
||||
|
||||
case BIT_IOR_EXPR:
|
||||
bit_ior:
|
||||
{
|
||||
register enum tree_code code0, code1;
|
||||
|
||||
if (integer_all_onesp (arg1))
|
||||
return omit_one_operand (type, arg1, arg0);
|
||||
if (integer_zerop (arg1))
|
||||
@ -5118,85 +5183,34 @@ fold (expr)
|
||||
if (t1 != NULL_TREE)
|
||||
return t1;
|
||||
|
||||
bit_rotate:
|
||||
/* (A << C1) | (A >> C2) if A is unsigned and C1+C2 is the size of A
|
||||
is a rotate of A by C1 bits. */
|
||||
/* (A << B) | (A >> (Z - B)) if A is unsigned and Z is the size of A
|
||||
is a rotate of A by B bits. */
|
||||
|
||||
/* Both transformations noted above also apply to when the inner
|
||||
operation is an XOR. */
|
||||
|
||||
code0 = TREE_CODE (arg0);
|
||||
code1 = TREE_CODE (arg1);
|
||||
if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
|
||||
|| (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
|
||||
&& operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1,0), 0)
|
||||
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
|
||||
{
|
||||
register tree tree01, tree11;
|
||||
register enum tree_code code01, code11;
|
||||
|
||||
tree01 = TREE_OPERAND (arg0, 1);
|
||||
tree11 = TREE_OPERAND (arg1, 1);
|
||||
STRIP_NOPS (tree01);
|
||||
STRIP_NOPS (tree11);
|
||||
code01 = TREE_CODE (tree01);
|
||||
code11 = TREE_CODE (tree11);
|
||||
if (code01 == INTEGER_CST
|
||||
&& code11 == INTEGER_CST
|
||||
&& TREE_INT_CST_HIGH (tree01) == 0
|
||||
&& TREE_INT_CST_HIGH (tree11) == 0
|
||||
&& ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
|
||||
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
|
||||
return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
|
||||
code0 == LSHIFT_EXPR ? tree01 : tree11);
|
||||
else if (code11 == MINUS_EXPR)
|
||||
{
|
||||
tree tree110, tree111;
|
||||
tree110 = TREE_OPERAND (tree11, 0);
|
||||
tree111 = TREE_OPERAND (tree11, 1);
|
||||
STRIP_NOPS (tree110);
|
||||
STRIP_NOPS (tree111);
|
||||
if (TREE_CODE (tree110) == INTEGER_CST
|
||||
&& TREE_INT_CST_HIGH (tree110) == 0
|
||||
&& (TREE_INT_CST_LOW (tree110)
|
||||
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))
|
||||
&& operand_equal_p (tree01, tree111, 0))
|
||||
return build ((code0 == LSHIFT_EXPR
|
||||
? LROTATE_EXPR
|
||||
: RROTATE_EXPR),
|
||||
type, TREE_OPERAND (arg0, 0), tree01);
|
||||
}
|
||||
else if (code01 == MINUS_EXPR)
|
||||
{
|
||||
tree tree010, tree011;
|
||||
tree010 = TREE_OPERAND (tree01, 0);
|
||||
tree011 = TREE_OPERAND (tree01, 1);
|
||||
STRIP_NOPS (tree010);
|
||||
STRIP_NOPS (tree011);
|
||||
if (TREE_CODE (tree010) == INTEGER_CST
|
||||
&& TREE_INT_CST_HIGH (tree010) == 0
|
||||
&& (TREE_INT_CST_LOW (tree010)
|
||||
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))
|
||||
&& operand_equal_p (tree11, tree011, 0))
|
||||
return build ((code0 != LSHIFT_EXPR
|
||||
? LROTATE_EXPR
|
||||
: RROTATE_EXPR),
|
||||
type, TREE_OPERAND (arg0, 0), tree11);
|
||||
}
|
||||
}
|
||||
|
||||
goto associate;
|
||||
}
|
||||
/* See if this can be simplified into a rotate first. If that
|
||||
is unsuccessful continue in the association code. */
|
||||
goto bit_rotate;
|
||||
|
||||
case BIT_XOR_EXPR:
|
||||
if (integer_zerop (arg1))
|
||||
return non_lvalue (convert (type, arg0));
|
||||
if (integer_all_onesp (arg1))
|
||||
return fold (build1 (BIT_NOT_EXPR, type, arg0));
|
||||
|
||||
/* If we are XORing two BIT_AND_EXPR's, both of which are and'ing
|
||||
with a constant, and the two constants have no bits in common,
|
||||
we should treat this as a BIT_IOR_EXPR since this may produce more
|
||||
simplifications. */
|
||||
if (TREE_CODE (arg0) == BIT_AND_EXPR
|
||||
&& TREE_CODE (arg1) == BIT_AND_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
|
||||
&& TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
|
||||
&& integer_zerop (const_binop (BIT_AND_EXPR,
|
||||
TREE_OPERAND (arg0, 1),
|
||||
TREE_OPERAND (arg1, 1), 0)))
|
||||
{
|
||||
code = BIT_IOR_EXPR;
|
||||
goto bit_ior;
|
||||
}
|
||||
|
||||
/* See if this can be simplified into a rotate first. If that
|
||||
is unsuccessful we will jump to the association code. */
|
||||
is unsuccessful continue in the association code. */
|
||||
goto bit_rotate;
|
||||
|
||||
case BIT_AND_EXPR:
|
||||
|
Loading…
Reference in New Issue
Block a user