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]

[tree-ssa] CCP fixes [patch]


This patch brings us to the same state we were in before
switching over to GENERIC and GIMPLE.  Nothing stands out.  It's
just a collection of minor fixes here and there.

One thing that this exposed is a bug in fold().  In
execute/ieee/rbug.c, a call to fold:

-----------------------------------------------------------------------------
 <fix_trunc_expr 0x4007f348
    type <integer_type 0x4001f658 long long unsigned int unsigned DI
        size <integer_cst 0x40024300 constant 64>
        unit size <integer_cst 0x40024420 constant 8>
        align 64 symtab 0 alias set -1 precision 64 min <integer_cst 0x40024460 0> max <integer_cst 0x40024480 -1>>

    arg 0 <real_cst 0x4007f2d0
        type <real_type 0x40026ae0 double DF
            size <integer_cst 0x40024600 constant 64>
            unit size <integer_cst 0x40024820 constant 8>
            align 64 symtab 0 alias set -1 precision 64
            pointer_to_this <pointer_type 0x40029a6c>>
        constant 9.6972994020723937280000000000000000001e+18>>
-----------------------------------------------------------------------------

returns

-----------------------------------------------------------------------------
 <integer_cst 0x40083d20 type <integer_type 0x4001f658 long long unsigned int> constant 0x7fffffffffffffff>
-----------------------------------------------------------------------------

which rth confirmed is a bug somewhere in fold(), because we are
somehow losing the unsigned bit.

As usual, CCP makes it all the way to stage2 but fails the
comparison check.  I'll look at this next.


Diego.


	* tree-cfg.c (make_cond_expr_edges): If the conditional has known
	value, only make the edge to the corresponding branch.
	(tree_delete_bb): Write a warning to the dump file when removing
	blocks with executable statements.
	(first_exec_stmt): Skip over empty BIND_EXPR blocks.

	* tree-dfa.c (find_refs_in_expr): Don't look for references in non
	GIMPLE statements.
	(remove_tree_ann): Clear the annotation with memset.
	(collect_dfa_stats_r): Don't call tree_annotation.
	(find_may_aliases_for): Avoid adding the same alias more than once.
	(may_alias_p): Fix comment grammar.

	* tree-flow-inline.h (is_exec_stmt): New function.
	* tree-flow.h (FOR_EACH_REF): Guard against NULL lists.
	(FOR_EACH_REF_REV): Likewise.
	(is_exec_stmt): Declare.

	* tree-ssa-ccp.c (visit_phi_node): Reformat debug dumping output.
	(visit_expression_for): Move check for clobbering definitions
	before check for NULL expressions.
	(visit_condexpr_for): Reformat debug dumping output.
	(set_lattice_value): Remove stale comments.
	(replace_uses_in): Don't clear TF_FOLDED flag from expression.

	* tree-ssa.c (add_phi_node): If possible, associate the PHI node to
	a statement.
	(create_default_def): Create initial declarations for static
	variables with DECL_INITIAL set.
	(delete_tree_ssa): Remove annotations from variables.


Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.15
diff -d -u -p -r1.1.4.15 tree-cfg.c
--- tree-cfg.c	14 Oct 2002 17:01:53 -0000	1.1.4.15
+++ tree-cfg.c	16 Oct 2002 18:33:23 -0000
@@ -577,6 +577,7 @@ make_cond_expr_edges (bb)
   tree entry = first_stmt (bb);
   basic_block successor_bb, then_bb, else_bb;
   tree predicate;
+  bool always_true, always_false;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (entry) != COND_EXPR)
@@ -590,7 +591,7 @@ make_cond_expr_edges (bb)
 
   /* Create the following edges.
 
-	      COND_EXPR
+	     COND_EXPR
 		/ \
 	       /   \
 	    THEN   ELSE
@@ -599,10 +600,12 @@ make_cond_expr_edges (bb)
      conditional can be statically computed.  */
   predicate = COND_EXPR_COND (entry);
 
-  if (simple_cst_equal (predicate, integer_one_node) == 1)
+  always_true = (simple_cst_equal (predicate, integer_one_node) == 1);
+  if (always_true)
     else_bb = NULL;
 
-  if (simple_cst_equal (predicate, integer_zero_node) == 1)
+  always_false = (simple_cst_equal (predicate, integer_zero_node) == 1);
+  if (always_false)
     then_bb = NULL;
 
   if (then_bb)
@@ -611,6 +614,11 @@ make_cond_expr_edges (bb)
   if (else_bb)
     make_edge (bb, else_bb, EDGE_FALSE_VALUE);
 
+  /* If the conditional is always true or false, return.  The only edge we
+     needed to add has been already created above.  */
+  if (always_true || always_false)
+    return;
+
   /* If conditional is missing one of the clauses, make an edge between the
      entry block and the first block outside the conditional.  */
   if (!then_bb || !else_bb)
@@ -743,6 +751,9 @@ tree_delete_bb (bb)
     {
       fprintf (dump_file, "Removed unreachable basic block %d\n", bb->index);
       tree_dump_bb (dump_file, "", bb, 0);
+      if (TREE_CODE (first_stmt (bb)) != BIND_EXPR)
+	fprintf (dump_file, "WARNING: Block %d has executable statements.\n",
+	         bb->index);
       fprintf (dump_file, "\n");
       dump_end (TDI_cfg, dump_file);
     }
@@ -1272,15 +1283,20 @@ first_exec_stmt (entry_p)
       STRIP_WFL (stmt);
       STRIP_NOPS (stmt);
 
-      /* Dive into BIND_EXPR bodies.  */
+      /* Dive into BIND_EXPR bodies.  If the body is empty, keep going with
+	 the statement following the BIND_EXPR node.  */
       if (TREE_CODE (stmt) == BIND_EXPR)
-	return first_exec_stmt (&BIND_EXPR_BODY (stmt));
+	{
+	  tree *first = first_exec_stmt (&BIND_EXPR_BODY (stmt));
+	  if (first)
+	    return first;
+	}
 
       /* Don't consider empty_stmt_node to be executable.  Note that we
 	 actually return the container for the executable statement, not
 	 the statement itself.  This is to allow the caller to start
 	 iterating from this point.  */
-      else if (stmt != empty_stmt_node)
+      else if (is_exec_stmt (stmt))
 	return gsi_container (i);
     }
 
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.4.29
diff -d -u -p -r1.1.4.29 tree-dfa.c
--- tree-dfa.c	14 Oct 2002 17:01:53 -0000	1.1.4.29
+++ tree-dfa.c	16 Oct 2002 18:33:23 -0000
@@ -259,8 +259,8 @@ find_refs_in_expr (expr_p, ref_type, bb,
 
   /* If this reference is associated with a non SIMPLE expression, then we
      mark the parent expression non SIMPLE and recursively clobber every
-     variable referenced by PARENT_EXPR.  */
-  if (parent_expr && TREE_NOT_GIMPLE (expr))
+     variable referenced by PARENT_EXPR.  FIXME: TREE_NOT_GIMPLE must die.  */
+  if (parent_stmt && parent_expr && TREE_NOT_GIMPLE (expr))
     {
       struct clobber_data_d clobber_data;
 
@@ -273,6 +273,13 @@ find_refs_in_expr (expr_p, ref_type, bb,
       return;
     }
 
+  /* If the parent statement is marked not-gimple, don't do anything.  This
+     means that in a previous iteration we encountered a non-gimple
+     sub-expression which already clobbered all the variables in the
+     statement.  FIXME: TREE_NOT_GIMPLE must die.  */
+  if (parent_stmt && TREE_NOT_GIMPLE (parent_stmt))
+    return;
+
   /* If we found a _DECL node, create a reference to it and return.  */
   if (code == VAR_DECL || code == PARM_DECL)
     {
@@ -950,21 +957,18 @@ void
 remove_tree_ann (t)
      tree t;
 {
-  tree expr;
   tree_ann ann;
 
   /* NOTE: We can't call tree_annotation here, because it always returns
      the annotation of wrapped trees.  If T is a WFL node, we will remove
      the same annotation twice.  */
-  ann = (tree_ann *)t->common.aux;
-  if (ann == NULL)
-    return;
-
-  ann->bb = NULL;
-  delete_ref_list (ann->refs);
-  ann->currdef = NULL;
-  ann->output_ref = NULL;
-  t->common.aux = NULL;
+  ann = (tree_ann)t->common.aux;
+  if (ann)
+    {
+      delete_ref_list (ann->refs);
+      memset ((void *) ann, 0, sizeof (*ann));
+      t->common.aux = NULL;
+    }
 }
 
 
@@ -1492,7 +1496,9 @@ collect_dfa_stats_r (tp, walk_subtrees, 
   tree t = *tp;
   struct dfa_stats_d *dfa_stats_p = (struct dfa_stats_d *)data;
 
-  ann = tree_annotation (t);
+  /* Don't call tree_annotation here because it strips the WFL and NOPS
+     wrappers from T.  */
+  ann = (tree_ann)t->common.aux;
   if (ann)
     {
       dfa_stats_p->num_tree_anns++;
@@ -1730,7 +1736,9 @@ find_may_aliases_for (ptr)
       tree var = referenced_var (i);
       tree var_sym = get_base_symbol (var);
 
-      if (may_alias_p (ptr, var_sym))
+      if (may_alias_p (ptr, var_sym)
+	  /* Avoid adding duplicate aliases.  */
+	  && get_alias_index (ptr, var_sym) == -1)
 	{
 	  add_may_alias (ptr, var_sym);
 	  add_may_alias (var_sym, ptr);
@@ -1751,7 +1759,7 @@ may_alias_p (ptr, var_sym)
   tree ptr_sym = get_base_symbol (ptr);
 
   /* GLOBAL_VAR aliases every global variable and locals that have had
-     its address taken.  */
+     their addresses taken.  */
   if (ptr == global_var
       && var_sym != global_var
       && (TREE_ADDRESSABLE (var_sym)
Index: tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow-inline.h,v
retrieving revision 1.1.2.3
diff -d -u -p -r1.1.2.3 tree-flow-inline.h
--- tree-flow-inline.h	14 Oct 2002 17:01:53 -0000	1.1.2.3
+++ tree-flow-inline.h	16 Oct 2002 18:33:23 -0000
@@ -636,4 +636,11 @@ gsi_start_bb (bb)
   return gsi_start (tp);
 }
 
+static inline bool
+is_exec_stmt (t)
+     tree t;
+{
+  return (t && t != empty_stmt_node);
+}
+
 #endif /* _TREE_FLOW_INLINE_H  */
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.24
diff -d -u -p -r1.1.4.24 tree-flow.h
--- tree-flow.h	14 Oct 2002 17:01:53 -0000	1.1.4.24
+++ tree-flow.h	16 Oct 2002 18:33:23 -0000
@@ -115,7 +115,7 @@ extern const HOST_WIDE_INT M_PARTIAL;
 /* M_INITIAL modifies a V_DEF reference to indicate that the definition is
    an initial static value for the variable.  Multiple executions of this
    reference do not produce multiple definitions of the variable.  This is
-   used to model static variables in C.  For instance,
+   used to model initialization of static variables.  For instance,
 
    		static int counter = 0;
 
@@ -171,9 +171,11 @@ typedef struct ref_list_priv *ref_list;
   for (TMP = FROM, REF = TMP->ref;  TMP != TO; TMP = TMP->DIR, REF = (TMP ? TMP->ref : NULL))
 
 #define FOR_EACH_REF(REF, TMP, LIST)				\
+  if (LIST)							\
   FOR_REF_BETWEEN (REF, TMP, LIST->first, LIST->last->next, next)
 
 #define FOR_EACH_REF_REV(REF, TMP, LIST)			\
+  if (LIST)							\
   FOR_REF_BETWEEN (REF, TMP, LIST->last, LIST->first->prev, prev)
 
 
@@ -513,6 +515,7 @@ static inline void set_indirect_var	PARA
 static inline tree may_alias		PARAMS ((tree, size_t));
 static inline size_t num_may_alias	PARAMS ((tree));
 static inline int get_lineno		PARAMS ((tree));
+static inline bool is_exec_stmt		PARAMS ((tree));
 
 /*---------------------------------------------------------------------------
 		  Block annotations stored in basic_block.aux
Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.21
diff -d -u -p -r1.1.2.21 tree-ssa-ccp.c
--- tree-ssa-ccp.c	14 Oct 2002 17:01:53 -0000	1.1.2.21
+++ tree-ssa-ccp.c	16 Oct 2002 18:33:23 -0000
@@ -423,12 +423,8 @@ visit_phi_node (phi_node)
 
       if (dump_file && (dump_flags & TDF_DETAILS))
 	{
-	  fprintf (dump_file, "\n    Examining argument #%d: ", i);
-	  dump_ref (dump_file, "", phi_arg_def (arg), 0, 1);
-	  fprintf (dump_file, "    incoming via basic block %d\n",
-	           e->src->index);
-	  fprintf (dump_file, "    Edge (%d -> %d) is %sexecutable\n",
-	           e->src->index, e->dest->index,
+	  fprintf (dump_file, "\n    Argument #%d (%d -> %d %sexecutable)\n",
+	           i, e->src->index, e->dest->index,
 		   (e->flags & EDGE_EXECUTABLE) ? "" : "not ");
 	}
 
@@ -436,13 +432,31 @@ visit_phi_node (phi_node)
 	 the existing value of the PHI node and the current PHI argument.  */
       if (e->flags & EDGE_EXECUTABLE)
 	{
-	  tree_ref rdef = phi_arg_def (arg);
-	  phi_val = cp_lattice_meet (phi_val, values[ref_id (rdef)]);
+	  tree_ref rdef;
+	  value rdef_val;
+	  
+	  rdef = phi_arg_def (arg);
+	  rdef_val = values[ref_id (rdef)];
+	  phi_val = cp_lattice_meet (phi_val, rdef_val);
+
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    {
+	      dump_ref (dump_file, "\t", phi_arg_def (arg), 0, 0);
+	      dump_lattice_value (dump_file, "\tValue: ", rdef_val);
+	      fprintf (dump_file, "\n");
+	    }
+
 	  if (phi_val.lattice_val == VARYING)
 	    break;
 	}
     }
 
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      dump_lattice_value (dump_file, "\n    PHI node value: ", phi_val);
+      fprintf (dump_file, "\n\n");
+    }
+
   set_lattice_value (phi_node, phi_val);
 }
 
@@ -516,6 +530,13 @@ visit_expression_for (ref)
     abort ();
 #endif
 
+  /* First examine the reference to see if it's a special definition
+     (clobbering, partial or may-def), mark it varying and add SSA edges
+     that may be coming out of it.  */
+  if ((ref_type (ref) & V_DEF)
+      && ref_type (ref) & (M_CLOBBER | M_PARTIAL | M_MAY | M_RELOCATE))
+    def_to_varying (ref);
+
   expr = ref_expr (ref);
   
   /* No need to do anything if the reference is not associated with an
@@ -530,14 +551,6 @@ visit_expression_for (ref)
       dump_ref (dump_file, "\nfor reference: ", ref, 0, 0);
     }
   
-  /* First examine the reference to see if it's a special definition
-     (clobbering, partial or may-def), mark it varying and add SSA edges
-     that may be coming out of it.  */
-  if ((ref_type (ref) & V_DEF)
-      && ref_type (ref) & (M_CLOBBER | M_PARTIAL | M_MAY | M_RELOCATE))
-    def_to_varying (ref);
-
-
   /* Now examine the expression.  If the expression produces an output
      value, evaluate the expression to see if the lattice value of its
      output has changed.  */
@@ -620,8 +633,11 @@ visit_condexpr_for (ref)
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
+      tree t = ref_stmt (ref);
+      STRIP_WFL (t);
+      STRIP_NOPS (t);
       fprintf (dump_file, "Predicate is for a control statement: %s\n",
-	  tree_code_name[TREE_CODE (ref_stmt (ref))]);
+	       tree_code_name[TREE_CODE (t)]);
       dump_lattice_value (dump_file, "value: ", val);
       fprintf (dump_file, "\n");
     }
@@ -981,7 +997,7 @@ set_lattice_value (def, val)
 
 
 /* Replace USE reference in the expression EXPR with their immediate reaching
-   definition.  Mark EXPR for folding (used in substitute_and_fold).  */
+   definition.  */
 
 static void
 replace_uses_in (expr)
@@ -1027,9 +1043,6 @@ replace_uses_in (expr)
 	  restore_ref_operand (use);
 	}
     }
-
-  /* The expression has not been folded already.  */
-  clear_tree_flag (expr, TF_FOLDED);
 }
 
 
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.21
diff -d -u -p -r1.1.4.21 tree-ssa.c
--- tree-ssa.c	10 Oct 2002 18:49:24 -0000	1.1.4.21
+++ tree-ssa.c	16 Oct 2002 18:33:23 -0000
@@ -796,8 +796,13 @@ add_phi_node (bb, var)
   if (VARRAY_TREE (added, bb->index) != var)
     {
       tree_ref phi;
+      tree *stmt_p;
 
-      phi = create_ref (var, V_PHI, bb, NULL_TREE, NULL_TREE, NULL, false);
+      /* If the basic block is not empty, associate the PHI node to its
+	 first executable statement.  This is for debugging convenience.
+	 This way, the PHI node will have line number information.  */
+      stmt_p = !bb_empty_p (bb) ? bb->head_tree_p : NULL;
+      phi = create_ref (var, V_PHI, bb, stmt_p, NULL, NULL, false);
       add_ref_to_list_begin (bb_refs (bb), phi);
 
       VARRAY_TREE (added, bb->index) = var;
@@ -912,7 +917,13 @@ set_alias_imm_reaching_def (ref, i, may_
 /* Create a default definition for VAR.  This is called when the SSA
    builder needs to get the current reaching definition for a PHI node or a
    V_USE reference and finds it to be NULL.  In the case of a V_USE
-   reference, this means that the variable may be used uninitialized.  */
+   reference, this means that the variable may be used uninitialized.
+
+   If the variable is static and DECL_INITIAL is set, then an initializing
+   definition is created.  This makes a difference when doing constant
+   propagation.  If we are initializing a read-only static variable, then
+   we can assume that DECL_INITIAL will be the constant value for the
+   variable.  */
 
 static tree_ref
 create_default_def (var)
@@ -921,11 +932,17 @@ create_default_def (var)
   basic_block decl_bb;
   tree_ref def;
   size_t i;
+  HOST_WIDE_INT mod;
 
   decl_bb = ENTRY_BLOCK_PTR->succ->dest;
 
+  if (TREE_STATIC (var) && DECL_INITIAL (var))
+    mod = M_INITIAL;
+  else
+    mod = M_DEFAULT;
+
   /* Create a default definition and set it to be CURRDEF(var).  */
-  def = create_ref (var, V_DEF | M_DEFAULT, decl_bb, NULL, NULL, NULL, false);
+  def = create_ref (var, V_DEF | mod, decl_bb, NULL, NULL, NULL, false);
   add_ref_to_list_begin (bb_refs (decl_bb), def);
   set_currdef_for (var, def);
 
@@ -982,8 +999,14 @@ void
 delete_tree_ssa (fnbody)
      tree fnbody;
 {
+  unsigned long int i;
+
   /* Remove annotations from every tree in the function.  */
   walk_tree (&fnbody, remove_annotations_r, NULL, NULL);
+
+  /* Remove annotations from every referenced variable.  */
+  for (i = 0; i < num_referenced_vars; i++)
+    remove_tree_ann (referenced_var (i));
 
   num_referenced_vars = 0;
   referenced_vars = NULL;


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