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] new tree-ssa pass (documented too)


This new pass combines some adjacent return statements so that
the normal optimizations can happen with their values.  This is
already done on the RTL level so the even the RTL does not change
when this is run except when some tree optimizations act on those
statements.

For an example:
struct a
{
  int i;
  int j;
  int k;
};
struct a f(int i, int j, int k, int o, int p)
{
  if (p)
    return (struct a){i,j,k};
  return (struct a){k,o,p};
}
before gets compiled to (PPC):
_f:
        cmpwi cr0,r8,0
        beq- cr0,L2
        stw r4,0(r3)
        stw r5,4(r3)
        stw r6,8(r3)
        stw r4,-48(r1)
        stw r5,-44(r1)
        stw r6,-40(r1)
        blr
L2:
        stw r6,0(r3)
        stw r7,4(r3)
        stw r8,8(r3)
        stw r6,-32(r1)
        stw r7,-28(r1)
        stw r8,-24(r1)
        blb
After this patch:
 _f:
        cmpwi cr7,r8,0
        mr r2,r3
        mr r0,r6
        li r9,0
        beq- cr7,L4
        mr r0,r4
        mr r7,r5
        mr r9,r6
L4:
        stw r0,0(r2)
        stw r7,4(r2)
        stw r9,8(r2)
        blr

Notice how the stores are gone in this case as SRA happens on the struct now.

This has been on the lno branch since March 11 and has caused no complaints yet
and I have bootstrapped on powerpc-apple-darwin7.3.0 with no regressions.
This is also a step to fix PR optimization/14135 (which shows up in the java
front-end).


OK?

ChangeLog:

	* tree-ssa-return.c: New file.
	* tree-pass.h (pass_return): Declare.
	* tree-optimize (init_tree_optimization_passes):
	Add pass_return.
	* timevar.def (TV_TREE_RETURN): New.

Patch:
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 2.15
diff -u -p -r2.15 tree-optimize.c
--- tree-optimize.c	13 May 2004 06:39:48 -0000	2.15
+++ tree-optimize.c	14 May 2004 13:21:33 -0000
@@ -283,6 +283,7 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_rename_ssa_copies);
   NEXT_PASS (pass_early_warn_uninitialized);
   NEXT_PASS (pass_dce);
+  NEXT_PASS (pass_return);
   NEXT_PASS (pass_dominator);
   NEXT_PASS (pass_redundant_phi);
   NEXT_PASS (DUP_PASS (pass_dce));
@@ -294,6 +295,7 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_del_pta);
   NEXT_PASS (pass_profile);
   NEXT_PASS (pass_lower_complex);
+  NEXT_PASS (DUP_PASS (pass_return));
   NEXT_PASS (pass_sra);
   NEXT_PASS (DUP_PASS (pass_rename_ssa_copies));
   NEXT_PASS (DUP_PASS (pass_dominator));
Index: tree-pass.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pass.h,v
retrieving revision 2.1
diff -u -p -r2.1 tree-pass.h
--- tree-pass.h	13 May 2004 06:39:48 -0000	2.1
+++ tree-pass.h	14 May 2004 13:21:33 -0000
@@ -125,6 +125,7 @@ extern struct tree_opt_pass pass_dse;
 extern struct tree_opt_pass pass_nrv;
 extern struct tree_opt_pass pass_remove_useless_vars;
 extern struct tree_opt_pass pass_rename_ssa_copies;
+extern struct tree_opt_pass pass_return;


#endif /* GCC_TREE_PASS_H */
Index: tree-ssa-return.c
===================================================================
RCS file: tree-ssa-return.c
diff -N tree-ssa-return.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tree-ssa-return.c 14 May 2004 13:21:33 -0000
@@ -0,0 +1,232 @@
+/* Optimization of return nodes by merging them into one basic block.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "errors.h"
+#include "ggc.h"
+#include "tree.h"
+#include "flags.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "basic-block.h"
+#include "timevar.h"
+#include "diagnostic.h"
+#include "tree-flow.h"
+#include "tree-pass.h"
+#include "tree-dump.h"
+
+static void tree_ssa_return (void);
+
+
+/* Build a temporary. Make sure and register it to be renamed. */
+
+static tree
+make_temp (tree type)
+{
+ tree t = create_tmp_var (type, NULL);
+ add_referenced_tmp_var (t);
+ bitmap_set_bit (vars_to_rename, var_ann (t)->uid);
+ return t;
+}
+
+
+static void
+tree_ssa_return (void)
+{
+ basic_block bb;
+
+ /* Search every basic block for return nodes we may be able to optimize. */
+ FOR_EACH_BB (bb)
+ {
+ tree returnstmt = last_stmt (bb);
+ edge pred = bb->pred;
+ basic_block bb_other = NULL;
+ tree returnstmt_other;
+ basic_block new_bb = NULL;
+ tree new_var = NULL;
+ block_stmt_iterator bsi, bsi_other, new_bsi;
+ tree ret_decl;
+ tree type;
+
+ /* If we have no predecessor, we can not do this for
+ the only basic block. */
+ if (!pred)
+ continue;
+
+ /* Cannot do this if there is no statements. */
+ if (!returnstmt)
+ continue;
+
+ if (TREE_CODE (returnstmt) == RETURN_EXPR)
+ ;
+ else
+ continue;
+
+ /* Only do this optimization for basic blocks which
+ have only one predecessor. */
+ if (!pred || pred->pred_next)
+ continue;
+
+ /* Only do this for predecessor which are only conditional ones. */
+ if (pred->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))
+ ;
+ else
+ continue;
+
+ /* Cannot do this optimization if predecessor is abnormal. */
+ if (pred->flags & EDGE_ABNORMAL)
+ continue;
+
+ /* No reason to do this if we are not returning a value. */
+ if (TREE_OPERAND (returnstmt, 0) == NULL)
+ continue;
+
+ /* Make sure that the predecessor's successor is not an abnormal. */
+ if (pred->src->succ->flags & EDGE_ABNORMAL)
+ continue;
+
+ /* Find the other basic block which is connected to the predecessor. */
+ if (pred->src->succ->dest == bb)
+ bb_other = pred->src->succ->succ_next->dest;
+ else
+ bb_other = pred->src->succ->dest;
+
+
+ /* If we do not have a basic block for the other edge, just continue. */
+ if (!bb_other)
+ continue;
+
+
+ /* Only do the optimization if are bb_other is only linked from one BB. */
+ if (bb_other->pred->src != pred->src)
+ continue;
+ else if (bb_other->pred->pred_next)
+ continue;
+
+ returnstmt_other = last_stmt (bb_other);
+
+ /* Cannot do the optimization if the other basic block does not
+ end with a return. */
+ if (!returnstmt_other || TREE_CODE (returnstmt_other) != RETURN_EXPR)
+ continue;
+
+ /* No reason to do this if we are not returning a value. */
+ if (TREE_OPERAND (returnstmt_other, 0) == NULL)
+ continue;
+
+ /* If we do not have a modify expression on both returns, there is no point
+ in doing this optimization. */
+ if (TREE_CODE (TREE_OPERAND (returnstmt, 0)) != MODIFY_EXPR)
+ continue;
+
+ if (TREE_CODE (TREE_OPERAND (returnstmt_other, 0)) != MODIFY_EXPR)
+ continue;
+
+ /* Create the new basic block. */
+ new_bb = create_empty_bb (bb_other);
+
+ /* Redirect the two basic blocks (the ones with the returns)
+ to the new basic block. */
+ redirect_edge_and_branch (bb->succ, new_bb);
+ redirect_edge_and_branch (bb_other->succ, new_bb);
+
+ bsi = bsi_last (bb);
+ bsi_other = bsi_last (bb_other);
+
+
+ ret_decl = TREE_OPERAND (TREE_OPERAND (returnstmt, 0), 0);
+
+ type = TREE_TYPE (ret_decl);
+
+ /* Add the new variable to hold the return values. */
+ new_var = make_temp (type);
+
+ if (TREE_CODE (ret_decl) == SSA_NAME)
+ ret_decl = SSA_NAME_VAR (ret_decl);
+
+ /* Assign the new temp variable to hold the return value of
+ the first side of the branch. */
+ bsi_insert_after (&bsi, build (MODIFY_EXPR, type, new_var,
+ TREE_OPERAND (TREE_OPERAND (returnstmt, 0), 1)),
+ BSI_NEW_STMT);
+
+
+ /* Do the other side. */
+
+ bsi_insert_after (&bsi_other, build (MODIFY_EXPR, type, new_var,
+ TREE_OPERAND (TREE_OPERAND (returnstmt_other,
+ 0), 1)),
+ BSI_NEW_STMT);
+
+
+ /* Build the new basic block which continues the return. */
+ new_bsi = bsi_last (new_bb);
+ bsi_insert_after (&new_bsi, build1 (RETURN_EXPR, void_type_node,
+ build (MODIFY_EXPR, type, ret_decl,
+ new_var)), TSI_NEW_STMT);
+
+
+
+ /* Make sure that the return value gets renamed if needed */
+ bitmap_set_bit (vars_to_rename, var_ann (ret_decl)->uid);
+
+ /* The new basic block exits. */
+ make_edge (new_bb, EXIT_BLOCK_PTR, 0);
+
+ /* update the DOM info if we have to. */
+ if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
+ set_immediate_dominator (CDI_DOMINATORS, new_bb, pred->src);
+ }
+
+
+ cleanup_tree_cfg ();
+}
+
+
+/* Always do these optimizations if we have SSA
+ trees to work on. */
+static bool
+gate_return (void)
+{
+ return 1;
+}
+
+struct tree_opt_pass pass_return =
+{
+ "return", /* name */
+ gate_return, /* gate */
+ tree_ssa_return, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_TREE_RETURN, /* tv_id */
+ PROP_cfg | PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */
+ | TODO_verify_ssa | TODO_rename_vars
+ | TODO_verify_flow
+};
+
+
Index: timevar.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/timevar.def,v
retrieving revision 1.27
diff -u -p -r1.27 timevar.def
--- timevar.def 13 May 2004 06:39:45 -0000 1.27
+++ timevar.def 14 May 2004 13:21:33 -0000
@@ -76,6 +76,7 @@ DEFTIMEVAR (TV_TREE_CCP , "tree CC
DEFTIMEVAR (TV_TREE_SPLIT_EDGES , "tree split crit edges")
DEFTIMEVAR (TV_TREE_PRE , "tree PRE")
DEFTIMEVAR (TV_TREE_PHIOPT , "tree linearize phis")
+DEFTIMEVAR (TV_TREE_RETURN , "tree merge returns")
DEFTIMEVAR (TV_TREE_FORWPROP , "tree forward propagate")
DEFTIMEVAR (TV_TREE_DCE , "tree conservative DCE")
DEFTIMEVAR (TV_TREE_CD_DCE , "tree aggressive DCE")
Index: doc/passes.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/passes.texi,v
retrieving revision 1.32
diff -u -p -r1.32 passes.texi
--- doc/passes.texi 13 May 2004 06:40:26 -0000 1.32
+++ doc/passes.texi 14 May 2004 13:21:33 -0000
@@ -274,6 +274,13 @@ that is stored in memory is considered u
times throughout the optimization process. It is located in
@file{tree-ssa-dce.c} and is described by @code{pass_dce}.


+@item Combine return statements
+
+This pass scans the function return statements that can be combined
+together so other optimizations can happen on them.  This pass is
+run twice throughout the optimization process.  It is located in
+@file{tree-ssa-return.c} and is described by @code{pass_return}.
+
 @item Dominator optimizations

This pass performs trivial dominator-based copy and constant propagation,

Attachment: returnpass.diff.txt
Description: Text document


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