re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / cgraphunit.c
index f2c40d43d71fd4c3fd8d8338cfa937aa3c251e2e..7e78bf789155c779f9620a4a5185e7f8465b85a7 100644 (file)
@@ -161,15 +161,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "double-int.h"
-#include "input.h"
 #include "alias.h"
 #include "symtab.h"
-#include "wide-int.h"
-#include "inchash.h"
 #include "tree.h"
 #include "fold-const.h"
 #include "varasm.h"
@@ -179,14 +172,15 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl.h"
 #include "predict.h"
 #include "hard-reg-set.h"
-#include "input.h"
 #include "function.h"
 #include "basic-block.h"
+#include "dominance.h"
+#include "cfgcleanup.h"
+#include "cfg.h"
 #include "tree-ssa-alias.h"
 #include "internal-fn.h"
 #include "gimple-fold.h"
 #include "gimple-expr.h"
-#include "is-a.h"
 #include "gimple.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
@@ -204,9 +198,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "params.h"
 #include "intl.h"
-#include "hash-map.h"
-#include "plugin-api.h"
-#include "ipa-ref.h"
 #include "cgraph.h"
 #include "alloc-pool.h"
 #include "symbol-summary.h"
@@ -406,10 +397,11 @@ cgraph_node::reset (void)
   remove_all_references ();
 }
 
-/* Return true when there are references to the node.  */
+/* Return true when there are references to the node.  INCLUDE_SELF is
+   true if a self reference counts as a reference.  */
 
 bool
-symtab_node::referred_to_p (void)
+symtab_node::referred_to_p (bool include_self)
 {
   ipa_ref *ref = NULL;
 
@@ -419,7 +411,13 @@ symtab_node::referred_to_p (void)
   /* For functions check also calls.  */
   cgraph_node *cn = dyn_cast <cgraph_node *> (this);
   if (cn && cn->callers)
-    return true;
+    {
+      if (include_self)
+       return true;
+      for (cgraph_edge *e = cn->callers; e; e = e->next_caller)
+       if (e->caller != this)
+         return true;
+    }
   return false;
 }
 
@@ -442,8 +440,10 @@ cgraph_node::finalize_function (tree decl, bool no_collect)
       node->local.redefined_extern_inline = true;
     }
 
-  notice_global_symbol (decl);
+  /* Set definition first before calling notice_global_symbol so that
+     it is available to notice_global_symbol.  */
   node->definition = true;
+  notice_global_symbol (decl);
   node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
 
   /* With -fkeep-inline-functions we are keeping all inline functions except
@@ -472,10 +472,6 @@ cgraph_node::finalize_function (tree decl, bool no_collect)
   if (!TREE_ASM_WRITTEN (decl))
     (*debug_hooks->deferred_inline_function) (decl);
 
-  /* Possibly warn about unused parameters.  */
-  if (warn_unused_parameter)
-    do_warn_unused_parameter (decl);
-
   if (!no_collect)
     ggc_collect ();
 
@@ -501,6 +497,23 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
 {
   gcc::pass_manager *passes = g->get_passes ();
   cgraph_node *node;
+
+  if (dump_file)
+    {
+      struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+      const char *function_type = ((gimple_has_body_p (fndecl))
+                                  ? (lowered
+                                     ? (gimple_in_ssa_p (fn)
+                                        ? "ssa gimple"
+                                        : "low gimple")
+                                     : "high gimple")
+                                  : "to-be-gimplified");
+      fprintf (dump_file,
+              "Added new %s function %s to callgraph\n",
+              function_type,
+              fndecl_name (fndecl));
+    }
+
   switch (symtab->state)
     {
       case PARSING:
@@ -629,7 +642,6 @@ cgraph_node::analyze (void)
         body.  */
       if (!gimple_has_body_p (decl))
        gimplify_function_tree (decl);
-      dump_function (TDI_generic, decl);
 
       /* Lower the function.  */
       if (!lowered)
@@ -803,8 +815,10 @@ varpool_node::finalize_decl (tree decl)
 
   if (node->definition)
     return;
-  notice_global_symbol (decl);
+  /* Set definition first before calling notice_global_symbol so that
+     it is available to notice_global_symbol.  */
   node->definition = true;
+  notice_global_symbol (decl);
   if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
       /* Traditionally we do not eliminate static variables when not
         optimizing and when not doing toplevel reoder.  */
@@ -862,9 +876,8 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
                  (TREE_TYPE (targets[i]->decl))
                   == METHOD_TYPE
              && !type_in_anonymous_namespace_p
-                  (method_class_type
-                    (TREE_TYPE (targets[i]->decl))))
-         enqueue_node (targets[i]);
+                  (TYPE_METHOD_BASETYPE (TREE_TYPE (targets[i]->decl))))
+           enqueue_node (targets[i]);
        }
     }
 
@@ -924,8 +937,12 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
 static cgraph_node *first_analyzed;
 static varpool_node *first_analyzed_var;
 
+/* FIRST_TIME is set to TRUE for the first time we are called for a
+   translation unit from finalize_compilation_unit() or false
+   otherwise.  */
+
 static void
-analyze_functions (void)
+analyze_functions (bool first_time)
 {
   /* Keep track of already processed nodes when called multiple times for
      intermodule optimization.  */
@@ -1097,6 +1114,13 @@ analyze_functions (void)
       symtab_node::dump_table (symtab->dump_file);
     }
 
+  if (first_time)
+    {
+      symtab_node *snode;
+      FOR_EACH_SYMBOL (snode)
+       check_global_declaration (snode->decl);
+    }
+
   if (symtab->dump_file)
     fprintf (symtab->dump_file, "\nRemoving unused symbols:");
 
@@ -1109,6 +1133,19 @@ analyze_functions (void)
        {
          if (symtab->dump_file)
            fprintf (symtab->dump_file, " %s", node->name ());
+
+         /* See if the debugger can use anything before the DECL
+            passes away.  Perhaps it can notice a DECL that is now a
+            constant and can tag the early DIE with an appropriate
+            attribute.
+
+            Otherwise, this is the last chance the debug_hooks have
+            at looking at optimized away DECLs, since
+            late_global_decl will subsequently be called from the
+            contents of the now pruned symbol table.  */
+         if (!decl_function_context (node->decl))
+           (*debug_hooks->late_global_decl) (node->decl);
+
          node->remove ();
          continue;
        }
@@ -1369,7 +1406,7 @@ init_lowered_empty_function (tree decl, bool in_ssa, gcov_type count)
   ENTRY_BLOCK_PTR_FOR_FN (cfun)->frequency = REG_BR_PROB_BASE;
   EXIT_BLOCK_PTR_FOR_FN (cfun)->count = count;
   EXIT_BLOCK_PTR_FOR_FN (cfun)->frequency = REG_BR_PROB_BASE;
-  bb = create_basic_block (NULL, (void *) 0, ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  bb = create_basic_block (NULL, ENTRY_BLOCK_PTR_FOR_FN (cfun));
   bb->count = count;
   bb->frequency = BB_FREQ_MAX;
   e = make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
@@ -1504,6 +1541,10 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
   tree thunk_fndecl = decl;
   tree a;
 
+  /* Instrumentation thunk is the same function with
+     a different signature.  Never need to expand it.  */
+  if (thunk.add_pointer_bounds_args)
+    return false;
 
   if (!force_gimple_thunk && this_adjusting
       && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
@@ -1577,6 +1618,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
       int i;
       tree resdecl;
       tree restmp = NULL;
+      tree resbnd = NULL;
 
       gcall *call;
       greturn *ret;
@@ -1676,6 +1718,14 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
       callees->call_stmt = call;
       gimple_call_set_from_thunk (call, true);
       gimple_call_set_with_bounds (call, instrumentation_clone);
+
+      /* Return slot optimization is always possible and in fact requred to
+         return values with DECL_BY_REFERENCE.  */
+      if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
+         && (!is_gimple_reg_type (TREE_TYPE (resdecl))
+             || DECL_BY_REFERENCE (resdecl)))
+        gimple_call_set_return_slot_opt (call, true);
+
       if (restmp && !alias_is_noreturn)
        {
           gimple_call_set_lhs (call, restmp);
@@ -1685,6 +1735,17 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
       gsi_insert_after (&bsi, call, GSI_NEW_STMT);
       if (!alias_is_noreturn)
        {
+         if (instrumentation_clone
+             && !DECL_BY_REFERENCE (resdecl)
+             && restmp
+             && BOUNDED_P (restmp))
+           {
+             resbnd = chkp_insert_retbnd_call (NULL, restmp, &bsi);
+             create_edge (get_create (gimple_call_fndecl (gsi_stmt (bsi))),
+                          as_a <gcall *> (gsi_stmt (bsi)),
+                          callees->count, callees->frequency);
+           }
+
          if (restmp && !this_adjusting
              && (fixed_offset || virtual_offset))
            {
@@ -1698,13 +1759,13 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
                     protect against NULL.  We know there will be an
                     adjustment, because that's why we're emitting a
                     thunk.  */
-                 then_bb = create_basic_block (NULL, (void *) 0, bb);
+                 then_bb = create_basic_block (NULL, bb);
                  then_bb->count = count - count / 16;
                  then_bb->frequency = BB_FREQ_MAX - BB_FREQ_MAX / 16;
-                 return_bb = create_basic_block (NULL, (void *) 0, then_bb);
+                 return_bb = create_basic_block (NULL, then_bb);
                  return_bb->count = count;
                  return_bb->frequency = BB_FREQ_MAX;
-                 else_bb = create_basic_block (NULL, (void *) 0, else_bb);
+                 else_bb = create_basic_block (NULL, else_bb);
                  then_bb->count = count / 16;
                  then_bb->frequency = BB_FREQ_MAX / 16;
                  add_bb_to_loop (then_bb, bb->loop_father);
@@ -1754,6 +1815,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
            ret = gimple_build_return (restmp);
          else
            ret = gimple_build_return (resdecl);
+         gimple_return_set_retbnd (ret, resbnd);
 
          gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
        }
@@ -1990,14 +2052,14 @@ expand_all_functions (void)
 
       if (node->process)
        {
-     expanded_func_count++;
-     if(node->tp_first_run)
-       profiled_func_count++;
-
-    if (symtab->dump_file)
-         fprintf (symtab->dump_file,
-                  "Time profile order in expand_all_functions:%s:%d\n",
-                  node->asm_name (), node->tp_first_run);
+         expanded_func_count++;
+         if(node->tp_first_run)
+           profiled_func_count++;
+
+         if (symtab->dump_file)
+           fprintf (symtab->dump_file,
+                    "Time profile order in expand_all_functions:%s:%d\n",
+                    node->asm_name (), node->tp_first_run);
          node->process = 0;
          node->expand ();
        }
@@ -2420,13 +2482,23 @@ symbol_table::finalize_compilation_unit (void)
 
   /* Gimplify and lower all functions, compute reachability and
      remove unreachable nodes.  */
-  analyze_functions ();
+  analyze_functions (/*first_time=*/true);
 
   /* Mark alias targets necessary and emit diagnostics.  */
   handle_alias_pairs ();
 
   /* Gimplify and lower thunks.  */
-  analyze_functions ();
+  analyze_functions (/*first_time=*/false);
+
+  /* Emit early debug for reachable functions, and by consequence,
+     locally scoped symbols.  */
+  struct cgraph_node *cnode;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
+    (*debug_hooks->early_global_decl) (cnode->decl);
+
+  /* Clean up anything that needs cleaning up after initial debug
+     generation.  */
+  (*debug_hooks->early_finish) ();
 
   /* Finally drive the pass manager.  */
   compile ();
@@ -2464,6 +2536,7 @@ cgraph_node::create_wrapper (cgraph_node *target)
   release_body (true);
   reset ();
 
+  DECL_UNINLINABLE (decl) = false;
   DECL_RESULT (decl) = decl_result;
   DECL_INITIAL (decl) = NULL;
   allocate_struct_function (decl, false);
@@ -2471,8 +2544,9 @@ cgraph_node::create_wrapper (cgraph_node *target)
 
   /* Turn alias into thunk and expand it into GIMPLE representation.  */
   definition = true;
+
+  memset (&thunk, 0, sizeof (cgraph_thunk_info));
   thunk.thunk_p = true;
-  thunk.this_adjusting = false;
   create_edge (target, NULL, count, CGRAPH_FREQ_BASE);
 
   tree arguments = DECL_ARGUMENTS (decl);