re PR tree-optimization/33512 (Simple bitwise simplification missed)

2012-04-24  Andrew Pinski  <apinski@cavium.com>

	PR tree-opt/33512
	* tree-ssa-forwprop.c (defcodefor_name): New function.
	(simplify_bitwise_binary): Use defcodefor_name instead of manually
	Simplify "( X | Y) & X" to X and "( X & Y) | X" to X.
	Simplify "(~X | Y) & X" to "X & Y" and
	"(~X & Y) | X" to "X | Y".

2012-04-24  Andrew Pinski  <apinski@cavium.com>

	PR tree-opt/33512
	* gcc.dg/tree-ssa/andor-3.c: New testcase.
	* gcc.dg/tree-ssa/andor-4.c: New testcase.
	* gcc.dg/tree-ssa/andor-5.c: New testcase.

From-SVN: r186749
This commit is contained in:
Andrew Pinski 2012-04-24 07:05:09 +00:00 committed by Andrew Pinski
parent 57ac4c3401
commit a1e179f5b7
6 changed files with 246 additions and 29 deletions

View File

@ -1,3 +1,12 @@
2012-04-24 Andrew Pinski <apinski@cavium.com>
PR tree-opt/33512
* tree-ssa-forwprop.c (defcodefor_name): New function.
(simplify_bitwise_binary): Use defcodefor_name instead of manually
Simplify "( X | Y) & X" to X and "( X & Y) | X" to X.
Simplify "(~X | Y) & X" to "X & Y" and
"(~X & Y) | X" to "X | Y".
2012-04-24 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
* recog.c (insn_invalid_p): Add IN_GROUP parameter and use

View File

@ -1,3 +1,10 @@
2012-04-24 Andrew Pinski <apinski@cavium.com>
PR tree-opt/33512
* gcc.dg/tree-ssa/andor-3.c: New testcase.
* gcc.dg/tree-ssa/andor-4.c: New testcase.
* gcc.dg/tree-ssa/andor-5.c: New testcase.
2012-04-24 Jakub Jelinek <jakub@redhat.com>
PR middle-end/53084

View File

@ -0,0 +1,24 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
int f(int y, int x)
{
return x & ((~x) | y);
}
int f1(int y, int x)
{
return x & (y | (~x));
}
int f2(int y, int x)
{
return ((~x) | y) & x;
}
int f3(int y, int x)
{
return (y | (~x)) & x;
}
/* { dg-final { scan-tree-dump-times "~x" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "x_..D. \& y_..D." 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -0,0 +1,24 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
int f(int y, int x)
{
return x | ((~x) & y);
}
int f1(int y, int x)
{
return x | (y & (~x));
}
int f2(int y, int x)
{
return ((~x) & y) | x;
}
int f3(int y, int x)
{
return (y & (~x)) | x;
}
/* { dg-final { scan-tree-dump-times "~x" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "x_..D. \\\| y_..D." 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -0,0 +1,50 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
int f(int y, int x)
{
int a = x | y;
return a & x;
}
int f1(int y, int x)
{
int a = y | x;
return a & x;
}
int f2(int y, int x)
{
int a = x | y;
return x & a;
}
int f3(int y, int x)
{
int a = x | y;
return x & a;
}
int f4(int y, int x)
{
int a = x & y;
return a | x;
}
int f5(int y, int x)
{
int a = y & x;
return a | x;
}
int f6(int y, int x)
{
int a = x & y;
return x | a;
}
int f7(int y, int x)
{
int a = x & y;
return x | a;
}
/* These all should be optimized to just return x; */
/* { dg-final { scan-tree-dump-times "\\\|" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "\&" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "return x_..D.;" 8 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -1794,6 +1794,51 @@ simplify_bitwise_binary_1 (enum tree_code code, tree type,
return NULL_TREE;
}
/* Given a ssa_name in NAME see if it was defined by an assignment and
set CODE to be the code and ARG1 to the first operand on the rhs and ARG2
to the second operand on the rhs. */
static inline void
defcodefor_name (tree name, enum tree_code *code, tree *arg1, tree *arg2)
{
gimple def;
enum tree_code code1;
tree arg11;
tree arg21;
tree arg31;
enum gimple_rhs_class grhs_class;
code1 = TREE_CODE (name);
arg11 = name;
arg21 = NULL_TREE;
grhs_class = get_gimple_rhs_class (code1);
if (code1 == SSA_NAME)
{
def = SSA_NAME_DEF_STMT (name);
if (def && is_gimple_assign (def)
&& can_propagate_from (def))
{
code1 = gimple_assign_rhs_code (def);
arg11 = gimple_assign_rhs1 (def);
arg21 = gimple_assign_rhs2 (def);
arg31 = gimple_assign_rhs2 (def);
}
}
else if (grhs_class == GIMPLE_TERNARY_RHS
|| GIMPLE_BINARY_RHS
|| GIMPLE_UNARY_RHS
|| GIMPLE_SINGLE_RHS)
extract_ops_from_tree_1 (name, &code1, &arg11, &arg21, &arg31);
*code = code1;
*arg1 = arg11;
if (arg2)
*arg2 = arg21;
/* Ignore arg3 currently. */
}
/* Simplify bitwise binary operations.
Return true if a transformation applied, otherwise return false. */
@ -1805,33 +1850,11 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
tree arg2 = gimple_assign_rhs2 (stmt);
enum tree_code code = gimple_assign_rhs_code (stmt);
tree res;
gimple def1 = NULL, def2 = NULL;
tree def1_arg1, def2_arg1;
tree def1_arg1, def1_arg2, def2_arg1, def2_arg2;
enum tree_code def1_code, def2_code;
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);
}
}
defcodefor_name (arg1, &def1_code, &def1_arg1, &def1_arg2);
defcodefor_name (arg2, &def2_code, &def2_arg1, &def2_arg2);
/* Try to fold (type) X op CST -> (type) (X op ((type-x) CST)). */
if (TREE_CODE (arg2) == INTEGER_CST
@ -1938,10 +1961,10 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
if (code == BIT_AND_EXPR
&& def1_code == BIT_IOR_EXPR
&& TREE_CODE (arg2) == INTEGER_CST
&& TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST)
&& TREE_CODE (def1_arg2) == INTEGER_CST)
{
tree cst = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg2),
arg2, gimple_assign_rhs2 (def1));
arg2, def1_arg2);
tree tem;
gimple newop;
if (integer_zerop (cst))
@ -1971,10 +1994,10 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
|| code == BIT_XOR_EXPR)
&& def1_code == code
&& TREE_CODE (arg2) == INTEGER_CST
&& TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST)
&& TREE_CODE (def1_arg2) == INTEGER_CST)
{
tree cst = fold_build2 (code, TREE_TYPE (arg2),
arg2, gimple_assign_rhs2 (def1));
arg2, def1_arg2);
gimple_assign_set_rhs1 (stmt, def1_arg1);
gimple_assign_set_rhs2 (stmt, cst);
update_stmt (stmt);
@ -2001,6 +2024,86 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
return true;
}
if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
{
enum tree_code ocode = code == BIT_AND_EXPR ? BIT_IOR_EXPR : BIT_AND_EXPR;
if (def1_code == ocode)
{
tree x = arg2;
enum tree_code coden;
tree a1, a2;
/* ( X | Y) & X -> X */
/* ( X & Y) | X -> X */
if (x == def1_arg1
|| x == def1_arg2)
{
gimple_assign_set_rhs_from_tree (gsi, x);
update_stmt (gsi_stmt (*gsi));
return true;
}
defcodefor_name (def1_arg1, &coden, &a1, &a2);
/* (~X | Y) & X -> X & Y */
/* (~X & Y) | X -> X | Y */
if (coden == BIT_NOT_EXPR && a1 == x)
{
gimple_assign_set_rhs_with_ops (gsi, code,
x, def1_arg2);
gcc_assert (gsi_stmt (*gsi) == stmt);
update_stmt (stmt);
return true;
}
defcodefor_name (def1_arg2, &coden, &a1, &a2);
/* (Y | ~X) & X -> X & Y */
/* (Y & ~X) | X -> X | Y */
if (coden == BIT_NOT_EXPR && a1 == x)
{
gimple_assign_set_rhs_with_ops (gsi, code,
x, def1_arg1);
gcc_assert (gsi_stmt (*gsi) == stmt);
update_stmt (stmt);
return true;
}
}
if (def2_code == ocode)
{
enum tree_code coden;
tree a1;
tree x = arg1;
/* X & ( X | Y) -> X */
/* X | ( X & Y) -> X */
if (x == def2_arg1
|| x == def2_arg2)
{
gimple_assign_set_rhs_from_tree (gsi, x);
update_stmt (gsi_stmt (*gsi));
return true;
}
defcodefor_name (def2_arg1, &coden, &a1, NULL);
/* (~X | Y) & X -> X & Y */
/* (~X & Y) | X -> X | Y */
if (coden == BIT_NOT_EXPR && a1 == x)
{
gimple_assign_set_rhs_with_ops (gsi, code,
x, def2_arg2);
gcc_assert (gsi_stmt (*gsi) == stmt);
update_stmt (stmt);
return true;
}
defcodefor_name (def2_arg2, &coden, &a1, NULL);
/* (Y | ~X) & X -> X & Y */
/* (Y & ~X) | X -> X | Y */
if (coden == BIT_NOT_EXPR && a1 == x)
{
gimple_assign_set_rhs_with_ops (gsi, code,
x, def2_arg1);
gcc_assert (gsi_stmt (*gsi) == stmt);
update_stmt (stmt);
return true;
}
}
}
return false;
}