OSDN Git Service

PR c/20740
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-operands.c
index a967f98..a010b30 100644 (file)
@@ -50,8 +50,6 @@ Boston, MA 02111-1307, USA.  */
    The routines in this file are concerned with creating this operand cache 
    from a stmt tree.
 
-   get_stmt_operands() in the primary entry point. 
-
    The operand tree is the parsed by the various get_* routines which look 
    through the stmt tree for the occurrence of operands which may be of 
    interest, and calls are made to the append_* routines whenever one is 
@@ -67,7 +65,7 @@ Boston, MA 02111-1307, USA.  */
    on each of the 5 operand vectors which have been built up.
 
    If the stmt had a previous operand cache, the finalization routines 
-   attempt to match up the new operands with the old ones.  If its a perfect 
+   attempt to match up the new operands with the old ones.  If it's a perfect 
    match, the old vector is simply reused.  If it isn't a perfect match, then 
    a new vector is created and the new operands are placed there.  For 
    virtual operands, if the previous cache had SSA_NAME version of a 
@@ -81,7 +79,7 @@ Boston, MA 02111-1307, USA.  */
 */
 
 
-/* Flags to describe operand properties in get_stmt_operands and helpers.  */
+/* Flags to describe operand properties in helpers.  */
 
 /* By default, operands are loaded.  */
 #define opf_none       0
@@ -456,7 +454,8 @@ finalize_ssa_defs (def_optype *old_ops_p, tree stmt)
    changed what this pointer points to via TREE_OPERANDS (exp, 0) = <...>.
    THe contents are different, but the the pointer is still the same.  This
    routine will check to make sure PTR is in the correct list, and if it isn't
-   put it in the correct list.  */
+   put it in the correct list.  We cannot simply check the previous node 
+   because all nodes in the same stmt might have be changed.  */
 
 static inline void
 correct_use_link (ssa_imm_use_t *ptr, tree stmt)
@@ -471,10 +470,28 @@ correct_use_link (ssa_imm_use_t *ptr, tree stmt)
   prev = ptr->prev;
   if (prev)
     {
-      /* find the root, which has a non-NULL stmt, and a NULL use.  */
-      while (prev->stmt == NULL || prev->use != NULL)
-        prev = prev->prev;
-      root = prev->stmt;
+      bool stmt_mod = true;
+      /* Find the first element which isn't a SAFE iterator, is in a different
+        stmt, and is not a a modified stmt,  That node is in the correct list,
+        see if we are too.  */
+
+      while (stmt_mod)
+       {
+         while (prev->stmt == stmt || prev->stmt == NULL)
+           prev = prev->prev;
+         if (prev->use == NULL)
+           stmt_mod = false;
+         else
+           if ((stmt_mod = stmt_modified_p (prev->stmt)))
+             prev = prev->prev;
+       }
+
+      /* Get the ssa_name of the list the node is in.  */
+      if (prev->use == NULL)
+       root = prev->stmt;
+      else
+       root = *(prev->use);
+      /* If it's the right list, simply return.  */
       if (root == *(ptr->use))
        return;
     }
@@ -501,9 +518,7 @@ finalize_ssa_uses (use_optype *old_ops_p, tree stmt)
   {
     unsigned x;
     /* If the pointer to the operand is the statement itself, something is
-       wrong.  It means that we are pointing to a local variable (the 
-       initial call to get_stmt_operands does not pass a pointer to a 
-       statement).  */
+       wrong.  It means that we are pointing to a local variable.  */
     for (x = 0; x < num; x++)
       gcc_assert (*(VARRAY_TREE_PTR (build_uses, x)) != stmt);
   }
@@ -1069,7 +1084,7 @@ parse_ssa_operands (tree stmt)
 
     default:
       /* Notice that if get_expr_operands tries to use &STMT as the operand
-        pointer (which may only happen for USE operands), we will abort in
+        pointer (which may only happen for USE operands), we will fail in
         append_use.  This default will handle statements like empty
         statements, or CALL_EXPRs that may appear on the RHS of a statement
         or as statements themselves.  */
@@ -1200,9 +1215,7 @@ swap_tree_operands (tree *exp0, tree *exp1)
   *exp1 = op0;
 }
 
-/* Get the operands of statement STMT.  Note that repeated calls to
-   get_stmt_operands for the same statement will do nothing until the
-   statement is marked modified by a call to mark_stmt_modified().  */
+/* Get the operands of statement STMT.  */
 
 void
 update_stmt_operands (tree stmt)
@@ -1210,8 +1223,7 @@ update_stmt_operands (tree stmt)
   stmt_ann_t ann;
   stmt_operands_t old_operands;
 
-  /* If get_stmt_operands is called before SSA is initialized, dont
-  do anything.  */
+  /* Don't do anything if we are called before SSA is initialized.  */
   if (build_defs == NULL)
     return;
   /* The optimizers cannot handle statements that are nothing but a
@@ -1230,9 +1242,7 @@ update_stmt_operands (tree stmt)
   build_ssa_operands (stmt, ann, &old_operands, &(ann->operands));
   free_ssa_operands (&old_operands);
 
-  /* Clear the modified bit for STMT.  Subsequent calls to
-     get_stmt_operands for this statement will do nothing until the
-     statement is marked modified by a call to mark_stmt_modified().  */
+  /* Clear the modified bit for STMT.  */
   ann->modified = 0;
 
   timevar_pop (TV_TREE_OPS);
@@ -1433,6 +1443,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
     case TRUTH_XOR_EXPR:
     case COMPOUND_EXPR:
     case OBJ_TYPE_REF:
+    case ASSERT_EXPR:
     do_binary:
       {
        tree op0 = TREE_OPERAND (expr, 0);
@@ -1669,7 +1680,7 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags)
 
   /* Everything else *should* have been folded elsewhere, but users
      are smarter than we in finding ways to write invalid code.  We
-     cannot just abort here.  If we were absolutely certain that we
+     cannot just assert here.  If we were absolutely certain that we
      do handle all valid cases, then we could just do nothing here.
      That seems optimistic, so attempt to do something logical... */
   else if ((TREE_CODE (ptr) == PLUS_EXPR || TREE_CODE (ptr) == MINUS_EXPR)
@@ -1716,7 +1727,7 @@ get_call_expr_operands (tree stmt, tree expr)
       && !bitmap_empty_p (call_clobbered_vars)
       && !(call_flags & ECF_NOVOPS))
     {
-      /* A 'pure' or a 'const' functions never call clobber anything. 
+      /* A 'pure' or a 'const' function never call-clobbers anything. 
         A 'noreturn' function might, but since we don't return anyway 
         there is no point in recording that.  */ 
       if (TREE_SIDE_EFFECTS (expr)
@@ -1779,6 +1790,24 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
   if (TREE_THIS_VOLATILE (sym) && s_ann)
     s_ann->has_volatile_ops = true;
 
+  /* If the variable cannot be modified and this is a V_MAY_DEF change
+     it into a VUSE.  This happens when read-only variables are marked
+     call-clobbered and/or aliased to writeable variables.  So we only
+     check that this only happens on stores, and not writes to GIMPLE
+     registers.
+     
+     FIXME: The C++ FE is emitting assignments in the IL stream for
+     read-only globals.  This is wrong, but for the time being disable
+     this transformation on V_MUST_DEF operands (otherwise, we
+     mis-optimize SPEC2000's eon).  */
+  if ((flags & opf_is_def)
+      && !(flags & opf_kill_def)
+      && unmodifiable_var_p (var))
+    {
+      gcc_assert (!is_real_op);
+      flags &= ~opf_is_def;
+    }
+
   if (is_real_op)
     {
       /* The variable is a GIMPLE register.  Add it to real operands.  */
@@ -1839,17 +1868,35 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
 
          if (flags & opf_is_def)
            {
+             bool added_may_defs_p = false;
+
              /* If the variable is also an alias tag, add a virtual
                 operand for it, otherwise we will miss representing
                 references to the members of the variable's alias set.
                 This fixes the bug in gcc.c-torture/execute/20020503-1.c.  */
              if (v_ann->is_alias_tag)
-               append_v_may_def (var);
+               {
+                 added_may_defs_p = true;
+                 append_v_may_def (var);
+               }
 
              for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
-               append_v_may_def (VARRAY_TREE (aliases, i));
+               {
+                 /* While VAR may be modifiable, some of its aliases
+                    may not be.  If that's the case, we don't really
+                    need to add them a V_MAY_DEF for them.  */
+                 tree alias = VARRAY_TREE (aliases, i);
+
+                 if (unmodifiable_var_p (alias))
+                   append_vuse (alias);
+                 else
+                   {
+                     append_v_may_def (alias);
+                     added_may_defs_p = true;
+                   }
+               }
 
-             if (s_ann)
+             if (s_ann && added_may_defs_p)
                s_ann->makes_aliased_stores = 1;
            }
          else
@@ -1981,8 +2028,7 @@ add_call_clobber_ops (tree stmt)
   EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
     {
       tree var = referenced_var (i);
-      if (TREE_READONLY (var)
-         && (TREE_STATIC (var) || DECL_EXTERNAL (var)))
+      if (unmodifiable_var_p (var))
        add_stmt_operand (&var, &empty_ann, opf_none);
       else
        add_stmt_operand (&var, &empty_ann, opf_is_def);
@@ -2173,29 +2219,6 @@ create_ssa_artficial_load_stmt (stmt_operands_p old_ops, tree new_stmt)
   ann->operands.vuse_ops = finalize_ssa_vuses (&(tmp.vuse_ops), NULL);
 }
 
-
-
-/* Issue immediate use error for VAR to debug file F.  */
-static void 
-verify_abort (FILE *f, ssa_imm_use_t *var)
-{
-  tree stmt;
-  stmt = var->stmt;
-  if (stmt)
-    {
-      if (stmt_modified_p(stmt))
-       {
-         fprintf (f, " STMT MODIFIED. - <%p> ", (void *)stmt);
-         print_generic_stmt (f, stmt, TDF_SLIM);
-       }
-    }
-  fprintf (f, " IMM ERROR : (use_p : tree - %p:%p)", (void *)var, 
-          (void *)var->use);
-  print_generic_expr (f, USE_FROM_PTR (var), TDF_SLIM);
-  fprintf(f, "\n");
-}
-
-
 /* Scan the immediate_use list for VAR making sure its linked properly.
    return RTUE iof there is a problem.  */
 
@@ -2222,31 +2245,18 @@ verify_imm_links (FILE *f, tree var)
   for (ptr = list->next; ptr != list; )
     {
       if (prev != ptr->prev)
-        {
-         verify_abort (f, ptr);
-         return true;
-       }
-
+       goto error;
+      
       if (ptr->use == NULL)
-        {
-         verify_abort (f, ptr);        /* 2 roots, or SAFE guard node.  */
-         return true;
-       }
-      else
-       if (*(ptr->use) != var)
-         {
-           verify_abort (f, ptr);
-           return true;
-         }
+       goto error; /* 2 roots, or SAFE guard node.  */
+      else if (*(ptr->use) != var)
+       goto error;
 
       prev = ptr;
       ptr = ptr->next;
       /* Avoid infinite loops.  */
       if (count++ > 30000)
-       {
-         verify_abort (f, ptr);
-         return true;
-       }
+       goto error;
     }
 
   /* Verify list in the other direction.  */
@@ -2254,26 +2264,29 @@ verify_imm_links (FILE *f, tree var)
   for (ptr = list->prev; ptr != list; )
     {
       if (prev != ptr->next)
-       {
-         verify_abort (f, ptr);
-         return true;
-       }
+       goto error;
       prev = ptr;
       ptr = ptr->prev;
       if (count-- < 0)
-       {
-         verify_abort (f, ptr);
-         return true;
-       }
+       goto error;
     }
 
   if (count != 0)
-    {
-      verify_abort (f, ptr);
-      return true;
-    }
+    goto error;
 
   return false;
+
+ error:
+  if (ptr->stmt && stmt_modified_p (ptr->stmt))
+    {
+      fprintf (f, " STMT MODIFIED. - <%p> ", (void *)ptr->stmt);
+      print_generic_stmt (f, ptr->stmt, TDF_SLIM);
+    }
+  fprintf (f, " IMM ERROR : (use_p : tree - %p:%p)", (void *)ptr, 
+          (void *)ptr->use);
+  print_generic_expr (f, USE_FROM_PTR (ptr), TDF_SLIM);
+  fprintf(f, "\n");
+  return true;
 }