OSDN Git Service

* common.opt (N, Q, Qn, Qy, Z, n, r, s, t): New options.
[pf3gnuchains/gcc-fork.git] / gcc / ipa-pure-const.c
index da8d442..101e8c9 100644 (file)
@@ -49,7 +49,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "flags.h"
 #include "timevar.h"
-#include "toplev.h"
 #include "diagnostic.h"
 #include "gimple-pretty-print.h"
 #include "langhooks.h"
@@ -95,6 +94,11 @@ struct funct_state_d
   bool can_throw;
 };
 
+/* State used when we know nothing about function.  */
+static struct funct_state_d varying_state
+   = { IPA_NEITHER, IPA_NEITHER, true, true, true };
+
+
 typedef struct funct_state_d * funct_state;
 
 /* The storage of the funct_state is abstracted because there is the
@@ -133,7 +137,7 @@ suggest_attribute (int option, tree decl, bool known_finite,
                   struct pointer_set_t *warned_about,
                   const char * attrib_name)
 {
-  if (!option_enabled (option))
+  if (!option_enabled (option, &global_options))
     return warned_about;
   if (TREE_THIS_VOLATILE (decl)
       || (known_finite && function_always_visible_to_compiler_p (decl)))
@@ -212,13 +216,12 @@ has_function_state (struct cgraph_node *node)
 static inline funct_state
 get_function_state (struct cgraph_node *node)
 {
-  static struct funct_state_d varying
-    = { IPA_NEITHER, IPA_NEITHER, true, true, true };
   if (!funct_state_vec
-      || VEC_length (funct_state, funct_state_vec) <= (unsigned int)node->uid)
+      || VEC_length (funct_state, funct_state_vec) <= (unsigned int)node->uid
+      || !VEC_index (funct_state, funct_state_vec, node->uid))
     /* We might want to put correct previously_known state into varying.  */
-    return &varying;
 return VEC_index (funct_state, funct_state_vec, node->uid);
+    return &varying_state;
+ return VEC_index (funct_state, funct_state_vec, node->uid);
 }
 
 /* Set the function state S for NODE.  */
@@ -324,7 +327,7 @@ check_op (funct_state local, tree t, bool checking_write)
       return;
     }
   else if (t
-          && INDIRECT_REF_P (t)
+          && (INDIRECT_REF_P (t) || TREE_CODE (t) == MEM_REF)
           && TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME
           && !ptr_deref_may_alias_global_p (TREE_OPERAND (t, 0)))
     {
@@ -420,6 +423,39 @@ worse_state (enum pure_const_state_e *state, bool *looping,
   *looping = MAX (*looping, looping2);
 }
 
+/* Recognize special cases of builtins that are by themself not pure or const
+   but function using them is.  */
+static bool
+special_builtin_state (enum pure_const_state_e *state, bool *looping,
+                       tree callee)
+{
+  if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (callee))
+      {
+       case BUILT_IN_RETURN:
+       case BUILT_IN_UNREACHABLE:
+       case BUILT_IN_ALLOCA:
+       case BUILT_IN_STACK_SAVE:
+       case BUILT_IN_STACK_RESTORE:
+       case BUILT_IN_EH_POINTER:
+       case BUILT_IN_EH_FILTER:
+       case BUILT_IN_UNWIND_RESUME:
+       case BUILT_IN_CXA_END_CLEANUP:
+       case BUILT_IN_EH_COPY_VALUES:
+       case BUILT_IN_FRAME_ADDRESS:
+       case BUILT_IN_APPLY:
+       case BUILT_IN_APPLY_ARGS:
+         *looping = false;
+         *state = IPA_CONST;
+         return true;
+       case BUILT_IN_PREFETCH:
+         *looping = true;
+         *state = IPA_CONST;
+         return true;
+      }
+  return false;
+}
+
 /* Check the parameters of a function call to CALL_EXPR to see if
    there are any references in the parameters that are not allowed for
    pure or const functions.  Also check to see if this is either an
@@ -470,9 +506,15 @@ check_call (funct_state local, gimple call, bool ipa)
      graph.  */
   if (callee_t)
     {
-      /* built_in_return is really just an return statemnt.  */
-      if (gimple_call_builtin_p (call, BUILT_IN_RETURN))
-       return;
+      enum pure_const_state_e call_state;
+      bool call_looping;
+
+      if (special_builtin_state (&call_state, &call_looping, callee_t))
+       {
+         worse_state (&local->pure_const_state, &local->looping,
+                      call_state, call_looping);
+         return;
+       }
       /* When bad things happen to bad functions, they cannot be const
         or pure.  */
       if (setjmp_call_p (callee_t))
@@ -608,6 +650,13 @@ check_stmt (gimple_stmt_iterator *gsip, funct_state local, bool ipa)
       print_gimple_stmt (dump_file, stmt, 0, 0);
     }
 
+  if (gimple_has_volatile_ops (stmt))
+    {
+      local->pure_const_state = IPA_NEITHER;
+      if (dump_file)
+       fprintf (dump_file, "    Volatile stmt is not const/pure\n");
+    }
+
   /* Look for loads and stores.  */
   walk_stmt_load_store_ops (stmt, local,
                            ipa ? check_ipa_load : check_load,
@@ -820,7 +869,9 @@ remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
 {
   if (has_function_state (node))
     {
-      free (get_function_state (node));
+      funct_state l = get_function_state (node);
+      if (l != &varying_state)
+        free (l);
       set_function_state (node, NULL);
     }
 }
@@ -903,7 +954,7 @@ pure_const_write_summary (cgraph_node_set set,
       node = csi_node (csi);
       if (node->analyzed && has_function_state (node))
        {
-         struct bitpack_d *bp;
+         struct bitpack_d bp;
          funct_state fs;
          int node_ref;
          lto_cgraph_encoder_t encoder;
@@ -916,14 +967,13 @@ pure_const_write_summary (cgraph_node_set set,
 
          /* Note that flags will need to be read in the opposite
             order as we are pushing the bitflags into FLAGS.  */
-         bp = bitpack_create ();
-         bp_pack_value (bp, fs->pure_const_state, 2);
-         bp_pack_value (bp, fs->state_previously_known, 2);
-         bp_pack_value (bp, fs->looping_previously_known, 1);
-         bp_pack_value (bp, fs->looping, 1);
-         bp_pack_value (bp, fs->can_throw, 1);
-         lto_output_bitpack (ob->main_stream, bp);
-         bitpack_delete (bp);
+         bp = bitpack_create (ob->main_stream);
+         bp_pack_value (&bp, fs->pure_const_state, 2);
+         bp_pack_value (&bp, fs->state_previously_known, 2);
+         bp_pack_value (&bp, fs->looping_previously_known, 1);
+         bp_pack_value (&bp, fs->looping, 1);
+         bp_pack_value (&bp, fs->can_throw, 1);
+         lto_output_bitpack (&bp);
        }
     }
 
@@ -958,7 +1008,7 @@ pure_const_read_summary (void)
            {
              unsigned int index;
              struct cgraph_node *node;
-             struct bitpack_d *bp;
+             struct bitpack_d bp;
              funct_state fs;
              lto_cgraph_encoder_t encoder;
 
@@ -973,12 +1023,12 @@ pure_const_read_summary (void)
                 pushed into FLAGS).  */
              bp = lto_input_bitpack (ib);
              fs->pure_const_state
-                       = (enum pure_const_state_e) bp_unpack_value (bp, 2);
+                       = (enum pure_const_state_e) bp_unpack_value (&bp, 2);
              fs->state_previously_known
-                       = (enum pure_const_state_e) bp_unpack_value (bp, 2);
-             fs->looping_previously_known = bp_unpack_value (bp, 1);
-             fs->looping = bp_unpack_value (bp, 1);
-             fs->can_throw = bp_unpack_value (bp, 1);
+                       = (enum pure_const_state_e) bp_unpack_value (&bp, 2);
+             fs->looping_previously_known = bp_unpack_value (&bp, 1);
+             fs->looping = bp_unpack_value (&bp, 1);
+             fs->can_throw = bp_unpack_value (&bp, 1);
              if (dump_file)
                {
                  int flags = flags_from_decl_or_type (node->decl);
@@ -1002,7 +1052,6 @@ pure_const_read_summary (void)
                  if (fs->can_throw)
                    fprintf (dump_file,"  function is locally throwing\n");
                }
-             bitpack_delete (bp);
            }
 
          lto_destroy_simple_input_block (file_data,
@@ -1153,10 +1202,13 @@ propagate_pure_const (void)
                      edge_looping = y_l->looping;
                    }
                }
+             else if (special_builtin_state (&edge_state, &edge_looping,
+                                              y->decl))
+               ;
              else
                state_from_flags (&edge_state, &edge_looping,
-                                 flags_from_decl_or_type (y->decl),
-                                 cgraph_edge_cannot_lead_to_return (e));
+                                 flags_from_decl_or_type (y->decl),
+                                 cgraph_edge_cannot_lead_to_return (e));
 
              /* Merge the results with what we already know.  */
              better_state (&edge_state, &edge_looping,
@@ -1269,8 +1321,7 @@ propagate_pure_const (void)
                             this_looping ? "looping " : "",
                             cgraph_node_name (w));
                }
-             cgraph_set_readonly_flag (w, true);
-             cgraph_set_looping_const_or_pure_flag (w, this_looping);
+             cgraph_set_const_flag (w, true, this_looping);
              break;
 
            case IPA_PURE:
@@ -1282,8 +1333,7 @@ propagate_pure_const (void)
                             this_looping ? "looping " : "",
                             cgraph_node_name (w));
                }
-             cgraph_set_pure_flag (w, true);
-             cgraph_set_looping_const_or_pure_flag (w, this_looping);
+             cgraph_set_pure_flag (w, true, this_looping);
              break;
 
            default:
@@ -1520,7 +1570,9 @@ local_pure_const (void)
       && skip)
     return 0;
 
-  /* First do NORETURN discovery.  */
+  l = analyze_function (node, false);
+
+  /* Do NORETURN discovery.  */
   if (!skip && !TREE_THIS_VOLATILE (current_function_decl)
       && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0)
     {
@@ -1536,7 +1588,6 @@ local_pure_const (void)
 
       changed = true;
     }
-  l = analyze_function (node, false);
 
   switch (l->pure_const_state)
     {
@@ -1546,8 +1597,7 @@ local_pure_const (void)
          warn_function_const (current_function_decl, !l->looping);
          if (!skip)
            {
-             cgraph_set_readonly_flag (node, true);
-             cgraph_set_looping_const_or_pure_flag (node, l->looping);
+             cgraph_set_const_flag (node, true, l->looping);
              changed = true;
            }
          if (dump_file)
@@ -1561,7 +1611,7 @@ local_pure_const (void)
        {
          if (!skip)
            {
-             cgraph_set_looping_const_or_pure_flag (node, false);
+             cgraph_set_const_flag (node, true, false);
              changed = true;
            }
          if (dump_file)
@@ -1576,8 +1626,7 @@ local_pure_const (void)
        {
          if (!skip)
            {
-             cgraph_set_pure_flag (node, true);
-             cgraph_set_looping_const_or_pure_flag (node, l->looping);
+             cgraph_set_pure_flag (node, true, l->looping);
              changed = true;
            }
          warn_function_pure (current_function_decl, !l->looping);
@@ -1592,7 +1641,7 @@ local_pure_const (void)
        {
          if (!skip)
            {
-             cgraph_set_looping_const_or_pure_flag (node, false);
+             cgraph_set_pure_flag (node, true, false);
              changed = true;
            }
          if (dump_file)