re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / cgraphunit.c
index 3e76bf0a68d02e72ce3df86d993dccaedc35132e..7e78bf789155c779f9620a4a5185e7f8465b85a7 100644 (file)
@@ -1,5 +1,5 @@
 /* Driver of optimization process
-   Copyright (C) 2003-2014 Free Software Foundation, Inc.
+   Copyright (C) 2003-2015 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -161,26 +161,26 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "varasm.h"
 #include "stor-layout.h"
 #include "stringpool.h"
 #include "output.h"
 #include "rtl.h"
 #include "predict.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.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"
@@ -197,8 +197,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "diagnostic.h"
 #include "params.h"
-#include "fibheap.h"
 #include "intl.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
 #include "ipa-prop.h"
 #include "tree-iterator.h"
 #include "tree-pass.h"
@@ -218,6 +220,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-nested.h"
 #include "gimplify.h"
 #include "dbgcnt.h"
+#include "tree-chkp.h"
+#include "lto-section-names.h"
+#include "omp-low.h"
+#include "print-tree.h"
 
 /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
    secondary queue used during optimization to accommodate passes that
@@ -256,7 +262,7 @@ symtab_node::needed_p (void)
   if (forced_by_abi && TREE_PUBLIC (decl))
     return true;
 
- /* Keep constructors, destructors and virtual functions.  */
 /* Keep constructors, destructors and virtual functions.  */
    if (TREE_CODE (decl) == FUNCTION_DECL
        && (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl)))
     return true;
@@ -320,6 +326,7 @@ symbol_table::process_new_functions (void)
 
        case IPA:
        case IPA_SSA:
+       case IPA_SSA_AFTER_INLINING:
          /* When IPA optimization already started, do all essential
             transformations that has been already performed on the whole
             cgraph but not on this function.  */
@@ -328,10 +335,10 @@ symbol_table::process_new_functions (void)
          if (!node->analyzed)
            node->analyze ();
          push_cfun (DECL_STRUCT_FUNCTION (fndecl));
-         if (state == IPA_SSA
+         if ((state == IPA_SSA || state == IPA_SSA_AFTER_INLINING)
              && !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
            g->get_passes ()->execute_early_local_passes ();
-         else if (inline_summary_vec != NULL)
+         else if (inline_summaries != NULL)
            compute_inline_parameters (node, true);
          free_dominance_info (CDI_POST_DOMINATORS);
          free_dominance_info (CDI_DOMINATORS);
@@ -390,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;
 
@@ -403,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;
 }
 
@@ -426,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
@@ -443,7 +459,7 @@ cgraph_node::finalize_function (tree decl, bool no_collect)
      declared inline and nested functions.  These were optimized out
      in the original implementation and it is unclear whether we want
      to change the behavior here.  */
-  if ((!optimize
+  if ((!opt_for_fn (decl, optimize)
        && !node->cpp_implicit_alias
        && !DECL_DISREGARD_INLINE_LIMITS (decl)
        && !DECL_DECLARED_INLINE_P (decl)
@@ -456,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 ();
 
@@ -485,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:
@@ -500,6 +529,7 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
 
       case IPA:
       case IPA_SSA:
+      case IPA_SSA_AFTER_INLINING:
       case EXPANSION:
        /* Bring the function into finalized state and enqueue for later
           analyzing and compilation.  */
@@ -563,8 +593,19 @@ cgraph_node::analyze (void)
 
   if (thunk.thunk_p)
     {
-      create_edge (cgraph_node::get (thunk.alias),
-                  NULL, 0, CGRAPH_FREQ_BASE);
+      cgraph_node *t = cgraph_node::get (thunk.alias);
+
+      create_edge (t, NULL, 0, CGRAPH_FREQ_BASE);
+      /* Target code in expand_thunk may need the thunk's target
+        to be analyzed, so recurse here.  */
+      if (!t->analyzed)
+       t->analyze ();
+      if (t->alias)
+       {
+         t = t->get_alias_target ();
+         if (!t->analyzed)
+           t->analyze ();
+       }
       if (!expand_thunk (false, false))
        {
          thunk.alias = NULL;
@@ -601,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)
@@ -775,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.  */
@@ -797,6 +839,9 @@ varpool_node::finalize_decl (tree decl)
       || (!flag_toplevel_reorder
        && symtab->state == EXPANSION))
     node->assemble_decl ();
+
+  if (DECL_INITIAL (decl))
+    chkp_register_var_initializer (decl);
 }
 
 /* EDGE is an polymorphic call.  Mark all possible targets as reachable
@@ -831,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]);
        }
     }
 
@@ -870,6 +914,11 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
 
          edge->make_direct (target);
          edge->redirect_call_stmt_to_callee ();
+
+         /* Call to __builtin_unreachable shouldn't be instrumented.  */
+         if (!targets.length ())
+           gimple_call_set_with_bounds (edge->call_stmt, false);
+
          if (symtab->dump_file)
            {
              fprintf (symtab->dump_file,
@@ -888,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.  */
@@ -914,8 +967,7 @@ analyze_functions (void)
     FOR_EACH_SYMBOL (node)
       if (node->cpp_implicit_alias)
          node->fixup_same_cpp_alias_visibility (node->get_alias_target ());
-  if (optimize && flag_devirtualize)
-    build_type_inheritance_graph ();
+  build_type_inheritance_graph ();
 
   /* Analysis adds static variables that in turn adds references to new functions.
      So we need to iterate the process until it stabilize.  */
@@ -984,9 +1036,23 @@ analyze_functions (void)
                cnode->analyze ();
 
              for (edge = cnode->callees; edge; edge = edge->next_callee)
-               if (edge->callee->definition)
+               if (edge->callee->definition
+                   && (!DECL_EXTERNAL (edge->callee->decl)
+                       /* When not optimizing, do not try to analyze extern
+                          inline functions.  Doing so is pointless.  */
+                       || opt_for_fn (edge->callee->decl, optimize)
+                       /* Weakrefs needs to be preserved.  */
+                       || edge->callee->alias
+                       /* always_inline functions are inlined aven at -O0.  */
+                       || lookup_attribute
+                                ("always_inline",
+                                 DECL_ATTRIBUTES (edge->callee->decl))
+                       /* Multiversioned functions needs the dispatcher to
+                          be produced locally even for extern functions.  */
+                       || edge->callee->function_version ()))
                   enqueue_node (edge->callee);
-             if (optimize && flag_devirtualize)
+             if (opt_for_fn (cnode->decl, optimize)
+                 && opt_for_fn (cnode->decl, flag_devirtualize))
                {
                  cgraph_edge *next;
 
@@ -1023,16 +1089,23 @@ analyze_functions (void)
              for (next = node->same_comdat_group;
                   next != node;
                   next = next->same_comdat_group)
-               enqueue_node (next);
+               if (!next->comdat_local_p ())
+                 enqueue_node (next);
            }
          for (i = 0; node->iterate_reference (i, ref); i++)
-           if (ref->referred->definition)
+           if (ref->referred->definition
+               && (!DECL_EXTERNAL (ref->referred->decl)
+                   || ((TREE_CODE (ref->referred->decl) != FUNCTION_DECL
+                        && optimize)
+                       || (TREE_CODE (ref->referred->decl) == FUNCTION_DECL
+                           && opt_for_fn (ref->referred->decl, optimize))
+                   || node->alias
+                   || ref->referred->alias)))
              enqueue_node (ref->referred);
          symtab->process_new_functions ();
        }
     }
-  if (optimize && flag_devirtualize)
-    update_type_inheritance_graph ();
+  update_type_inheritance_graph ();
 
   /* Collect entry points to the unit.  */
   if (symtab->dump_file)
@@ -1041,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:");
 
@@ -1053,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;
        }
@@ -1280,9 +1373,10 @@ mark_functions_to_output (void)
    return basic block in the function body.  */
 
 basic_block
-init_lowered_empty_function (tree decl, bool in_ssa)
+init_lowered_empty_function (tree decl, bool in_ssa, gcov_type count)
 {
   basic_block bb;
+  edge e;
 
   current_function_decl = decl;
   allocate_struct_function (decl, false);
@@ -1308,9 +1402,19 @@ init_lowered_empty_function (tree decl, bool in_ssa)
   loops_for_fn (cfun)->state |= LOOPS_MAY_HAVE_MULTIPLE_LATCHES;
 
   /* Create BB for body of the function and connect it properly.  */
-  bb = create_basic_block (NULL, (void *) 0, ENTRY_BLOCK_PTR_FOR_FN (cfun));
-  make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
-  make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+  ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = 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, 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);
+  e->count = count;
+  e->probability = REG_BR_PROB_BASE;
+  e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+  e->count = count;
+  e->probability = REG_BR_PROB_BASE;
   add_bb_to_loop (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun)->loop_father);
 
   return bb;
@@ -1326,7 +1430,7 @@ thunk_adjust (gimple_stmt_iterator * bsi,
              tree ptr, bool this_adjusting,
              HOST_WIDE_INT fixed_offset, tree virtual_offset)
 {
-  gimple stmt;
+  gassign *stmt;
   tree ret;
 
   if (this_adjusting
@@ -1437,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,
@@ -1453,13 +1561,14 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
        }
 
       if (in_lto_p)
-       get_body ();
+       get_untransformed_body ();
       a = DECL_ARGUMENTS (thunk_fndecl);
       
       current_function_decl = thunk_fndecl;
 
       /* Ensure thunks are emitted in their correct sections.  */
-      resolve_unique_section (thunk_fndecl, 0, flag_function_sections);
+      resolve_unique_section (thunk_fndecl, 0,
+                             flag_function_sections);
 
       DECL_RESULT (thunk_fndecl)
        = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
@@ -1491,6 +1600,14 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
       thunk.thunk_p = false;
       analyzed = false;
     }
+  else if (stdarg_p (TREE_TYPE (thunk_fndecl)))
+    {
+      error ("generic thunk code fails for method %qD which uses %<...%>",
+            thunk_fndecl);
+      TREE_ASM_WRITTEN (thunk_fndecl) = 1;
+      analyzed = true;
+      return false;
+    }
   else
     {
       tree restype;
@@ -1501,18 +1618,21 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
       int i;
       tree resdecl;
       tree restmp = NULL;
+      tree resbnd = NULL;
 
-      gimple call;
-      gimple ret;
+      gcall *call;
+      greturn *ret;
+      bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
 
       if (in_lto_p)
-       get_body ();
+       get_untransformed_body ();
       a = DECL_ARGUMENTS (thunk_fndecl);
 
       current_function_decl = thunk_fndecl;
 
       /* Ensure thunks are emitted in their correct sections.  */
-      resolve_unique_section (thunk_fndecl, 0, flag_function_sections);
+      resolve_unique_section (thunk_fndecl, 0,
+                             flag_function_sections);
 
       DECL_IGNORED_P (thunk_fndecl) = 1;
       bitmap_obstack_initialize (NULL);
@@ -1533,20 +1653,36 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
       else
        resdecl = DECL_RESULT (thunk_fndecl);
 
-      bb = then_bb = else_bb = return_bb = init_lowered_empty_function (thunk_fndecl, true);
+      bb = then_bb = else_bb = return_bb
+       = init_lowered_empty_function (thunk_fndecl, true, count);
 
       bsi = gsi_start_bb (bb);
 
       /* Build call to the function being thunked.  */
-      if (!VOID_TYPE_P (restype))
+      if (!VOID_TYPE_P (restype) && !alias_is_noreturn)
        {
          if (DECL_BY_REFERENCE (resdecl))
-           restmp = gimple_fold_indirect_ref (resdecl);
+           {
+             restmp = gimple_fold_indirect_ref (resdecl);
+             if (!restmp)
+               restmp = build2 (MEM_REF,
+                                TREE_TYPE (TREE_TYPE (DECL_RESULT (alias))),
+                                resdecl,
+                                build_int_cst (TREE_TYPE
+                                  (DECL_RESULT (alias)), 0));
+           }
          else if (!is_gimple_reg_type (restype))
            {
-             restmp = resdecl;
-             add_local_decl (cfun, restmp);
-             BLOCK_VARS (DECL_INITIAL (current_function_decl)) = restmp;
+             if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
+               {
+                 restmp = resdecl;
+
+                 if (TREE_CODE (restmp) == VAR_DECL)
+                   add_local_decl (cfun, restmp);
+                 BLOCK_VARS (DECL_INITIAL (current_function_decl)) = restmp;
+               }
+             else
+               restmp = create_tmp_var (restype, "retval");
            }
          else
            restmp = create_tmp_reg (restype, "retval");
@@ -1555,14 +1691,18 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
       for (arg = a; arg; arg = DECL_CHAIN (arg))
         nargs++;
       auto_vec<tree> vargs (nargs);
+      i = 0;
+      arg = a;
       if (this_adjusting)
-        vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
-                                       virtual_offset));
-      else if (nargs)
-        vargs.quick_push (a);
+       {
+         vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
+                                         virtual_offset));
+         arg = DECL_CHAIN (a);
+         i = 1;
+       }
 
       if (nargs)
-        for (i = 1, arg = DECL_CHAIN (a); i < nargs; i++, arg = DECL_CHAIN (arg))
+       for (; i < nargs; i++, arg = DECL_CHAIN (arg))
          {
            tree tmp = arg;
            if (!is_gimple_val (arg))
@@ -1577,15 +1717,35 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
       call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
       callees->call_stmt = call;
       gimple_call_set_from_thunk (call, true);
-      if (restmp)
+      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);
          gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
                                                 TREE_TYPE (TREE_TYPE (alias))));
        }
       gsi_insert_after (&bsi, call, GSI_NEW_STMT);
-      if (!(gimple_call_flags (call) & ECF_NORETURN))
+      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))
            {
@@ -1594,13 +1754,20 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
              if (TREE_CODE (TREE_TYPE (restmp)) == POINTER_TYPE)
                {
                  gimple stmt;
+                 edge e;
                  /* If the return type is a pointer, we need to
                     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);
-                 return_bb = create_basic_block (NULL, (void *) 0, then_bb);
-                 else_bb = create_basic_block (NULL, (void *) 0, else_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, then_bb);
+                 return_bb->count = count;
+                 return_bb->frequency = BB_FREQ_MAX;
+                 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);
                  add_bb_to_loop (return_bb, bb->loop_father);
                  add_bb_to_loop (else_bb, bb->loop_father);
@@ -1610,11 +1777,21 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
                                            build_zero_cst (TREE_TYPE (restmp)),
                                            NULL_TREE, NULL_TREE);
                  gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
-                 make_edge (bb, then_bb, EDGE_TRUE_VALUE);
-                 make_edge (bb, else_bb, EDGE_FALSE_VALUE);
-                 make_edge (return_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
-                 make_edge (then_bb, return_bb, EDGE_FALLTHRU);
-                 make_edge (else_bb, return_bb, EDGE_FALLTHRU);
+                 e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
+                 e->probability = REG_BR_PROB_BASE - REG_BR_PROB_BASE / 16;
+                 e->count = count - count / 16;
+                 e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
+                 e->probability = REG_BR_PROB_BASE / 16;
+                 e->count = count / 16;
+                 e = make_edge (return_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+                 e->probability = REG_BR_PROB_BASE;
+                 e->count = count;
+                 e = make_edge (then_bb, return_bb, EDGE_FALLTHRU);
+                 e->probability = REG_BR_PROB_BASE;
+                 e->count = count - count / 16;
+                 e = make_edge (else_bb, return_bb, EDGE_FALLTHRU);
+                 e->probability = REG_BR_PROB_BASE;
+                 e->count = count / 16;
                  bsi = gsi_last_bb (then_bb);
                }
 
@@ -1634,7 +1811,12 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
            gimple_call_set_tail (call, true);
 
          /* Build return value.  */
-         ret = gimple_build_return (restmp);
+         if (!DECL_BY_REFERENCE (resdecl))
+           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);
        }
       else
@@ -1644,6 +1826,8 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
        }
 
       cfun->gimple_df->in_ssa_p = true;
+      profile_status_for_fn (cfun)
+        = count ? PROFILE_READ : PROFILE_GUESSED;
       /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks.  */
       TREE_ASM_WRITTEN (thunk_fndecl) = false;
       delete_unreachable_blocks ();
@@ -1673,7 +1857,8 @@ cgraph_node::assemble_thunks_and_aliases (void)
   ipa_ref *ref;
 
   for (e = callers; e;)
-    if (e->caller->thunk.thunk_p)
+    if (e->caller->thunk.thunk_p
+       && !e->caller->thunk.add_pointer_bounds_args)
       {
        cgraph_node *thunk = e->caller;
 
@@ -1712,7 +1897,7 @@ cgraph_node::expand (void)
   announce_function (decl);
   process = 0;
   gcc_assert (lowered);
-  get_body ();
+  get_untransformed_body ();
 
   /* Generate RTL for the body of DECL.  */
 
@@ -1867,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 ();
        }
@@ -2023,7 +2208,7 @@ ipa_passes (void)
 
   /* This extra symtab_remove_unreachable_nodes pass tends to catch some
      devirtualization and other changes where removal iterate.  */
-  symtab->remove_unreachable_nodes (true, symtab->dump_file);
+  symtab->remove_unreachable_nodes (symtab->dump_file);
 
   /* If pass_all_early_optimizations was not scheduled, the state of
      the cgraph will not be properly updated.  Update it now.  */
@@ -2045,13 +2230,27 @@ ipa_passes (void)
     }
 
   /* Some targets need to handle LTO assembler output specially.  */
-  if (flag_generate_lto)
+  if (flag_generate_lto || flag_generate_offload)
     targetm.asm_out.lto_start ();
 
   if (!in_lto_p)
-    ipa_write_summaries ();
+    {
+      if (g->have_offload)
+       {
+         section_name_prefix = OFFLOAD_SECTION_NAME_PREFIX;
+         lto_stream_offload_p = true;
+         ipa_write_summaries ();
+         lto_stream_offload_p = false;
+       }
+      if (flag_lto)
+       {
+         section_name_prefix = LTO_SECTION_NAME_PREFIX;
+         lto_stream_offload_p = false;
+         ipa_write_summaries ();
+       }
+    }
 
-  if (flag_generate_lto)
+  if (flag_generate_lto || flag_generate_offload)
     targetm.asm_out.lto_end ();
 
   if (!flag_ltrans && (in_lto_p || !flag_lto || flag_fat_lto_objects))
@@ -2080,9 +2279,13 @@ void
 symbol_table::output_weakrefs (void)
 {
   symtab_node *node;
+  cgraph_node *cnode;
   FOR_EACH_SYMBOL (node)
     if (node->alias
         && !TREE_ASM_WRITTEN (node->decl)
+       && (!(cnode = dyn_cast <cgraph_node *> (node))
+           || !cnode->instrumented_version
+           || !TREE_ASM_WRITTEN (cnode->instrumented_version->decl))
        && node->weakref)
       {
        tree target;
@@ -2129,8 +2332,12 @@ symbol_table::compile (void)
     fprintf (stderr, "Performing interprocedural optimizations\n");
   state = IPA;
 
+  /* Offloading requires LTO infrastructure.  */
+  if (!in_lto_p && g->have_offload)
+    flag_generate_offload = 1;
+
   /* If LTO is enabled, initialize the streamer hooks needed by GIMPLE.  */
-  if (flag_lto)
+  if (flag_generate_lto || flag_generate_offload)
     lto_streamer_hooks_init ();
 
   /* Don't run the IPA passes if there was any error or sorry messages.  */
@@ -2145,10 +2352,6 @@ symbol_table::compile (void)
       return;
     }
 
-  /* This pass remove bodies of extern inline functions we never inlined.
-     Do this later so other IPA passes see what is really going on.
-     FIXME: This should be run just after inlining by pasmanager.  */
-  remove_unreachable_nodes (false, dump_file);
   global_info_ready = true;
   if (dump_file)
     {
@@ -2279,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 ();
@@ -2315,32 +2528,40 @@ cgraphunit_c_finalize (void)
 void
 cgraph_node::create_wrapper (cgraph_node *target)
 {
-    /* Preserve DECL_RESULT so we get right by reference flag.  */
-    tree decl_result = DECL_RESULT (decl);
+  /* Preserve DECL_RESULT so we get right by reference flag.  */
+  tree decl_result = DECL_RESULT (decl);
+
+  /* Remove the function's body but keep arguments to be reused
+     for thunk.  */
+  release_body (true);
+  reset ();
 
-    /* Remove the function's body but keep arguments to be reused
-       for thunk.  */
-    release_body (true);
-    reset ();
+  DECL_UNINLINABLE (decl) = false;
+  DECL_RESULT (decl) = decl_result;
+  DECL_INITIAL (decl) = NULL;
+  allocate_struct_function (decl, false);
+  set_cfun (NULL);
 
-    DECL_RESULT (decl) = decl_result;
-    DECL_INITIAL (decl) = NULL;
-    allocate_struct_function (decl, false);
-    set_cfun (NULL);
+  /* Turn alias into thunk and expand it into GIMPLE representation.  */
+  definition = true;
 
-    /* Turn alias into thunk and expand it into GIMPLE representation.  */
-    definition = true;
-    thunk.thunk_p = true;
-    thunk.this_adjusting = false;
+  memset (&thunk, 0, sizeof (cgraph_thunk_info));
+  thunk.thunk_p = true;
+  create_edge (target, NULL, count, CGRAPH_FREQ_BASE);
 
-    cgraph_edge *e = create_edge (target, NULL, 0, CGRAPH_FREQ_BASE);
+  tree arguments = DECL_ARGUMENTS (decl);
+
+  while (arguments)
+    {
+      TREE_ADDRESSABLE (arguments) = false;
+      arguments = TREE_CHAIN (arguments);
+    }
 
-    expand_thunk (false, true);
-    e->call_stmt_cannot_inline_p = true;
+  expand_thunk (false, true);
 
-    /* Inline summary set-up.  */
-    analyze ();
-    inline_analyze_function (this);
+  /* Inline summary set-up.  */
+  analyze ();
+  inline_analyze_function (this);
 }
 
 #include "gt-cgraphunit.h"