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]

[RFC] Use fold to do phi optimizations


While experimenting with phiopt and getting bored about the code duplication it has, I tried this attempt at reorganizing substantially the way it works. With this patch, phiopt will create GENERIC for the condition block and the other_block, creates a COND_EXPR from these and the PHI tries to fold it, and if the folding succeeds it replaces the phi with the gimplified result.

The phi optimization succeeds if it can eat all of the statements in the other_block (or if it is empty, of course). For now, the only GENERIC constructs that are searched backwards are casts, but it could be possible to look for more constructs.

This adds optimizations such as synthesizing MIN_EXPR/MAX_EXPR, so I'm also removing from gimplify_expr the gimplification of MIN_EXPRs and MAX_EXPRs; they become valid GIMPLE binary operations.

It could do more such as (A & 2 ? 2 : 0) ==> A & 2 with some tweaks to fold: an example is in the fold-const.c hunk of the attached patch, necessary to obtain the same replacements that were in value_replacement.

I've not bootstrapped nor regtested it (except for checking that it passes the few phiopt tests in the tree-ssa test suite), it creates too much garbage, etc. etc.; I just wanted to ask if the concept seems sound.

Paolo

2004-06-02 Paolo Bonzini <bonzini@gnu.org>

	* tree-ssa-phiopt.c (conditional_replacement, value_replacement,
	abs_replacement): Remove.
	(tree_combine_replacement, tree_combine_backwards,
	gimplify_result, bsi_prev_executable): New.
	(empty_block_p): Use bsi_prev_executable.
	(replace_phi_with_stmt): Do not insert the new statement here.
	(tree_ssa_phiopt): Call tree_combine_replacement.
	* fold-const.c (fold): Fold A OP B ? C : A like
	!(A OP B) ? A : C, if A OP B can be inverted.
	* gimplify.c (gimplify_minimax_expr): Remove.
	(gimplify_expr): Do not call it.

*** gcc-save/gcc/tree-ssa-phiopt.c	2004-05-24 10:39:18.000000000 +0200
--- gcc/gcc/tree-ssa-phiopt.c	2004-06-02 23:40:49.000000000 +0200
***************
*** 37,45 ****
  #include "langhooks.h"
  
  static void tree_ssa_phiopt (void);
! static bool conditional_replacement (basic_block, tree, tree, tree);
! static bool value_replacement (basic_block, tree, tree, tree);
! static bool abs_replacement (basic_block, tree, tree, tree);
  static void replace_phi_with_stmt (block_stmt_iterator, basic_block,
  				   basic_block, tree, tree);
  static bool candidate_bb_for_phi_optimization (basic_block,
--- 37,43 ----
  #include "langhooks.h"
  
  static void tree_ssa_phiopt (void);
! static bool tree_combine_replacement (basic_block, tree, tree, tree);
  static void replace_phi_with_stmt (block_stmt_iterator, basic_block,
  				   basic_block, tree, tree);
  static bool candidate_bb_for_phi_optimization (basic_block,
***************
*** 47,111 ****
  					       basic_block *);
  static bool empty_block_p (basic_block);
  
! /* This pass eliminates PHI nodes which can be trivially implemented as
!    an assignment from a conditional expression.  ie if we have something
!    like:
  
!      bb0:
        if (cond) goto bb2; else goto bb1;
!      bb1:
!      bb2:
!       x = PHI (0 (bb1), 1 (bb0)
  
!    We can rewrite that as:
!     
!      bb0:
!      bb1:
!      bb2:
!       x = cond;
! 
!    bb1 will become unreachable and bb0 and bb2 will almost always
!    be merged into a single block.  This occurs often due to gimplification
!     of conditionals. 
!    
!    Also done is the following optimization:
  
!      bb0:
        if (a != b) goto bb2; else goto bb1;
!      bb1:
!      bb2:
!       x = PHI (a (bb1), b (bb0))
! 
!    We can rewrite that as:
! 
!      bb0:
!      bb1:
!      bb2:
!       x = b;
! 
!    This can sometimes occur as a result of other optimizations.  A
!    similar transformation is done by the ifcvt RTL optimizer. 
  
!    This pass also eliminates PHI nodes which are really absolute 
!    values.  i.e. if we have something like:
  
!      bb0:
        if (a >= 0) goto bb2; else goto bb1;
!      bb1:
        x = -a;
!      bb2:
!       x = PHI (x (bb1), a (bb0));
  
-    We can rewrite that as:
  
!      bb0:
!      bb1:
!      bb2:
!       x = ABS_EXPR< a >;
! 
!    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
  tree_ssa_phiopt (void)
--- 45,97 ----
  					       basic_block *);
  static bool empty_block_p (basic_block);
  
! /* This pass eliminates PHI nodes which can be trivially replaced with
!    assignments from constants or expressions (such as conditionals,
!    ABS_EXPRs, MIN_EXPRs, MAX_EXPRs, SAT_PLUS_EXPRs and SAT_MINUS_EXPRs).
!    The core of the optimization is in fold-const.c: all we do here is
!    to create COND_EXPRs back from the PHI nodes, pass them to fold-const.c,
!    and gimplify the result again if it is not a COND_EXPR.
  
!    The rewrites we perform are:
! 
!      bb0:                                               bb0:
        if (cond) goto bb2; else goto bb1;
!      bb1:                                      =>       bb1:
!      bb2:                                               bb2:
!       x = PHI (0 (bb1), 1 (bb0)	                          x = cond;
  
!    This occurs often due to gimplification of conditionals. 
  
!      bb0:                                               bb0:
        if (a != b) goto bb2; else goto bb1;
!      bb1:                                     =>        bb1:
!      bb2:                                               bb2:
!       x = PHI (a (bb1), b (bb0))                          x = b;
  
!    This can sometimes occur as a result of other optimizations.
  
!      bb0:                                               bb0:
        if (a >= 0) goto bb2; else goto bb1;
!      bb1:                                     =>        bb1:
        x = -a;
!      bb2:                                               bb2:
!       x = PHI (x (bb1), a (bb0));                         x = ABS_EXPR (a);
  
  
! 
!      bb0:                                               bb0:
!       if (a COND b) goto bb2; else goto bb1;
!      bb1:                                     =>        bb1:
!      bb2:                                               bb2:
!       x = PHI (a (bb1), b (bb0));                         x = MIN_EXPR (a, b);
! 
!    Where COND is <, <=, > or >=.  A similar optimization can happen when
!    the condition is "b COND a"; depending on the original code, a MAX_EXPR
!    may result.
!     
!    Most of these cases are already handled by the ifcvt RTL optimizer.
!    In all these transforms, bb1 will become unreachable and bb0 and bb2 will
!    almost always be merged into a single block.  */
  
  static void
  tree_ssa_phiopt (void)
***************
*** 127,141 ****
  	  arg0 = PHI_ARG_DEF (phi, 0);
  	  arg1 = PHI_ARG_DEF (phi, 1);
  	    
! 	  /* Do the replacement of conditional if it can be done.  */
! 	    if (conditional_replacement (bb, phi, arg0, arg1)
! 		|| value_replacement (bb, phi, arg0, arg1)
! 		|| abs_replacement (bb, phi, arg0, arg1))
! 	      {
! 		/* We have done the replacement so we need to rebuild the
! 		   cfg when this pass is complete.  */
! 		removed_phis = true;
! 	      }
  	}
      }
  
--- 113,122 ----
  	  arg0 = PHI_ARG_DEF (phi, 0);
  	  arg1 = PHI_ARG_DEF (phi, 1);
  	    
! 	  /* Do the replacement of conditional if it can be done.  If we
! 	     do it, we need to rebuild the cfg when this pass is complete.  */
! 	  if (tree_combine_replacement (bb, phi, arg0, arg1))
! 	    removed_phis = true;
  	}
      }
  
***************
*** 145,150 ****
--- 126,140 ----
      cleanup_tree_cfg ();
  }
  
+ static void
+ bsi_prev_executable (block_stmt_iterator *bsi)
+ {
+   while (!bsi_end_p (*bsi)
+ 	  && (TREE_CODE (bsi_stmt (*bsi)) == LABEL_EXPR
+ 	      || IS_EMPTY_STMT (bsi_stmt (*bsi))))
+     bsi_prev (bsi);
+ }
+ 
  /* Return TRUE if block BB has no executable statements, otherwise return
     FALSE.  */
  static bool
***************
*** 153,168 ****
    block_stmt_iterator bsi;
  
    /* BB must have no executable statements.  */
!   bsi = bsi_start (bb);
!   while (!bsi_end_p (bsi)
! 	  && (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR
! 	      || IS_EMPTY_STMT (bsi_stmt (bsi))))
!     bsi_next (&bsi);
!   
!   if (!bsi_end_p (bsi))
!     return false;
! 
!   return true;
  }
  
  /* BB is a basic block which has only one PHI node with precisely two
--- 143,151 ----
    block_stmt_iterator bsi;
  
    /* BB must have no executable statements.  */
!   bsi = bsi_last (bb);
!   bsi_prev_executable (&bsi); 
!   return bsi_end_p (bsi);
  }
  
  /* BB is a basic block which has only one PHI node with precisely two
***************
*** 228,233 ****
--- 211,272 ----
    return true;
  }
  
+ /* Recursively create MODIFY_EXPRs for the elements of the expressioon
+    EXPR, inserting them after the position indicated by BSI.  */
+ static tree
+ gimplify_result (block_stmt_iterator *bsi, tree result, tree expr, tree orig_stmt)
+ {
+   enum tree_code code;
+   int class;
+   tree t, arg0, arg1, type, new_stmt;
+ 
+   STRIP_NOPS (expr);
+   code = TREE_CODE (expr);
+   type = TREE_TYPE (expr);
+   class = TREE_CODE_CLASS (code);
+ 
+   if (class == '1' || class == '2' || class == '<')
+     {
+       arg0 = TREE_OPERAND (expr, 0);
+       if (!is_gimple_val (arg0))
+         {
+           t = make_rename_temp (type, NULL);
+           arg0 = gimplify_result (bsi, t, arg0, orig_stmt);
+         }
+     }
+ 
+   switch (class)
+     {
+     case '1':
+       expr = build1 (code, type, arg0);
+       break;
+ 
+     case '2': case '<':
+       arg1 = TREE_OPERAND (expr, 0);
+       if (!is_gimple_val (arg1))
+ 	{
+           t = make_rename_temp (type, NULL);
+           arg1 = gimplify_result (bsi, t, arg1, orig_stmt);
+ 	}
+ 
+       expr = build2 (code, type, arg0, arg1);
+       break;
+ 
+     default:
+       if (is_gimple_val (expr))
+ 	break;
+ 
+       abort ();
+     }
+ 
+   new_stmt = build2 (MODIFY_EXPR, type, result, expr);
+   SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
+   TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
+ 
+   bsi_insert_after (bsi, new_stmt, BSI_NEW_STMT);
+   return new_stmt;
+ }
+ 
  /* Replace PHI in block BB with statement NEW.  NEW is inserted after
     BSI.  Remove the edge from COND_BLOCK which does not lead to BB (COND_BLOCK
     is known to have two edges, one of which must reach BB).  */
***************
*** 236,244 ****
  replace_phi_with_stmt (block_stmt_iterator bsi, basic_block bb,
  		       basic_block cond_block, tree phi, tree new)
  {
-   /* Insert our new statement at the head of our block.  */
-   bsi_insert_after (&bsi, new, BSI_NEW_STMT);
-   
    /* Register our new statement as the defining statement for
       the result.  */
    SSA_NAME_DEF_STMT (PHI_RESULT (phi)) = new;
--- 275,280 ----
***************
*** 277,497 ****
  	      bb->index);
  }
  
! /*  The function conditional_replacement does the main work of doing the
!     conditional 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 PHI.  Likewise for ARG1.   */
! 
! static bool
! conditional_replacement (basic_block bb, tree phi, tree arg0, tree arg1)
  {
!   tree result;
!   tree old_result = NULL;
!   basic_block other_block = NULL;
!   basic_block cond_block = NULL;
!   tree new, cond;
!   block_stmt_iterator bsi;
!   edge true_edge, false_edge;
!   tree new_var = NULL;
! 
!   /* The PHI arguments have the constants 0 and 1, then convert
!      it to the conditional.  */
!   if ((integer_zerop (arg0) && integer_onep (arg1))
!       || (integer_zerop (arg1) && integer_onep (arg0)))
!     ;
!   else
!     return false;
!   
!   if (!candidate_bb_for_phi_optimization (bb, &cond_block, &other_block)
!       || !empty_block_p (other_block))
!     return false;
! 										
!   /* If the condition is not a naked SSA_NAME and its type does not
!      match the type of the result, then we have to create a new
!      variable to optimize this case as it would likely create
!      non-gimple code when the condition was converted to the
!      result's type.  */
!   cond = COND_EXPR_COND (last_stmt (cond_block));
!   result = PHI_RESULT (phi);
!   if (TREE_CODE (cond) != SSA_NAME
!       && !lang_hooks.types_compatible_p (TREE_TYPE (cond), TREE_TYPE (result)))
!     {
!       new_var = make_rename_temp (TREE_TYPE (cond), NULL);
!       old_result = cond;
!       cond = new_var;
!     }
!   
!   /* If the condition was a naked SSA_NAME and the type is not the
!      same as the type of the result, then convert the type of the
!      condition.  */
!   if (!lang_hooks.types_compatible_p (TREE_TYPE (cond), TREE_TYPE (result)))
!     cond = fold_convert (TREE_TYPE (result), cond);
!   
!   /* We need to know which is the true edge and which is the false
!      edge so that we know when to invert the condition below.  */
!   extract_true_false_edges_from_block (cond_block, &true_edge, &false_edge);
!       
!   /* Insert our new statement at the head of our block.  */
!   bsi = bsi_start (bb);
!   
!   if (old_result)
!     {
!       tree new1;
!       if (TREE_CODE_CLASS (TREE_CODE (old_result)) != '<')
! 	return false;
!       
!       new1 = build (TREE_CODE (old_result), TREE_TYPE (result),
! 		    TREE_OPERAND (old_result, 0),
! 		    TREE_OPERAND (old_result, 1));
!       
!       new1 = build (MODIFY_EXPR, TREE_TYPE (result), new_var, new1);
!       bsi_insert_after (&bsi, new1, BSI_NEW_STMT);
!     }
!   
!   /* At this point we know we have a COND_EXPR with two successors.
!      One successor is BB, the other successor is an empty block which
!      falls through into BB.
!   
!      There is a single PHI node at the join point (BB) and its arguments
!      are constants (0, 1).
!   
!      So, given the condition COND, and the two PHI arguments, we can
!      rewrite this PHI into non-branching code: 
!   
!        dest = (COND) or dest = COND'
!   
!      We use the condition as-is if the argument associated with the
!      true edge has the value one or the argument associated with the
!      false edge as the value zero.  Note that those conditions are not
!      the same since only one of the outgoing edges from the COND_EXPR
!      will directly reach BB and thus be associated with an argument.  */
!   if ((PHI_ARG_EDGE (phi, 0) == true_edge && integer_onep (arg0))
!       || (PHI_ARG_EDGE (phi, 0) == false_edge && integer_zerop (arg0))
!       || (PHI_ARG_EDGE (phi, 1) == true_edge && integer_onep (arg1))
!       || (PHI_ARG_EDGE (phi, 1) == false_edge && integer_zerop (arg1)))
!     {
!       new = build (MODIFY_EXPR, TREE_TYPE (PHI_RESULT (phi)),
! 		    PHI_RESULT (phi), cond);
!     }
!   else
!     {
!       tree cond1 = invert_truthvalue (cond);
!       
!       cond = cond1;
!       /* If what we get back is a conditional expression, there is no
! 	  way that it can be gimple.  */
!       if (TREE_CODE (cond) == COND_EXPR)
! 	return false; 
! 
!       /* If what we get back is not gimple try to create it as gimple by
! 	 using a temporary variable.   */
!       if (is_gimple_cast (cond)
! 	  && !is_gimple_val (TREE_OPERAND (cond, 0)))
! 	{
! 	  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);
! 	}
!       
!       if (TREE_CODE (cond) == TRUTH_NOT_EXPR
! 	  &&  !is_gimple_val (TREE_OPERAND (cond, 0)))
! 	return false;
! 
!       new = build (MODIFY_EXPR, TREE_TYPE (PHI_RESULT (phi)),
! 		    PHI_RESULT (phi), cond);
!     }
!   
!   replace_phi_with_stmt (bsi, bb, cond_block, phi, new);
! 
!   /* Note that we optimized this PHI.  */
!   return true;
! }
! 
! /*  The function value_replacement does the main work of doing the value
!     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
! value_replacement (basic_block bb, tree phi, tree arg0, tree arg1)
! {
!   tree result;
!   basic_block other_block = NULL;
!   basic_block cond_block = NULL;
!   tree new, cond;
!   edge true_edge, false_edge;
! 
!   /* If the type says honor signed zeros we cannot do this
!      optimization.   */
!   if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
!     return false;
! 
!   if (!candidate_bb_for_phi_optimization (bb, &cond_block, &other_block)
!       || !empty_block_p (other_block))
!     return false;
! 
!   cond = COND_EXPR_COND (last_stmt (cond_block));
!   result = PHI_RESULT (phi);
! 
!   /* This transformation is only valid for equality comparisons.  */
!   if (TREE_CODE (cond) != NE_EXPR && TREE_CODE (cond) != EQ_EXPR)
!     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_block, &true_edge, &false_edge);
! 
!   /* At this point we know we have a COND_EXPR with two successors.
!      One successor is BB, the other successor is an empty block which
!      falls through into BB.
! 
!      The condition for the COND_EXPR is known to be NE_EXPR or EQ_EXPR.
! 
!      There is a single PHI node at the join point (BB) with two arguments.
! 
!      We now need to verify that the two arguments in the PHI node match
!      the two arguments to the equality comparison.  */
!   
!   if ((operand_equal_p (arg0, TREE_OPERAND (cond, 0), 0)
!        && operand_equal_p (arg1, TREE_OPERAND (cond, 1), 0))
!       || (operand_equal_p (arg1, TREE_OPERAND (cond, 0), 0)
! 	  && operand_equal_p (arg0, TREE_OPERAND (cond, 1), 0)))
!     {
!       edge e;
!       tree arg;
! 
!       /* For NE_EXPR, we want to build an assignment result = arg where
! 	 arg is the PHI argument associated with the true edge.  For
! 	 EQ_EXPR we want the PHI argument associated with the false edge.  */
!       e = (TREE_CODE (cond) == NE_EXPR ? true_edge : false_edge);
! 
!       /* Unfortunately, E may not reach BB (it may instead have gone to
! 	 OTHER_BLOCK).  If that is the case, then we want the single outgoing
! 	 edge from OTHER_BLOCK which reaches BB and represents the desired
! 	 path from COND_BLOCK.  */
!       if (e->dest == other_block)
! 	e = e->dest->succ;
! 
!       /* Now we know the incoming edge to BB that has the argument for the
! 	 RHS of our new assignment statement.  */
!       if (PHI_ARG_EDGE (phi, 0) == e)
! 	arg = arg0;
        else
! 	arg = arg1;
! 
!       /* Build the new assignment.  */
!       new = build (MODIFY_EXPR, TREE_TYPE (result), result, arg);
! 
!       replace_phi_with_stmt (bsi_start (bb), bb, cond_block, phi, new);
! 
!       /* Note that we optimized this PHI.  */
!       return true;
      }
!   return false;
  }
  
  /*  The function absolute_replacement does the main work of doing the absolute
--- 313,363 ----
  	      bb->index);
  }
  
! static int
! tree_combine_backwards (block_stmt_iterator *bsi, tree *p_rhs)
  {
!   tree *rhs0 = NULL, *rhs1 = NULL;
!   tree rhs = copy_node (*p_rhs);
!   enum tree_code code = TREE_CODE (rhs);
!   int class = TREE_CODE_CLASS (code);
! 
!   if (class == '1')
!     {
!       rhs0 = &TREE_OPERAND (rhs, 0);
!       rhs1 = NULL;
!     }
!   else if (class == '2' || class == '<')
!     {
!       rhs0 = &TREE_OPERAND (rhs, 0);
!       rhs1 = &TREE_OPERAND (rhs, 1);
!     }
! 
!   while (!bsi_end_p (*bsi))
!     {
!       tree dest, value, stmt = bsi_stmt (*bsi);
!       bsi_prev (bsi);
!       bsi_prev_executable (bsi);
!       if (TREE_CODE (stmt) != MODIFY_EXPR)
! 	break;
! 
!       /* If we already found the assignment, but it was not the only
! 	 executable statement in OTHER_BLOCK, see if it is simply a
! 	 NOP_EXPR.  */
!       dest = TREE_OPERAND (stmt, 0);
!       value = TREE_OPERAND (stmt, 1);
!       if (TREE_CODE (value) != NOP_EXPR)
! 	break;
! 
!       if (rhs0 && dest == *rhs0)
!         *rhs0 = copy_node (value), rhs0 = &TREE_OPERAND (*rhs0, 0);
!       else if (rhs1 && dest == *rhs1)
!         *rhs1 = copy_node (value), rhs1 = &TREE_OPERAND (*rhs1, 0);
        else
! 	break;
      }
! 
!   *p_rhs = rhs;
!   return bsi_end_p (*bsi);
  }
  
  /*  The function absolute_replacement does the main work of doing the absolute
***************
*** 500,653 ****
      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
! abs_replacement (basic_block bb, tree phi, tree arg0, tree arg1)
  {
    tree result;
    basic_block other_block = NULL;
    basic_block cond_block = NULL;
!   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;
- 
-   /* If the type says honor signed zeros we cannot do this
-      optimization.   */
-   if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
-     return false;
  
    if (!candidate_bb_for_phi_optimization (bb, &cond_block, &other_block))
      return false;
  
!   /* OTHER_BLOCK must have only one executable statement which must have the
!      form arg0 = -arg1 or arg1 = -arg0.  */
!   bsi = bsi_start (other_block);
!   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_block));
!   result = PHI_RESULT (phi);
! 
!   /* Only relationals comparing arg[01] against zero are interesting.  */
!   cond_code = TREE_CODE (cond);
!   if (cond_code != GT_EXPR && cond_code != GE_EXPR
!       && cond_code != LT_EXPR && cond_code != LE_EXPR)
!     return false;
  
!   /* Make sure the conditional is arg[01] OP y.   */
!   if (TREE_OPERAND (cond, 0) != rhs)
!     return false;
  
!   if (FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1)))
! 	       ? real_zerop (TREE_OPERAND (cond, 1))
! 	       : integer_zerop (TREE_OPERAND (cond, 1)))
!     ;
!   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_block, &true_edge, &false_edge);
  
!   /* For GT_EXPR/GE_EXPR, if the true edge goes to OTHER_BLOCK, then we
!      will need to negate the result.  Similarly for LT_EXPR/LE_EXPR if
!      the false edge goes to OTHER_BLOCK.  */
!   if (cond_code == GT_EXPR || cond_code == GE_EXPR)
!     e = true_edge;
!   else
!     e = false_edge;
!   
!   if (e->dest == other_block)
!     negate = true;
!   else
!     negate = false;
    
!   if (negate)
!     lhs = make_rename_temp (TREE_TYPE (result), NULL);
!   else
!     lhs = result;
! 
!   /*  Build the modify expression with abs expression.   */
!   new = build (MODIFY_EXPR, TREE_TYPE (lhs),
!                lhs, build1 (ABS_EXPR, TREE_TYPE (lhs), rhs));
  
    replace_phi_with_stmt (bsi_start (bb), bb, cond_block, phi, new);
  
-   if (negate)
-     {
- 
-       /* 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.  */
-       bsi = bsi_start (bb);
-       bsi_next (&bsi);
-       new = build (MODIFY_EXPR, TREE_TYPE (result),
-                    result, build1 (NEGATE_EXPR, TREE_TYPE (lhs), lhs));
- 
-       bsi_insert_after (&bsi, new, BSI_NEW_STMT);
- 
-       /* Register the new statement as defining the temporary -- this is
- 	 normally done by replace_phi_with_stmt, but the link will be wrong
- 	 if we had to negate the resulting value.  */
-       SSA_NAME_DEF_STMT (result) = new;
-     }
- 
    /* Note that we optimized this PHI.  */
    return true;
  }
  
- 
  /* Always do these optimizations if we have SSA
     trees to work on.  */						
  static bool
--- 366,437 ----
      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
! tree_combine_replacement (basic_block bb, tree phi, tree arg0, tree arg1)
  {
    tree result;
    basic_block other_block = NULL;
    basic_block cond_block = NULL;
!   tree new, cond, rhs, lhs, stmt, cond_stmt;
    block_stmt_iterator bsi;
    edge true_edge, false_edge;
  
    if (!candidate_bb_for_phi_optimization (bb, &cond_block, &other_block))
      return false;
  
!   if (!empty_block_p (other_block))
!     {
!       bsi = bsi_last (other_block);
!       bsi_prev_executable (&bsi);
!       stmt = bsi_stmt (bsi);
!       if (TREE_CODE (stmt) != MODIFY_EXPR)
!         return false;
! 
!       lhs = TREE_OPERAND (stmt, 0);
!       rhs = TREE_OPERAND (stmt, 1);
!       if (lhs == arg0)
!         rhs = arg0 = copy_node (rhs);
!       else if (lhs == arg1)
!         rhs = arg1 = copy_node (rhs);
        else
!         return false;
  
!       if (!tree_combine_backwards (&bsi, &rhs))
!         return false;
!     }
  
!   cond_stmt = last_stmt (cond_block);
!   cond = COND_EXPR_COND (cond_stmt);
!   bsi = bsi_last (cond_block);
!   tree_combine_backwards (&bsi, &cond);
  
    /* We need to know which is the true edge and which is the false
!      edge so that we know if have direct or inverse comparison.
!      If the false edge goes to OTHER_BLOCK, then we will need to
!      invert the comparison, which is easily done by swapping the PHI's
!      arguments.  */
    extract_true_false_edges_from_block (cond_block, &true_edge, &false_edge);
  
!   if (false_edge->dest == other_block)
!     {
!       tree temp = arg0;
!       arg0 = arg1;
!       arg1 = temp;
!     }
    
!   result = PHI_RESULT (phi);
!   cond = fold (build3 (COND_EXPR, TREE_TYPE (result), cond, arg0, arg1));
!   if (TREE_CODE (cond) == COND_EXPR)
!     return false;
  
+   /*  Build the MODIFY_EXPR, gimplifying cond along the way.   */
+   bsi = bsi_start (bb);
+   new = gimplify_result (&bsi, result, cond, cond_stmt);
    replace_phi_with_stmt (bsi_start (bb), bb, cond_block, phi, new);
  
    /* Note that we optimized this PHI.  */
    return true;
  }
  
  /* Always do these optimizations if we have SSA
     trees to work on.  */						
  static bool
***************
*** 675,677 ****
--- 459,462 ----
  };
  												
  
+ 
*** gcc-save/gcc/fold-const.c	2004-05-28 20:30:47.000000000 +0200
--- gcc/gcc/fold-const.c	2004-06-02 23:32:26.000000000 +0200
***************
*** 8394,8399 ****
--- 8523,8546 ----
  	      }
  	}
  
+       /* Try swapping the arguments and inverting the conditional.  */
+       else if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
+ 	  && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
+ 					     TREE_OPERAND (t, 2),
+ 					     TREE_OPERAND (arg0, 1))
+ 	  && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 2)))))
+ 	{
+ 	  tree arg2 = TREE_OPERAND (t, 2);
+ 	  tree new_arg0 = invert_truthvalue (arg0);
+ 	  if (TREE_CODE_CLASS (TREE_CODE (new_arg0)) == '<')
+ 	    {
+ 	      tree folded = fold (build3 (COND_EXPR, type, new_arg0, arg2, arg1));
+ 	      if (TREE_CODE (folded) != COND_EXPR)
+ 		return folded;
+ 	    }
+ 	}
+ 
+ 
        /* If the second operand is simpler than the third, swap them
  	 since that produces better jump optimization results.  */
        if (tree_swap_operands_p (TREE_OPERAND (t, 1),
*** gcc-save/gcc/gimplify.c	Fri May 28 20:30:02 2004
--- gcc/gcc/gimplify.c	Wed Jun  2 22:40:45 2004
***************
*** 1577,1610 ****
    return GS_OK;
  }
  
- /* Reduce MIN/MAX_EXPR to a COND_EXPR for further gimplification.  */
- 
- static enum gimplify_status
- gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p)
- {
-   tree op1 = TREE_OPERAND (*expr_p, 0);
-   tree op2 = TREE_OPERAND (*expr_p, 1);
-   enum tree_code code;
-   enum gimplify_status r0, r1;
- 
-   if (TREE_CODE (*expr_p) == MIN_EXPR)
-     code = LE_EXPR;
-   else
-     code = GE_EXPR;
- 
-   r0 = gimplify_expr (&op1, pre_p, post_p, is_gimple_val, fb_rvalue);
-   r1 = gimplify_expr (&op2, pre_p, post_p, is_gimple_val, fb_rvalue);
- 
-   *expr_p = build (COND_EXPR, TREE_TYPE (*expr_p),
- 		   build (code, boolean_type_node, op1, op2),
- 		   op1, op2);
- 
-   if (r0 == GS_ERROR || r1 == GS_ERROR)
-     return GS_ERROR;
-   else
-     return GS_OK;
- }
- 
  /*  Build an expression for the address of T.  Folds away INDIRECT_REF to
      avoid confusing the gimplify process.  */
  
--- 1577,1582 ----
***************
*** 3400,3410 ****
  			       is_gimple_min_lval, fb_lvalue);
  	  break;
  
- 	case MIN_EXPR:
- 	case MAX_EXPR:
- 	  ret = gimplify_minimax_expr (expr_p, pre_p, post_p);
- 	  break;
- 
  	case LABEL_DECL:
  	  /* We get here when taking the address of a label.  We mark
  	     the label as "forced"; meaning it can never be removed and
--- 3372,3377 ----

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