cgraph.c (cgraph_node::call_for_symbol_thunks_and_aliases): Check availability on...
authorJan Hubicka <hubicka@ucw.cz>
Wed, 4 May 2016 16:36:51 +0000 (18:36 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 4 May 2016 16:36:51 +0000 (16:36 +0000)
* cgraph.c (cgraph_node::call_for_symbol_thunks_and_aliases):
Check availability on NODE, too.
* cgraph.h (symtab_node::call_for_symbol_and_aliases): Likewise.
(cgraph_node::call_for_symbol_and_aliases): Likewise.
(varpool_node::call_for_symbol_and_aliase): Likewise.
* ipa-pure-const.c (add_new_function): Analyze all bodies.
(propagate_pure_const): Propagate across interposable functions, too.
(skip_function_for_local_pure_const): Do not skip interposable bodies
with aliases.
(pass_local_pure_const::execute): Update.

* gcc.dg/ipa/pure-const-3.c: New testcase.

From-SVN: r235887

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/ipa-pure-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/ipa/pure-const-3.c [new file with mode: 0644]

index 17390ab74718138c56491499fce84a36de32f3c8..d3d54ec82a538e24678e9ba355a2e455352b551c 100644 (file)
@@ -1,3 +1,16 @@
+2016-05-04  Jan Hubicka  <hubicka@ucw.cz>
+
+       * cgraph.c (cgraph_node::call_for_symbol_thunks_and_aliases):
+       Check availability on NODE, too.
+       * cgraph.h (symtab_node::call_for_symbol_and_aliases): Likewise.
+       (cgraph_node::call_for_symbol_and_aliases): Likewise.
+       (varpool_node::call_for_symbol_and_aliase): Likewise.
+       * ipa-pure-const.c (add_new_function): Analyze all bodies.
+       (propagate_pure_const): Propagate across interposable functions, too.
+       (skip_function_for_local_pure_const): Do not skip interposable bodies
+       with aliases.
+       (pass_local_pure_const::execute): Update.
+
 2016-05-04  Marek Polacek  <polacek@redhat.com>
 
        * doc/invoke.texi: Document -Wdangling-else.
index 782cb520eacf25ba547b06ece696d09e70c08f52..0c6ff93d6253928d2e5bec4d632ea27cd9e6c441 100644 (file)
@@ -2289,7 +2289,7 @@ cgraph_node::can_be_local_p (void)
 }
 
 /* Call callback on cgraph_node, thunks and aliases associated to cgraph_node.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+   When INCLUDE_OVERWRITABLE is false, overwritable symbols are
    skipped.  When EXCLUDE_VIRTUAL_THUNKS is true, virtual thunks are
    skipped.  */
 bool
@@ -2301,9 +2301,14 @@ cgraph_node::call_for_symbol_thunks_and_aliases (bool (*callback)
 {
   cgraph_edge *e;
   ipa_ref *ref;
+  enum availability avail = AVAIL_AVAILABLE;
 
-  if (callback (this, data))
-    return true;
+  if (include_overwritable
+      || (avail = get_availability ()) > AVAIL_INTERPOSABLE)
+    {
+      if (callback (this, data))
+        return true;
+    }
   FOR_EACH_ALIAS (this, ref)
     {
       cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
@@ -2314,7 +2319,7 @@ cgraph_node::call_for_symbol_thunks_and_aliases (bool (*callback)
                                                     exclude_virtual_thunks))
          return true;
     }
-  if (get_availability () <= AVAIL_INTERPOSABLE)
+  if (avail <= AVAIL_INTERPOSABLE)
     return false;
   for (e = callers; e; e = e->next_caller)
     if (e->caller->thunk.thunk_p
index 5ce032e1e5745ed00c2dccf621673fe8b589c938..d714ad75189f8daf5ee845b3e9510ebfcea64466 100644 (file)
@@ -3096,8 +3096,7 @@ symtab_node::get_availability (symtab_node *ref)
 }
 
 /* Call calback on symtab node and aliases associated to this node.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
-   skipped. */
+   When INCLUDE_OVERWRITABLE is false, overwritable symbols are skipped. */
 
 inline bool
 symtab_node::call_for_symbol_and_aliases (bool (*callback) (symtab_node *,
@@ -3105,15 +3104,19 @@ symtab_node::call_for_symbol_and_aliases (bool (*callback) (symtab_node *,
                                          void *data,
                                          bool include_overwritable)
 {
-  if (callback (this, data))
-    return true;
+  if (include_overwritable
+      || get_availability () > AVAIL_INTERPOSABLE)
+    {
+      if (callback (this, data))
+        return true;
+    }
   if (has_aliases_p ())
     return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
   return false;
 }
 
 /* Call callback on function and aliases associated to the function.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+   When INCLUDE_OVERWRITABLE is false, overwritable symbols are
    skipped.  */
 
 inline bool
@@ -3122,15 +3125,19 @@ cgraph_node::call_for_symbol_and_aliases (bool (*callback) (cgraph_node *,
                                          void *data,
                                          bool include_overwritable)
 {
-  if (callback (this, data))
-    return true;
+  if (include_overwritable
+      || get_availability () > AVAIL_INTERPOSABLE)
+    {
+      if (callback (this, data))
+        return true;
+    }
   if (has_aliases_p ())
     return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
   return false;
 }
 
 /* Call calback on varpool symbol and aliases associated to varpool symbol.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+   When INCLUDE_OVERWRITABLE is false, overwritable symbols are
    skipped. */
 
 inline bool
@@ -3139,8 +3146,12 @@ varpool_node::call_for_symbol_and_aliases (bool (*callback) (varpool_node *,
                                           void *data,
                                           bool include_overwritable)
 {
-  if (callback (this, data))
-    return true;
+  if (include_overwritable
+      || get_availability () > AVAIL_INTERPOSABLE)
+    {
+      if (callback (this, data))
+        return true;
+    }
   if (has_aliases_p ())
     return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
   return false;
index 63fbf581c71e41cce6ea7879c542ae5d506b55fb..ba76275a696792ecd89b0346fe66755a2c455cc1 100644 (file)
@@ -927,8 +927,6 @@ end:
 static void
 add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
 {
- if (node->get_availability () < AVAIL_INTERPOSABLE)
-   return;
   /* There are some shared nodes, in particular the initializers on
      static declarations.  We do not need to scan them more than once
      since all we would be interested in are the addressof
@@ -1222,6 +1220,7 @@ propagate_pure_const (void)
   int i;
   struct ipa_dfs_info * w_info;
   bool remove_p = false;
+  bool has_cdtor;
 
   order_pos = ipa_reduced_postorder (order, true, false,
                                     ignore_edge_for_pure_const);
@@ -1274,26 +1273,6 @@ propagate_pure_const (void)
          if (pure_const_state == IPA_NEITHER)
            break;
 
-         /* For interposable nodes we can not assume anything.
-            FIXME: It should be safe to remove this conditional and allow
-            interposable functions with non-interposable aliases next
-            stage 1.  */
-         if (w->get_availability () == AVAIL_INTERPOSABLE)
-           {
-             worse_state (&pure_const_state, &looping,
-                          w_l->state_previously_known,
-                          w_l->looping_previously_known,
-                          NULL, NULL);
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               {
-                 fprintf (dump_file,
-                          "    Interposable. state %s looping %i\n",
-                          pure_const_names[w_l->state_previously_known],
-                          w_l->looping_previously_known);
-               }
-             break;
-           }
-
          count++;
 
          /* We consider recursive cycles as possibly infinite.
@@ -1506,9 +1485,22 @@ propagate_pure_const (void)
                               this_looping ? "looping " : "",
                               w->name ());
                  }
-               remove_p |= w->call_for_symbol_and_aliases (cdtor_p,
-                                                           NULL, true);
-               w->set_const_flag (true, this_looping);
+               /* Turning constructor or destructor to non-looping const/pure
+                  enables us to possibly remove the function completely.  */
+               if (this_looping)
+                 has_cdtor = false;
+               else
+                 has_cdtor = w->call_for_symbol_and_aliases (cdtor_p,
+                                                             NULL, true);
+               if (w->set_const_flag (true, this_looping))
+                 {
+                   if (dump_file)
+                     fprintf (dump_file,
+                              "Declaration updated to be %sconst: %s\n",
+                              this_looping ? "looping " : "",
+                              w->name ());
+                   remove_p |= has_cdtor;
+                 }
                break;
 
              case IPA_PURE:
@@ -1520,9 +1512,20 @@ propagate_pure_const (void)
                               this_looping ? "looping " : "",
                               w->name ());
                  }
-               remove_p |= w->call_for_symbol_and_aliases (cdtor_p,
-                                                           NULL, true);
-               w->set_pure_flag (true, this_looping);
+               if (this_looping)
+                 has_cdtor = false;
+               else
+                 has_cdtor = w->call_for_symbol_and_aliases (cdtor_p,
+                                                             NULL, true);
+               if (w->set_pure_flag (true, this_looping))
+                 {
+                   if (dump_file)
+                     fprintf (dump_file,
+                              "Declaration updated to be %spure: %s\n",
+                              this_looping ? "looping " : "",
+                              w->name ());
+                   remove_p |= has_cdtor;
+                 }
                break;
 
              default:
@@ -1723,11 +1726,14 @@ skip_function_for_local_pure_const (struct cgraph_node *node)
         fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
       return true;
     }
-  if (node->get_availability () <= AVAIL_INTERPOSABLE)
+  /* Save some work and do not analyze functions which are interposable and
+     do not have any non-interposable aliases.  */
+  if (node->get_availability () <= AVAIL_INTERPOSABLE
+      && !node->has_aliases_p ())
     {
       if (dump_file)
         fprintf (dump_file,
-                "Function is not available or interposable; not analyzing.\n");
+                "Function is interposable; not analyzing.\n");
       return true;
     }
   return false;
@@ -1806,11 +1812,6 @@ pass_local_pure_const::execute (function *fun)
       if (!TREE_READONLY (current_function_decl))
        {
          warn_function_const (current_function_decl, !l->looping);
-         if (!skip)
-           {
-             node->set_const_flag (true, l->looping);
-             changed = true;
-           }
          if (dump_file)
            fprintf (dump_file, "Function found to be %sconst: %s\n",
                     l->looping ? "looping " : "",
@@ -1819,25 +1820,23 @@ pass_local_pure_const::execute (function *fun)
       else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
               && !l->looping)
        {
-         if (!skip)
-           {
-             node->set_const_flag (true, false);
-             changed = true;
-           }
          if (dump_file)
            fprintf (dump_file, "Function found to be non-looping: %s\n",
                     current_function_name ());
        }
+      if (!skip && node->set_const_flag (true, l->looping))
+       {
+         if (dump_file)
+           fprintf (dump_file, "Declaration updated to be %sconst: %s\n",
+                    l->looping ? "looping " : "",
+                    current_function_name ());
+         changed = true;
+       }
       break;
 
     case IPA_PURE:
       if (!DECL_PURE_P (current_function_decl))
        {
-         if (!skip)
-           {
-             node->set_pure_flag (true, l->looping);
-             changed = true;
-           }
          warn_function_pure (current_function_decl, !l->looping);
          if (dump_file)
            fprintf (dump_file, "Function found to be %spure: %s\n",
@@ -1847,15 +1846,18 @@ pass_local_pure_const::execute (function *fun)
       else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
               && !l->looping)
        {
-         if (!skip)
-           {
-             node->set_pure_flag (true, false);
-             changed = true;
-           }
          if (dump_file)
            fprintf (dump_file, "Function found to be non-looping: %s\n",
                     current_function_name ());
        }
+      if (!skip && node->set_pure_flag (true, l->looping))
+       {
+         if (dump_file)
+           fprintf (dump_file, "Declaration updated to be %spure: %s\n",
+                    l->looping ? "looping " : "",
+                    current_function_name ());
+         changed = true;
+       }
       break;
 
     default:
index fdf961d72ff23f753bf9b9c1a7f108cff4f885ca..5fe37cc248035f5e40ddc0957bfe1a4d74491621 100644 (file)
@@ -1,3 +1,7 @@
+2016-05-04  Jan Hubicka  <hubicka@ucw.cz>
+
+       * gcc.dg/ipa/pure-const-3.c: New testcase.
+
 2016-05-04  Marek Polacek  <polacek@redhat.com>
 
        * c-c++-common/Wdangling-else-1.c: New test.
diff --git a/gcc/testsuite/gcc.dg/ipa/pure-const-3.c b/gcc/testsuite/gcc.dg/ipa/pure-const-3.c
new file mode 100644 (file)
index 0000000..036b828
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-require-alias "" }  */
+/* { dg-options "-O2 -fdump-tree-local-pure-const1" } */
+
+__attribute__ ((weak))
+__attribute__ ((noinline))
+int a(int v)
+{
+  return v;
+}
+__attribute__ ((noinline))
+static int b(int v) __attribute__ ((alias("a")));
+int
+main()
+{
+  int c = a(1)==a(1);
+  int d = b(1)==b(1);
+  if (__builtin_constant_p (c))
+    __builtin_abort ();
+  if (!__builtin_constant_p (d))
+    __builtin_abort ();
+  return 0;
+}
+/* { dg-final { scan-ipa-dump "found to be const" "pure-const"} } */