From cc52902d97894d218cf6acfd2aa1b904cb4c62e8 Mon Sep 17 00:00:00 2001
From: Andrew Pinski <pinskia@physics.uc.edu>
Date: Wed, 19 May 2004 03:35:19 +0000
Subject: [PATCH] tree-ssa-phiopt.c (abs_replacement): New function.

        * tree-ssa-phiopt.c (abs_replacement): New function.
        (empty_block_p): New function extracted from...
        (candidate_bb_for_phi_optimization): Break out empty block test.
        (conditional_replacement): Use empty_block_p.
        (value_replacement): Similarly.

        * gcc.dg/tree-ssa/20040514-2.c: Update expected output.
        * gcc.dg/tree-ssa/20040518-2.c: New test.

Co-Authored-By: Jeff Law <law@redhat.com>

From-SVN: r82017
---
 gcc/ChangeLog                              |   6 +
 gcc/testsuite/ChangeLog                    |   4 +
 gcc/testsuite/gcc.dg/tree-ssa/20040514-2.c |   6 +-
 gcc/testsuite/gcc.dg/tree-ssa/20040518-2.c |  16 ++
 gcc/tree-ssa-phiopt.c                      | 227 +++++++++++++++++++--
 5 files changed, 237 insertions(+), 22 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040518-2.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 331c634c1005..cff555cea4aa 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -40,6 +40,12 @@
 2004-05-18  Andrew Pinski  <pinskia@physics.uc.edu>
 	    Jeff Law <law@redhat.com>
 
+	* tree-ssa-phiopt.c (abs_replacement): New function.
+	(empty_block_p): New function extracted from...
+	(candidate_bb_for_phi_optimization): Break out empty block test.
+	(conditional_replacement): Use empty_block_p.
+	(value_replacement): Similarly.
+
 	* Makefile.in (tree-ssa-phiopt.o): Depends on flags.h.
 	* tree-ssa-phiopt.c: Include flags.h.
 	(conditional_replacement): Remove argument names from prototype.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 01ab2bb74399..001a935fd80d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -3,6 +3,10 @@
 	* gfortran.fortran-torture/execute/power.f90: Test constant integers.
 
 2004-05-18  Andrew Pinski  <pinskia@physics.uc.edu>
+            Jeff Law  <law@redhat.com>
+
+        * gcc.dg/tree-ssa/20040514-2.c: Update expected output.
+        * gcc.dg/tree-ssa/20040518-2.c: New test.
 
 	* gcc.dg/tree-ssa/20040518-1.c: New test.
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040514-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20040514-2.c
index b651ae32cf95..fb01bb8d858b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/20040514-2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/20040514-2.c
@@ -11,5 +11,7 @@ foo2 (distance, i, j)
  return t;
 }
 
-/* There should be no ABS_EXPR.  */
-/* { dg-final { scan-tree-dump-times "ABS_EXPR " 0 "dom3"} } */
+/* There should be one ABS_EXPR and no conditionals.  */
+/* { dg-final { scan-tree-dump-times "ABS_EXPR " 1 "dom3"} } */
+/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040518-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20040518-2.c
new file mode 100644
index 000000000000..009dce45efab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/20040518-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt1-details" } */
+
+int t( int i)
+{
+   int j;
+   if(i>=0)
+    j = i;
+   else
+    j = -i;
+   return j;
+}
+
+/* We should convert one COND_EXPRs into straightline code with ABS.  */
+/* { dg-final { scan-tree-dump-times "straightline" 1 "phiopt1"} } */
+/* { dg-final { scan-tree-dump-times "ABS_EXPR" 1 "phiopt1"} } */
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index bc339c808bf7..7648bc090d60 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -39,11 +39,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 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,
 					       basic_block *,
 					       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
@@ -82,8 +84,29 @@ static bool candidate_bb_for_phi_optimization (basic_block,
       x = b;
 
    This can sometimes occur as a result of other optimizations.  A
-   similar transformation is done by the ifcvt RTL optimizer.  */
-   
+   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)
 {
@@ -106,7 +129,8 @@ tree_ssa_phiopt (void)
 	    
 	  /* Do the replacement of conditional if it can be done.  */
 	    if (conditional_replacement (bb, phi, arg0, arg1)
-		|| value_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.  */
@@ -121,12 +145,32 @@ tree_ssa_phiopt (void)
     cleanup_tree_cfg ();
 }
 
+/* Return TRUE if block BB has no executable statements, otherwise return
+   FALSE.  */
+static bool
+empty_block_p (basic_block bb)
+{
+  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
    arguments.
 
    Examine both of BB's predecessors to see if one ends with a 
-   COND_EXPR and the other is an empty block.  If so, then we may
-   be able to optimize PHI nodes at the start of BB. 
+   COND_EXPR and the other is a successor of the COND_EXPR.  If so, then
+   we may be able to optimize PHI nodes at the start of BB. 
 
    If so, mark store the block with the COND_EXPR into COND_BLOCK_P
    and the other block into OTHER_BLOCK_P and return true, otherwise
@@ -138,12 +182,10 @@ candidate_bb_for_phi_optimization (basic_block bb,
 				   basic_block *other_block_p)
 {
   tree last0, last1;
-  block_stmt_iterator bsi;
   basic_block cond_block, other_block;
 
   /* One of the alternatives must come from a block ending with
-     a COND_EXPR.  The other block must be entirely empty, except
-     for labels.  */
+     a COND_EXPR.  */
   last0 = last_stmt (bb->pred->src);
   last1 = last_stmt (bb->pred->pred_next->src);
   if (last0 && TREE_CODE (last0) == COND_EXPR)
@@ -180,16 +222,6 @@ candidate_bb_for_phi_optimization (basic_block bb,
       || phi_nodes (other_block))
     return false;
   
-  /* OTHER_BLOCK must have no executable statements.  */
-  bsi = bsi_start (other_block);
-  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;
-
   *cond_block_p = cond_block;
   *other_block_p = other_block;
   /* Everything looks OK.  */
@@ -271,7 +303,8 @@ conditional_replacement (basic_block bb, tree phi, tree arg0, tree arg1)
   else
     return false;
   
-  if (!candidate_bb_for_phi_optimization (bb, &cond_block, &other_block))
+  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
@@ -397,7 +430,8 @@ value_replacement (basic_block bb, tree phi, tree arg0, tree arg1)
   if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
     return false;
 
-  if (!candidate_bb_for_phi_optimization (bb, &cond_block, &other_block))
+  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));
@@ -447,6 +481,159 @@ value_replacement (basic_block bb, tree phi, tree arg0, tree arg1)
   return false;
 }
 
+/*  The function absolute_replacement does the main work of doing the absolute
+    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
+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.  */