From: Andrew Pinski Date: Wed, 19 May 2004 03:35:19 +0000 (+0000) Subject: tree-ssa-phiopt.c (abs_replacement): New function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=cc52902d97894d218cf6acfd2aa1b904cb4c62e8;p=gcc.git 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 From-SVN: r82017 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 331c634c100..cff555cea4a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -40,6 +40,12 @@ 2004-05-18 Andrew Pinski Jeff Law + * 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 01ab2bb7439..001a935fd80 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 + Jeff Law + + * 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 b651ae32cf9..fb01bb8d858 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 00000000000..009dce45efa --- /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 bc339c808bf..7648bc090d6 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. */