re PR tree-optimization/15256 ([tree-ssa] Optimize manual bitfield manipilation.)

2011-05-11  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/15256
	* tree-ssa-forwprop.c (simplify_bitwise_binary): Canonicalize
	(A & B) | C, combine (A op CST1) op CST2.
	(tree_ssa_forward_propagate_single_use_vars): Only bother to
	visit assigns that have uses.

	* gcc.dg/tree-ssa/forwprop-14.c: New testcase.

From-SVN: r173659
This commit is contained in:
Richard Guenther 2011-05-11 14:13:38 +00:00 committed by Richard Biener
parent 515456820e
commit 51e020fc08
4 changed files with 126 additions and 33 deletions

View File

@ -1,3 +1,11 @@
2011-05-11 Richard Guenther <rguenther@suse.de>
PR tree-optimization/15256
* tree-ssa-forwprop.c (simplify_bitwise_binary): Canonicalize
(A & B) | C, combine (A op CST1) op CST2.
(tree_ssa_forward_propagate_single_use_vars): Only bother to
visit assigns that have uses.
2011-05-11 Nathan Froyd <froydnj@codesourcery.com> 2011-05-11 Nathan Froyd <froydnj@codesourcery.com>
* ggc-page.c (extra_order_size_table): Use struct * ggc-page.c (extra_order_size_table): Use struct

View File

@ -1,3 +1,8 @@
2011-05-11 Richard Guenther <rguenther@suse.de>
PR tree-optimization/15256
* gcc.dg/tree-ssa/forwprop-14.c: New testcase.
2011-05-11 Jakub Jelinek <jakub@redhat.com> 2011-05-11 Jakub Jelinek <jakub@redhat.com>
PR debug/48159 PR debug/48159

View File

@ -0,0 +1,18 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-optimized" } */
unsigned int
foo (unsigned int eax)
{
eax |= 4;
eax &= 247;
eax |= 16;
eax &= 223;
eax |= 64;
eax &= 127;
return eax;
}
/* { dg-final { scan-tree-dump-times " & " 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times " \\\| " 1 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -1623,6 +1623,9 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
tree arg2 = gimple_assign_rhs2 (stmt); tree arg2 = gimple_assign_rhs2 (stmt);
enum tree_code code = gimple_assign_rhs_code (stmt); enum tree_code code = gimple_assign_rhs_code (stmt);
tree res; tree res;
gimple def1 = NULL, def2 = NULL;
tree def1_arg1, def2_arg1;
enum tree_code def1_code, def2_code;
/* If the first argument is an SSA name that is itself a result of a /* If the first argument is an SSA name that is itself a result of a
typecast of an ADDR_EXPR to an integer, feed the ADDR_EXPR to the typecast of an ADDR_EXPR to an integer, feed the ADDR_EXPR to the
@ -1655,44 +1658,102 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
} }
} }
def1_code = TREE_CODE (arg1);
def1_arg1 = arg1;
if (TREE_CODE (arg1) == SSA_NAME)
{
def1 = SSA_NAME_DEF_STMT (arg1);
if (is_gimple_assign (def1))
{
def1_code = gimple_assign_rhs_code (def1);
def1_arg1 = gimple_assign_rhs1 (def1);
}
}
def2_code = TREE_CODE (arg2);
def2_arg1 = arg2;
if (TREE_CODE (arg2) == SSA_NAME)
{
def2 = SSA_NAME_DEF_STMT (arg2);
if (is_gimple_assign (def2))
{
def2_code = gimple_assign_rhs_code (def2);
def2_arg1 = gimple_assign_rhs1 (def2);
}
}
/* For bitwise binary operations apply operand conversions to the /* For bitwise binary operations apply operand conversions to the
binary operation result instead of to the operands. This allows binary operation result instead of to the operands. This allows
to combine successive conversions and bitwise binary operations. */ to combine successive conversions and bitwise binary operations. */
if (TREE_CODE (arg1) == SSA_NAME if (CONVERT_EXPR_CODE_P (def1_code)
&& TREE_CODE (arg2) == SSA_NAME) && CONVERT_EXPR_CODE_P (def2_code)
&& types_compatible_p (TREE_TYPE (def1_arg1), TREE_TYPE (def2_arg1))
/* Make sure that the conversion widens the operands or that it
changes the operation to a bitfield precision. */
&& ((TYPE_PRECISION (TREE_TYPE (def1_arg1))
< TYPE_PRECISION (TREE_TYPE (arg1)))
|| (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1)))
!= MODE_INT)
|| (TYPE_PRECISION (TREE_TYPE (arg1))
!= GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg1))))))
{ {
gimple def_stmt1 = SSA_NAME_DEF_STMT (arg1); gimple newop;
gimple def_stmt2 = SSA_NAME_DEF_STMT (arg2); tree tem = create_tmp_reg (TREE_TYPE (def1_arg1),
if (is_gimple_assign (def_stmt1) NULL);
&& is_gimple_assign (def_stmt2) newop = gimple_build_assign_with_ops (code, tem, def1_arg1, def2_arg1);
&& CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt1)) tem = make_ssa_name (tem, newop);
&& CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt2))) gimple_assign_set_lhs (newop, tem);
gsi_insert_before (gsi, newop, GSI_SAME_STMT);
gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR,
tem, NULL_TREE, NULL_TREE);
update_stmt (gsi_stmt (*gsi));
return true;
}
/* (a | CST1) & CST2 -> (a & CST2) | (CST1 & CST2). */
if (code == BIT_AND_EXPR
&& def1_code == BIT_IOR_EXPR
&& TREE_CODE (arg2) == INTEGER_CST
&& TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST)
{
tree cst = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg2),
arg2, gimple_assign_rhs2 (def1));
tree tem;
gimple newop;
if (integer_zerop (cst))
{ {
tree darg1 = gimple_assign_rhs1 (def_stmt1); gimple_assign_set_rhs1 (stmt, def1_arg1);
tree darg2 = gimple_assign_rhs1 (def_stmt2); update_stmt (stmt);
/* Make sure that the conversion widens the operands or that it return true;
changes the operation to a bitfield precision. */
if (types_compatible_p (TREE_TYPE (darg1), TREE_TYPE (darg2))
&& ((TYPE_PRECISION (TREE_TYPE (darg1))
< TYPE_PRECISION (TREE_TYPE (arg1)))
|| (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1)))
!= MODE_INT)
|| (TYPE_PRECISION (TREE_TYPE (arg1))
!= GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg1))))))
{
gimple newop;
tree tem = create_tmp_reg (TREE_TYPE (darg1),
NULL);
newop = gimple_build_assign_with_ops (code, tem, darg1, darg2);
tem = make_ssa_name (tem, newop);
gimple_assign_set_lhs (newop, tem);
gsi_insert_before (gsi, newop, GSI_SAME_STMT);
gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR,
tem, NULL_TREE, NULL_TREE);
update_stmt (gsi_stmt (*gsi));
return true;
}
} }
tem = create_tmp_reg (TREE_TYPE (arg2), NULL);
newop = gimple_build_assign_with_ops (BIT_AND_EXPR,
tem, def1_arg1, arg2);
tem = make_ssa_name (tem, newop);
gimple_assign_set_lhs (newop, tem);
/* Make sure to re-process the new stmt as it's walking upwards. */
gsi_insert_before (gsi, newop, GSI_NEW_STMT);
gimple_assign_set_rhs1 (stmt, tem);
gimple_assign_set_rhs2 (stmt, cst);
gimple_assign_set_rhs_code (stmt, BIT_IOR_EXPR);
update_stmt (stmt);
return true;
}
/* Combine successive equal operations with constants. */
if ((code == BIT_AND_EXPR
|| code == BIT_IOR_EXPR
|| code == BIT_XOR_EXPR)
&& def1_code == code
&& TREE_CODE (arg2) == INTEGER_CST
&& TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST)
{
tree cst = fold_build2 (code, TREE_TYPE (arg2),
arg2, gimple_assign_rhs2 (def1));
gimple_assign_set_rhs1 (stmt, def1_arg1);
gimple_assign_set_rhs2 (stmt, cst);
update_stmt (stmt);
return true;
} }
return false; return false;
@ -2171,7 +2232,8 @@ tree_ssa_forward_propagate_single_use_vars (void)
tree rhs = gimple_assign_rhs1 (stmt); tree rhs = gimple_assign_rhs1 (stmt);
enum tree_code code = gimple_assign_rhs_code (stmt); enum tree_code code = gimple_assign_rhs_code (stmt);
if (TREE_CODE (lhs) != SSA_NAME) if (TREE_CODE (lhs) != SSA_NAME
|| has_zero_uses (lhs))
{ {
gsi_next (&gsi); gsi_next (&gsi);
continue; continue;