OSDN Git Service

2004-09-22 Frank Ch. Eigler <fche@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa.c
index 3bb3595..56c9c8f 100644 (file)
@@ -41,7 +41,6 @@ Boston, MA 02111-1307, USA.  */
 #include "tree-inline.h"
 #include "varray.h"
 #include "timevar.h"
-#include "tree-alias-common.h"
 #include "hashtab.h"
 #include "tree-dump.h"
 #include "tree-pass.h"
@@ -178,9 +177,9 @@ verify_def (basic_block bb, basic_block *definition_block, tree ssa_name,
     {
       error ("SSA_NAME_DEF_STMT is wrong");
       fprintf (stderr, "Expected definition statement:\n");
-      debug_generic_stmt (SSA_NAME_DEF_STMT (ssa_name));
+      print_generic_stmt (stderr, SSA_NAME_DEF_STMT (ssa_name), TDF_VOPS);
       fprintf (stderr, "\nActual definition statement:\n");
-      debug_generic_stmt (stmt);
+      print_generic_stmt (stderr, stmt, TDF_VOPS);
       goto err;
     }
 
@@ -190,7 +189,7 @@ err:
   fprintf (stderr, "while verifying SSA_NAME ");
   print_generic_expr (stderr, ssa_name, 0);
   fprintf (stderr, " in statement\n");
-  debug_generic_stmt (stmt);
+  print_generic_stmt (stderr, stmt, TDF_VOPS);
 
   return true;
 }
@@ -208,11 +207,15 @@ err:
       arguments).
 
    IS_VIRTUAL is true if SSA_NAME is created by a V_MAY_DEF or a
-      V_MUST_DEF.  */
+      V_MUST_DEF.
+   
+   If NAMES_DEFINED_IN_BB is not NULL, it contains a bitmap of ssa names
+     that are defined before STMT in basic block BB.  */
 
 static bool
 verify_use (basic_block bb, basic_block def_bb, tree ssa_name,
-           tree stmt, bool check_abnormal, bool is_virtual)
+           tree stmt, bool check_abnormal, bool is_virtual,
+           bitmap names_defined_in_bb)
 {
   bool err = false;
 
@@ -233,6 +236,13 @@ verify_use (basic_block bb, basic_block def_bb, tree ssa_name,
             def_bb->index, bb->index);
       err = true;
     }
+  else if (bb == def_bb
+          && names_defined_in_bb != NULL
+          && !bitmap_bit_p (names_defined_in_bb, SSA_NAME_VERSION (ssa_name)))
+    {
+      error ("Definition in block %i follows the use", def_bb->index);
+      err = true;
+    }
 
   if (check_abnormal
       && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssa_name))
@@ -244,9 +254,9 @@ verify_use (basic_block bb, basic_block def_bb, tree ssa_name,
   if (err)
     {
       fprintf (stderr, "for SSA_NAME: ");
-      debug_generic_expr (ssa_name);
+      print_generic_expr (stderr, ssa_name, TDF_VOPS);
       fprintf (stderr, "in statement:\n");
-      debug_generic_stmt (stmt);
+      print_generic_stmt (stderr, stmt, TDF_VOPS);
     }
 
   return err;
@@ -282,7 +292,8 @@ verify_phi_args (tree phi, basic_block bb, basic_block *definition_block)
       if (TREE_CODE (op) == SSA_NAME)
        err = verify_use (e->src, definition_block[SSA_NAME_VERSION (op)], op,
                          phi, e->flags & EDGE_ABNORMAL,
-                         !is_gimple_reg (PHI_RESULT (phi)));
+                         !is_gimple_reg (PHI_RESULT (phi)),
+                         NULL);
 
       if (e->dest != bb)
        {
@@ -308,7 +319,7 @@ verify_phi_args (tree phi, basic_block bb, basic_block *definition_block)
       if (err)
        {
          fprintf (stderr, "PHI argument\n");
-         debug_generic_stmt (op);
+         print_generic_stmt (stderr, op, TDF_VOPS);
          goto error;
        }
 
@@ -331,7 +342,7 @@ error:
   if (err)
     {
       fprintf (stderr, "for PHI node\n");
-      debug_generic_stmt (phi);
+      print_generic_stmt (stderr, phi, TDF_VOPS);
     }
 
 
@@ -408,6 +419,8 @@ verify_flow_sensitive_alias_info (void)
       struct ptr_info_def *pi;
 
       ptr = ssa_name (i);
+      if (!ptr)
+       continue;
       ann = var_ann (SSA_NAME_VAR (ptr));
       pi = SSA_NAME_PTR_INFO (ptr);
 
@@ -433,18 +446,6 @@ verify_flow_sensitive_alias_info (void)
          goto err;
        }
 
-      if (pi->pt_anything && (pi->pt_malloc || pi->pt_vars))
-       {
-         error ("Pointers that point to anything should not point to malloc or other vars");
-         goto err;
-       }
-      
-      if (pi->pt_malloc && pi->pt_vars)
-       {
-         error ("Pointers pointing to malloc get a unique tag and cannot point to other vars");
-         goto err;
-       }
-
       if (pi->name_mem_tag
          && !pi->pt_malloc
          && (pi->pt_vars == NULL
@@ -467,25 +468,26 @@ verify_flow_sensitive_alias_info (void)
          size_t j;
 
          for (j = i + 1; j < num_ssa_names; j++)
-           {
-             tree ptr2 = ssa_name (j);
-             struct ptr_info_def *pi2 = SSA_NAME_PTR_INFO (ptr2);
-
-             if (!POINTER_TYPE_P (TREE_TYPE (ptr2)))
-               continue;
-
-             if (pi2
-                 && pi2->name_mem_tag
-                 && pi2->pt_vars
-                 && bitmap_first_set_bit (pi2->pt_vars) >= 0
-                 && pi->name_mem_tag != pi2->name_mem_tag
-                 && bitmap_equal_p (pi->pt_vars, pi2->pt_vars))
-               {
-                 error ("Two pointers with different name tags and identical points-to sets");
-                 debug_variable (ptr2);
-                 goto err;
-               }
-           }
+           if (ssa_name (j))
+             {
+               tree ptr2 = ssa_name (j);
+               struct ptr_info_def *pi2 = SSA_NAME_PTR_INFO (ptr2);
+
+               if (!TREE_VISITED (ptr2) || !POINTER_TYPE_P (TREE_TYPE (ptr2)))
+                 continue;
+
+               if (pi2
+                   && pi2->name_mem_tag
+                   && pi2->pt_vars
+                   && bitmap_first_set_bit (pi2->pt_vars) >= 0
+                   && pi->name_mem_tag != pi2->name_mem_tag
+                   && bitmap_equal_p (pi->pt_vars, pi2->pt_vars))
+                 {
+                   error ("Two pointers with different name tags and identical points-to sets");
+                   debug_variable (ptr2);
+                   goto err;
+                 }
+             }
        }
     }
 
@@ -516,12 +518,17 @@ verify_ssa (void)
   size_t i;
   basic_block bb;
   basic_block *definition_block = xcalloc (num_ssa_names, sizeof (basic_block));
+  ssa_op_iter iter;
+  tree op;
+  enum dom_state orig_dom_state = dom_computed[CDI_DOMINATORS];
+  bitmap names_defined_in_bb = BITMAP_XMALLOC ();
 
   timevar_push (TV_TREE_SSA_VERIFY);
 
   /* Keep track of SSA names present in the IL.  */
   for (i = 1; i < num_ssa_names; i++)
-    TREE_VISITED (ssa_name (i)) = 0;
+    if (ssa_name (i))
+      TREE_VISITED (ssa_name (i)) = 0;
 
   calculate_dominance_info (CDI_DOMINATORS);
 
@@ -540,43 +547,26 @@ verify_ssa (void)
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
        {
          tree stmt;
-         stmt_ann_t ann;
-         unsigned int j;
-         v_may_def_optype v_may_defs;
-         v_must_def_optype v_must_defs;
-         def_optype defs;
 
          stmt = bsi_stmt (bsi);
-         ann = stmt_ann (stmt);
          get_stmt_operands (stmt);
 
-         v_may_defs = V_MAY_DEF_OPS (ann);
-         if (ann->makes_aliased_stores && NUM_V_MAY_DEFS (v_may_defs) == 0)
+         if (stmt_ann (stmt)->makes_aliased_stores 
+             && NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) == 0)
            {
              error ("Statement makes aliased stores, but has no V_MAY_DEFS");
-             debug_generic_stmt (stmt);
+             print_generic_stmt (stderr, stmt, TDF_VOPS);
              goto err;
            }
            
-         for (j = 0; j < NUM_V_MAY_DEFS (v_may_defs); j++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
            {
-             tree op = V_MAY_DEF_RESULT (v_may_defs, j);
              if (verify_def (bb, definition_block, op, stmt, true))
                goto err;
            }
           
-         v_must_defs = STMT_V_MUST_DEF_OPS (stmt);
-         for (j = 0; j < NUM_V_MUST_DEFS (v_must_defs); j++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
            {
-             tree op = V_MUST_DEF_OP (v_must_defs, j);
-             if (verify_def (bb, definition_block, op, stmt, true))
-               goto err;
-           }
-
-         defs = DEF_OPS (ann);
-         for (j = 0; j < NUM_DEFS (defs); j++)
-           {
-             tree op = DEF_OP (defs, j);
              if (verify_def (bb, definition_block, op, stmt, false))
                goto err;
            }
@@ -605,52 +595,73 @@ verify_ssa (void)
 
       /* Verify the arguments for every PHI node in the block.  */
       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-       if (verify_phi_args (phi, bb, definition_block))
-         goto err;
+       {
+         if (verify_phi_args (phi, bb, definition_block))
+           goto err;
+         bitmap_set_bit (names_defined_in_bb,
+                         SSA_NAME_VERSION (PHI_RESULT (phi)));
+       }
 
       /* Now verify all the uses and vuses in every statement of the block.  */
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
        {
          tree stmt = bsi_stmt (bsi);
-         stmt_ann_t ann = stmt_ann (stmt);
-         unsigned int j;
-         vuse_optype vuses;
-         v_may_def_optype v_may_defs;
-         use_optype uses;
-
-         vuses = VUSE_OPS (ann); 
-         for (j = 0; j < NUM_VUSES (vuses); j++)
+
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_USES)
            {
-             tree op = VUSE_OP (vuses, j);
              if (verify_use (bb, definition_block[SSA_NAME_VERSION (op)],
-                             op, stmt, false, true))
+                             op, stmt, false, true,
+                             names_defined_in_bb))
                goto err;
            }
 
-         v_may_defs = V_MAY_DEF_OPS (ann);
-         for (j = 0; j < NUM_V_MAY_DEFS (v_may_defs); j++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
            {
-             tree op = V_MAY_DEF_OP (v_may_defs, j);
              if (verify_use (bb, definition_block[SSA_NAME_VERSION (op)],
-                             op, stmt, false, true))
+                             op, stmt, false, false,
+                             names_defined_in_bb))
                goto err;
            }
 
-         uses = USE_OPS (ann);
-         for (j = 0; j < NUM_USES (uses); j++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_ALL_DEFS)
+           {
+             bitmap_set_bit (names_defined_in_bb, SSA_NAME_VERSION (op));
+           }
+       }
+
+      /* Verify the uses in arguments of PHI nodes at the exits from the
+        block.  */
+      for (e = bb->succ; e; e = e->succ_next)
+       {
+         for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
            {
-             tree op = USE_OP (uses, j);
+             bool virtual = !is_gimple_reg (PHI_RESULT (phi));
+             op = PHI_ARG_DEF_FROM_EDGE (phi, e);
+             if (TREE_CODE (op) != SSA_NAME)
+               continue;
+
              if (verify_use (bb, definition_block[SSA_NAME_VERSION (op)],
-                             op, stmt, false, false))
+                             op, phi, false, virtual,
+                             names_defined_in_bb))
                goto err;
            }
        }
+
+      bitmap_clear (names_defined_in_bb);
     }
 
   /* Finally, verify alias information.  */
   verify_alias_info ();
 
   free (definition_block);
+  /* Restore the dominance information to its prior known state, so
+     that we do not perturb the compiler's subsequent behavior.  */
+  if (orig_dom_state == DOM_NONE)
+    free_dominance_info (CDI_DOMINATORS);
+  else
+    dom_computed[CDI_DOMINATORS] = orig_dom_state;
+  
+  BITMAP_XFREE (names_defined_in_bb);
   timevar_pop (TV_TREE_SSA_VERIFY);
   return;
 
@@ -686,13 +697,22 @@ delete_tree_ssa (void)
   /* Remove annotations from every tree in the function.  */
   FOR_EACH_BB (bb)
     for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-      bsi_stmt (bsi)->common.ann = NULL;
+      {
+       tree stmt = bsi_stmt (bsi);
+        release_defs (stmt);
+       ggc_free (stmt->common.ann);
+       stmt->common.ann = NULL;
+      }
 
   /* Remove annotations from every referenced variable.  */
   if (referenced_vars)
     {
       for (i = 0; i < num_referenced_vars; i++)
-       referenced_var (i)->common.ann = NULL;
+       {
+         tree var = referenced_var (i);
+         ggc_free (var->common.ann);
+         var->common.ann = NULL;
+       }
       referenced_vars = NULL;
     }
 
@@ -881,10 +901,7 @@ walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data,
 {
   tree def_stmt;
 
-#if defined ENABLE_CHECKING
-  if (TREE_CODE (var) != SSA_NAME)
-    abort ();
-#endif
+  gcc_assert (TREE_CODE (var) == SSA_NAME);
 
   def_stmt = SSA_NAME_DEF_STMT (var);
 
@@ -916,16 +933,15 @@ propagate_into_addr (tree stmt, tree var, tree *x, tree repl)
     return;
   addr_var = TREE_OPERAND (repl, 0);
 
-  while (TREE_CODE (*x) == ARRAY_REF
-        || TREE_CODE (*x) == COMPONENT_REF
-        || TREE_CODE (*x) == BIT_FIELD_REF)
+  while (handled_component_p (*x)
+        || TREE_CODE (*x) == REALPART_EXPR
+        || TREE_CODE (*x) == IMAGPART_EXPR)
     x = &TREE_OPERAND (*x, 0);
 
   if (TREE_CODE (*x) != INDIRECT_REF
       || TREE_OPERAND (*x, 0) != var)
     return;
 
-  modify_stmt (stmt);
   if (TREE_TYPE (*x) == TREE_TYPE (addr_var))
     {
       *x = addr_var;
@@ -933,6 +949,7 @@ propagate_into_addr (tree stmt, tree var, tree *x, tree repl)
       return;
     }
 
+
   /* Frontends sometimes produce expressions like *&a instead of a[0].
      Create a temporary variable to handle this case.  */
   ass_stmt = build2 (MODIFY_EXPR, void_type_node, NULL_TREE, repl);
@@ -953,14 +970,12 @@ propagate_into_addr (tree stmt, tree var, tree *x, tree repl)
 static void
 replace_immediate_uses (tree var, tree repl)
 {
-  use_optype uses;
-  vuse_optype vuses;
-  v_may_def_optype v_may_defs;
   int i, j, n;
   dataflow_t df;
   tree stmt;
-  stmt_ann_t ann;
   bool mark_new_vars;
+  ssa_op_iter iter;
+  use_operand_p use_p;
 
   df = get_immediate_uses (SSA_NAME_DEF_STMT (var));
   n = num_immediate_uses (df);
@@ -968,7 +983,6 @@ replace_immediate_uses (tree var, tree repl)
   for (i = 0; i < n; i++)
     {
       stmt = immediate_use (df, i);
-      ann = stmt_ann (stmt);
 
       if (TREE_CODE (stmt) == PHI_NODE)
        {
@@ -994,25 +1008,37 @@ replace_immediate_uses (tree var, tree repl)
              propagate_into_addr (stmt, var, &TREE_OPERAND (stmt, 1), repl);
            }
 
-         uses = USE_OPS (ann);
-         for (j = 0; j < (int) NUM_USES (uses); j++)
-           if (USE_OP (uses, j) == var)
+         FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+           if (USE_FROM_PTR (use_p) == var)
              {
-               propagate_value (USE_OP_PTR (uses, j), repl);
+               propagate_value (use_p, repl);
                mark_new_vars = POINTER_TYPE_P (TREE_TYPE (repl));
              }
        }
       else
        {
-         vuses = VUSE_OPS (ann);
-         for (j = 0; j < (int) NUM_VUSES (vuses); j++)
-           if (VUSE_OP (vuses, j) == var)
-             propagate_value (VUSE_OP_PTR (vuses, j), repl);
-
-         v_may_defs = V_MAY_DEF_OPS (ann);
-         for (j = 0; j < (int) NUM_V_MAY_DEFS (v_may_defs); j++)
-           if (V_MAY_DEF_OP (v_may_defs, j) == var)
-             propagate_value (V_MAY_DEF_OP_PTR (v_may_defs, j), repl);
+         FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_VIRTUAL_USES)
+           if (USE_FROM_PTR (use_p) == var)
+             propagate_value (use_p, repl);
+       }
+
+      /* FIXME.  If REPL is a constant, we need to fold STMT.
+        However, fold_stmt wants a pointer to the statement, because
+        it may happen that it needs to replace the whole statement
+        with a new expression.  Since the current def-use machinery
+        does not return pointers to statements, we call fold_stmt
+        with the address of a local temporary, if that call changes
+        the temporary then we fall on our swords.
+
+        Note that all this will become unnecessary soon.  This
+        pass is being replaced with a proper copy propagation pass
+        for 4.1 (dnovillo, 2004-09-17).  */
+      if (TREE_CODE (repl) != SSA_NAME)
+       {
+         tree tmp = stmt;
+         fold_stmt (&tmp);
+         if (tmp != stmt)
+           abort ();
        }
 
       /* If REPL is a pointer, it may have different memory tags associated
@@ -1091,8 +1117,7 @@ check_phi_redundancy (tree phi, tree *eq_to)
 
   /* At least one of the arguments should not be equal to the result, or
      something strange is happening.  */
-  if (!val)
-    abort ();
+  gcc_assert (val);
 
   if (get_eq_name (eq_to, res) == val)
     return;
@@ -1208,7 +1233,8 @@ struct tree_opt_pass pass_redundant_phi =
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_dump_func | TODO_rename_vars 
-    | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
+    | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
+  0                                    /* letter */
 };
 \f
 /* Emit warnings for uninitialized variables.  This is done in two passes.
@@ -1274,7 +1300,7 @@ warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data)
       warn_uninit (t, "%H'%D' is used uninitialized in this function", locus);
       *walk_subtrees = 0;
     }
-  else if (DECL_P (t) || TYPE_P (t))
+  else if (IS_TYPE_OR_DECL_P (t))
     *walk_subtrees = 0;
 
   return NULL_TREE;
@@ -1348,7 +1374,8 @@ struct tree_opt_pass pass_early_warn_uninitialized =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
+  0,                                    /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 struct tree_opt_pass pass_late_warn_uninitialized =
@@ -1364,5 +1391,6 @@ struct tree_opt_pass pass_late_warn_uninitialized =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
+  0,                                    /* todo_flags_finish */
+  0                                    /* letter */
 };