OSDN Git Service

* obj-c++.dg/comp-types-10.mm: XFAIL for ICE.
[pf3gnuchains/gcc-fork.git] / gcc / ipa-pure-const.c
index 041cf29..a2c9206 100644 (file)
@@ -1,12 +1,12 @@
 /* Callgraph based analysis of static variables.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
 
 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
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,12 +15,12 @@ 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, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This file mark functions as being either const (TREE_READONLY) or
-   pure (DECL_IS_PURE).
+   pure (DECL_PURE_P).  It can also set the a variant of these that
+   are allowed to infinite loop (DECL_LOOPING_CONST_PURE_P).
 
    This must be run after inlining decisions have been made since
    otherwise, the local sets will not contain information that is
@@ -70,6 +70,7 @@ enum pure_const_state_e
 struct funct_state_d 
 {
   enum pure_const_state_e pure_const_state;
+  bool looping;
   bool state_set_in_source;
 };
 
@@ -80,8 +81,8 @@ typedef struct funct_state_d * funct_state;
 static inline funct_state
 get_function_state (struct cgraph_node *node)
 {
-  struct ipa_dfs_info * info = node->aux;
-  return info->aux;
+  struct ipa_dfs_info * info = (struct ipa_dfs_info *) node->aux;
+  return (funct_state) info->aux;
 }
 
 /* Check to see if the use (or definition when CHECHING_WRITE is true) 
@@ -96,6 +97,7 @@ check_decl (funct_state local,
   if (lookup_attribute ("used", DECL_ATTRIBUTES (t)))
     {
       local->pure_const_state = IPA_NEITHER;
+      local->looping = false;
       return;
     }
 
@@ -104,6 +106,7 @@ check_decl (funct_state local,
   if (TREE_THIS_VOLATILE (t)) 
     { 
       local->pure_const_state = IPA_NEITHER;
+      local->looping = false;
       return;
     }
 
@@ -115,7 +118,11 @@ check_decl (funct_state local,
      are CHECKING_WRITE, this cannot be a pure or constant
      function.  */
   if (checking_write) 
-    local->pure_const_state = IPA_NEITHER;
+    {
+      local->pure_const_state = IPA_NEITHER;
+      local->looping = false;
+      return;
+    }
 
   if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
     {
@@ -163,9 +170,19 @@ check_operand (funct_state local,
 static void
 check_tree (funct_state local, tree t, bool checking_write)
 {
-  if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
+  if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR)
+      || TREE_CODE (t) == SSA_NAME)
     return;
 
+  /* Any tree which is volatile disqualifies thie function from being
+     const or pure. */
+  if (TREE_THIS_VOLATILE (t))
+    {
+      local->pure_const_state = IPA_NEITHER;
+      local->looping = false;
+      return;
+    }
+
   while (TREE_CODE (t) == REALPART_EXPR 
         || TREE_CODE (t) == IMAGPART_EXPR
         || handled_component_p (t))
@@ -183,12 +200,14 @@ check_tree (funct_state local, tree t, bool checking_write)
       
       /* Any indirect reference that occurs on the lhs
         disqualifies the function from being pure or const. Any
-        indirect reference to a volatile disqualifies the
-        function from being pure or const.  Any indirect
-        reference that occurs on the rhs disqualifies the
+        indirect reference that occurs on the rhs disqualifies the
         function from being const.  */
-      if (checking_write || TREE_THIS_VOLATILE (t)) 
-       local->pure_const_state = IPA_NEITHER;
+      if (checking_write) 
+       {
+         local->pure_const_state = IPA_NEITHER;
+         local->looping = false;
+         return;
+       }
       else if (local->pure_const_state == IPA_CONST)
        local->pure_const_state = IPA_PURE;
     }
@@ -306,20 +325,15 @@ get_asm_expr_operands (funct_state local, tree stmt)
 static void
 check_call (funct_state local, tree call_expr) 
 {
-  int flags = call_expr_flags(call_expr);
-  tree operand_list = TREE_OPERAND (call_expr, 1);
+  int flags = call_expr_flags (call_expr);
   tree operand;
+  call_expr_arg_iterator iter;
   tree callee_t = get_callee_fndecl (call_expr);
   struct cgraph_node* callee;
   enum availability avail = AVAIL_NOT_AVAILABLE;
 
-  for (operand = operand_list;
-       operand != NULL_TREE;
-       operand = TREE_CHAIN (operand))
-    {
-      tree argument = TREE_VALUE (operand);
-      check_rhs_var (local, argument);
-    }
+  FOR_EACH_CALL_EXPR_ARG (operand, iter, call_expr)
+    check_rhs_var (local, operand);
   
   /* The const and pure flags are set by a variety of places in the
      compiler (including here).  If someone has already set the flags
@@ -339,7 +353,10 @@ check_call (funct_state local, tree call_expr)
       /* When bad things happen to bad functions, they cannot be const
         or pure.  */
       if (setjmp_call_p (callee_t))
-       local->pure_const_state = IPA_NEITHER;
+       {
+         local->pure_const_state = IPA_NEITHER;
+         local->looping = false;
+       }
 
       if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL)
        switch (DECL_FUNCTION_CODE (callee_t))
@@ -347,6 +364,7 @@ check_call (funct_state local, tree call_expr)
          case BUILT_IN_LONGJMP:
          case BUILT_IN_NONLOCAL_GOTO:
            local->pure_const_state = IPA_NEITHER;
+           local->looping = false;
            break;
          default:
            break;
@@ -391,7 +409,7 @@ scan_function (tree *tp,
                      int *walk_subtrees, 
                      void *data)
 {
-  struct cgraph_node *fn = data;
+  struct cgraph_node *fn = (struct cgraph_node *) data;
   tree t = *tp;
   funct_state local = get_function_state (fn);
 
@@ -403,11 +421,11 @@ scan_function (tree *tp,
       *walk_subtrees = 0;
       break;
 
-    case MODIFY_EXPR:
+    case GIMPLE_MODIFY_STMT:
       {
        /* First look on the lhs and see what variable is stored to */
-       tree lhs = TREE_OPERAND (t, 0);
-       tree rhs = TREE_OPERAND (t, 1);
+       tree lhs = GIMPLE_STMT_OPERAND (t, 0);
+       tree rhs = GIMPLE_STMT_OPERAND (t, 1);
        check_lhs_var (local, lhs);
 
        /* For the purposes of figuring out what the cast affects */
@@ -442,7 +460,14 @@ scan_function (tree *tp,
              case ADDR_EXPR:
                check_rhs_var (local, rhs);
                break;
-             case CALL_EXPR: 
+             default:
+               break;
+             }
+           break;
+         case tcc_vl_exp:
+           switch (TREE_CODE (rhs)) 
+             {
+             case CALL_EXPR:
                check_call (local, rhs);
                break;
              default:
@@ -466,7 +491,10 @@ scan_function (tree *tp,
     case LABEL_EXPR:
       if (DECL_NONLOCAL (TREE_OPERAND (t, 0)))
        /* Target of long jump. */
-       local->pure_const_state = IPA_NEITHER;
+       {
+         local->pure_const_state = IPA_NEITHER;
+         local->looping = false;
+       }
       break;
 
     case CALL_EXPR: 
@@ -493,12 +521,16 @@ analyze_function (struct cgraph_node *fn)
 {
   funct_state l = XCNEW (struct funct_state_d);
   tree decl = fn->decl;
-  struct ipa_dfs_info * w_info = fn->aux;
+  struct ipa_dfs_info * w_info = (struct ipa_dfs_info *) fn->aux;
 
   w_info->aux = l;
 
   l->pure_const_state = IPA_CONST;
   l->state_set_in_source = false;
+  if (DECL_LOOPING_CONST_OR_PURE_P (decl))
+    l->looping = true;
+  else
+    l->looping = false;
 
   /* If this function does not return normally or does not bind local,
      do not touch this unless it has been marked as const or pure by the
@@ -515,7 +547,7 @@ analyze_function (struct cgraph_node *fn)
       l->pure_const_state = IPA_CONST;
       l->state_set_in_source = true;
     }
-  if (DECL_IS_PURE (decl))
+  if (DECL_PURE_P (decl))
     {
       l->pure_const_state = IPA_PURE;
       l->state_set_in_source = true;
@@ -541,7 +573,7 @@ analyze_function (struct cgraph_node *fn)
              walk_tree (bsi_stmt_ptr (bsi), scan_function, 
                         fn, visited_nodes);
              if (l->pure_const_state == IPA_NEITHER) 
-               return;
+               goto end;
            }
        }
 
@@ -568,6 +600,14 @@ analyze_function (struct cgraph_node *fn)
          pop_cfun ();
        }
     }
+
+end:
+  if (dump_file)
+    {
+      fprintf (dump_file, "after local analysis of %s with initial value = %d\n ", 
+              cgraph_node_name (fn),
+              l->pure_const_state);
+    }
 }
 
 \f
@@ -582,7 +622,7 @@ static_execute (void)
   struct cgraph_node *w;
   struct cgraph_node **order =
     XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
-  int order_pos = order_pos = ipa_utils_reduced_inorder (order, true, false);
+  int order_pos = ipa_utils_reduced_inorder (order, true, false);
   int i;
   struct ipa_dfs_info * w_info;
 
@@ -622,6 +662,8 @@ static_execute (void)
   for (i = 0; i < order_pos; i++ )
     {
       enum pure_const_state_e pure_const_state = IPA_CONST;
+      bool looping = false;
+      int count = 0;
       node = order[i];
 
       /* Find the worst state for any node in the cycle.  */
@@ -632,17 +674,28 @@ static_execute (void)
          if (pure_const_state < w_l->pure_const_state)
            pure_const_state = w_l->pure_const_state;
 
+         if (w_l->looping)
+           looping = true;
+
          if (pure_const_state == IPA_NEITHER) 
            break;
 
          if (!w_l->state_set_in_source)
            {
              struct cgraph_edge *e;
+             count++;
+
+             if (count > 1)
+               looping = true;
+                   
              for (e = w->callees; e; e = e->next_callee) 
                {
                  struct cgraph_node *y = e->callee;
                  /* Only look at the master nodes and skip external nodes.  */
                  y = cgraph_master_clone (y);
+
+                 if (w == y)
+                   looping = true;
                  if (y)
                    {
                      funct_state y_l = get_function_state (y);
@@ -650,10 +703,12 @@ static_execute (void)
                        pure_const_state = y_l->pure_const_state;
                      if (pure_const_state == IPA_NEITHER) 
                        break;
+                     if (y_l->looping)
+                       looping = true;
                    }
                }
            }
-         w_info = w->aux;
+         w_info = (struct ipa_dfs_info *) w->aux;
          w = w_info->next_cycle;
        }
 
@@ -672,15 +727,19 @@ static_execute (void)
                {
                case IPA_CONST:
                  TREE_READONLY (w->decl) = 1;
+                 DECL_LOOPING_CONST_OR_PURE_P (w->decl) = looping;
                  if (dump_file)
-                   fprintf (dump_file, "Function found to be const: %s\n",  
+                   fprintf (dump_file, "Function found to be %sconst: %s\n",  
+                            looping ? "looping " : "",
                             lang_hooks.decl_printable_name(w->decl, 2)); 
                  break;
                  
                case IPA_PURE:
-                 DECL_IS_PURE (w->decl) = 1;
+                 DECL_PURE_P (w->decl) = 1;
+                 DECL_LOOPING_CONST_OR_PURE_P (w->decl) = looping;
                  if (dump_file)
-                   fprintf (dump_file, "Function found to be pure: %s\n",  
+                   fprintf (dump_file, "Function found to be %spure: %s\n",  
+                            looping ? "looping " : "",
                             lang_hooks.decl_printable_name(w->decl, 2)); 
                  break;
                  
@@ -688,7 +747,7 @@ static_execute (void)
                  break;
                }
            }
-         w_info = w->aux;
+         w_info = (struct ipa_dfs_info *) w->aux;
          w = w_info->next_cycle;
        }
     }
@@ -698,7 +757,7 @@ static_execute (void)
     /* Get rid of the aux information.  */
     if (node->aux)
       {
-       w_info = node->aux;
+       w_info = (struct ipa_dfs_info *) node->aux;
        if (w_info->aux)
          free (w_info->aux);
        free (node->aux);
@@ -717,8 +776,10 @@ gate_pure_const (void)
          && !(errorcount || sorrycount));
 }
 
-struct tree_opt_pass pass_ipa_pure_const =
+struct simple_ipa_opt_pass pass_ipa_pure_const =
 {
+ {
+  SIMPLE_IPA_PASS,
   "pure-const",                                /* name */
   gate_pure_const,                     /* gate */
   static_execute,                      /* execute */
@@ -730,8 +791,8 @@ struct tree_opt_pass pass_ipa_pure_const =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                    /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };