Allow constant global VAR_DECLs in constant jump functions
[gcc.git] / gcc / ipa-cp.c
index 0c540eb61c71027c331868e888e169f5b4e52f1f..8caa973e46c7fe44a2e99c5d1b9bf618e81a986c 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural constant propagation
-   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Copyright (C) 2005-2016 Free Software Foundation, Inc.
 
    Contributed by Razya Ladelsky <RAZYA@il.ibm.com> and Martin Jambor
    <mjambor@suse.cz>
@@ -103,39 +103,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "hash-map.h"
-#include "double-int.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
-#include "options.h"
-#include "wide-int.h"
-#include "inchash.h"
+#include "backend.h"
 #include "tree.h"
-#include "fold-const.h"
-#include "gimple-fold.h"
 #include "gimple-expr.h"
-#include "target.h"
 #include "predict.h"
-#include "basic-block.h"
-#include "is-a.h"
-#include "plugin-api.h"
-#include "tm.h"
-#include "hard-reg-set.h"
-#include "input.h"
-#include "function.h"
-#include "ipa-ref.h"
-#include "cgraph.h"
 #include "alloc-pool.h"
-#include "symbol-summary.h"
-#include "ipa-prop.h"
-#include "bitmap.h"
 #include "tree-pass.h"
-#include "flags.h"
+#include "cgraph.h"
 #include "diagnostic.h"
+#include "fold-const.h"
+#include "gimple-fold.h"
+#include "symbol-summary.h"
+#include "ipa-prop.h"
 #include "tree-pretty-print.h"
 #include "tree-inline.h"
 #include "params.h"
@@ -257,6 +236,36 @@ public:
   struct ipcp_agg_lattice *next;
 };
 
+/* Lattice of pointer alignment.  Unlike the previous types of lattices, this
+   one is only capable of holding one value.  */
+
+class ipcp_alignment_lattice
+{
+public:
+  /* If bottom and top are both false, these two fields hold values as given by
+     ptr_info_def and get_pointer_alignment_1.  */
+  unsigned align;
+  unsigned misalign;
+
+  inline bool bottom_p () const;
+  inline bool top_p () const;
+  inline bool set_to_bottom ();
+  bool meet_with (unsigned new_align, unsigned new_misalign);
+  bool meet_with (const ipcp_alignment_lattice &other, HOST_WIDE_INT offset);
+  void print (FILE * f);
+private:
+  /* If set, this lattice is bottom and all other fields should be
+     disregarded.  */
+  bool bottom;
+  /* If bottom and not_top are false, the lattice is TOP.  If not_top is true,
+     the known alignment is stored in the fields align and misalign.  The field
+     is negated so that memset to zero initializes the lattice to TOP
+     state.  */
+  bool not_top;
+
+  bool meet_with_1 (unsigned new_align, unsigned new_misalign);
+};
+
 /* Structure containing lattices for a parameter itself and for pieces of
    aggregates that are passed in the parameter or by a reference in a parameter
    plus some other useful flags.  */
@@ -266,13 +275,12 @@ class ipcp_param_lattices
 public:
   /* Lattice describing the value of the parameter itself.  */
   ipcp_lattice<tree> itself;
-  /* Lattice describing the the polymorphic contexts of a parameter.  */
+  /* Lattice describing the polymorphic contexts of a parameter.  */
   ipcp_lattice<ipa_polymorphic_call_context> ctxlat;
   /* Lattices describing aggregate parts.  */
   ipcp_agg_lattice *aggs;
-  /* Alignment information.  Very basic one value lattice where !known means
-     TOP and zero alignment bottom.  */
-  ipa_alignment alignment;
+  /* Lattice describing known alignment.  */
+  ipcp_alignment_lattice alignment;
   /* Number of aggregate lattices */
   int aggs_count;
   /* True if aggregate data were passed by reference (as opposed to by
@@ -291,10 +299,17 @@ public:
 
 /* Allocation pools for values and their sources in ipa-cp.  */
 
-alloc_pool ipcp_cst_values_pool;
-alloc_pool ipcp_poly_ctx_values_pool;
-alloc_pool ipcp_sources_pool;
-alloc_pool ipcp_agg_lattice_pool;
+object_allocator<ipcp_value<tree> > ipcp_cst_values_pool
+  ("IPA-CP constant values");
+
+object_allocator<ipcp_value<ipa_polymorphic_call_context> >
+  ipcp_poly_ctx_values_pool ("IPA-CP polymorphic contexts");
+
+object_allocator<ipcp_value_source<tree> > ipcp_sources_pool
+  ("IPA-CP value sources");
+
+object_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool
+  ("IPA_CP aggregate lattices");
 
 /* Maximal count found in program.  */
 
@@ -430,6 +445,19 @@ ipcp_lattice<valtype>::print (FILE * f, bool dump_sources, bool dump_benefits)
     fprintf (f, "\n");
 }
 
+/* Print alignment lattice to F.  */
+
+void
+ipcp_alignment_lattice::print (FILE * f)
+{
+  if (top_p ())
+    fprintf (f, "         Alignment unknown (TOP)\n");
+  else if (bottom_p ())
+    fprintf (f, "         Alignment unusable (BOTTOM)\n");
+  else
+    fprintf (f, "         Alignment %u, misalignment %u\n", align, misalign);
+}
+
 /* Print all ipcp_lattices of all functions to F.  */
 
 static void
@@ -455,13 +483,7 @@ print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits)
          plats->itself.print (f, dump_sources, dump_benefits);
          fprintf (f, "         ctxs: ");
          plats->ctxlat.print (f, dump_sources, dump_benefits);
-         if (plats->alignment.known && plats->alignment.align > 0)
-           fprintf (f, "         Alignment %u, misalignment %u\n",
-                    plats->alignment.align, plats->alignment.misalign);
-         else if (plats->alignment.known)
-           fprintf (f, "         Alignment unusable\n");
-         else
-           fprintf (f, "         Alignment unknown\n");
+         plats->alignment.print (f);
          if (plats->virt_call)
            fprintf (f, "        virt_call flag set\n");
 
@@ -487,7 +509,8 @@ print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits)
    with NODE.  */
 
 static void
-determine_versionability (struct cgraph_node *node)
+determine_versionability (struct cgraph_node *node,
+                         struct ipa_node_params *info)
 {
   const char *reason = NULL;
 
@@ -519,7 +542,7 @@ determine_versionability (struct cgraph_node *node)
     fprintf (dump_file, "Function %s/%i is not versionable, reason: %s.\n",
             node->name (), node->order, reason);
 
-  node->local.versionable = (reason == NULL);
+  info->versionable = (reason == NULL);
 }
 
 /* Return true if it is at all technically possible to create clones of a
@@ -528,7 +551,7 @@ determine_versionability (struct cgraph_node *node)
 static bool
 ipcp_versionable_function_p (struct cgraph_node *node)
 {
-  return node->local.versionable;
+  return IPA_NODE_REF (node)->versionable;
 }
 
 /* Structure holding accumulated information about callers of a node.  */
@@ -560,10 +583,7 @@ gather_caller_stats (struct cgraph_node *node, void *data)
   struct cgraph_edge *cs;
 
   for (cs = node->callers; cs; cs = cs->next_caller)
-    if (cs->caller->thunk.thunk_p)
-      cs->caller->call_for_symbol_thunks_and_aliases (gather_caller_stats,
-                                                   stats, false);
-    else
+    if (!cs->caller->thunk.thunk_p)
       {
        stats->count_sum += cs->count;
        stats->freq_sum += cs->frequency;
@@ -593,7 +613,7 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
       return false;
     }
 
-  if (!optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->decl)))
+  if (node->optimize_for_size_p ())
     {
       if (dump_file)
         fprintf (dump_file, "Not considering %s for cloning; "
@@ -779,27 +799,111 @@ set_agg_lats_contain_variable (struct ipcp_param_lattices *plats)
   return ret;
 }
 
-/* Return true if alignment information in PLATS is known to be unusable.  */
+/* Return true if alignment information in the lattice is yet unknown.  */
 
-static inline bool
-alignment_bottom_p (ipcp_param_lattices *plats)
+bool
+ipcp_alignment_lattice::top_p () const
 {
-  return plats->alignment.known && (plats->alignment.align == 0);
+  return !bottom && !not_top;
 }
 
-/* Set alignment information in PLATS to unusable.  Return true if it
-   previously was usable or unknown.  */
+/* Return true if alignment information in the lattice is known to be
+   unusable.  */
 
-static inline bool
-set_alignment_to_bottom (ipcp_param_lattices *plats)
+bool
+ipcp_alignment_lattice::bottom_p () const
+{
+  return bottom;
+}
+
+/* Set alignment information in the lattice to bottom.  Return true if it
+   previously was in a different state.  */
+
+bool
+ipcp_alignment_lattice::set_to_bottom ()
 {
-  if (alignment_bottom_p (plats))
+  if (bottom_p ())
     return false;
-  plats->alignment.known = true;
-  plats->alignment.align = 0;
+  bottom = true;
   return true;
 }
 
+/* Meet the current value of the lattice with alignment described by NEW_ALIGN
+   and NEW_MISALIGN, assuming that we know the current value is neither TOP nor
+   BOTTOM.  Return true if the value of lattice has changed.  */
+
+bool
+ipcp_alignment_lattice::meet_with_1 (unsigned new_align, unsigned new_misalign)
+{
+  gcc_checking_assert (new_align != 0);
+  if (align == new_align && misalign == new_misalign)
+    return false;
+
+  bool changed = false;
+  if (align > new_align)
+    {
+      align = new_align;
+      misalign = misalign % new_align;
+      changed = true;
+    }
+  if (misalign != (new_misalign % align))
+    {
+      int diff = abs ((int) misalign - (int) (new_misalign % align));
+      align = (unsigned) diff & -diff;
+      if (align)
+       misalign = misalign % align;
+      else
+       set_to_bottom ();
+      changed = true;
+    }
+  gcc_checking_assert (bottom_p () || align != 0);
+  return changed;
+}
+
+/* Meet the current value of the lattice with alignment described by NEW_ALIGN
+   and NEW_MISALIGN.  Return true if the value of lattice has changed.  */
+
+bool
+ipcp_alignment_lattice::meet_with (unsigned new_align, unsigned new_misalign)
+{
+  gcc_assert (new_align != 0);
+  if (bottom_p ())
+    return false;
+  if (top_p ())
+    {
+      not_top = true;
+      align = new_align;
+      misalign = new_misalign;
+      return true;
+    }
+  return meet_with_1 (new_align, new_misalign);
+}
+
+/* Meet the current value of the lattice with OTHER, taking into account that
+   OFFSET has been added to the pointer value.  Return true if the value of
+   lattice has changed.  */
+
+bool
+ipcp_alignment_lattice::meet_with (const ipcp_alignment_lattice &other,
+                                  HOST_WIDE_INT offset)
+{
+  if (other.bottom_p ())
+    return set_to_bottom ();
+  if (bottom_p () || other.top_p ())
+    return false;
+
+  unsigned adjusted_misalign = (other.misalign + offset) % other.align;
+  if (top_p ())
+    {
+      not_top = true;
+      align = other.align;
+      misalign = adjusted_misalign;
+      return true;
+    }
+
+  return meet_with_1 (other.align, adjusted_misalign);
+}
+
 /* Mark bot aggregate and scalar lattices as containing an unknown variable,
    return true is any of them has not been marked as such so far.  */
 
@@ -810,10 +914,44 @@ set_all_contains_variable (struct ipcp_param_lattices *plats)
   ret = plats->itself.set_contains_variable ();
   ret |= plats->ctxlat.set_contains_variable ();
   ret |= set_agg_lats_contain_variable (plats);
-  ret |= set_alignment_to_bottom (plats);
+  ret |= plats->alignment.set_to_bottom ();
   return ret;
 }
 
+/* Worker of call_for_symbol_thunks_and_aliases, increment the integer DATA
+   points to by the number of callers to NODE.  */
+
+static bool
+count_callers (cgraph_node *node, void *data)
+{
+  int *caller_count = (int *) data;
+
+  for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller)
+    /* Local thunks can be handled transparently, but if the thunk can not
+       be optimized out, count it as a real use.  */
+    if (!cs->caller->thunk.thunk_p || !cs->caller->local.local)
+      ++*caller_count;
+  return false;
+}
+
+/* Worker of call_for_symbol_thunks_and_aliases, it is supposed to be called on
+   the one caller of some other node.  Set the caller's corresponding flag.  */
+
+static bool
+set_single_call_flag (cgraph_node *node, void *)
+{
+  cgraph_edge *cs = node->callers;
+  /* Local thunks can be handled transparently, skip them.  */
+  while (cs && cs->caller->thunk.thunk_p && cs->caller->local.local)
+    cs = cs->next_caller;
+  if (cs)
+    {
+      IPA_NODE_REF (cs->caller)->node_calling_single_call = true;
+      return true;
+    }
+  return false;
+}
+
 /* Initialize ipcp_lattices.  */
 
 static void
@@ -825,7 +963,17 @@ initialize_node_lattices (struct cgraph_node *node)
   int i;
 
   gcc_checking_assert (node->has_gimple_body_p ());
-  if (!cgraph_local_p (node))
+  if (cgraph_local_p (node))
+    {
+      int caller_count = 0;
+      node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count,
+                                               true);
+      gcc_checking_assert (caller_count > 0);
+      if (caller_count == 1)
+       node->call_for_symbol_thunks_and_aliases (set_single_call_flag,
+                                                 NULL, true);
+    }
+  else
     {
       /* When cloning is allowed, we can assume that externally visible
         functions are not called.  We will compensate this by cloning
@@ -847,7 +995,7 @@ initialize_node_lattices (struct cgraph_node *node)
              plats->itself.set_to_bottom ();
              plats->ctxlat.set_to_bottom ();
              set_agg_lats_to_bottom (plats);
-             set_alignment_to_bottom (plats);
+             plats->alignment.set_to_bottom ();
            }
          else
            set_all_contains_variable (plats);
@@ -878,9 +1026,10 @@ ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input)
 {
   tree restype, res;
 
-  gcc_checking_assert (is_gimple_ip_invariant (input));
   if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
     return input;
+  if (!is_gimple_ip_invariant (input))
+    return NULL_TREE;
 
   if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc))
       == tcc_comparison)
@@ -907,7 +1056,7 @@ ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input)
     {
       tree t = TREE_OPERAND (input, 0);
       t = build_ref_for_offset (EXPR_LOCATION (t), t,
-                               ipa_get_jf_ancestor_offset (jfunc),
+                               ipa_get_jf_ancestor_offset (jfunc), false,
                                ptr_type_node, NULL, false);
       return build_fold_addr_expr (t);
     }
@@ -1106,7 +1255,7 @@ ipcp_value<valtype>::add_source (cgraph_edge *cs, ipcp_value *src_val,
 {
   ipcp_value_source<valtype> *src;
 
-  src = new (pool_alloc (ipcp_sources_pool)) ipcp_value_source<valtype>;
+  src = new (ipcp_sources_pool.allocate ()) ipcp_value_source<valtype>;
   src->offset = offset;
   src->cs = cs;
   src->val = src_val;
@@ -1124,7 +1273,7 @@ allocate_and_init_ipcp_value (tree source)
 {
   ipcp_value<tree> *val;
 
-  val = new (pool_alloc (ipcp_cst_values_pool)) ipcp_value<tree>;
+  val = ipcp_cst_values_pool.allocate ();
   memset (val, 0, sizeof (*val));
   val->value = source;
   return val;
@@ -1138,8 +1287,8 @@ allocate_and_init_ipcp_value (ipa_polymorphic_call_context source)
 {
   ipcp_value<ipa_polymorphic_call_context> *val;
 
-  val = new (pool_alloc (ipcp_poly_ctx_values_pool))
-    ipcp_value<ipa_polymorphic_call_context>;
+  // TODO
+  val = ipcp_poly_ctx_values_pool.allocate ();
   memset (val, 0, sizeof (*val));
   val->value = source;
   return val;
@@ -1181,14 +1330,14 @@ ipcp_lattice<valtype>::add_value (valtype newval, cgraph_edge *cs,
   if (values_count == PARAM_VALUE (PARAM_IPA_CP_VALUE_LIST_SIZE))
     {
       /* We can only free sources, not the values themselves, because sources
-        of other values in this this SCC might point to them.   */
+        of other values in this SCC might point to them.   */
       for (val = values; val; val = val->next)
        {
          while (val->sources)
            {
              ipcp_value_source<valtype> *src = val->sources;
              val->sources = src->next;
-             pool_free (ipcp_sources_pool, src);
+             ipcp_sources_pool.remove ((ipcp_value_source<tree>*)src);
            }
        }
 
@@ -1416,22 +1565,17 @@ propagate_context_accross_jump_function (cgraph_edge *cs,
    edge CS and update DEST_LAT accordingly.  */
 
 static bool
-propagate_alignment_accross_jump_function (struct cgraph_edge *cs,
-                                          struct ipa_jump_func *jfunc,
-                                          struct ipcp_param_lattices *dest_lat)
+propagate_alignment_accross_jump_function (cgraph_edge *cs,
+                                          ipa_jump_func *jfunc,
+                                          ipcp_alignment_lattice *dest_lat)
 {
-  if (alignment_bottom_p (dest_lat))
+  if (dest_lat->bottom_p ())
     return false;
 
-  ipa_alignment cur;
-  cur.known = false;
-  if (jfunc->alignment.known)
-    cur = jfunc->alignment;
-  else if (jfunc->type == IPA_JF_PASS_THROUGH
+  if (jfunc->type == IPA_JF_PASS_THROUGH
           || jfunc->type == IPA_JF_ANCESTOR)
     {
       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
-      struct ipcp_param_lattices *src_lats;
       HOST_WIDE_INT offset = 0;
       int src_idx;
 
@@ -1441,12 +1585,11 @@ propagate_alignment_accross_jump_function (struct cgraph_edge *cs,
          if (op != NOP_EXPR)
            {
              if (op != POINTER_PLUS_EXPR
-                 && op != PLUS_EXPR
-                 && op != MINUS_EXPR)
-               goto prop_fail;
+                 && op != PLUS_EXPR)
+               return dest_lat->set_to_bottom ();
              tree operand = ipa_get_jf_pass_through_operand (jfunc);
              if (!tree_fits_shwi_p (operand))
-               goto prop_fail;
+               return dest_lat->set_to_bottom ();
              offset = tree_to_shwi (operand);
            }
          src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
@@ -1454,33 +1597,21 @@ propagate_alignment_accross_jump_function (struct cgraph_edge *cs,
       else
        {
          src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
-         offset = ipa_get_jf_ancestor_offset (jfunc);
+         offset = ipa_get_jf_ancestor_offset (jfunc) / BITS_PER_UNIT;
        }
 
+      struct ipcp_param_lattices *src_lats;
       src_lats = ipa_get_parm_lattices (caller_info, src_idx);
-      if (!src_lats->alignment.known
-         || alignment_bottom_p (src_lats))
-       goto prop_fail;
-
-      cur = src_lats->alignment;
-      cur.misalign = (cur.misalign + offset) % cur.align;
+      return dest_lat->meet_with (src_lats->alignment, offset);
     }
-
-  if (cur.known)
+  else
     {
-      if (!dest_lat->alignment.known)
-       {
-         dest_lat->alignment = cur;
-         return true;
-       }
-      else if (dest_lat->alignment.align == cur.align
-              && dest_lat->alignment.misalign == cur.misalign)
-       return false;
+      if (jfunc->alignment.known)
+       return dest_lat->meet_with (jfunc->alignment.align,
+                                   jfunc->alignment.misalign);
+      else
+       return dest_lat->set_to_bottom ();
     }
-
- prop_fail:
-  set_alignment_to_bottom (dest_lat);
-  return true;
 }
 
 /* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
@@ -1559,7 +1690,7 @@ merge_agg_lats_step (struct ipcp_param_lattices *dest_plats,
       if (dest_plats->aggs_count == PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS))
        return false;
       dest_plats->aggs_count++;
-      new_al = (struct ipcp_agg_lattice *) pool_alloc (ipcp_agg_lattice_pool);
+      new_al = ipcp_agg_lattice_pool.allocate ();
       memset (new_al, 0, sizeof (*new_al));
 
       new_al->offset = offset;
@@ -1747,6 +1878,18 @@ propagate_aggs_accross_jump_function (struct cgraph_edge *cs,
   return ret;
 }
 
+/* Return true if on the way cfrom CS->caller to the final (non-alias and
+   non-thunk) destination, the call passes through a thunk.  */
+
+static bool
+call_passes_through_thunk_p (cgraph_edge *cs)
+{
+  cgraph_node *alias_or_thunk = cs->callee;
+  while (alias_or_thunk->alias)
+    alias_or_thunk = alias_or_thunk->get_alias_target ();
+  return alias_or_thunk->thunk.thunk_p;
+}
+
 /* Propagate constants from the caller to the callee of CS.  INFO describes the
    caller.  */
 
@@ -1755,7 +1898,7 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
 {
   struct ipa_node_params *callee_info;
   enum availability availability;
-  struct cgraph_node *callee, *alias_or_thunk;
+  cgraph_node *callee;
   struct ipa_edge_args *args;
   bool ret = false;
   int i, args_count, parms_count;
@@ -1793,10 +1936,7 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
   /* If this call goes through a thunk we must not propagate to the first (0th)
      parameter.  However, we might need to uncover a thunk from below a series
      of aliases first.  */
-  alias_or_thunk = cs->callee;
-  while (alias_or_thunk->alias)
-    alias_or_thunk = alias_or_thunk->get_alias_target ();
-  if (alias_or_thunk->thunk.thunk_p)
+  if (call_passes_through_thunk_p (cs))
     {
       ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
                                                               0));
@@ -1820,7 +1960,7 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
          ret |= propagate_context_accross_jump_function (cs, jump_func, i,
                                                          &dest_plats->ctxlat);
          ret |= propagate_alignment_accross_jump_function (cs, jump_func,
-                                                           dest_plats);
+                                                        &dest_plats->alignment);
          ret |= propagate_aggs_accross_jump_function (cs, jump_func,
                                                       dest_plats);
        }
@@ -1860,9 +2000,9 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 
       if (ie->indirect_info->agg_contents)
        {
-         if (agg_reps)
+         t = NULL;
+         if (agg_reps && ie->indirect_info->guaranteed_unmodified)
            {
-             t = NULL;
              while (agg_reps)
                {
                  if (agg_reps->index == param_index
@@ -1875,15 +2015,22 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
                  agg_reps = agg_reps->next;
                }
            }
-         else if (known_aggs.length () > (unsigned int) param_index)
+         if (!t)
            {
              struct ipa_agg_jump_function *agg;
-             agg = known_aggs[param_index];
-             t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset,
-                                             ie->indirect_info->by_ref);
+             if (known_aggs.length () > (unsigned int) param_index)
+               agg = known_aggs[param_index];
+             else
+               agg = NULL;
+             bool from_global_constant;
+             t = ipa_find_agg_cst_for_param (agg, known_csts[param_index],
+                                             ie->indirect_info->offset,
+                                             ie->indirect_info->by_ref,
+                                             &from_global_constant);
+             if (!from_global_constant
+                 && !ie->indirect_info->guaranteed_unmodified)
+               t = NULL_TREE;
            }
-         else
-           t = NULL;
        }
       else
        t = known_csts[param_index];
@@ -1927,7 +2074,8 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
     {
        struct ipa_agg_jump_function *agg;
        agg = known_aggs[param_index];
-       t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset,
+       t = ipa_find_agg_cst_for_param (agg, known_csts[param_index],
+                                      ie->indirect_info->offset,
                                       true);
     }
 
@@ -1938,15 +2086,22 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
       unsigned HOST_WIDE_INT offset;
       if (vtable_pointer_value_to_vtable (t, &vtable, &offset))
        {
+         bool can_refer;
          target = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token,
-                                                     vtable, offset);
-         if (target)
+                                                     vtable, offset, &can_refer);
+         if (can_refer)
            {
-             if ((TREE_CODE (TREE_TYPE (target)) == FUNCTION_TYPE
-                  && DECL_FUNCTION_CODE (target) == BUILT_IN_UNREACHABLE)
+             if (!target
+                 || (TREE_CODE (TREE_TYPE (target)) == FUNCTION_TYPE
+                     && DECL_FUNCTION_CODE (target) == BUILT_IN_UNREACHABLE)
                  || !possible_polymorphic_call_target_p
                       (ie, cgraph_node::get (target)))
-               target = ipa_impossible_devirt_target (ie, target);
+               {
+                 /* Do not speculate builtin_unreachable, it is stupid!  */
+                 if (ie->indirect_info->vptr_changed)
+                   return NULL;
+                 target = ipa_impossible_devirt_target (ie, target);
+               }
               *speculative = ie->indirect_info->vptr_changed;
              if (!*speculative)
                return target;
@@ -2024,7 +2179,11 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 
   if (target && !possible_polymorphic_call_target_p (ie,
                                                     cgraph_node::get (target)))
-    target = ipa_impossible_devirt_target (ie, target);
+    {
+      if (*speculative)
+       return NULL;
+      target = ipa_impossible_devirt_target (ie, target);
+    }
 
   return target;
 }
@@ -2109,6 +2268,24 @@ hint_time_bonus (inline_hints hints)
   return result;
 }
 
+/* If there is a reason to penalize the function described by INFO in the
+   cloning goodness evaluation, do so.  */
+
+static inline int64_t
+incorporate_penalties (ipa_node_params *info, int64_t evaluation)
+{
+  if (info->node_within_scc)
+    evaluation = (evaluation
+                 * (100 - PARAM_VALUE (PARAM_IPA_CP_RECURSION_PENALTY))) / 100;
+
+  if (info->node_calling_single_call)
+    evaluation = (evaluation
+                 * (100 - PARAM_VALUE (PARAM_IPA_CP_SINGLE_CALL_PENALTY)))
+      / 100;
+
+  return evaluation;
+}
+
 /* Return true if cloning NODE is a good idea, given the estimated TIME_BENEFIT
    and SIZE_COST and with the sum of frequencies of incoming edges to the
    potential new clone in FREQUENCIES.  */
@@ -2119,23 +2296,27 @@ good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit,
 {
   if (time_benefit == 0
       || !opt_for_fn (node->decl, flag_ipa_cp_clone)
-      || !optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->decl)))
+      || node->optimize_for_size_p ())
     return false;
 
   gcc_assert (size_cost > 0);
 
+  struct ipa_node_params *info = IPA_NODE_REF (node);
   if (max_count)
     {
       int factor = (count_sum * 1000) / max_count;
       int64_t evaluation = (((int64_t) time_benefit * factor)
                                    / size_cost);
+      evaluation = incorporate_penalties (info, evaluation);
 
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "     good_cloning_opportunity_p (time: %i, "
                 "size: %i, count_sum: " HOST_WIDE_INT_PRINT_DEC
-                ") -> evaluation: " "%"PRId64
+                "%s%s) -> evaluation: " "%" PRId64
                 ", threshold: %i\n",
                 time_benefit, size_cost, (HOST_WIDE_INT) count_sum,
+                info->node_within_scc ? ", scc" : "",
+                info->node_calling_single_call ? ", single_call" : "",
                 evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
 
       return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
@@ -2144,13 +2325,16 @@ good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit,
     {
       int64_t evaluation = (((int64_t) time_benefit * freq_sum)
                                    / size_cost);
+      evaluation = incorporate_penalties (info, evaluation);
 
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "     good_cloning_opportunity_p (time: %i, "
-                "size: %i, freq_sum: %i) -> evaluation: "
-                "%"PRId64 ", threshold: %i\n",
-                time_benefit, size_cost, freq_sum, evaluation,
-                PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
+                "size: %i, freq_sum: %i%s%s) -> evaluation: "
+                "%" PRId64 ", threshold: %i\n",
+                time_benefit, size_cost, freq_sum,
+                info->node_within_scc ? ", scc" : "",
+                info->node_calling_single_call ? ", single_call" : "",
+                evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
 
       return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
     }
@@ -2232,12 +2416,14 @@ gather_context_independent_values (struct ipa_node_params *info,
        *removable_params_cost
          += ipa_get_param_move_cost (info, i);
 
+      if (!ipa_is_param_used (info, i))
+       continue;
+
       ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
+      /* Do not account known context as reason for cloning.  We can see
+        if it permits devirtualization.  */
       if (ctxlat->is_single_const ())
-       {
-         (*known_contexts)[i] = ctxlat->values->value;
-         ret = true;
-       }
+       (*known_contexts)[i] = ctxlat->values->value;
 
       if (known_aggs)
        {
@@ -2339,7 +2525,10 @@ estimate_local_effects (struct cgraph_node *node)
                                                    &known_contexts, &known_aggs,
                                                    &removable_params_cost);
   known_aggs_ptrs = agg_jmp_p_vec_for_t_vec (known_aggs);
-  if (always_const)
+  int devirt_bonus = devirtualization_time_bonus (node, known_csts,
+                                          known_contexts, known_aggs_ptrs);
+  if (always_const || devirt_bonus
+      || (removable_params_cost && node->local.can_change_signature))
     {
       struct caller_statistics stats;
       inline_hints hints;
@@ -2350,8 +2539,7 @@ estimate_local_effects (struct cgraph_node *node)
                                              false);
       estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
                                         known_aggs_ptrs, &size, &time, &hints);
-      time -= devirtualization_time_bonus (node, known_csts, known_contexts,
-                                          known_aggs_ptrs);
+      time -= devirt_bonus;
       time -= hint_time_bonus (hints);
       time -= removable_params_cost;
       size -= stats.n_calls * removable_params_cost;
@@ -2360,8 +2548,7 @@ estimate_local_effects (struct cgraph_node *node)
        fprintf (dump_file, " - context independent values, size: %i, "
                 "time_benefit: %i\n", size, base_time - time);
 
-      if (size <= 0
-         || node->will_be_removed_from_program_if_no_direct_calls_p ())
+      if (size <= 0 || node->local.local)
        {
          info->do_clone_for_all_contexts = true;
          base_time = time;
@@ -2389,6 +2576,10 @@ estimate_local_effects (struct cgraph_node *node)
                     "max_new_size would be reached with %li.\n",
                     size + overall_size);
        }
+      else if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, "   Not cloning for all contexts because "
+                "!good_cloning_opportunity_p.\n");
+       
     }
 
   for (i = 0; i < count ; i++)
@@ -2641,9 +2832,12 @@ propagate_constants_topo (struct ipa_topo_info *topo)
          struct cgraph_edge *cs;
 
          for (cs = v->callees; cs; cs = cs->next_callee)
-           if (ipa_edge_within_scc (cs)
-               && propagate_constants_accross_call (cs))
-             push_node_to_stack (topo, cs->callee);
+           if (ipa_edge_within_scc (cs))
+             {
+               IPA_NODE_REF (v)->node_within_scc = true;
+               if (propagate_constants_accross_call (cs))
+                 push_node_to_stack (topo, cs->callee->function_symbol ());
+             }
          v = pop_node_from_stack (topo);
        }
 
@@ -2734,7 +2928,7 @@ ipcp_propagate_stage (struct ipa_topo_info *topo)
   {
     struct ipa_node_params *info = IPA_NODE_REF (node);
 
-    determine_versionability (node);
+    determine_versionability (node, info);
     if (node->has_gimple_body_p ())
       {
        info->lattices = XCNEWVEC (struct ipcp_param_lattices,
@@ -2757,9 +2951,8 @@ ipcp_propagate_stage (struct ipa_topo_info *topo)
             overall_size, max_new_size);
 
   propagate_constants_topo (topo);
-#ifdef ENABLE_CHECKING
-  ipcp_verify_propagated_values ();
-#endif
+  if (flag_checking)
+    ipcp_verify_propagated_values ();
   topo->constants.propagate_effects ();
   topo->contexts.propagate_effects ();
 
@@ -3336,7 +3529,11 @@ find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
          struct ipa_jump_func *jump_func;
          tree t;
 
-          if (i >= ipa_get_cs_argument_count (IPA_EDGE_REF (cs)))
+          if (i >= ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
+             || (i == 0
+                 && call_passes_through_thunk_p (cs))
+             || (!cs->callee->instrumentation_clone
+                 && cs->callee->function_symbol ()->instrumentation_clone))
             {
               newval = NULL_TREE;
               break;
@@ -3900,7 +4097,7 @@ cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs,
 /* Given an original NODE and a VAL for which we have already created a
    specialized clone, look whether there are incoming edges that still lead
    into the old node but now also bring the requested value and also conform to
-   all other criteria such that they can be redirected the the special node.
+   all other criteria such that they can be redirected the special node.
    This function can therefore redirect the final edge in a SCC.  */
 
 template <typename valtype>
@@ -4262,7 +4459,7 @@ identify_dead_nodes (struct cgraph_node *node)
 {
   struct cgraph_node *v;
   for (v = node; v ; v = ((struct ipa_dfs_info *) v->aux)->next_cycle)
-    if (v->will_be_removed_from_program_if_no_direct_calls_p ()
+    if (v->local.local
        && !v->call_for_symbol_thunks_and_aliases
             (has_undead_caller_from_outside_scc_p, NULL, true))
       IPA_NODE_REF (v)->node_dead = 1;
@@ -4326,6 +4523,15 @@ ipcp_store_alignment_results (void)
     bool dumped_sth = false;
     bool found_useful_result = false;
 
+    if (!opt_for_fn (node->decl, flag_ipa_cp_alignment))
+      {
+       if (dump_file)
+         fprintf (dump_file, "Not considering %s for alignment discovery "
+                  "and propagate; -fipa-cp-alignment: disabled.\n",
+                  node->name ());
+       continue;
+      }
+
    if (info->ipcp_orig_node)
       info = IPA_NODE_REF (info->ipcp_orig_node);
 
@@ -4333,9 +4539,10 @@ ipcp_store_alignment_results (void)
    for (unsigned i = 0; i < count ; i++)
      {
        ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
-       if (plats->alignment.known
-          && plats->alignment.align > 0)
+       if (!plats->alignment.bottom_p ()
+          && !plats->alignment.top_p ())
         {
+          gcc_checking_assert (plats->alignment.align > 0);
           found_useful_result = true;
           break;
         }
@@ -4343,19 +4550,27 @@ ipcp_store_alignment_results (void)
    if (!found_useful_result)
      continue;
 
-  ipcp_grow_transformations_if_necessary ();
+   ipcp_grow_transformations_if_necessary ();
    ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
    vec_safe_reserve_exact (ts->alignments, count);
 
    for (unsigned i = 0; i < count ; i++)
      {
        ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
+       ipa_alignment al;
 
-       if (plats->alignment.align == 0)
-        plats->alignment.known = false;
+       if (!plats->alignment.bottom_p ()
+          && !plats->alignment.top_p ())
+        {
+          al.known = true;
+          al.align = plats->alignment.align;
+          al.misalign = plats->alignment.misalign;
+        }
+       else
+        al.known = false;
 
-       ts->alignments->quick_push (plats->alignment);
-       if (!dump_file || !plats->alignment.known)
+       ts->alignments->quick_push (al);
+       if (!dump_file || !al.known)
         continue;
        if (!dumped_sth)
         {
@@ -4364,7 +4579,7 @@ ipcp_store_alignment_results (void)
           dumped_sth = true;
         }
        fprintf (dump_file, "  param %i: align: %u, misalign: %u\n",
-               i, plats->alignment.align, plats->alignment.misalign);
+               i, al.align, al.misalign);
      }
   }
 }
@@ -4386,16 +4601,6 @@ ipcp_driver (void)
   edge_removal_hook_holder =
     symtab->add_edge_removal_hook (&ipcp_edge_removal_hook, NULL);
 
-  ipcp_cst_values_pool = create_alloc_pool ("IPA-CP constant values",
-                                           sizeof (ipcp_value<tree>), 32);
-  ipcp_poly_ctx_values_pool = create_alloc_pool
-    ("IPA-CP polymorphic contexts",
-     sizeof (ipcp_value<ipa_polymorphic_call_context>), 32);
-  ipcp_sources_pool = create_alloc_pool ("IPA-CP value sources",
-                                        sizeof (ipcp_value_source<tree>), 64);
-  ipcp_agg_lattice_pool = create_alloc_pool ("IPA_CP aggregate lattices",
-                                            sizeof (struct ipcp_agg_lattice),
-                                            32);
   if (dump_file)
     {
       fprintf (dump_file, "\nIPA structures before propagation:\n");
@@ -4416,6 +4621,7 @@ ipcp_driver (void)
   /* Free all IPCP structures.  */
   free_toporder_info (&topo);
   next_edge_clone.release ();
+  prev_edge_clone.release ();
   symtab->remove_edge_removal_hook (edge_removal_hook_holder);
   symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
   ipa_free_all_structures_after_ipa_cp ();
@@ -4438,11 +4644,7 @@ ipcp_generate_summary (void)
   ipa_register_cgraph_hooks ();
 
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
-      {
-       node->local.versionable
-         = tree_versionable_function_p (node->decl);
-       ipa_analyze_node (node);
-      }
+    ipa_analyze_node (node);
 }
 
 /* Write ipcp summary for nodes in SET.  */