This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa and mainline] Move folding from do_store_flag to fold
- From: law at redhat dot com
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 02 Jul 2003 23:51:09 -0600
- Subject: [tree-ssa and mainline] Move folding from do_store_flag to fold
- Reply-to: law at redhat dot com
I found this while evaluating a case where tree-ssa was generating less
efficient code than the mainline sources.
gimplification like to create nice simple insns and as a result if we
were looking for something like this after gimplification (say during
the tree->rtl conversion phase) it's never going to match:
EQ
BIT_AND_EXPR
<argument>
<constant power of 2>
constant 0
[ gimplification will break this down into two distinct expressions. ]
Not surprisingly, there is code during the tree->rtl conversion pass which
identifies such cases and transforms them into a more efficient form involving
shifts and logical operations (inside do_store_flag).
So I'm moving the code from the tree->rtl phase into the folder.
1. Folding is where this code naturally belongs.
2. There's already some code which does similar stuff in fold, but
handles fewer cases.
3. It's easy to put the code into fold and call back to it if
needed from do_store_flag.
4. tree-ssa won't be at a disadvantage since these expressions
will get rewritten into the preferred form before gimplification
breaks them down into simpler expressions.
Bootstrapped and regression tested i686-pc-linux-gnu, both in the mainline
and the tree-ssa branch. Installed into both. For the tests I was looking
at this eliminates the unwanted jumps.
One version for the mainline, the other for tree-ssa. They only differ
in their context for the tree.h change.
* expr.c (do_store_flag): Remove special case folding for
single bit tests. Instead call back into the commonized folder
routine.
* fold-const.c (fold_single_bit_test): New function, mostly
extracted from do_store_flag, with an additional case extracted
from fold.
(fold): Call fold_single_bit_test appropriately.
* tree.h (fold_single_bit_test): Prototype.
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.467.2.37
diff -c -3 -p -r1.467.2.37 expr.c
*** expr.c 1 Jul 2003 19:50:44 -0000 1.467.2.37
--- expr.c 3 Jul 2003 05:48:01 -0000
*************** do_store_flag (exp, target, mode, only_c
*** 10178,10242 ****
do this by shifting the bit being tested to the low-order bit and
masking the result with the constant 1. If the condition was EQ,
we xor it with 1. This does not require an scc insn and is faster
! than an scc insn even if we have it. */
if ((code == NE || code == EQ)
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
&& integer_pow2p (TREE_OPERAND (arg0, 1)))
! {
! tree inner = TREE_OPERAND (arg0, 0);
! int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
! int ops_unsignedp;
!
! /* If INNER is a right shift of a constant and it plus BITNUM does
! not overflow, adjust BITNUM and INNER. */
!
! if (TREE_CODE (inner) == RSHIFT_EXPR
! && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
! && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
! && bitnum < TYPE_PRECISION (type)
! && 0 > compare_tree_int (TREE_OPERAND (inner, 1),
! bitnum - TYPE_PRECISION (type)))
! {
! bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
! inner = TREE_OPERAND (inner, 0);
! }
!
! /* If we are going to be able to omit the AND below, we must do our
! operations as unsigned. If we must use the AND, we have a choice.
! Normally unsigned is faster, but for some machines signed is. */
! ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1
! #ifdef LOAD_EXTEND_OP
! : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1)
! #else
! : 1
! #endif
! );
!
! if (! get_subtarget (subtarget)
! || GET_MODE (subtarget) != operand_mode
! || ! safe_from_p (subtarget, inner, 1))
! subtarget = 0;
!
! op0 = expand_expr (inner, subtarget, VOIDmode, 0);
!
! if (bitnum != 0)
! op0 = expand_shift (RSHIFT_EXPR, operand_mode, op0,
! size_int (bitnum), subtarget, ops_unsignedp);
!
! if (GET_MODE (op0) != mode)
! op0 = convert_to_mode (mode, op0, ops_unsignedp);
!
! if ((code == EQ && ! invert) || (code == NE && invert))
! op0 = expand_binop (mode, xor_optab, op0, const1_rtx, subtarget,
! ops_unsignedp, OPTAB_LIB_WIDEN);
!
! /* Put the AND last so it can combine with more things. */
! if (bitnum != TYPE_PRECISION (type) - 1)
! op0 = expand_and (mode, op0, const1_rtx, subtarget);
!
! return op0;
! }
/* Now see if we are likely to be able to do this. Return if not. */
if (! can_compare_p (code, operand_mode, ccp_store_flag))
--- 10178,10194 ----
do this by shifting the bit being tested to the low-order bit and
masking the result with the constant 1. If the condition was EQ,
we xor it with 1. This does not require an scc insn and is faster
! than an scc insn even if we have it.
!
! The code to make this transformation was moved into fold_single_bit_test,
! so we just call into the folder and expand its result. */
if ((code == NE || code == EQ)
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
&& integer_pow2p (TREE_OPERAND (arg0, 1)))
! return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
! arg0, arg1, type),
! target, VOIDmode, EXPAND_NORMAL);
/* Now see if we are likely to be able to do this. Return if not. */
if (! can_compare_p (code, operand_mode, ccp_store_flag))
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.213.2.33
diff -c -3 -p -r1.213.2.33 fold-const.c
*** fold-const.c 29 Jun 2003 13:50:06 -0000 1.213.2.33
--- fold-const.c 3 Jul 2003 05:48:22 -0000
*************** nondestructive_fold_unary_to_constant (c
*** 5662,5667 ****
--- 5662,5772 ----
}
}
+ /* If CODE with arguments ARG0 and ARG1 represents a single bit
+ equality/inequality test, then return a simplified form of
+ the test using shifts and logical operations. Otherwise return
+ NULL. TYPE is the desired result type. */
+
+ tree
+ fold_single_bit_test (code, arg0, arg1, result_type)
+ enum tree_code code;
+ tree arg0;
+ tree arg1;
+ tree result_type;
+ {
+ /* If this is a TRUTH_NOT_EXPR, it may have a single bit test inside
+ operand 0. */
+ if (code == TRUTH_NOT_EXPR)
+ {
+ code = TREE_CODE (arg0);
+ if (code != NE_EXPR && code != EQ_EXPR)
+ return NULL_TREE;
+
+ /* Extract the arguments of the EQ/NE. */
+ arg1 = TREE_OPERAND (arg0, 1);
+ arg0 = TREE_OPERAND (arg0, 0);
+
+ /* This requires us to invert the code. */
+ code = (code == EQ_EXPR ? NE_EXPR : EQ_EXPR);
+ }
+
+ /* If this is testing a single bit, we can optimize the test. */
+ if ((code == NE_EXPR || code == EQ_EXPR)
+ && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
+ && integer_pow2p (TREE_OPERAND (arg0, 1)))
+ {
+ tree inner = TREE_OPERAND (arg0, 0);
+ tree type = TREE_TYPE (arg0);
+ int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
+ enum machine_mode operand_mode = TYPE_MODE (type);
+ int ops_unsigned;
+ tree signed_type, unsigned_type;
+ tree arg00;
+
+ /* 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. */
+ 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)));
+ }
+
+ /* Otherwise we have (A & C) != 0 where C is a single bit,
+ convert that into ((A >> C2) & 1). Where C2 = log2(C).
+ Similarly for (A & C) == 0. */
+
+ /* If INNER is a right shift of a constant and it plus BITNUM does
+ not overflow, adjust BITNUM and INNER. */
+ if (TREE_CODE (inner) == RSHIFT_EXPR
+ && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
+ && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
+ && bitnum < TYPE_PRECISION (type)
+ && 0 > compare_tree_int (TREE_OPERAND (inner, 1),
+ bitnum - TYPE_PRECISION (type)))
+ {
+ bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
+ inner = TREE_OPERAND (inner, 0);
+ }
+
+ /* If we are going to be able to omit the AND below, we must do our
+ operations as unsigned. If we must use the AND, we have a choice.
+ Normally unsigned is faster, but for some machines signed is. */
+ ops_unsigned = (bitnum == TYPE_PRECISION (type) - 1 ? 1
+ #ifdef LOAD_EXTEND_OP
+ : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1)
+ #else
+ : 1
+ #endif
+ );
+
+ signed_type = (*lang_hooks.types.type_for_mode) (operand_mode, 0);
+ unsigned_type = (*lang_hooks.types.type_for_mode) (operand_mode, 1);
+
+ if (bitnum != 0)
+ inner = build (RSHIFT_EXPR, ops_unsigned ? unsigned_type : signed_type,
+ inner, size_int (bitnum));
+
+ if (code == EQ_EXPR)
+ inner = build (BIT_XOR_EXPR, ops_unsigned ? unsigned_type : signed_type,
+ inner, integer_one_node);
+
+ /* Put the AND last so it can combine with more things. */
+ if (bitnum != TYPE_PRECISION (type) - 1)
+ inner = build (BIT_AND_EXPR, ops_unsigned ? unsigned_type : signed_type,
+ inner, integer_one_node);
+
+ /* Make sure to return the proper type. */
+ if (TREE_TYPE (inner) != result_type)
+ inner = convert (result_type, inner);
+
+ return inner;
+ }
+ return NULL_TREE;
+ }
+
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
and application of the associative law.
*************** fold (expr)
*** 7034,7040 ****
tem = invert_truthvalue (arg0);
/* Avoid infinite recursion. */
if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
! return t;
return convert (type, tem);
case TRUTH_ANDIF_EXPR:
--- 7139,7150 ----
tem = invert_truthvalue (arg0);
/* Avoid infinite recursion. */
if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
! {
! tem = fold_single_bit_test (code, arg0, arg1, type);
! if (tem)
! return tem;
! return t;
! }
return convert (type, tem);
case TRUTH_ANDIF_EXPR:
*************** fold (expr)
*** 7601,7622 ****
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 !=. */
--- 7711,7721 ----
return fold (build (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
arg0, integer_zero_node));
! /* If we have (A & C) != 0 or (A & C) == 0 and C is a power of
! 2, then fold the expression into shifts and logical operations. */
! tem = fold_single_bit_test (code, arg0, arg1, type);
! if (tem)
! return tem;
/* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
and similarly for >= into !=. */
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.74
diff -c -3 -p -r1.342.2.74 tree.h
*** tree.h 1 Jul 2003 22:49:55 -0000 1.342.2.74
--- tree.h 3 Jul 2003 05:48:29 -0000
*************** extern void using_eh_for_cleanups PARAM
*** 3069,3074 ****
--- 3069,3076 ----
subexpressions are not changed. */
extern tree fold PARAMS ((tree));
+ extern tree fold_single_bit_test
+ PARAMS ((enum tree_code, tree, tree, tree));
extern tree nondestructive_fold_unary_to_constant
PARAMS ((enum tree_code, tree, tree));
extern tree nondestructive_fold_binary_to_constant
* expr.c (do_store_flag): Remove special case folding for
single bit tests. Instead call back into the commonized folder
routine.
* fold-const.c (fold_single_bit_test): New function, mostly
extracted from do_store_flag, with an additional case extracted
from fold.
(fold): Call fold_single_bit_test appropriately.
* tree.h (fold_single_bit_test): Prototype.
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.560
diff -c -3 -p -r1.560 expr.c
*** expr.c 2 Jul 2003 07:41:06 -0000 1.560
--- expr.c 3 Jul 2003 05:37:52 -0000
*************** do_store_flag (tree exp, rtx target, enu
*** 9990,10054 ****
do this by shifting the bit being tested to the low-order bit and
masking the result with the constant 1. If the condition was EQ,
we xor it with 1. This does not require an scc insn and is faster
! than an scc insn even if we have it. */
if ((code == NE || code == EQ)
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
&& integer_pow2p (TREE_OPERAND (arg0, 1)))
! {
! tree inner = TREE_OPERAND (arg0, 0);
! int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
! int ops_unsignedp;
!
! /* If INNER is a right shift of a constant and it plus BITNUM does
! not overflow, adjust BITNUM and INNER. */
!
! if (TREE_CODE (inner) == RSHIFT_EXPR
! && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
! && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
! && bitnum < TYPE_PRECISION (type)
! && 0 > compare_tree_int (TREE_OPERAND (inner, 1),
! bitnum - TYPE_PRECISION (type)))
! {
! bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
! inner = TREE_OPERAND (inner, 0);
! }
!
! /* If we are going to be able to omit the AND below, we must do our
! operations as unsigned. If we must use the AND, we have a choice.
! Normally unsigned is faster, but for some machines signed is. */
! ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1
! #ifdef LOAD_EXTEND_OP
! : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1)
! #else
! : 1
! #endif
! );
!
! if (! get_subtarget (subtarget)
! || GET_MODE (subtarget) != operand_mode
! || ! safe_from_p (subtarget, inner, 1))
! subtarget = 0;
!
! op0 = expand_expr (inner, subtarget, VOIDmode, 0);
!
! if (bitnum != 0)
! op0 = expand_shift (RSHIFT_EXPR, operand_mode, op0,
! size_int (bitnum), subtarget, ops_unsignedp);
!
! if (GET_MODE (op0) != mode)
! op0 = convert_to_mode (mode, op0, ops_unsignedp);
!
! if ((code == EQ && ! invert) || (code == NE && invert))
! op0 = expand_binop (mode, xor_optab, op0, const1_rtx, subtarget,
! ops_unsignedp, OPTAB_LIB_WIDEN);
!
! /* Put the AND last so it can combine with more things. */
! if (bitnum != TYPE_PRECISION (type) - 1)
! op0 = expand_and (mode, op0, const1_rtx, subtarget);
!
! return op0;
! }
/* Now see if we are likely to be able to do this. Return if not. */
if (! can_compare_p (code, operand_mode, ccp_store_flag))
--- 9990,10006 ----
do this by shifting the bit being tested to the low-order bit and
masking the result with the constant 1. If the condition was EQ,
we xor it with 1. This does not require an scc insn and is faster
! than an scc insn even if we have it.
!
! The code to make this transformation was moved into fold_single_bit_test,
! so we just call into the folder and expand its result. */
if ((code == NE || code == EQ)
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
&& integer_pow2p (TREE_OPERAND (arg0, 1)))
! return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
! arg0, arg1, type),
! target, VOIDmode, EXPAND_NORMAL);
/* Now see if we are likely to be able to do this. Return if not. */
if (! can_compare_p (code, operand_mode, ccp_store_flag))
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.272
diff -c -3 -p -r1.272 fold-const.c
*** fold-const.c 2 Jul 2003 07:41:07 -0000 1.272
--- fold-const.c 3 Jul 2003 05:38:08 -0000
*************** fold_inf_compare (enum tree_code code, t
*** 4797,4802 ****
--- 4797,4907 ----
return NULL_TREE;
}
+ /* If CODE with arguments ARG0 and ARG1 represents a single bit
+ equality/inequality test, then return a simplified form of
+ the test using shifts and logical operations. Otherwise return
+ NULL. TYPE is the desired result type. */
+
+ tree
+ fold_single_bit_test (code, arg0, arg1, result_type)
+ enum tree_code code;
+ tree arg0;
+ tree arg1;
+ tree result_type;
+ {
+ /* If this is a TRUTH_NOT_EXPR, it may have a single bit test inside
+ operand 0. */
+ if (code == TRUTH_NOT_EXPR)
+ {
+ code = TREE_CODE (arg0);
+ if (code != NE_EXPR && code != EQ_EXPR)
+ return NULL_TREE;
+
+ /* Extract the arguments of the EQ/NE. */
+ arg1 = TREE_OPERAND (arg0, 1);
+ arg0 = TREE_OPERAND (arg0, 0);
+
+ /* This requires us to invert the code. */
+ code = (code == EQ_EXPR ? NE_EXPR : EQ_EXPR);
+ }
+
+ /* If this is testing a single bit, we can optimize the test. */
+ if ((code == NE_EXPR || code == EQ_EXPR)
+ && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
+ && integer_pow2p (TREE_OPERAND (arg0, 1)))
+ {
+ tree inner = TREE_OPERAND (arg0, 0);
+ tree type = TREE_TYPE (arg0);
+ int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
+ enum machine_mode operand_mode = TYPE_MODE (type);
+ int ops_unsigned;
+ tree signed_type, unsigned_type;
+ tree arg00;
+
+ /* 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. */
+ 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)));
+ }
+
+ /* Otherwise we have (A & C) != 0 where C is a single bit,
+ convert that into ((A >> C2) & 1). Where C2 = log2(C).
+ Similarly for (A & C) == 0. */
+
+ /* If INNER is a right shift of a constant and it plus BITNUM does
+ not overflow, adjust BITNUM and INNER. */
+ if (TREE_CODE (inner) == RSHIFT_EXPR
+ && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
+ && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
+ && bitnum < TYPE_PRECISION (type)
+ && 0 > compare_tree_int (TREE_OPERAND (inner, 1),
+ bitnum - TYPE_PRECISION (type)))
+ {
+ bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
+ inner = TREE_OPERAND (inner, 0);
+ }
+
+ /* If we are going to be able to omit the AND below, we must do our
+ operations as unsigned. If we must use the AND, we have a choice.
+ Normally unsigned is faster, but for some machines signed is. */
+ ops_unsigned = (bitnum == TYPE_PRECISION (type) - 1 ? 1
+ #ifdef LOAD_EXTEND_OP
+ : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1)
+ #else
+ : 1
+ #endif
+ );
+
+ signed_type = (*lang_hooks.types.type_for_mode) (operand_mode, 0);
+ unsigned_type = (*lang_hooks.types.type_for_mode) (operand_mode, 1);
+
+ if (bitnum != 0)
+ inner = build (RSHIFT_EXPR, ops_unsigned ? unsigned_type : signed_type,
+ inner, size_int (bitnum));
+
+ if (code == EQ_EXPR)
+ inner = build (BIT_XOR_EXPR, ops_unsigned ? unsigned_type : signed_type,
+ inner, integer_one_node);
+
+ /* Put the AND last so it can combine with more things. */
+ if (bitnum != TYPE_PRECISION (type) - 1)
+ inner = build (BIT_AND_EXPR, ops_unsigned ? unsigned_type : signed_type,
+ inner, integer_one_node);
+
+ /* Make sure to return the proper type. */
+ if (TREE_TYPE (inner) != result_type)
+ inner = convert (result_type, inner);
+
+ return inner;
+ }
+ return NULL_TREE;
+ }
+
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
and application of the associative law.
*************** fold (tree expr)
*** 6320,6326 ****
tem = invert_truthvalue (arg0);
/* Avoid infinite recursion. */
if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
! return t;
return convert (type, tem);
case TRUTH_ANDIF_EXPR:
--- 6425,6436 ----
tem = invert_truthvalue (arg0);
/* Avoid infinite recursion. */
if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
! {
! tem = fold_single_bit_test (code, arg0, arg1, type);
! if (tem)
! return tem;
! return t;
! }
return convert (type, tem);
case TRUTH_ANDIF_EXPR:
*************** fold (tree expr)
*** 7012,7033 ****
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 !=. */
--- 7122,7132 ----
return fold (build (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
arg0, integer_zero_node));
! /* If we have (A & C) != 0 or (A & C) == 0 and C is a power of
! 2, then fold the expression into shifts and logical operations. */
! tem = fold_single_bit_test (code, arg0, arg1, type);
! if (tem)
! return tem;
/* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
and similarly for >= into !=. */
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.418
diff -c -3 -p -r1.418 tree.h
*** tree.h 1 Jul 2003 02:04:11 -0000 1.418
--- tree.h 3 Jul 2003 05:38:13 -0000
*************** extern void using_eh_for_cleanups PARAM
*** 2727,2732 ****
--- 2727,2734 ----
subexpressions are not changed. */
extern tree fold PARAMS ((tree));
+ extern tree fold_single_bit_test
+ PARAMS ((enum tree_code, tree, tree, tree));
extern int force_fit_type PARAMS ((tree, int));
extern int add_double PARAMS ((unsigned HOST_WIDE_INT, HOST_WIDE_INT,