This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] MIN/MAX_EXPR transform in phiopts


Hello,

this patch makes ivopts turn

   if (a < b)
     a = b;

into

   a = MAX_EXPR (a, b)

and

   if (a < 0)
     a = 0;
   else if (a > 10)
     a = 10;

into

   a = MAX_EXPR (0, MIN_EXPR (a, 10))

It also makes several related cleanups to phiopts:

1) To handle nested conditionals (like in the later transforms), phiopts
   pass the blocks using FOR_EACH_BB_REVERSE, so that the inner
   conditions are tested and collapsed first.  This is not reliable,
   since the order of the blocks in the list may be arbitrary.
   The patch forces a correct ordering -- the one in that a basic
   block with a single predecessor is guaranteed to be processed
   before the predecessor.

2) abs_replacement is made to use last_and_only_stmt instead of
   nontrivially looking loop to pass over the statements of the
   middle block.

3) On a few places, build is replaced with build1/build2.

Bootstrapped & regtested on i686 and ppc.

Btw.: yesterday I noticed Steven mentioning in a mailing list that he has
a similar patch; sorry for the work duplication, I had already the patch
in testing at the moment :-(

Zdenek

	* tree-ssa-phiopt.c (minmax_replacement, blocks_in_phiopt_order):
	New functions.
	(tree_ssa_phiopt): Use blocks_in_phiopt_order and minmax_replacement.
	Remove unused removed_phis variable.
	(conditional_replacement): Use build1/build2.
	(abs_replacement): Use last_and_only_stmt and build1/build2.

	* gcc.dg/tree-ssa/phi-opt-5.c: New test.

Index: tree-ssa-phiopt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-phiopt.c,v
retrieving revision 2.25
diff -c -3 -p -r2.25 tree-ssa-phiopt.c
*** tree-ssa-phiopt.c	8 Mar 2005 13:56:58 -0000	2.25
--- tree-ssa-phiopt.c	10 Mar 2005 23:48:04 -0000
*************** static bool conditional_replacement (bas
*** 41,50 ****
--- 41,53 ----
  				     edge, edge, tree, tree, tree);
  static bool value_replacement (basic_block, basic_block, basic_block,
  			       edge, edge, tree, tree, tree);
+ static bool minmax_replacement (basic_block, basic_block, basic_block,
+ 				edge, edge, tree, tree, tree);
  static bool abs_replacement (basic_block, basic_block, basic_block,
  			     edge, edge, tree, tree, tree);
  static void replace_phi_edge_with_variable (basic_block, basic_block, edge,
  					    tree, tree);
+ static basic_block *blocks_in_phiopt_order (void);
  
  /* This pass eliminates PHI nodes which can be trivially implemented as
     an assignment from a conditional expression.  i.e. if we have something
*************** static void replace_phi_edge_with_variab
*** 102,107 ****
--- 105,125 ----
       bb2:
        x = ABS_EXPR< a >;
  
+    Similarly,
+ 
+      bb0:
+       if (a <= b) goto bb2; else goto bb1;
+      bb1:
+       goto bb2;
+      bb2:
+       x = PHI (b (bb1), a (bb0));
+ 
+    Becomes
+ 
+      x = MIN_EXPR (a, b)
+ 
+    And the same transformation for MAX_EXPR.
+ 
     bb1 will become unreachable and bb0 and bb2 will almost always be merged
     into a single block.  Similar transformations are done by the ifcvt
     RTL optimizer.  */
*************** static void
*** 110,125 ****
  tree_ssa_phiopt (void)
  {
    basic_block bb;
!   bool removed_phis = false;
  
!   /* Search every basic block for COND_EXPR we may be able to optimize
!      in reverse order so we can find more.  */
!   FOR_EACH_BB_REVERSE (bb)
      {
        tree cond_expr;
        tree phi;
        basic_block bb1, bb2;
        edge e1, e2;
  
        cond_expr = last_stmt (bb);
        /* Check to see if the last statement is a COND_EXPR.  */
--- 128,155 ----
  tree_ssa_phiopt (void)
  {
    basic_block bb;
!   basic_block *bb_order;
!   unsigned n, i;
! 
!   /* Search every basic block for COND_EXPR we may be able to optimize.
  
!      We walk the blocks in order that guarantees that a block with
!      a single predecessor is processed before the predecessor.
!      This ensures that we collapse inner ifs before visiting the
!      outer ones, and also that we do not try to visit a removed
!      block.  */
!   bb_order = blocks_in_phiopt_order ();
!   n = n_basic_blocks;
! 
!   for (i = 0; i < n; i++)
      {
        tree cond_expr;
        tree phi;
        basic_block bb1, bb2;
        edge e1, e2;
+       tree arg0, arg1;
+ 
+       bb = bb_order[i];
  
        cond_expr = last_stmt (bb);
        /* Check to see if the last statement is a COND_EXPR.  */
*************** tree_ssa_phiopt (void)
*** 175,202 ****
        /* Check to make sure that there is only one PHI node.
           TODO: we could do it with more than one iff the other PHI nodes
  	 have the same elements for these two edges.  */
!       if (phi && PHI_CHAIN (phi) == NULL)
! 	{
! 	  tree arg0 = NULL, arg1 = NULL;
  
! 	  arg0 = PHI_ARG_DEF_TREE (phi, e1->dest_idx);
! 	  arg1 = PHI_ARG_DEF_TREE (phi, e2->dest_idx);
  
! 	  /* We know something is wrong if we cannot find the edges in the PHI
! 	     node.  */
! 	  gcc_assert (arg0 != NULL && arg1 != NULL);
! 
! 	  /* Do the replacement of conditional if it can be done.  */
! 	  if (conditional_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1)
! 	      || value_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1)
! 	      || abs_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1))
! 	    {
! 	      /* We have done the replacement so we need to rebuild the
! 		 cfg when this pass is complete.  */
! 	      removed_phis = true;
! 	    }
  	}
      }
  }
  
  /* Return TRUE if block BB has no executable statements, otherwise return
--- 205,281 ----
        /* Check to make sure that there is only one PHI node.
           TODO: we could do it with more than one iff the other PHI nodes
  	 have the same elements for these two edges.  */
!       if (!phi || PHI_CHAIN (phi) != NULL)
! 	continue;
  
!       arg0 = PHI_ARG_DEF_TREE (phi, e1->dest_idx);
!       arg1 = PHI_ARG_DEF_TREE (phi, e2->dest_idx);
  
!       /* We know something is wrong if we cannot find the edges in the PHI
! 	 node.  */
!       gcc_assert (arg0 != NULL && arg1 != NULL);
! 
!       /* Do the replacement of conditional if it can be done.  */
!       if (conditional_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1))
! 	;
!       else if (value_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1))
! 	;
!       else if (abs_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1))
! 	;
!       else
! 	minmax_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1);
!     }
! 
!   free (bb_order);
! }
! 
! /* Returns the list of basic blocks in the function in an order that guarantees
!    that if a block X has just a single predecessor Y, then Y is after X in the
!    ordering.  */
! 
! static basic_block *
! blocks_in_phiopt_order (void)
! {
!   basic_block x, y;
!   basic_block *order = xmalloc (sizeof (basic_block) * n_basic_blocks);
!   unsigned n = n_basic_blocks, np, i;
! 
!   ENTRY_BLOCK_PTR->flags |= BB_VISITED;
!   FOR_EACH_BB (x)
!     {
!       if (x->flags & BB_VISITED)
! 	continue;
! 
!       /* Walk the predecessors of x as long as they have precisely one
! 	 predecessor and add them to the list, so that they get stored
! 	 after x.  */
!       for (y = x, np = 1;
! 	   EDGE_COUNT (y->preds) == 1
! 	   && !(EDGE_PRED (y, 0)->src->flags & BB_VISITED);
! 	   y = EDGE_PRED (y, 0)->src)
! 	np++;
!       for (y = x, i = n - np;
! 	   EDGE_COUNT (y->preds) == 1
! 	   && !(EDGE_PRED (y, 0)->src->flags & BB_VISITED);
! 	   y = EDGE_PRED (y, 0)->src, i++)
! 	{
! 	  order[i] = y;
! 	  y->flags |= BB_VISITED;
  	}
+       order[i] = y;
+       y->flags |= BB_VISITED;
+ 
+       gcc_assert (i == n - 1);
+       n -= np;
+     }
+ 
+   ENTRY_BLOCK_PTR->flags &= ~BB_VISITED;
+   FOR_EACH_BB (x)
+     {
+       x->flags &= ~BB_VISITED;
      }
+   gcc_assert (n == 0);
+   return order;
  }
  
  /* Return TRUE if block BB has no executable statements, otherwise return
*************** conditional_replacement (basic_block con
*** 328,338 ****
        if (!COMPARISON_CLASS_P (old_result))
  	return false;
  
!       new1 = build (TREE_CODE (old_result), TREE_TYPE (old_result),
! 		    TREE_OPERAND (old_result, 0),
! 		    TREE_OPERAND (old_result, 1));
  
!       new1 = build (MODIFY_EXPR, TREE_TYPE (old_result), new_var, new1);
        bsi_insert_after (&bsi, new1, BSI_NEW_STMT);
      }
  
--- 407,417 ----
        if (!COMPARISON_CLASS_P (old_result))
  	return false;
  
!       new1 = build2 (TREE_CODE (old_result), TREE_TYPE (old_result),
! 		     TREE_OPERAND (old_result, 0),
! 		     TREE_OPERAND (old_result, 1));
  
!       new1 = build2 (MODIFY_EXPR, TREE_TYPE (old_result), new_var, new1);
        bsi_insert_after (&bsi, new1, BSI_NEW_STMT);
      }
  
*************** conditional_replacement (basic_block con
*** 361,367 ****
        || (e1 == true_edge && integer_onep (arg1))
        || (e1 == false_edge && integer_zerop (arg1)))
      {
!       new = build (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
      }
    else
      {
--- 440,446 ----
        || (e1 == true_edge && integer_onep (arg1))
        || (e1 == false_edge && integer_zerop (arg1)))
      {
!       new = build2 (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
      }
    else
      {
*************** conditional_replacement (basic_block con
*** 383,389 ****
  	{
  	  tree temp = TREE_OPERAND (cond, 0);
  	  tree new_var_1 = make_rename_temp (TREE_TYPE (temp), NULL);
! 	  new = build (MODIFY_EXPR, TREE_TYPE (new_var_1), new_var_1, temp);
  	  bsi_insert_after (&bsi, new, BSI_NEW_STMT);
  	  cond = fold_convert (TREE_TYPE (result), new_var_1);
  	}
--- 462,468 ----
  	{
  	  tree temp = TREE_OPERAND (cond, 0);
  	  tree new_var_1 = make_rename_temp (TREE_TYPE (temp), NULL);
! 	  new = build2 (MODIFY_EXPR, TREE_TYPE (new_var_1), new_var_1, temp);
  	  bsi_insert_after (&bsi, new, BSI_NEW_STMT);
  	  cond = fold_convert (TREE_TYPE (result), new_var_1);
  	}
*************** conditional_replacement (basic_block con
*** 395,401 ****
  	  return false;
  	}
  
!       new = build (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
      }
  
    bsi_insert_after (&bsi, new, BSI_NEW_STMT);
--- 474,480 ----
  	  return false;
  	}
  
!       new = build2 (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
      }
  
    bsi_insert_after (&bsi, new, BSI_NEW_STMT);
*************** value_replacement (basic_block cond_bb, 
*** 488,493 ****
--- 567,823 ----
    return false;
  }
  
+ /*  The function minmax_replacement does the main work of doing the minmax
+     replacement.  Return true if the replacement is done.  Otherwise return
+     false.
+     BB is the basic block where the replacement is going to be done on.  ARG0
+     is argument 0 from the PHI.  Likewise for ARG1.  */
+ 
+ static bool
+ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
+ 		    basic_block phi_bb, edge e0, edge e1, tree phi,
+ 		    tree arg0, tree arg1)
+ {
+   tree result, type;
+   tree cond, new;
+   edge true_edge, false_edge;
+   enum tree_code cmp, minmax, ass_code;
+   tree smaller, larger, arg_true, arg_false;
+   block_stmt_iterator bsi, bsi_from;
+ 
+   type = TREE_TYPE (PHI_RESULT (phi));
+ 
+   /* The optimization may be unsafe due to NaNs.  */
+   if (HONOR_NANS (TYPE_MODE (type)))
+     return false;
+ 
+   cond = COND_EXPR_COND (last_stmt (cond_bb));
+   cmp = TREE_CODE (cond);
+   result = PHI_RESULT (phi);
+ 
+   /* This transformation is only valid for order comparisons.  Record which
+      operand is smaller/larger if the result of the comparison is true.  */
+   if (cmp == LT_EXPR || cmp == LE_EXPR)
+     {
+       smaller = TREE_OPERAND (cond, 0);
+       larger = TREE_OPERAND (cond, 1);
+     }
+   else if (cmp == GT_EXPR || cmp == GE_EXPR)
+     {
+       smaller = TREE_OPERAND (cond, 1);
+       larger = TREE_OPERAND (cond, 0);
+     }
+   else
+     return false;
+ 
+   /* We need to know which is the true edge and which is the false
+       edge so that we know if have abs or negative abs.  */
+   extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
+ 
+   /* Forward the edges over the middle basic block.  */
+   if (true_edge->dest == middle_bb)
+     true_edge = EDGE_SUCC (true_edge->dest, 0);
+   if (false_edge->dest == middle_bb)
+     false_edge = EDGE_SUCC (false_edge->dest, 0);
+ 
+   if (true_edge == e0)
+     {
+       gcc_assert (false_edge == e1);
+       arg_true = arg0;
+       arg_false = arg1;
+     }
+   else
+     {
+       gcc_assert (false_edge == e0);
+       gcc_assert (true_edge == e1);
+       arg_true = arg1;
+       arg_false = arg0;
+     }
+ 
+   if (empty_block_p (middle_bb))
+     {
+       if (operand_equal_for_phi_arg_p (arg_true, smaller)
+ 	  && operand_equal_for_phi_arg_p (arg_false, larger))
+ 	{
+ 	  /* Case
+ 	 
+ 	     if (smaller < larger)
+ 	     rslt = smaller;
+ 	     else
+ 	     rslt = larger;  */
+ 	  minmax = MIN_EXPR;
+ 	}
+       else if (operand_equal_for_phi_arg_p (arg_false, smaller)
+ 	       && operand_equal_for_phi_arg_p (arg_true, larger))
+ 	minmax = MAX_EXPR;
+       else
+ 	return false;
+     }
+   else
+     {
+       /* Recognize the following case, assuming d <= u:
+ 
+ 	 if (a <= u)
+ 	   b = MAX (a, d);
+ 	 x = PHI <b, u>
+ 
+ 	 This is equivalent to
+ 
+ 	 b = MAX (a, d);
+ 	 x = MIN (b, u);  */
+ 
+       tree assign = last_and_only_stmt (middle_bb);
+       tree lhs, rhs, op0, op1, bound;
+ 
+       if (!assign
+ 	  || TREE_CODE (assign) != MODIFY_EXPR)
+ 	return false;
+ 
+       lhs = TREE_OPERAND (assign, 0);
+       rhs = TREE_OPERAND (assign, 1);
+       ass_code = TREE_CODE (rhs);
+       if (ass_code != MAX_EXPR && ass_code != MIN_EXPR)
+ 	return false;
+       op0 = TREE_OPERAND (rhs, 0);
+       op1 = TREE_OPERAND (rhs, 1);
+ 
+       if (true_edge->src == middle_bb)
+ 	{
+ 	  /* We got here if the condition is true, i.e., SMALLER < LARGER.  */
+ 	  if (!operand_equal_for_phi_arg_p (lhs, arg_true))
+ 	    return false;
+ 
+ 	  if (operand_equal_for_phi_arg_p (arg_false, larger))
+ 	    {
+ 	      /* Case
+ 
+ 		 if (smaller < larger)
+ 		   {
+ 		     r' = MAX_EXPR (smaller, bound)
+ 		   }
+ 		 r = PHI <r', larger>  --> to be turned to MIN_EXPR.  */
+ 	      if (ass_code != MAX_EXPR)
+ 		return false;
+ 
+ 	      minmax = MIN_EXPR;
+ 	      if (operand_equal_for_phi_arg_p (op0, smaller))
+ 		bound = op1;
+ 	      else if (operand_equal_for_phi_arg_p (op1, smaller))
+ 		bound = op0;
+ 	      else
+ 		return false;
+ 
+ 	      /* We need BOUND <= LARGER.  */
+ 	      if (!integer_nonzerop (fold (build2 (LE_EXPR, boolean_type_node,
+ 						   bound, larger))))
+ 		return false;
+ 	    }
+ 	  else if (operand_equal_for_phi_arg_p (arg_false, smaller))
+ 	    {
+ 	      /* Case
+ 
+ 		 if (smaller < larger)
+ 		   {
+ 		     r' = MIN_EXPR (larger, bound)
+ 		   }
+ 		 r = PHI <r', smaller>  --> to be turned to MAX_EXPR.  */
+ 	      if (ass_code != MIN_EXPR)
+ 		return false;
+ 
+ 	      minmax = MAX_EXPR;
+ 	      if (operand_equal_for_phi_arg_p (op0, larger))
+ 		bound = op1;
+ 	      else if (operand_equal_for_phi_arg_p (op1, larger))
+ 		bound = op0;
+ 	      else
+ 		return false;
+ 
+ 	      /* We need BOUND >= SMALLER.  */
+ 	      if (!integer_nonzerop (fold (build2 (GE_EXPR, boolean_type_node,
+ 						   bound, smaller))))
+ 		return false;
+ 	    }
+ 	  else
+ 	    return false;
+ 	}
+       else
+ 	{
+ 	  /* We got here if the condition is false, i.e., SMALLER > LARGER.  */
+ 	  if (!operand_equal_for_phi_arg_p (lhs, arg_false))
+ 	    return false;
+ 
+ 	  if (operand_equal_for_phi_arg_p (arg_true, larger))
+ 	    {
+ 	      /* Case
+ 
+ 		 if (smaller > larger)
+ 		   {
+ 		     r' = MIN_EXPR (smaller, bound)
+ 		   }
+ 		 r = PHI <r', larger>  --> to be turned to MAX_EXPR.  */
+ 	      if (ass_code != MIN_EXPR)
+ 		return false;
+ 
+ 	      minmax = MAX_EXPR;
+ 	      if (operand_equal_for_phi_arg_p (op0, smaller))
+ 		bound = op1;
+ 	      else if (operand_equal_for_phi_arg_p (op1, smaller))
+ 		bound = op0;
+ 	      else
+ 		return false;
+ 
+ 	      /* We need BOUND >= LARGER.  */
+ 	      if (!integer_nonzerop (fold (build2 (GE_EXPR, boolean_type_node,
+ 						   bound, larger))))
+ 		return false;
+ 	    }
+ 	  else if (operand_equal_for_phi_arg_p (arg_true, smaller))
+ 	    {
+ 	      /* Case
+ 
+ 		 if (smaller > larger)
+ 		   {
+ 		     r' = MAX_EXPR (larger, bound)
+ 		   }
+ 		 r = PHI <r', smaller>  --> to be turned to MIN_EXPR.  */
+ 	      if (ass_code != MAX_EXPR)
+ 		return false;
+ 
+ 	      minmax = MIN_EXPR;
+ 	      if (operand_equal_for_phi_arg_p (op0, larger))
+ 		bound = op1;
+ 	      else if (operand_equal_for_phi_arg_p (op1, larger))
+ 		bound = op0;
+ 	      else
+ 		return false;
+ 
+ 	      /* We need BOUND <= SMALLER.  */
+ 	      if (!integer_nonzerop (fold (build2 (LE_EXPR, boolean_type_node,
+ 						   bound, smaller))))
+ 		return false;
+ 	    }
+ 	  else
+ 	    return false;
+ 	}
+ 
+       /* Move the statement from the middle block.  */
+       bsi = bsi_last (cond_bb);
+       bsi_from = bsi_last (middle_bb);
+       bsi_move_before (&bsi_from, &bsi);
+     }
+ 
+   /* Emit the statement to compute min/max.  */
+   result = duplicate_ssa_name (PHI_RESULT (phi), NULL);
+   new = build2 (MODIFY_EXPR, type, result,
+ 		build2 (minmax, type, arg0, arg1));
+   SSA_NAME_DEF_STMT (result) = new;
+   bsi = bsi_last (cond_bb);
+   bsi_insert_before (&bsi, new, BSI_NEW_STMT);
+ 
+   replace_phi_edge_with_variable (cond_bb, phi_bb, e1, phi, result);
+   return true;
+ }
+ 
  /*  The function absolute_replacement does the main work of doing the absolute
      replacement.  Return true if the replacement is done.  Otherwise return
      false.
*************** abs_replacement (basic_block cond_bb, ba
*** 503,511 ****
    tree new, cond;
    block_stmt_iterator bsi;
    edge true_edge, false_edge;
!   tree assign = NULL;
    edge e;
!   tree rhs = NULL, lhs = NULL;
    bool negate;
    enum tree_code cond_code;
  
--- 833,841 ----
    tree new, cond;
    block_stmt_iterator bsi;
    edge true_edge, false_edge;
!   tree assign;
    edge e;
!   tree rhs, lhs;
    bool negate;
    enum tree_code cond_code;
  
*************** abs_replacement (basic_block cond_bb, ba
*** 516,572 ****
  
    /* OTHER_BLOCK must have only one executable statement which must have the
       form arg0 = -arg1 or arg1 = -arg0.  */
-   bsi = bsi_start (middle_bb);
-   while (!bsi_end_p (bsi))
-     {
-       tree stmt = bsi_stmt (bsi);
- 
-       /* Empty statements and labels are uninteresting.  */
-       if (TREE_CODE (stmt) == LABEL_EXPR
-           || IS_EMPTY_STMT (stmt))
-         {
-           bsi_next (&bsi);
-           continue;
-         }
- 
-       /* If we found the assignment, but it was not the only executable
- 	 statement in OTHER_BLOCK, then we can not optimize.  */
-       if (assign)
- 	return false;
- 
-       /* If we got here, then we have found the first executable statement
- 	 in OTHER_BLOCK.  If it is anything other than arg = -arg1 or
- 	 arg1 = -arg0, then we can not optimize.  */
-       if (TREE_CODE (stmt) == MODIFY_EXPR)
-         {
-           lhs = TREE_OPERAND (stmt, 0);
-           rhs = TREE_OPERAND (stmt, 1);
- 
-           if (TREE_CODE (rhs) == NEGATE_EXPR)
-             {
-               rhs = TREE_OPERAND (rhs, 0);
- 
-               /* The assignment has to be arg0 = -arg1 or arg1 = -arg0.  */
-               if ((lhs == arg0 && rhs == arg1)
- 		  || (lhs == arg1 && rhs == arg0))
- 		{
- 		  assign = stmt;
- 		  bsi_next (&bsi);
- 		}
- 	      else
- 		return false;
-             }
- 	  else
- 	    return false;
-         }
-       else
- 	return false;
-     }
  
    /* If we did not find the proper negation assignment, then we can not
       optimize.  */
    if (assign == NULL)
      return false;
  
    cond = COND_EXPR_COND (last_stmt (cond_bb));
    result = PHI_RESULT (phi);
--- 846,876 ----
  
    /* OTHER_BLOCK must have only one executable statement which must have the
       form arg0 = -arg1 or arg1 = -arg0.  */
  
+   assign = last_and_only_stmt (middle_bb);
    /* If we did not find the proper negation assignment, then we can not
       optimize.  */
    if (assign == NULL)
      return false;
+       
+   /* If we got here, then we have found the only executable statement
+      in OTHER_BLOCK.  If it is anything other than arg = -arg1 or
+      arg1 = -arg0, then we can not optimize.  */
+   if (TREE_CODE (assign) != MODIFY_EXPR)
+     return false;
+ 
+   lhs = TREE_OPERAND (assign, 0);
+   rhs = TREE_OPERAND (assign, 1);
+ 
+   if (TREE_CODE (rhs) != NEGATE_EXPR)
+     return false;
+ 
+   rhs = TREE_OPERAND (rhs, 0);
+               
+   /* The assignment has to be arg0 = -arg1 or arg1 = -arg0.  */
+   if (!(lhs == arg0 && rhs == arg1)
+       && !(lhs == arg1 && rhs == arg0))
+     return false;
  
    cond = COND_EXPR_COND (last_stmt (cond_bb));
    result = PHI_RESULT (phi);
*************** abs_replacement (basic_block cond_bb, ba
*** 613,620 ****
      lhs = result;
  
    /* Build the modify expression with abs expression.  */
!   new = build (MODIFY_EXPR, TREE_TYPE (lhs),
!                lhs, build1 (ABS_EXPR, TREE_TYPE (lhs), rhs));
  
    bsi = bsi_last (cond_bb);
    bsi_insert_before (&bsi, new, BSI_NEW_STMT);
--- 917,924 ----
      lhs = result;
  
    /* Build the modify expression with abs expression.  */
!   new = build2 (MODIFY_EXPR, TREE_TYPE (lhs),
! 		lhs, build1 (ABS_EXPR, TREE_TYPE (lhs), rhs));
  
    bsi = bsi_last (cond_bb);
    bsi_insert_before (&bsi, new, BSI_NEW_STMT);
*************** abs_replacement (basic_block cond_bb, ba
*** 624,631 ****
        /* Get the right BSI.  We want to insert after the recently
  	 added ABS_EXPR statement (which we know is the first statement
  	 in the block.  */
!       new = build (MODIFY_EXPR, TREE_TYPE (result),
!                    result, build1 (NEGATE_EXPR, TREE_TYPE (lhs), lhs));
  
        bsi_insert_after (&bsi, new, BSI_NEW_STMT);
      }
--- 928,935 ----
        /* Get the right BSI.  We want to insert after the recently
  	 added ABS_EXPR statement (which we know is the first statement
  	 in the block.  */
!       new = build2 (MODIFY_EXPR, TREE_TYPE (result),
! 		    result, build1 (NEGATE_EXPR, TREE_TYPE (lhs), lhs));
  
        bsi_insert_after (&bsi, new, BSI_NEW_STMT);
      }
Index: testsuite/gcc.dg/tree-ssa/phi-opt-5.c
===================================================================
RCS file: testsuite/gcc.dg/tree-ssa/phi-opt-5.c
diff -N testsuite/gcc.dg/tree-ssa/phi-opt-5.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/tree-ssa/phi-opt-5.c	10 Mar 2005 23:48:05 -0000
***************
*** 0 ****
--- 1,58 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O1 -ffinite-math-only -fdump-tree-phiopt1" } */
+ 
+ float repl1 (float varx)
+ {
+   if (varx < 0.0)
+     return 0.0;
+   else if (varx > 1.0)
+     return 1.0;
+   else
+     return varx;
+ }
+ 
+ /* Should be turned to
+ 
+    varx_4 = MIN_EXPR <1.0e+0, varx_2>;
+    varx_5 = MAX_EXPR <varx_4, 0.0>;  */  
+ 
+ /* { dg-final { scan-tree-dump "varx.*MIN_EXPR.*1\\.0" "phiopt1"} } */
+ /* { dg-final { scan-tree-dump "varx.*MAX_EXPR.*0\\.0" "phiopt1"} } */
+ 
+ float repl2 (float vary)
+ {
+   if (vary > 1.0)
+     return 1.0;
+   else if (vary < 0.0)
+     return 0.0;
+   else
+     return vary;
+ }
+ 
+ /* Should be turned to
+ 
+    vary_4 = MAX_EXPR <0.0, vary_2>;
+    vary_5 = MIN_EXPR <vary_4, 1.0e+0>;  */
+ 
+ /* { dg-final { scan-tree-dump "vary.*MAX_EXPR.*0\\.0" "phiopt1"} } */
+ /* { dg-final { scan-tree-dump "vary.*MIN_EXPR.*1\\.0" "phiopt1"} } */
+ 
+ float repl3 (float varz, float vara, float varb)
+ {
+   if (varz > vara)
+     return vara;
+   else if (varz < varb)
+     return varb;
+   else
+     return varz;
+ }
+ 
+ /* Should be turned to
+ 
+   if (varz_2 > vara_3) goto <L4>; else goto <L1>;
+ 
+ <L1>:;
+   vara_6 = MAX_EXPR <varb_5, varz_2>;  */
+ 
+ /* { dg-final { scan-tree-dump "if .*varz" "phiopt1"} } */
+ /* { dg-final { scan-tree-dump "vara.*MAX_EXPR" "phiopt1"} } */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]