Hello,
This patch improves via type-sinking folding of binary and, or, and
xor operations.
First we do sinking also for compatible types with same precision, as
those don't need to be preserved for these operations.
Additional try to fold patterns (TYPE) X bin-op (Y CMP Z) and (TYPE) X
bin-op !Y, if type of X is
compatible to Y.
ChangeLog gcc
2011-06-22 Kai Tietz <[email protected]>
* tree-ssa-forwprop.c (simplify_bitwise_binary):
Improve binary folding regarding casts.
ChangeLog gcc/testsuite
2011-06-22 Kai Tietz <[email protected]>
* gcc.dg/binop-notand1a.c: New test.
* gcc.dg/binop-notand2a.c: New test.
* gcc.dg/binop-notand3a.c: New test.
* gcc.dg/binop-notand4a.c: New test.
* gcc.dg/binop-notand5a.c: New test.
* gcc.dg/binop-notand6a.c: New test.
Bootstrapped and regression tested for all standard languages, Ada,
and Obj-C++. Ok for apply?
Regards,
Kai
Index: gcc/gcc/tree-ssa-forwprop.c
===================================================================
--- gcc.orig/gcc/tree-ssa-forwprop.c 2011-06-17 11:52:51.000000000 +0200
+++ gcc/gcc/tree-ssa-forwprop.c 2011-06-22 12:36:49.432774100 +0200
@@ -1682,10 +1682,11 @@ simplify_bitwise_binary (gimple_stmt_ite
if (CONVERT_EXPR_CODE_P (def1_code)
&& 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. */
+ /* Make sure that the conversion widens the operands, or has same
+ precision, or that it changes the operation to a bitfield
+ precision. */
&& ((TYPE_PRECISION (TREE_TYPE (def1_arg1))
- < TYPE_PRECISION (TREE_TYPE (arg1)))
+ <= TYPE_PRECISION (TREE_TYPE (arg1)))
|| (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1)))
!= MODE_INT)
|| (TYPE_PRECISION (TREE_TYPE (arg1))
@@ -1704,6 +1705,88 @@ simplify_bitwise_binary (gimple_stmt_ite
return true;
}
+ /* Try to fold (TYPE) X op (Y CMP Z), or (TYPE) X op !Y, if type
+ of X is compatible to type of Y. */
+ if (CONVERT_EXPR_CODE_P (def1_code)
+ && (TREE_CODE_CLASS (def2_code) == tcc_comparison
+ || def2_code == TRUTH_NOT_EXPR)
+ && types_compatible_p (TREE_TYPE (def1_arg1), TREE_TYPE (def2_arg1)))
+ {
+ tree t;
+ if (def2_code == TRUTH_NOT_EXPR)
+ t = fold_build1_loc (gimple_location (def2), def2_code,
+ TREE_TYPE (def1_arg1), def2_arg1);
+ else
+ t = fold_build2_loc (gimple_location (def2), def2_code,
+ TREE_TYPE (def1_arg1), def2_arg1,
+ gimple_assign_rhs2 (def2));
+ t = fold_binary_loc (gimple_location (stmt), code,
+ TREE_TYPE (def1_arg1), def1_arg1, t);
+ if (t && TREE_CODE (t) == INTEGER_CST)
+ {
+ t = fold_convert (TREE_TYPE (arg1), t);
+ gimple_assign_set_rhs_from_tree (gsi, t);
+ update_stmt (gsi_stmt (*gsi));
+ return true;
+ }
+ else if (t && TREE_CODE_CLASS (TREE_CODE (t)) == tcc_comparison)
+ {
+ gimple newop;
+ tree tem = create_tmp_reg (boolean_type_node, NULL);
+ newop = gimple_build_assign_with_ops (TREE_CODE (t), tem,
+ TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1));
+ 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;
+ }
+ }
+
+ /* Try to fold (Y CMP Z) op (TYPE) X, or !Y op (TYPE) X, if type
+ of X is compatible to type of Y. */
+ if (CONVERT_EXPR_CODE_P (def2_code)
+ && (TREE_CODE_CLASS (def1_code) == tcc_comparison
+ || def1_code == TRUTH_NOT_EXPR)
+ && types_compatible_p (TREE_TYPE (def2_arg1), TREE_TYPE (def1_arg1)))
+ {
+ tree t;
+ if (def1_code == TRUTH_NOT_EXPR)
+ t = fold_build1_loc (gimple_location (def1), def1_code,
+ TREE_TYPE (def2_arg1), def1_arg1);
+ else
+ t = fold_build2_loc (gimple_location (def1), def1_code,
+ TREE_TYPE (def2_arg1), def1_arg1,
+ gimple_assign_rhs2 (def1));
+ t = fold_binary_loc (gimple_location (stmt), code,
+ TREE_TYPE (def2_arg1), t, def2_arg1);
+ if (t && TREE_CODE (t) == INTEGER_CST)
+ {
+ t = fold_convert (TREE_TYPE (arg2), t);
+ gimple_assign_set_rhs_from_tree (gsi, t);
+ update_stmt (gsi_stmt (*gsi));
+ return true;
+ }
+ else if (t && TREE_CODE_CLASS (TREE_CODE (t)) == tcc_comparison)
+ {
+ gimple newop;
+ tree tem = create_tmp_reg (boolean_type_node, NULL);
+ newop = gimple_build_assign_with_ops (TREE_CODE (t), tem,
+ TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1));
+ 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;
+ }
+ }
+
/* (a | CST1) & CST2 -> (a & CST2) | (CST1 & CST2). */
if (code == BIT_AND_EXPR
&& def1_code == BIT_IOR_EXPR
Index: gcc/gcc/testsuite/gcc.dg/binop-notand1a.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-notand1a.c 2011-06-22 11:03:03.735901300
+0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (char a, unsigned short b)
+{
+ return (a & !a) | (b & !b);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-notand2a.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-notand2a.c 2011-06-22 11:05:43.629705200
+0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a)
+{
+ return (!a & 1) != (a == 0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-notand3a.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-notand3a.c 2011-06-22 11:09:05.107289600
+0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (short a)
+{
+ return (!a & 1) != ((a == 0) & 1);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-notand4a.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-notand4a.c 2011-06-22 11:09:43.515666900
+0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (unsigned char a, _Bool b)
+{
+ return (!a & a) | (b & !b);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-notand5a.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-notand5a.c 2011-06-22 11:10:11.556727600
+0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (long a, unsigned long b)
+{
+ return (a & (a == 0)) | (b & !b);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-notand6a.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-notand6a.c 2011-06-22 11:10:30.816673300
+0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (unsigned long a, long b)
+{
+ return (a & !a) | (b & (b == 0));
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */