public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Constant-fold vector comparisons
@ 2012-09-29 15:16 Marc Glisse
  2012-10-01 11:40 ` Richard Guenther
  2012-10-12 14:10 ` Constant-fold vector comparisons Marc Glisse
  0 siblings, 2 replies; 20+ messages in thread
From: Marc Glisse @ 2012-09-29 15:16 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1479 bytes --]

Hello,

this patch does 2 things (I should have split it in 2, but the questions 
go together):

1) it handles constant folding of vector comparisons,

2) it fixes another place where vectors are not expected (I'll probably 
wait to have front-end support and testcases to do more of those, but 
there is something to discuss).

I wasn't sure what integer_truep should test exactly. For integer: == 1 or 
!= 0? For vectors: == -1 or < 0? I chose the one that worked best for the 
forwprop case where I used it.

It seems that before this patch, the middle-end didn't know how comparison 
results were encoded (a good reason for VEC_COND_EXPR to require a 
comparison as its first argument). I am using the OpenCL encoding that 
what matters is the high bit of each vector element. I am not quite sure 
what happens for targets (are there any?) that use a different encoding. 
When expanding vcond, they can do the comparison as they like. When 
expanding an isolated comparison, I expect they have to expand it as 
vcond(a<b,-1,0). So it should be ok, but I could easily have missed 
something.


2012-10-01  Marc Glisse  <marc.glisse@inria.fr>

gcc/
 	* tree.c (integer_truep): New function.
 	* tree.h (integer_truep): Declare.
 	* tree-ssa-forwprop.c (forward_propagate_into_cond): Call it.
 	Don't use boolean_type_node for vectors.
 	* fold-const.c (fold_relational_const): Handle VECTOR_CST.

gcc/testsuite/
 	* gcc.dg/tree-ssa/foldconst-6.c: New testcase.

-- 
Marc Glisse

[-- Attachment #2: Type: TEXT/PLAIN, Size: 6700 bytes --]

Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 191850)
+++ gcc/tree.h	(working copy)
@@ -5272,20 +5272,25 @@ extern int integer_zerop (const_tree);
 
 /* integer_onep (tree x) is nonzero if X is an integer constant of value 1.  */
 
 extern int integer_onep (const_tree);
 
 /* integer_all_onesp (tree x) is nonzero if X is an integer constant
    all of whose significant bits are 1.  */
 
 extern int integer_all_onesp (const_tree);
 
+/* integer_truep (tree x) is nonzero if X is an integer constant of value 1,
+   or a vector constant of value < 0.  */
+
+extern bool integer_truep (const_tree);
+
 /* integer_pow2p (tree x) is nonzero is X is an integer constant with
    exactly one bit 1.  */
 
 extern int integer_pow2p (const_tree);
 
 /* integer_nonzerop (tree x) is nonzero if X is an integer constant
    with a nonzero value.  */
 
 extern int integer_nonzerop (const_tree);
 
Index: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c	(revision 191850)
+++ gcc/tree-ssa-forwprop.c	(working copy)
@@ -564,46 +564,46 @@ forward_propagate_into_cond (gimple_stmt
       enum tree_code code;
       tree name = cond;
       gimple def_stmt = get_prop_source_stmt (name, true, NULL);
       if (!def_stmt || !can_propagate_from (def_stmt))
 	return 0;
 
       code = gimple_assign_rhs_code (def_stmt);
       if (TREE_CODE_CLASS (code) == tcc_comparison)
 	tmp = fold_build2_loc (gimple_location (def_stmt),
 			       code,
-			       boolean_type_node,
+			       TREE_TYPE (cond),
 			       gimple_assign_rhs1 (def_stmt),
 			       gimple_assign_rhs2 (def_stmt));
       else if ((code == BIT_NOT_EXPR
 		&& TYPE_PRECISION (TREE_TYPE (cond)) == 1)
 	       || (code == BIT_XOR_EXPR
-		   && integer_onep (gimple_assign_rhs2 (def_stmt))))
+		   && integer_truep (gimple_assign_rhs2 (def_stmt))))
 	{
 	  tmp = gimple_assign_rhs1 (def_stmt);
 	  swap = true;
 	}
     }
 
   if (tmp
       && is_gimple_condexpr (tmp))
     {
       if (dump_file && tmp)
 	{
 	  fprintf (dump_file, "  Replaced '");
 	  print_generic_expr (dump_file, cond, 0);
 	  fprintf (dump_file, "' with '");
 	  print_generic_expr (dump_file, tmp, 0);
 	  fprintf (dump_file, "'\n");
 	}
 
-      if (integer_onep (tmp))
+      if (integer_truep (tmp))
 	gimple_assign_set_rhs_from_tree (gsi_p, gimple_assign_rhs2 (stmt));
       else if (integer_zerop (tmp))
 	gimple_assign_set_rhs_from_tree (gsi_p, gimple_assign_rhs3 (stmt));
       else
 	{
 	  gimple_assign_set_rhs1 (stmt, unshare_expr (tmp));
 	  if (swap)
 	    {
 	      tree t = gimple_assign_rhs2 (stmt);
 	      gimple_assign_set_rhs2 (stmt, gimple_assign_rhs3 (stmt));
Index: gcc/testsuite/gcc.dg/tree-ssa/foldconst-6.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/foldconst-6.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/foldconst-6.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1" } */
+
+typedef long vec __attribute__ ((vector_size (2 * sizeof(long))));
+
+vec f ()
+{
+  vec a = { -2, 666 };
+  vec b = { 3, 2 };
+  return a < b;
+}
+
+/* { dg-final { scan-tree-dump-not "666" "ccp1"} } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */

Property changes on: gcc/testsuite/gcc.dg/tree-ssa/foldconst-6.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision URL
Added: svn:eol-style
   + native

Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 191850)
+++ gcc/fold-const.c	(working copy)
@@ -16084,20 +16084,44 @@ fold_relational_const (enum tree_code co
 					  TREE_IMAGPART (op0),
 					  TREE_IMAGPART (op1));
       if (code == EQ_EXPR)
 	return fold_build2 (TRUTH_ANDIF_EXPR, type, rcond, icond);
       else if (code == NE_EXPR)
 	return fold_build2 (TRUTH_ORIF_EXPR, type, rcond, icond);
       else
 	return NULL_TREE;
     }
 
+  if (TREE_CODE (op0) == VECTOR_CST && TREE_CODE (op1) == VECTOR_CST)
+    {
+      int count = VECTOR_CST_NELTS (op0);
+      tree *elts =  XALLOCAVEC (tree, count);
+      gcc_assert (TREE_CODE (type) == VECTOR_TYPE);
+
+      for (int i = 0; i < count; i++)
+	{
+	  tree elem_type = TREE_TYPE (type);
+	  tree elem0 = VECTOR_CST_ELT (op0, i);
+	  tree elem1 = VECTOR_CST_ELT (op1, i);
+
+	  elts[i] = fold_relational_const (code, elem_type,
+					   elem0, elem1);
+
+	  if(elts[i] == NULL_TREE)
+	    return NULL_TREE;
+
+	  elts[i] = fold_negate_const (elts[i], elem_type);
+	}
+
+      return build_vector (type, elts);
+    }
+
   /* From here on we only handle LT, LE, GT, GE, EQ and NE.
 
      To compute GT, swap the arguments and do LT.
      To compute GE, do LT and invert the result.
      To compute LE, swap the arguments, do LT and invert the result.
      To compute NE, do EQ and invert the result.
 
      Therefore, the code below must handle only EQ and LT.  */
 
   if (code == LE_EXPR || code == GT_EXPR)
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 191850)
+++ gcc/tree.c	(working copy)
@@ -1835,20 +1835,48 @@ integer_all_onesp (const_tree expr)
       else
 	high_value = ((HOST_WIDE_INT) 1 << shift_amount) - 1;
 
       return (TREE_INT_CST_LOW (expr) == ~(unsigned HOST_WIDE_INT) 0
 	      && TREE_INT_CST_HIGH (expr) == high_value);
     }
   else
     return TREE_INT_CST_LOW (expr) == ((unsigned HOST_WIDE_INT) 1 << prec) - 1;
 }
 
+/* Return true if EXPR is an integer constant representing true.  */
+
+bool
+integer_truep (const_tree expr)
+{
+  STRIP_NOPS (expr);
+
+  switch (TREE_CODE (expr))
+    {
+    case INTEGER_CST:
+      /* Do not just test != 0, some places expect the value 1.  */
+      return (TREE_INT_CST_LOW (expr) == 1
+	      && TREE_INT_CST_HIGH (expr) == 0);
+    case VECTOR_CST:
+      {
+	for (unsigned i = 0; i < VECTOR_CST_NELTS (expr); ++i)
+	  {
+	    tree elm = VECTOR_CST_ELT (expr, i);
+	    if (TREE_CODE (elm) != INTEGER_CST || !tree_int_cst_sign_bit (elm))
+	      return false;
+	  }
+	return true;
+      }
+    default:
+      return false;
+    }
+}
+
 /* Return 1 if EXPR is an integer constant that is a power of 2 (i.e., has only
    one bit on).  */
 
 int
 integer_pow2p (const_tree expr)
 {
   int prec;
   unsigned HOST_WIDE_INT high, low;
 
   STRIP_NOPS (expr);

^ permalink raw reply	[flat|nested] 20+ messages in thread
* vec_cond_expr adjustments
@ 2012-09-27 22:57 Marc Glisse
  2012-09-28 10:11 ` Richard Guenther
  0 siblings, 1 reply; 20+ messages in thread
From: Marc Glisse @ 2012-09-27 22:57 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1356 bytes --]

Hello,

I have been experimenting with generating VEC_COND_EXPR from the 
front-end, and these are just a couple things I noticed.

1) optabs.c requires that the first argument of vec_cond_expr be a 
comparison, but verify_gimple_assign_ternary only checks 
is_gimple_condexpr, like for COND_EXPR. In the long term, it seems better 
to also allow ssa_name and vector_cst (thus match the is_gimple_condexpr 
condition), but for now I just want to know early if I created an invalid 
vec_cond_expr.

2) a little refactoring of the code to find a suitable vector type for 
comparison results, and one more place where it should be used (no 
testcase yet because I don't know if that path can be taken without 
front-end changes first). I did wonder, for tree-ssa-forwprop, about using 
directly TREE_TYPE (cond) without truth_type_for.

Hmm, now I am wondering whether I should have waited until I had front-end 
vec_cond_expr support to submit everything at once...

2012-09-27  Marc Glisse  <marc.glisse@inria.fr>

 	* tree-cfg.c (verify_gimple_assign_ternary): Stricter check on
 	first argument of VEC_COND_EXPR.
 	* tree.c (truth_type_for): New function.
 	* tree.h (truth_type_for): Declare.
 	* gimple-fold.c (and_comparisons_1): Call it.
 	(or_comparisons_1): Likewise.
 	* tree-ssa-forwprop.c (forward_propagate_into_cond): Likewise.

-- 
Marc Glisse

[-- Attachment #2: Type: TEXT/PLAIN, Size: 8176 bytes --]

Index: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c	(revision 191810)
+++ gcc/tree-ssa-forwprop.c	(working copy)
@@ -549,21 +549,22 @@ static bool
 forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
 {
   gimple stmt = gsi_stmt (*gsi_p);
   tree tmp = NULL_TREE;
   tree cond = gimple_assign_rhs1 (stmt);
   bool swap = false;
 
   /* We can do tree combining on SSA_NAME and comparison expressions.  */
   if (COMPARISON_CLASS_P (cond))
     tmp = forward_propagate_into_comparison_1 (stmt, TREE_CODE (cond),
-					       boolean_type_node,
+					       truth_type_for
+						 (TREE_TYPE (cond)),
 					       TREE_OPERAND (cond, 0),
 					       TREE_OPERAND (cond, 1));
   else if (TREE_CODE (cond) == SSA_NAME)
     {
       enum tree_code code;
       tree name = cond;
       gimple def_stmt = get_prop_source_stmt (name, true, NULL);
       if (!def_stmt || !can_propagate_from (def_stmt))
 	return 0;
 
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c	(revision 191810)
+++ gcc/tree-cfg.c	(working copy)
@@ -3758,22 +3758,24 @@ verify_gimple_assign_ternary (gimple stm
   tree rhs2_type = TREE_TYPE (rhs2);
   tree rhs3 = gimple_assign_rhs3 (stmt);
   tree rhs3_type = TREE_TYPE (rhs3);
 
   if (!is_gimple_reg (lhs))
     {
       error ("non-register as LHS of ternary operation");
       return true;
     }
 
-  if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR)
-       ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1))
+  if (((rhs_code == COND_EXPR) ? !is_gimple_condexpr (rhs1)
+       : (rhs_code == VEC_COND_EXPR) ? (!is_gimple_condexpr (rhs1)
+					|| is_gimple_val (rhs1))
+       : !is_gimple_val (rhs1))
       || !is_gimple_val (rhs2)
       || !is_gimple_val (rhs3))
     {
       error ("invalid operands in ternary operation");
       return true;
     }
 
   /* First handle operations that involve different types.  */
   switch (rhs_code)
     {
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 191810)
+++ gcc/gimple-fold.c	(working copy)
@@ -23,21 +23,20 @@ along with GCC; see the file COPYING3.
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
 #include "flags.h"
 #include "function.h"
 #include "dumpfile.h"
 #include "tree-flow.h"
 #include "tree-ssa-propagate.h"
 #include "target.h"
 #include "gimple-fold.h"
-#include "langhooks.h"
 
 /* Return true when DECL can be referenced from current unit.
    FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
    We can get declarations that are not possible to reference for various
    reasons:
 
      1) When analyzing C++ virtual tables.
 	C++ virtual tables do have known constructors even
 	when they are keyed to other compilation unit.
 	Those tables can contain pointers to methods and vars
@@ -1686,29 +1685,21 @@ and_var_with_comparison_1 (gimple stmt,
    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
    If this can be done without constructing an intermediate value,
    return the resulting tree; otherwise NULL_TREE is returned.
    This function is deliberately asymmetric as it recurses on SSA_DEFs
    in the first comparison but not the second.  */
 
 static tree
 and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree truth_type = boolean_type_node;
-  if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
-    {
-      tree vec_type = TREE_TYPE (op1a);
-      tree elem = lang_hooks.types.type_for_size
-	(GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
-      truth_type = build_opaque_vector_type (elem,
-					     TYPE_VECTOR_SUBPARTS (vec_type));
-    }
+  tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
   /* First check for ((x CODE1 y) AND (x CODE2 y)).  */
   if (operand_equal_p (op1a, op2a, 0)
       && operand_equal_p (op1b, op2b, 0))
     {
       /* Result will be either NULL_TREE, or a combined comparison.  */
       tree t = combine_comparisons (UNKNOWN_LOCATION,
 				    TRUTH_ANDIF_EXPR, code1, code2,
 				    truth_type, op1a, op1b);
       if (t)
@@ -2158,29 +2149,21 @@ or_var_with_comparison_1 (gimple stmt,
    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
    If this can be done without constructing an intermediate value,
    return the resulting tree; otherwise NULL_TREE is returned.
    This function is deliberately asymmetric as it recurses on SSA_DEFs
    in the first comparison but not the second.  */
 
 static tree
 or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b)
 {
-  tree truth_type = boolean_type_node;
-  if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
-    {
-      tree vec_type = TREE_TYPE (op1a);
-      tree elem = lang_hooks.types.type_for_size
-	(GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
-      truth_type = build_opaque_vector_type (elem,
-					     TYPE_VECTOR_SUBPARTS (vec_type));
-    }
+  tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
   /* First check for ((x CODE1 y) OR (x CODE2 y)).  */
   if (operand_equal_p (op1a, op2a, 0)
       && operand_equal_p (op1b, op2b, 0))
     {
       /* Result will be either NULL_TREE, or a combined comparison.  */
       tree t = combine_comparisons (UNKNOWN_LOCATION,
 				    TRUTH_ORIF_EXPR, code1, code2,
 				    truth_type, op1a, op1b);
       if (t)
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 191810)
+++ gcc/tree.c	(working copy)
@@ -10243,20 +10243,36 @@ unsigned_type_for (tree type)
 /* If TYPE is an integral or pointer type, return an integer type with
    the same precision which is signed, or itself if TYPE is already a
    signed integer type.  */
 
 tree
 signed_type_for (tree type)
 {
   return signed_or_unsigned_type_for (0, type);
 }
 
+/* If TYPE is a vector type, return a signed integer vector type with the
+   same width and number of subparts. Otherwise return boolean_type_node.  */
+
+tree
+truth_type_for (tree type)
+{
+  if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      tree elem = lang_hooks.types.type_for_size
+        (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (type))), 0);
+      return build_opaque_vector_type (elem, TYPE_VECTOR_SUBPARTS (type));
+    }
+  else
+    return boolean_type_node;
+}
+
 /* Returns the largest value obtainable by casting something in INNER type to
    OUTER type.  */
 
 tree
 upper_bound_in_type (tree outer, tree inner)
 {
   double_int high;
   unsigned int det = 0;
   unsigned oprec = TYPE_PRECISION (outer);
   unsigned iprec = TYPE_PRECISION (inner);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 191810)
+++ gcc/tree.h	(working copy)
@@ -4762,20 +4762,21 @@ extern tree build_call_valist (tree, tre
 extern tree build_call_array_loc (location_t, tree, tree, int, const tree *);
 extern tree build_call_vec (tree, tree, VEC(tree,gc) *);
 
 /* Construct various nodes representing data types.  */
 
 extern tree make_signed_type (int);
 extern tree make_unsigned_type (int);
 extern tree signed_or_unsigned_type_for (int, tree);
 extern tree signed_type_for (tree);
 extern tree unsigned_type_for (tree);
+extern tree truth_type_for (tree);
 extern void initialize_sizetypes (void);
 extern void fixup_unsigned_type (tree);
 extern tree build_pointer_type_for_mode (tree, enum machine_mode, bool);
 extern tree build_pointer_type (tree);
 extern tree build_reference_type_for_mode (tree, enum machine_mode, bool);
 extern tree build_reference_type (tree);
 extern tree build_vector_type_for_mode (tree, enum machine_mode);
 extern tree build_vector_type (tree innertype, int nunits);
 extern tree build_opaque_vector_type (tree innertype, int nunits);
 extern tree build_type_no_quals (tree);

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2012-10-23  9:55 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-29 15:16 Constant-fold vector comparisons Marc Glisse
2012-10-01 11:40 ` Richard Guenther
2012-10-01 15:58   ` vec_cond_expr adjustments Marc Glisse
2012-10-02 12:41     ` Richard Guenther
2012-10-05 15:01       ` Marc Glisse
2012-10-08  9:04         ` Richard Guenther
2012-10-08  9:34           ` Marc Glisse
2012-10-08  9:44             ` Richard Guenther
2012-10-10 23:37               ` Marc Glisse
2012-10-11 12:58                 ` Richard Biener
2012-10-12 14:10 ` Constant-fold vector comparisons Marc Glisse
2012-10-15 10:34   ` Richard Biener
2012-10-15 14:19     ` Marc Glisse
2012-10-16 11:38       ` Richard Biener
2012-10-22 20:33         ` Marc Glisse
2012-10-23 10:05           ` Richard Biener
  -- strict thread matches above, loose matches on Subject: below --
2012-09-27 22:57 vec_cond_expr adjustments Marc Glisse
2012-09-28 10:11 ` Richard Guenther
2012-09-28 17:22   ` Marc Glisse
2012-10-01  9:30     ` Richard Guenther

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).