OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / passes.c
index 4cfc4d3..a786881 100644 (file)
@@ -1,7 +1,7 @@
 /* Top level of GCC compilers (cc1, cc1plus, etc.)
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011, 2012  Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-streamer.h"
 #include "plugin.h"
 #include "ipa-utils.h"
+#include "tree-pretty-print.h"
 
 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
@@ -155,6 +156,11 @@ rest_of_decl_compilation (tree decl,
       {
        alias = TREE_VALUE (TREE_VALUE (alias));
        alias = get_identifier (TREE_STRING_POINTER (alias));
+       /* A quirk of the initial implementation of aliases required that the
+          user add "extern" to all of them.  Which is silly, but now
+          historical.  Do note that the symbol is in fact locally defined.  */
+       if (!lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+         DECL_EXTERNAL (decl) = 0;
        assemble_alias (decl, alias);
       }
   }
@@ -331,7 +337,7 @@ struct rtl_opt_pass pass_postreload =
 
 /* The root of the compilation pass tree, once constructed.  */
 struct opt_pass *all_passes, *all_small_ipa_passes, *all_lowering_passes,
-  *all_regular_ipa_passes, *all_lto_gen_passes;
+  *all_regular_ipa_passes, *all_late_ipa_passes, *all_lto_gen_passes;
 
 /* This is used by plugins, and should also be used in register_pass.  */
 #define DEF_PASS_LIST(LIST) &LIST,
@@ -408,6 +414,7 @@ register_one_dump_file (struct opt_pass *pass)
   set_pass_for_id (id, pass);
   full_name = concat (prefix, pass->name, num, NULL);
   register_pass_name (pass, full_name);
+  free (CONST_CAST (char *, full_name));
 }
 
 /* Recursive worker function for register_dump_files.  */
@@ -477,7 +484,7 @@ passr_eq (const void *p1, const void *p2)
   return !strcmp (s1->unique_name, s2->unique_name);
 }
 
-static htab_t pass_name_tab = NULL;
+static htab_t name_to_pass_map = NULL;
 
 /* Register PASS with NAME.  */
 
@@ -487,11 +494,11 @@ register_pass_name (struct opt_pass *pass, const char *name)
   struct pass_registry **slot;
   struct pass_registry pr;
 
-  if (!pass_name_tab)
-    pass_name_tab = htab_create (256, passr_hash, passr_eq, NULL);
+  if (!name_to_pass_map)
+    name_to_pass_map = htab_create (256, passr_hash, passr_eq, NULL);
 
   pr.unique_name = name;
-  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, INSERT);
+  slot = (struct pass_registry **) htab_find_slot (name_to_pass_map, &pr, INSERT);
   if (!*slot)
     {
       struct pass_registry *new_pr;
@@ -505,6 +512,125 @@ register_pass_name (struct opt_pass *pass, const char *name)
     return; /* Ignore plugin passes.  */
 }
 
+/* Map from pass id to canonicalized pass name.  */
+
+typedef const char *char_ptr;
+DEF_VEC_P(char_ptr);
+DEF_VEC_ALLOC_P(char_ptr, heap);
+static VEC(char_ptr, heap) *pass_tab = NULL;
+
+/* Callback function for traversing NAME_TO_PASS_MAP.  */
+
+static int
+pass_traverse (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  struct pass_registry **p = (struct pass_registry **)slot;
+  struct opt_pass *pass = (*p)->pass;
+
+  gcc_assert (pass->static_pass_number > 0);
+  gcc_assert (pass_tab);
+
+  VEC_replace (char_ptr, pass_tab, pass->static_pass_number,
+               (*p)->unique_name);
+
+  return 1;
+}
+
+/* The function traverses NAME_TO_PASS_MAP and creates a pass info
+   table for dumping purpose.  */
+
+static void
+create_pass_tab (void)
+{
+  if (!flag_dump_passes)
+    return;
+
+  VEC_safe_grow_cleared (char_ptr, heap,
+                         pass_tab, passes_by_id_size + 1);
+  htab_traverse (name_to_pass_map, pass_traverse, NULL);
+}
+
+static bool override_gate_status (struct opt_pass *, tree, bool);
+
+/* Dump the instantiated name for PASS. IS_ON indicates if PASS
+   is turned on or not.  */
+
+static void
+dump_one_pass (struct opt_pass *pass, int pass_indent)
+{
+  int indent = 3 * pass_indent;
+  const char *pn;
+  bool is_on, is_really_on;
+
+  is_on = (pass->gate == NULL) ? true : pass->gate();
+  is_really_on = override_gate_status (pass, current_function_decl, is_on);
+
+  if (pass->static_pass_number <= 0)
+    pn = pass->name;
+  else
+    pn = VEC_index (char_ptr, pass_tab, pass->static_pass_number);
+
+  fprintf (stderr, "%*s%-40s%*s:%s%s\n", indent, " ", pn,
+           (15 - indent < 0 ? 0 : 15 - indent), " ",
+           is_on ? "  ON" : "  OFF",
+           ((!is_on) == (!is_really_on) ? ""
+            : (is_really_on ? " (FORCED_ON)" : " (FORCED_OFF)")));
+}
+
+/* Dump pass list PASS with indentation INDENT.  */
+
+static void
+dump_pass_list (struct opt_pass *pass, int indent)
+{
+  do
+    {
+      dump_one_pass (pass, indent);
+      if (pass->sub)
+        dump_pass_list (pass->sub, indent + 1);
+      pass = pass->next;
+    }
+  while (pass);
+}
+
+/* Dump all optimization passes.  */
+
+void
+dump_passes (void)
+{
+  struct cgraph_node *n, *node = NULL;
+  tree save_fndecl = current_function_decl;
+
+  create_pass_tab();
+
+  n = cgraph_nodes;
+  while (n)
+    {
+      if (DECL_STRUCT_FUNCTION (n->decl))
+        {
+          node = n;
+          break;
+        }
+      n = n->next;
+    }
+
+  if (!node)
+    return;
+
+  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+  current_function_decl = node->decl;
+
+  dump_pass_list (all_lowering_passes, 1);
+  dump_pass_list (all_small_ipa_passes, 1);
+  dump_pass_list (all_regular_ipa_passes, 1);
+  dump_pass_list (all_lto_gen_passes, 1);
+  dump_pass_list (all_late_ipa_passes, 1);
+  dump_pass_list (all_passes, 1);
+
+  pop_cfun ();
+  current_function_decl = save_fndecl;
+}
+
+
 /* Returns the pass with NAME.  */
 
 static struct opt_pass *
@@ -512,9 +638,8 @@ get_pass_by_name (const char *name)
 {
   struct pass_registry **slot, pr;
 
-  gcc_assert (pass_name_tab);
   pr.unique_name = name;
-  slot = (struct pass_registry **) htab_find_slot (pass_name_tab,
+  slot = (struct pass_registry **) htab_find_slot (name_to_pass_map,
                                                    &pr, NO_INSERT);
 
   if (!slot || !*slot)
@@ -530,6 +655,7 @@ struct uid_range
 {
   unsigned int start;
   unsigned int last;
+  const char *assem_name;
   struct uid_range *next;
 };
 
@@ -541,6 +667,7 @@ DEF_VEC_ALLOC_P(uid_range_p, heap);
 static VEC(uid_range_p, heap) *enabled_pass_uid_range_tab = NULL;
 static VEC(uid_range_p, heap) *disabled_pass_uid_range_tab = NULL;
 
+
 /* Parse option string for -fdisable- and -fenable-
    The syntax of the options:
 
@@ -627,6 +754,7 @@ enable_disable_pass (const char *arg, bool is_enable)
          uid_range_p new_range;
          char *invalid = NULL;
          long start;
+         char *func_name = NULL;
 
          next_range = strchr (one_range, ',');
          if (next_range)
@@ -644,17 +772,31 @@ enable_disable_pass (const char *arg, bool is_enable)
          start = strtol (one_range, &invalid, 10);
          if (*invalid || start < 0)
            {
-             error ("Invalid range %s in option %s",
-                    one_range,
-                    is_enable ? "-fenable" : "-fdisable");
-             free (argstr);
-             return;
+              if (end_val || (one_range[0] >= '0'
+                             && one_range[0] <= '9'))
+                {
+                  error ("Invalid range %s in option %s",
+                         one_range,
+                         is_enable ? "-fenable" : "-fdisable");
+                  free (argstr);
+                  return;
+                }
+             func_name = one_range;
            }
          if (!end_val)
            {
              new_range = XCNEW (struct uid_range);
-             new_range->start = (unsigned) start;
-             new_range->last = (unsigned) start;
+              if (!func_name)
+                {
+                  new_range->start = (unsigned) start;
+                  new_range->last = (unsigned) start;
+                }
+              else
+                {
+                  new_range->start = (unsigned) -1;
+                  new_range->last = (unsigned) -1;
+                  new_range->assem_name = xstrdup (func_name);
+                }
            }
          else
            {
@@ -676,15 +818,28 @@ enable_disable_pass (const char *arg, bool is_enable)
           new_range->next = slot;
           VEC_replace (uid_range_p, *tab, pass->static_pass_number,
                        new_range);
-
           if (is_enable)
-            inform (UNKNOWN_LOCATION,
-                    "enable pass %s for functions in the range of [%u, %u]",
-                    phase_name, new_range->start, new_range->last);
+            {
+              if (new_range->assem_name)
+                inform (UNKNOWN_LOCATION,
+                        "enable pass %s for function %s",
+                        phase_name, new_range->assem_name);
+              else
+                inform (UNKNOWN_LOCATION,
+                        "enable pass %s for functions in the range of [%u, %u]",
+                        phase_name, new_range->start, new_range->last);
+            }
           else
-            inform (UNKNOWN_LOCATION,
-                    "disable pass %s for functions in the range of [%u, %u]",
-                    phase_name, new_range->start, new_range->last);
+            {
+              if (new_range->assem_name)
+                inform (UNKNOWN_LOCATION,
+                        "disable pass %s for function %s",
+                        phase_name, new_range->assem_name);
+              else
+                inform (UNKNOWN_LOCATION,
+                        "disable pass %s for functions in the range of [%u, %u]",
+                        phase_name, new_range->start, new_range->last);
+            }
 
          one_range = next_range;
        } while (next_range);
@@ -718,6 +873,7 @@ is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
 {
   uid_range_p slot, range;
   int cgraph_uid;
+  const char *aname = NULL;
 
   if (!tab
       || (unsigned) pass->static_pass_number >= VEC_length (uid_range_p, tab)
@@ -729,6 +885,8 @@ is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
     return false;
 
   cgraph_uid = func ? cgraph_get_node (func)->uid : 0;
+  if (func && DECL_ASSEMBLER_NAME_SET_P (func))
+    aname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func));
 
   range = slot;
   while (range)
@@ -736,6 +894,9 @@ is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
       if ((unsigned) cgraph_uid >= range->start
          && (unsigned) cgraph_uid <= range->last)
        return true;
+      if (range->assem_name && aname
+          && !strcmp (range->assem_name, aname))
+        return true;
       range = range->next;
     }
 
@@ -949,6 +1110,8 @@ register_pass (struct register_pass_info *pass_info)
   if (!success || all_instances)
     success |= position_pass (pass_info, &all_lto_gen_passes);
   if (!success || all_instances)
+    success |= position_pass (pass_info, &all_late_ipa_passes);
+  if (!success || all_instances)
     success |= position_pass (pass_info, &all_passes);
   if (!success)
     fatal_error
@@ -1017,9 +1180,11 @@ init_optimization_passes (void)
   p = &all_lowering_passes;
   NEXT_PASS (pass_warn_unused_result);
   NEXT_PASS (pass_diagnose_omp_blocks);
+  NEXT_PASS (pass_diagnose_tm_blocks);
   NEXT_PASS (pass_mudflap_1);
   NEXT_PASS (pass_lower_omp);
   NEXT_PASS (pass_lower_cf);
+  NEXT_PASS (pass_lower_tm);
   NEXT_PASS (pass_refactor_eh);
   NEXT_PASS (pass_lower_eh);
   NEXT_PASS (pass_build_cfg);
@@ -1084,6 +1249,7 @@ init_optimization_passes (void)
     }
   NEXT_PASS (pass_ipa_increase_alignment);
   NEXT_PASS (pass_ipa_matrix_reorg);
+  NEXT_PASS (pass_ipa_tm);
   NEXT_PASS (pass_ipa_lower_emutls);
   *p = NULL;
 
@@ -1095,7 +1261,6 @@ init_optimization_passes (void)
   NEXT_PASS (pass_ipa_inline);
   NEXT_PASS (pass_ipa_pure_const);
   NEXT_PASS (pass_ipa_reference);
-  NEXT_PASS (pass_ipa_pta);
   *p = NULL;
 
   p = &all_lto_gen_passes;
@@ -1103,9 +1268,16 @@ init_optimization_passes (void)
   NEXT_PASS (pass_ipa_lto_finish_out);  /* This must be the last LTO pass.  */
   *p = NULL;
 
+  /* Simple IPA passes executed after the regular passes.  In WHOPR mode the
+     passes are executed after partitioning and thus see just parts of the
+     compiled unit.  */
+  p = &all_late_ipa_passes;
+  NEXT_PASS (pass_ipa_pta);
+  *p = NULL;
   /* These passes are run after IPA passes on every function that is being
      output to the assembler file.  */
   p = &all_passes;
+  NEXT_PASS (pass_fixup_cfg);
   NEXT_PASS (pass_lower_eh_dispatch);
   NEXT_PASS (pass_all_optimizations);
     {
@@ -1158,6 +1330,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_forwprop);
       NEXT_PASS (pass_phiopt);
       NEXT_PASS (pass_object_sizes);
+      NEXT_PASS (pass_strlen);
       NEXT_PASS (pass_ccp);
       NEXT_PASS (pass_copy_prop);
       NEXT_PASS (pass_cse_sincos);
@@ -1191,7 +1364,6 @@ init_optimization_passes (void)
          NEXT_PASS (pass_vectorize);
            {
              struct opt_pass **p = &pass_vectorize.pass.sub;
-             NEXT_PASS (pass_lower_vector_ssa);
              NEXT_PASS (pass_dce_loop);
            }
           NEXT_PASS (pass_predcom);
@@ -1200,8 +1372,10 @@ init_optimization_passes (void)
          NEXT_PASS (pass_parallelize_loops);
          NEXT_PASS (pass_loop_prefetch);
          NEXT_PASS (pass_iv_optimize);
+         NEXT_PASS (pass_lim);
          NEXT_PASS (pass_tree_loop_done);
        }
+      NEXT_PASS (pass_lower_vector_ssa);
       NEXT_PASS (pass_cse_reciprocals);
       NEXT_PASS (pass_reassoc);
       NEXT_PASS (pass_vrp);
@@ -1235,6 +1409,13 @@ init_optimization_passes (void)
       NEXT_PASS (pass_uncprop);
       NEXT_PASS (pass_local_pure_const);
     }
+  NEXT_PASS (pass_tm_init);
+    {
+      struct opt_pass **p = &pass_tm_init.pass.sub;
+      NEXT_PASS (pass_tm_mark);
+      NEXT_PASS (pass_tm_memopt);
+      NEXT_PASS (pass_tm_edges);
+    }
   NEXT_PASS (pass_lower_complex_O0);
   NEXT_PASS (pass_cleanup_eh);
   NEXT_PASS (pass_lower_resx);
@@ -1304,13 +1485,14 @@ init_optimization_passes (void)
       NEXT_PASS (pass_sms);
       NEXT_PASS (pass_sched);
       NEXT_PASS (pass_ira);
+      NEXT_PASS (pass_reload);
       NEXT_PASS (pass_postreload);
        {
          struct opt_pass **p = &pass_postreload.pass.sub;
          NEXT_PASS (pass_postreload_cse);
          NEXT_PASS (pass_gcse2);
          NEXT_PASS (pass_split_after_reload);
-         NEXT_PASS (pass_implicit_zee);
+         NEXT_PASS (pass_ree);
          NEXT_PASS (pass_compare_elim_after_reload);
          NEXT_PASS (pass_branch_target_load_optimize1);
          NEXT_PASS (pass_thread_prologue_and_epilogue);
@@ -1343,6 +1525,7 @@ init_optimization_passes (void)
          NEXT_PASS (pass_convert_to_eh_region_ranges);
          NEXT_PASS (pass_shorten_branches);
          NEXT_PASS (pass_set_nothrow_function_flags);
+         NEXT_PASS (pass_dwarf2_frame);
          NEXT_PASS (pass_final);
        }
       NEXT_PASS (pass_df_finish);
@@ -1363,6 +1546,9 @@ init_optimization_passes (void)
   register_dump_files (all_lto_gen_passes,
                       PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
                       | PROP_cfg);
+  register_dump_files (all_late_ipa_passes,
+                      PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
+                      | PROP_cfg);
   register_dump_files (all_passes,
                       PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
                       | PROP_cfg);
@@ -1448,6 +1634,37 @@ do_per_function_toporder (void (*callback) (void *data), void *data)
   nnodes = 0;
 }
 
+/* Helper function to perform function body dump.  */
+
+static void
+execute_function_dump (void *data ATTRIBUTE_UNUSED)
+{
+  if (dump_file && current_function_decl)
+    {
+      if (cfun->curr_properties & PROP_trees)
+        dump_function_to_file (current_function_decl, dump_file, dump_flags);
+      else
+       {
+         if (dump_flags & TDF_SLIM)
+           print_rtl_slim_with_bb (dump_file, get_insns (), dump_flags);
+         else if ((cfun->curr_properties & PROP_cfg)
+                  && (dump_flags & TDF_BLOCKS))
+           print_rtl_with_bb (dump_file, get_insns ());
+          else
+           print_rtl (dump_file, get_insns ());
+
+         if ((cfun->curr_properties & PROP_cfg)
+             && graph_dump_format != no_graph
+             && (dump_flags & TDF_GRAPH))
+           print_rtl_graph_with_bb (dump_file_name, get_insns ());
+       }
+
+      /* Flush the file.  If verification fails, we won't be able to
+        close the file before aborting.  */
+      fflush (dump_file);
+    }
+}
+
 /* Perform all TODO actions that ought to be done on each function.  */
 
 static void
@@ -1494,31 +1711,6 @@ execute_function_todo (void *data)
   if (flags & TODO_remove_unused_locals)
     remove_unused_locals ();
 
-  if ((flags & TODO_dump_func) && dump_file && current_function_decl)
-    {
-      if (cfun->curr_properties & PROP_trees)
-        dump_function_to_file (current_function_decl, dump_file, dump_flags);
-      else
-       {
-         if (dump_flags & TDF_SLIM)
-           print_rtl_slim_with_bb (dump_file, get_insns (), dump_flags);
-         else if ((cfun->curr_properties & PROP_cfg)
-                  && (dump_flags & TDF_BLOCKS))
-           print_rtl_with_bb (dump_file, get_insns ());
-          else
-           print_rtl (dump_file, get_insns ());
-
-         if ((cfun->curr_properties & PROP_cfg)
-             && graph_dump_format != no_graph
-             && (dump_flags & TDF_GRAPH))
-           print_rtl_graph_with_bb (dump_file_name, get_insns ());
-       }
-
-      /* Flush the file.  If verification fails, we won't be able to
-        close the file before aborting.  */
-      fflush (dump_file);
-    }
-
   if (flags & TODO_rebuild_frequencies)
     rebuild_frequencies ();
 
@@ -1637,21 +1829,7 @@ pass_init_dump_file (struct opt_pass *pass)
       dump_file_name = get_dump_file_name (pass->static_pass_number);
       dump_file = dump_begin (pass->static_pass_number, &dump_flags);
       if (dump_file && current_function_decl)
-       {
-         const char *dname, *aname;
-         struct cgraph_node *node = cgraph_get_node (current_function_decl);
-         dname = lang_hooks.decl_printable_name (current_function_decl, 2);
-         aname = (IDENTIFIER_POINTER
-                  (DECL_ASSEMBLER_NAME (current_function_decl)));
-         fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
-            node->frequency == NODE_FREQUENCY_HOT
-            ? " (hot)"
-            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
-            ? " (unlikely executed)"
-            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
-            ? " (executed once)"
-            : "");
-       }
+        dump_function_header (dump_file, current_function_decl, dump_flags);
       return initializing_dump;
     }
   else
@@ -1758,6 +1936,7 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
   execute_todo (todo_after);
   verify_interpass_invariants ();
 
+  do_per_function (execute_function_dump, NULL);
   pass_fini_dump_file (pass);
 
   current_pass = NULL;
@@ -1788,6 +1967,20 @@ execute_all_ipa_transforms (void)
     }
 }
 
+/* Callback for do_per_function to apply all IPA transforms.  */
+
+static void
+apply_ipa_transforms (void *data)
+{
+  struct cgraph_node *node = cgraph_get_node (current_function_decl);
+  if (!node->global.inlined_to && node->ipa_transforms_to_apply)
+    {
+      *(bool *)data = true;
+      execute_all_ipa_transforms();
+      rebuild_cgraph_edges ();
+    }
+}
+
 /* Check if PASS is explicitly disabled or enabled and return
    the gate status.  FUNC is the function to be processed, and
    GATE_STATUS is the gate status determined by pass manager by
@@ -1849,6 +2042,18 @@ execute_one_pass (struct opt_pass *pass)
      executed.  */
   invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass);
 
+  /* SIPLE IPA passes do not handle callgraphs with IPA transforms in it.
+     Apply all trnasforms first.  */
+  if (pass->type == SIMPLE_IPA_PASS)
+    {
+      bool applied = false;
+      do_per_function (apply_ipa_transforms, (void *)&applied);
+      if (applied)
+        cgraph_remove_unreachable_nodes (true, dump_file);
+      /* Restore current_pass.  */
+      current_pass = pass;
+    }
+
   if (!quiet_flag && !cfun)
     fprintf (stderr, " <%s>", pass->name ? pass->name : "");
 
@@ -1898,6 +2103,7 @@ execute_one_pass (struct opt_pass *pass)
   /* Run post-pass cleanup and verification.  */
   execute_todo (todo_after | pass->todo_flags_finish);
   verify_interpass_invariants ();
+  do_per_function (execute_function_dump, NULL);
   if (pass->type == IPA_PASS)
     {
       struct cgraph_node *node;
@@ -2042,7 +2248,7 @@ ipa_write_summaries (void)
   vset = varpool_node_set_new ();
 
   for (vnode = varpool_nodes; vnode; vnode = vnode->next)
-    if (vnode->needed && !vnode->alias)
+    if (vnode->needed && (!vnode->alias || vnode->alias_of))
       varpool_node_set_add (vset, vnode);
 
   ipa_write_summaries_1 (set, vset);