[patch] fold-const.c: Don't transform X & C into (X >> C') & 1 in fold_binary.
Kazu Hirata
kazu@cs.umass.edu
Wed Apr 20 21:27:00 GMT 2005
Hi,
Attached is a patch to teach fold_binary not to transform
X & C
into
(X >> C) & 1.
Note that fold_single_bit_test, a subroutine of fold_binary,
transforms
int a = ...;
if (a & 4)
into
a.0_2 = (unsigned int) a_1;
D.1236_3 = a.0_2 >> 2;
D.1237_4 = (int) D.1236_3;
D.1238_5 = D.1237_4 & 1;
if (D.1238_5 != 0) goto <L0>; else goto <L1>;
which is pretty long. The patch disables this transformation for
fold. In the above example, we would instead have
D.1235_2 = a_1 & 4;
if (D.1235_2 != 0) goto <L0>; else goto <L1>;
AFAICT, it does not matter whether we do this transformation or not as
far as conditional branches are concerned. Combine canonicalizes a
single bit test into zero_extract regardless of whether we have
a & 4
or
(a >> 2) & 1
Also the transformation does not matter for a store flag operation
because do_store_flag calls fold_single_bit_test to transform
var = (a & 4) != 0;
into
var = (a >> 2) & 1;
So all in all, the "SHIFT and AND" form seems to do nothing but take
up a lot of statements during tree optimizations.
The patch factors out a part of fold_single_bit_test that transforms
(x & SIGNBIT) != 0 into x < 0. With this patch, fold_binary calls the
new function fold_single_bit_test_into_sign_test instead of
fold_single_bit_test.
Roger agreed that it was a good idea to disable this transformation in
fold, but I would like to know what others think as well. Jeff?
Richard?
IIRC, do_jump contains code to reverse the effect of
fold_single_bit_test. If this patch is approved, I am planning to
adjust that code as a follow-up patch.
Tested on i686-pc-linux-gnu. OK to apply?
Kazu Hirata
2005-04-20 Kazu Hirata <kazu@cs.umass.edu>
* fold-const.c (fold_single_bit_test_into_sign_test): New,
split out from ...
(fold_single_bit_test): ... here.
(fold_binary): Call fold_single_bit_test_into_sign_test
instead of fold_single_bit_test.
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.565
diff -c -d -p -r1.565 fold-const.c
*** fold-const.c 20 Apr 2005 02:31:21 -0000 1.565
--- fold-const.c 20 Apr 2005 03:57:35 -0000
*************** fold_div_compare (enum tree_code code, t
*** 5929,5958 ****
/* 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 (enum tree_code code, tree arg0, tree arg1,
! tree result_type)
{
/* 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, intermediate_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
/* This is only a win if casting to a signed type is cheap,
i.e. when arg00's type is not a partial mode. */
--- 5929,5951 ----
/* If CODE with arguments ARG0 and ARG1 represents a single bit
! equality/inequality test, then return a simplified form of the test
! using a sign testing. Otherwise return NULL. TYPE is the desired
! result type. */
! static tree
! fold_single_bit_test_into_sign_test (enum tree_code code, tree arg0, tree arg1,
! tree result_type)
{
/* 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)))
{
/* 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. */
! tree arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
!
if (arg00 != NULL_TREE
/* This is only a win if casting to a signed type is cheap,
i.e. when arg00's type is not a partial mode. */
*************** fold_single_bit_test (enum tree_code cod
*** 5964,5969 ****
--- 5957,5995 ----
result_type, fold_convert (stype, arg00),
fold_convert (stype, integer_zero_node));
}
+ }
+
+ 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 (enum tree_code code, tree arg0, tree arg1,
+ tree result_type)
+ {
+ /* 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, intermediate_type;
+ tree tem;
+
+ /* First, see if we can fold the single bit test into a sign-bit
+ test. */
+ tem = fold_single_bit_test_into_sign_test (code, arg0, arg1,
+ result_type);
+ if (tem)
+ return tem;
/* Otherwise we have (A & C) != 0 where C is a single bit,
convert that into ((A >> C2) & 1). Where C2 = log2(C).
*************** fold_binary (enum tree_code code, tree t
*** 9433,9441 ****
arg0, fold_convert (TREE_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;
--- 9459,9467 ----
arg0, fold_convert (TREE_TYPE (arg0),
integer_zero_node));
! /* If we have (A & C) != 0 or (A & C) == 0 and C is the sign
! bit, then fold the expression into A < 0 or A >= 0. */
! tem = fold_single_bit_test_into_sign_test (code, arg0, arg1, type);
if (tem)
return tem;
More information about the Gcc-patches
mailing list