diff mbox

Fix 416.gamess miscompare (PR71311)

Message ID alpine.LSU.2.11.1605311446000.1493@t29.fhfr.qr
State New
Headers show

Commit Message

Richard Biener May 31, 2016, 12:48 p.m. UTC
The following patch adds missing patterns with swapped comparison
operands for the @0 < @1 and @0 < @2 to @0 < min (@1, @2) transform.
This nullifies the difference gimplify-into-SSA made on
rhfuhf.F:ROFOCK which causes the function no longer to be miscompiled
(by vectorization eventually, -fno-tree-vectorize also fixes the
miscompare at r235817).

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

I didn't attempt to understand the miscompile or create an executable
testcase.

Richard.

2016-05-31  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/71311
	* match.pd (@0 < @1 and @0 < @2 to @0 < min (@1, @2)): Add
	cases with swapped comparison operands.

Comments

Richard Biener May 31, 2016, 1:55 p.m. UTC | #1
On Tue, 31 May 2016, Richard Biener wrote:

> 
> The following patch adds missing patterns with swapped comparison
> operands for the @0 < @1 and @0 < @2 to @0 < min (@1, @2) transform.
> This nullifies the difference gimplify-into-SSA made on
> rhfuhf.F:ROFOCK which causes the function no longer to be miscompiled
> (by vectorization eventually, -fno-tree-vectorize also fixes the
> miscompare at r235817).

The following is a variant, avoiding the pattern repetition in match.pd
by (finally) completing a local patch I had to support "commutating"
relational operators.  It also adds sanity-checking for what you apply
:c to which catches a few cases in match.pd I introduce :C for in this
patch.

Bootstrap / regtest in progress on x86_64-unknown-linux-gnu.

Richard.

2016-05-31  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/71311
	* genmatch.c (comparison_code_p): New predicate.
	(swap_tree_comparison): New function.
	(commutate): Add for_vec parameter to append new for entries.
	Support commutating relational operators by swapping it alongside
	operands.
	(lower_commutative): Adjust.
	(dt_simplify::gen): Do not pass artificial operators to gen
	functions.
	(decision_tree::gen): Do not add artificial operators as parameters.
	(parser::parse_expr): Verify operator commutativity when :c is
	applied.  Allow :C to override this.
	* match.pd: Adjust patterns to use :C instead of :c where required.
	Add :c to @0 < @1 && @0 < @2 -> @0 < min(@1,@2) transform.

Index: gcc/genmatch.c
===================================================================
*** gcc/genmatch.c	(revision 236877)
--- gcc/genmatch.c	(working copy)
*************** commutative_ternary_tree_code (enum tree
*** 291,296 ****
--- 291,325 ----
    return false;
  }
  
+ /* Return true if CODE is a comparison.  */
+ 
+ bool
+ comparison_code_p (enum tree_code code)
+ {
+   switch (code)
+     {
+     case EQ_EXPR:
+     case NE_EXPR:
+     case ORDERED_EXPR:
+     case UNORDERED_EXPR:
+     case LTGT_EXPR:
+     case UNEQ_EXPR:
+     case GT_EXPR:
+     case GE_EXPR:
+     case LT_EXPR:
+     case LE_EXPR:
+     case UNGT_EXPR:
+     case UNGE_EXPR:
+     case UNLT_EXPR:
+     case UNLE_EXPR:
+       return true;
+ 
+     default:
+       break;
+     }
+   return false;
+ }
+ 
  
  /* Base class for all identifiers the parser knows.  */
  
*************** get_operator (const char *id, bool allow
*** 528,533 ****
--- 557,598 ----
    return operators->find_with_hash (&tem, tem.hashval);
  }
  
+ /* Return the comparison operators that results if the operands are
+    swapped.  This is safe for floating-point.  */
+ 
+ id_base *
+ swap_tree_comparison (operator_id *p)
+ {
+   switch (p->code)
+     {
+     case EQ_EXPR:
+     case NE_EXPR:
+     case ORDERED_EXPR:
+     case UNORDERED_EXPR:
+     case LTGT_EXPR:
+     case UNEQ_EXPR:
+       return p;
+     case GT_EXPR:
+       return get_operator ("LT_EXPR");
+     case GE_EXPR:
+       return get_operator ("LE_EXPR");
+     case LT_EXPR:
+       return get_operator ("GT_EXPR");
+     case LE_EXPR:
+       return get_operator ("GE_EXPR");
+     case UNGT_EXPR:
+       return get_operator ("UNLT_EXPR");
+     case UNGE_EXPR:
+       return get_operator ("UNLE_EXPR");
+     case UNLT_EXPR:
+       return get_operator ("UNGT_EXPR");
+     case UNLE_EXPR:
+       return get_operator ("UNGE_EXPR");
+     default:
+       gcc_unreachable ();
+     }
+ }
+ 
  typedef hash_map<nofree_string_hash, unsigned> cid_map_t;
  
  
*************** cartesian_product (const vec< vec<operan
*** 816,822 ****
  /* Lower OP to two operands in case it is marked as commutative.  */
  
  static vec<operand *>
! commutate (operand *op)
  {
    vec<operand *> ret = vNULL;
  
--- 881,887 ----
  /* Lower OP to two operands in case it is marked as commutative.  */
  
  static vec<operand *>
! commutate (operand *op, vec<vec<user_id *> > &for_vec)
  {
    vec<operand *> ret = vNULL;
  
*************** commutate (operand *op)
*** 827,833 ****
  	  ret.safe_push (op);
  	  return ret;
  	}
!       vec<operand *> v = commutate (c->what);
        for (unsigned i = 0; i < v.length (); ++i)
  	{
  	  capture *nc = new capture (c->location, c->where, v[i]);
--- 892,898 ----
  	  ret.safe_push (op);
  	  return ret;
  	}
!       vec<operand *> v = commutate (c->what, for_vec);
        for (unsigned i = 0; i < v.length (); ++i)
  	{
  	  capture *nc = new capture (c->location, c->where, v[i]);
*************** commutate (operand *op)
*** 845,851 ****
  
    vec< vec<operand *> > ops_vector = vNULL;
    for (unsigned i = 0; i < e->ops.length (); ++i)
!     ops_vector.safe_push (commutate (e->ops[i]));
  
    auto_vec< vec<operand *> > result;
    auto_vec<operand *> v (e->ops.length ());
--- 910,916 ----
  
    vec< vec<operand *> > ops_vector = vNULL;
    for (unsigned i = 0; i < e->ops.length (); ++i)
!     ops_vector.safe_push (commutate (e->ops[i], for_vec));
  
    auto_vec< vec<operand *> > result;
    auto_vec<operand *> v (e->ops.length ());
*************** commutate (operand *op)
*** 868,873 ****
--- 933,982 ----
    for (unsigned i = 0; i < result.length (); ++i)
      {
        expr *ne = new expr (e);
+       if (operator_id *p = dyn_cast <operator_id *> (ne->operation))
+ 	{
+ 	  if (comparison_code_p (p->code))
+ 	    ne->operation = swap_tree_comparison (p);
+ 	}
+       else if (user_id *p = dyn_cast <user_id *> (ne->operation))
+ 	{
+ 	  bool found_compare = false;
+ 	  for (unsigned j = 0; j < p->substitutes.length (); ++j)
+ 	    if (operator_id *q = dyn_cast <operator_id *> (p->substitutes[j]))
+ 	      {
+ 		if (comparison_code_p (q->code)
+ 		    && swap_tree_comparison (q) != q)
+ 		  {
+ 		    found_compare = true;
+ 		    break;
+ 		  }
+ 	      }
+ 	  if (found_compare)
+ 	    {
+ 	      user_id *newop = new user_id ("<internal>");
+ 	      for (unsigned j = 0; j < p->substitutes.length (); ++j)
+ 		{
+ 		  id_base *subst = p->substitutes[j];
+ 		  if (operator_id *q = dyn_cast <operator_id *> (subst))
+ 		    {
+ 		      if (comparison_code_p (q->code))
+ 			subst = swap_tree_comparison (q);
+ 		    }
+ 		  newop->substitutes.safe_push (subst);
+ 		}
+ 	      ne->operation = newop;
+ 	      /* Search for 'p' inside the for vector and push 'newop'
+ 	         to the same level.  */
+ 	      for (unsigned j = 0; newop && j < for_vec.length (); ++j)
+ 		for (unsigned k = 0; k < for_vec[j].length (); ++k)
+ 		  if (for_vec[j][k] == p)
+ 		    {
+ 		      for_vec[j].safe_push (newop);
+ 		      newop = NULL;
+ 		      break;
+ 		    }
+ 	    }
+ 	}
        ne->is_commutative = false;
        // result[i].length () is 2 since e->operation is binary
        for (unsigned j = result[i].length (); j; --j)
*************** commutate (operand *op)
*** 884,890 ****
  static void
  lower_commutative (simplify *s, vec<simplify *>& simplifiers)
  {
!   vec<operand *> matchers = commutate (s->match);
    for (unsigned i = 0; i < matchers.length (); ++i)
      {
        simplify *ns = new simplify (s->kind, matchers[i], s->result,
--- 993,999 ----
  static void
  lower_commutative (simplify *s, vec<simplify *>& simplifiers)
  {
!   vec<operand *> matchers = commutate (s->match, s->for_vec);
    for (unsigned i = 0; i < matchers.length (); ++i)
      {
        simplify *ns = new simplify (s->kind, matchers[i], s->result,
*************** dt_simplify::gen (FILE *f, int indent, b
*** 3248,3254 ****
  	  fprintf_indent (f, indent, "if (%s (res_code, res_ops, seq, "
  			  "valueize, type, captures", info->fname);
  	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
! 	    fprintf (f, ", %s", s->for_subst_vec[i].second->id);
  	  fprintf (f, "))\n");
  	  fprintf_indent (f, indent, "  return true;\n");
  	}
--- 3357,3364 ----
  	  fprintf_indent (f, indent, "if (%s (res_code, res_ops, seq, "
  			  "valueize, type, captures", info->fname);
  	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
! 	    if (s->for_subst_vec[i].first->used)
! 	      fprintf (f, ", %s", s->for_subst_vec[i].second->id);
  	  fprintf (f, "))\n");
  	  fprintf_indent (f, indent, "  return true;\n");
  	}
*************** dt_simplify::gen (FILE *f, int indent, b
*** 3260,3266 ****
  	    fprintf (f, ", op%d", i);
  	  fprintf (f, ", captures");
  	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
! 	    fprintf (f, ", %s", s->for_subst_vec[i].second->id);
  	  fprintf (f, ");\n");
  	  fprintf_indent (f, indent, "if (res) return res;\n");
  	}
--- 3370,3379 ----
  	    fprintf (f, ", op%d", i);
  	  fprintf (f, ", captures");
  	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
! 	    {
! 	      if (s->for_subst_vec[i].first->used)
! 		fprintf (f, ", %s", s->for_subst_vec[i].second->id);
! 	    }
  	  fprintf (f, ");\n");
  	  fprintf_indent (f, indent, "if (res) return res;\n");
  	}
*************** dt_simplify::gen (FILE *f, int indent, b
*** 3269,3274 ****
--- 3382,3389 ----
      {
        for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
  	{
+ 	  if (! s->for_subst_vec[i].first->used)
+ 	    continue;
  	  if (is_a <operator_id *> (s->for_subst_vec[i].second))
  	    fprintf_indent (f, indent, "enum tree_code %s = %s;\n",
  			    s->for_subst_vec[i].first->id,
*************** decision_tree::gen (FILE *f, bool gimple
*** 3425,3430 ****
--- 3540,3547 ----
  	}
        for (unsigned i = 0; i < s->s->s->for_subst_vec.length (); ++i)
  	{
+ 	  if (! s->s->s->for_subst_vec[i].first->used)
+ 	    continue;
  	  if (is_a <operator_id *> (s->s->s->for_subst_vec[i].second))
  	    fprintf (f, ", enum tree_code ARG_UNUSED (%s)",
  		     s->s->s->for_subst_vec[i].first->id);
*************** parser::parse_expr ()
*** 3885,3890 ****
--- 4002,4031 ----
  	      while (*sp)
  		{
  		  if (*sp == 'c')
+ 		    {
+ 		      if (operator_id *p
+ 			    = dyn_cast<operator_id *> (e->operation))
+ 			{
+ 			  if (!commutative_tree_code (p->code)
+ 			      && !comparison_code_p (p->code))
+ 			    fatal_at (token, "operation is not commutative");
+ 			}
+ 		      else if (user_id *p = dyn_cast<user_id *> (e->operation))
+ 			for (unsigned i = 0;
+ 			     i < p->substitutes.length (); ++i)
+ 			  {
+ 			    if (operator_id *q
+ 				  = dyn_cast<operator_id *> (p->substitutes[i]))
+ 			      {
+ 				if (!commutative_tree_code (q->code)
+ 				    && !comparison_code_p (q->code))
+ 				  fatal_at (token, "operation %s is not "
+ 					    "commutative", q->id);
+ 			      }
+ 			  }
+ 		      is_commutative = true;
+ 		    }
+ 		  else if (*sp == 'C')
  		    is_commutative = true;
  		  else if (*sp == 's')
  		    {
Index: gcc/match.pd
===================================================================
*** gcc/match.pd	(revision 236877)
--- gcc/match.pd	(working copy)
*************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
*** 189,195 ****
  /* Optimize -A / A to -1.0 if we don't care about
     NaNs or Infinities.  */
  (simplify
!  (rdiv:c @0 (negate @0))
   (if (FLOAT_TYPE_P (type)
        && ! HONOR_NANS (type)
        && ! HONOR_INFINITIES (type))
--- 189,195 ----
  /* Optimize -A / A to -1.0 if we don't care about
     NaNs or Infinities.  */
  (simplify
!  (rdiv:C @0 (negate @0))
   (if (FLOAT_TYPE_P (type)
        && ! HONOR_NANS (type)
        && ! HONOR_INFINITIES (type))
*************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
*** 2811,2817 ****
  
  /* cabs(x+0i) or cabs(0+xi) -> abs(x).  */
  (simplify
!  (CABS (complex:c @0 real_zerop@1))
   (abs @0))
  
  /* trunc(trunc(x)) -> trunc(x), etc.  */
--- 2833,2839 ----
  
  /* cabs(x+0i) or cabs(0+xi) -> abs(x).  */
  (simplify
!  (CABS (complex:C @0 real_zerop@1))
   (abs @0))
  
  /* trunc(trunc(x)) -> trunc(x), etc.  */
*************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
*** 3246,3252 ****
  (for op (lt le gt ge)
       ext (min min max max)
   (simplify
!   (bit_and (op:s @0 @1) (op:s @0 @2))
    (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
     (op @0 (ext @1 @2)))))
  
--- 3268,3274 ----
  (for op (lt le gt ge)
       ext (min min max max)
   (simplify
!   (bit_and (op:cs @0 @1) (op:cs @0 @2))
    (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
     (op @0 (ext @1 @2)))))
Richard Biener June 1, 2016, 7:37 a.m. UTC | #2
On Tue, 31 May 2016, Richard Biener wrote:

> On Tue, 31 May 2016, Richard Biener wrote:
> 
> > 
> > The following patch adds missing patterns with swapped comparison
> > operands for the @0 < @1 and @0 < @2 to @0 < min (@1, @2) transform.
> > This nullifies the difference gimplify-into-SSA made on
> > rhfuhf.F:ROFOCK which causes the function no longer to be miscompiled
> > (by vectorization eventually, -fno-tree-vectorize also fixes the
> > miscompare at r235817).
> 
> The following is a variant, avoiding the pattern repetition in match.pd
> by (finally) completing a local patch I had to support "commutating"
> relational operators.  It also adds sanity-checking for what you apply
> :c to which catches a few cases in match.pd I introduce :C for in this
> patch.
> 
> Bootstrap / regtest in progress on x86_64-unknown-linux-gnu.

I'm re-testing with enforcing a non-INTEGER_CST @0 on the pattern, thus

/* Transform (@0 < @1 and @0 < @2) to use min,
   (@0 > @1 and @0 > @2) to use max */
(for op (lt le gt ge)
     ext (min min max max)
 (simplify
  (bit_and (op:cs @0 @1) (op:cs @0 @2))
  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
       && TREE_CODE (@0) != INTEGER_CST)
   (op @0 (ext @1 @2)))))

as otherwise we have testsuite regressions and ICEs because 
operand_equal_p doesn't enforce type compatibility between INTEGER_CSTs.
Using types_match (@1, @2) still leads to tests like
ssa-ifcombine-ccmp-1.c FAILing in their dump scanning.  It's also hardly
profitable to replace a < 0 && b < 0 with max(a,b) < 0 given tests
against constants are going to be way cheaper than computing max.

Meanwhile I've split the relational :c support and committed that,
also testing a followup to replace existing duplications with :c
(will post after testing completed).

Richard.

> Richard.
> 
> 2016-05-31  Richard Biener  <rguenther@suse.de>
> 
> 	PR tree-optimization/71311
> 	* genmatch.c (comparison_code_p): New predicate.
> 	(swap_tree_comparison): New function.
> 	(commutate): Add for_vec parameter to append new for entries.
> 	Support commutating relational operators by swapping it alongside
> 	operands.
> 	(lower_commutative): Adjust.
> 	(dt_simplify::gen): Do not pass artificial operators to gen
> 	functions.
> 	(decision_tree::gen): Do not add artificial operators as parameters.
> 	(parser::parse_expr): Verify operator commutativity when :c is
> 	applied.  Allow :C to override this.
> 	* match.pd: Adjust patterns to use :C instead of :c where required.
> 	Add :c to @0 < @1 && @0 < @2 -> @0 < min(@1,@2) transform.
> 
> Index: gcc/genmatch.c
> ===================================================================
> *** gcc/genmatch.c	(revision 236877)
> --- gcc/genmatch.c	(working copy)
> *************** commutative_ternary_tree_code (enum tree
> *** 291,296 ****
> --- 291,325 ----
>     return false;
>   }
>   
> + /* Return true if CODE is a comparison.  */
> + 
> + bool
> + comparison_code_p (enum tree_code code)
> + {
> +   switch (code)
> +     {
> +     case EQ_EXPR:
> +     case NE_EXPR:
> +     case ORDERED_EXPR:
> +     case UNORDERED_EXPR:
> +     case LTGT_EXPR:
> +     case UNEQ_EXPR:
> +     case GT_EXPR:
> +     case GE_EXPR:
> +     case LT_EXPR:
> +     case LE_EXPR:
> +     case UNGT_EXPR:
> +     case UNGE_EXPR:
> +     case UNLT_EXPR:
> +     case UNLE_EXPR:
> +       return true;
> + 
> +     default:
> +       break;
> +     }
> +   return false;
> + }
> + 
>   
>   /* Base class for all identifiers the parser knows.  */
>   
> *************** get_operator (const char *id, bool allow
> *** 528,533 ****
> --- 557,598 ----
>     return operators->find_with_hash (&tem, tem.hashval);
>   }
>   
> + /* Return the comparison operators that results if the operands are
> +    swapped.  This is safe for floating-point.  */
> + 
> + id_base *
> + swap_tree_comparison (operator_id *p)
> + {
> +   switch (p->code)
> +     {
> +     case EQ_EXPR:
> +     case NE_EXPR:
> +     case ORDERED_EXPR:
> +     case UNORDERED_EXPR:
> +     case LTGT_EXPR:
> +     case UNEQ_EXPR:
> +       return p;
> +     case GT_EXPR:
> +       return get_operator ("LT_EXPR");
> +     case GE_EXPR:
> +       return get_operator ("LE_EXPR");
> +     case LT_EXPR:
> +       return get_operator ("GT_EXPR");
> +     case LE_EXPR:
> +       return get_operator ("GE_EXPR");
> +     case UNGT_EXPR:
> +       return get_operator ("UNLT_EXPR");
> +     case UNGE_EXPR:
> +       return get_operator ("UNLE_EXPR");
> +     case UNLT_EXPR:
> +       return get_operator ("UNGT_EXPR");
> +     case UNLE_EXPR:
> +       return get_operator ("UNGE_EXPR");
> +     default:
> +       gcc_unreachable ();
> +     }
> + }
> + 
>   typedef hash_map<nofree_string_hash, unsigned> cid_map_t;
>   
>   
> *************** cartesian_product (const vec< vec<operan
> *** 816,822 ****
>   /* Lower OP to two operands in case it is marked as commutative.  */
>   
>   static vec<operand *>
> ! commutate (operand *op)
>   {
>     vec<operand *> ret = vNULL;
>   
> --- 881,887 ----
>   /* Lower OP to two operands in case it is marked as commutative.  */
>   
>   static vec<operand *>
> ! commutate (operand *op, vec<vec<user_id *> > &for_vec)
>   {
>     vec<operand *> ret = vNULL;
>   
> *************** commutate (operand *op)
> *** 827,833 ****
>   	  ret.safe_push (op);
>   	  return ret;
>   	}
> !       vec<operand *> v = commutate (c->what);
>         for (unsigned i = 0; i < v.length (); ++i)
>   	{
>   	  capture *nc = new capture (c->location, c->where, v[i]);
> --- 892,898 ----
>   	  ret.safe_push (op);
>   	  return ret;
>   	}
> !       vec<operand *> v = commutate (c->what, for_vec);
>         for (unsigned i = 0; i < v.length (); ++i)
>   	{
>   	  capture *nc = new capture (c->location, c->where, v[i]);
> *************** commutate (operand *op)
> *** 845,851 ****
>   
>     vec< vec<operand *> > ops_vector = vNULL;
>     for (unsigned i = 0; i < e->ops.length (); ++i)
> !     ops_vector.safe_push (commutate (e->ops[i]));
>   
>     auto_vec< vec<operand *> > result;
>     auto_vec<operand *> v (e->ops.length ());
> --- 910,916 ----
>   
>     vec< vec<operand *> > ops_vector = vNULL;
>     for (unsigned i = 0; i < e->ops.length (); ++i)
> !     ops_vector.safe_push (commutate (e->ops[i], for_vec));
>   
>     auto_vec< vec<operand *> > result;
>     auto_vec<operand *> v (e->ops.length ());
> *************** commutate (operand *op)
> *** 868,873 ****
> --- 933,982 ----
>     for (unsigned i = 0; i < result.length (); ++i)
>       {
>         expr *ne = new expr (e);
> +       if (operator_id *p = dyn_cast <operator_id *> (ne->operation))
> + 	{
> + 	  if (comparison_code_p (p->code))
> + 	    ne->operation = swap_tree_comparison (p);
> + 	}
> +       else if (user_id *p = dyn_cast <user_id *> (ne->operation))
> + 	{
> + 	  bool found_compare = false;
> + 	  for (unsigned j = 0; j < p->substitutes.length (); ++j)
> + 	    if (operator_id *q = dyn_cast <operator_id *> (p->substitutes[j]))
> + 	      {
> + 		if (comparison_code_p (q->code)
> + 		    && swap_tree_comparison (q) != q)
> + 		  {
> + 		    found_compare = true;
> + 		    break;
> + 		  }
> + 	      }
> + 	  if (found_compare)
> + 	    {
> + 	      user_id *newop = new user_id ("<internal>");
> + 	      for (unsigned j = 0; j < p->substitutes.length (); ++j)
> + 		{
> + 		  id_base *subst = p->substitutes[j];
> + 		  if (operator_id *q = dyn_cast <operator_id *> (subst))
> + 		    {
> + 		      if (comparison_code_p (q->code))
> + 			subst = swap_tree_comparison (q);
> + 		    }
> + 		  newop->substitutes.safe_push (subst);
> + 		}
> + 	      ne->operation = newop;
> + 	      /* Search for 'p' inside the for vector and push 'newop'
> + 	         to the same level.  */
> + 	      for (unsigned j = 0; newop && j < for_vec.length (); ++j)
> + 		for (unsigned k = 0; k < for_vec[j].length (); ++k)
> + 		  if (for_vec[j][k] == p)
> + 		    {
> + 		      for_vec[j].safe_push (newop);
> + 		      newop = NULL;
> + 		      break;
> + 		    }
> + 	    }
> + 	}
>         ne->is_commutative = false;
>         // result[i].length () is 2 since e->operation is binary
>         for (unsigned j = result[i].length (); j; --j)
> *************** commutate (operand *op)
> *** 884,890 ****
>   static void
>   lower_commutative (simplify *s, vec<simplify *>& simplifiers)
>   {
> !   vec<operand *> matchers = commutate (s->match);
>     for (unsigned i = 0; i < matchers.length (); ++i)
>       {
>         simplify *ns = new simplify (s->kind, matchers[i], s->result,
> --- 993,999 ----
>   static void
>   lower_commutative (simplify *s, vec<simplify *>& simplifiers)
>   {
> !   vec<operand *> matchers = commutate (s->match, s->for_vec);
>     for (unsigned i = 0; i < matchers.length (); ++i)
>       {
>         simplify *ns = new simplify (s->kind, matchers[i], s->result,
> *************** dt_simplify::gen (FILE *f, int indent, b
> *** 3248,3254 ****
>   	  fprintf_indent (f, indent, "if (%s (res_code, res_ops, seq, "
>   			  "valueize, type, captures", info->fname);
>   	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
> ! 	    fprintf (f, ", %s", s->for_subst_vec[i].second->id);
>   	  fprintf (f, "))\n");
>   	  fprintf_indent (f, indent, "  return true;\n");
>   	}
> --- 3357,3364 ----
>   	  fprintf_indent (f, indent, "if (%s (res_code, res_ops, seq, "
>   			  "valueize, type, captures", info->fname);
>   	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
> ! 	    if (s->for_subst_vec[i].first->used)
> ! 	      fprintf (f, ", %s", s->for_subst_vec[i].second->id);
>   	  fprintf (f, "))\n");
>   	  fprintf_indent (f, indent, "  return true;\n");
>   	}
> *************** dt_simplify::gen (FILE *f, int indent, b
> *** 3260,3266 ****
>   	    fprintf (f, ", op%d", i);
>   	  fprintf (f, ", captures");
>   	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
> ! 	    fprintf (f, ", %s", s->for_subst_vec[i].second->id);
>   	  fprintf (f, ");\n");
>   	  fprintf_indent (f, indent, "if (res) return res;\n");
>   	}
> --- 3370,3379 ----
>   	    fprintf (f, ", op%d", i);
>   	  fprintf (f, ", captures");
>   	  for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
> ! 	    {
> ! 	      if (s->for_subst_vec[i].first->used)
> ! 		fprintf (f, ", %s", s->for_subst_vec[i].second->id);
> ! 	    }
>   	  fprintf (f, ");\n");
>   	  fprintf_indent (f, indent, "if (res) return res;\n");
>   	}
> *************** dt_simplify::gen (FILE *f, int indent, b
> *** 3269,3274 ****
> --- 3382,3389 ----
>       {
>         for (unsigned i = 0; i < s->for_subst_vec.length (); ++i)
>   	{
> + 	  if (! s->for_subst_vec[i].first->used)
> + 	    continue;
>   	  if (is_a <operator_id *> (s->for_subst_vec[i].second))
>   	    fprintf_indent (f, indent, "enum tree_code %s = %s;\n",
>   			    s->for_subst_vec[i].first->id,
> *************** decision_tree::gen (FILE *f, bool gimple
> *** 3425,3430 ****
> --- 3540,3547 ----
>   	}
>         for (unsigned i = 0; i < s->s->s->for_subst_vec.length (); ++i)
>   	{
> + 	  if (! s->s->s->for_subst_vec[i].first->used)
> + 	    continue;
>   	  if (is_a <operator_id *> (s->s->s->for_subst_vec[i].second))
>   	    fprintf (f, ", enum tree_code ARG_UNUSED (%s)",
>   		     s->s->s->for_subst_vec[i].first->id);
> *************** parser::parse_expr ()
> *** 3885,3890 ****
> --- 4002,4031 ----
>   	      while (*sp)
>   		{
>   		  if (*sp == 'c')
> + 		    {
> + 		      if (operator_id *p
> + 			    = dyn_cast<operator_id *> (e->operation))
> + 			{
> + 			  if (!commutative_tree_code (p->code)
> + 			      && !comparison_code_p (p->code))
> + 			    fatal_at (token, "operation is not commutative");
> + 			}
> + 		      else if (user_id *p = dyn_cast<user_id *> (e->operation))
> + 			for (unsigned i = 0;
> + 			     i < p->substitutes.length (); ++i)
> + 			  {
> + 			    if (operator_id *q
> + 				  = dyn_cast<operator_id *> (p->substitutes[i]))
> + 			      {
> + 				if (!commutative_tree_code (q->code)
> + 				    && !comparison_code_p (q->code))
> + 				  fatal_at (token, "operation %s is not "
> + 					    "commutative", q->id);
> + 			      }
> + 			  }
> + 		      is_commutative = true;
> + 		    }
> + 		  else if (*sp == 'C')
>   		    is_commutative = true;
>   		  else if (*sp == 's')
>   		    {
> Index: gcc/match.pd
> ===================================================================
> *** gcc/match.pd	(revision 236877)
> --- gcc/match.pd	(working copy)
> *************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> *** 189,195 ****
>   /* Optimize -A / A to -1.0 if we don't care about
>      NaNs or Infinities.  */
>   (simplify
> !  (rdiv:c @0 (negate @0))
>    (if (FLOAT_TYPE_P (type)
>         && ! HONOR_NANS (type)
>         && ! HONOR_INFINITIES (type))
> --- 189,195 ----
>   /* Optimize -A / A to -1.0 if we don't care about
>      NaNs or Infinities.  */
>   (simplify
> !  (rdiv:C @0 (negate @0))
>    (if (FLOAT_TYPE_P (type)
>         && ! HONOR_NANS (type)
>         && ! HONOR_INFINITIES (type))
> *************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> *** 2811,2817 ****
>   
>   /* cabs(x+0i) or cabs(0+xi) -> abs(x).  */
>   (simplify
> !  (CABS (complex:c @0 real_zerop@1))
>    (abs @0))
>   
>   /* trunc(trunc(x)) -> trunc(x), etc.  */
> --- 2833,2839 ----
>   
>   /* cabs(x+0i) or cabs(0+xi) -> abs(x).  */
>   (simplify
> !  (CABS (complex:C @0 real_zerop@1))
>    (abs @0))
>   
>   /* trunc(trunc(x)) -> trunc(x), etc.  */
> *************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> *** 3246,3252 ****
>   (for op (lt le gt ge)
>        ext (min min max max)
>    (simplify
> !   (bit_and (op:s @0 @1) (op:s @0 @2))
>     (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
>      (op @0 (ext @1 @2)))))
>   
> --- 3268,3274 ----
>   (for op (lt le gt ge)
>        ext (min min max max)
>    (simplify
> !   (bit_and (op:cs @0 @1) (op:cs @0 @2))
>     (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
>      (op @0 (ext @1 @2)))))
>   
>
Bernhard Reutner-Fischer June 2, 2016, 5:47 p.m. UTC | #3
On June 1, 2016 9:37:26 AM GMT+02:00, Richard Biener <rguenther@suse.de> wrote:

>> 	PR tree-optimization/71311
>> 	* genmatch.c (comparison_code_p): New predicate.

TREE_CODE_CLASS (code) == tcc_comparison

?
thanks,
Richard Biener June 2, 2016, 7:05 p.m. UTC | #4
On June 2, 2016 7:47:19 PM GMT+02:00, Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> wrote:
>On June 1, 2016 9:37:26 AM GMT+02:00, Richard Biener
><rguenther@suse.de> wrote:
>
>>> 	PR tree-optimization/71311
>>> 	* genmatch.c (comparison_code_p): New predicate.
>
>TREE_CODE_CLASS (code) == tcc_comparison

Only if I'd pull all of the tree stuff into the generator.

Richard.

>?
>thanks,
Bernhard Reutner-Fischer June 2, 2016, 8:36 p.m. UTC | #5
On June 2, 2016 9:05:36 PM GMT+02:00, Richard Biener <rguenther@suse.de> wrote:
>On June 2, 2016 7:47:19 PM GMT+02:00, Bernhard Reutner-Fischer
><rep.dot.nop@gmail.com> wrote:
>>On June 1, 2016 9:37:26 AM GMT+02:00, Richard Biener
>><rguenther@suse.de> wrote:
>>
>>>> 	PR tree-optimization/71311
>>>> 	* genmatch.c (comparison_code_p): New predicate.
>>
>>TREE_CODE_CLASS (code) == tcc_comparison
>
>Only if I'd pull all of the tree stuff into the generator.

Ah, I thought this already was in there.
diff mbox

Patch

Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 235817)
+++ gcc/match.pd	(working copy)
@@ -3179,6 +3179,23 @@  DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (bit_and (op:s @0 @1) (op:s @0 @2))
   (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
    (op @0 (ext @1 @2)))))
+/* Transform (@1 < @0 and @2 < @0) to use max,
+   (@1 > @0 and @2 > @0) to use min */
+(for op (lt le gt ge)
+     ext (max max min min)
+ (simplify
+  (bit_and (op:s @1 @0) (op:s @2 @0))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
+   (op (ext @1 @2) @0))))
+/* Transform (@0 < @1 and @2 > @0) to use min, 
+   (@0 > @1 and @2 < @0) to use max */
+(for op (lt le gt ge)
+     ops (gt ge lt le)
+     ext (min min max max)
+ (simplify
+  (bit_and:c (op:s @0 @1) (ops:s @2 @0))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
+   (op @0 (ext @1 @2)))))
 
 (simplify
  /* signbit(x) -> 0 if x is nonnegative.  */