cgraph.h (cgraph_node): Add predicate prevailing_p.
authorJan Hubicka <hubicka@ucw.cz>
Sat, 15 Dec 2018 21:24:52 +0000 (22:24 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 15 Dec 2018 21:24:52 +0000 (21:24 +0000)
* cgraph.h (cgraph_node): Add predicate prevailing_p.
(cgraph_edge): Add predicate possible_call_in_translation_unit_p.
* ipa-prop.c (ipa_write_jump_function): Optimize streaming of ADDR_EXPR.
(ipa_read_jump_function): Add prevails parameter; optimize streaming.
(ipa_read_edge_info): Break out from ...
(ipa_read_node_info): ... here; optimize streaming.
* cgraph.c (cgraph_edge::possibly_call_in_translation_unit_p): New
predicate.

From-SVN: r267175

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/ipa-prop.c

index fd92845039ef53f8244e0e0f60aa021c745fb121..f95477fae6346c552c206badf8d5e6751cb6e67d 100644 (file)
@@ -1,3 +1,14 @@
+2018-12-15  Jan Hubicka  <hubicka@ucw.cz>
+
+       * cgraph.h (cgraph_node): Add predicate prevailing_p.
+       (cgraph_edge): Add predicate possible_call_in_translation_unit_p.
+       * ipa-prop.c (ipa_write_jump_function): Optimize streaming of ADDR_EXPR.
+       (ipa_read_jump_function): Add prevails parameter; optimize streaming.
+       (ipa_read_edge_info): Break out from ...
+       (ipa_read_node_info): ... here; optimize streaming.
+       * cgraph.c (cgraph_edge::possibly_call_in_translation_unit_p): New
+       predicate.
+
 2018-12-15  Jan Hubicka  <hubicka@ucw.cz>
 
        * ipa-utils.c (ipa_merge_profiles): Do no merging when source function
index b3dd4296ea0b54c4836c13e634cda2eb8faa2e90..850a9b62469a15a89c4c02f37bd616e34f1674a7 100644 (file)
@@ -3766,6 +3766,41 @@ cgraph_edge::sreal_frequency ()
                               : caller->count);
 }
 
+
+/* During LTO stream in this can be used to check whether call can possibly
+   be internal to the current translation unit.  */
+
+bool
+cgraph_edge::possibly_call_in_translation_unit_p (void)
+{
+  gcc_checking_assert (in_lto_p && caller->prevailing_p ());
+
+  /* While incremental linking we may end up getting function body later.  */
+  if (flag_incremental_link == INCREMENTAL_LINK_LTO)
+    return true;
+
+  /* We may be smarter here and avoid stremaing in indirect calls we can't
+     track, but that would require arranging stremaing the indirect call
+     summary first.  */
+  if (!callee)
+    return true;
+
+  /* If calle is local to the original translation unit, it will be defined.  */
+  if (!TREE_PUBLIC (callee->decl) && !DECL_EXTERNAL (callee->decl))
+    return true;
+
+  /* Otherwise we need to lookup prevailing symbol (symbol table is not merged,
+     yet) and see if it is a definition.  In fact we may also resolve aliases,
+     but that is probably not too important.  */
+  symtab_node *node = callee;
+  for (int n = 10; node->previous_sharing_asm_name && n ; n--)
+    node = node->previous_sharing_asm_name;
+  if (node->previous_sharing_asm_name)
+    node = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (callee->decl));
+  gcc_assert (TREE_PUBLIC (node->decl));
+  return node->get_availability () >= AVAIL_AVAILABLE;
+}
+
 /* A stashed copy of "symtab" for use by selftest::symbol_table_test.
    This needs to be a global so that it can be a GC root, and thus
    prevent the stashed copy from being garbage-collected if the GC runs
index b8e23cc338aec7ead0c68240a04906ba5b1ecd61..51cea066ad35bb3eda571184879cb3ff27b040e9 100644 (file)
@@ -308,6 +308,10 @@ public:
   /* Return availability of NODE when referenced from REF.  */
   enum availability get_availability (symtab_node *ref = NULL);
 
+  /* During LTO stream-in this predicate can be used to check whether node
+     in question prevails in the linking to save some memory usage.  */
+  bool prevailing_p (void);
+
   /* Return true if NODE binds to current definition in final executable
      when referenced from REF.  If REF is NULL return conservative value
      for any reference.  */
@@ -1730,6 +1734,10 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
      after passes that don't update the cgraph.  */
   static void rebuild_references (void);
 
+  /* During LTO stream in this can be used to check whether call can possibly
+     be internal to the current translation unit.  */
+  bool possibly_call_in_translation_unit_p (void);
+
   /* Expected number of executions: calculated in profile.c.  */
   profile_count count;
   cgraph_node *caller;
@@ -3357,6 +3365,15 @@ xstrdup_for_dump (const char *transient_str)
   return ggc_strdup (transient_str);
 }
 
+/* During LTO stream-in this predicate can be used to check whether node
+   in question prevails in the linking to save some memory usage.  */
+inline bool
+symtab_node::prevailing_p (void)
+{
+  return definition && ((!TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
+                        || previous_sharing_asm_name == NULL);
+}
+
 extern GTY(()) symbol_table *saved_symtab;
 
 #if CHECKING_P
index 4a2a6fa14cc6c42755e22dab0d1f3104e6a5147d..05e666e05882e9b590a419da3c39abbaf327129d 100644 (file)
@@ -4053,8 +4053,15 @@ ipa_write_jump_function (struct output_block *ob,
   struct ipa_agg_jf_item *item;
   struct bitpack_d bp;
   int i, count;
+  int flag = 0;
 
-  streamer_write_uhwi (ob, jump_func->type);
+  /* ADDR_EXPRs are very comon IP invariants; save some streamer data
+     as well as WPA memory by handling them specially.  */
+  if (jump_func->type == IPA_JF_CONST
+      && TREE_CODE (jump_func->value.constant.value) == ADDR_EXPR)
+    flag = 1;
+
+  streamer_write_uhwi (ob, jump_func->type * 2 + flag);
   switch (jump_func->type)
     {
     case IPA_JF_UNKNOWN:
@@ -4062,7 +4069,10 @@ ipa_write_jump_function (struct output_block *ob,
     case IPA_JF_CONST:
       gcc_assert (
          EXPR_LOCATION (jump_func->value.constant.value) == UNKNOWN_LOCATION);
-      stream_write_tree (ob, jump_func->value.constant.value, true);
+      stream_write_tree (ob,
+                        flag
+                        ? TREE_OPERAND (jump_func->value.constant.value, 0)
+                        : jump_func->value.constant.value, true);
       break;
     case IPA_JF_PASS_THROUGH:
       streamer_write_uhwi (ob, jump_func->value.pass_through.operation);
@@ -4131,20 +4141,28 @@ static void
 ipa_read_jump_function (struct lto_input_block *ib,
                        struct ipa_jump_func *jump_func,
                        struct cgraph_edge *cs,
-                       struct data_in *data_in)
+                       struct data_in *data_in,
+                       bool prevails)
 {
   enum jump_func_type jftype;
   enum tree_code operation;
   int i, count;
+  int val = streamer_read_uhwi (ib);
+  bool flag = val & 1;
 
-  jftype = (enum jump_func_type) streamer_read_uhwi (ib);
+  jftype = (enum jump_func_type) (val / 2);
   switch (jftype)
     {
     case IPA_JF_UNKNOWN:
       ipa_set_jf_unknown (jump_func);
       break;
     case IPA_JF_CONST:
-      ipa_set_jf_constant (jump_func, stream_read_tree (ib, data_in), cs);
+      {
+       tree t = stream_read_tree (ib, data_in);
+       if (flag && prevails)
+         t = build_fold_addr_expr (t);
+       ipa_set_jf_constant (jump_func, t, cs);
+      }
       break;
     case IPA_JF_PASS_THROUGH:
       operation = (enum tree_code) streamer_read_uhwi (ib);
@@ -4177,10 +4195,13 @@ ipa_read_jump_function (struct lto_input_block *ib,
        ipa_set_ancestor_jf (jump_func, offset, formal_id, agg_preserved);
        break;
       }
+    default:
+      fatal_error (UNKNOWN_LOCATION, "invalid jump function in LTO stream");
     }
 
   count = streamer_read_uhwi (ib);
-  vec_alloc (jump_func->agg.items, count);
+  if (prevails)
+    vec_alloc (jump_func->agg.items, count);
   if (count)
     {
       struct bitpack_d bp = streamer_read_bitpack (ib);
@@ -4191,7 +4212,8 @@ ipa_read_jump_function (struct lto_input_block *ib,
       struct ipa_agg_jf_item item;
       item.offset = streamer_read_uhwi (ib);
       item.value = stream_read_tree (ib, data_in);
-      jump_func->agg.items->quick_push (item);
+      if (prevails)
+        jump_func->agg.items->quick_push (item);
     }
 
   struct bitpack_d bp = streamer_read_bitpack (ib);
@@ -4200,7 +4222,8 @@ ipa_read_jump_function (struct lto_input_block *ib,
     {
       widest_int value = streamer_read_widest_int (ib);
       widest_int mask = streamer_read_widest_int (ib);
-      ipa_set_jfunc_bits (jump_func, value, mask);
+      if (prevails)
+        ipa_set_jfunc_bits (jump_func, value, mask);
     }
   else
     jump_func->bits = NULL;
@@ -4213,7 +4236,8 @@ ipa_read_jump_function (struct lto_input_block *ib,
                                                       VR_LAST);
       tree min = stream_read_tree (ib, data_in);
       tree max = stream_read_tree (ib, data_in);
-      ipa_set_jfunc_vr (jump_func, type, min, max);
+      if (prevails)
+        ipa_set_jfunc_vr (jump_func, type, min, max);
     }
   else
     jump_func->m_vr = NULL;
@@ -4345,24 +4369,48 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
     }
 }
 
-/* If jump functions points to node we possibly can propagate into.
-   At this moment symbol table is still not merged, but the prevailing
-   symbol is always first in the list.  */
+/* Stream in edge E from IB.  */
 
-static bool
-jump_function_useful_p (symtab_node *node)
+static void
+ipa_read_edge_info (struct lto_input_block *ib,
+                   struct data_in *data_in,
+                   struct cgraph_edge *e, bool prevails)
 {
-  /* While incremental linking we may end up getting function body later.  */
-  if (flag_incremental_link == INCREMENTAL_LINK_LTO)
-    return true;
-  if (!TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))
-    return true;
-  for (int n = 10; node->previous_sharing_asm_name && n ; n--)
-    node = node->previous_sharing_asm_name;
-  if (node->previous_sharing_asm_name)
-    node = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (node->decl));
-  gcc_assert (TREE_PUBLIC (node->decl));
-  return node->definition;
+  int count = streamer_read_uhwi (ib);
+  bool contexts_computed = count & 1;
+
+  count /= 2;
+  if (!count)
+    return;
+  if (prevails && e->possibly_call_in_translation_unit_p ())
+    {
+      struct ipa_edge_args *args = IPA_EDGE_REF (e);
+      vec_safe_grow_cleared (args->jump_functions, count);
+      if (contexts_computed)
+       vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
+      for (int k = 0; k < count; k++)
+       {
+         ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
+                                 data_in, prevails);
+         if (contexts_computed)
+           ipa_get_ith_polymorhic_call_context (args, k)->stream_in
+                                                            (ib, data_in);
+       }
+    }
+  else
+    {
+      for (int k = 0; k < count; k++)
+       {
+         struct ipa_jump_func dummy;
+         ipa_read_jump_function (ib, &dummy, e,
+                                 data_in, prevails);
+         if (contexts_computed)
+           {
+             struct ipa_polymorphic_call_context ctx;
+             ctx.stream_in (ib, data_in);
+           }
+       }
+    }
 }
 
 /* Stream in NODE info from IB.  */
@@ -4371,82 +4419,50 @@ static void
 ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
                    struct data_in *data_in)
 {
-  struct ipa_node_params *info = IPA_NODE_REF (node);
   int k;
   struct cgraph_edge *e;
   struct bitpack_d bp;
-
-  ipa_alloc_node_params (node, streamer_read_uhwi (ib));
-
-  for (k = 0; k < ipa_get_param_count (info); k++)
-    (*info->descriptors)[k].move_cost = streamer_read_uhwi (ib);
+  bool prevails = node->prevailing_p ();
+  struct ipa_node_params *info = prevails ? IPA_NODE_REF (node) : NULL;
+
+  int param_count = streamer_read_uhwi (ib);
+  if (prevails)
+    {
+      ipa_alloc_node_params (node, param_count);
+      for (k = 0; k < param_count; k++)
+        (*info->descriptors)[k].move_cost = streamer_read_uhwi (ib);
+      if (ipa_get_param_count (info) != 0)
+       info->analysis_done = true;
+      info->node_enqueued = false;
+    }
+  else
+    for (k = 0; k < param_count; k++)
+      streamer_read_uhwi (ib);
 
   bp = streamer_read_bitpack (ib);
-  if (ipa_get_param_count (info) != 0)
-    info->analysis_done = true;
-  info->node_enqueued = false;
-  for (k = 0; k < ipa_get_param_count (info); k++)
-    ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
-  for (k = 0; k < ipa_get_param_count (info); k++)
+  for (k = 0; k < param_count; k++)
     {
-      ipa_set_controlled_uses (info, k, streamer_read_hwi (ib));
-      (*info->descriptors)[k].decl_or_type = stream_read_tree (ib, data_in);
+      bool used = bp_unpack_value (&bp, 1);
+
+      if (prevails)
+        ipa_set_param_used (info, k, used);
     }
-  for (e = node->callees; e; e = e->next_callee)
+  for (k = 0; k < param_count; k++)
     {
-      struct ipa_edge_args *args = IPA_EDGE_REF (e);
-      int count = streamer_read_uhwi (ib);
-      bool contexts_computed = count & 1;
-      count /= 2;
-
-      if (!count)
-       continue;
-      if (!jump_function_useful_p (e->callee))
-       {
-          for (k = 0; k < count; k++)
-           {
-             struct ipa_jump_func dummy;
-             ipa_read_jump_function (ib, &dummy, e, data_in);
-             if (contexts_computed)
-               {
-                 struct ipa_polymorphic_call_context ctx;
-                 ctx.stream_in (ib, data_in);
-               }
-           }
-         continue;
-       }
-      vec_safe_grow_cleared (args->jump_functions, count);
-      if (contexts_computed)
-       vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
+      int nuses = streamer_read_hwi (ib);
+      tree type = stream_read_tree (ib, data_in);
 
-      for (k = 0; k < ipa_get_cs_argument_count (args); k++)
+      if (prevails)
        {
-         ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
-                                 data_in);
-         if (contexts_computed)
-           ipa_get_ith_polymorhic_call_context (args, k)->stream_in (ib, data_in);
+         ipa_set_controlled_uses (info, k, nuses);
+         (*info->descriptors)[k].decl_or_type = type;
        }
     }
+  for (e = node->callees; e; e = e->next_callee)
+    ipa_read_edge_info (ib, data_in, e, prevails);
   for (e = node->indirect_calls; e; e = e->next_callee)
     {
-      struct ipa_edge_args *args = IPA_EDGE_REF (e);
-      int count = streamer_read_uhwi (ib);
-      bool contexts_computed = count & 1;
-      count /= 2;
-
-      if (count)
-       {
-         vec_safe_grow_cleared (args->jump_functions, count);
-         if (contexts_computed)
-           vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
-          for (k = 0; k < ipa_get_cs_argument_count (args); k++)
-           {
-             ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
-                                     data_in);
-             if (contexts_computed)
-               ipa_get_ith_polymorhic_call_context (args, k)->stream_in (ib, data_in);
-           }
-       }
+      ipa_read_edge_info (ib, data_in, e, prevails);
       ipa_read_indirect_edge_info (ib, data_in, e);
     }
 }