xref: /dragonfly/contrib/gcc-8.0/gcc/ipa-cp.c (revision e215fc28)
138fd1498Szrj /* Interprocedural constant propagation
238fd1498Szrj    Copyright (C) 2005-2018 Free Software Foundation, Inc.
338fd1498Szrj 
438fd1498Szrj    Contributed by Razya Ladelsky <RAZYA@il.ibm.com> and Martin Jambor
538fd1498Szrj    <mjambor@suse.cz>
638fd1498Szrj 
738fd1498Szrj This file is part of GCC.
838fd1498Szrj 
938fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
1038fd1498Szrj the terms of the GNU General Public License as published by the Free
1138fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1238fd1498Szrj version.
1338fd1498Szrj 
1438fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1538fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1638fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1738fd1498Szrj for more details.
1838fd1498Szrj 
1938fd1498Szrj You should have received a copy of the GNU General Public License
2038fd1498Szrj along with GCC; see the file COPYING3.  If not see
2138fd1498Szrj <http://www.gnu.org/licenses/>.  */
2238fd1498Szrj 
2338fd1498Szrj /* Interprocedural constant propagation (IPA-CP).
2438fd1498Szrj 
2538fd1498Szrj    The goal of this transformation is to
2638fd1498Szrj 
2738fd1498Szrj    1) discover functions which are always invoked with some arguments with the
2838fd1498Szrj       same known constant values and modify the functions so that the
2938fd1498Szrj       subsequent optimizations can take advantage of the knowledge, and
3038fd1498Szrj 
3138fd1498Szrj    2) partial specialization - create specialized versions of functions
3238fd1498Szrj       transformed in this way if some parameters are known constants only in
3338fd1498Szrj       certain contexts but the estimated tradeoff between speedup and cost size
3438fd1498Szrj       is deemed good.
3538fd1498Szrj 
3638fd1498Szrj    The algorithm also propagates types and attempts to perform type based
3738fd1498Szrj    devirtualization.  Types are propagated much like constants.
3838fd1498Szrj 
3938fd1498Szrj    The algorithm basically consists of three stages.  In the first, functions
4038fd1498Szrj    are analyzed one at a time and jump functions are constructed for all known
4138fd1498Szrj    call-sites.  In the second phase, the pass propagates information from the
4238fd1498Szrj    jump functions across the call to reveal what values are available at what
4338fd1498Szrj    call sites, performs estimations of effects of known values on functions and
4438fd1498Szrj    their callees, and finally decides what specialized extra versions should be
4538fd1498Szrj    created.  In the third, the special versions materialize and appropriate
4638fd1498Szrj    calls are redirected.
4738fd1498Szrj 
4838fd1498Szrj    The algorithm used is to a certain extent based on "Interprocedural Constant
4938fd1498Szrj    Propagation", by David Callahan, Keith D Cooper, Ken Kennedy, Linda Torczon,
5038fd1498Szrj    Comp86, pg 152-161 and "A Methodology for Procedure Cloning" by Keith D
5138fd1498Szrj    Cooper, Mary W. Hall, and Ken Kennedy.
5238fd1498Szrj 
5338fd1498Szrj 
5438fd1498Szrj    First stage - intraprocedural analysis
5538fd1498Szrj    =======================================
5638fd1498Szrj 
5738fd1498Szrj    This phase computes jump_function and modification flags.
5838fd1498Szrj 
5938fd1498Szrj    A jump function for a call-site represents the values passed as an actual
6038fd1498Szrj    arguments of a given call-site. In principle, there are three types of
6138fd1498Szrj    values:
6238fd1498Szrj 
6338fd1498Szrj    Pass through - the caller's formal parameter is passed as an actual
6438fd1498Szrj 		  argument, plus an operation on it can be performed.
6538fd1498Szrj    Constant - a constant is passed as an actual argument.
6638fd1498Szrj    Unknown - neither of the above.
6738fd1498Szrj 
6838fd1498Szrj    All jump function types are described in detail in ipa-prop.h, together with
6938fd1498Szrj    the data structures that represent them and methods of accessing them.
7038fd1498Szrj 
7138fd1498Szrj    ipcp_generate_summary() is the main function of the first stage.
7238fd1498Szrj 
7338fd1498Szrj    Second stage - interprocedural analysis
7438fd1498Szrj    ========================================
7538fd1498Szrj 
7638fd1498Szrj    This stage is itself divided into two phases.  In the first, we propagate
7738fd1498Szrj    known values over the call graph, in the second, we make cloning decisions.
7838fd1498Szrj    It uses a different algorithm than the original Callahan's paper.
7938fd1498Szrj 
8038fd1498Szrj    First, we traverse the functions topologically from callers to callees and,
8138fd1498Szrj    for each strongly connected component (SCC), we propagate constants
8238fd1498Szrj    according to previously computed jump functions.  We also record what known
8338fd1498Szrj    values depend on other known values and estimate local effects.  Finally, we
8438fd1498Szrj    propagate cumulative information about these effects from dependent values
8538fd1498Szrj    to those on which they depend.
8638fd1498Szrj 
8738fd1498Szrj    Second, we again traverse the call graph in the same topological order and
8838fd1498Szrj    make clones for functions which we know are called with the same values in
8938fd1498Szrj    all contexts and decide about extra specialized clones of functions just for
9038fd1498Szrj    some contexts - these decisions are based on both local estimates and
9138fd1498Szrj    cumulative estimates propagated from callees.
9238fd1498Szrj 
9338fd1498Szrj    ipcp_propagate_stage() and ipcp_decision_stage() together constitute the
9438fd1498Szrj    third stage.
9538fd1498Szrj 
9638fd1498Szrj    Third phase - materialization of clones, call statement updates.
9738fd1498Szrj    ============================================
9838fd1498Szrj 
9938fd1498Szrj    This stage is currently performed by call graph code (mainly in cgraphunit.c
10038fd1498Szrj    and tree-inline.c) according to instructions inserted to the call graph by
10138fd1498Szrj    the second stage.  */
10238fd1498Szrj 
10338fd1498Szrj #include "config.h"
10438fd1498Szrj #include "system.h"
10538fd1498Szrj #include "coretypes.h"
10638fd1498Szrj #include "backend.h"
10738fd1498Szrj #include "tree.h"
10838fd1498Szrj #include "gimple-expr.h"
10938fd1498Szrj #include "predict.h"
11038fd1498Szrj #include "alloc-pool.h"
11138fd1498Szrj #include "tree-pass.h"
11238fd1498Szrj #include "cgraph.h"
11338fd1498Szrj #include "diagnostic.h"
11438fd1498Szrj #include "fold-const.h"
11538fd1498Szrj #include "gimple-fold.h"
11638fd1498Szrj #include "symbol-summary.h"
11738fd1498Szrj #include "tree-vrp.h"
11838fd1498Szrj #include "ipa-prop.h"
11938fd1498Szrj #include "tree-pretty-print.h"
12038fd1498Szrj #include "tree-inline.h"
12138fd1498Szrj #include "params.h"
12238fd1498Szrj #include "ipa-fnsummary.h"
12338fd1498Szrj #include "ipa-utils.h"
12438fd1498Szrj #include "tree-ssa-ccp.h"
12538fd1498Szrj #include "stringpool.h"
12638fd1498Szrj #include "attribs.h"
12738fd1498Szrj 
12838fd1498Szrj template <typename valtype> class ipcp_value;
12938fd1498Szrj 
13038fd1498Szrj /* Describes a particular source for an IPA-CP value.  */
13138fd1498Szrj 
13238fd1498Szrj template <typename valtype>
13338fd1498Szrj class ipcp_value_source
13438fd1498Szrj {
13538fd1498Szrj public:
13638fd1498Szrj   /* Aggregate offset of the source, negative if the source is scalar value of
13738fd1498Szrj      the argument itself.  */
13838fd1498Szrj   HOST_WIDE_INT offset;
13938fd1498Szrj   /* The incoming edge that brought the value.  */
14038fd1498Szrj   cgraph_edge *cs;
14138fd1498Szrj   /* If the jump function that resulted into his value was a pass-through or an
14238fd1498Szrj      ancestor, this is the ipcp_value of the caller from which the described
14338fd1498Szrj      value has been derived.  Otherwise it is NULL.  */
14438fd1498Szrj   ipcp_value<valtype> *val;
14538fd1498Szrj   /* Next pointer in a linked list of sources of a value.  */
14638fd1498Szrj   ipcp_value_source *next;
14738fd1498Szrj   /* If the jump function that resulted into his value was a pass-through or an
14838fd1498Szrj      ancestor, this is the index of the parameter of the caller the jump
14938fd1498Szrj      function references.  */
15038fd1498Szrj   int index;
15138fd1498Szrj };
15238fd1498Szrj 
15338fd1498Szrj /* Common ancestor for all ipcp_value instantiations.  */
15438fd1498Szrj 
15538fd1498Szrj class ipcp_value_base
15638fd1498Szrj {
15738fd1498Szrj public:
15838fd1498Szrj   /* Time benefit and size cost that specializing the function for this value
15938fd1498Szrj      would bring about in this function alone.  */
16038fd1498Szrj   int local_time_benefit, local_size_cost;
16138fd1498Szrj   /* Time benefit and size cost that specializing the function for this value
16238fd1498Szrj      can bring about in it's callees (transitively).  */
16338fd1498Szrj   int prop_time_benefit, prop_size_cost;
16438fd1498Szrj 
ipcp_value_base()16538fd1498Szrj   ipcp_value_base ()
16638fd1498Szrj     : local_time_benefit (0), local_size_cost (0),
16738fd1498Szrj       prop_time_benefit (0), prop_size_cost (0) {}
16838fd1498Szrj };
16938fd1498Szrj 
17038fd1498Szrj /* Describes one particular value stored in struct ipcp_lattice.  */
17138fd1498Szrj 
17238fd1498Szrj template <typename valtype>
17338fd1498Szrj class ipcp_value : public ipcp_value_base
17438fd1498Szrj {
17538fd1498Szrj public:
17638fd1498Szrj   /* The actual value for the given parameter.  */
17738fd1498Szrj   valtype value;
17838fd1498Szrj   /* The list of sources from which this value originates.  */
17938fd1498Szrj   ipcp_value_source <valtype> *sources;
18038fd1498Szrj   /* Next pointers in a linked list of all values in a lattice.  */
18138fd1498Szrj   ipcp_value *next;
18238fd1498Szrj   /* Next pointers in a linked list of values in a strongly connected component
18338fd1498Szrj      of values. */
18438fd1498Szrj   ipcp_value *scc_next;
18538fd1498Szrj   /* Next pointers in a linked list of SCCs of values sorted topologically
18638fd1498Szrj      according their sources.  */
18738fd1498Szrj   ipcp_value  *topo_next;
18838fd1498Szrj   /* A specialized node created for this value, NULL if none has been (so far)
18938fd1498Szrj      created.  */
19038fd1498Szrj   cgraph_node *spec_node;
19138fd1498Szrj   /* Depth first search number and low link for topological sorting of
19238fd1498Szrj      values.  */
19338fd1498Szrj   int dfs, low_link;
19438fd1498Szrj   /* True if this valye is currently on the topo-sort stack.  */
19538fd1498Szrj   bool on_stack;
19638fd1498Szrj 
ipcp_value()19738fd1498Szrj   ipcp_value()
19838fd1498Szrj     : sources (0), next (0), scc_next (0), topo_next (0),
19938fd1498Szrj       spec_node (0), dfs (0), low_link (0), on_stack (false) {}
20038fd1498Szrj 
20138fd1498Szrj   void add_source (cgraph_edge *cs, ipcp_value *src_val, int src_idx,
20238fd1498Szrj 		   HOST_WIDE_INT offset);
20338fd1498Szrj };
20438fd1498Szrj 
20538fd1498Szrj /* Lattice describing potential values of a formal parameter of a function, or
20638fd1498Szrj    a part of an aggregate.  TOP is represented by a lattice with zero values
20738fd1498Szrj    and with contains_variable and bottom flags cleared.  BOTTOM is represented
20838fd1498Szrj    by a lattice with the bottom flag set.  In that case, values and
20938fd1498Szrj    contains_variable flag should be disregarded.  */
21038fd1498Szrj 
21138fd1498Szrj template <typename valtype>
21238fd1498Szrj class ipcp_lattice
21338fd1498Szrj {
21438fd1498Szrj public:
21538fd1498Szrj   /* The list of known values and types in this lattice.  Note that values are
21638fd1498Szrj      not deallocated if a lattice is set to bottom because there may be value
21738fd1498Szrj      sources referencing them.  */
21838fd1498Szrj   ipcp_value<valtype> *values;
21938fd1498Szrj   /* Number of known values and types in this lattice.  */
22038fd1498Szrj   int values_count;
22138fd1498Szrj   /* The lattice contains a variable component (in addition to values).  */
22238fd1498Szrj   bool contains_variable;
22338fd1498Szrj   /* The value of the lattice is bottom (i.e. variable and unusable for any
22438fd1498Szrj      propagation).  */
22538fd1498Szrj   bool bottom;
22638fd1498Szrj 
22738fd1498Szrj   inline bool is_single_const ();
22838fd1498Szrj   inline bool set_to_bottom ();
22938fd1498Szrj   inline bool set_contains_variable ();
23038fd1498Szrj   bool add_value (valtype newval, cgraph_edge *cs,
23138fd1498Szrj 		  ipcp_value<valtype> *src_val = NULL,
23238fd1498Szrj 		  int src_idx = 0, HOST_WIDE_INT offset = -1);
23338fd1498Szrj   void print (FILE * f, bool dump_sources, bool dump_benefits);
23438fd1498Szrj };
23538fd1498Szrj 
23638fd1498Szrj /* Lattice of tree values with an offset to describe a part of an
23738fd1498Szrj    aggregate.  */
23838fd1498Szrj 
23938fd1498Szrj class ipcp_agg_lattice : public ipcp_lattice<tree>
24038fd1498Szrj {
24138fd1498Szrj public:
24238fd1498Szrj   /* Offset that is being described by this lattice. */
24338fd1498Szrj   HOST_WIDE_INT offset;
24438fd1498Szrj   /* Size so that we don't have to re-compute it every time we traverse the
24538fd1498Szrj      list.  Must correspond to TYPE_SIZE of all lat values.  */
24638fd1498Szrj   HOST_WIDE_INT size;
24738fd1498Szrj   /* Next element of the linked list.  */
24838fd1498Szrj   struct ipcp_agg_lattice *next;
24938fd1498Szrj };
25038fd1498Szrj 
25138fd1498Szrj /* Lattice of known bits, only capable of holding one value.
25238fd1498Szrj    Bitwise constant propagation propagates which bits of a
25338fd1498Szrj    value are constant.
25438fd1498Szrj    For eg:
25538fd1498Szrj    int f(int x)
25638fd1498Szrj    {
25738fd1498Szrj      return some_op (x);
25838fd1498Szrj    }
25938fd1498Szrj 
26038fd1498Szrj    int f1(int y)
26138fd1498Szrj    {
26238fd1498Szrj      if (cond)
26338fd1498Szrj       return f (y & 0xff);
26438fd1498Szrj      else
26538fd1498Szrj       return f (y & 0xf);
26638fd1498Szrj    }
26738fd1498Szrj 
26838fd1498Szrj    In the above case, the param 'x' will always have all
26938fd1498Szrj    the bits (except the bits in lsb) set to 0.
27038fd1498Szrj    Hence the mask of 'x' would be 0xff. The mask
27138fd1498Szrj    reflects that the bits in lsb are unknown.
27238fd1498Szrj    The actual propagated value is given by m_value & ~m_mask.  */
27338fd1498Szrj 
27438fd1498Szrj class ipcp_bits_lattice
27538fd1498Szrj {
27638fd1498Szrj public:
bottom_p()27738fd1498Szrj   bool bottom_p () { return m_lattice_val == IPA_BITS_VARYING; }
top_p()27838fd1498Szrj   bool top_p () { return m_lattice_val == IPA_BITS_UNDEFINED; }
constant_p()27938fd1498Szrj   bool constant_p () { return m_lattice_val == IPA_BITS_CONSTANT; }
28038fd1498Szrj   bool set_to_bottom ();
28138fd1498Szrj   bool set_to_constant (widest_int, widest_int);
28238fd1498Szrj 
get_value()28338fd1498Szrj   widest_int get_value () { return m_value; }
get_mask()28438fd1498Szrj   widest_int get_mask () { return m_mask; }
28538fd1498Szrj 
28638fd1498Szrj   bool meet_with (ipcp_bits_lattice& other, unsigned, signop,
28738fd1498Szrj 		  enum tree_code, tree);
28838fd1498Szrj 
28938fd1498Szrj   bool meet_with (widest_int, widest_int, unsigned);
29038fd1498Szrj 
29138fd1498Szrj   void print (FILE *);
29238fd1498Szrj 
29338fd1498Szrj private:
29438fd1498Szrj   enum { IPA_BITS_UNDEFINED, IPA_BITS_CONSTANT, IPA_BITS_VARYING } m_lattice_val;
29538fd1498Szrj 
29638fd1498Szrj   /* Similar to ccp_lattice_t, mask represents which bits of value are constant.
29738fd1498Szrj      If a bit in mask is set to 0, then the corresponding bit in
29838fd1498Szrj      value is known to be constant.  */
29938fd1498Szrj   widest_int m_value, m_mask;
30038fd1498Szrj 
30138fd1498Szrj   bool meet_with_1 (widest_int, widest_int, unsigned);
30238fd1498Szrj   void get_value_and_mask (tree, widest_int *, widest_int *);
30338fd1498Szrj };
30438fd1498Szrj 
30538fd1498Szrj /* Lattice of value ranges.  */
30638fd1498Szrj 
30738fd1498Szrj class ipcp_vr_lattice
30838fd1498Szrj {
30938fd1498Szrj public:
31038fd1498Szrj   value_range m_vr;
31138fd1498Szrj 
31238fd1498Szrj   inline bool bottom_p () const;
31338fd1498Szrj   inline bool top_p () const;
31438fd1498Szrj   inline bool set_to_bottom ();
31538fd1498Szrj   bool meet_with (const value_range *p_vr);
31638fd1498Szrj   bool meet_with (const ipcp_vr_lattice &other);
init()31738fd1498Szrj   void init () { m_vr.type = VR_UNDEFINED; }
31838fd1498Szrj   void print (FILE * f);
31938fd1498Szrj 
32038fd1498Szrj private:
32138fd1498Szrj   bool meet_with_1 (const value_range *other_vr);
32238fd1498Szrj };
32338fd1498Szrj 
32438fd1498Szrj /* Structure containing lattices for a parameter itself and for pieces of
32538fd1498Szrj    aggregates that are passed in the parameter or by a reference in a parameter
32638fd1498Szrj    plus some other useful flags.  */
32738fd1498Szrj 
32838fd1498Szrj class ipcp_param_lattices
32938fd1498Szrj {
33038fd1498Szrj public:
33138fd1498Szrj   /* Lattice describing the value of the parameter itself.  */
33238fd1498Szrj   ipcp_lattice<tree> itself;
33338fd1498Szrj   /* Lattice describing the polymorphic contexts of a parameter.  */
33438fd1498Szrj   ipcp_lattice<ipa_polymorphic_call_context> ctxlat;
33538fd1498Szrj   /* Lattices describing aggregate parts.  */
33638fd1498Szrj   ipcp_agg_lattice *aggs;
33738fd1498Szrj   /* Lattice describing known bits.  */
33838fd1498Szrj   ipcp_bits_lattice bits_lattice;
33938fd1498Szrj   /* Lattice describing value range.  */
34038fd1498Szrj   ipcp_vr_lattice m_value_range;
34138fd1498Szrj   /* Number of aggregate lattices */
34238fd1498Szrj   int aggs_count;
34338fd1498Szrj   /* True if aggregate data were passed by reference (as opposed to by
34438fd1498Szrj      value).  */
34538fd1498Szrj   bool aggs_by_ref;
34638fd1498Szrj   /* All aggregate lattices contain a variable component (in addition to
34738fd1498Szrj      values).  */
34838fd1498Szrj   bool aggs_contain_variable;
34938fd1498Szrj   /* The value of all aggregate lattices is bottom (i.e. variable and unusable
35038fd1498Szrj      for any propagation).  */
35138fd1498Szrj   bool aggs_bottom;
35238fd1498Szrj 
35338fd1498Szrj   /* There is a virtual call based on this parameter.  */
35438fd1498Szrj   bool virt_call;
35538fd1498Szrj };
35638fd1498Szrj 
35738fd1498Szrj /* Allocation pools for values and their sources in ipa-cp.  */
35838fd1498Szrj 
35938fd1498Szrj object_allocator<ipcp_value<tree> > ipcp_cst_values_pool
36038fd1498Szrj   ("IPA-CP constant values");
36138fd1498Szrj 
36238fd1498Szrj object_allocator<ipcp_value<ipa_polymorphic_call_context> >
36338fd1498Szrj   ipcp_poly_ctx_values_pool ("IPA-CP polymorphic contexts");
36438fd1498Szrj 
36538fd1498Szrj object_allocator<ipcp_value_source<tree> > ipcp_sources_pool
36638fd1498Szrj   ("IPA-CP value sources");
36738fd1498Szrj 
36838fd1498Szrj object_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool
36938fd1498Szrj   ("IPA_CP aggregate lattices");
37038fd1498Szrj 
37138fd1498Szrj /* Maximal count found in program.  */
37238fd1498Szrj 
37338fd1498Szrj static profile_count max_count;
37438fd1498Szrj 
37538fd1498Szrj /* Original overall size of the program.  */
37638fd1498Szrj 
37738fd1498Szrj static long overall_size, max_new_size;
37838fd1498Szrj 
37938fd1498Szrj /* Return the param lattices structure corresponding to the Ith formal
38038fd1498Szrj    parameter of the function described by INFO.  */
38138fd1498Szrj static inline struct ipcp_param_lattices *
ipa_get_parm_lattices(struct ipa_node_params * info,int i)38238fd1498Szrj ipa_get_parm_lattices (struct ipa_node_params *info, int i)
38338fd1498Szrj {
38438fd1498Szrj   gcc_assert (i >= 0 && i < ipa_get_param_count (info));
38538fd1498Szrj   gcc_checking_assert (!info->ipcp_orig_node);
38638fd1498Szrj   gcc_checking_assert (info->lattices);
38738fd1498Szrj   return &(info->lattices[i]);
38838fd1498Szrj }
38938fd1498Szrj 
39038fd1498Szrj /* Return the lattice corresponding to the scalar value of the Ith formal
39138fd1498Szrj    parameter of the function described by INFO.  */
39238fd1498Szrj static inline ipcp_lattice<tree> *
ipa_get_scalar_lat(struct ipa_node_params * info,int i)39338fd1498Szrj ipa_get_scalar_lat (struct ipa_node_params *info, int i)
39438fd1498Szrj {
39538fd1498Szrj   struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
39638fd1498Szrj   return &plats->itself;
39738fd1498Szrj }
39838fd1498Szrj 
39938fd1498Szrj /* Return the lattice corresponding to the scalar value of the Ith formal
40038fd1498Szrj    parameter of the function described by INFO.  */
40138fd1498Szrj static inline ipcp_lattice<ipa_polymorphic_call_context> *
ipa_get_poly_ctx_lat(struct ipa_node_params * info,int i)40238fd1498Szrj ipa_get_poly_ctx_lat (struct ipa_node_params *info, int i)
40338fd1498Szrj {
40438fd1498Szrj   struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
40538fd1498Szrj   return &plats->ctxlat;
40638fd1498Szrj }
40738fd1498Szrj 
40838fd1498Szrj /* Return the lattice corresponding to the value range of the Ith formal
40938fd1498Szrj    parameter of the function described by INFO.  */
41038fd1498Szrj 
41138fd1498Szrj static inline ipcp_vr_lattice *
ipa_get_vr_lat(struct ipa_node_params * info,int i)41238fd1498Szrj ipa_get_vr_lat (struct ipa_node_params *info, int i)
41338fd1498Szrj {
41438fd1498Szrj   struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
41538fd1498Szrj   return &plats->m_value_range;
41638fd1498Szrj }
41738fd1498Szrj 
41838fd1498Szrj /* Return whether LAT is a lattice with a single constant and without an
41938fd1498Szrj    undefined value.  */
42038fd1498Szrj 
42138fd1498Szrj template <typename valtype>
42238fd1498Szrj inline bool
is_single_const()42338fd1498Szrj ipcp_lattice<valtype>::is_single_const ()
42438fd1498Szrj {
42538fd1498Szrj   if (bottom || contains_variable || values_count != 1)
42638fd1498Szrj     return false;
42738fd1498Szrj   else
42838fd1498Szrj     return true;
42938fd1498Szrj }
43038fd1498Szrj 
43138fd1498Szrj /* Print V which is extracted from a value in a lattice to F.  */
43238fd1498Szrj 
43338fd1498Szrj static void
print_ipcp_constant_value(FILE * f,tree v)43438fd1498Szrj print_ipcp_constant_value (FILE * f, tree v)
43538fd1498Szrj {
43638fd1498Szrj   if (TREE_CODE (v) == ADDR_EXPR
43738fd1498Szrj       && TREE_CODE (TREE_OPERAND (v, 0)) == CONST_DECL)
43838fd1498Szrj     {
43938fd1498Szrj       fprintf (f, "& ");
44038fd1498Szrj       print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (v, 0)));
44138fd1498Szrj     }
44238fd1498Szrj   else
44338fd1498Szrj     print_generic_expr (f, v);
44438fd1498Szrj }
44538fd1498Szrj 
44638fd1498Szrj /* Print V which is extracted from a value in a lattice to F.  */
44738fd1498Szrj 
44838fd1498Szrj static void
print_ipcp_constant_value(FILE * f,ipa_polymorphic_call_context v)44938fd1498Szrj print_ipcp_constant_value (FILE * f, ipa_polymorphic_call_context v)
45038fd1498Szrj {
45138fd1498Szrj   v.dump(f, false);
45238fd1498Szrj }
45338fd1498Szrj 
45438fd1498Szrj /* Print a lattice LAT to F.  */
45538fd1498Szrj 
45638fd1498Szrj template <typename valtype>
45738fd1498Szrj void
print(FILE * f,bool dump_sources,bool dump_benefits)45838fd1498Szrj ipcp_lattice<valtype>::print (FILE * f, bool dump_sources, bool dump_benefits)
45938fd1498Szrj {
46038fd1498Szrj   ipcp_value<valtype> *val;
46138fd1498Szrj   bool prev = false;
46238fd1498Szrj 
46338fd1498Szrj   if (bottom)
46438fd1498Szrj     {
46538fd1498Szrj       fprintf (f, "BOTTOM\n");
46638fd1498Szrj       return;
46738fd1498Szrj     }
46838fd1498Szrj 
46938fd1498Szrj   if (!values_count && !contains_variable)
47038fd1498Szrj     {
47138fd1498Szrj       fprintf (f, "TOP\n");
47238fd1498Szrj       return;
47338fd1498Szrj     }
47438fd1498Szrj 
47538fd1498Szrj   if (contains_variable)
47638fd1498Szrj     {
47738fd1498Szrj       fprintf (f, "VARIABLE");
47838fd1498Szrj       prev = true;
47938fd1498Szrj       if (dump_benefits)
48038fd1498Szrj 	fprintf (f, "\n");
48138fd1498Szrj     }
48238fd1498Szrj 
48338fd1498Szrj   for (val = values; val; val = val->next)
48438fd1498Szrj     {
48538fd1498Szrj       if (dump_benefits && prev)
48638fd1498Szrj 	fprintf (f, "               ");
48738fd1498Szrj       else if (!dump_benefits && prev)
48838fd1498Szrj 	fprintf (f, ", ");
48938fd1498Szrj       else
49038fd1498Szrj 	prev = true;
49138fd1498Szrj 
49238fd1498Szrj       print_ipcp_constant_value (f, val->value);
49338fd1498Szrj 
49438fd1498Szrj       if (dump_sources)
49538fd1498Szrj 	{
49638fd1498Szrj 	  ipcp_value_source<valtype> *s;
49738fd1498Szrj 
49838fd1498Szrj 	  fprintf (f, " [from:");
49938fd1498Szrj 	  for (s = val->sources; s; s = s->next)
50038fd1498Szrj 	    fprintf (f, " %i(%f)", s->cs->caller->order,
50138fd1498Szrj 		     s->cs->sreal_frequency ().to_double ());
50238fd1498Szrj 	  fprintf (f, "]");
50338fd1498Szrj 	}
50438fd1498Szrj 
50538fd1498Szrj       if (dump_benefits)
50638fd1498Szrj 	fprintf (f, " [loc_time: %i, loc_size: %i, "
50738fd1498Szrj 		 "prop_time: %i, prop_size: %i]\n",
50838fd1498Szrj 		 val->local_time_benefit, val->local_size_cost,
50938fd1498Szrj 		 val->prop_time_benefit, val->prop_size_cost);
51038fd1498Szrj     }
51138fd1498Szrj   if (!dump_benefits)
51238fd1498Szrj     fprintf (f, "\n");
51338fd1498Szrj }
51438fd1498Szrj 
51538fd1498Szrj void
print(FILE * f)51638fd1498Szrj ipcp_bits_lattice::print (FILE *f)
51738fd1498Szrj {
51838fd1498Szrj   if (top_p ())
51938fd1498Szrj     fprintf (f, "         Bits unknown (TOP)\n");
52038fd1498Szrj   else if (bottom_p ())
52138fd1498Szrj     fprintf (f, "         Bits unusable (BOTTOM)\n");
52238fd1498Szrj   else
52338fd1498Szrj     {
52438fd1498Szrj       fprintf (f, "         Bits: value = "); print_hex (get_value (), f);
52538fd1498Szrj       fprintf (f, ", mask = "); print_hex (get_mask (), f);
52638fd1498Szrj       fprintf (f, "\n");
52738fd1498Szrj     }
52838fd1498Szrj }
52938fd1498Szrj 
53038fd1498Szrj /* Print value range lattice to F.  */
53138fd1498Szrj 
53238fd1498Szrj void
print(FILE * f)53338fd1498Szrj ipcp_vr_lattice::print (FILE * f)
53438fd1498Szrj {
53538fd1498Szrj   dump_value_range (f, &m_vr);
53638fd1498Szrj }
53738fd1498Szrj 
53838fd1498Szrj /* Print all ipcp_lattices of all functions to F.  */
53938fd1498Szrj 
54038fd1498Szrj static void
print_all_lattices(FILE * f,bool dump_sources,bool dump_benefits)54138fd1498Szrj print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits)
54238fd1498Szrj {
54338fd1498Szrj   struct cgraph_node *node;
54438fd1498Szrj   int i, count;
54538fd1498Szrj 
54638fd1498Szrj   fprintf (f, "\nLattices:\n");
54738fd1498Szrj   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
54838fd1498Szrj     {
54938fd1498Szrj       struct ipa_node_params *info;
55038fd1498Szrj 
55138fd1498Szrj       info = IPA_NODE_REF (node);
55238fd1498Szrj       fprintf (f, "  Node: %s:\n", node->dump_name ());
55338fd1498Szrj       count = ipa_get_param_count (info);
55438fd1498Szrj       for (i = 0; i < count; i++)
55538fd1498Szrj 	{
55638fd1498Szrj 	  struct ipcp_agg_lattice *aglat;
55738fd1498Szrj 	  struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
55838fd1498Szrj 	  fprintf (f, "    param [%d]: ", i);
55938fd1498Szrj 	  plats->itself.print (f, dump_sources, dump_benefits);
56038fd1498Szrj 	  fprintf (f, "         ctxs: ");
56138fd1498Szrj 	  plats->ctxlat.print (f, dump_sources, dump_benefits);
56238fd1498Szrj 	  plats->bits_lattice.print (f);
56338fd1498Szrj 	  fprintf (f, "         ");
56438fd1498Szrj 	  plats->m_value_range.print (f);
56538fd1498Szrj 	  fprintf (f, "\n");
56638fd1498Szrj 	  if (plats->virt_call)
56738fd1498Szrj 	    fprintf (f, "        virt_call flag set\n");
56838fd1498Szrj 
56938fd1498Szrj 	  if (plats->aggs_bottom)
57038fd1498Szrj 	    {
57138fd1498Szrj 	      fprintf (f, "        AGGS BOTTOM\n");
57238fd1498Szrj 	      continue;
57338fd1498Szrj 	    }
57438fd1498Szrj 	  if (plats->aggs_contain_variable)
57538fd1498Szrj 	    fprintf (f, "        AGGS VARIABLE\n");
57638fd1498Szrj 	  for (aglat = plats->aggs; aglat; aglat = aglat->next)
57738fd1498Szrj 	    {
57838fd1498Szrj 	      fprintf (f, "        %soffset " HOST_WIDE_INT_PRINT_DEC ": ",
57938fd1498Szrj 		       plats->aggs_by_ref ? "ref " : "", aglat->offset);
58038fd1498Szrj 	      aglat->print (f, dump_sources, dump_benefits);
58138fd1498Szrj 	    }
58238fd1498Szrj 	}
58338fd1498Szrj     }
58438fd1498Szrj }
58538fd1498Szrj 
58638fd1498Szrj /* Determine whether it is at all technically possible to create clones of NODE
58738fd1498Szrj    and store this information in the ipa_node_params structure associated
58838fd1498Szrj    with NODE.  */
58938fd1498Szrj 
59038fd1498Szrj static void
determine_versionability(struct cgraph_node * node,struct ipa_node_params * info)59138fd1498Szrj determine_versionability (struct cgraph_node *node,
59238fd1498Szrj 			  struct ipa_node_params *info)
59338fd1498Szrj {
59438fd1498Szrj   const char *reason = NULL;
59538fd1498Szrj 
59638fd1498Szrj   /* There are a number of generic reasons functions cannot be versioned.  We
59738fd1498Szrj      also cannot remove parameters if there are type attributes such as fnspec
59838fd1498Szrj      present.  */
59938fd1498Szrj   if (node->alias || node->thunk.thunk_p)
60038fd1498Szrj     reason = "alias or thunk";
60138fd1498Szrj   else if (!node->local.versionable)
60238fd1498Szrj     reason = "not a tree_versionable_function";
60338fd1498Szrj   else if (node->get_availability () <= AVAIL_INTERPOSABLE)
60438fd1498Szrj     reason = "insufficient body availability";
60538fd1498Szrj   else if (!opt_for_fn (node->decl, optimize)
60638fd1498Szrj 	   || !opt_for_fn (node->decl, flag_ipa_cp))
60738fd1498Szrj     reason = "non-optimized function";
60838fd1498Szrj   else if (lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (node->decl)))
60938fd1498Szrj     {
61038fd1498Szrj       /* Ideally we should clone the SIMD clones themselves and create
61138fd1498Szrj 	 vector copies of them, so IPA-cp and SIMD clones can happily
61238fd1498Szrj 	 coexist, but that may not be worth the effort.  */
61338fd1498Szrj       reason = "function has SIMD clones";
61438fd1498Szrj     }
61538fd1498Szrj   else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (node->decl)))
61638fd1498Szrj     {
61738fd1498Szrj       /* Ideally we should clone the target clones themselves and create
61838fd1498Szrj 	 copies of them, so IPA-cp and target clones can happily
61938fd1498Szrj 	 coexist, but that may not be worth the effort.  */
62038fd1498Szrj       reason = "function target_clones attribute";
62138fd1498Szrj     }
62238fd1498Szrj   /* Don't clone decls local to a comdat group; it breaks and for C++
62338fd1498Szrj      decloned constructors, inlining is always better anyway.  */
62438fd1498Szrj   else if (node->comdat_local_p ())
62538fd1498Szrj     reason = "comdat-local function";
62638fd1498Szrj   else if (node->calls_comdat_local)
62738fd1498Szrj     {
62838fd1498Szrj       /* TODO: call is versionable if we make sure that all
62938fd1498Szrj 	 callers are inside of a comdat group.  */
63038fd1498Szrj       reason = "calls comdat-local function";
63138fd1498Szrj     }
63238fd1498Szrj 
63338fd1498Szrj   /* Functions calling BUILT_IN_VA_ARG_PACK and BUILT_IN_VA_ARG_PACK_LEN
63438fd1498Szrj      work only when inlined.  Cloning them may still lead to better code
63538fd1498Szrj      because ipa-cp will not give up on cloning further.  If the function is
63638fd1498Szrj      external this however leads to wrong code because we may end up producing
63738fd1498Szrj      offline copy of the function.  */
63838fd1498Szrj   if (DECL_EXTERNAL (node->decl))
63938fd1498Szrj     for (cgraph_edge *edge = node->callees; !reason && edge;
64038fd1498Szrj 	 edge = edge->next_callee)
64138fd1498Szrj       if (DECL_BUILT_IN (edge->callee->decl)
64238fd1498Szrj 	  && DECL_BUILT_IN_CLASS (edge->callee->decl) == BUILT_IN_NORMAL)
64338fd1498Szrj         {
64438fd1498Szrj 	  if (DECL_FUNCTION_CODE (edge->callee->decl) == BUILT_IN_VA_ARG_PACK)
64538fd1498Szrj 	    reason = "external function which calls va_arg_pack";
64638fd1498Szrj 	  if (DECL_FUNCTION_CODE (edge->callee->decl)
64738fd1498Szrj 	      == BUILT_IN_VA_ARG_PACK_LEN)
64838fd1498Szrj 	    reason = "external function which calls va_arg_pack_len";
64938fd1498Szrj         }
65038fd1498Szrj 
65138fd1498Szrj   if (reason && dump_file && !node->alias && !node->thunk.thunk_p)
65238fd1498Szrj     fprintf (dump_file, "Function %s is not versionable, reason: %s.\n",
65338fd1498Szrj 	     node->dump_name (), reason);
65438fd1498Szrj 
65538fd1498Szrj   info->versionable = (reason == NULL);
65638fd1498Szrj }
65738fd1498Szrj 
65838fd1498Szrj /* Return true if it is at all technically possible to create clones of a
65938fd1498Szrj    NODE.  */
66038fd1498Szrj 
66138fd1498Szrj static bool
ipcp_versionable_function_p(struct cgraph_node * node)66238fd1498Szrj ipcp_versionable_function_p (struct cgraph_node *node)
66338fd1498Szrj {
66438fd1498Szrj   return IPA_NODE_REF (node)->versionable;
66538fd1498Szrj }
66638fd1498Szrj 
66738fd1498Szrj /* Structure holding accumulated information about callers of a node.  */
66838fd1498Szrj 
66938fd1498Szrj struct caller_statistics
67038fd1498Szrj {
67138fd1498Szrj   profile_count count_sum;
67238fd1498Szrj   int n_calls, n_hot_calls, freq_sum;
67338fd1498Szrj };
67438fd1498Szrj 
67538fd1498Szrj /* Initialize fields of STAT to zeroes.  */
67638fd1498Szrj 
67738fd1498Szrj static inline void
init_caller_stats(struct caller_statistics * stats)67838fd1498Szrj init_caller_stats (struct caller_statistics *stats)
67938fd1498Szrj {
68038fd1498Szrj   stats->count_sum = profile_count::zero ();
68138fd1498Szrj   stats->n_calls = 0;
68238fd1498Szrj   stats->n_hot_calls = 0;
68338fd1498Szrj   stats->freq_sum = 0;
68438fd1498Szrj }
68538fd1498Szrj 
68638fd1498Szrj /* Worker callback of cgraph_for_node_and_aliases accumulating statistics of
68738fd1498Szrj    non-thunk incoming edges to NODE.  */
68838fd1498Szrj 
68938fd1498Szrj static bool
gather_caller_stats(struct cgraph_node * node,void * data)69038fd1498Szrj gather_caller_stats (struct cgraph_node *node, void *data)
69138fd1498Szrj {
69238fd1498Szrj   struct caller_statistics *stats = (struct caller_statistics *) data;
69338fd1498Szrj   struct cgraph_edge *cs;
69438fd1498Szrj 
69538fd1498Szrj   for (cs = node->callers; cs; cs = cs->next_caller)
69638fd1498Szrj     if (!cs->caller->thunk.thunk_p)
69738fd1498Szrj       {
69838fd1498Szrj         if (cs->count.ipa ().initialized_p ())
69938fd1498Szrj 	  stats->count_sum += cs->count.ipa ();
70038fd1498Szrj 	stats->freq_sum += cs->frequency ();
70138fd1498Szrj 	stats->n_calls++;
70238fd1498Szrj 	if (cs->maybe_hot_p ())
70338fd1498Szrj 	  stats->n_hot_calls ++;
70438fd1498Szrj       }
70538fd1498Szrj   return false;
70638fd1498Szrj 
70738fd1498Szrj }
70838fd1498Szrj 
70938fd1498Szrj /* Return true if this NODE is viable candidate for cloning.  */
71038fd1498Szrj 
71138fd1498Szrj static bool
ipcp_cloning_candidate_p(struct cgraph_node * node)71238fd1498Szrj ipcp_cloning_candidate_p (struct cgraph_node *node)
71338fd1498Szrj {
71438fd1498Szrj   struct caller_statistics stats;
71538fd1498Szrj 
71638fd1498Szrj   gcc_checking_assert (node->has_gimple_body_p ());
71738fd1498Szrj 
71838fd1498Szrj   if (!opt_for_fn (node->decl, flag_ipa_cp_clone))
71938fd1498Szrj     {
72038fd1498Szrj       if (dump_file)
72138fd1498Szrj 	fprintf (dump_file, "Not considering %s for cloning; "
72238fd1498Szrj 		 "-fipa-cp-clone disabled.\n",
72338fd1498Szrj  		 node->name ());
72438fd1498Szrj       return false;
72538fd1498Szrj     }
72638fd1498Szrj 
72738fd1498Szrj   if (node->optimize_for_size_p ())
72838fd1498Szrj     {
72938fd1498Szrj       if (dump_file)
73038fd1498Szrj 	fprintf (dump_file, "Not considering %s for cloning; "
73138fd1498Szrj 		 "optimizing it for size.\n",
73238fd1498Szrj  		 node->name ());
73338fd1498Szrj       return false;
73438fd1498Szrj     }
73538fd1498Szrj 
73638fd1498Szrj   init_caller_stats (&stats);
73738fd1498Szrj   node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, false);
73838fd1498Szrj 
73938fd1498Szrj   if (ipa_fn_summaries->get (node)->self_size < stats.n_calls)
74038fd1498Szrj     {
74138fd1498Szrj       if (dump_file)
74238fd1498Szrj 	fprintf (dump_file, "Considering %s for cloning; code might shrink.\n",
74338fd1498Szrj  		 node->name ());
74438fd1498Szrj       return true;
74538fd1498Szrj     }
74638fd1498Szrj 
74738fd1498Szrj   /* When profile is available and function is hot, propagate into it even if
74838fd1498Szrj      calls seems cold; constant propagation can improve function's speed
74938fd1498Szrj      significantly.  */
75038fd1498Szrj   if (max_count > profile_count::zero ())
75138fd1498Szrj     {
75238fd1498Szrj       if (stats.count_sum > node->count.ipa ().apply_scale (90, 100))
75338fd1498Szrj 	{
75438fd1498Szrj 	  if (dump_file)
75538fd1498Szrj 	    fprintf (dump_file, "Considering %s for cloning; "
75638fd1498Szrj 		     "usually called directly.\n",
75738fd1498Szrj 		     node->name ());
75838fd1498Szrj 	  return true;
75938fd1498Szrj 	}
76038fd1498Szrj     }
76138fd1498Szrj   if (!stats.n_hot_calls)
76238fd1498Szrj     {
76338fd1498Szrj       if (dump_file)
76438fd1498Szrj 	fprintf (dump_file, "Not considering %s for cloning; no hot calls.\n",
76538fd1498Szrj 		 node->name ());
76638fd1498Szrj       return false;
76738fd1498Szrj     }
76838fd1498Szrj   if (dump_file)
76938fd1498Szrj     fprintf (dump_file, "Considering %s for cloning.\n",
77038fd1498Szrj 	     node->name ());
77138fd1498Szrj   return true;
77238fd1498Szrj }
77338fd1498Szrj 
77438fd1498Szrj template <typename valtype>
77538fd1498Szrj class value_topo_info
77638fd1498Szrj {
77738fd1498Szrj public:
77838fd1498Szrj   /* Head of the linked list of topologically sorted values. */
77938fd1498Szrj   ipcp_value<valtype> *values_topo;
78038fd1498Szrj   /* Stack for creating SCCs, represented by a linked list too.  */
78138fd1498Szrj   ipcp_value<valtype> *stack;
78238fd1498Szrj   /* Counter driving the algorithm in add_val_to_toposort.  */
78338fd1498Szrj   int dfs_counter;
78438fd1498Szrj 
value_topo_info()78538fd1498Szrj   value_topo_info () : values_topo (NULL), stack (NULL), dfs_counter (0)
78638fd1498Szrj   {}
78738fd1498Szrj   void add_val (ipcp_value<valtype> *cur_val);
78838fd1498Szrj   void propagate_effects ();
78938fd1498Szrj };
79038fd1498Szrj 
79138fd1498Szrj /* Arrays representing a topological ordering of call graph nodes and a stack
79238fd1498Szrj    of nodes used during constant propagation and also data required to perform
79338fd1498Szrj    topological sort of values and propagation of benefits in the determined
79438fd1498Szrj    order.  */
79538fd1498Szrj 
79638fd1498Szrj class ipa_topo_info
79738fd1498Szrj {
79838fd1498Szrj public:
79938fd1498Szrj   /* Array with obtained topological order of cgraph nodes.  */
80038fd1498Szrj   struct cgraph_node **order;
80138fd1498Szrj   /* Stack of cgraph nodes used during propagation within SCC until all values
80238fd1498Szrj      in the SCC stabilize.  */
80338fd1498Szrj   struct cgraph_node **stack;
80438fd1498Szrj   int nnodes, stack_top;
80538fd1498Szrj 
80638fd1498Szrj   value_topo_info<tree> constants;
80738fd1498Szrj   value_topo_info<ipa_polymorphic_call_context> contexts;
80838fd1498Szrj 
ipa_topo_info()80938fd1498Szrj   ipa_topo_info () : order(NULL), stack(NULL), nnodes(0), stack_top(0),
81038fd1498Szrj     constants ()
81138fd1498Szrj   {}
81238fd1498Szrj };
81338fd1498Szrj 
81438fd1498Szrj /* Allocate the arrays in TOPO and topologically sort the nodes into order.  */
81538fd1498Szrj 
81638fd1498Szrj static void
build_toporder_info(struct ipa_topo_info * topo)81738fd1498Szrj build_toporder_info (struct ipa_topo_info *topo)
81838fd1498Szrj {
81938fd1498Szrj   topo->order = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count);
82038fd1498Szrj   topo->stack = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count);
82138fd1498Szrj 
82238fd1498Szrj   gcc_checking_assert (topo->stack_top == 0);
82358e805e6Szrj   topo->nnodes = ipa_reduced_postorder (topo->order, true, NULL);
82438fd1498Szrj }
82538fd1498Szrj 
82638fd1498Szrj /* Free information about strongly connected components and the arrays in
82738fd1498Szrj    TOPO.  */
82838fd1498Szrj 
82938fd1498Szrj static void
free_toporder_info(struct ipa_topo_info * topo)83038fd1498Szrj free_toporder_info (struct ipa_topo_info *topo)
83138fd1498Szrj {
83238fd1498Szrj   ipa_free_postorder_info ();
83338fd1498Szrj   free (topo->order);
83438fd1498Szrj   free (topo->stack);
83538fd1498Szrj }
83638fd1498Szrj 
83738fd1498Szrj /* Add NODE to the stack in TOPO, unless it is already there.  */
83838fd1498Szrj 
83938fd1498Szrj static inline void
push_node_to_stack(struct ipa_topo_info * topo,struct cgraph_node * node)84038fd1498Szrj push_node_to_stack (struct ipa_topo_info *topo, struct cgraph_node *node)
84138fd1498Szrj {
84238fd1498Szrj   struct ipa_node_params *info = IPA_NODE_REF (node);
84338fd1498Szrj   if (info->node_enqueued)
84438fd1498Szrj     return;
84538fd1498Szrj   info->node_enqueued = 1;
84638fd1498Szrj   topo->stack[topo->stack_top++] = node;
84738fd1498Szrj }
84838fd1498Szrj 
84938fd1498Szrj /* Pop a node from the stack in TOPO and return it or return NULL if the stack
85038fd1498Szrj    is empty.  */
85138fd1498Szrj 
85238fd1498Szrj static struct cgraph_node *
pop_node_from_stack(struct ipa_topo_info * topo)85338fd1498Szrj pop_node_from_stack (struct ipa_topo_info *topo)
85438fd1498Szrj {
85538fd1498Szrj   if (topo->stack_top)
85638fd1498Szrj     {
85738fd1498Szrj       struct cgraph_node *node;
85838fd1498Szrj       topo->stack_top--;
85938fd1498Szrj       node = topo->stack[topo->stack_top];
86038fd1498Szrj       IPA_NODE_REF (node)->node_enqueued = 0;
86138fd1498Szrj       return node;
86238fd1498Szrj     }
86338fd1498Szrj   else
86438fd1498Szrj     return NULL;
86538fd1498Szrj }
86638fd1498Szrj 
86738fd1498Szrj /* Set lattice LAT to bottom and return true if it previously was not set as
86838fd1498Szrj    such.  */
86938fd1498Szrj 
87038fd1498Szrj template <typename valtype>
87138fd1498Szrj inline bool
set_to_bottom()87238fd1498Szrj ipcp_lattice<valtype>::set_to_bottom ()
87338fd1498Szrj {
87438fd1498Szrj   bool ret = !bottom;
87538fd1498Szrj   bottom = true;
87638fd1498Szrj   return ret;
87738fd1498Szrj }
87838fd1498Szrj 
87938fd1498Szrj /* Mark lattice as containing an unknown value and return true if it previously
88038fd1498Szrj    was not marked as such.  */
88138fd1498Szrj 
88238fd1498Szrj template <typename valtype>
88338fd1498Szrj inline bool
set_contains_variable()88438fd1498Szrj ipcp_lattice<valtype>::set_contains_variable ()
88538fd1498Szrj {
88638fd1498Szrj   bool ret = !contains_variable;
88738fd1498Szrj   contains_variable = true;
88838fd1498Szrj   return ret;
88938fd1498Szrj }
89038fd1498Szrj 
89138fd1498Szrj /* Set all aggegate lattices in PLATS to bottom and return true if they were
89238fd1498Szrj    not previously set as such.  */
89338fd1498Szrj 
89438fd1498Szrj static inline bool
set_agg_lats_to_bottom(struct ipcp_param_lattices * plats)89538fd1498Szrj set_agg_lats_to_bottom (struct ipcp_param_lattices *plats)
89638fd1498Szrj {
89738fd1498Szrj   bool ret = !plats->aggs_bottom;
89838fd1498Szrj   plats->aggs_bottom = true;
89938fd1498Szrj   return ret;
90038fd1498Szrj }
90138fd1498Szrj 
90238fd1498Szrj /* Mark all aggegate lattices in PLATS as containing an unknown value and
90338fd1498Szrj    return true if they were not previously marked as such.  */
90438fd1498Szrj 
90538fd1498Szrj static inline bool
set_agg_lats_contain_variable(struct ipcp_param_lattices * plats)90638fd1498Szrj set_agg_lats_contain_variable (struct ipcp_param_lattices *plats)
90738fd1498Szrj {
90838fd1498Szrj   bool ret = !plats->aggs_contain_variable;
90938fd1498Szrj   plats->aggs_contain_variable = true;
91038fd1498Szrj   return ret;
91138fd1498Szrj }
91238fd1498Szrj 
91338fd1498Szrj bool
meet_with(const ipcp_vr_lattice & other)91438fd1498Szrj ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other)
91538fd1498Szrj {
91638fd1498Szrj   return meet_with_1 (&other.m_vr);
91738fd1498Szrj }
91838fd1498Szrj 
91938fd1498Szrj /* Meet the current value of the lattice with value ranfge described by VR
92038fd1498Szrj    lattice.  */
92138fd1498Szrj 
92238fd1498Szrj bool
meet_with(const value_range * p_vr)92338fd1498Szrj ipcp_vr_lattice::meet_with (const value_range *p_vr)
92438fd1498Szrj {
92538fd1498Szrj   return meet_with_1 (p_vr);
92638fd1498Szrj }
92738fd1498Szrj 
92838fd1498Szrj /* Meet the current value of the lattice with value ranfge described by
92938fd1498Szrj    OTHER_VR lattice.  */
93038fd1498Szrj 
93138fd1498Szrj bool
meet_with_1(const value_range * other_vr)93238fd1498Szrj ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
93338fd1498Szrj {
93438fd1498Szrj   tree min = m_vr.min, max = m_vr.max;
93538fd1498Szrj   value_range_type type = m_vr.type;
93638fd1498Szrj 
93738fd1498Szrj   if (bottom_p ())
93838fd1498Szrj     return false;
93938fd1498Szrj 
94038fd1498Szrj   if (other_vr->type == VR_VARYING)
94138fd1498Szrj     return set_to_bottom ();
94238fd1498Szrj 
94338fd1498Szrj   vrp_meet (&m_vr, other_vr);
94438fd1498Szrj   if (type != m_vr.type
94538fd1498Szrj       || min != m_vr.min
94638fd1498Szrj       || max != m_vr.max)
94738fd1498Szrj     return true;
94838fd1498Szrj   else
94938fd1498Szrj     return false;
95038fd1498Szrj }
95138fd1498Szrj 
95238fd1498Szrj /* Return true if value range information in the lattice is yet unknown.  */
95338fd1498Szrj 
95438fd1498Szrj bool
top_p()95538fd1498Szrj ipcp_vr_lattice::top_p () const
95638fd1498Szrj {
95738fd1498Szrj   return m_vr.type == VR_UNDEFINED;
95838fd1498Szrj }
95938fd1498Szrj 
96038fd1498Szrj /* Return true if value range information in the lattice is known to be
96138fd1498Szrj    unusable.  */
96238fd1498Szrj 
96338fd1498Szrj bool
bottom_p()96438fd1498Szrj ipcp_vr_lattice::bottom_p () const
96538fd1498Szrj {
96638fd1498Szrj   return m_vr.type == VR_VARYING;
96738fd1498Szrj }
96838fd1498Szrj 
96938fd1498Szrj /* Set value range information in the lattice to bottom.  Return true if it
97038fd1498Szrj    previously was in a different state.  */
97138fd1498Szrj 
97238fd1498Szrj bool
set_to_bottom()97338fd1498Szrj ipcp_vr_lattice::set_to_bottom ()
97438fd1498Szrj {
97538fd1498Szrj   if (m_vr.type == VR_VARYING)
97638fd1498Szrj     return false;
97738fd1498Szrj   m_vr.type = VR_VARYING;
97838fd1498Szrj   return true;
97938fd1498Szrj }
98038fd1498Szrj 
98138fd1498Szrj /* Set lattice value to bottom, if it already isn't the case.  */
98238fd1498Szrj 
98338fd1498Szrj bool
set_to_bottom()98438fd1498Szrj ipcp_bits_lattice::set_to_bottom ()
98538fd1498Szrj {
98638fd1498Szrj   if (bottom_p ())
98738fd1498Szrj     return false;
98838fd1498Szrj   m_lattice_val = IPA_BITS_VARYING;
98938fd1498Szrj   m_value = 0;
99038fd1498Szrj   m_mask = -1;
99138fd1498Szrj   return true;
99238fd1498Szrj }
99338fd1498Szrj 
99438fd1498Szrj /* Set to constant if it isn't already. Only meant to be called
99538fd1498Szrj    when switching state from TOP.  */
99638fd1498Szrj 
99738fd1498Szrj bool
set_to_constant(widest_int value,widest_int mask)99838fd1498Szrj ipcp_bits_lattice::set_to_constant (widest_int value, widest_int mask)
99938fd1498Szrj {
100038fd1498Szrj   gcc_assert (top_p ());
100138fd1498Szrj   m_lattice_val = IPA_BITS_CONSTANT;
100238fd1498Szrj   m_value = value;
100338fd1498Szrj   m_mask = mask;
100438fd1498Szrj   return true;
100538fd1498Szrj }
100638fd1498Szrj 
100738fd1498Szrj /* Convert operand to value, mask form.  */
100838fd1498Szrj 
100938fd1498Szrj void
get_value_and_mask(tree operand,widest_int * valuep,widest_int * maskp)101038fd1498Szrj ipcp_bits_lattice::get_value_and_mask (tree operand, widest_int *valuep, widest_int *maskp)
101138fd1498Szrj {
101238fd1498Szrj   wide_int get_nonzero_bits (const_tree);
101338fd1498Szrj 
101438fd1498Szrj   if (TREE_CODE (operand) == INTEGER_CST)
101538fd1498Szrj     {
101638fd1498Szrj       *valuep = wi::to_widest (operand);
101738fd1498Szrj       *maskp = 0;
101838fd1498Szrj     }
101938fd1498Szrj   else
102038fd1498Szrj     {
102138fd1498Szrj       *valuep = 0;
102238fd1498Szrj       *maskp = -1;
102338fd1498Szrj     }
102438fd1498Szrj }
102538fd1498Szrj 
102638fd1498Szrj /* Meet operation, similar to ccp_lattice_meet, we xor values
102738fd1498Szrj    if this->value, value have different values at same bit positions, we want
102838fd1498Szrj    to drop that bit to varying. Return true if mask is changed.
102938fd1498Szrj    This function assumes that the lattice value is in CONSTANT state  */
103038fd1498Szrj 
103138fd1498Szrj bool
meet_with_1(widest_int value,widest_int mask,unsigned precision)103238fd1498Szrj ipcp_bits_lattice::meet_with_1 (widest_int value, widest_int mask,
103338fd1498Szrj 				unsigned precision)
103438fd1498Szrj {
103538fd1498Szrj   gcc_assert (constant_p ());
103638fd1498Szrj 
103738fd1498Szrj   widest_int old_mask = m_mask;
103838fd1498Szrj   m_mask = (m_mask | mask) | (m_value ^ value);
103938fd1498Szrj 
104038fd1498Szrj   if (wi::sext (m_mask, precision) == -1)
104138fd1498Szrj     return set_to_bottom ();
104238fd1498Szrj 
104338fd1498Szrj   return m_mask != old_mask;
104438fd1498Szrj }
104538fd1498Szrj 
104638fd1498Szrj /* Meet the bits lattice with operand
104738fd1498Szrj    described by <value, mask, sgn, precision.  */
104838fd1498Szrj 
104938fd1498Szrj bool
meet_with(widest_int value,widest_int mask,unsigned precision)105038fd1498Szrj ipcp_bits_lattice::meet_with (widest_int value, widest_int mask,
105138fd1498Szrj 			      unsigned precision)
105238fd1498Szrj {
105338fd1498Szrj   if (bottom_p ())
105438fd1498Szrj     return false;
105538fd1498Szrj 
105638fd1498Szrj   if (top_p ())
105738fd1498Szrj     {
105838fd1498Szrj       if (wi::sext (mask, precision) == -1)
105938fd1498Szrj 	return set_to_bottom ();
106038fd1498Szrj       return set_to_constant (value, mask);
106138fd1498Szrj     }
106238fd1498Szrj 
106338fd1498Szrj   return meet_with_1 (value, mask, precision);
106438fd1498Szrj }
106538fd1498Szrj 
106638fd1498Szrj /* Meet bits lattice with the result of bit_value_binop (other, operand)
106738fd1498Szrj    if code is binary operation or bit_value_unop (other) if code is unary op.
106838fd1498Szrj    In the case when code is nop_expr, no adjustment is required. */
106938fd1498Szrj 
107038fd1498Szrj bool
meet_with(ipcp_bits_lattice & other,unsigned precision,signop sgn,enum tree_code code,tree operand)107138fd1498Szrj ipcp_bits_lattice::meet_with (ipcp_bits_lattice& other, unsigned precision,
107238fd1498Szrj 			      signop sgn, enum tree_code code, tree operand)
107338fd1498Szrj {
107438fd1498Szrj   if (other.bottom_p ())
107538fd1498Szrj     return set_to_bottom ();
107638fd1498Szrj 
107738fd1498Szrj   if (bottom_p () || other.top_p ())
107838fd1498Szrj     return false;
107938fd1498Szrj 
108038fd1498Szrj   widest_int adjusted_value, adjusted_mask;
108138fd1498Szrj 
108238fd1498Szrj   if (TREE_CODE_CLASS (code) == tcc_binary)
108338fd1498Szrj     {
108438fd1498Szrj       tree type = TREE_TYPE (operand);
108538fd1498Szrj       gcc_assert (INTEGRAL_TYPE_P (type));
108638fd1498Szrj       widest_int o_value, o_mask;
108738fd1498Szrj       get_value_and_mask (operand, &o_value, &o_mask);
108838fd1498Szrj 
108938fd1498Szrj       bit_value_binop (code, sgn, precision, &adjusted_value, &adjusted_mask,
109038fd1498Szrj 		       sgn, precision, other.get_value (), other.get_mask (),
109138fd1498Szrj 		       TYPE_SIGN (type), TYPE_PRECISION (type), o_value, o_mask);
109238fd1498Szrj 
109338fd1498Szrj       if (wi::sext (adjusted_mask, precision) == -1)
109438fd1498Szrj 	return set_to_bottom ();
109538fd1498Szrj     }
109638fd1498Szrj 
109738fd1498Szrj   else if (TREE_CODE_CLASS (code) == tcc_unary)
109838fd1498Szrj     {
109938fd1498Szrj       bit_value_unop (code, sgn, precision, &adjusted_value,
110038fd1498Szrj 		      &adjusted_mask, sgn, precision, other.get_value (),
110138fd1498Szrj 		      other.get_mask ());
110238fd1498Szrj 
110338fd1498Szrj       if (wi::sext (adjusted_mask, precision) == -1)
110438fd1498Szrj 	return set_to_bottom ();
110538fd1498Szrj     }
110638fd1498Szrj 
110738fd1498Szrj   else
110838fd1498Szrj     return set_to_bottom ();
110938fd1498Szrj 
111038fd1498Szrj   if (top_p ())
111138fd1498Szrj     {
111238fd1498Szrj       if (wi::sext (adjusted_mask, precision) == -1)
111338fd1498Szrj 	return set_to_bottom ();
111438fd1498Szrj       return set_to_constant (adjusted_value, adjusted_mask);
111538fd1498Szrj     }
111638fd1498Szrj   else
111738fd1498Szrj     return meet_with_1 (adjusted_value, adjusted_mask, precision);
111838fd1498Szrj }
111938fd1498Szrj 
112038fd1498Szrj /* Mark bot aggregate and scalar lattices as containing an unknown variable,
112138fd1498Szrj    return true is any of them has not been marked as such so far.  */
112238fd1498Szrj 
112338fd1498Szrj static inline bool
set_all_contains_variable(struct ipcp_param_lattices * plats)112438fd1498Szrj set_all_contains_variable (struct ipcp_param_lattices *plats)
112538fd1498Szrj {
112638fd1498Szrj   bool ret;
112738fd1498Szrj   ret = plats->itself.set_contains_variable ();
112838fd1498Szrj   ret |= plats->ctxlat.set_contains_variable ();
112938fd1498Szrj   ret |= set_agg_lats_contain_variable (plats);
113038fd1498Szrj   ret |= plats->bits_lattice.set_to_bottom ();
113138fd1498Szrj   ret |= plats->m_value_range.set_to_bottom ();
113238fd1498Szrj   return ret;
113338fd1498Szrj }
113438fd1498Szrj 
113538fd1498Szrj /* Worker of call_for_symbol_thunks_and_aliases, increment the integer DATA
113638fd1498Szrj    points to by the number of callers to NODE.  */
113738fd1498Szrj 
113838fd1498Szrj static bool
count_callers(cgraph_node * node,void * data)113938fd1498Szrj count_callers (cgraph_node *node, void *data)
114038fd1498Szrj {
114138fd1498Szrj   int *caller_count = (int *) data;
114238fd1498Szrj 
114338fd1498Szrj   for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller)
114438fd1498Szrj     /* Local thunks can be handled transparently, but if the thunk can not
114538fd1498Szrj        be optimized out, count it as a real use.  */
114638fd1498Szrj     if (!cs->caller->thunk.thunk_p || !cs->caller->local.local)
114738fd1498Szrj       ++*caller_count;
114838fd1498Szrj   return false;
114938fd1498Szrj }
115038fd1498Szrj 
115138fd1498Szrj /* Worker of call_for_symbol_thunks_and_aliases, it is supposed to be called on
115238fd1498Szrj    the one caller of some other node.  Set the caller's corresponding flag.  */
115338fd1498Szrj 
115438fd1498Szrj static bool
set_single_call_flag(cgraph_node * node,void *)115538fd1498Szrj set_single_call_flag (cgraph_node *node, void *)
115638fd1498Szrj {
115738fd1498Szrj   cgraph_edge *cs = node->callers;
115838fd1498Szrj   /* Local thunks can be handled transparently, skip them.  */
115938fd1498Szrj   while (cs && cs->caller->thunk.thunk_p && cs->caller->local.local)
116038fd1498Szrj     cs = cs->next_caller;
116138fd1498Szrj   if (cs)
116238fd1498Szrj     {
116338fd1498Szrj       IPA_NODE_REF (cs->caller)->node_calling_single_call = true;
116438fd1498Szrj       return true;
116538fd1498Szrj     }
116638fd1498Szrj   return false;
116738fd1498Szrj }
116838fd1498Szrj 
116938fd1498Szrj /* Initialize ipcp_lattices.  */
117038fd1498Szrj 
117138fd1498Szrj static void
initialize_node_lattices(struct cgraph_node * node)117238fd1498Szrj initialize_node_lattices (struct cgraph_node *node)
117338fd1498Szrj {
117438fd1498Szrj   struct ipa_node_params *info = IPA_NODE_REF (node);
117538fd1498Szrj   struct cgraph_edge *ie;
117638fd1498Szrj   bool disable = false, variable = false;
117738fd1498Szrj   int i;
117838fd1498Szrj 
117938fd1498Szrj   gcc_checking_assert (node->has_gimple_body_p ());
118038fd1498Szrj   if (cgraph_local_p (node))
118138fd1498Szrj     {
118238fd1498Szrj       int caller_count = 0;
118338fd1498Szrj       node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count,
118438fd1498Szrj 						true);
118538fd1498Szrj       gcc_checking_assert (caller_count > 0);
118638fd1498Szrj       if (caller_count == 1)
118738fd1498Szrj 	node->call_for_symbol_thunks_and_aliases (set_single_call_flag,
118838fd1498Szrj 						  NULL, true);
118938fd1498Szrj     }
119038fd1498Szrj   else
119138fd1498Szrj     {
119238fd1498Szrj       /* When cloning is allowed, we can assume that externally visible
119338fd1498Szrj 	 functions are not called.  We will compensate this by cloning
119438fd1498Szrj 	 later.  */
119538fd1498Szrj       if (ipcp_versionable_function_p (node)
119638fd1498Szrj 	  && ipcp_cloning_candidate_p (node))
119738fd1498Szrj 	variable = true;
119838fd1498Szrj       else
119938fd1498Szrj 	disable = true;
120038fd1498Szrj     }
120138fd1498Szrj 
120238fd1498Szrj   for (i = 0; i < ipa_get_param_count (info); i++)
120338fd1498Szrj     {
120438fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
120538fd1498Szrj       plats->m_value_range.init ();
120638fd1498Szrj     }
120738fd1498Szrj 
120838fd1498Szrj   if (disable || variable)
120938fd1498Szrj     {
121038fd1498Szrj       for (i = 0; i < ipa_get_param_count (info); i++)
121138fd1498Szrj 	{
121238fd1498Szrj 	  struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
121338fd1498Szrj 	  if (disable)
121438fd1498Szrj 	    {
121538fd1498Szrj 	      plats->itself.set_to_bottom ();
121638fd1498Szrj 	      plats->ctxlat.set_to_bottom ();
121738fd1498Szrj 	      set_agg_lats_to_bottom (plats);
121838fd1498Szrj 	      plats->bits_lattice.set_to_bottom ();
121938fd1498Szrj 	      plats->m_value_range.set_to_bottom ();
122038fd1498Szrj 	    }
122138fd1498Szrj 	  else
122238fd1498Szrj 	    set_all_contains_variable (plats);
122338fd1498Szrj 	}
122438fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS)
122538fd1498Szrj 	  && !node->alias && !node->thunk.thunk_p)
122638fd1498Szrj 	fprintf (dump_file, "Marking all lattices of %s as %s\n",
122738fd1498Szrj 		 node->dump_name (), disable ? "BOTTOM" : "VARIABLE");
122838fd1498Szrj     }
122938fd1498Szrj 
123038fd1498Szrj   for (ie = node->indirect_calls; ie; ie = ie->next_callee)
123138fd1498Szrj     if (ie->indirect_info->polymorphic
123238fd1498Szrj 	&& ie->indirect_info->param_index >= 0)
123338fd1498Szrj       {
123438fd1498Szrj 	gcc_checking_assert (ie->indirect_info->param_index >= 0);
123538fd1498Szrj 	ipa_get_parm_lattices (info,
123638fd1498Szrj 			       ie->indirect_info->param_index)->virt_call = 1;
123738fd1498Szrj       }
123838fd1498Szrj }
123938fd1498Szrj 
124038fd1498Szrj /* Return the result of a (possibly arithmetic) pass through jump function
124138fd1498Szrj    JFUNC on the constant value INPUT.  RES_TYPE is the type of the parameter
124238fd1498Szrj    to which the result is passed.  Return NULL_TREE if that cannot be
124338fd1498Szrj    determined or be considered an interprocedural invariant.  */
124438fd1498Szrj 
124538fd1498Szrj static tree
ipa_get_jf_pass_through_result(struct ipa_jump_func * jfunc,tree input,tree res_type)124638fd1498Szrj ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input,
124738fd1498Szrj 				tree res_type)
124838fd1498Szrj {
124938fd1498Szrj   tree res;
125038fd1498Szrj 
125138fd1498Szrj   if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
125238fd1498Szrj     return input;
125338fd1498Szrj   if (!is_gimple_ip_invariant (input))
125438fd1498Szrj     return NULL_TREE;
125538fd1498Szrj 
125638fd1498Szrj   tree_code opcode = ipa_get_jf_pass_through_operation (jfunc);
125738fd1498Szrj   if (!res_type)
125838fd1498Szrj     {
125938fd1498Szrj       if (TREE_CODE_CLASS (opcode) == tcc_comparison)
126038fd1498Szrj 	res_type = boolean_type_node;
126138fd1498Szrj       else if (expr_type_first_operand_type_p (opcode))
126238fd1498Szrj 	res_type = TREE_TYPE (input);
126338fd1498Szrj       else
126438fd1498Szrj 	return NULL_TREE;
126538fd1498Szrj     }
126638fd1498Szrj 
126738fd1498Szrj   if (TREE_CODE_CLASS (opcode) == tcc_unary)
126838fd1498Szrj     res = fold_unary (opcode, res_type, input);
126938fd1498Szrj   else
127038fd1498Szrj     res = fold_binary (opcode, res_type, input,
127138fd1498Szrj 		       ipa_get_jf_pass_through_operand (jfunc));
127238fd1498Szrj 
127338fd1498Szrj   if (res && !is_gimple_ip_invariant (res))
127438fd1498Szrj     return NULL_TREE;
127538fd1498Szrj 
127638fd1498Szrj   return res;
127738fd1498Szrj }
127838fd1498Szrj 
127938fd1498Szrj /* Return the result of an ancestor jump function JFUNC on the constant value
128038fd1498Szrj    INPUT.  Return NULL_TREE if that cannot be determined.  */
128138fd1498Szrj 
128238fd1498Szrj static tree
ipa_get_jf_ancestor_result(struct ipa_jump_func * jfunc,tree input)128338fd1498Szrj ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input)
128438fd1498Szrj {
128538fd1498Szrj   gcc_checking_assert (TREE_CODE (input) != TREE_BINFO);
128638fd1498Szrj   if (TREE_CODE (input) == ADDR_EXPR)
128738fd1498Szrj     {
128838fd1498Szrj       tree t = TREE_OPERAND (input, 0);
128938fd1498Szrj       t = build_ref_for_offset (EXPR_LOCATION (t), t,
129038fd1498Szrj 				ipa_get_jf_ancestor_offset (jfunc), false,
129138fd1498Szrj 				ptr_type_node, NULL, false);
129238fd1498Szrj       return build_fold_addr_expr (t);
129338fd1498Szrj     }
129438fd1498Szrj   else
129538fd1498Szrj     return NULL_TREE;
129638fd1498Szrj }
129738fd1498Szrj 
129838fd1498Szrj /* Determine whether JFUNC evaluates to a single known constant value and if
129938fd1498Szrj    so, return it.  Otherwise return NULL.  INFO describes the caller node or
130038fd1498Szrj    the one it is inlined to, so that pass-through jump functions can be
130138fd1498Szrj    evaluated.  PARM_TYPE is the type of the parameter to which the result is
130238fd1498Szrj    passed.  */
130338fd1498Szrj 
130438fd1498Szrj tree
ipa_value_from_jfunc(struct ipa_node_params * info,struct ipa_jump_func * jfunc,tree parm_type)130538fd1498Szrj ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc,
130638fd1498Szrj 		      tree parm_type)
130738fd1498Szrj {
130838fd1498Szrj   if (jfunc->type == IPA_JF_CONST)
130938fd1498Szrj     return ipa_get_jf_constant (jfunc);
131038fd1498Szrj   else if (jfunc->type == IPA_JF_PASS_THROUGH
131138fd1498Szrj 	   || jfunc->type == IPA_JF_ANCESTOR)
131238fd1498Szrj     {
131338fd1498Szrj       tree input;
131438fd1498Szrj       int idx;
131538fd1498Szrj 
131638fd1498Szrj       if (jfunc->type == IPA_JF_PASS_THROUGH)
131738fd1498Szrj 	idx = ipa_get_jf_pass_through_formal_id (jfunc);
131838fd1498Szrj       else
131938fd1498Szrj 	idx = ipa_get_jf_ancestor_formal_id (jfunc);
132038fd1498Szrj 
132138fd1498Szrj       if (info->ipcp_orig_node)
132238fd1498Szrj 	input = info->known_csts[idx];
132338fd1498Szrj       else
132438fd1498Szrj 	{
132538fd1498Szrj 	  ipcp_lattice<tree> *lat;
132638fd1498Szrj 
132738fd1498Szrj 	  if (!info->lattices
132838fd1498Szrj 	      || idx >= ipa_get_param_count (info))
132938fd1498Szrj 	    return NULL_TREE;
133038fd1498Szrj 	  lat = ipa_get_scalar_lat (info, idx);
133138fd1498Szrj 	  if (!lat->is_single_const ())
133238fd1498Szrj 	    return NULL_TREE;
133338fd1498Szrj 	  input = lat->values->value;
133438fd1498Szrj 	}
133538fd1498Szrj 
133638fd1498Szrj       if (!input)
133738fd1498Szrj 	return NULL_TREE;
133838fd1498Szrj 
133938fd1498Szrj       if (jfunc->type == IPA_JF_PASS_THROUGH)
134038fd1498Szrj 	return ipa_get_jf_pass_through_result (jfunc, input, parm_type);
134138fd1498Szrj       else
134238fd1498Szrj 	return ipa_get_jf_ancestor_result (jfunc, input);
134338fd1498Szrj     }
134438fd1498Szrj   else
134538fd1498Szrj     return NULL_TREE;
134638fd1498Szrj }
134738fd1498Szrj 
134838fd1498Szrj /* Determie whether JFUNC evaluates to single known polymorphic context, given
134938fd1498Szrj    that INFO describes the caller node or the one it is inlined to, CS is the
135038fd1498Szrj    call graph edge corresponding to JFUNC and CSIDX index of the described
135138fd1498Szrj    parameter.  */
135238fd1498Szrj 
135338fd1498Szrj ipa_polymorphic_call_context
ipa_context_from_jfunc(ipa_node_params * info,cgraph_edge * cs,int csidx,ipa_jump_func * jfunc)135438fd1498Szrj ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
135538fd1498Szrj 			ipa_jump_func *jfunc)
135638fd1498Szrj {
135738fd1498Szrj   ipa_edge_args *args = IPA_EDGE_REF (cs);
135838fd1498Szrj   ipa_polymorphic_call_context ctx;
135938fd1498Szrj   ipa_polymorphic_call_context *edge_ctx
136038fd1498Szrj     = cs ? ipa_get_ith_polymorhic_call_context (args, csidx) : NULL;
136138fd1498Szrj 
136238fd1498Szrj   if (edge_ctx && !edge_ctx->useless_p ())
136338fd1498Szrj     ctx = *edge_ctx;
136438fd1498Szrj 
136538fd1498Szrj   if (jfunc->type == IPA_JF_PASS_THROUGH
136638fd1498Szrj       || jfunc->type == IPA_JF_ANCESTOR)
136738fd1498Szrj     {
136838fd1498Szrj       ipa_polymorphic_call_context srcctx;
136938fd1498Szrj       int srcidx;
137038fd1498Szrj       bool type_preserved = true;
137138fd1498Szrj       if (jfunc->type == IPA_JF_PASS_THROUGH)
137238fd1498Szrj 	{
137338fd1498Szrj 	  if (ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR)
137438fd1498Szrj 	    return ctx;
137538fd1498Szrj 	  type_preserved = ipa_get_jf_pass_through_type_preserved (jfunc);
137638fd1498Szrj 	  srcidx = ipa_get_jf_pass_through_formal_id (jfunc);
137738fd1498Szrj 	}
137838fd1498Szrj       else
137938fd1498Szrj 	{
138038fd1498Szrj 	  type_preserved = ipa_get_jf_ancestor_type_preserved (jfunc);
138138fd1498Szrj 	  srcidx = ipa_get_jf_ancestor_formal_id (jfunc);
138238fd1498Szrj 	}
138338fd1498Szrj       if (info->ipcp_orig_node)
138438fd1498Szrj 	{
138538fd1498Szrj 	  if (info->known_contexts.exists ())
138638fd1498Szrj 	    srcctx = info->known_contexts[srcidx];
138738fd1498Szrj 	}
138838fd1498Szrj       else
138938fd1498Szrj 	{
139038fd1498Szrj 	  if (!info->lattices
139138fd1498Szrj 	      || srcidx >= ipa_get_param_count (info))
139238fd1498Szrj 	    return ctx;
139338fd1498Szrj 	  ipcp_lattice<ipa_polymorphic_call_context> *lat;
139438fd1498Szrj 	  lat = ipa_get_poly_ctx_lat (info, srcidx);
139538fd1498Szrj 	  if (!lat->is_single_const ())
139638fd1498Szrj 	    return ctx;
139738fd1498Szrj 	  srcctx = lat->values->value;
139838fd1498Szrj 	}
139938fd1498Szrj       if (srcctx.useless_p ())
140038fd1498Szrj 	return ctx;
140138fd1498Szrj       if (jfunc->type == IPA_JF_ANCESTOR)
140238fd1498Szrj 	srcctx.offset_by (ipa_get_jf_ancestor_offset (jfunc));
140338fd1498Szrj       if (!type_preserved)
140438fd1498Szrj 	srcctx.possible_dynamic_type_change (cs->in_polymorphic_cdtor);
140538fd1498Szrj       srcctx.combine_with (ctx);
140638fd1498Szrj       return srcctx;
140738fd1498Szrj     }
140838fd1498Szrj 
140938fd1498Szrj   return ctx;
141038fd1498Szrj }
141138fd1498Szrj 
141238fd1498Szrj /* If checking is enabled, verify that no lattice is in the TOP state, i.e. not
141338fd1498Szrj    bottom, not containing a variable component and without any known value at
141438fd1498Szrj    the same time.  */
141538fd1498Szrj 
141638fd1498Szrj DEBUG_FUNCTION void
ipcp_verify_propagated_values(void)141738fd1498Szrj ipcp_verify_propagated_values (void)
141838fd1498Szrj {
141938fd1498Szrj   struct cgraph_node *node;
142038fd1498Szrj 
142138fd1498Szrj   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
142238fd1498Szrj     {
142338fd1498Szrj       struct ipa_node_params *info = IPA_NODE_REF (node);
142438fd1498Szrj       int i, count = ipa_get_param_count (info);
142538fd1498Szrj 
142638fd1498Szrj       for (i = 0; i < count; i++)
142738fd1498Szrj 	{
142838fd1498Szrj 	  ipcp_lattice<tree> *lat = ipa_get_scalar_lat (info, i);
142938fd1498Szrj 
143038fd1498Szrj 	  if (!lat->bottom
143138fd1498Szrj 	      && !lat->contains_variable
143238fd1498Szrj 	      && lat->values_count == 0)
143338fd1498Szrj 	    {
143438fd1498Szrj 	      if (dump_file)
143538fd1498Szrj 		{
143638fd1498Szrj 		  symtab->dump (dump_file);
143738fd1498Szrj 		  fprintf (dump_file, "\nIPA lattices after constant "
143838fd1498Szrj 			   "propagation, before gcc_unreachable:\n");
143938fd1498Szrj 		  print_all_lattices (dump_file, true, false);
144038fd1498Szrj 		}
144138fd1498Szrj 
144238fd1498Szrj 	      gcc_unreachable ();
144338fd1498Szrj 	    }
144438fd1498Szrj 	}
144538fd1498Szrj     }
144638fd1498Szrj }
144738fd1498Szrj 
144838fd1498Szrj /* Return true iff X and Y should be considered equal values by IPA-CP.  */
144938fd1498Szrj 
145038fd1498Szrj static bool
values_equal_for_ipcp_p(tree x,tree y)145138fd1498Szrj values_equal_for_ipcp_p (tree x, tree y)
145238fd1498Szrj {
145338fd1498Szrj   gcc_checking_assert (x != NULL_TREE && y != NULL_TREE);
145438fd1498Szrj 
145538fd1498Szrj   if (x == y)
145638fd1498Szrj     return true;
145738fd1498Szrj 
145838fd1498Szrj   if (TREE_CODE (x) ==  ADDR_EXPR
145938fd1498Szrj       && TREE_CODE (y) ==  ADDR_EXPR
146038fd1498Szrj       && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL
146138fd1498Szrj       && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL)
146238fd1498Szrj     return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)),
146338fd1498Szrj 			    DECL_INITIAL (TREE_OPERAND (y, 0)), 0);
146438fd1498Szrj   else
146538fd1498Szrj     return operand_equal_p (x, y, 0);
146638fd1498Szrj }
146738fd1498Szrj 
146838fd1498Szrj /* Return true iff X and Y should be considered equal contexts by IPA-CP.  */
146938fd1498Szrj 
147038fd1498Szrj static bool
values_equal_for_ipcp_p(ipa_polymorphic_call_context x,ipa_polymorphic_call_context y)147138fd1498Szrj values_equal_for_ipcp_p (ipa_polymorphic_call_context x,
147238fd1498Szrj 			 ipa_polymorphic_call_context y)
147338fd1498Szrj {
147438fd1498Szrj   return x.equal_to (y);
147538fd1498Szrj }
147638fd1498Szrj 
147738fd1498Szrj 
147838fd1498Szrj /* Add a new value source to the value represented by THIS, marking that a
147938fd1498Szrj    value comes from edge CS and (if the underlying jump function is a
148038fd1498Szrj    pass-through or an ancestor one) from a caller value SRC_VAL of a caller
148138fd1498Szrj    parameter described by SRC_INDEX.  OFFSET is negative if the source was the
148238fd1498Szrj    scalar value of the parameter itself or the offset within an aggregate.  */
148338fd1498Szrj 
148438fd1498Szrj template <typename valtype>
148538fd1498Szrj void
add_source(cgraph_edge * cs,ipcp_value * src_val,int src_idx,HOST_WIDE_INT offset)148638fd1498Szrj ipcp_value<valtype>::add_source (cgraph_edge *cs, ipcp_value *src_val,
148738fd1498Szrj 				 int src_idx, HOST_WIDE_INT offset)
148838fd1498Szrj {
148938fd1498Szrj   ipcp_value_source<valtype> *src;
149038fd1498Szrj 
149138fd1498Szrj   src = new (ipcp_sources_pool.allocate ()) ipcp_value_source<valtype>;
149238fd1498Szrj   src->offset = offset;
149338fd1498Szrj   src->cs = cs;
149438fd1498Szrj   src->val = src_val;
149538fd1498Szrj   src->index = src_idx;
149638fd1498Szrj 
149738fd1498Szrj   src->next = sources;
149838fd1498Szrj   sources = src;
149938fd1498Szrj }
150038fd1498Szrj 
150138fd1498Szrj /* Allocate a new ipcp_value holding a tree constant, initialize its value to
150238fd1498Szrj    SOURCE and clear all other fields.  */
150338fd1498Szrj 
150438fd1498Szrj static ipcp_value<tree> *
allocate_and_init_ipcp_value(tree source)150538fd1498Szrj allocate_and_init_ipcp_value (tree source)
150638fd1498Szrj {
150738fd1498Szrj   ipcp_value<tree> *val;
150838fd1498Szrj 
150938fd1498Szrj   val = new (ipcp_cst_values_pool.allocate ()) ipcp_value<tree>();
151038fd1498Szrj   val->value = source;
151138fd1498Szrj   return val;
151238fd1498Szrj }
151338fd1498Szrj 
151438fd1498Szrj /* Allocate a new ipcp_value holding a polymorphic context, initialize its
151538fd1498Szrj    value to SOURCE and clear all other fields.  */
151638fd1498Szrj 
151738fd1498Szrj static ipcp_value<ipa_polymorphic_call_context> *
allocate_and_init_ipcp_value(ipa_polymorphic_call_context source)151838fd1498Szrj allocate_and_init_ipcp_value (ipa_polymorphic_call_context source)
151938fd1498Szrj {
152038fd1498Szrj   ipcp_value<ipa_polymorphic_call_context> *val;
152138fd1498Szrj 
152238fd1498Szrj   // TODO
152338fd1498Szrj   val = new (ipcp_poly_ctx_values_pool.allocate ())
152438fd1498Szrj     ipcp_value<ipa_polymorphic_call_context>();
152538fd1498Szrj   val->value = source;
152638fd1498Szrj   return val;
152738fd1498Szrj }
152838fd1498Szrj 
152938fd1498Szrj /* Try to add NEWVAL to LAT, potentially creating a new ipcp_value for it.  CS,
153038fd1498Szrj    SRC_VAL SRC_INDEX and OFFSET are meant for add_source and have the same
153138fd1498Szrj    meaning.  OFFSET -1 means the source is scalar and not a part of an
153238fd1498Szrj    aggregate.  */
153338fd1498Szrj 
153438fd1498Szrj template <typename valtype>
153538fd1498Szrj bool
add_value(valtype newval,cgraph_edge * cs,ipcp_value<valtype> * src_val,int src_idx,HOST_WIDE_INT offset)153638fd1498Szrj ipcp_lattice<valtype>::add_value (valtype newval, cgraph_edge *cs,
153738fd1498Szrj 				  ipcp_value<valtype> *src_val,
153838fd1498Szrj 				  int src_idx, HOST_WIDE_INT offset)
153938fd1498Szrj {
154038fd1498Szrj   ipcp_value<valtype> *val;
154138fd1498Szrj 
154238fd1498Szrj   if (bottom)
154338fd1498Szrj     return false;
154438fd1498Szrj 
154538fd1498Szrj   for (val = values; val; val = val->next)
154638fd1498Szrj     if (values_equal_for_ipcp_p (val->value, newval))
154738fd1498Szrj       {
154838fd1498Szrj 	if (ipa_edge_within_scc (cs))
154938fd1498Szrj 	  {
155038fd1498Szrj 	    ipcp_value_source<valtype> *s;
155138fd1498Szrj 	    for (s = val->sources; s; s = s->next)
155238fd1498Szrj 	      if (s->cs == cs)
155338fd1498Szrj 		break;
155438fd1498Szrj 	    if (s)
155538fd1498Szrj 	      return false;
155638fd1498Szrj 	  }
155738fd1498Szrj 
155838fd1498Szrj 	val->add_source (cs, src_val, src_idx, offset);
155938fd1498Szrj 	return false;
156038fd1498Szrj       }
156138fd1498Szrj 
156238fd1498Szrj   if (values_count == PARAM_VALUE (PARAM_IPA_CP_VALUE_LIST_SIZE))
156338fd1498Szrj     {
156438fd1498Szrj       /* We can only free sources, not the values themselves, because sources
156538fd1498Szrj 	 of other values in this SCC might point to them.   */
156638fd1498Szrj       for (val = values; val; val = val->next)
156738fd1498Szrj 	{
156838fd1498Szrj 	  while (val->sources)
156938fd1498Szrj 	    {
157038fd1498Szrj 	      ipcp_value_source<valtype> *src = val->sources;
157138fd1498Szrj 	      val->sources = src->next;
157238fd1498Szrj 	      ipcp_sources_pool.remove ((ipcp_value_source<tree>*)src);
157338fd1498Szrj 	    }
157438fd1498Szrj 	}
157538fd1498Szrj 
157638fd1498Szrj       values = NULL;
157738fd1498Szrj       return set_to_bottom ();
157838fd1498Szrj     }
157938fd1498Szrj 
158038fd1498Szrj   values_count++;
158138fd1498Szrj   val = allocate_and_init_ipcp_value (newval);
158238fd1498Szrj   val->add_source (cs, src_val, src_idx, offset);
158338fd1498Szrj   val->next = values;
158438fd1498Szrj   values = val;
158538fd1498Szrj   return true;
158638fd1498Szrj }
158738fd1498Szrj 
158838fd1498Szrj /* Propagate values through a pass-through jump function JFUNC associated with
158938fd1498Szrj    edge CS, taking values from SRC_LAT and putting them into DEST_LAT.  SRC_IDX
159038fd1498Szrj    is the index of the source parameter.  PARM_TYPE is the type of the
159138fd1498Szrj    parameter to which the result is passed.  */
159238fd1498Szrj 
159338fd1498Szrj static bool
propagate_vals_across_pass_through(cgraph_edge * cs,ipa_jump_func * jfunc,ipcp_lattice<tree> * src_lat,ipcp_lattice<tree> * dest_lat,int src_idx,tree parm_type)159438fd1498Szrj propagate_vals_across_pass_through (cgraph_edge *cs, ipa_jump_func *jfunc,
159538fd1498Szrj 				    ipcp_lattice<tree> *src_lat,
159638fd1498Szrj 				    ipcp_lattice<tree> *dest_lat, int src_idx,
159738fd1498Szrj 				    tree parm_type)
159838fd1498Szrj {
159938fd1498Szrj   ipcp_value<tree> *src_val;
160038fd1498Szrj   bool ret = false;
160138fd1498Szrj 
160238fd1498Szrj   /* Do not create new values when propagating within an SCC because if there
160338fd1498Szrj      are arithmetic functions with circular dependencies, there is infinite
160438fd1498Szrj      number of them and we would just make lattices bottom.  If this condition
160538fd1498Szrj      is ever relaxed we have to detect self-feeding recursive calls in
160638fd1498Szrj      cgraph_edge_brings_value_p in a smarter way.  */
160738fd1498Szrj   if ((ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR)
160838fd1498Szrj       && ipa_edge_within_scc (cs))
160938fd1498Szrj     ret = dest_lat->set_contains_variable ();
161038fd1498Szrj   else
161138fd1498Szrj     for (src_val = src_lat->values; src_val; src_val = src_val->next)
161238fd1498Szrj       {
161338fd1498Szrj 	tree cstval = ipa_get_jf_pass_through_result (jfunc, src_val->value,
161438fd1498Szrj 						      parm_type);
161538fd1498Szrj 
161638fd1498Szrj 	if (cstval)
161738fd1498Szrj 	  ret |= dest_lat->add_value (cstval, cs, src_val, src_idx);
161838fd1498Szrj 	else
161938fd1498Szrj 	  ret |= dest_lat->set_contains_variable ();
162038fd1498Szrj       }
162138fd1498Szrj 
162238fd1498Szrj   return ret;
162338fd1498Szrj }
162438fd1498Szrj 
162538fd1498Szrj /* Propagate values through an ancestor jump function JFUNC associated with
162638fd1498Szrj    edge CS, taking values from SRC_LAT and putting them into DEST_LAT.  SRC_IDX
162738fd1498Szrj    is the index of the source parameter.  */
162838fd1498Szrj 
162938fd1498Szrj static bool
propagate_vals_across_ancestor(struct cgraph_edge * cs,struct ipa_jump_func * jfunc,ipcp_lattice<tree> * src_lat,ipcp_lattice<tree> * dest_lat,int src_idx)163038fd1498Szrj propagate_vals_across_ancestor (struct cgraph_edge *cs,
163138fd1498Szrj 				struct ipa_jump_func *jfunc,
163238fd1498Szrj 				ipcp_lattice<tree> *src_lat,
163338fd1498Szrj 				ipcp_lattice<tree> *dest_lat, int src_idx)
163438fd1498Szrj {
163538fd1498Szrj   ipcp_value<tree> *src_val;
163638fd1498Szrj   bool ret = false;
163738fd1498Szrj 
163838fd1498Szrj   if (ipa_edge_within_scc (cs))
163938fd1498Szrj     return dest_lat->set_contains_variable ();
164038fd1498Szrj 
164138fd1498Szrj   for (src_val = src_lat->values; src_val; src_val = src_val->next)
164238fd1498Szrj     {
164338fd1498Szrj       tree t = ipa_get_jf_ancestor_result (jfunc, src_val->value);
164438fd1498Szrj 
164538fd1498Szrj       if (t)
164638fd1498Szrj 	ret |= dest_lat->add_value (t, cs, src_val, src_idx);
164738fd1498Szrj       else
164838fd1498Szrj 	ret |= dest_lat->set_contains_variable ();
164938fd1498Szrj     }
165038fd1498Szrj 
165138fd1498Szrj   return ret;
165238fd1498Szrj }
165338fd1498Szrj 
165438fd1498Szrj /* Propagate scalar values across jump function JFUNC that is associated with
165538fd1498Szrj    edge CS and put the values into DEST_LAT.  PARM_TYPE is the type of the
165638fd1498Szrj    parameter to which the result is passed.  */
165738fd1498Szrj 
165838fd1498Szrj static bool
propagate_scalar_across_jump_function(struct cgraph_edge * cs,struct ipa_jump_func * jfunc,ipcp_lattice<tree> * dest_lat,tree param_type)165938fd1498Szrj propagate_scalar_across_jump_function (struct cgraph_edge *cs,
166038fd1498Szrj 				       struct ipa_jump_func *jfunc,
166138fd1498Szrj 				       ipcp_lattice<tree> *dest_lat,
166238fd1498Szrj 				       tree param_type)
166338fd1498Szrj {
166438fd1498Szrj   if (dest_lat->bottom)
166538fd1498Szrj     return false;
166638fd1498Szrj 
166738fd1498Szrj   if (jfunc->type == IPA_JF_CONST)
166838fd1498Szrj     {
166938fd1498Szrj       tree val = ipa_get_jf_constant (jfunc);
167038fd1498Szrj       return dest_lat->add_value (val, cs, NULL, 0);
167138fd1498Szrj     }
167238fd1498Szrj   else if (jfunc->type == IPA_JF_PASS_THROUGH
167338fd1498Szrj 	   || jfunc->type == IPA_JF_ANCESTOR)
167438fd1498Szrj     {
167538fd1498Szrj       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
167638fd1498Szrj       ipcp_lattice<tree> *src_lat;
167738fd1498Szrj       int src_idx;
167838fd1498Szrj       bool ret;
167938fd1498Szrj 
168038fd1498Szrj       if (jfunc->type == IPA_JF_PASS_THROUGH)
168138fd1498Szrj 	src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
168238fd1498Szrj       else
168338fd1498Szrj 	src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
168438fd1498Szrj 
168538fd1498Szrj       src_lat = ipa_get_scalar_lat (caller_info, src_idx);
168638fd1498Szrj       if (src_lat->bottom)
168738fd1498Szrj 	return dest_lat->set_contains_variable ();
168838fd1498Szrj 
168938fd1498Szrj       /* If we would need to clone the caller and cannot, do not propagate.  */
169038fd1498Szrj       if (!ipcp_versionable_function_p (cs->caller)
169138fd1498Szrj 	  && (src_lat->contains_variable
169238fd1498Szrj 	      || (src_lat->values_count > 1)))
169338fd1498Szrj 	return dest_lat->set_contains_variable ();
169438fd1498Szrj 
169538fd1498Szrj       if (jfunc->type == IPA_JF_PASS_THROUGH)
169638fd1498Szrj 	ret = propagate_vals_across_pass_through (cs, jfunc, src_lat,
169738fd1498Szrj 						  dest_lat, src_idx, param_type);
169838fd1498Szrj       else
169938fd1498Szrj 	ret = propagate_vals_across_ancestor (cs, jfunc, src_lat, dest_lat,
170038fd1498Szrj 					      src_idx);
170138fd1498Szrj 
170238fd1498Szrj       if (src_lat->contains_variable)
170338fd1498Szrj 	ret |= dest_lat->set_contains_variable ();
170438fd1498Szrj 
170538fd1498Szrj       return ret;
170638fd1498Szrj     }
170738fd1498Szrj 
170838fd1498Szrj   /* TODO: We currently do not handle member method pointers in IPA-CP (we only
170938fd1498Szrj      use it for indirect inlining), we should propagate them too.  */
171038fd1498Szrj   return dest_lat->set_contains_variable ();
171138fd1498Szrj }
171238fd1498Szrj 
171338fd1498Szrj /* Propagate scalar values across jump function JFUNC that is associated with
171438fd1498Szrj    edge CS and describes argument IDX and put the values into DEST_LAT.  */
171538fd1498Szrj 
171638fd1498Szrj static bool
propagate_context_across_jump_function(cgraph_edge * cs,ipa_jump_func * jfunc,int idx,ipcp_lattice<ipa_polymorphic_call_context> * dest_lat)171738fd1498Szrj propagate_context_across_jump_function (cgraph_edge *cs,
171838fd1498Szrj 			  ipa_jump_func *jfunc, int idx,
171938fd1498Szrj 			  ipcp_lattice<ipa_polymorphic_call_context> *dest_lat)
172038fd1498Szrj {
172138fd1498Szrj   ipa_edge_args *args = IPA_EDGE_REF (cs);
172238fd1498Szrj   if (dest_lat->bottom)
172338fd1498Szrj     return false;
172438fd1498Szrj   bool ret = false;
172538fd1498Szrj   bool added_sth = false;
172638fd1498Szrj   bool type_preserved = true;
172738fd1498Szrj 
172838fd1498Szrj   ipa_polymorphic_call_context edge_ctx, *edge_ctx_ptr
172938fd1498Szrj     = ipa_get_ith_polymorhic_call_context (args, idx);
173038fd1498Szrj 
173138fd1498Szrj   if (edge_ctx_ptr)
173238fd1498Szrj     edge_ctx = *edge_ctx_ptr;
173338fd1498Szrj 
173438fd1498Szrj   if (jfunc->type == IPA_JF_PASS_THROUGH
173538fd1498Szrj       || jfunc->type == IPA_JF_ANCESTOR)
173638fd1498Szrj     {
173738fd1498Szrj       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
173838fd1498Szrj       int src_idx;
173938fd1498Szrj       ipcp_lattice<ipa_polymorphic_call_context> *src_lat;
174038fd1498Szrj 
174138fd1498Szrj       /* TODO: Once we figure out how to propagate speculations, it will
174238fd1498Szrj 	 probably be a good idea to switch to speculation if type_preserved is
174338fd1498Szrj 	 not set instead of punting.  */
174438fd1498Szrj       if (jfunc->type == IPA_JF_PASS_THROUGH)
174538fd1498Szrj 	{
174638fd1498Szrj 	  if (ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR)
174738fd1498Szrj 	    goto prop_fail;
174838fd1498Szrj 	  type_preserved = ipa_get_jf_pass_through_type_preserved (jfunc);
174938fd1498Szrj 	  src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
175038fd1498Szrj 	}
175138fd1498Szrj       else
175238fd1498Szrj 	{
175338fd1498Szrj 	  type_preserved = ipa_get_jf_ancestor_type_preserved (jfunc);
175438fd1498Szrj 	  src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
175538fd1498Szrj 	}
175638fd1498Szrj 
175738fd1498Szrj       src_lat = ipa_get_poly_ctx_lat (caller_info, src_idx);
175838fd1498Szrj       /* If we would need to clone the caller and cannot, do not propagate.  */
175938fd1498Szrj       if (!ipcp_versionable_function_p (cs->caller)
176038fd1498Szrj 	  && (src_lat->contains_variable
176138fd1498Szrj 	      || (src_lat->values_count > 1)))
176238fd1498Szrj 	goto prop_fail;
176338fd1498Szrj 
176438fd1498Szrj       ipcp_value<ipa_polymorphic_call_context> *src_val;
176538fd1498Szrj       for (src_val = src_lat->values; src_val; src_val = src_val->next)
176638fd1498Szrj 	{
176738fd1498Szrj 	  ipa_polymorphic_call_context cur = src_val->value;
176838fd1498Szrj 
176938fd1498Szrj 	  if (!type_preserved)
177038fd1498Szrj 	    cur.possible_dynamic_type_change (cs->in_polymorphic_cdtor);
177138fd1498Szrj 	  if (jfunc->type == IPA_JF_ANCESTOR)
177238fd1498Szrj 	    cur.offset_by (ipa_get_jf_ancestor_offset (jfunc));
177338fd1498Szrj 	  /* TODO: In cases we know how the context is going to be used,
177438fd1498Szrj 	     we can improve the result by passing proper OTR_TYPE.  */
177538fd1498Szrj 	  cur.combine_with (edge_ctx);
177638fd1498Szrj 	  if (!cur.useless_p ())
177738fd1498Szrj 	    {
177838fd1498Szrj 	      if (src_lat->contains_variable
177938fd1498Szrj 		  && !edge_ctx.equal_to (cur))
178038fd1498Szrj 		ret |= dest_lat->set_contains_variable ();
178138fd1498Szrj 	      ret |= dest_lat->add_value (cur, cs, src_val, src_idx);
178238fd1498Szrj 	      added_sth = true;
178338fd1498Szrj 	    }
178438fd1498Szrj 	}
178538fd1498Szrj 
178638fd1498Szrj     }
178738fd1498Szrj 
178838fd1498Szrj  prop_fail:
178938fd1498Szrj   if (!added_sth)
179038fd1498Szrj     {
179138fd1498Szrj       if (!edge_ctx.useless_p ())
179238fd1498Szrj 	ret |= dest_lat->add_value (edge_ctx, cs);
179338fd1498Szrj       else
179438fd1498Szrj 	ret |= dest_lat->set_contains_variable ();
179538fd1498Szrj     }
179638fd1498Szrj 
179738fd1498Szrj   return ret;
179838fd1498Szrj }
179938fd1498Szrj 
180038fd1498Szrj /* Propagate bits across jfunc that is associated with
180138fd1498Szrj    edge cs and update dest_lattice accordingly.  */
180238fd1498Szrj 
180338fd1498Szrj bool
propagate_bits_across_jump_function(cgraph_edge * cs,int idx,ipa_jump_func * jfunc,ipcp_bits_lattice * dest_lattice)180438fd1498Szrj propagate_bits_across_jump_function (cgraph_edge *cs, int idx,
180538fd1498Szrj 				     ipa_jump_func *jfunc,
180638fd1498Szrj 				     ipcp_bits_lattice *dest_lattice)
180738fd1498Szrj {
180838fd1498Szrj   if (dest_lattice->bottom_p ())
180938fd1498Szrj     return false;
181038fd1498Szrj 
181138fd1498Szrj   enum availability availability;
181238fd1498Szrj   cgraph_node *callee = cs->callee->function_symbol (&availability);
181338fd1498Szrj   struct ipa_node_params *callee_info = IPA_NODE_REF (callee);
181438fd1498Szrj   tree parm_type = ipa_get_type (callee_info, idx);
181538fd1498Szrj 
181638fd1498Szrj   /* For K&R C programs, ipa_get_type() could return NULL_TREE.  Avoid the
181738fd1498Szrj      transform for these cases.  Similarly, we can have bad type mismatches
181838fd1498Szrj      with LTO, avoid doing anything with those too.  */
181938fd1498Szrj   if (!parm_type
182038fd1498Szrj       || (!INTEGRAL_TYPE_P (parm_type) && !POINTER_TYPE_P (parm_type)))
182138fd1498Szrj     {
182238fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
182338fd1498Szrj 	fprintf (dump_file, "Setting dest_lattice to bottom, because type of "
182438fd1498Szrj 		 "param %i of %s is NULL or unsuitable for bits propagation\n",
182538fd1498Szrj 		 idx, cs->callee->name ());
182638fd1498Szrj 
182738fd1498Szrj       return dest_lattice->set_to_bottom ();
182838fd1498Szrj     }
182938fd1498Szrj 
183038fd1498Szrj   unsigned precision = TYPE_PRECISION (parm_type);
183138fd1498Szrj   signop sgn = TYPE_SIGN (parm_type);
183238fd1498Szrj 
183338fd1498Szrj   if (jfunc->type == IPA_JF_PASS_THROUGH
183438fd1498Szrj       || jfunc->type == IPA_JF_ANCESTOR)
183538fd1498Szrj     {
183638fd1498Szrj       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
183738fd1498Szrj       tree operand = NULL_TREE;
183838fd1498Szrj       enum tree_code code;
183938fd1498Szrj       unsigned src_idx;
184038fd1498Szrj 
184138fd1498Szrj       if (jfunc->type == IPA_JF_PASS_THROUGH)
184238fd1498Szrj 	{
184338fd1498Szrj 	  code = ipa_get_jf_pass_through_operation (jfunc);
184438fd1498Szrj 	  src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
184538fd1498Szrj 	  if (code != NOP_EXPR)
184638fd1498Szrj 	    operand = ipa_get_jf_pass_through_operand (jfunc);
184738fd1498Szrj 	}
184838fd1498Szrj       else
184938fd1498Szrj 	{
185038fd1498Szrj 	  code = POINTER_PLUS_EXPR;
185138fd1498Szrj 	  src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
185238fd1498Szrj 	  unsigned HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc) / BITS_PER_UNIT;
185338fd1498Szrj 	  operand = build_int_cstu (size_type_node, offset);
185438fd1498Szrj 	}
185538fd1498Szrj 
185638fd1498Szrj       struct ipcp_param_lattices *src_lats
185738fd1498Szrj 	= ipa_get_parm_lattices (caller_info, src_idx);
185838fd1498Szrj 
185938fd1498Szrj       /* Try to propagate bits if src_lattice is bottom, but jfunc is known.
186038fd1498Szrj 	 for eg consider:
186138fd1498Szrj 	 int f(int x)
186238fd1498Szrj 	 {
186338fd1498Szrj 	   g (x & 0xff);
186438fd1498Szrj 	 }
186538fd1498Szrj 	 Assume lattice for x is bottom, however we can still propagate
186638fd1498Szrj 	 result of x & 0xff == 0xff, which gets computed during ccp1 pass
186738fd1498Szrj 	 and we store it in jump function during analysis stage.  */
186838fd1498Szrj 
186938fd1498Szrj       if (src_lats->bits_lattice.bottom_p ()
187038fd1498Szrj 	  && jfunc->bits)
187138fd1498Szrj 	return dest_lattice->meet_with (jfunc->bits->value, jfunc->bits->mask,
187238fd1498Szrj 					precision);
187338fd1498Szrj       else
187438fd1498Szrj 	return dest_lattice->meet_with (src_lats->bits_lattice, precision, sgn,
187538fd1498Szrj 					code, operand);
187638fd1498Szrj     }
187738fd1498Szrj 
187838fd1498Szrj   else if (jfunc->type == IPA_JF_ANCESTOR)
187938fd1498Szrj     return dest_lattice->set_to_bottom ();
188038fd1498Szrj   else if (jfunc->bits)
188138fd1498Szrj     return dest_lattice->meet_with (jfunc->bits->value, jfunc->bits->mask,
188238fd1498Szrj 				    precision);
188338fd1498Szrj   else
188438fd1498Szrj     return dest_lattice->set_to_bottom ();
188538fd1498Szrj }
188638fd1498Szrj 
188738fd1498Szrj /* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
188838fd1498Szrj    DST_TYPE on value range in SRC_VR and store it to DST_VR.  Return true if
188938fd1498Szrj    the result is a range or an anti-range.  */
189038fd1498Szrj 
189138fd1498Szrj static bool
ipa_vr_operation_and_type_effects(value_range * dst_vr,value_range * src_vr,enum tree_code operation,tree dst_type,tree src_type)189238fd1498Szrj ipa_vr_operation_and_type_effects (value_range *dst_vr, value_range *src_vr,
189338fd1498Szrj 				   enum tree_code operation,
189438fd1498Szrj 				   tree dst_type, tree src_type)
189538fd1498Szrj {
189638fd1498Szrj   memset (dst_vr, 0, sizeof (*dst_vr));
189738fd1498Szrj   extract_range_from_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
189838fd1498Szrj   if (dst_vr->type == VR_RANGE || dst_vr->type == VR_ANTI_RANGE)
189938fd1498Szrj     return true;
190038fd1498Szrj   else
190138fd1498Szrj     return false;
190238fd1498Szrj }
190338fd1498Szrj 
190438fd1498Szrj /* Propagate value range across jump function JFUNC that is associated with
190538fd1498Szrj    edge CS with param of callee of PARAM_TYPE and update DEST_PLATS
190638fd1498Szrj    accordingly.  */
190738fd1498Szrj 
190838fd1498Szrj static bool
propagate_vr_across_jump_function(cgraph_edge * cs,ipa_jump_func * jfunc,struct ipcp_param_lattices * dest_plats,tree param_type)190938fd1498Szrj propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
191038fd1498Szrj 				   struct ipcp_param_lattices *dest_plats,
191138fd1498Szrj 				   tree param_type)
191238fd1498Szrj {
191338fd1498Szrj   ipcp_vr_lattice *dest_lat = &dest_plats->m_value_range;
191438fd1498Szrj 
191538fd1498Szrj   if (dest_lat->bottom_p ())
191638fd1498Szrj     return false;
191738fd1498Szrj 
191838fd1498Szrj   if (!param_type
191938fd1498Szrj       || (!INTEGRAL_TYPE_P (param_type)
192038fd1498Szrj 	  && !POINTER_TYPE_P (param_type)))
192138fd1498Szrj     return dest_lat->set_to_bottom ();
192238fd1498Szrj 
192338fd1498Szrj   if (jfunc->type == IPA_JF_PASS_THROUGH)
192438fd1498Szrj     {
192538fd1498Szrj       enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
192638fd1498Szrj 
192738fd1498Szrj       if (TREE_CODE_CLASS (operation) == tcc_unary)
192838fd1498Szrj 	{
192938fd1498Szrj 	  struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
193038fd1498Szrj 	  int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
193138fd1498Szrj 	  tree operand_type = ipa_get_type (caller_info, src_idx);
193238fd1498Szrj 	  struct ipcp_param_lattices *src_lats
193338fd1498Szrj 	    = ipa_get_parm_lattices (caller_info, src_idx);
193438fd1498Szrj 
193538fd1498Szrj 	  if (src_lats->m_value_range.bottom_p ())
193638fd1498Szrj 	    return dest_lat->set_to_bottom ();
193738fd1498Szrj 	  value_range vr;
193838fd1498Szrj 	  if (ipa_vr_operation_and_type_effects (&vr,
193938fd1498Szrj 						 &src_lats->m_value_range.m_vr,
194038fd1498Szrj 						 operation, param_type,
194138fd1498Szrj 						 operand_type))
194238fd1498Szrj 	    return dest_lat->meet_with (&vr);
194338fd1498Szrj 	}
194438fd1498Szrj     }
194538fd1498Szrj   else if (jfunc->type == IPA_JF_CONST)
194638fd1498Szrj     {
194738fd1498Szrj       tree val = ipa_get_jf_constant (jfunc);
194838fd1498Szrj       if (TREE_CODE (val) == INTEGER_CST)
194938fd1498Szrj 	{
195038fd1498Szrj 	  val = fold_convert (param_type, val);
195138fd1498Szrj 	  if (TREE_OVERFLOW_P (val))
195238fd1498Szrj 	    val = drop_tree_overflow (val);
195338fd1498Szrj 
195438fd1498Szrj 	  value_range tmpvr;
195538fd1498Szrj 	  memset (&tmpvr, 0, sizeof (tmpvr));
195638fd1498Szrj 	  tmpvr.type = VR_RANGE;
195738fd1498Szrj 	  tmpvr.min = val;
195838fd1498Szrj 	  tmpvr.max = val;
195938fd1498Szrj 	  return dest_lat->meet_with (&tmpvr);
196038fd1498Szrj 	}
196138fd1498Szrj     }
196238fd1498Szrj 
196338fd1498Szrj   value_range vr;
196438fd1498Szrj   if (jfunc->m_vr
196538fd1498Szrj       && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
196638fd1498Szrj 					    param_type,
196738fd1498Szrj 					    TREE_TYPE (jfunc->m_vr->min)))
196838fd1498Szrj     return dest_lat->meet_with (&vr);
196938fd1498Szrj   else
197038fd1498Szrj     return dest_lat->set_to_bottom ();
197138fd1498Szrj }
197238fd1498Szrj 
197338fd1498Szrj /* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
197438fd1498Szrj    NEW_AGGS_BY_REF and if not, mark all aggs as bottoms and return true (in all
197538fd1498Szrj    other cases, return false).  If there are no aggregate items, set
197638fd1498Szrj    aggs_by_ref to NEW_AGGS_BY_REF.  */
197738fd1498Szrj 
197838fd1498Szrj static bool
set_check_aggs_by_ref(struct ipcp_param_lattices * dest_plats,bool new_aggs_by_ref)197938fd1498Szrj set_check_aggs_by_ref (struct ipcp_param_lattices *dest_plats,
198038fd1498Szrj 		       bool new_aggs_by_ref)
198138fd1498Szrj {
198238fd1498Szrj   if (dest_plats->aggs)
198338fd1498Szrj     {
198438fd1498Szrj       if (dest_plats->aggs_by_ref != new_aggs_by_ref)
198538fd1498Szrj 	{
198638fd1498Szrj 	  set_agg_lats_to_bottom (dest_plats);
198738fd1498Szrj 	  return true;
198838fd1498Szrj 	}
198938fd1498Szrj     }
199038fd1498Szrj   else
199138fd1498Szrj     dest_plats->aggs_by_ref = new_aggs_by_ref;
199238fd1498Szrj   return false;
199338fd1498Szrj }
199438fd1498Szrj 
199538fd1498Szrj /* Walk aggregate lattices in DEST_PLATS from ***AGLAT on, until ***aglat is an
199638fd1498Szrj    already existing lattice for the given OFFSET and SIZE, marking all skipped
199738fd1498Szrj    lattices as containing variable and checking for overlaps.  If there is no
199838fd1498Szrj    already existing lattice for the OFFSET and VAL_SIZE, create one, initialize
199938fd1498Szrj    it with offset, size and contains_variable to PRE_EXISTING, and return true,
200038fd1498Szrj    unless there are too many already.  If there are two many, return false.  If
200138fd1498Szrj    there are overlaps turn whole DEST_PLATS to bottom and return false.  If any
200238fd1498Szrj    skipped lattices were newly marked as containing variable, set *CHANGE to
200338fd1498Szrj    true.  */
200438fd1498Szrj 
200538fd1498Szrj static bool
merge_agg_lats_step(struct ipcp_param_lattices * dest_plats,HOST_WIDE_INT offset,HOST_WIDE_INT val_size,struct ipcp_agg_lattice *** aglat,bool pre_existing,bool * change)200638fd1498Szrj merge_agg_lats_step (struct ipcp_param_lattices *dest_plats,
200738fd1498Szrj 		     HOST_WIDE_INT offset, HOST_WIDE_INT val_size,
200838fd1498Szrj 		     struct ipcp_agg_lattice ***aglat,
200938fd1498Szrj 		     bool pre_existing, bool *change)
201038fd1498Szrj {
201138fd1498Szrj   gcc_checking_assert (offset >= 0);
201238fd1498Szrj 
201338fd1498Szrj   while (**aglat && (**aglat)->offset < offset)
201438fd1498Szrj     {
201538fd1498Szrj       if ((**aglat)->offset + (**aglat)->size > offset)
201638fd1498Szrj 	{
201738fd1498Szrj 	  set_agg_lats_to_bottom (dest_plats);
201838fd1498Szrj 	  return false;
201938fd1498Szrj 	}
202038fd1498Szrj       *change |= (**aglat)->set_contains_variable ();
202138fd1498Szrj       *aglat = &(**aglat)->next;
202238fd1498Szrj     }
202338fd1498Szrj 
202438fd1498Szrj   if (**aglat && (**aglat)->offset == offset)
202538fd1498Szrj     {
202638fd1498Szrj       if ((**aglat)->size != val_size
202738fd1498Szrj 	  || ((**aglat)->next
202838fd1498Szrj 	      && (**aglat)->next->offset < offset + val_size))
202938fd1498Szrj 	{
203038fd1498Szrj 	  set_agg_lats_to_bottom (dest_plats);
203138fd1498Szrj 	  return false;
203238fd1498Szrj 	}
203338fd1498Szrj       gcc_checking_assert (!(**aglat)->next
203438fd1498Szrj 			   || (**aglat)->next->offset >= offset + val_size);
203538fd1498Szrj       return true;
203638fd1498Szrj     }
203738fd1498Szrj   else
203838fd1498Szrj     {
203938fd1498Szrj       struct ipcp_agg_lattice *new_al;
204038fd1498Szrj 
204138fd1498Szrj       if (**aglat && (**aglat)->offset < offset + val_size)
204238fd1498Szrj 	{
204338fd1498Szrj 	  set_agg_lats_to_bottom (dest_plats);
204438fd1498Szrj 	  return false;
204538fd1498Szrj 	}
204638fd1498Szrj       if (dest_plats->aggs_count == PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS))
204738fd1498Szrj 	return false;
204838fd1498Szrj       dest_plats->aggs_count++;
204938fd1498Szrj       new_al = ipcp_agg_lattice_pool.allocate ();
205038fd1498Szrj       memset (new_al, 0, sizeof (*new_al));
205138fd1498Szrj 
205238fd1498Szrj       new_al->offset = offset;
205338fd1498Szrj       new_al->size = val_size;
205438fd1498Szrj       new_al->contains_variable = pre_existing;
205538fd1498Szrj 
205638fd1498Szrj       new_al->next = **aglat;
205738fd1498Szrj       **aglat = new_al;
205838fd1498Szrj       return true;
205938fd1498Szrj     }
206038fd1498Szrj }
206138fd1498Szrj 
206238fd1498Szrj /* Set all AGLAT and all other aggregate lattices reachable by next pointers as
206338fd1498Szrj    containing an unknown value.  */
206438fd1498Szrj 
206538fd1498Szrj static bool
set_chain_of_aglats_contains_variable(struct ipcp_agg_lattice * aglat)206638fd1498Szrj set_chain_of_aglats_contains_variable (struct ipcp_agg_lattice *aglat)
206738fd1498Szrj {
206838fd1498Szrj   bool ret = false;
206938fd1498Szrj   while (aglat)
207038fd1498Szrj     {
207138fd1498Szrj       ret |= aglat->set_contains_variable ();
207238fd1498Szrj       aglat = aglat->next;
207338fd1498Szrj     }
207438fd1498Szrj   return ret;
207538fd1498Szrj }
207638fd1498Szrj 
207738fd1498Szrj /* Merge existing aggregate lattices in SRC_PLATS to DEST_PLATS, subtracting
207838fd1498Szrj    DELTA_OFFSET.  CS is the call graph edge and SRC_IDX the index of the source
207938fd1498Szrj    parameter used for lattice value sources.  Return true if DEST_PLATS changed
208038fd1498Szrj    in any way.  */
208138fd1498Szrj 
208238fd1498Szrj static bool
merge_aggregate_lattices(struct cgraph_edge * cs,struct ipcp_param_lattices * dest_plats,struct ipcp_param_lattices * src_plats,int src_idx,HOST_WIDE_INT offset_delta)208338fd1498Szrj merge_aggregate_lattices (struct cgraph_edge *cs,
208438fd1498Szrj 			  struct ipcp_param_lattices *dest_plats,
208538fd1498Szrj 			  struct ipcp_param_lattices *src_plats,
208638fd1498Szrj 			  int src_idx, HOST_WIDE_INT offset_delta)
208738fd1498Szrj {
208838fd1498Szrj   bool pre_existing = dest_plats->aggs != NULL;
208938fd1498Szrj   struct ipcp_agg_lattice **dst_aglat;
209038fd1498Szrj   bool ret = false;
209138fd1498Szrj 
209238fd1498Szrj   if (set_check_aggs_by_ref (dest_plats, src_plats->aggs_by_ref))
209338fd1498Szrj     return true;
209438fd1498Szrj   if (src_plats->aggs_bottom)
209538fd1498Szrj     return set_agg_lats_contain_variable (dest_plats);
209638fd1498Szrj   if (src_plats->aggs_contain_variable)
209738fd1498Szrj     ret |= set_agg_lats_contain_variable (dest_plats);
209838fd1498Szrj   dst_aglat = &dest_plats->aggs;
209938fd1498Szrj 
210038fd1498Szrj   for (struct ipcp_agg_lattice *src_aglat = src_plats->aggs;
210138fd1498Szrj        src_aglat;
210238fd1498Szrj        src_aglat = src_aglat->next)
210338fd1498Szrj     {
210438fd1498Szrj       HOST_WIDE_INT new_offset = src_aglat->offset - offset_delta;
210538fd1498Szrj 
210638fd1498Szrj       if (new_offset < 0)
210738fd1498Szrj 	continue;
210838fd1498Szrj       if (merge_agg_lats_step (dest_plats, new_offset, src_aglat->size,
210938fd1498Szrj 			       &dst_aglat, pre_existing, &ret))
211038fd1498Szrj 	{
211138fd1498Szrj 	  struct ipcp_agg_lattice *new_al = *dst_aglat;
211238fd1498Szrj 
211338fd1498Szrj 	  dst_aglat = &(*dst_aglat)->next;
211438fd1498Szrj 	  if (src_aglat->bottom)
211538fd1498Szrj 	    {
211638fd1498Szrj 	      ret |= new_al->set_contains_variable ();
211738fd1498Szrj 	      continue;
211838fd1498Szrj 	    }
211938fd1498Szrj 	  if (src_aglat->contains_variable)
212038fd1498Szrj 	    ret |= new_al->set_contains_variable ();
212138fd1498Szrj 	  for (ipcp_value<tree> *val = src_aglat->values;
212238fd1498Szrj 	       val;
212338fd1498Szrj 	       val = val->next)
212438fd1498Szrj 	    ret |= new_al->add_value (val->value, cs, val, src_idx,
212538fd1498Szrj 				      src_aglat->offset);
212638fd1498Szrj 	}
212738fd1498Szrj       else if (dest_plats->aggs_bottom)
212838fd1498Szrj 	return true;
212938fd1498Szrj     }
213038fd1498Szrj   ret |= set_chain_of_aglats_contains_variable (*dst_aglat);
213138fd1498Szrj   return ret;
213238fd1498Szrj }
213338fd1498Szrj 
213438fd1498Szrj /* Determine whether there is anything to propagate FROM SRC_PLATS through a
213538fd1498Szrj    pass-through JFUNC and if so, whether it has conform and conforms to the
213638fd1498Szrj    rules about propagating values passed by reference.  */
213738fd1498Szrj 
213838fd1498Szrj static bool
agg_pass_through_permissible_p(struct ipcp_param_lattices * src_plats,struct ipa_jump_func * jfunc)213938fd1498Szrj agg_pass_through_permissible_p (struct ipcp_param_lattices *src_plats,
214038fd1498Szrj 				struct ipa_jump_func *jfunc)
214138fd1498Szrj {
214238fd1498Szrj   return src_plats->aggs
214338fd1498Szrj     && (!src_plats->aggs_by_ref
214438fd1498Szrj 	|| ipa_get_jf_pass_through_agg_preserved (jfunc));
214538fd1498Szrj }
214638fd1498Szrj 
214738fd1498Szrj /* Propagate scalar values across jump function JFUNC that is associated with
214838fd1498Szrj    edge CS and put the values into DEST_LAT.  */
214938fd1498Szrj 
215038fd1498Szrj static bool
propagate_aggs_across_jump_function(struct cgraph_edge * cs,struct ipa_jump_func * jfunc,struct ipcp_param_lattices * dest_plats)215138fd1498Szrj propagate_aggs_across_jump_function (struct cgraph_edge *cs,
215238fd1498Szrj 				     struct ipa_jump_func *jfunc,
215338fd1498Szrj 				     struct ipcp_param_lattices *dest_plats)
215438fd1498Szrj {
215538fd1498Szrj   bool ret = false;
215638fd1498Szrj 
215738fd1498Szrj   if (dest_plats->aggs_bottom)
215838fd1498Szrj     return false;
215938fd1498Szrj 
216038fd1498Szrj   if (jfunc->type == IPA_JF_PASS_THROUGH
216138fd1498Szrj       && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
216238fd1498Szrj     {
216338fd1498Szrj       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
216438fd1498Szrj       int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
216538fd1498Szrj       struct ipcp_param_lattices *src_plats;
216638fd1498Szrj 
216738fd1498Szrj       src_plats = ipa_get_parm_lattices (caller_info, src_idx);
216838fd1498Szrj       if (agg_pass_through_permissible_p (src_plats, jfunc))
216938fd1498Szrj 	{
217038fd1498Szrj 	  /* Currently we do not produce clobber aggregate jump
217138fd1498Szrj 	     functions, replace with merging when we do.  */
217238fd1498Szrj 	  gcc_assert (!jfunc->agg.items);
217338fd1498Szrj 	  ret |= merge_aggregate_lattices (cs, dest_plats, src_plats,
217438fd1498Szrj 					   src_idx, 0);
217538fd1498Szrj 	}
217638fd1498Szrj       else
217738fd1498Szrj 	ret |= set_agg_lats_contain_variable (dest_plats);
217838fd1498Szrj     }
217938fd1498Szrj   else if (jfunc->type == IPA_JF_ANCESTOR
218038fd1498Szrj 	   && ipa_get_jf_ancestor_agg_preserved (jfunc))
218138fd1498Szrj     {
218238fd1498Szrj       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
218338fd1498Szrj       int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
218438fd1498Szrj       struct ipcp_param_lattices *src_plats;
218538fd1498Szrj 
218638fd1498Szrj       src_plats = ipa_get_parm_lattices (caller_info, src_idx);
218738fd1498Szrj       if (src_plats->aggs && src_plats->aggs_by_ref)
218838fd1498Szrj 	{
218938fd1498Szrj 	  /* Currently we do not produce clobber aggregate jump
219038fd1498Szrj 	     functions, replace with merging when we do.  */
219138fd1498Szrj 	  gcc_assert (!jfunc->agg.items);
219238fd1498Szrj 	  ret |= merge_aggregate_lattices (cs, dest_plats, src_plats, src_idx,
219338fd1498Szrj 					   ipa_get_jf_ancestor_offset (jfunc));
219438fd1498Szrj 	}
219538fd1498Szrj       else if (!src_plats->aggs_by_ref)
219638fd1498Szrj 	ret |= set_agg_lats_to_bottom (dest_plats);
219738fd1498Szrj       else
219838fd1498Szrj 	ret |= set_agg_lats_contain_variable (dest_plats);
219938fd1498Szrj     }
220038fd1498Szrj   else if (jfunc->agg.items)
220138fd1498Szrj     {
220238fd1498Szrj       bool pre_existing = dest_plats->aggs != NULL;
220338fd1498Szrj       struct ipcp_agg_lattice **aglat = &dest_plats->aggs;
220438fd1498Szrj       struct ipa_agg_jf_item *item;
220538fd1498Szrj       int i;
220638fd1498Szrj 
220738fd1498Szrj       if (set_check_aggs_by_ref (dest_plats, jfunc->agg.by_ref))
220838fd1498Szrj 	return true;
220938fd1498Szrj 
221038fd1498Szrj       FOR_EACH_VEC_ELT (*jfunc->agg.items, i, item)
221138fd1498Szrj 	{
221238fd1498Szrj 	  HOST_WIDE_INT val_size;
221338fd1498Szrj 
221438fd1498Szrj 	  if (item->offset < 0)
221538fd1498Szrj 	    continue;
221638fd1498Szrj 	  gcc_checking_assert (is_gimple_ip_invariant (item->value));
221738fd1498Szrj 	  val_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (item->value)));
221838fd1498Szrj 
221938fd1498Szrj 	  if (merge_agg_lats_step (dest_plats, item->offset, val_size,
222038fd1498Szrj 				   &aglat, pre_existing, &ret))
222138fd1498Szrj 	    {
222238fd1498Szrj 	      ret |= (*aglat)->add_value (item->value, cs, NULL, 0, 0);
222338fd1498Szrj 	      aglat = &(*aglat)->next;
222438fd1498Szrj 	    }
222538fd1498Szrj 	  else if (dest_plats->aggs_bottom)
222638fd1498Szrj 	    return true;
222738fd1498Szrj 	}
222838fd1498Szrj 
222938fd1498Szrj       ret |= set_chain_of_aglats_contains_variable (*aglat);
223038fd1498Szrj     }
223138fd1498Szrj   else
223238fd1498Szrj     ret |= set_agg_lats_contain_variable (dest_plats);
223338fd1498Szrj 
223438fd1498Szrj   return ret;
223538fd1498Szrj }
223638fd1498Szrj 
223738fd1498Szrj /* Return true if on the way cfrom CS->caller to the final (non-alias and
223838fd1498Szrj    non-thunk) destination, the call passes through a thunk.  */
223938fd1498Szrj 
224038fd1498Szrj static bool
call_passes_through_thunk_p(cgraph_edge * cs)224138fd1498Szrj call_passes_through_thunk_p (cgraph_edge *cs)
224238fd1498Szrj {
224338fd1498Szrj   cgraph_node *alias_or_thunk = cs->callee;
224438fd1498Szrj   while (alias_or_thunk->alias)
224538fd1498Szrj     alias_or_thunk = alias_or_thunk->get_alias_target ();
224638fd1498Szrj   return alias_or_thunk->thunk.thunk_p;
224738fd1498Szrj }
224838fd1498Szrj 
224938fd1498Szrj /* Propagate constants from the caller to the callee of CS.  INFO describes the
225038fd1498Szrj    caller.  */
225138fd1498Szrj 
225238fd1498Szrj static bool
propagate_constants_across_call(struct cgraph_edge * cs)225338fd1498Szrj propagate_constants_across_call (struct cgraph_edge *cs)
225438fd1498Szrj {
225538fd1498Szrj   struct ipa_node_params *callee_info;
225638fd1498Szrj   enum availability availability;
225738fd1498Szrj   cgraph_node *callee;
225838fd1498Szrj   struct ipa_edge_args *args;
225938fd1498Szrj   bool ret = false;
226038fd1498Szrj   int i, args_count, parms_count;
226138fd1498Szrj 
226238fd1498Szrj   callee = cs->callee->function_symbol (&availability);
226338fd1498Szrj   if (!callee->definition)
226438fd1498Szrj     return false;
226538fd1498Szrj   gcc_checking_assert (callee->has_gimple_body_p ());
226638fd1498Szrj   callee_info = IPA_NODE_REF (callee);
226738fd1498Szrj 
226838fd1498Szrj   args = IPA_EDGE_REF (cs);
226938fd1498Szrj   args_count = ipa_get_cs_argument_count (args);
227038fd1498Szrj   parms_count = ipa_get_param_count (callee_info);
227138fd1498Szrj   if (parms_count == 0)
227238fd1498Szrj     return false;
227338fd1498Szrj 
227438fd1498Szrj   /* No propagation through instrumentation thunks is available yet.
227538fd1498Szrj      It should be possible with proper mapping of call args and
227638fd1498Szrj      instrumented callee params in the propagation loop below.  But
227738fd1498Szrj      this case mostly occurs when legacy code calls instrumented code
227838fd1498Szrj      and it is not a primary target for optimizations.
227938fd1498Szrj      We detect instrumentation thunks in aliases and thunks chain by
228038fd1498Szrj      checking instrumentation_clone flag for chain source and target.
228138fd1498Szrj      Going through instrumentation thunks we always have it changed
228238fd1498Szrj      from 0 to 1 and all other nodes do not change it.  */
228338fd1498Szrj   if (!cs->callee->instrumentation_clone
228438fd1498Szrj       && callee->instrumentation_clone)
228538fd1498Szrj     {
228638fd1498Szrj       for (i = 0; i < parms_count; i++)
228738fd1498Szrj 	ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
228838fd1498Szrj 								 i));
228938fd1498Szrj       return ret;
229038fd1498Szrj     }
229138fd1498Szrj 
229238fd1498Szrj   /* If this call goes through a thunk we must not propagate to the first (0th)
229338fd1498Szrj      parameter.  However, we might need to uncover a thunk from below a series
229438fd1498Szrj      of aliases first.  */
229538fd1498Szrj   if (call_passes_through_thunk_p (cs))
229638fd1498Szrj     {
229738fd1498Szrj       ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
229838fd1498Szrj 							       0));
229938fd1498Szrj       i = 1;
230038fd1498Szrj     }
230138fd1498Szrj   else
230238fd1498Szrj     i = 0;
230338fd1498Szrj 
230438fd1498Szrj   for (; (i < args_count) && (i < parms_count); i++)
230538fd1498Szrj     {
230638fd1498Szrj       struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i);
230738fd1498Szrj       struct ipcp_param_lattices *dest_plats;
230838fd1498Szrj       tree param_type = ipa_get_type (callee_info, i);
230938fd1498Szrj 
231038fd1498Szrj       dest_plats = ipa_get_parm_lattices (callee_info, i);
231138fd1498Szrj       if (availability == AVAIL_INTERPOSABLE)
231238fd1498Szrj 	ret |= set_all_contains_variable (dest_plats);
231338fd1498Szrj       else
231438fd1498Szrj 	{
231538fd1498Szrj 	  ret |= propagate_scalar_across_jump_function (cs, jump_func,
231638fd1498Szrj 							&dest_plats->itself,
231738fd1498Szrj 							param_type);
231838fd1498Szrj 	  ret |= propagate_context_across_jump_function (cs, jump_func, i,
231938fd1498Szrj 							 &dest_plats->ctxlat);
232038fd1498Szrj 	  ret
232138fd1498Szrj 	    |= propagate_bits_across_jump_function (cs, i, jump_func,
232238fd1498Szrj 						    &dest_plats->bits_lattice);
232338fd1498Szrj 	  ret |= propagate_aggs_across_jump_function (cs, jump_func,
232438fd1498Szrj 						      dest_plats);
232538fd1498Szrj 	  if (opt_for_fn (callee->decl, flag_ipa_vrp))
232638fd1498Szrj 	    ret |= propagate_vr_across_jump_function (cs, jump_func,
232738fd1498Szrj 						      dest_plats, param_type);
232838fd1498Szrj 	  else
232938fd1498Szrj 	    ret |= dest_plats->m_value_range.set_to_bottom ();
233038fd1498Szrj 	}
233138fd1498Szrj     }
233238fd1498Szrj   for (; i < parms_count; i++)
233338fd1498Szrj     ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i));
233438fd1498Szrj 
233538fd1498Szrj   return ret;
233638fd1498Szrj }
233738fd1498Szrj 
233838fd1498Szrj /* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
233938fd1498Szrj    KNOWN_CONTEXTS, KNOWN_AGGS or AGG_REPS return the destination.  The latter
234038fd1498Szrj    three can be NULL.  If AGG_REPS is not NULL, KNOWN_AGGS is ignored.  */
234138fd1498Szrj 
234238fd1498Szrj static tree
ipa_get_indirect_edge_target_1(struct cgraph_edge * ie,vec<tree> known_csts,vec<ipa_polymorphic_call_context> known_contexts,vec<ipa_agg_jump_function_p> known_aggs,struct ipa_agg_replacement_value * agg_reps,bool * speculative)234338fd1498Szrj ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
234438fd1498Szrj 				vec<tree> known_csts,
234538fd1498Szrj 				vec<ipa_polymorphic_call_context> known_contexts,
234638fd1498Szrj 				vec<ipa_agg_jump_function_p> known_aggs,
234738fd1498Szrj 				struct ipa_agg_replacement_value *agg_reps,
234838fd1498Szrj 				bool *speculative)
234938fd1498Szrj {
235038fd1498Szrj   int param_index = ie->indirect_info->param_index;
235138fd1498Szrj   HOST_WIDE_INT anc_offset;
235238fd1498Szrj   tree t;
235338fd1498Szrj   tree target = NULL;
235438fd1498Szrj 
235538fd1498Szrj   *speculative = false;
235638fd1498Szrj 
235738fd1498Szrj   if (param_index == -1
235838fd1498Szrj       || known_csts.length () <= (unsigned int) param_index)
235938fd1498Szrj     return NULL_TREE;
236038fd1498Szrj 
236138fd1498Szrj   if (!ie->indirect_info->polymorphic)
236238fd1498Szrj     {
236338fd1498Szrj       tree t;
236438fd1498Szrj 
236538fd1498Szrj       if (ie->indirect_info->agg_contents)
236638fd1498Szrj 	{
236738fd1498Szrj 	  t = NULL;
236838fd1498Szrj 	  if (agg_reps && ie->indirect_info->guaranteed_unmodified)
236938fd1498Szrj 	    {
237038fd1498Szrj 	      while (agg_reps)
237138fd1498Szrj 		{
237238fd1498Szrj 		  if (agg_reps->index == param_index
237338fd1498Szrj 		      && agg_reps->offset == ie->indirect_info->offset
237438fd1498Szrj 		      && agg_reps->by_ref == ie->indirect_info->by_ref)
237538fd1498Szrj 		    {
237638fd1498Szrj 		      t = agg_reps->value;
237738fd1498Szrj 		      break;
237838fd1498Szrj 		    }
237938fd1498Szrj 		  agg_reps = agg_reps->next;
238038fd1498Szrj 		}
238138fd1498Szrj 	    }
238238fd1498Szrj 	  if (!t)
238338fd1498Szrj 	    {
238438fd1498Szrj 	      struct ipa_agg_jump_function *agg;
238538fd1498Szrj 	      if (known_aggs.length () > (unsigned int) param_index)
238638fd1498Szrj 		agg = known_aggs[param_index];
238738fd1498Szrj 	      else
238838fd1498Szrj 		agg = NULL;
238938fd1498Szrj 	      bool from_global_constant;
239038fd1498Szrj 	      t = ipa_find_agg_cst_for_param (agg, known_csts[param_index],
239138fd1498Szrj 					      ie->indirect_info->offset,
239238fd1498Szrj 					      ie->indirect_info->by_ref,
239338fd1498Szrj 					      &from_global_constant);
239438fd1498Szrj 	      if (t
239538fd1498Szrj 		  && !from_global_constant
239638fd1498Szrj 		  && !ie->indirect_info->guaranteed_unmodified)
239738fd1498Szrj 		t = NULL_TREE;
239838fd1498Szrj 	    }
239938fd1498Szrj 	}
240038fd1498Szrj       else
240138fd1498Szrj 	t = known_csts[param_index];
240238fd1498Szrj 
240338fd1498Szrj       if (t
240438fd1498Szrj 	  && TREE_CODE (t) == ADDR_EXPR
240538fd1498Szrj 	  && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
240638fd1498Szrj 	return TREE_OPERAND (t, 0);
240738fd1498Szrj       else
240838fd1498Szrj 	return NULL_TREE;
240938fd1498Szrj     }
241038fd1498Szrj 
241138fd1498Szrj   if (!opt_for_fn (ie->caller->decl, flag_devirtualize))
241238fd1498Szrj     return NULL_TREE;
241338fd1498Szrj 
241438fd1498Szrj   gcc_assert (!ie->indirect_info->agg_contents);
241538fd1498Szrj   anc_offset = ie->indirect_info->offset;
241638fd1498Szrj 
241738fd1498Szrj   t = NULL;
241838fd1498Szrj 
241938fd1498Szrj   /* Try to work out value of virtual table pointer value in replacemnets.  */
242038fd1498Szrj   if (!t && agg_reps && !ie->indirect_info->by_ref)
242138fd1498Szrj     {
242238fd1498Szrj       while (agg_reps)
242338fd1498Szrj 	{
242438fd1498Szrj 	  if (agg_reps->index == param_index
242538fd1498Szrj 	      && agg_reps->offset == ie->indirect_info->offset
242638fd1498Szrj 	      && agg_reps->by_ref)
242738fd1498Szrj 	    {
242838fd1498Szrj 	      t = agg_reps->value;
242938fd1498Szrj 	      break;
243038fd1498Szrj 	    }
243138fd1498Szrj 	  agg_reps = agg_reps->next;
243238fd1498Szrj 	}
243338fd1498Szrj     }
243438fd1498Szrj 
243538fd1498Szrj   /* Try to work out value of virtual table pointer value in known
243638fd1498Szrj      aggregate values.  */
243738fd1498Szrj   if (!t && known_aggs.length () > (unsigned int) param_index
243838fd1498Szrj       && !ie->indirect_info->by_ref)
243938fd1498Szrj     {
244038fd1498Szrj       struct ipa_agg_jump_function *agg;
244138fd1498Szrj       agg = known_aggs[param_index];
244238fd1498Szrj       t = ipa_find_agg_cst_for_param (agg, known_csts[param_index],
244338fd1498Szrj 				      ie->indirect_info->offset, true);
244438fd1498Szrj     }
244538fd1498Szrj 
244638fd1498Szrj   /* If we found the virtual table pointer, lookup the target.  */
244738fd1498Szrj   if (t)
244838fd1498Szrj     {
244938fd1498Szrj       tree vtable;
245038fd1498Szrj       unsigned HOST_WIDE_INT offset;
245138fd1498Szrj       if (vtable_pointer_value_to_vtable (t, &vtable, &offset))
245238fd1498Szrj 	{
245338fd1498Szrj 	  bool can_refer;
245438fd1498Szrj 	  target = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token,
245538fd1498Szrj 						      vtable, offset, &can_refer);
245638fd1498Szrj 	  if (can_refer)
245738fd1498Szrj 	    {
245838fd1498Szrj 	      if (!target
245938fd1498Szrj 		  || (TREE_CODE (TREE_TYPE (target)) == FUNCTION_TYPE
246038fd1498Szrj 		      && DECL_FUNCTION_CODE (target) == BUILT_IN_UNREACHABLE)
246138fd1498Szrj 		  || !possible_polymorphic_call_target_p
246238fd1498Szrj 		       (ie, cgraph_node::get (target)))
246338fd1498Szrj 		{
246438fd1498Szrj 		  /* Do not speculate builtin_unreachable, it is stupid!  */
246538fd1498Szrj 		  if (ie->indirect_info->vptr_changed)
246638fd1498Szrj 		    return NULL;
246738fd1498Szrj 		  target = ipa_impossible_devirt_target (ie, target);
246838fd1498Szrj 		}
246938fd1498Szrj 	      *speculative = ie->indirect_info->vptr_changed;
247038fd1498Szrj 	      if (!*speculative)
247138fd1498Szrj 		return target;
247238fd1498Szrj 	    }
247338fd1498Szrj 	}
247438fd1498Szrj     }
247538fd1498Szrj 
247638fd1498Szrj   /* Do we know the constant value of pointer?  */
247738fd1498Szrj   if (!t)
247838fd1498Szrj     t = known_csts[param_index];
247938fd1498Szrj 
248038fd1498Szrj   gcc_checking_assert (!t || TREE_CODE (t) != TREE_BINFO);
248138fd1498Szrj 
248238fd1498Szrj   ipa_polymorphic_call_context context;
248338fd1498Szrj   if (known_contexts.length () > (unsigned int) param_index)
248438fd1498Szrj     {
248538fd1498Szrj       context = known_contexts[param_index];
248638fd1498Szrj       context.offset_by (anc_offset);
248738fd1498Szrj       if (ie->indirect_info->vptr_changed)
248838fd1498Szrj 	context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
248938fd1498Szrj 					      ie->indirect_info->otr_type);
249038fd1498Szrj       if (t)
249138fd1498Szrj 	{
249238fd1498Szrj 	  ipa_polymorphic_call_context ctx2 = ipa_polymorphic_call_context
249338fd1498Szrj 	    (t, ie->indirect_info->otr_type, anc_offset);
249438fd1498Szrj 	  if (!ctx2.useless_p ())
249538fd1498Szrj 	    context.combine_with (ctx2, ie->indirect_info->otr_type);
249638fd1498Szrj 	}
249738fd1498Szrj     }
249838fd1498Szrj   else if (t)
249938fd1498Szrj     {
250038fd1498Szrj       context = ipa_polymorphic_call_context (t, ie->indirect_info->otr_type,
250138fd1498Szrj 					      anc_offset);
250238fd1498Szrj       if (ie->indirect_info->vptr_changed)
250338fd1498Szrj 	context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
250438fd1498Szrj 					      ie->indirect_info->otr_type);
250538fd1498Szrj     }
250638fd1498Szrj   else
250738fd1498Szrj     return NULL_TREE;
250838fd1498Szrj 
250938fd1498Szrj   vec <cgraph_node *>targets;
251038fd1498Szrj   bool final;
251138fd1498Szrj 
251238fd1498Szrj   targets = possible_polymorphic_call_targets
251338fd1498Szrj     (ie->indirect_info->otr_type,
251438fd1498Szrj      ie->indirect_info->otr_token,
251538fd1498Szrj      context, &final);
251638fd1498Szrj   if (!final || targets.length () > 1)
251738fd1498Szrj     {
251838fd1498Szrj       struct cgraph_node *node;
251938fd1498Szrj       if (*speculative)
252038fd1498Szrj 	return target;
252138fd1498Szrj       if (!opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)
252238fd1498Szrj 	  || ie->speculative || !ie->maybe_hot_p ())
252338fd1498Szrj 	return NULL;
252438fd1498Szrj       node = try_speculative_devirtualization (ie->indirect_info->otr_type,
252538fd1498Szrj 					       ie->indirect_info->otr_token,
252638fd1498Szrj 					       context);
252738fd1498Szrj       if (node)
252838fd1498Szrj 	{
252938fd1498Szrj 	  *speculative = true;
253038fd1498Szrj 	  target = node->decl;
253138fd1498Szrj 	}
253238fd1498Szrj       else
253338fd1498Szrj 	return NULL;
253438fd1498Szrj     }
253538fd1498Szrj   else
253638fd1498Szrj     {
253738fd1498Szrj       *speculative = false;
253838fd1498Szrj       if (targets.length () == 1)
253938fd1498Szrj 	target = targets[0]->decl;
254038fd1498Szrj       else
254138fd1498Szrj 	target = ipa_impossible_devirt_target (ie, NULL_TREE);
254238fd1498Szrj     }
254338fd1498Szrj 
254438fd1498Szrj   if (target && !possible_polymorphic_call_target_p (ie,
254538fd1498Szrj 						     cgraph_node::get (target)))
254638fd1498Szrj     {
254738fd1498Szrj       if (*speculative)
254838fd1498Szrj 	return NULL;
254938fd1498Szrj       target = ipa_impossible_devirt_target (ie, target);
255038fd1498Szrj     }
255138fd1498Szrj 
255238fd1498Szrj   return target;
255338fd1498Szrj }
255438fd1498Szrj 
255538fd1498Szrj 
255638fd1498Szrj /* If an indirect edge IE can be turned into a direct one based on KNOWN_CSTS,
255738fd1498Szrj    KNOWN_CONTEXTS (which can be vNULL) or KNOWN_AGGS (which also can be vNULL)
255838fd1498Szrj    return the destination.  */
255938fd1498Szrj 
256038fd1498Szrj tree
ipa_get_indirect_edge_target(struct cgraph_edge * ie,vec<tree> known_csts,vec<ipa_polymorphic_call_context> known_contexts,vec<ipa_agg_jump_function_p> known_aggs,bool * speculative)256138fd1498Szrj ipa_get_indirect_edge_target (struct cgraph_edge *ie,
256238fd1498Szrj 			      vec<tree> known_csts,
256338fd1498Szrj 			      vec<ipa_polymorphic_call_context> known_contexts,
256438fd1498Szrj 			      vec<ipa_agg_jump_function_p> known_aggs,
256538fd1498Szrj 			      bool *speculative)
256638fd1498Szrj {
256738fd1498Szrj   return ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
256838fd1498Szrj 					 known_aggs, NULL, speculative);
256938fd1498Szrj }
257038fd1498Szrj 
257138fd1498Szrj /* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS
257238fd1498Szrj    and KNOWN_CONTEXTS.  */
257338fd1498Szrj 
257438fd1498Szrj static int
devirtualization_time_bonus(struct cgraph_node * node,vec<tree> known_csts,vec<ipa_polymorphic_call_context> known_contexts,vec<ipa_agg_jump_function_p> known_aggs)257538fd1498Szrj devirtualization_time_bonus (struct cgraph_node *node,
257638fd1498Szrj 			     vec<tree> known_csts,
257738fd1498Szrj 			     vec<ipa_polymorphic_call_context> known_contexts,
257838fd1498Szrj 			     vec<ipa_agg_jump_function_p> known_aggs)
257938fd1498Szrj {
258038fd1498Szrj   struct cgraph_edge *ie;
258138fd1498Szrj   int res = 0;
258238fd1498Szrj 
258338fd1498Szrj   for (ie = node->indirect_calls; ie; ie = ie->next_callee)
258438fd1498Szrj     {
258538fd1498Szrj       struct cgraph_node *callee;
258638fd1498Szrj       struct ipa_fn_summary *isummary;
258738fd1498Szrj       enum availability avail;
258838fd1498Szrj       tree target;
258938fd1498Szrj       bool speculative;
259038fd1498Szrj 
259138fd1498Szrj       target = ipa_get_indirect_edge_target (ie, known_csts, known_contexts,
259238fd1498Szrj 					     known_aggs, &speculative);
259338fd1498Szrj       if (!target)
259438fd1498Szrj 	continue;
259538fd1498Szrj 
259638fd1498Szrj       /* Only bare minimum benefit for clearly un-inlineable targets.  */
259738fd1498Szrj       res += 1;
259838fd1498Szrj       callee = cgraph_node::get (target);
259938fd1498Szrj       if (!callee || !callee->definition)
260038fd1498Szrj 	continue;
260138fd1498Szrj       callee = callee->function_symbol (&avail);
260238fd1498Szrj       if (avail < AVAIL_AVAILABLE)
260338fd1498Szrj 	continue;
260438fd1498Szrj       isummary = ipa_fn_summaries->get (callee);
260538fd1498Szrj       if (!isummary->inlinable)
260638fd1498Szrj 	continue;
260738fd1498Szrj 
260838fd1498Szrj       /* FIXME: The values below need re-considering and perhaps also
260938fd1498Szrj 	 integrating into the cost metrics, at lest in some very basic way.  */
261038fd1498Szrj       if (isummary->size <= MAX_INLINE_INSNS_AUTO / 4)
261138fd1498Szrj 	res += 31 / ((int)speculative + 1);
261238fd1498Szrj       else if (isummary->size <= MAX_INLINE_INSNS_AUTO / 2)
261338fd1498Szrj 	res += 15 / ((int)speculative + 1);
261438fd1498Szrj       else if (isummary->size <= MAX_INLINE_INSNS_AUTO
261538fd1498Szrj 	       || DECL_DECLARED_INLINE_P (callee->decl))
261638fd1498Szrj 	res += 7 / ((int)speculative + 1);
261738fd1498Szrj     }
261838fd1498Szrj 
261938fd1498Szrj   return res;
262038fd1498Szrj }
262138fd1498Szrj 
262238fd1498Szrj /* Return time bonus incurred because of HINTS.  */
262338fd1498Szrj 
262438fd1498Szrj static int
hint_time_bonus(ipa_hints hints)262538fd1498Szrj hint_time_bonus (ipa_hints hints)
262638fd1498Szrj {
262738fd1498Szrj   int result = 0;
262838fd1498Szrj   if (hints & (INLINE_HINT_loop_iterations | INLINE_HINT_loop_stride))
262938fd1498Szrj     result += PARAM_VALUE (PARAM_IPA_CP_LOOP_HINT_BONUS);
263038fd1498Szrj   if (hints & INLINE_HINT_array_index)
263138fd1498Szrj     result += PARAM_VALUE (PARAM_IPA_CP_ARRAY_INDEX_HINT_BONUS);
263238fd1498Szrj   return result;
263338fd1498Szrj }
263438fd1498Szrj 
263538fd1498Szrj /* If there is a reason to penalize the function described by INFO in the
263638fd1498Szrj    cloning goodness evaluation, do so.  */
263738fd1498Szrj 
263838fd1498Szrj static inline int64_t
incorporate_penalties(ipa_node_params * info,int64_t evaluation)263938fd1498Szrj incorporate_penalties (ipa_node_params *info, int64_t evaluation)
264038fd1498Szrj {
264138fd1498Szrj   if (info->node_within_scc)
264238fd1498Szrj     evaluation = (evaluation
264338fd1498Szrj 		  * (100 - PARAM_VALUE (PARAM_IPA_CP_RECURSION_PENALTY))) / 100;
264438fd1498Szrj 
264538fd1498Szrj   if (info->node_calling_single_call)
264638fd1498Szrj     evaluation = (evaluation
264738fd1498Szrj 		  * (100 - PARAM_VALUE (PARAM_IPA_CP_SINGLE_CALL_PENALTY)))
264838fd1498Szrj       / 100;
264938fd1498Szrj 
265038fd1498Szrj   return evaluation;
265138fd1498Szrj }
265238fd1498Szrj 
265338fd1498Szrj /* Return true if cloning NODE is a good idea, given the estimated TIME_BENEFIT
265438fd1498Szrj    and SIZE_COST and with the sum of frequencies of incoming edges to the
265538fd1498Szrj    potential new clone in FREQUENCIES.  */
265638fd1498Szrj 
265738fd1498Szrj static bool
good_cloning_opportunity_p(struct cgraph_node * node,int time_benefit,int freq_sum,profile_count count_sum,int size_cost)265838fd1498Szrj good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit,
265938fd1498Szrj 			    int freq_sum, profile_count count_sum, int size_cost)
266038fd1498Szrj {
266138fd1498Szrj   if (time_benefit == 0
266238fd1498Szrj       || !opt_for_fn (node->decl, flag_ipa_cp_clone)
266338fd1498Szrj       || node->optimize_for_size_p ())
266438fd1498Szrj     return false;
266538fd1498Szrj 
266638fd1498Szrj   gcc_assert (size_cost > 0);
266738fd1498Szrj 
266838fd1498Szrj   struct ipa_node_params *info = IPA_NODE_REF (node);
266938fd1498Szrj   if (max_count > profile_count::zero ())
267038fd1498Szrj     {
267138fd1498Szrj       int factor = RDIV (count_sum.probability_in
267238fd1498Szrj 				 (max_count).to_reg_br_prob_base ()
267338fd1498Szrj 		         * 1000, REG_BR_PROB_BASE);
267438fd1498Szrj       int64_t evaluation = (((int64_t) time_benefit * factor)
267538fd1498Szrj 				    / size_cost);
267638fd1498Szrj       evaluation = incorporate_penalties (info, evaluation);
267738fd1498Szrj 
267838fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
267938fd1498Szrj 	{
268038fd1498Szrj 	  fprintf (dump_file, "     good_cloning_opportunity_p (time: %i, "
268138fd1498Szrj 		   "size: %i, count_sum: ", time_benefit, size_cost);
268238fd1498Szrj 	  count_sum.dump (dump_file);
268338fd1498Szrj 	  fprintf (dump_file, "%s%s) -> evaluation: " "%" PRId64
268438fd1498Szrj 		 ", threshold: %i\n",
268538fd1498Szrj 		 info->node_within_scc ? ", scc" : "",
268638fd1498Szrj 		 info->node_calling_single_call ? ", single_call" : "",
268738fd1498Szrj 		 evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
268838fd1498Szrj 	}
268938fd1498Szrj 
269038fd1498Szrj       return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
269138fd1498Szrj     }
269238fd1498Szrj   else
269338fd1498Szrj     {
269438fd1498Szrj       int64_t evaluation = (((int64_t) time_benefit * freq_sum)
269538fd1498Szrj 				    / size_cost);
269638fd1498Szrj       evaluation = incorporate_penalties (info, evaluation);
269738fd1498Szrj 
269838fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
269938fd1498Szrj 	fprintf (dump_file, "     good_cloning_opportunity_p (time: %i, "
270038fd1498Szrj 		 "size: %i, freq_sum: %i%s%s) -> evaluation: "
270138fd1498Szrj 		 "%" PRId64 ", threshold: %i\n",
270238fd1498Szrj 		 time_benefit, size_cost, freq_sum,
270338fd1498Szrj 		 info->node_within_scc ? ", scc" : "",
270438fd1498Szrj 		 info->node_calling_single_call ? ", single_call" : "",
270538fd1498Szrj 		 evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
270638fd1498Szrj 
270738fd1498Szrj       return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
270838fd1498Szrj     }
270938fd1498Szrj }
271038fd1498Szrj 
271138fd1498Szrj /* Return all context independent values from aggregate lattices in PLATS in a
271238fd1498Szrj    vector.  Return NULL if there are none.  */
271338fd1498Szrj 
271438fd1498Szrj static vec<ipa_agg_jf_item, va_gc> *
context_independent_aggregate_values(struct ipcp_param_lattices * plats)271538fd1498Szrj context_independent_aggregate_values (struct ipcp_param_lattices *plats)
271638fd1498Szrj {
271738fd1498Szrj   vec<ipa_agg_jf_item, va_gc> *res = NULL;
271838fd1498Szrj 
271938fd1498Szrj   if (plats->aggs_bottom
272038fd1498Szrj       || plats->aggs_contain_variable
272138fd1498Szrj       || plats->aggs_count == 0)
272238fd1498Szrj     return NULL;
272338fd1498Szrj 
272438fd1498Szrj   for (struct ipcp_agg_lattice *aglat = plats->aggs;
272538fd1498Szrj        aglat;
272638fd1498Szrj        aglat = aglat->next)
272738fd1498Szrj     if (aglat->is_single_const ())
272838fd1498Szrj       {
272938fd1498Szrj 	struct ipa_agg_jf_item item;
273038fd1498Szrj 	item.offset = aglat->offset;
273138fd1498Szrj 	item.value = aglat->values->value;
273238fd1498Szrj 	vec_safe_push (res, item);
273338fd1498Szrj       }
273438fd1498Szrj   return res;
273538fd1498Szrj }
273638fd1498Szrj 
273738fd1498Szrj /* Allocate KNOWN_CSTS, KNOWN_CONTEXTS and, if non-NULL, KNOWN_AGGS and
273838fd1498Szrj    populate them with values of parameters that are known independent of the
273938fd1498Szrj    context.  INFO describes the function.  If REMOVABLE_PARAMS_COST is
274038fd1498Szrj    non-NULL, the movement cost of all removable parameters will be stored in
274138fd1498Szrj    it.  */
274238fd1498Szrj 
274338fd1498Szrj static bool
gather_context_independent_values(struct ipa_node_params * info,vec<tree> * known_csts,vec<ipa_polymorphic_call_context> * known_contexts,vec<ipa_agg_jump_function> * known_aggs,int * removable_params_cost)274438fd1498Szrj gather_context_independent_values (struct ipa_node_params *info,
274538fd1498Szrj 				   vec<tree> *known_csts,
274638fd1498Szrj 				   vec<ipa_polymorphic_call_context>
274738fd1498Szrj 				   *known_contexts,
274838fd1498Szrj 				   vec<ipa_agg_jump_function> *known_aggs,
274938fd1498Szrj 				   int *removable_params_cost)
275038fd1498Szrj {
275138fd1498Szrj   int i, count = ipa_get_param_count (info);
275238fd1498Szrj   bool ret = false;
275338fd1498Szrj 
275438fd1498Szrj   known_csts->create (0);
275538fd1498Szrj   known_contexts->create (0);
275638fd1498Szrj   known_csts->safe_grow_cleared (count);
275738fd1498Szrj   known_contexts->safe_grow_cleared (count);
275838fd1498Szrj   if (known_aggs)
275938fd1498Szrj     {
276038fd1498Szrj       known_aggs->create (0);
276138fd1498Szrj       known_aggs->safe_grow_cleared (count);
276238fd1498Szrj     }
276338fd1498Szrj 
276438fd1498Szrj   if (removable_params_cost)
276538fd1498Szrj     *removable_params_cost = 0;
276638fd1498Szrj 
276738fd1498Szrj   for (i = 0; i < count; i++)
276838fd1498Szrj     {
276938fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
277038fd1498Szrj       ipcp_lattice<tree> *lat = &plats->itself;
277138fd1498Szrj 
277238fd1498Szrj       if (lat->is_single_const ())
277338fd1498Szrj 	{
277438fd1498Szrj 	  ipcp_value<tree> *val = lat->values;
277538fd1498Szrj 	  gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO);
277638fd1498Szrj 	  (*known_csts)[i] = val->value;
277738fd1498Szrj 	  if (removable_params_cost)
277838fd1498Szrj 	    *removable_params_cost
277938fd1498Szrj 	      += estimate_move_cost (TREE_TYPE (val->value), false);
278038fd1498Szrj 	  ret = true;
278138fd1498Szrj 	}
278238fd1498Szrj       else if (removable_params_cost
278338fd1498Szrj 	       && !ipa_is_param_used (info, i))
278438fd1498Szrj 	*removable_params_cost
278538fd1498Szrj 	  += ipa_get_param_move_cost (info, i);
278638fd1498Szrj 
278738fd1498Szrj       if (!ipa_is_param_used (info, i))
278838fd1498Szrj 	continue;
278938fd1498Szrj 
279038fd1498Szrj       ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
279138fd1498Szrj       /* Do not account known context as reason for cloning.  We can see
279238fd1498Szrj 	 if it permits devirtualization.  */
279338fd1498Szrj       if (ctxlat->is_single_const ())
279438fd1498Szrj 	(*known_contexts)[i] = ctxlat->values->value;
279538fd1498Szrj 
279638fd1498Szrj       if (known_aggs)
279738fd1498Szrj 	{
279838fd1498Szrj 	  vec<ipa_agg_jf_item, va_gc> *agg_items;
279938fd1498Szrj 	  struct ipa_agg_jump_function *ajf;
280038fd1498Szrj 
280138fd1498Szrj 	  agg_items = context_independent_aggregate_values (plats);
280238fd1498Szrj 	  ajf = &(*known_aggs)[i];
280338fd1498Szrj 	  ajf->items = agg_items;
280438fd1498Szrj 	  ajf->by_ref = plats->aggs_by_ref;
280538fd1498Szrj 	  ret |= agg_items != NULL;
280638fd1498Szrj 	}
280738fd1498Szrj     }
280838fd1498Szrj 
280938fd1498Szrj   return ret;
281038fd1498Szrj }
281138fd1498Szrj 
281238fd1498Szrj /* The current interface in ipa-inline-analysis requires a pointer vector.
281338fd1498Szrj    Create it.
281438fd1498Szrj 
281538fd1498Szrj    FIXME: That interface should be re-worked, this is slightly silly.  Still,
281638fd1498Szrj    I'd like to discuss how to change it first and this demonstrates the
281738fd1498Szrj    issue.  */
281838fd1498Szrj 
281938fd1498Szrj static vec<ipa_agg_jump_function_p>
agg_jmp_p_vec_for_t_vec(vec<ipa_agg_jump_function> known_aggs)282038fd1498Szrj agg_jmp_p_vec_for_t_vec (vec<ipa_agg_jump_function> known_aggs)
282138fd1498Szrj {
282238fd1498Szrj   vec<ipa_agg_jump_function_p> ret;
282338fd1498Szrj   struct ipa_agg_jump_function *ajf;
282438fd1498Szrj   int i;
282538fd1498Szrj 
282638fd1498Szrj   ret.create (known_aggs.length ());
282738fd1498Szrj   FOR_EACH_VEC_ELT (known_aggs, i, ajf)
282838fd1498Szrj     ret.quick_push (ajf);
282938fd1498Szrj   return ret;
283038fd1498Szrj }
283138fd1498Szrj 
283238fd1498Szrj /* Perform time and size measurement of NODE with the context given in
283338fd1498Szrj    KNOWN_CSTS, KNOWN_CONTEXTS and KNOWN_AGGS, calculate the benefit and cost
283438fd1498Szrj    given BASE_TIME of the node without specialization, REMOVABLE_PARAMS_COST of
283538fd1498Szrj    all context-independent removable parameters and EST_MOVE_COST of estimated
283638fd1498Szrj    movement of the considered parameter and store it into VAL.  */
283738fd1498Szrj 
283838fd1498Szrj static void
perform_estimation_of_a_value(cgraph_node * node,vec<tree> known_csts,vec<ipa_polymorphic_call_context> known_contexts,vec<ipa_agg_jump_function_p> known_aggs_ptrs,int removable_params_cost,int est_move_cost,ipcp_value_base * val)283938fd1498Szrj perform_estimation_of_a_value (cgraph_node *node, vec<tree> known_csts,
284038fd1498Szrj 			       vec<ipa_polymorphic_call_context> known_contexts,
284138fd1498Szrj 			       vec<ipa_agg_jump_function_p> known_aggs_ptrs,
284238fd1498Szrj 			       int removable_params_cost,
284338fd1498Szrj 			       int est_move_cost, ipcp_value_base *val)
284438fd1498Szrj {
284538fd1498Szrj   int size, time_benefit;
284638fd1498Szrj   sreal time, base_time;
284738fd1498Szrj   ipa_hints hints;
284838fd1498Szrj 
284938fd1498Szrj   estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
285038fd1498Szrj 				     known_aggs_ptrs, &size, &time,
285138fd1498Szrj 				     &base_time, &hints);
285238fd1498Szrj   base_time -= time;
285338fd1498Szrj   if (base_time > 65535)
285438fd1498Szrj     base_time = 65535;
2855*e215fc28Szrj 
2856*e215fc28Szrj   /* Extern inline functions have no cloning local time benefits because they
2857*e215fc28Szrj      will be inlined anyway.  The only reason to clone them is if it enables
2858*e215fc28Szrj      optimization in any of the functions they call.  */
2859*e215fc28Szrj   if (DECL_EXTERNAL (node->decl) && DECL_DECLARED_INLINE_P (node->decl))
2860*e215fc28Szrj     time_benefit = 0;
2861*e215fc28Szrj   else
286238fd1498Szrj     time_benefit = base_time.to_int ()
286338fd1498Szrj       + devirtualization_time_bonus (node, known_csts, known_contexts,
286438fd1498Szrj 				     known_aggs_ptrs)
286538fd1498Szrj       + hint_time_bonus (hints)
286638fd1498Szrj       + removable_params_cost + est_move_cost;
286738fd1498Szrj 
286838fd1498Szrj   gcc_checking_assert (size >=0);
286938fd1498Szrj   /* The inliner-heuristics based estimates may think that in certain
287038fd1498Szrj      contexts some functions do not have any size at all but we want
287138fd1498Szrj      all specializations to have at least a tiny cost, not least not to
287238fd1498Szrj      divide by zero.  */
287338fd1498Szrj   if (size == 0)
287438fd1498Szrj     size = 1;
287538fd1498Szrj 
287638fd1498Szrj   val->local_time_benefit = time_benefit;
287738fd1498Szrj   val->local_size_cost = size;
287838fd1498Szrj }
287938fd1498Szrj 
288038fd1498Szrj /* Iterate over known values of parameters of NODE and estimate the local
288138fd1498Szrj    effects in terms of time and size they have.  */
288238fd1498Szrj 
288338fd1498Szrj static void
estimate_local_effects(struct cgraph_node * node)288438fd1498Szrj estimate_local_effects (struct cgraph_node *node)
288538fd1498Szrj {
288638fd1498Szrj   struct ipa_node_params *info = IPA_NODE_REF (node);
288738fd1498Szrj   int i, count = ipa_get_param_count (info);
288838fd1498Szrj   vec<tree> known_csts;
288938fd1498Szrj   vec<ipa_polymorphic_call_context> known_contexts;
289038fd1498Szrj   vec<ipa_agg_jump_function> known_aggs;
289138fd1498Szrj   vec<ipa_agg_jump_function_p> known_aggs_ptrs;
289238fd1498Szrj   bool always_const;
289338fd1498Szrj   int removable_params_cost;
289438fd1498Szrj 
289538fd1498Szrj   if (!count || !ipcp_versionable_function_p (node))
289638fd1498Szrj     return;
289738fd1498Szrj 
289838fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
289938fd1498Szrj     fprintf (dump_file, "\nEstimating effects for %s.\n", node->dump_name ());
290038fd1498Szrj 
290138fd1498Szrj   always_const = gather_context_independent_values (info, &known_csts,
290238fd1498Szrj 						    &known_contexts, &known_aggs,
290338fd1498Szrj 						    &removable_params_cost);
290438fd1498Szrj   known_aggs_ptrs = agg_jmp_p_vec_for_t_vec (known_aggs);
290538fd1498Szrj   int devirt_bonus = devirtualization_time_bonus (node, known_csts,
290638fd1498Szrj 					   known_contexts, known_aggs_ptrs);
290738fd1498Szrj   if (always_const || devirt_bonus
290838fd1498Szrj       || (removable_params_cost && node->local.can_change_signature))
290938fd1498Szrj     {
291038fd1498Szrj       struct caller_statistics stats;
291138fd1498Szrj       ipa_hints hints;
291238fd1498Szrj       sreal time, base_time;
291338fd1498Szrj       int size;
291438fd1498Szrj 
291538fd1498Szrj       init_caller_stats (&stats);
291638fd1498Szrj       node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats,
291738fd1498Szrj 					      false);
291838fd1498Szrj       estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
291938fd1498Szrj 					 known_aggs_ptrs, &size, &time,
292038fd1498Szrj 					 &base_time, &hints);
292138fd1498Szrj       time -= devirt_bonus;
292238fd1498Szrj       time -= hint_time_bonus (hints);
292338fd1498Szrj       time -= removable_params_cost;
292438fd1498Szrj       size -= stats.n_calls * removable_params_cost;
292538fd1498Szrj 
292638fd1498Szrj       if (dump_file)
292738fd1498Szrj 	fprintf (dump_file, " - context independent values, size: %i, "
292838fd1498Szrj 		 "time_benefit: %f\n", size, (base_time - time).to_double ());
292938fd1498Szrj 
293038fd1498Szrj       if (size <= 0 || node->local.local)
293138fd1498Szrj 	{
293238fd1498Szrj 	  info->do_clone_for_all_contexts = true;
293338fd1498Szrj 
293438fd1498Szrj 	  if (dump_file)
293538fd1498Szrj 	    fprintf (dump_file, "     Decided to specialize for all "
293638fd1498Szrj 		     "known contexts, code not going to grow.\n");
293738fd1498Szrj 	}
293838fd1498Szrj       else if (good_cloning_opportunity_p (node,
293938fd1498Szrj 					   MAX ((base_time - time).to_int (),
294038fd1498Szrj 						65536),
294138fd1498Szrj 					   stats.freq_sum, stats.count_sum,
294238fd1498Szrj 					   size))
294338fd1498Szrj 	{
294438fd1498Szrj 	  if (size + overall_size <= max_new_size)
294538fd1498Szrj 	    {
294638fd1498Szrj 	      info->do_clone_for_all_contexts = true;
294738fd1498Szrj 	      overall_size += size;
294838fd1498Szrj 
294938fd1498Szrj 	      if (dump_file)
295038fd1498Szrj 		fprintf (dump_file, "     Decided to specialize for all "
295138fd1498Szrj 			 "known contexts, growth deemed beneficial.\n");
295238fd1498Szrj 	    }
295338fd1498Szrj 	  else if (dump_file && (dump_flags & TDF_DETAILS))
295438fd1498Szrj 	    fprintf (dump_file, "   Not cloning for all contexts because "
295538fd1498Szrj 		     "max_new_size would be reached with %li.\n",
295638fd1498Szrj 		     size + overall_size);
295738fd1498Szrj 	}
295838fd1498Szrj       else if (dump_file && (dump_flags & TDF_DETAILS))
295938fd1498Szrj 	fprintf (dump_file, "   Not cloning for all contexts because "
296038fd1498Szrj 		 "!good_cloning_opportunity_p.\n");
296138fd1498Szrj 
296238fd1498Szrj     }
296338fd1498Szrj 
296438fd1498Szrj   for (i = 0; i < count; i++)
296538fd1498Szrj     {
296638fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
296738fd1498Szrj       ipcp_lattice<tree> *lat = &plats->itself;
296838fd1498Szrj       ipcp_value<tree> *val;
296938fd1498Szrj 
297038fd1498Szrj       if (lat->bottom
297138fd1498Szrj 	  || !lat->values
297238fd1498Szrj 	  || known_csts[i])
297338fd1498Szrj 	continue;
297438fd1498Szrj 
297538fd1498Szrj       for (val = lat->values; val; val = val->next)
297638fd1498Szrj 	{
297738fd1498Szrj 	  gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO);
297838fd1498Szrj 	  known_csts[i] = val->value;
297938fd1498Szrj 
298038fd1498Szrj 	  int emc = estimate_move_cost (TREE_TYPE (val->value), true);
298138fd1498Szrj 	  perform_estimation_of_a_value (node, known_csts, known_contexts,
298238fd1498Szrj 					 known_aggs_ptrs,
298338fd1498Szrj 					 removable_params_cost, emc, val);
298438fd1498Szrj 
298538fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
298638fd1498Szrj 	    {
298738fd1498Szrj 	      fprintf (dump_file, " - estimates for value ");
298838fd1498Szrj 	      print_ipcp_constant_value (dump_file, val->value);
298938fd1498Szrj 	      fprintf (dump_file, " for ");
299038fd1498Szrj 	      ipa_dump_param (dump_file, info, i);
299138fd1498Szrj 	      fprintf (dump_file, ": time_benefit: %i, size: %i\n",
299238fd1498Szrj 		       val->local_time_benefit, val->local_size_cost);
299338fd1498Szrj 	    }
299438fd1498Szrj 	}
299538fd1498Szrj       known_csts[i] = NULL_TREE;
299638fd1498Szrj     }
299738fd1498Szrj 
299838fd1498Szrj   for (i = 0; i < count; i++)
299938fd1498Szrj     {
300038fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
300138fd1498Szrj 
300238fd1498Szrj       if (!plats->virt_call)
300338fd1498Szrj 	continue;
300438fd1498Szrj 
300538fd1498Szrj       ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
300638fd1498Szrj       ipcp_value<ipa_polymorphic_call_context> *val;
300738fd1498Szrj 
300838fd1498Szrj       if (ctxlat->bottom
300938fd1498Szrj 	  || !ctxlat->values
301038fd1498Szrj 	  || !known_contexts[i].useless_p ())
301138fd1498Szrj 	continue;
301238fd1498Szrj 
301338fd1498Szrj       for (val = ctxlat->values; val; val = val->next)
301438fd1498Szrj 	{
301538fd1498Szrj 	  known_contexts[i] = val->value;
301638fd1498Szrj 	  perform_estimation_of_a_value (node, known_csts, known_contexts,
301738fd1498Szrj 					 known_aggs_ptrs,
301838fd1498Szrj 					 removable_params_cost, 0, val);
301938fd1498Szrj 
302038fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
302138fd1498Szrj 	    {
302238fd1498Szrj 	      fprintf (dump_file, " - estimates for polymorphic context ");
302338fd1498Szrj 	      print_ipcp_constant_value (dump_file, val->value);
302438fd1498Szrj 	      fprintf (dump_file, " for ");
302538fd1498Szrj 	      ipa_dump_param (dump_file, info, i);
302638fd1498Szrj 	      fprintf (dump_file, ": time_benefit: %i, size: %i\n",
302738fd1498Szrj 		       val->local_time_benefit, val->local_size_cost);
302838fd1498Szrj 	    }
302938fd1498Szrj 	}
303038fd1498Szrj       known_contexts[i] = ipa_polymorphic_call_context ();
303138fd1498Szrj     }
303238fd1498Szrj 
303338fd1498Szrj   for (i = 0; i < count; i++)
303438fd1498Szrj     {
303538fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
303638fd1498Szrj       struct ipa_agg_jump_function *ajf;
303738fd1498Szrj       struct ipcp_agg_lattice *aglat;
303838fd1498Szrj 
303938fd1498Szrj       if (plats->aggs_bottom || !plats->aggs)
304038fd1498Szrj 	continue;
304138fd1498Szrj 
304238fd1498Szrj       ajf = &known_aggs[i];
304338fd1498Szrj       for (aglat = plats->aggs; aglat; aglat = aglat->next)
304438fd1498Szrj 	{
304538fd1498Szrj 	  ipcp_value<tree> *val;
304638fd1498Szrj 	  if (aglat->bottom || !aglat->values
304738fd1498Szrj 	      /* If the following is true, the one value is in known_aggs.  */
304838fd1498Szrj 	      || (!plats->aggs_contain_variable
304938fd1498Szrj 		  && aglat->is_single_const ()))
305038fd1498Szrj 	    continue;
305138fd1498Szrj 
305238fd1498Szrj 	  for (val = aglat->values; val; val = val->next)
305338fd1498Szrj 	    {
305438fd1498Szrj 	      struct ipa_agg_jf_item item;
305538fd1498Szrj 
305638fd1498Szrj 	      item.offset = aglat->offset;
305738fd1498Szrj 	      item.value = val->value;
305838fd1498Szrj 	      vec_safe_push (ajf->items, item);
305938fd1498Szrj 
306038fd1498Szrj 	      perform_estimation_of_a_value (node, known_csts, known_contexts,
306138fd1498Szrj 					     known_aggs_ptrs,
306238fd1498Szrj 					     removable_params_cost, 0, val);
306338fd1498Szrj 
306438fd1498Szrj 	      if (dump_file && (dump_flags & TDF_DETAILS))
306538fd1498Szrj 		{
306638fd1498Szrj 		  fprintf (dump_file, " - estimates for value ");
306738fd1498Szrj 		  print_ipcp_constant_value (dump_file, val->value);
306838fd1498Szrj 		  fprintf (dump_file, " for ");
306938fd1498Szrj 		  ipa_dump_param (dump_file, info, i);
307038fd1498Szrj 		  fprintf (dump_file, "[%soffset: " HOST_WIDE_INT_PRINT_DEC
307138fd1498Szrj 			   "]: time_benefit: %i, size: %i\n",
307238fd1498Szrj 			   plats->aggs_by_ref ? "ref " : "",
307338fd1498Szrj 			   aglat->offset,
307438fd1498Szrj 			   val->local_time_benefit, val->local_size_cost);
307538fd1498Szrj 		}
307638fd1498Szrj 
307738fd1498Szrj 	      ajf->items->pop ();
307838fd1498Szrj 	    }
307938fd1498Szrj 	}
308038fd1498Szrj     }
308138fd1498Szrj 
308238fd1498Szrj   for (i = 0; i < count; i++)
308338fd1498Szrj     vec_free (known_aggs[i].items);
308438fd1498Szrj 
308538fd1498Szrj   known_csts.release ();
308638fd1498Szrj   known_contexts.release ();
308738fd1498Szrj   known_aggs.release ();
308838fd1498Szrj   known_aggs_ptrs.release ();
308938fd1498Szrj }
309038fd1498Szrj 
309138fd1498Szrj 
309238fd1498Szrj /* Add value CUR_VAL and all yet-unsorted values it is dependent on to the
309338fd1498Szrj    topological sort of values.  */
309438fd1498Szrj 
309538fd1498Szrj template <typename valtype>
309638fd1498Szrj void
add_val(ipcp_value<valtype> * cur_val)309738fd1498Szrj value_topo_info<valtype>::add_val (ipcp_value<valtype> *cur_val)
309838fd1498Szrj {
309938fd1498Szrj   ipcp_value_source<valtype> *src;
310038fd1498Szrj 
310138fd1498Szrj   if (cur_val->dfs)
310238fd1498Szrj     return;
310338fd1498Szrj 
310438fd1498Szrj   dfs_counter++;
310538fd1498Szrj   cur_val->dfs = dfs_counter;
310638fd1498Szrj   cur_val->low_link = dfs_counter;
310738fd1498Szrj 
310838fd1498Szrj   cur_val->topo_next = stack;
310938fd1498Szrj   stack = cur_val;
311038fd1498Szrj   cur_val->on_stack = true;
311138fd1498Szrj 
311238fd1498Szrj   for (src = cur_val->sources; src; src = src->next)
311338fd1498Szrj     if (src->val)
311438fd1498Szrj       {
311538fd1498Szrj 	if (src->val->dfs == 0)
311638fd1498Szrj 	  {
311738fd1498Szrj 	    add_val (src->val);
311838fd1498Szrj 	    if (src->val->low_link < cur_val->low_link)
311938fd1498Szrj 	      cur_val->low_link = src->val->low_link;
312038fd1498Szrj 	  }
312138fd1498Szrj 	else if (src->val->on_stack
312238fd1498Szrj 		 && src->val->dfs < cur_val->low_link)
312338fd1498Szrj 	  cur_val->low_link = src->val->dfs;
312438fd1498Szrj       }
312538fd1498Szrj 
312638fd1498Szrj   if (cur_val->dfs == cur_val->low_link)
312738fd1498Szrj     {
312838fd1498Szrj       ipcp_value<valtype> *v, *scc_list = NULL;
312938fd1498Szrj 
313038fd1498Szrj       do
313138fd1498Szrj 	{
313238fd1498Szrj 	  v = stack;
313338fd1498Szrj 	  stack = v->topo_next;
313438fd1498Szrj 	  v->on_stack = false;
313538fd1498Szrj 
313638fd1498Szrj 	  v->scc_next = scc_list;
313738fd1498Szrj 	  scc_list = v;
313838fd1498Szrj 	}
313938fd1498Szrj       while (v != cur_val);
314038fd1498Szrj 
314138fd1498Szrj       cur_val->topo_next = values_topo;
314238fd1498Szrj       values_topo = cur_val;
314338fd1498Szrj     }
314438fd1498Szrj }
314538fd1498Szrj 
314638fd1498Szrj /* Add all values in lattices associated with NODE to the topological sort if
314738fd1498Szrj    they are not there yet.  */
314838fd1498Szrj 
314938fd1498Szrj static void
add_all_node_vals_to_toposort(cgraph_node * node,ipa_topo_info * topo)315038fd1498Szrj add_all_node_vals_to_toposort (cgraph_node *node, ipa_topo_info *topo)
315138fd1498Szrj {
315238fd1498Szrj   struct ipa_node_params *info = IPA_NODE_REF (node);
315338fd1498Szrj   int i, count = ipa_get_param_count (info);
315438fd1498Szrj 
315538fd1498Szrj   for (i = 0; i < count; i++)
315638fd1498Szrj     {
315738fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
315838fd1498Szrj       ipcp_lattice<tree> *lat = &plats->itself;
315938fd1498Szrj       struct ipcp_agg_lattice *aglat;
316038fd1498Szrj 
316138fd1498Szrj       if (!lat->bottom)
316238fd1498Szrj 	{
316338fd1498Szrj 	  ipcp_value<tree> *val;
316438fd1498Szrj 	  for (val = lat->values; val; val = val->next)
316538fd1498Szrj 	    topo->constants.add_val (val);
316638fd1498Szrj 	}
316738fd1498Szrj 
316838fd1498Szrj       if (!plats->aggs_bottom)
316938fd1498Szrj 	for (aglat = plats->aggs; aglat; aglat = aglat->next)
317038fd1498Szrj 	  if (!aglat->bottom)
317138fd1498Szrj 	    {
317238fd1498Szrj 	      ipcp_value<tree> *val;
317338fd1498Szrj 	      for (val = aglat->values; val; val = val->next)
317438fd1498Szrj 		topo->constants.add_val (val);
317538fd1498Szrj 	    }
317638fd1498Szrj 
317738fd1498Szrj       ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
317838fd1498Szrj       if (!ctxlat->bottom)
317938fd1498Szrj 	{
318038fd1498Szrj 	  ipcp_value<ipa_polymorphic_call_context> *ctxval;
318138fd1498Szrj 	  for (ctxval = ctxlat->values; ctxval; ctxval = ctxval->next)
318238fd1498Szrj 	    topo->contexts.add_val (ctxval);
318338fd1498Szrj 	}
318438fd1498Szrj     }
318538fd1498Szrj }
318638fd1498Szrj 
318738fd1498Szrj /* One pass of constants propagation along the call graph edges, from callers
318838fd1498Szrj    to callees (requires topological ordering in TOPO), iterate over strongly
318938fd1498Szrj    connected components.  */
319038fd1498Szrj 
319138fd1498Szrj static void
propagate_constants_topo(struct ipa_topo_info * topo)319238fd1498Szrj propagate_constants_topo (struct ipa_topo_info *topo)
319338fd1498Szrj {
319438fd1498Szrj   int i;
319538fd1498Szrj 
319638fd1498Szrj   for (i = topo->nnodes - 1; i >= 0; i--)
319738fd1498Szrj     {
319838fd1498Szrj       unsigned j;
319938fd1498Szrj       struct cgraph_node *v, *node = topo->order[i];
320038fd1498Szrj       vec<cgraph_node *> cycle_nodes = ipa_get_nodes_in_cycle (node);
320138fd1498Szrj 
320238fd1498Szrj       /* First, iteratively propagate within the strongly connected component
320338fd1498Szrj 	 until all lattices stabilize.  */
320438fd1498Szrj       FOR_EACH_VEC_ELT (cycle_nodes, j, v)
320538fd1498Szrj 	if (v->has_gimple_body_p ())
320638fd1498Szrj 	  push_node_to_stack (topo, v);
320738fd1498Szrj 
320838fd1498Szrj       v = pop_node_from_stack (topo);
320938fd1498Szrj       while (v)
321038fd1498Szrj 	{
321138fd1498Szrj 	  struct cgraph_edge *cs;
321238fd1498Szrj 
321338fd1498Szrj 	  for (cs = v->callees; cs; cs = cs->next_callee)
321438fd1498Szrj 	    if (ipa_edge_within_scc (cs))
321538fd1498Szrj 	      {
321638fd1498Szrj 		IPA_NODE_REF (v)->node_within_scc = true;
321738fd1498Szrj 		if (propagate_constants_across_call (cs))
321838fd1498Szrj 		  push_node_to_stack (topo, cs->callee->function_symbol ());
321938fd1498Szrj 	      }
322038fd1498Szrj 	  v = pop_node_from_stack (topo);
322138fd1498Szrj 	}
322238fd1498Szrj 
322338fd1498Szrj       /* Afterwards, propagate along edges leading out of the SCC, calculates
322438fd1498Szrj 	 the local effects of the discovered constants and all valid values to
322538fd1498Szrj 	 their topological sort.  */
322638fd1498Szrj       FOR_EACH_VEC_ELT (cycle_nodes, j, v)
322738fd1498Szrj 	if (v->has_gimple_body_p ())
322838fd1498Szrj 	  {
322938fd1498Szrj 	    struct cgraph_edge *cs;
323038fd1498Szrj 
323138fd1498Szrj 	    estimate_local_effects (v);
323238fd1498Szrj 	    add_all_node_vals_to_toposort (v, topo);
323338fd1498Szrj 	    for (cs = v->callees; cs; cs = cs->next_callee)
323438fd1498Szrj 	      if (!ipa_edge_within_scc (cs))
323538fd1498Szrj 		propagate_constants_across_call (cs);
323638fd1498Szrj 	  }
323738fd1498Szrj       cycle_nodes.release ();
323838fd1498Szrj     }
323938fd1498Szrj }
324038fd1498Szrj 
324138fd1498Szrj 
324238fd1498Szrj /* Return the sum of A and B if none of them is bigger than INT_MAX/2, return
324338fd1498Szrj    the bigger one if otherwise.  */
324438fd1498Szrj 
324538fd1498Szrj static int
safe_add(int a,int b)324638fd1498Szrj safe_add (int a, int b)
324738fd1498Szrj {
324838fd1498Szrj   if (a > INT_MAX/2 || b > INT_MAX/2)
324938fd1498Szrj     return a > b ? a : b;
325038fd1498Szrj   else
325138fd1498Szrj     return a + b;
325238fd1498Szrj }
325338fd1498Szrj 
325438fd1498Szrj 
325538fd1498Szrj /* Propagate the estimated effects of individual values along the topological
325638fd1498Szrj    from the dependent values to those they depend on.  */
325738fd1498Szrj 
325838fd1498Szrj template <typename valtype>
325938fd1498Szrj void
propagate_effects()326038fd1498Szrj value_topo_info<valtype>::propagate_effects ()
326138fd1498Szrj {
326238fd1498Szrj   ipcp_value<valtype> *base;
326338fd1498Szrj 
326438fd1498Szrj   for (base = values_topo; base; base = base->topo_next)
326538fd1498Szrj     {
326638fd1498Szrj       ipcp_value_source<valtype> *src;
326738fd1498Szrj       ipcp_value<valtype> *val;
326838fd1498Szrj       int time = 0, size = 0;
326938fd1498Szrj 
327038fd1498Szrj       for (val = base; val; val = val->scc_next)
327138fd1498Szrj 	{
327238fd1498Szrj 	  time = safe_add (time,
327338fd1498Szrj 			   val->local_time_benefit + val->prop_time_benefit);
327438fd1498Szrj 	  size = safe_add (size, val->local_size_cost + val->prop_size_cost);
327538fd1498Szrj 	}
327638fd1498Szrj 
327738fd1498Szrj       for (val = base; val; val = val->scc_next)
327838fd1498Szrj 	for (src = val->sources; src; src = src->next)
327938fd1498Szrj 	  if (src->val
328038fd1498Szrj 	      && src->cs->maybe_hot_p ())
328138fd1498Szrj 	    {
328238fd1498Szrj 	      src->val->prop_time_benefit = safe_add (time,
328338fd1498Szrj 						src->val->prop_time_benefit);
328438fd1498Szrj 	      src->val->prop_size_cost = safe_add (size,
328538fd1498Szrj 						   src->val->prop_size_cost);
328638fd1498Szrj 	    }
328738fd1498Szrj     }
328838fd1498Szrj }
328938fd1498Szrj 
329038fd1498Szrj 
329138fd1498Szrj /* Propagate constants, polymorphic contexts and their effects from the
329238fd1498Szrj    summaries interprocedurally.  */
329338fd1498Szrj 
329438fd1498Szrj static void
ipcp_propagate_stage(struct ipa_topo_info * topo)329538fd1498Szrj ipcp_propagate_stage (struct ipa_topo_info *topo)
329638fd1498Szrj {
329738fd1498Szrj   struct cgraph_node *node;
329838fd1498Szrj 
329938fd1498Szrj   if (dump_file)
330038fd1498Szrj     fprintf (dump_file, "\n Propagating constants:\n\n");
330138fd1498Szrj 
330238fd1498Szrj   max_count = profile_count::uninitialized ();
330338fd1498Szrj 
330438fd1498Szrj   FOR_EACH_DEFINED_FUNCTION (node)
330538fd1498Szrj   {
330638fd1498Szrj     struct ipa_node_params *info = IPA_NODE_REF (node);
330738fd1498Szrj 
330838fd1498Szrj     determine_versionability (node, info);
330938fd1498Szrj     if (node->has_gimple_body_p ())
331038fd1498Szrj       {
331138fd1498Szrj 	info->lattices = XCNEWVEC (struct ipcp_param_lattices,
331238fd1498Szrj 				   ipa_get_param_count (info));
331338fd1498Szrj 	initialize_node_lattices (node);
331438fd1498Szrj       }
331538fd1498Szrj     if (node->definition && !node->alias)
331638fd1498Szrj       overall_size += ipa_fn_summaries->get (node)->self_size;
331738fd1498Szrj     max_count = max_count.max (node->count.ipa ());
331838fd1498Szrj   }
331938fd1498Szrj 
332038fd1498Szrj   max_new_size = overall_size;
332138fd1498Szrj   if (max_new_size < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS))
332238fd1498Szrj     max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS);
332338fd1498Szrj   max_new_size += max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1;
332438fd1498Szrj 
332538fd1498Szrj   if (dump_file)
332638fd1498Szrj     fprintf (dump_file, "\noverall_size: %li, max_new_size: %li\n",
332738fd1498Szrj 	     overall_size, max_new_size);
332838fd1498Szrj 
332938fd1498Szrj   propagate_constants_topo (topo);
333038fd1498Szrj   if (flag_checking)
333138fd1498Szrj     ipcp_verify_propagated_values ();
333238fd1498Szrj   topo->constants.propagate_effects ();
333338fd1498Szrj   topo->contexts.propagate_effects ();
333438fd1498Szrj 
333538fd1498Szrj   if (dump_file)
333638fd1498Szrj     {
333738fd1498Szrj       fprintf (dump_file, "\nIPA lattices after all propagation:\n");
333838fd1498Szrj       print_all_lattices (dump_file, (dump_flags & TDF_DETAILS), true);
333938fd1498Szrj     }
334038fd1498Szrj }
334138fd1498Szrj 
334238fd1498Szrj /* Discover newly direct outgoing edges from NODE which is a new clone with
334338fd1498Szrj    known KNOWN_CSTS and make them direct.  */
334438fd1498Szrj 
334538fd1498Szrj static void
ipcp_discover_new_direct_edges(struct cgraph_node * node,vec<tree> known_csts,vec<ipa_polymorphic_call_context> known_contexts,struct ipa_agg_replacement_value * aggvals)334638fd1498Szrj ipcp_discover_new_direct_edges (struct cgraph_node *node,
334738fd1498Szrj 				vec<tree> known_csts,
334838fd1498Szrj 				vec<ipa_polymorphic_call_context>
334938fd1498Szrj 				known_contexts,
335038fd1498Szrj 				struct ipa_agg_replacement_value *aggvals)
335138fd1498Szrj {
335238fd1498Szrj   struct cgraph_edge *ie, *next_ie;
335338fd1498Szrj   bool found = false;
335438fd1498Szrj 
335538fd1498Szrj   for (ie = node->indirect_calls; ie; ie = next_ie)
335638fd1498Szrj     {
335738fd1498Szrj       tree target;
335838fd1498Szrj       bool speculative;
335938fd1498Szrj 
336038fd1498Szrj       next_ie = ie->next_callee;
336138fd1498Szrj       target = ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
336238fd1498Szrj 					       vNULL, aggvals, &speculative);
336338fd1498Szrj       if (target)
336438fd1498Szrj 	{
336538fd1498Szrj 	  bool agg_contents = ie->indirect_info->agg_contents;
336638fd1498Szrj 	  bool polymorphic = ie->indirect_info->polymorphic;
336738fd1498Szrj 	  int param_index = ie->indirect_info->param_index;
336838fd1498Szrj 	  struct cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target,
336938fd1498Szrj 								   speculative);
337038fd1498Szrj 	  found = true;
337138fd1498Szrj 
337238fd1498Szrj 	  if (cs && !agg_contents && !polymorphic)
337338fd1498Szrj 	    {
337438fd1498Szrj 	      struct ipa_node_params *info = IPA_NODE_REF (node);
337538fd1498Szrj 	      int c = ipa_get_controlled_uses (info, param_index);
337638fd1498Szrj 	      if (c != IPA_UNDESCRIBED_USE)
337738fd1498Szrj 		{
337838fd1498Szrj 		  struct ipa_ref *to_del;
337938fd1498Szrj 
338038fd1498Szrj 		  c--;
338138fd1498Szrj 		  ipa_set_controlled_uses (info, param_index, c);
338238fd1498Szrj 		  if (dump_file && (dump_flags & TDF_DETAILS))
338338fd1498Szrj 		    fprintf (dump_file, "     controlled uses count of param "
338438fd1498Szrj 			     "%i bumped down to %i\n", param_index, c);
338538fd1498Szrj 		  if (c == 0
338638fd1498Szrj 		      && (to_del = node->find_reference (cs->callee, NULL, 0)))
338738fd1498Szrj 		    {
338838fd1498Szrj 		      if (dump_file && (dump_flags & TDF_DETAILS))
338938fd1498Szrj 			fprintf (dump_file, "       and even removing its "
339038fd1498Szrj 				 "cloning-created reference\n");
339138fd1498Szrj 		      to_del->remove_reference ();
339238fd1498Szrj 		    }
339338fd1498Szrj 		}
339438fd1498Szrj 	    }
339538fd1498Szrj 	}
339638fd1498Szrj     }
339738fd1498Szrj   /* Turning calls to direct calls will improve overall summary.  */
339838fd1498Szrj   if (found)
339938fd1498Szrj     ipa_update_overall_fn_summary (node);
340038fd1498Szrj }
340138fd1498Szrj 
340238fd1498Szrj /* Vector of pointers which for linked lists of clones of an original crgaph
340338fd1498Szrj    edge. */
340438fd1498Szrj 
340538fd1498Szrj static vec<cgraph_edge *> next_edge_clone;
340638fd1498Szrj static vec<cgraph_edge *> prev_edge_clone;
340738fd1498Szrj 
340838fd1498Szrj static inline void
grow_edge_clone_vectors(void)340938fd1498Szrj grow_edge_clone_vectors (void)
341038fd1498Szrj {
341138fd1498Szrj   if (next_edge_clone.length ()
341238fd1498Szrj       <=  (unsigned) symtab->edges_max_uid)
341338fd1498Szrj     next_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1);
341438fd1498Szrj   if (prev_edge_clone.length ()
341538fd1498Szrj       <=  (unsigned) symtab->edges_max_uid)
341638fd1498Szrj     prev_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1);
341738fd1498Szrj }
341838fd1498Szrj 
341938fd1498Szrj /* Edge duplication hook to grow the appropriate linked list in
342038fd1498Szrj    next_edge_clone. */
342138fd1498Szrj 
342238fd1498Szrj static void
ipcp_edge_duplication_hook(struct cgraph_edge * src,struct cgraph_edge * dst,void *)342338fd1498Szrj ipcp_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
342438fd1498Szrj 			    void *)
342538fd1498Szrj {
342638fd1498Szrj   grow_edge_clone_vectors ();
342738fd1498Szrj 
342838fd1498Szrj   struct cgraph_edge *old_next = next_edge_clone[src->uid];
342938fd1498Szrj   if (old_next)
343038fd1498Szrj     prev_edge_clone[old_next->uid] = dst;
343138fd1498Szrj   prev_edge_clone[dst->uid] = src;
343238fd1498Szrj 
343338fd1498Szrj   next_edge_clone[dst->uid] = old_next;
343438fd1498Szrj   next_edge_clone[src->uid] = dst;
343538fd1498Szrj }
343638fd1498Szrj 
343738fd1498Szrj /* Hook that is called by cgraph.c when an edge is removed.  */
343838fd1498Szrj 
343938fd1498Szrj static void
ipcp_edge_removal_hook(struct cgraph_edge * cs,void *)344038fd1498Szrj ipcp_edge_removal_hook (struct cgraph_edge *cs, void *)
344138fd1498Szrj {
344238fd1498Szrj   grow_edge_clone_vectors ();
344338fd1498Szrj 
344438fd1498Szrj   struct cgraph_edge *prev = prev_edge_clone[cs->uid];
344538fd1498Szrj   struct cgraph_edge *next = next_edge_clone[cs->uid];
344638fd1498Szrj   if (prev)
344738fd1498Szrj     next_edge_clone[prev->uid] = next;
344838fd1498Szrj   if (next)
344938fd1498Szrj     prev_edge_clone[next->uid] = prev;
345038fd1498Szrj }
345138fd1498Szrj 
345238fd1498Szrj /* See if NODE is a clone with a known aggregate value at a given OFFSET of a
345338fd1498Szrj    parameter with the given INDEX.  */
345438fd1498Szrj 
345538fd1498Szrj static tree
get_clone_agg_value(struct cgraph_node * node,HOST_WIDE_INT offset,int index)345638fd1498Szrj get_clone_agg_value (struct cgraph_node *node, HOST_WIDE_INT offset,
345738fd1498Szrj 		     int index)
345838fd1498Szrj {
345938fd1498Szrj   struct ipa_agg_replacement_value *aggval;
346038fd1498Szrj 
346138fd1498Szrj   aggval = ipa_get_agg_replacements_for_node (node);
346238fd1498Szrj   while (aggval)
346338fd1498Szrj     {
346438fd1498Szrj       if (aggval->offset == offset
346538fd1498Szrj 	  && aggval->index == index)
346638fd1498Szrj 	return aggval->value;
346738fd1498Szrj       aggval = aggval->next;
346838fd1498Szrj     }
346938fd1498Szrj   return NULL_TREE;
347038fd1498Szrj }
347138fd1498Szrj 
347238fd1498Szrj /* Return true is NODE is DEST or its clone for all contexts.  */
347338fd1498Szrj 
347438fd1498Szrj static bool
same_node_or_its_all_contexts_clone_p(cgraph_node * node,cgraph_node * dest)347538fd1498Szrj same_node_or_its_all_contexts_clone_p (cgraph_node *node, cgraph_node *dest)
347638fd1498Szrj {
347738fd1498Szrj   if (node == dest)
347838fd1498Szrj     return true;
347938fd1498Szrj 
348038fd1498Szrj   struct ipa_node_params *info = IPA_NODE_REF (node);
348138fd1498Szrj   return info->is_all_contexts_clone && info->ipcp_orig_node == dest;
348238fd1498Szrj }
348338fd1498Szrj 
348438fd1498Szrj /* Return true if edge CS does bring about the value described by SRC to
348538fd1498Szrj    DEST_VAL of node DEST or its clone for all contexts.  */
348638fd1498Szrj 
348738fd1498Szrj static bool
cgraph_edge_brings_value_p(cgraph_edge * cs,ipcp_value_source<tree> * src,cgraph_node * dest,ipcp_value<tree> * dest_val)348838fd1498Szrj cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<tree> *src,
348938fd1498Szrj 			    cgraph_node *dest, ipcp_value<tree> *dest_val)
349038fd1498Szrj {
349138fd1498Szrj   struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
349238fd1498Szrj   enum availability availability;
349338fd1498Szrj   cgraph_node *real_dest = cs->callee->function_symbol (&availability);
349438fd1498Szrj 
349538fd1498Szrj   if (!same_node_or_its_all_contexts_clone_p (real_dest, dest)
349638fd1498Szrj       || availability <= AVAIL_INTERPOSABLE
349738fd1498Szrj       || caller_info->node_dead)
349838fd1498Szrj     return false;
349938fd1498Szrj 
350038fd1498Szrj   if (!src->val)
350138fd1498Szrj     return true;
350238fd1498Szrj 
350338fd1498Szrj   if (caller_info->ipcp_orig_node)
350438fd1498Szrj     {
350538fd1498Szrj       tree t;
350638fd1498Szrj       if (src->offset == -1)
350738fd1498Szrj 	t = caller_info->known_csts[src->index];
350838fd1498Szrj       else
350938fd1498Szrj 	t = get_clone_agg_value (cs->caller, src->offset, src->index);
351038fd1498Szrj       return (t != NULL_TREE
351138fd1498Szrj 	      && values_equal_for_ipcp_p (src->val->value, t));
351238fd1498Szrj     }
351338fd1498Szrj   else
351438fd1498Szrj     {
351538fd1498Szrj       /* At the moment we do not propagate over arithmetic jump functions in
351638fd1498Szrj 	 SCCs, so it is safe to detect self-feeding recursive calls in this
351738fd1498Szrj 	 way.  */
351838fd1498Szrj       if (src->val == dest_val)
351938fd1498Szrj 	return true;
352038fd1498Szrj 
352138fd1498Szrj       struct ipcp_agg_lattice *aglat;
352238fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (caller_info,
352338fd1498Szrj 								 src->index);
352438fd1498Szrj       if (src->offset == -1)
352538fd1498Szrj 	return (plats->itself.is_single_const ()
352638fd1498Szrj 		&& values_equal_for_ipcp_p (src->val->value,
352738fd1498Szrj 					    plats->itself.values->value));
352838fd1498Szrj       else
352938fd1498Szrj 	{
353038fd1498Szrj 	  if (plats->aggs_bottom || plats->aggs_contain_variable)
353138fd1498Szrj 	    return false;
353238fd1498Szrj 	  for (aglat = plats->aggs; aglat; aglat = aglat->next)
353338fd1498Szrj 	    if (aglat->offset == src->offset)
353438fd1498Szrj 	      return  (aglat->is_single_const ()
353538fd1498Szrj 		       && values_equal_for_ipcp_p (src->val->value,
353638fd1498Szrj 						   aglat->values->value));
353738fd1498Szrj 	}
353838fd1498Szrj       return false;
353938fd1498Szrj     }
354038fd1498Szrj }
354138fd1498Szrj 
354238fd1498Szrj /* Return true if edge CS does bring about the value described by SRC to
354338fd1498Szrj    DST_VAL of node DEST or its clone for all contexts.  */
354438fd1498Szrj 
354538fd1498Szrj static bool
cgraph_edge_brings_value_p(cgraph_edge * cs,ipcp_value_source<ipa_polymorphic_call_context> * src,cgraph_node * dest,ipcp_value<ipa_polymorphic_call_context> *)354638fd1498Szrj cgraph_edge_brings_value_p (cgraph_edge *cs,
354738fd1498Szrj 			    ipcp_value_source<ipa_polymorphic_call_context> *src,
354838fd1498Szrj 			    cgraph_node *dest,
354938fd1498Szrj 			    ipcp_value<ipa_polymorphic_call_context> *)
355038fd1498Szrj {
355138fd1498Szrj   struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
355238fd1498Szrj   cgraph_node *real_dest = cs->callee->function_symbol ();
355338fd1498Szrj 
355438fd1498Szrj   if (!same_node_or_its_all_contexts_clone_p (real_dest, dest)
355538fd1498Szrj       || caller_info->node_dead)
355638fd1498Szrj     return false;
355738fd1498Szrj   if (!src->val)
355838fd1498Szrj     return true;
355938fd1498Szrj 
356038fd1498Szrj   if (caller_info->ipcp_orig_node)
356138fd1498Szrj     return (caller_info->known_contexts.length () > (unsigned) src->index)
356238fd1498Szrj       && values_equal_for_ipcp_p (src->val->value,
356338fd1498Szrj 				  caller_info->known_contexts[src->index]);
356438fd1498Szrj 
356538fd1498Szrj   struct ipcp_param_lattices *plats = ipa_get_parm_lattices (caller_info,
356638fd1498Szrj 							     src->index);
356738fd1498Szrj   return plats->ctxlat.is_single_const ()
356838fd1498Szrj     && values_equal_for_ipcp_p (src->val->value,
356938fd1498Szrj 				plats->ctxlat.values->value);
357038fd1498Szrj }
357138fd1498Szrj 
357238fd1498Szrj /* Get the next clone in the linked list of clones of an edge.  */
357338fd1498Szrj 
357438fd1498Szrj static inline struct cgraph_edge *
get_next_cgraph_edge_clone(struct cgraph_edge * cs)357538fd1498Szrj get_next_cgraph_edge_clone (struct cgraph_edge *cs)
357638fd1498Szrj {
357738fd1498Szrj   return next_edge_clone[cs->uid];
357838fd1498Szrj }
357938fd1498Szrj 
358038fd1498Szrj /* Given VAL that is intended for DEST, iterate over all its sources and if any
358138fd1498Szrj    of them is viable and hot, return true.  In that case, for those that still
358238fd1498Szrj    hold, add their edge frequency and their number into *FREQUENCY and
358338fd1498Szrj    *CALLER_COUNT respectively.  */
358438fd1498Szrj 
358538fd1498Szrj template <typename valtype>
358638fd1498Szrj static bool
get_info_about_necessary_edges(ipcp_value<valtype> * val,cgraph_node * dest,int * freq_sum,profile_count * count_sum,int * caller_count)358738fd1498Szrj get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest,
358838fd1498Szrj 				int *freq_sum,
358938fd1498Szrj 				profile_count *count_sum, int *caller_count)
359038fd1498Szrj {
359138fd1498Szrj   ipcp_value_source<valtype> *src;
359238fd1498Szrj   int freq = 0, count = 0;
359338fd1498Szrj   profile_count cnt = profile_count::zero ();
359438fd1498Szrj   bool hot = false;
359538fd1498Szrj   bool non_self_recursive = false;
359638fd1498Szrj 
359738fd1498Szrj   for (src = val->sources; src; src = src->next)
359838fd1498Szrj     {
359938fd1498Szrj       struct cgraph_edge *cs = src->cs;
360038fd1498Szrj       while (cs)
360138fd1498Szrj 	{
360238fd1498Szrj 	  if (cgraph_edge_brings_value_p (cs, src, dest, val))
360338fd1498Szrj 	    {
360438fd1498Szrj 	      count++;
360538fd1498Szrj 	      freq += cs->frequency ();
360638fd1498Szrj 	      if (cs->count.ipa ().initialized_p ())
360738fd1498Szrj 	        cnt += cs->count.ipa ();
360838fd1498Szrj 	      hot |= cs->maybe_hot_p ();
360938fd1498Szrj 	      if (cs->caller != dest)
361038fd1498Szrj 		non_self_recursive = true;
361138fd1498Szrj 	    }
361238fd1498Szrj 	  cs = get_next_cgraph_edge_clone (cs);
361338fd1498Szrj 	}
361438fd1498Szrj     }
361538fd1498Szrj 
361638fd1498Szrj   /* If the only edges bringing a value are self-recursive ones, do not bother
361738fd1498Szrj      evaluating it.  */
361838fd1498Szrj   if (!non_self_recursive)
361938fd1498Szrj     return false;
362038fd1498Szrj 
362138fd1498Szrj   *freq_sum = freq;
362238fd1498Szrj   *count_sum = cnt;
362338fd1498Szrj   *caller_count = count;
362438fd1498Szrj   return hot;
362538fd1498Szrj }
362638fd1498Szrj 
362738fd1498Szrj /* Return a vector of incoming edges that do bring value VAL to node DEST.  It
362838fd1498Szrj    is assumed their number is known and equal to CALLER_COUNT.  */
362938fd1498Szrj 
363038fd1498Szrj template <typename valtype>
363138fd1498Szrj static vec<cgraph_edge *>
gather_edges_for_value(ipcp_value<valtype> * val,cgraph_node * dest,int caller_count)363238fd1498Szrj gather_edges_for_value (ipcp_value<valtype> *val, cgraph_node *dest,
363338fd1498Szrj 			int caller_count)
363438fd1498Szrj {
363538fd1498Szrj   ipcp_value_source<valtype> *src;
363638fd1498Szrj   vec<cgraph_edge *> ret;
363738fd1498Szrj 
363838fd1498Szrj   ret.create (caller_count);
363938fd1498Szrj   for (src = val->sources; src; src = src->next)
364038fd1498Szrj     {
364138fd1498Szrj       struct cgraph_edge *cs = src->cs;
364238fd1498Szrj       while (cs)
364338fd1498Szrj 	{
364438fd1498Szrj 	  if (cgraph_edge_brings_value_p (cs, src, dest, val))
364538fd1498Szrj 	    ret.quick_push (cs);
364638fd1498Szrj 	  cs = get_next_cgraph_edge_clone (cs);
364738fd1498Szrj 	}
364838fd1498Szrj     }
364938fd1498Szrj 
365038fd1498Szrj   return ret;
365138fd1498Szrj }
365238fd1498Szrj 
365338fd1498Szrj /* Construct a replacement map for a know VALUE for a formal parameter PARAM.
365438fd1498Szrj    Return it or NULL if for some reason it cannot be created.  */
365538fd1498Szrj 
365638fd1498Szrj static struct ipa_replace_map *
get_replacement_map(struct ipa_node_params * info,tree value,int parm_num)365738fd1498Szrj get_replacement_map (struct ipa_node_params *info, tree value, int parm_num)
365838fd1498Szrj {
365938fd1498Szrj   struct ipa_replace_map *replace_map;
366038fd1498Szrj 
366138fd1498Szrj 
366238fd1498Szrj   replace_map = ggc_alloc<ipa_replace_map> ();
366338fd1498Szrj   if (dump_file)
366438fd1498Szrj     {
366538fd1498Szrj       fprintf (dump_file, "    replacing ");
366638fd1498Szrj       ipa_dump_param (dump_file, info, parm_num);
366738fd1498Szrj 
366838fd1498Szrj       fprintf (dump_file, " with const ");
366938fd1498Szrj       print_generic_expr (dump_file, value);
367038fd1498Szrj       fprintf (dump_file, "\n");
367138fd1498Szrj     }
367238fd1498Szrj   replace_map->old_tree = NULL;
367338fd1498Szrj   replace_map->parm_num = parm_num;
367438fd1498Szrj   replace_map->new_tree = value;
367538fd1498Szrj   replace_map->replace_p = true;
367638fd1498Szrj   replace_map->ref_p = false;
367738fd1498Szrj 
367838fd1498Szrj   return replace_map;
367938fd1498Szrj }
368038fd1498Szrj 
368138fd1498Szrj /* Dump new profiling counts */
368238fd1498Szrj 
368338fd1498Szrj static void
dump_profile_updates(struct cgraph_node * orig_node,struct cgraph_node * new_node)368438fd1498Szrj dump_profile_updates (struct cgraph_node *orig_node,
368538fd1498Szrj 		      struct cgraph_node *new_node)
368638fd1498Szrj {
368738fd1498Szrj   struct cgraph_edge *cs;
368838fd1498Szrj 
368938fd1498Szrj   fprintf (dump_file, "    setting count of the specialized node to ");
369038fd1498Szrj   new_node->count.dump (dump_file);
369138fd1498Szrj   fprintf (dump_file, "\n");
369238fd1498Szrj   for (cs = new_node->callees; cs; cs = cs->next_callee)
369338fd1498Szrj     {
369438fd1498Szrj       fprintf (dump_file, "      edge to %s has count ",
369538fd1498Szrj 	       cs->callee->name ());
369638fd1498Szrj       cs->count.dump (dump_file);
369738fd1498Szrj       fprintf (dump_file, "\n");
369838fd1498Szrj     }
369938fd1498Szrj 
370038fd1498Szrj   fprintf (dump_file, "    setting count of the original node to ");
370138fd1498Szrj   orig_node->count.dump (dump_file);
370238fd1498Szrj   fprintf (dump_file, "\n");
370338fd1498Szrj   for (cs = orig_node->callees; cs; cs = cs->next_callee)
370438fd1498Szrj     {
370538fd1498Szrj       fprintf (dump_file, "      edge to %s is left with ",
370638fd1498Szrj 	       cs->callee->name ());
370738fd1498Szrj       cs->count.dump (dump_file);
370838fd1498Szrj       fprintf (dump_file, "\n");
370938fd1498Szrj     }
371038fd1498Szrj }
371138fd1498Szrj 
371238fd1498Szrj /* After a specialized NEW_NODE version of ORIG_NODE has been created, update
371338fd1498Szrj    their profile information to reflect this.  */
371438fd1498Szrj 
371538fd1498Szrj static void
update_profiling_info(struct cgraph_node * orig_node,struct cgraph_node * new_node)371638fd1498Szrj update_profiling_info (struct cgraph_node *orig_node,
371738fd1498Szrj 		       struct cgraph_node *new_node)
371838fd1498Szrj {
371938fd1498Szrj   struct cgraph_edge *cs;
372038fd1498Szrj   struct caller_statistics stats;
372138fd1498Szrj   profile_count new_sum, orig_sum;
372238fd1498Szrj   profile_count remainder, orig_node_count = orig_node->count;
372338fd1498Szrj 
372438fd1498Szrj   if (!(orig_node_count.ipa () > profile_count::zero ()))
372538fd1498Szrj     return;
372638fd1498Szrj 
372738fd1498Szrj   init_caller_stats (&stats);
372838fd1498Szrj   orig_node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats,
372938fd1498Szrj 					       false);
373038fd1498Szrj   orig_sum = stats.count_sum;
373138fd1498Szrj   init_caller_stats (&stats);
373238fd1498Szrj   new_node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats,
373338fd1498Szrj 					      false);
373438fd1498Szrj   new_sum = stats.count_sum;
373538fd1498Szrj 
373638fd1498Szrj   if (orig_node_count < orig_sum + new_sum)
373738fd1498Szrj     {
373838fd1498Szrj       if (dump_file)
373938fd1498Szrj 	{
374038fd1498Szrj 	  fprintf (dump_file, "    Problem: node %s has too low count ",
374138fd1498Szrj 		   orig_node->dump_name ());
374238fd1498Szrj 	  orig_node_count.dump (dump_file);
374338fd1498Szrj 	  fprintf (dump_file, "while the sum of incoming count is ");
374438fd1498Szrj 	  (orig_sum + new_sum).dump (dump_file);
374538fd1498Szrj 	  fprintf (dump_file, "\n");
374638fd1498Szrj 	}
374738fd1498Szrj 
374838fd1498Szrj       orig_node_count = (orig_sum + new_sum).apply_scale (12, 10);
374938fd1498Szrj       if (dump_file)
375038fd1498Szrj 	{
375138fd1498Szrj 	  fprintf (dump_file, "      proceeding by pretending it was ");
375238fd1498Szrj 	  orig_node_count.dump (dump_file);
375338fd1498Szrj 	  fprintf (dump_file, "\n");
375438fd1498Szrj 	}
375538fd1498Szrj     }
375638fd1498Szrj 
375738fd1498Szrj   remainder = orig_node_count.combine_with_ipa_count (orig_node_count.ipa ()
375838fd1498Szrj 						      - new_sum.ipa ());
375938fd1498Szrj   new_sum = orig_node_count.combine_with_ipa_count (new_sum);
376038fd1498Szrj   orig_node->count = remainder;
376138fd1498Szrj 
376238fd1498Szrj   for (cs = new_node->callees; cs; cs = cs->next_callee)
376338fd1498Szrj     cs->count = cs->count.apply_scale (new_sum, orig_node_count);
376438fd1498Szrj 
376538fd1498Szrj   for (cs = orig_node->callees; cs; cs = cs->next_callee)
376638fd1498Szrj     cs->count = cs->count.apply_scale (remainder, orig_node_count);
376738fd1498Szrj 
376838fd1498Szrj   if (dump_file)
376938fd1498Szrj     dump_profile_updates (orig_node, new_node);
377038fd1498Szrj }
377138fd1498Szrj 
377238fd1498Szrj /* Update the respective profile of specialized NEW_NODE and the original
377338fd1498Szrj    ORIG_NODE after additional edges with cumulative count sum REDIRECTED_SUM
377438fd1498Szrj    have been redirected to the specialized version.  */
377538fd1498Szrj 
377638fd1498Szrj static void
update_specialized_profile(struct cgraph_node * new_node,struct cgraph_node * orig_node,profile_count redirected_sum)377738fd1498Szrj update_specialized_profile (struct cgraph_node *new_node,
377838fd1498Szrj 			    struct cgraph_node *orig_node,
377938fd1498Szrj 			    profile_count redirected_sum)
378038fd1498Szrj {
378138fd1498Szrj   struct cgraph_edge *cs;
378238fd1498Szrj   profile_count new_node_count, orig_node_count = orig_node->count;
378338fd1498Szrj 
378438fd1498Szrj   if (dump_file)
378538fd1498Szrj     {
378638fd1498Szrj       fprintf (dump_file, "    the sum of counts of redirected  edges is ");
378738fd1498Szrj       redirected_sum.dump (dump_file);
378838fd1498Szrj       fprintf (dump_file, "\n");
378938fd1498Szrj     }
379038fd1498Szrj   if (!(orig_node_count > profile_count::zero ()))
379138fd1498Szrj     return;
379238fd1498Szrj 
379338fd1498Szrj   gcc_assert (orig_node_count >= redirected_sum);
379438fd1498Szrj 
379538fd1498Szrj   new_node_count = new_node->count;
379638fd1498Szrj   new_node->count += redirected_sum;
379738fd1498Szrj   orig_node->count -= redirected_sum;
379838fd1498Szrj 
379938fd1498Szrj   for (cs = new_node->callees; cs; cs = cs->next_callee)
380038fd1498Szrj     cs->count += cs->count.apply_scale (redirected_sum, new_node_count);
380138fd1498Szrj 
380238fd1498Szrj   for (cs = orig_node->callees; cs; cs = cs->next_callee)
380338fd1498Szrj     {
380438fd1498Szrj       profile_count dec = cs->count.apply_scale (redirected_sum,
380538fd1498Szrj 						 orig_node_count);
380638fd1498Szrj       cs->count -= dec;
380738fd1498Szrj     }
380838fd1498Szrj 
380938fd1498Szrj   if (dump_file)
381038fd1498Szrj     dump_profile_updates (orig_node, new_node);
381138fd1498Szrj }
381238fd1498Szrj 
381338fd1498Szrj /* Create a specialized version of NODE with known constants in KNOWN_CSTS,
381438fd1498Szrj    known contexts in KNOWN_CONTEXTS and known aggregate values in AGGVALS and
381538fd1498Szrj    redirect all edges in CALLERS to it.  */
381638fd1498Szrj 
381738fd1498Szrj static struct cgraph_node *
create_specialized_node(struct cgraph_node * node,vec<tree> known_csts,vec<ipa_polymorphic_call_context> known_contexts,struct ipa_agg_replacement_value * aggvals,vec<cgraph_edge * > callers)381838fd1498Szrj create_specialized_node (struct cgraph_node *node,
381938fd1498Szrj 			 vec<tree> known_csts,
382038fd1498Szrj 			 vec<ipa_polymorphic_call_context> known_contexts,
382138fd1498Szrj 			 struct ipa_agg_replacement_value *aggvals,
382238fd1498Szrj 			 vec<cgraph_edge *> callers)
382338fd1498Szrj {
382438fd1498Szrj   struct ipa_node_params *new_info, *info = IPA_NODE_REF (node);
382538fd1498Szrj   vec<ipa_replace_map *, va_gc> *replace_trees = NULL;
382638fd1498Szrj   struct ipa_agg_replacement_value *av;
382738fd1498Szrj   struct cgraph_node *new_node;
382838fd1498Szrj   int i, count = ipa_get_param_count (info);
382938fd1498Szrj   bitmap args_to_skip;
383038fd1498Szrj 
383138fd1498Szrj   gcc_assert (!info->ipcp_orig_node);
383238fd1498Szrj 
383338fd1498Szrj   if (node->local.can_change_signature)
383438fd1498Szrj     {
383538fd1498Szrj       args_to_skip = BITMAP_GGC_ALLOC ();
383638fd1498Szrj       for (i = 0; i < count; i++)
383738fd1498Szrj 	{
383838fd1498Szrj 	  tree t = known_csts[i];
383938fd1498Szrj 
384038fd1498Szrj 	  if (t || !ipa_is_param_used (info, i))
384138fd1498Szrj 	    bitmap_set_bit (args_to_skip, i);
384238fd1498Szrj 	}
384338fd1498Szrj     }
384438fd1498Szrj   else
384538fd1498Szrj     {
384638fd1498Szrj       args_to_skip = NULL;
384738fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
384838fd1498Szrj 	fprintf (dump_file, "      cannot change function signature\n");
384938fd1498Szrj     }
385038fd1498Szrj 
385138fd1498Szrj   for (i = 0; i < count; i++)
385238fd1498Szrj     {
385338fd1498Szrj       tree t = known_csts[i];
385438fd1498Szrj       if (t)
385538fd1498Szrj 	{
385638fd1498Szrj 	  struct ipa_replace_map *replace_map;
385738fd1498Szrj 
385838fd1498Szrj 	  gcc_checking_assert (TREE_CODE (t) != TREE_BINFO);
385938fd1498Szrj 	  replace_map = get_replacement_map (info, t, i);
386038fd1498Szrj 	  if (replace_map)
386138fd1498Szrj 	    vec_safe_push (replace_trees, replace_map);
386238fd1498Szrj 	}
386338fd1498Szrj     }
386438fd1498Szrj   auto_vec<cgraph_edge *, 2> self_recursive_calls;
386538fd1498Szrj   for (i = callers.length () - 1; i >= 0; i--)
386638fd1498Szrj     {
386738fd1498Szrj       cgraph_edge *cs = callers[i];
386838fd1498Szrj       if (cs->caller == node)
386938fd1498Szrj 	{
387038fd1498Szrj 	  self_recursive_calls.safe_push (cs);
387138fd1498Szrj 	  callers.unordered_remove (i);
387238fd1498Szrj 	}
387338fd1498Szrj     }
387438fd1498Szrj 
387538fd1498Szrj   new_node = node->create_virtual_clone (callers, replace_trees,
387638fd1498Szrj 					 args_to_skip, "constprop");
387738fd1498Szrj 
387838fd1498Szrj   bool have_self_recursive_calls = !self_recursive_calls.is_empty ();
387938fd1498Szrj   for (unsigned j = 0; j < self_recursive_calls.length (); j++)
388038fd1498Szrj     {
388138fd1498Szrj       cgraph_edge *cs = next_edge_clone[self_recursive_calls[j]->uid];
388238fd1498Szrj       /* Cloned edges can disappear during cloning as speculation can be
388338fd1498Szrj 	 resolved, check that we have one and that it comes from the last
388438fd1498Szrj 	 cloning.  */
388538fd1498Szrj       if (cs && cs->caller == new_node)
388638fd1498Szrj 	cs->redirect_callee_duplicating_thunks (new_node);
388738fd1498Szrj       /* Any future code that would make more than one clone of an outgoing
388838fd1498Szrj 	 edge would confuse this mechanism, so let's check that does not
388938fd1498Szrj 	 happen.  */
389038fd1498Szrj       gcc_checking_assert (!cs
389138fd1498Szrj 			   || !next_edge_clone[cs->uid]
389238fd1498Szrj 			   || next_edge_clone[cs->uid]->caller != new_node);
389338fd1498Szrj     }
389438fd1498Szrj   if (have_self_recursive_calls)
389538fd1498Szrj     new_node->expand_all_artificial_thunks ();
389638fd1498Szrj 
389738fd1498Szrj   ipa_set_node_agg_value_chain (new_node, aggvals);
389838fd1498Szrj   for (av = aggvals; av; av = av->next)
389938fd1498Szrj     new_node->maybe_create_reference (av->value, NULL);
390038fd1498Szrj 
390138fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
390238fd1498Szrj     {
390338fd1498Szrj       fprintf (dump_file, "     the new node is %s.\n", new_node->dump_name ());
390438fd1498Szrj       if (known_contexts.exists ())
390538fd1498Szrj 	{
390638fd1498Szrj 	  for (i = 0; i < count; i++)
390738fd1498Szrj 	    if (!known_contexts[i].useless_p ())
390838fd1498Szrj 	      {
390938fd1498Szrj 		fprintf (dump_file, "     known ctx %i is ", i);
391038fd1498Szrj 		known_contexts[i].dump (dump_file);
391138fd1498Szrj 	      }
391238fd1498Szrj 	}
391338fd1498Szrj       if (aggvals)
391438fd1498Szrj 	ipa_dump_agg_replacement_values (dump_file, aggvals);
391538fd1498Szrj     }
391638fd1498Szrj   ipa_check_create_node_params ();
391738fd1498Szrj   update_profiling_info (node, new_node);
391838fd1498Szrj   new_info = IPA_NODE_REF (new_node);
391938fd1498Szrj   new_info->ipcp_orig_node = node;
392038fd1498Szrj   new_info->known_csts = known_csts;
392138fd1498Szrj   new_info->known_contexts = known_contexts;
392238fd1498Szrj 
392338fd1498Szrj   ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts, aggvals);
392438fd1498Szrj 
392538fd1498Szrj   callers.release ();
392638fd1498Szrj   return new_node;
392738fd1498Szrj }
392838fd1498Szrj 
392938fd1498Szrj /* Return true, if JFUNC, which describes a i-th parameter of call CS, is a
393038fd1498Szrj    simple no-operation pass-through function to itself.  */
393138fd1498Szrj 
393238fd1498Szrj static bool
self_recursive_pass_through_p(cgraph_edge * cs,ipa_jump_func * jfunc,int i)393338fd1498Szrj self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i)
393438fd1498Szrj {
393538fd1498Szrj   enum availability availability;
393638fd1498Szrj   if (cs->caller == cs->callee->function_symbol (&availability)
393738fd1498Szrj       && availability > AVAIL_INTERPOSABLE
393838fd1498Szrj       && jfunc->type == IPA_JF_PASS_THROUGH
393938fd1498Szrj       && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR
394038fd1498Szrj       && ipa_get_jf_pass_through_formal_id (jfunc) == i)
394138fd1498Szrj     return true;
394238fd1498Szrj   return false;
394338fd1498Szrj }
394438fd1498Szrj 
394538fd1498Szrj /* Given a NODE, and a subset of its CALLERS, try to populate blanks slots in
394638fd1498Szrj    KNOWN_CSTS with constants that are also known for all of the CALLERS.  */
394738fd1498Szrj 
394838fd1498Szrj static void
find_more_scalar_values_for_callers_subset(struct cgraph_node * node,vec<tree> known_csts,vec<cgraph_edge * > callers)394938fd1498Szrj find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
395038fd1498Szrj 					    vec<tree> known_csts,
395138fd1498Szrj 					    vec<cgraph_edge *> callers)
395238fd1498Szrj {
395338fd1498Szrj   struct ipa_node_params *info = IPA_NODE_REF (node);
395438fd1498Szrj   int i, count = ipa_get_param_count (info);
395538fd1498Szrj 
395638fd1498Szrj   for (i = 0; i < count; i++)
395738fd1498Szrj     {
395838fd1498Szrj       struct cgraph_edge *cs;
395938fd1498Szrj       tree newval = NULL_TREE;
396038fd1498Szrj       int j;
396138fd1498Szrj       bool first = true;
396238fd1498Szrj       tree type = ipa_get_type (info, i);
396338fd1498Szrj 
396438fd1498Szrj       if (ipa_get_scalar_lat (info, i)->bottom || known_csts[i])
396538fd1498Szrj 	continue;
396638fd1498Szrj 
396738fd1498Szrj       FOR_EACH_VEC_ELT (callers, j, cs)
396838fd1498Szrj 	{
396938fd1498Szrj 	  struct ipa_jump_func *jump_func;
397038fd1498Szrj 	  tree t;
397138fd1498Szrj 
397238fd1498Szrj 	  if (IPA_NODE_REF (cs->caller)->node_dead)
397338fd1498Szrj 	    continue;
397438fd1498Szrj 
397538fd1498Szrj 	  if (i >= ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
397638fd1498Szrj 	      || (i == 0
397738fd1498Szrj 		  && call_passes_through_thunk_p (cs))
397838fd1498Szrj 	      || (!cs->callee->instrumentation_clone
397938fd1498Szrj 		  && cs->callee->function_symbol ()->instrumentation_clone))
398038fd1498Szrj 	    {
398138fd1498Szrj 	      newval = NULL_TREE;
398238fd1498Szrj 	      break;
398338fd1498Szrj 	    }
398438fd1498Szrj 	  jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
398538fd1498Szrj 	  if (self_recursive_pass_through_p (cs, jump_func, i))
398638fd1498Szrj 	    continue;
398738fd1498Szrj 
398838fd1498Szrj 	  t = ipa_value_from_jfunc (IPA_NODE_REF (cs->caller), jump_func, type);
398938fd1498Szrj 	  if (!t
399038fd1498Szrj 	      || (newval
399138fd1498Szrj 		  && !values_equal_for_ipcp_p (t, newval))
399238fd1498Szrj 	      || (!first && !newval))
399338fd1498Szrj 	    {
399438fd1498Szrj 	      newval = NULL_TREE;
399538fd1498Szrj 	      break;
399638fd1498Szrj 	    }
399738fd1498Szrj 	  else
399838fd1498Szrj 	    newval = t;
399938fd1498Szrj 	  first = false;
400038fd1498Szrj 	}
400138fd1498Szrj 
400238fd1498Szrj       if (newval)
400338fd1498Szrj 	{
400438fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
400538fd1498Szrj 	    {
400638fd1498Szrj 	      fprintf (dump_file, "    adding an extra known scalar value ");
400738fd1498Szrj 	      print_ipcp_constant_value (dump_file, newval);
400838fd1498Szrj 	      fprintf (dump_file, " for ");
400938fd1498Szrj 	      ipa_dump_param (dump_file, info, i);
401038fd1498Szrj 	      fprintf (dump_file, "\n");
401138fd1498Szrj 	    }
401238fd1498Szrj 
401338fd1498Szrj 	  known_csts[i] = newval;
401438fd1498Szrj 	}
401538fd1498Szrj     }
401638fd1498Szrj }
401738fd1498Szrj 
401838fd1498Szrj /* Given a NODE and a subset of its CALLERS, try to populate plank slots in
401938fd1498Szrj    KNOWN_CONTEXTS with polymorphic contexts that are also known for all of the
402038fd1498Szrj    CALLERS.  */
402138fd1498Szrj 
402238fd1498Szrj static void
find_more_contexts_for_caller_subset(cgraph_node * node,vec<ipa_polymorphic_call_context> * known_contexts,vec<cgraph_edge * > callers)402338fd1498Szrj find_more_contexts_for_caller_subset (cgraph_node *node,
402438fd1498Szrj 				      vec<ipa_polymorphic_call_context>
402538fd1498Szrj 				      *known_contexts,
402638fd1498Szrj 				      vec<cgraph_edge *> callers)
402738fd1498Szrj {
402838fd1498Szrj   ipa_node_params *info = IPA_NODE_REF (node);
402938fd1498Szrj   int i, count = ipa_get_param_count (info);
403038fd1498Szrj 
403138fd1498Szrj   for (i = 0; i < count; i++)
403238fd1498Szrj     {
403338fd1498Szrj       cgraph_edge *cs;
403438fd1498Szrj 
403538fd1498Szrj       if (ipa_get_poly_ctx_lat (info, i)->bottom
403638fd1498Szrj 	  || (known_contexts->exists ()
403738fd1498Szrj 	      && !(*known_contexts)[i].useless_p ()))
403838fd1498Szrj 	continue;
403938fd1498Szrj 
404038fd1498Szrj       ipa_polymorphic_call_context newval;
404138fd1498Szrj       bool first = true;
404238fd1498Szrj       int j;
404338fd1498Szrj 
404438fd1498Szrj       FOR_EACH_VEC_ELT (callers, j, cs)
404538fd1498Szrj 	{
404638fd1498Szrj 	  if (i >= ipa_get_cs_argument_count (IPA_EDGE_REF (cs)))
404738fd1498Szrj 	    return;
404838fd1498Szrj 	  ipa_jump_func *jfunc = ipa_get_ith_jump_func (IPA_EDGE_REF (cs),
404938fd1498Szrj 							    i);
405038fd1498Szrj 	  ipa_polymorphic_call_context ctx;
405138fd1498Szrj 	  ctx = ipa_context_from_jfunc (IPA_NODE_REF (cs->caller), cs, i,
405238fd1498Szrj 					jfunc);
405338fd1498Szrj 	  if (first)
405438fd1498Szrj 	    {
405538fd1498Szrj 	      newval = ctx;
405638fd1498Szrj 	      first = false;
405738fd1498Szrj 	    }
405838fd1498Szrj 	  else
405938fd1498Szrj 	    newval.meet_with (ctx);
406038fd1498Szrj 	  if (newval.useless_p ())
406138fd1498Szrj 	    break;
406238fd1498Szrj 	}
406338fd1498Szrj 
406438fd1498Szrj       if (!newval.useless_p ())
406538fd1498Szrj 	{
406638fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
406738fd1498Szrj 	    {
406838fd1498Szrj 	      fprintf (dump_file, "    adding an extra known polymorphic "
406938fd1498Szrj 		       "context ");
407038fd1498Szrj 	      print_ipcp_constant_value (dump_file, newval);
407138fd1498Szrj 	      fprintf (dump_file, " for ");
407238fd1498Szrj 	      ipa_dump_param (dump_file, info, i);
407338fd1498Szrj 	      fprintf (dump_file, "\n");
407438fd1498Szrj 	    }
407538fd1498Szrj 
407638fd1498Szrj 	  if (!known_contexts->exists ())
407738fd1498Szrj 	    known_contexts->safe_grow_cleared (ipa_get_param_count (info));
407838fd1498Szrj 	  (*known_contexts)[i] = newval;
407938fd1498Szrj 	}
408038fd1498Szrj 
408138fd1498Szrj     }
408238fd1498Szrj }
408338fd1498Szrj 
408438fd1498Szrj /* Go through PLATS and create a vector of values consisting of values and
408538fd1498Szrj    offsets (minus OFFSET) of lattices that contain only a single value.  */
408638fd1498Szrj 
408738fd1498Szrj static vec<ipa_agg_jf_item>
copy_plats_to_inter(struct ipcp_param_lattices * plats,HOST_WIDE_INT offset)408838fd1498Szrj copy_plats_to_inter (struct ipcp_param_lattices *plats, HOST_WIDE_INT offset)
408938fd1498Szrj {
409038fd1498Szrj   vec<ipa_agg_jf_item> res = vNULL;
409138fd1498Szrj 
409238fd1498Szrj   if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom)
409338fd1498Szrj     return vNULL;
409438fd1498Szrj 
409538fd1498Szrj   for (struct ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next)
409638fd1498Szrj     if (aglat->is_single_const ())
409738fd1498Szrj       {
409838fd1498Szrj 	struct ipa_agg_jf_item ti;
409938fd1498Szrj 	ti.offset = aglat->offset - offset;
410038fd1498Szrj 	ti.value = aglat->values->value;
410138fd1498Szrj 	res.safe_push (ti);
410238fd1498Szrj       }
410338fd1498Szrj   return res;
410438fd1498Szrj }
410538fd1498Szrj 
410638fd1498Szrj /* Intersect all values in INTER with single value lattices in PLATS (while
410738fd1498Szrj    subtracting OFFSET).  */
410838fd1498Szrj 
410938fd1498Szrj static void
intersect_with_plats(struct ipcp_param_lattices * plats,vec<ipa_agg_jf_item> * inter,HOST_WIDE_INT offset)411038fd1498Szrj intersect_with_plats (struct ipcp_param_lattices *plats,
411138fd1498Szrj 		      vec<ipa_agg_jf_item> *inter,
411238fd1498Szrj 		      HOST_WIDE_INT offset)
411338fd1498Szrj {
411438fd1498Szrj   struct ipcp_agg_lattice *aglat;
411538fd1498Szrj   struct ipa_agg_jf_item *item;
411638fd1498Szrj   int k;
411738fd1498Szrj 
411838fd1498Szrj   if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom)
411938fd1498Szrj     {
412038fd1498Szrj       inter->release ();
412138fd1498Szrj       return;
412238fd1498Szrj     }
412338fd1498Szrj 
412438fd1498Szrj   aglat = plats->aggs;
412538fd1498Szrj   FOR_EACH_VEC_ELT (*inter, k, item)
412638fd1498Szrj     {
412738fd1498Szrj       bool found = false;
412838fd1498Szrj       if (!item->value)
412938fd1498Szrj 	continue;
413038fd1498Szrj       while (aglat)
413138fd1498Szrj 	{
413238fd1498Szrj 	  if (aglat->offset - offset > item->offset)
413338fd1498Szrj 	    break;
413438fd1498Szrj 	  if (aglat->offset - offset == item->offset)
413538fd1498Szrj 	    {
413638fd1498Szrj 	      gcc_checking_assert (item->value);
413758e805e6Szrj 	      if (aglat->is_single_const ()
413858e805e6Szrj 		  && values_equal_for_ipcp_p (item->value,
413958e805e6Szrj 					      aglat->values->value))
414038fd1498Szrj 		found = true;
414138fd1498Szrj 	      break;
414238fd1498Szrj 	    }
414338fd1498Szrj 	  aglat = aglat->next;
414438fd1498Szrj 	}
414538fd1498Szrj       if (!found)
414638fd1498Szrj 	item->value = NULL_TREE;
414738fd1498Szrj     }
414838fd1498Szrj }
414938fd1498Szrj 
415038fd1498Szrj /* Copy aggregate replacement values of NODE (which is an IPA-CP clone) to the
415138fd1498Szrj    vector result while subtracting OFFSET from the individual value offsets.  */
415238fd1498Szrj 
415338fd1498Szrj static vec<ipa_agg_jf_item>
agg_replacements_to_vector(struct cgraph_node * node,int index,HOST_WIDE_INT offset)415438fd1498Szrj agg_replacements_to_vector (struct cgraph_node *node, int index,
415538fd1498Szrj 			    HOST_WIDE_INT offset)
415638fd1498Szrj {
415738fd1498Szrj   struct ipa_agg_replacement_value *av;
415838fd1498Szrj   vec<ipa_agg_jf_item> res = vNULL;
415938fd1498Szrj 
416038fd1498Szrj   for (av = ipa_get_agg_replacements_for_node (node); av; av = av->next)
416138fd1498Szrj     if (av->index == index
416238fd1498Szrj 	&& (av->offset - offset) >= 0)
416338fd1498Szrj     {
416438fd1498Szrj       struct ipa_agg_jf_item item;
416538fd1498Szrj       gcc_checking_assert (av->value);
416638fd1498Szrj       item.offset = av->offset - offset;
416738fd1498Szrj       item.value = av->value;
416838fd1498Szrj       res.safe_push (item);
416938fd1498Szrj     }
417038fd1498Szrj 
417138fd1498Szrj   return res;
417238fd1498Szrj }
417338fd1498Szrj 
417438fd1498Szrj /* Intersect all values in INTER with those that we have already scheduled to
417538fd1498Szrj    be replaced in parameter number INDEX of NODE, which is an IPA-CP clone
417638fd1498Szrj    (while subtracting OFFSET).  */
417738fd1498Szrj 
417838fd1498Szrj static void
intersect_with_agg_replacements(struct cgraph_node * node,int index,vec<ipa_agg_jf_item> * inter,HOST_WIDE_INT offset)417938fd1498Szrj intersect_with_agg_replacements (struct cgraph_node *node, int index,
418038fd1498Szrj 				 vec<ipa_agg_jf_item> *inter,
418138fd1498Szrj 				 HOST_WIDE_INT offset)
418238fd1498Szrj {
418338fd1498Szrj   struct ipa_agg_replacement_value *srcvals;
418438fd1498Szrj   struct ipa_agg_jf_item *item;
418538fd1498Szrj   int i;
418638fd1498Szrj 
418738fd1498Szrj   srcvals = ipa_get_agg_replacements_for_node (node);
418838fd1498Szrj   if (!srcvals)
418938fd1498Szrj     {
419038fd1498Szrj       inter->release ();
419138fd1498Szrj       return;
419238fd1498Szrj     }
419338fd1498Szrj 
419438fd1498Szrj   FOR_EACH_VEC_ELT (*inter, i, item)
419538fd1498Szrj     {
419638fd1498Szrj       struct ipa_agg_replacement_value *av;
419738fd1498Szrj       bool found = false;
419838fd1498Szrj       if (!item->value)
419938fd1498Szrj 	continue;
420038fd1498Szrj       for (av = srcvals; av; av = av->next)
420138fd1498Szrj 	{
420238fd1498Szrj 	  gcc_checking_assert (av->value);
420338fd1498Szrj 	  if (av->index == index
420438fd1498Szrj 	      && av->offset - offset == item->offset)
420538fd1498Szrj 	    {
420638fd1498Szrj 	      if (values_equal_for_ipcp_p (item->value, av->value))
420738fd1498Szrj 		found = true;
420838fd1498Szrj 	      break;
420938fd1498Szrj 	    }
421038fd1498Szrj 	}
421138fd1498Szrj       if (!found)
421238fd1498Szrj 	item->value = NULL_TREE;
421338fd1498Szrj     }
421438fd1498Szrj }
421538fd1498Szrj 
421638fd1498Szrj /* Intersect values in INTER with aggregate values that come along edge CS to
421738fd1498Szrj    parameter number INDEX and return it.  If INTER does not actually exist yet,
421838fd1498Szrj    copy all incoming values to it.  If we determine we ended up with no values
421938fd1498Szrj    whatsoever, return a released vector.  */
422038fd1498Szrj 
422138fd1498Szrj static vec<ipa_agg_jf_item>
intersect_aggregates_with_edge(struct cgraph_edge * cs,int index,vec<ipa_agg_jf_item> inter)422238fd1498Szrj intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
422338fd1498Szrj 				vec<ipa_agg_jf_item> inter)
422438fd1498Szrj {
422538fd1498Szrj   struct ipa_jump_func *jfunc;
422638fd1498Szrj   jfunc = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), index);
422738fd1498Szrj   if (jfunc->type == IPA_JF_PASS_THROUGH
422838fd1498Szrj       && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
422938fd1498Szrj     {
423038fd1498Szrj       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
423138fd1498Szrj       int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
423238fd1498Szrj 
423338fd1498Szrj       if (caller_info->ipcp_orig_node)
423438fd1498Szrj 	{
423538fd1498Szrj 	  struct cgraph_node *orig_node = caller_info->ipcp_orig_node;
423638fd1498Szrj 	  struct ipcp_param_lattices *orig_plats;
423738fd1498Szrj 	  orig_plats = ipa_get_parm_lattices (IPA_NODE_REF (orig_node),
423838fd1498Szrj 					      src_idx);
423938fd1498Szrj 	  if (agg_pass_through_permissible_p (orig_plats, jfunc))
424038fd1498Szrj 	    {
424138fd1498Szrj 	      if (!inter.exists ())
424238fd1498Szrj 		inter = agg_replacements_to_vector (cs->caller, src_idx, 0);
424338fd1498Szrj 	      else
424438fd1498Szrj 		intersect_with_agg_replacements (cs->caller, src_idx,
424538fd1498Szrj 						 &inter, 0);
424638fd1498Szrj 	    }
424738fd1498Szrj 	  else
424838fd1498Szrj 	    {
424938fd1498Szrj 	      inter.release ();
425038fd1498Szrj 	      return vNULL;
425138fd1498Szrj 	    }
425238fd1498Szrj 	}
425338fd1498Szrj       else
425438fd1498Szrj 	{
425538fd1498Szrj 	  struct ipcp_param_lattices *src_plats;
425638fd1498Szrj 	  src_plats = ipa_get_parm_lattices (caller_info, src_idx);
425738fd1498Szrj 	  if (agg_pass_through_permissible_p (src_plats, jfunc))
425838fd1498Szrj 	    {
425938fd1498Szrj 	      /* Currently we do not produce clobber aggregate jump
426038fd1498Szrj 		 functions, adjust when we do.  */
426138fd1498Szrj 	      gcc_checking_assert (!jfunc->agg.items);
426238fd1498Szrj 	      if (!inter.exists ())
426338fd1498Szrj 		inter = copy_plats_to_inter (src_plats, 0);
426438fd1498Szrj 	      else
426538fd1498Szrj 		intersect_with_plats (src_plats, &inter, 0);
426638fd1498Szrj 	    }
426738fd1498Szrj 	  else
426838fd1498Szrj 	    {
426938fd1498Szrj 	      inter.release ();
427038fd1498Szrj 	      return vNULL;
427138fd1498Szrj 	    }
427238fd1498Szrj 	}
427338fd1498Szrj     }
427438fd1498Szrj   else if (jfunc->type == IPA_JF_ANCESTOR
427538fd1498Szrj 	   && ipa_get_jf_ancestor_agg_preserved (jfunc))
427638fd1498Szrj     {
427738fd1498Szrj       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
427838fd1498Szrj       int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
427938fd1498Szrj       struct ipcp_param_lattices *src_plats;
428038fd1498Szrj       HOST_WIDE_INT delta = ipa_get_jf_ancestor_offset (jfunc);
428138fd1498Szrj 
428238fd1498Szrj       if (caller_info->ipcp_orig_node)
428338fd1498Szrj 	{
428438fd1498Szrj 	  if (!inter.exists ())
428538fd1498Szrj 	    inter = agg_replacements_to_vector (cs->caller, src_idx, delta);
428638fd1498Szrj 	  else
428738fd1498Szrj 	    intersect_with_agg_replacements (cs->caller, src_idx, &inter,
428838fd1498Szrj 					     delta);
428938fd1498Szrj 	}
429038fd1498Szrj       else
429138fd1498Szrj 	{
429238fd1498Szrj 	  src_plats = ipa_get_parm_lattices (caller_info, src_idx);
429338fd1498Szrj 	  /* Currently we do not produce clobber aggregate jump
429438fd1498Szrj 	     functions, adjust when we do.  */
429538fd1498Szrj 	  gcc_checking_assert (!src_plats->aggs || !jfunc->agg.items);
429638fd1498Szrj 	  if (!inter.exists ())
429738fd1498Szrj 	    inter = copy_plats_to_inter (src_plats, delta);
429838fd1498Szrj 	  else
429938fd1498Szrj 	    intersect_with_plats (src_plats, &inter, delta);
430038fd1498Szrj 	}
430138fd1498Szrj     }
430238fd1498Szrj   else if (jfunc->agg.items)
430338fd1498Szrj     {
430438fd1498Szrj       struct ipa_agg_jf_item *item;
430538fd1498Szrj       int k;
430638fd1498Szrj 
430738fd1498Szrj       if (!inter.exists ())
430838fd1498Szrj 	for (unsigned i = 0; i < jfunc->agg.items->length (); i++)
430938fd1498Szrj 	  inter.safe_push ((*jfunc->agg.items)[i]);
431038fd1498Szrj       else
431138fd1498Szrj 	FOR_EACH_VEC_ELT (inter, k, item)
431238fd1498Szrj 	  {
431338fd1498Szrj 	    int l = 0;
431438fd1498Szrj 	    bool found = false;
431538fd1498Szrj 
431638fd1498Szrj 	    if (!item->value)
431738fd1498Szrj 	      continue;
431838fd1498Szrj 
431938fd1498Szrj 	    while ((unsigned) l < jfunc->agg.items->length ())
432038fd1498Szrj 	      {
432138fd1498Szrj 		struct ipa_agg_jf_item *ti;
432238fd1498Szrj 		ti = &(*jfunc->agg.items)[l];
432338fd1498Szrj 		if (ti->offset > item->offset)
432438fd1498Szrj 		  break;
432538fd1498Szrj 		if (ti->offset == item->offset)
432638fd1498Szrj 		  {
432738fd1498Szrj 		    gcc_checking_assert (ti->value);
432838fd1498Szrj 		    if (values_equal_for_ipcp_p (item->value,
432938fd1498Szrj 						 ti->value))
433038fd1498Szrj 		      found = true;
433138fd1498Szrj 		    break;
433238fd1498Szrj 		  }
433338fd1498Szrj 		l++;
433438fd1498Szrj 	      }
433538fd1498Szrj 	    if (!found)
433638fd1498Szrj 	      item->value = NULL;
433738fd1498Szrj 	  }
433838fd1498Szrj     }
433938fd1498Szrj   else
434038fd1498Szrj     {
434138fd1498Szrj       inter.release ();
434238fd1498Szrj       return vec<ipa_agg_jf_item>();
434338fd1498Szrj     }
434438fd1498Szrj   return inter;
434538fd1498Szrj }
434638fd1498Szrj 
434738fd1498Szrj /* Look at edges in CALLERS and collect all known aggregate values that arrive
434838fd1498Szrj    from all of them.  */
434938fd1498Szrj 
435038fd1498Szrj static struct ipa_agg_replacement_value *
find_aggregate_values_for_callers_subset(struct cgraph_node * node,vec<cgraph_edge * > callers)435138fd1498Szrj find_aggregate_values_for_callers_subset (struct cgraph_node *node,
435238fd1498Szrj 					  vec<cgraph_edge *> callers)
435338fd1498Szrj {
435438fd1498Szrj   struct ipa_node_params *dest_info = IPA_NODE_REF (node);
435538fd1498Szrj   struct ipa_agg_replacement_value *res;
435638fd1498Szrj   struct ipa_agg_replacement_value **tail = &res;
435738fd1498Szrj   struct cgraph_edge *cs;
435838fd1498Szrj   int i, j, count = ipa_get_param_count (dest_info);
435938fd1498Szrj 
436038fd1498Szrj   FOR_EACH_VEC_ELT (callers, j, cs)
436138fd1498Szrj     {
436238fd1498Szrj       int c = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
436338fd1498Szrj       if (c < count)
436438fd1498Szrj 	count = c;
436538fd1498Szrj     }
436638fd1498Szrj 
436738fd1498Szrj   for (i = 0; i < count; i++)
436838fd1498Szrj     {
436938fd1498Szrj       struct cgraph_edge *cs;
437038fd1498Szrj       vec<ipa_agg_jf_item> inter = vNULL;
437138fd1498Szrj       struct ipa_agg_jf_item *item;
437238fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (dest_info, i);
437338fd1498Szrj       int j;
437438fd1498Szrj 
437538fd1498Szrj       /* Among other things, the following check should deal with all by_ref
437638fd1498Szrj 	 mismatches.  */
437738fd1498Szrj       if (plats->aggs_bottom)
437838fd1498Szrj 	continue;
437938fd1498Szrj 
438038fd1498Szrj       FOR_EACH_VEC_ELT (callers, j, cs)
438138fd1498Szrj 	{
438238fd1498Szrj 	  struct ipa_jump_func *jfunc
438338fd1498Szrj 	    = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
438438fd1498Szrj 	  if (self_recursive_pass_through_p (cs, jfunc, i)
438538fd1498Szrj 	      && (!plats->aggs_by_ref
438638fd1498Szrj 		  || ipa_get_jf_pass_through_agg_preserved (jfunc)))
438738fd1498Szrj 	    continue;
438838fd1498Szrj 	  inter = intersect_aggregates_with_edge (cs, i, inter);
438938fd1498Szrj 
439038fd1498Szrj 	  if (!inter.exists ())
439138fd1498Szrj 	    goto next_param;
439238fd1498Szrj 	}
439338fd1498Szrj 
439438fd1498Szrj       FOR_EACH_VEC_ELT (inter, j, item)
439538fd1498Szrj 	{
439638fd1498Szrj 	  struct ipa_agg_replacement_value *v;
439738fd1498Szrj 
439838fd1498Szrj 	  if (!item->value)
439938fd1498Szrj 	    continue;
440038fd1498Szrj 
440138fd1498Szrj 	  v = ggc_alloc<ipa_agg_replacement_value> ();
440238fd1498Szrj 	  v->index = i;
440338fd1498Szrj 	  v->offset = item->offset;
440438fd1498Szrj 	  v->value = item->value;
440538fd1498Szrj 	  v->by_ref = plats->aggs_by_ref;
440638fd1498Szrj 	  *tail = v;
440738fd1498Szrj 	  tail = &v->next;
440838fd1498Szrj 	}
440938fd1498Szrj 
441038fd1498Szrj     next_param:
441138fd1498Szrj       if (inter.exists ())
441238fd1498Szrj 	inter.release ();
441338fd1498Szrj     }
441438fd1498Szrj   *tail = NULL;
441538fd1498Szrj   return res;
441638fd1498Szrj }
441738fd1498Szrj 
441838fd1498Szrj /* Determine whether CS also brings all scalar values that the NODE is
441938fd1498Szrj    specialized for.  */
442038fd1498Szrj 
442138fd1498Szrj static bool
cgraph_edge_brings_all_scalars_for_node(struct cgraph_edge * cs,struct cgraph_node * node)442238fd1498Szrj cgraph_edge_brings_all_scalars_for_node (struct cgraph_edge *cs,
442338fd1498Szrj 					 struct cgraph_node *node)
442438fd1498Szrj {
442538fd1498Szrj   struct ipa_node_params *dest_info = IPA_NODE_REF (node);
442638fd1498Szrj   int count = ipa_get_param_count (dest_info);
442738fd1498Szrj   struct ipa_node_params *caller_info;
442838fd1498Szrj   struct ipa_edge_args *args;
442938fd1498Szrj   int i;
443038fd1498Szrj 
443138fd1498Szrj   caller_info = IPA_NODE_REF (cs->caller);
443238fd1498Szrj   args = IPA_EDGE_REF (cs);
443338fd1498Szrj   for (i = 0; i < count; i++)
443438fd1498Szrj     {
443538fd1498Szrj       struct ipa_jump_func *jump_func;
443638fd1498Szrj       tree val, t;
443738fd1498Szrj 
443838fd1498Szrj       val = dest_info->known_csts[i];
443938fd1498Szrj       if (!val)
444038fd1498Szrj 	continue;
444138fd1498Szrj 
444238fd1498Szrj       if (i >= ipa_get_cs_argument_count (args))
444338fd1498Szrj 	return false;
444438fd1498Szrj       jump_func = ipa_get_ith_jump_func (args, i);
444538fd1498Szrj       t = ipa_value_from_jfunc (caller_info, jump_func,
444638fd1498Szrj 				ipa_get_type (dest_info, i));
444738fd1498Szrj       if (!t || !values_equal_for_ipcp_p (val, t))
444838fd1498Szrj 	return false;
444938fd1498Szrj     }
445038fd1498Szrj   return true;
445138fd1498Szrj }
445238fd1498Szrj 
445338fd1498Szrj /* Determine whether CS also brings all aggregate values that NODE is
445438fd1498Szrj    specialized for.  */
445538fd1498Szrj static bool
cgraph_edge_brings_all_agg_vals_for_node(struct cgraph_edge * cs,struct cgraph_node * node)445638fd1498Szrj cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs,
445738fd1498Szrj 					  struct cgraph_node *node)
445838fd1498Szrj {
445938fd1498Szrj   struct ipa_node_params *orig_caller_info = IPA_NODE_REF (cs->caller);
446038fd1498Szrj   struct ipa_node_params *orig_node_info;
446138fd1498Szrj   struct ipa_agg_replacement_value *aggval;
446238fd1498Szrj   int i, ec, count;
446338fd1498Szrj 
446438fd1498Szrj   aggval = ipa_get_agg_replacements_for_node (node);
446538fd1498Szrj   if (!aggval)
446638fd1498Szrj     return true;
446738fd1498Szrj 
446838fd1498Szrj   count = ipa_get_param_count (IPA_NODE_REF (node));
446938fd1498Szrj   ec = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
447038fd1498Szrj   if (ec < count)
447138fd1498Szrj     for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
447238fd1498Szrj       if (aggval->index >= ec)
447338fd1498Szrj 	return false;
447438fd1498Szrj 
447538fd1498Szrj   orig_node_info = IPA_NODE_REF (IPA_NODE_REF (node)->ipcp_orig_node);
447638fd1498Szrj   if (orig_caller_info->ipcp_orig_node)
447738fd1498Szrj     orig_caller_info = IPA_NODE_REF (orig_caller_info->ipcp_orig_node);
447838fd1498Szrj 
447938fd1498Szrj   for (i = 0; i < count; i++)
448038fd1498Szrj     {
448138fd1498Szrj       static vec<ipa_agg_jf_item> values = vec<ipa_agg_jf_item>();
448238fd1498Szrj       struct ipcp_param_lattices *plats;
448338fd1498Szrj       bool interesting = false;
448438fd1498Szrj       for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
448538fd1498Szrj 	if (aggval->index == i)
448638fd1498Szrj 	  {
448738fd1498Szrj 	    interesting = true;
448838fd1498Szrj 	    break;
448938fd1498Szrj 	  }
449038fd1498Szrj       if (!interesting)
449138fd1498Szrj 	continue;
449238fd1498Szrj 
449338fd1498Szrj       plats = ipa_get_parm_lattices (orig_node_info, aggval->index);
449438fd1498Szrj       if (plats->aggs_bottom)
449538fd1498Szrj 	return false;
449638fd1498Szrj 
449738fd1498Szrj       values = intersect_aggregates_with_edge (cs, i, values);
449838fd1498Szrj       if (!values.exists ())
449938fd1498Szrj 	return false;
450038fd1498Szrj 
450138fd1498Szrj       for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
450238fd1498Szrj 	if (aggval->index == i)
450338fd1498Szrj 	  {
450438fd1498Szrj 	    struct ipa_agg_jf_item *item;
450538fd1498Szrj 	    int j;
450638fd1498Szrj 	    bool found = false;
450738fd1498Szrj 	    FOR_EACH_VEC_ELT (values, j, item)
450838fd1498Szrj 	      if (item->value
450938fd1498Szrj 		  && item->offset == av->offset
451038fd1498Szrj 		  && values_equal_for_ipcp_p (item->value, av->value))
451138fd1498Szrj 		{
451238fd1498Szrj 		  found = true;
451338fd1498Szrj 		  break;
451438fd1498Szrj 		}
451538fd1498Szrj 	    if (!found)
451638fd1498Szrj 	      {
451738fd1498Szrj 		values.release ();
451838fd1498Szrj 		return false;
451938fd1498Szrj 	      }
452038fd1498Szrj 	  }
452138fd1498Szrj     }
452238fd1498Szrj   return true;
452338fd1498Szrj }
452438fd1498Szrj 
452538fd1498Szrj /* Given an original NODE and a VAL for which we have already created a
452638fd1498Szrj    specialized clone, look whether there are incoming edges that still lead
452738fd1498Szrj    into the old node but now also bring the requested value and also conform to
452838fd1498Szrj    all other criteria such that they can be redirected the special node.
452938fd1498Szrj    This function can therefore redirect the final edge in a SCC.  */
453038fd1498Szrj 
453138fd1498Szrj template <typename valtype>
453238fd1498Szrj static void
perhaps_add_new_callers(cgraph_node * node,ipcp_value<valtype> * val)453338fd1498Szrj perhaps_add_new_callers (cgraph_node *node, ipcp_value<valtype> *val)
453438fd1498Szrj {
453538fd1498Szrj   ipcp_value_source<valtype> *src;
453638fd1498Szrj   profile_count redirected_sum = profile_count::zero ();
453738fd1498Szrj 
453838fd1498Szrj   for (src = val->sources; src; src = src->next)
453938fd1498Szrj     {
454038fd1498Szrj       struct cgraph_edge *cs = src->cs;
454138fd1498Szrj       while (cs)
454238fd1498Szrj 	{
454338fd1498Szrj 	  if (cgraph_edge_brings_value_p (cs, src, node, val)
454438fd1498Szrj 	      && cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node)
454538fd1498Szrj 	      && cgraph_edge_brings_all_agg_vals_for_node (cs, val->spec_node))
454638fd1498Szrj 	    {
454738fd1498Szrj 	      if (dump_file)
454838fd1498Szrj 		fprintf (dump_file, " - adding an extra caller %s of %s\n",
454938fd1498Szrj 			 cs->caller->dump_name (),
455038fd1498Szrj 			 val->spec_node->dump_name ());
455138fd1498Szrj 
455238fd1498Szrj 	      cs->redirect_callee_duplicating_thunks (val->spec_node);
455338fd1498Szrj 	      val->spec_node->expand_all_artificial_thunks ();
455438fd1498Szrj 	      if (cs->count.ipa ().initialized_p ())
455538fd1498Szrj 	        redirected_sum = redirected_sum + cs->count.ipa ();
455638fd1498Szrj 	    }
455738fd1498Szrj 	  cs = get_next_cgraph_edge_clone (cs);
455838fd1498Szrj 	}
455938fd1498Szrj     }
456038fd1498Szrj 
456138fd1498Szrj   if (redirected_sum.nonzero_p ())
456238fd1498Szrj     update_specialized_profile (val->spec_node, node, redirected_sum);
456338fd1498Szrj }
456438fd1498Szrj 
456538fd1498Szrj /* Return true if KNOWN_CONTEXTS contain at least one useful context.  */
456638fd1498Szrj 
456738fd1498Szrj static bool
known_contexts_useful_p(vec<ipa_polymorphic_call_context> known_contexts)456838fd1498Szrj known_contexts_useful_p (vec<ipa_polymorphic_call_context> known_contexts)
456938fd1498Szrj {
457038fd1498Szrj   ipa_polymorphic_call_context *ctx;
457138fd1498Szrj   int i;
457238fd1498Szrj 
457338fd1498Szrj   FOR_EACH_VEC_ELT (known_contexts, i, ctx)
457438fd1498Szrj     if (!ctx->useless_p ())
457538fd1498Szrj       return true;
457638fd1498Szrj   return false;
457738fd1498Szrj }
457838fd1498Szrj 
457938fd1498Szrj /* Return a copy of KNOWN_CSTS if it is not empty, otherwise return vNULL.  */
458038fd1498Szrj 
458138fd1498Szrj static vec<ipa_polymorphic_call_context>
copy_useful_known_contexts(vec<ipa_polymorphic_call_context> known_contexts)458238fd1498Szrj copy_useful_known_contexts (vec<ipa_polymorphic_call_context> known_contexts)
458338fd1498Szrj {
458438fd1498Szrj   if (known_contexts_useful_p (known_contexts))
458538fd1498Szrj     return known_contexts.copy ();
458638fd1498Szrj   else
458738fd1498Szrj     return vNULL;
458838fd1498Szrj }
458938fd1498Szrj 
459038fd1498Szrj /* Copy KNOWN_CSTS and modify the copy according to VAL and INDEX.  If
459138fd1498Szrj    non-empty, replace KNOWN_CONTEXTS with its copy too.  */
459238fd1498Szrj 
459338fd1498Szrj static void
modify_known_vectors_with_val(vec<tree> * known_csts,vec<ipa_polymorphic_call_context> * known_contexts,ipcp_value<tree> * val,int index)459438fd1498Szrj modify_known_vectors_with_val (vec<tree> *known_csts,
459538fd1498Szrj 			       vec<ipa_polymorphic_call_context> *known_contexts,
459638fd1498Szrj 			       ipcp_value<tree> *val,
459738fd1498Szrj 			       int index)
459838fd1498Szrj {
459938fd1498Szrj   *known_csts = known_csts->copy ();
460038fd1498Szrj   *known_contexts = copy_useful_known_contexts (*known_contexts);
460138fd1498Szrj   (*known_csts)[index] = val->value;
460238fd1498Szrj }
460338fd1498Szrj 
460438fd1498Szrj /* Replace KNOWN_CSTS with its copy.  Also copy KNOWN_CONTEXTS and modify the
460538fd1498Szrj    copy according to VAL and INDEX.  */
460638fd1498Szrj 
460738fd1498Szrj static void
modify_known_vectors_with_val(vec<tree> * known_csts,vec<ipa_polymorphic_call_context> * known_contexts,ipcp_value<ipa_polymorphic_call_context> * val,int index)460838fd1498Szrj modify_known_vectors_with_val (vec<tree> *known_csts,
460938fd1498Szrj 			       vec<ipa_polymorphic_call_context> *known_contexts,
461038fd1498Szrj 			       ipcp_value<ipa_polymorphic_call_context> *val,
461138fd1498Szrj 			       int index)
461238fd1498Szrj {
461338fd1498Szrj   *known_csts = known_csts->copy ();
461438fd1498Szrj   *known_contexts = known_contexts->copy ();
461538fd1498Szrj   (*known_contexts)[index] = val->value;
461638fd1498Szrj }
461738fd1498Szrj 
461838fd1498Szrj /* Return true if OFFSET indicates this was not an aggregate value or there is
461938fd1498Szrj    a replacement equivalent to VALUE, INDEX and OFFSET among those in the
462038fd1498Szrj    AGGVALS list.  */
462138fd1498Szrj 
462238fd1498Szrj DEBUG_FUNCTION bool
ipcp_val_agg_replacement_ok_p(ipa_agg_replacement_value * aggvals,int index,HOST_WIDE_INT offset,tree value)462338fd1498Szrj ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *aggvals,
462438fd1498Szrj 			       int index, HOST_WIDE_INT offset, tree value)
462538fd1498Szrj {
462638fd1498Szrj   if (offset == -1)
462738fd1498Szrj     return true;
462838fd1498Szrj 
462938fd1498Szrj   while (aggvals)
463038fd1498Szrj     {
463138fd1498Szrj       if (aggvals->index == index
463238fd1498Szrj 	  && aggvals->offset == offset
463338fd1498Szrj 	  && values_equal_for_ipcp_p (aggvals->value, value))
463438fd1498Szrj 	return true;
463538fd1498Szrj       aggvals = aggvals->next;
463638fd1498Szrj     }
463738fd1498Szrj   return false;
463838fd1498Szrj }
463938fd1498Szrj 
464038fd1498Szrj /* Return true if offset is minus one because source of a polymorphic contect
464138fd1498Szrj    cannot be an aggregate value.  */
464238fd1498Szrj 
464338fd1498Szrj DEBUG_FUNCTION bool
ipcp_val_agg_replacement_ok_p(ipa_agg_replacement_value *,int,HOST_WIDE_INT offset,ipa_polymorphic_call_context)464438fd1498Szrj ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *,
464538fd1498Szrj 			       int , HOST_WIDE_INT offset,
464638fd1498Szrj 			       ipa_polymorphic_call_context)
464738fd1498Szrj {
464838fd1498Szrj   return offset == -1;
464938fd1498Szrj }
465038fd1498Szrj 
465138fd1498Szrj /* Decide wheter to create a special version of NODE for value VAL of parameter
465238fd1498Szrj    at the given INDEX.  If OFFSET is -1, the value is for the parameter itself,
465338fd1498Szrj    otherwise it is stored at the given OFFSET of the parameter.  KNOWN_CSTS,
465438fd1498Szrj    KNOWN_CONTEXTS and KNOWN_AGGS describe the other already known values.  */
465538fd1498Szrj 
465638fd1498Szrj template <typename valtype>
465738fd1498Szrj static bool
decide_about_value(struct cgraph_node * node,int index,HOST_WIDE_INT offset,ipcp_value<valtype> * val,vec<tree> known_csts,vec<ipa_polymorphic_call_context> known_contexts)465838fd1498Szrj decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset,
465938fd1498Szrj 		    ipcp_value<valtype> *val, vec<tree> known_csts,
466038fd1498Szrj 		    vec<ipa_polymorphic_call_context> known_contexts)
466138fd1498Szrj {
466238fd1498Szrj   struct ipa_agg_replacement_value *aggvals;
466338fd1498Szrj   int freq_sum, caller_count;
466438fd1498Szrj   profile_count count_sum;
466538fd1498Szrj   vec<cgraph_edge *> callers;
466638fd1498Szrj 
466738fd1498Szrj   if (val->spec_node)
466838fd1498Szrj     {
466938fd1498Szrj       perhaps_add_new_callers (node, val);
467038fd1498Szrj       return false;
467138fd1498Szrj     }
467238fd1498Szrj   else if (val->local_size_cost + overall_size > max_new_size)
467338fd1498Szrj     {
467438fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
467538fd1498Szrj 	fprintf (dump_file, "   Ignoring candidate value because "
467638fd1498Szrj 		 "max_new_size would be reached with %li.\n",
467738fd1498Szrj 		 val->local_size_cost + overall_size);
467838fd1498Szrj       return false;
467938fd1498Szrj     }
468038fd1498Szrj   else if (!get_info_about_necessary_edges (val, node, &freq_sum, &count_sum,
468138fd1498Szrj 					    &caller_count))
468238fd1498Szrj     return false;
468338fd1498Szrj 
468438fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
468538fd1498Szrj     {
468638fd1498Szrj       fprintf (dump_file, " - considering value ");
468738fd1498Szrj       print_ipcp_constant_value (dump_file, val->value);
468838fd1498Szrj       fprintf (dump_file, " for ");
468938fd1498Szrj       ipa_dump_param (dump_file, IPA_NODE_REF (node), index);
469038fd1498Szrj       if (offset != -1)
469138fd1498Szrj 	fprintf (dump_file, ", offset: " HOST_WIDE_INT_PRINT_DEC, offset);
469238fd1498Szrj       fprintf (dump_file, " (caller_count: %i)\n", caller_count);
469338fd1498Szrj     }
469438fd1498Szrj 
469538fd1498Szrj   if (!good_cloning_opportunity_p (node, val->local_time_benefit,
469638fd1498Szrj 				   freq_sum, count_sum,
469738fd1498Szrj 				   val->local_size_cost)
469838fd1498Szrj       && !good_cloning_opportunity_p (node,
469938fd1498Szrj 				      val->local_time_benefit
470038fd1498Szrj 				      + val->prop_time_benefit,
470138fd1498Szrj 				      freq_sum, count_sum,
470238fd1498Szrj 				      val->local_size_cost
470338fd1498Szrj 				      + val->prop_size_cost))
470438fd1498Szrj     return false;
470538fd1498Szrj 
470638fd1498Szrj   if (dump_file)
470738fd1498Szrj     fprintf (dump_file, "  Creating a specialized node of %s.\n",
470838fd1498Szrj 	     node->dump_name ());
470938fd1498Szrj 
471038fd1498Szrj   callers = gather_edges_for_value (val, node, caller_count);
471138fd1498Szrj   if (offset == -1)
471238fd1498Szrj     modify_known_vectors_with_val (&known_csts, &known_contexts, val, index);
471338fd1498Szrj   else
471438fd1498Szrj     {
471538fd1498Szrj       known_csts = known_csts.copy ();
471638fd1498Szrj       known_contexts = copy_useful_known_contexts (known_contexts);
471738fd1498Szrj     }
471838fd1498Szrj   find_more_scalar_values_for_callers_subset (node, known_csts, callers);
471938fd1498Szrj   find_more_contexts_for_caller_subset (node, &known_contexts, callers);
472038fd1498Szrj   aggvals = find_aggregate_values_for_callers_subset (node, callers);
472138fd1498Szrj   gcc_checking_assert (ipcp_val_agg_replacement_ok_p (aggvals, index,
472238fd1498Szrj 						      offset, val->value));
472338fd1498Szrj   val->spec_node = create_specialized_node (node, known_csts, known_contexts,
472438fd1498Szrj 					    aggvals, callers);
472538fd1498Szrj   overall_size += val->local_size_cost;
472638fd1498Szrj 
472738fd1498Szrj   /* TODO: If for some lattice there is only one other known value
472838fd1498Szrj      left, make a special node for it too. */
472938fd1498Szrj 
473038fd1498Szrj   return true;
473138fd1498Szrj }
473238fd1498Szrj 
473338fd1498Szrj /* Decide whether and what specialized clones of NODE should be created.  */
473438fd1498Szrj 
473538fd1498Szrj static bool
decide_whether_version_node(struct cgraph_node * node)473638fd1498Szrj decide_whether_version_node (struct cgraph_node *node)
473738fd1498Szrj {
473838fd1498Szrj   struct ipa_node_params *info = IPA_NODE_REF (node);
473938fd1498Szrj   int i, count = ipa_get_param_count (info);
474038fd1498Szrj   vec<tree> known_csts;
474138fd1498Szrj   vec<ipa_polymorphic_call_context> known_contexts;
474238fd1498Szrj   vec<ipa_agg_jump_function> known_aggs = vNULL;
474338fd1498Szrj   bool ret = false;
474438fd1498Szrj 
474538fd1498Szrj   if (count == 0)
474638fd1498Szrj     return false;
474738fd1498Szrj 
474838fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
474938fd1498Szrj     fprintf (dump_file, "\nEvaluating opportunities for %s.\n",
475038fd1498Szrj 	     node->dump_name ());
475138fd1498Szrj 
475238fd1498Szrj   gather_context_independent_values (info, &known_csts, &known_contexts,
475338fd1498Szrj 				  info->do_clone_for_all_contexts ? &known_aggs
475438fd1498Szrj 				  : NULL, NULL);
475538fd1498Szrj 
475638fd1498Szrj   for (i = 0; i < count;i++)
475738fd1498Szrj     {
475838fd1498Szrj       struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
475938fd1498Szrj       ipcp_lattice<tree> *lat = &plats->itself;
476038fd1498Szrj       ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
476138fd1498Szrj 
476238fd1498Szrj       if (!lat->bottom
476338fd1498Szrj 	  && !known_csts[i])
476438fd1498Szrj 	{
476538fd1498Szrj 	  ipcp_value<tree> *val;
476638fd1498Szrj 	  for (val = lat->values; val; val = val->next)
476738fd1498Szrj 	    ret |= decide_about_value (node, i, -1, val, known_csts,
476838fd1498Szrj 				       known_contexts);
476938fd1498Szrj 	}
477038fd1498Szrj 
477138fd1498Szrj       if (!plats->aggs_bottom)
477238fd1498Szrj 	{
477338fd1498Szrj 	  struct ipcp_agg_lattice *aglat;
477438fd1498Szrj 	  ipcp_value<tree> *val;
477538fd1498Szrj 	  for (aglat = plats->aggs; aglat; aglat = aglat->next)
477638fd1498Szrj 	    if (!aglat->bottom && aglat->values
477738fd1498Szrj 		/* If the following is false, the one value is in
477838fd1498Szrj 		   known_aggs.  */
477938fd1498Szrj 		&& (plats->aggs_contain_variable
478038fd1498Szrj 		    || !aglat->is_single_const ()))
478138fd1498Szrj 	      for (val = aglat->values; val; val = val->next)
478238fd1498Szrj 		ret |= decide_about_value (node, i, aglat->offset, val,
478338fd1498Szrj 					   known_csts, known_contexts);
478438fd1498Szrj 	}
478538fd1498Szrj 
478638fd1498Szrj       if (!ctxlat->bottom
478738fd1498Szrj 	  && known_contexts[i].useless_p ())
478838fd1498Szrj 	{
478938fd1498Szrj 	  ipcp_value<ipa_polymorphic_call_context> *val;
479038fd1498Szrj 	  for (val = ctxlat->values; val; val = val->next)
479138fd1498Szrj 	    ret |= decide_about_value (node, i, -1, val, known_csts,
479238fd1498Szrj 				       known_contexts);
479338fd1498Szrj 	}
479438fd1498Szrj 
479538fd1498Szrj 	info = IPA_NODE_REF (node);
479638fd1498Szrj     }
479738fd1498Szrj 
479838fd1498Szrj   if (info->do_clone_for_all_contexts)
479938fd1498Szrj     {
480038fd1498Szrj       struct cgraph_node *clone;
480138fd1498Szrj       vec<cgraph_edge *> callers;
480238fd1498Szrj 
480338fd1498Szrj       if (dump_file)
480438fd1498Szrj 	fprintf (dump_file, " - Creating a specialized node of %s "
480538fd1498Szrj 		 "for all known contexts.\n", node->dump_name ());
480638fd1498Szrj 
480738fd1498Szrj       callers = node->collect_callers ();
480838fd1498Szrj       find_more_scalar_values_for_callers_subset (node, known_csts, callers);
480938fd1498Szrj       find_more_contexts_for_caller_subset (node, &known_contexts, callers);
481038fd1498Szrj       ipa_agg_replacement_value *aggvals
481138fd1498Szrj 	= find_aggregate_values_for_callers_subset (node, callers);
481238fd1498Szrj 
481338fd1498Szrj       if (!known_contexts_useful_p (known_contexts))
481438fd1498Szrj 	{
481538fd1498Szrj 	  known_contexts.release ();
481638fd1498Szrj 	  known_contexts = vNULL;
481738fd1498Szrj 	}
481838fd1498Szrj       clone = create_specialized_node (node, known_csts, known_contexts,
481938fd1498Szrj 				       aggvals, callers);
482038fd1498Szrj       info = IPA_NODE_REF (node);
482138fd1498Szrj       info->do_clone_for_all_contexts = false;
482238fd1498Szrj       IPA_NODE_REF (clone)->is_all_contexts_clone = true;
482338fd1498Szrj       for (i = 0; i < count; i++)
482438fd1498Szrj 	vec_free (known_aggs[i].items);
482538fd1498Szrj       known_aggs.release ();
482638fd1498Szrj       ret = true;
482738fd1498Szrj     }
482838fd1498Szrj   else
482938fd1498Szrj     {
483038fd1498Szrj       known_csts.release ();
483138fd1498Szrj       known_contexts.release ();
483238fd1498Szrj     }
483338fd1498Szrj 
483438fd1498Szrj   return ret;
483538fd1498Szrj }
483638fd1498Szrj 
483738fd1498Szrj /* Transitively mark all callees of NODE within the same SCC as not dead.  */
483838fd1498Szrj 
483938fd1498Szrj static void
spread_undeadness(struct cgraph_node * node)484038fd1498Szrj spread_undeadness (struct cgraph_node *node)
484138fd1498Szrj {
484238fd1498Szrj   struct cgraph_edge *cs;
484338fd1498Szrj 
484438fd1498Szrj   for (cs = node->callees; cs; cs = cs->next_callee)
484538fd1498Szrj     if (ipa_edge_within_scc (cs))
484638fd1498Szrj       {
484738fd1498Szrj 	struct cgraph_node *callee;
484838fd1498Szrj 	struct ipa_node_params *info;
484938fd1498Szrj 
485038fd1498Szrj 	callee = cs->callee->function_symbol (NULL);
485138fd1498Szrj 	info = IPA_NODE_REF (callee);
485238fd1498Szrj 
485338fd1498Szrj 	if (info->node_dead)
485438fd1498Szrj 	  {
485538fd1498Szrj 	    info->node_dead = 0;
485638fd1498Szrj 	    spread_undeadness (callee);
485738fd1498Szrj 	  }
485838fd1498Szrj       }
485938fd1498Szrj }
486038fd1498Szrj 
486138fd1498Szrj /* Return true if NODE has a caller from outside of its SCC that is not
486238fd1498Szrj    dead.  Worker callback for cgraph_for_node_and_aliases.  */
486338fd1498Szrj 
486438fd1498Szrj static bool
has_undead_caller_from_outside_scc_p(struct cgraph_node * node,void * data ATTRIBUTE_UNUSED)486538fd1498Szrj has_undead_caller_from_outside_scc_p (struct cgraph_node *node,
486638fd1498Szrj 				      void *data ATTRIBUTE_UNUSED)
486738fd1498Szrj {
486838fd1498Szrj   struct cgraph_edge *cs;
486938fd1498Szrj 
487038fd1498Szrj   for (cs = node->callers; cs; cs = cs->next_caller)
487138fd1498Szrj     if (cs->caller->thunk.thunk_p
487238fd1498Szrj 	&& cs->caller->call_for_symbol_thunks_and_aliases
487338fd1498Szrj 	  (has_undead_caller_from_outside_scc_p, NULL, true))
487438fd1498Szrj       return true;
487538fd1498Szrj     else if (!ipa_edge_within_scc (cs)
487638fd1498Szrj 	     && !IPA_NODE_REF (cs->caller)->node_dead)
487738fd1498Szrj       return true;
487838fd1498Szrj   return false;
487938fd1498Szrj }
488038fd1498Szrj 
488138fd1498Szrj 
488238fd1498Szrj /* Identify nodes within the same SCC as NODE which are no longer needed
488338fd1498Szrj    because of new clones and will be removed as unreachable.  */
488438fd1498Szrj 
488538fd1498Szrj static void
identify_dead_nodes(struct cgraph_node * node)488638fd1498Szrj identify_dead_nodes (struct cgraph_node *node)
488738fd1498Szrj {
488838fd1498Szrj   struct cgraph_node *v;
488938fd1498Szrj   for (v = node; v; v = ((struct ipa_dfs_info *) v->aux)->next_cycle)
489038fd1498Szrj     if (v->local.local
489138fd1498Szrj 	&& !v->call_for_symbol_thunks_and_aliases
489238fd1498Szrj 	     (has_undead_caller_from_outside_scc_p, NULL, true))
489338fd1498Szrj       IPA_NODE_REF (v)->node_dead = 1;
489438fd1498Szrj 
489538fd1498Szrj   for (v = node; v; v = ((struct ipa_dfs_info *) v->aux)->next_cycle)
489638fd1498Szrj     if (!IPA_NODE_REF (v)->node_dead)
489738fd1498Szrj       spread_undeadness (v);
489838fd1498Szrj 
489938fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
490038fd1498Szrj     {
490138fd1498Szrj       for (v = node; v; v = ((struct ipa_dfs_info *) v->aux)->next_cycle)
490238fd1498Szrj 	if (IPA_NODE_REF (v)->node_dead)
490338fd1498Szrj 	  fprintf (dump_file, "  Marking node as dead: %s.\n", v->dump_name ());
490438fd1498Szrj     }
490538fd1498Szrj }
490638fd1498Szrj 
490738fd1498Szrj /* The decision stage.  Iterate over the topological order of call graph nodes
490838fd1498Szrj    TOPO and make specialized clones if deemed beneficial.  */
490938fd1498Szrj 
491038fd1498Szrj static void
ipcp_decision_stage(struct ipa_topo_info * topo)491138fd1498Szrj ipcp_decision_stage (struct ipa_topo_info *topo)
491238fd1498Szrj {
491338fd1498Szrj   int i;
491438fd1498Szrj 
491538fd1498Szrj   if (dump_file)
491638fd1498Szrj     fprintf (dump_file, "\nIPA decision stage:\n\n");
491738fd1498Szrj 
491838fd1498Szrj   for (i = topo->nnodes - 1; i >= 0; i--)
491938fd1498Szrj     {
492038fd1498Szrj       struct cgraph_node *node = topo->order[i];
492138fd1498Szrj       bool change = false, iterate = true;
492238fd1498Szrj 
492338fd1498Szrj       while (iterate)
492438fd1498Szrj 	{
492538fd1498Szrj 	  struct cgraph_node *v;
492638fd1498Szrj 	  iterate = false;
492738fd1498Szrj 	  for (v = node; v; v = ((struct ipa_dfs_info *) v->aux)->next_cycle)
492838fd1498Szrj 	    if (v->has_gimple_body_p ()
492938fd1498Szrj 		&& ipcp_versionable_function_p (v))
493038fd1498Szrj 	      iterate |= decide_whether_version_node (v);
493138fd1498Szrj 
493238fd1498Szrj 	  change |= iterate;
493338fd1498Szrj 	}
493438fd1498Szrj       if (change)
493538fd1498Szrj 	identify_dead_nodes (node);
493638fd1498Szrj     }
493738fd1498Szrj }
493838fd1498Szrj 
493938fd1498Szrj /* Look up all the bits information that we have discovered and copy it over
494038fd1498Szrj    to the transformation summary.  */
494138fd1498Szrj 
494238fd1498Szrj static void
ipcp_store_bits_results(void)494338fd1498Szrj ipcp_store_bits_results (void)
494438fd1498Szrj {
494538fd1498Szrj   cgraph_node *node;
494638fd1498Szrj 
494738fd1498Szrj   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
494838fd1498Szrj     {
494938fd1498Szrj       ipa_node_params *info = IPA_NODE_REF (node);
495038fd1498Szrj       bool dumped_sth = false;
495138fd1498Szrj       bool found_useful_result = false;
495238fd1498Szrj 
495338fd1498Szrj       if (!opt_for_fn (node->decl, flag_ipa_bit_cp))
495438fd1498Szrj 	{
495538fd1498Szrj 	  if (dump_file)
495638fd1498Szrj 	    fprintf (dump_file, "Not considering %s for ipa bitwise propagation "
495738fd1498Szrj 				"; -fipa-bit-cp: disabled.\n",
495838fd1498Szrj 				node->name ());
495938fd1498Szrj 	  continue;
496038fd1498Szrj 	}
496138fd1498Szrj 
496238fd1498Szrj       if (info->ipcp_orig_node)
496338fd1498Szrj 	info = IPA_NODE_REF (info->ipcp_orig_node);
496438fd1498Szrj 
496538fd1498Szrj       unsigned count = ipa_get_param_count (info);
496638fd1498Szrj       for (unsigned i = 0; i < count; i++)
496738fd1498Szrj 	{
496838fd1498Szrj 	  ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
496938fd1498Szrj 	  if (plats->bits_lattice.constant_p ())
497038fd1498Szrj 	    {
497138fd1498Szrj 	      found_useful_result = true;
497238fd1498Szrj 	      break;
497338fd1498Szrj 	    }
497438fd1498Szrj 	}
497538fd1498Szrj 
497638fd1498Szrj       if (!found_useful_result)
497738fd1498Szrj 	continue;
497838fd1498Szrj 
497938fd1498Szrj       ipcp_grow_transformations_if_necessary ();
498038fd1498Szrj       ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
498138fd1498Szrj       vec_safe_reserve_exact (ts->bits, count);
498238fd1498Szrj 
498338fd1498Szrj       for (unsigned i = 0; i < count; i++)
498438fd1498Szrj 	{
498538fd1498Szrj 	  ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
498638fd1498Szrj 	  ipa_bits *jfbits;
498738fd1498Szrj 
498838fd1498Szrj 	  if (plats->bits_lattice.constant_p ())
498938fd1498Szrj 	    jfbits
499038fd1498Szrj 	      = ipa_get_ipa_bits_for_value (plats->bits_lattice.get_value (),
499138fd1498Szrj 					    plats->bits_lattice.get_mask ());
499238fd1498Szrj 	  else
499338fd1498Szrj 	    jfbits = NULL;
499438fd1498Szrj 
499538fd1498Szrj 	  ts->bits->quick_push (jfbits);
499638fd1498Szrj 	  if (!dump_file || !jfbits)
499738fd1498Szrj 	    continue;
499838fd1498Szrj 	  if (!dumped_sth)
499938fd1498Szrj 	    {
500038fd1498Szrj 	      fprintf (dump_file, "Propagated bits info for function %s:\n",
500138fd1498Szrj 		       node->dump_name ());
500238fd1498Szrj 	      dumped_sth = true;
500338fd1498Szrj 	    }
500438fd1498Szrj 	  fprintf (dump_file, " param %i: value = ", i);
500538fd1498Szrj 	  print_hex (jfbits->value, dump_file);
500638fd1498Szrj 	  fprintf (dump_file, ", mask = ");
500738fd1498Szrj 	  print_hex (jfbits->mask, dump_file);
500838fd1498Szrj 	  fprintf (dump_file, "\n");
500938fd1498Szrj 	}
501038fd1498Szrj     }
501138fd1498Szrj }
501238fd1498Szrj 
501338fd1498Szrj /* Look up all VR information that we have discovered and copy it over
501438fd1498Szrj    to the transformation summary.  */
501538fd1498Szrj 
501638fd1498Szrj static void
ipcp_store_vr_results(void)501738fd1498Szrj ipcp_store_vr_results (void)
501838fd1498Szrj {
501938fd1498Szrj   cgraph_node *node;
502038fd1498Szrj 
502138fd1498Szrj   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
502238fd1498Szrj     {
502338fd1498Szrj       ipa_node_params *info = IPA_NODE_REF (node);
502438fd1498Szrj       bool found_useful_result = false;
502538fd1498Szrj 
502638fd1498Szrj       if (!opt_for_fn (node->decl, flag_ipa_vrp))
502738fd1498Szrj 	{
502838fd1498Szrj 	  if (dump_file)
502938fd1498Szrj 	    fprintf (dump_file, "Not considering %s for VR discovery "
503038fd1498Szrj 		     "and propagate; -fipa-ipa-vrp: disabled.\n",
503138fd1498Szrj 		     node->name ());
503238fd1498Szrj 	  continue;
503338fd1498Szrj 	}
503438fd1498Szrj 
503538fd1498Szrj       if (info->ipcp_orig_node)
503638fd1498Szrj 	info = IPA_NODE_REF (info->ipcp_orig_node);
503738fd1498Szrj 
503838fd1498Szrj       unsigned count = ipa_get_param_count (info);
503938fd1498Szrj       for (unsigned i = 0; i < count; i++)
504038fd1498Szrj 	{
504138fd1498Szrj 	  ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
504238fd1498Szrj 	  if (!plats->m_value_range.bottom_p ()
504338fd1498Szrj 	      && !plats->m_value_range.top_p ())
504438fd1498Szrj 	    {
504538fd1498Szrj 	      found_useful_result = true;
504638fd1498Szrj 	      break;
504738fd1498Szrj 	    }
504838fd1498Szrj 	}
504938fd1498Szrj       if (!found_useful_result)
505038fd1498Szrj 	continue;
505138fd1498Szrj 
505238fd1498Szrj       ipcp_grow_transformations_if_necessary ();
505338fd1498Szrj       ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
505438fd1498Szrj       vec_safe_reserve_exact (ts->m_vr, count);
505538fd1498Szrj 
505638fd1498Szrj       for (unsigned i = 0; i < count; i++)
505738fd1498Szrj 	{
505838fd1498Szrj 	  ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
505938fd1498Szrj 	  ipa_vr vr;
506038fd1498Szrj 
506138fd1498Szrj 	  if (!plats->m_value_range.bottom_p ()
506238fd1498Szrj 	      && !plats->m_value_range.top_p ())
506338fd1498Szrj 	    {
506438fd1498Szrj 	      vr.known = true;
506538fd1498Szrj 	      vr.type = plats->m_value_range.m_vr.type;
506638fd1498Szrj 	      vr.min = wi::to_wide (plats->m_value_range.m_vr.min);
506738fd1498Szrj 	      vr.max = wi::to_wide (plats->m_value_range.m_vr.max);
506838fd1498Szrj 	    }
506938fd1498Szrj 	  else
507038fd1498Szrj 	    {
507138fd1498Szrj 	      vr.known = false;
507238fd1498Szrj 	      vr.type = VR_VARYING;
507338fd1498Szrj 	      vr.min = vr.max = wi::zero (INT_TYPE_SIZE);
507438fd1498Szrj 	    }
507538fd1498Szrj 	  ts->m_vr->quick_push (vr);
507638fd1498Szrj 	}
507738fd1498Szrj     }
507838fd1498Szrj }
507938fd1498Szrj 
508038fd1498Szrj /* The IPCP driver.  */
508138fd1498Szrj 
508238fd1498Szrj static unsigned int
ipcp_driver(void)508338fd1498Szrj ipcp_driver (void)
508438fd1498Szrj {
508538fd1498Szrj   struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
508638fd1498Szrj   struct cgraph_edge_hook_list *edge_removal_hook_holder;
508738fd1498Szrj   struct ipa_topo_info topo;
508838fd1498Szrj 
508938fd1498Szrj   ipa_check_create_node_params ();
509038fd1498Szrj   ipa_check_create_edge_args ();
509138fd1498Szrj   grow_edge_clone_vectors ();
509238fd1498Szrj   edge_duplication_hook_holder
509338fd1498Szrj     = symtab->add_edge_duplication_hook (&ipcp_edge_duplication_hook, NULL);
509438fd1498Szrj   edge_removal_hook_holder
509538fd1498Szrj     = symtab->add_edge_removal_hook (&ipcp_edge_removal_hook, NULL);
509638fd1498Szrj 
509738fd1498Szrj   if (dump_file)
509838fd1498Szrj     {
509938fd1498Szrj       fprintf (dump_file, "\nIPA structures before propagation:\n");
510038fd1498Szrj       if (dump_flags & TDF_DETAILS)
510138fd1498Szrj 	ipa_print_all_params (dump_file);
510238fd1498Szrj       ipa_print_all_jump_functions (dump_file);
510338fd1498Szrj     }
510438fd1498Szrj 
510538fd1498Szrj   /* Topological sort.  */
510638fd1498Szrj   build_toporder_info (&topo);
510738fd1498Szrj   /* Do the interprocedural propagation.  */
510838fd1498Szrj   ipcp_propagate_stage (&topo);
510938fd1498Szrj   /* Decide what constant propagation and cloning should be performed.  */
511038fd1498Szrj   ipcp_decision_stage (&topo);
511138fd1498Szrj   /* Store results of bits propagation.  */
511238fd1498Szrj   ipcp_store_bits_results ();
511338fd1498Szrj   /* Store results of value range propagation.  */
511438fd1498Szrj   ipcp_store_vr_results ();
511538fd1498Szrj 
511638fd1498Szrj   /* Free all IPCP structures.  */
511738fd1498Szrj   free_toporder_info (&topo);
511838fd1498Szrj   next_edge_clone.release ();
511938fd1498Szrj   prev_edge_clone.release ();
512038fd1498Szrj   symtab->remove_edge_removal_hook (edge_removal_hook_holder);
512138fd1498Szrj   symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
512238fd1498Szrj   ipa_free_all_structures_after_ipa_cp ();
512338fd1498Szrj   if (dump_file)
512438fd1498Szrj     fprintf (dump_file, "\nIPA constant propagation end\n");
512538fd1498Szrj   return 0;
512638fd1498Szrj }
512738fd1498Szrj 
512838fd1498Szrj /* Initialization and computation of IPCP data structures.  This is the initial
512938fd1498Szrj    intraprocedural analysis of functions, which gathers information to be
513038fd1498Szrj    propagated later on.  */
513138fd1498Szrj 
513238fd1498Szrj static void
ipcp_generate_summary(void)513338fd1498Szrj ipcp_generate_summary (void)
513438fd1498Szrj {
513538fd1498Szrj   struct cgraph_node *node;
513638fd1498Szrj 
513738fd1498Szrj   if (dump_file)
513838fd1498Szrj     fprintf (dump_file, "\nIPA constant propagation start:\n");
513938fd1498Szrj   ipa_register_cgraph_hooks ();
514038fd1498Szrj 
514138fd1498Szrj   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
514238fd1498Szrj     ipa_analyze_node (node);
514338fd1498Szrj }
514438fd1498Szrj 
514538fd1498Szrj /* Write ipcp summary for nodes in SET.  */
514638fd1498Szrj 
514738fd1498Szrj static void
ipcp_write_summary(void)514838fd1498Szrj ipcp_write_summary (void)
514938fd1498Szrj {
515038fd1498Szrj   ipa_prop_write_jump_functions ();
515138fd1498Szrj }
515238fd1498Szrj 
515338fd1498Szrj /* Read ipcp summary.  */
515438fd1498Szrj 
515538fd1498Szrj static void
ipcp_read_summary(void)515638fd1498Szrj ipcp_read_summary (void)
515738fd1498Szrj {
515838fd1498Szrj   ipa_prop_read_jump_functions ();
515938fd1498Szrj }
516038fd1498Szrj 
516138fd1498Szrj namespace {
516238fd1498Szrj 
516338fd1498Szrj const pass_data pass_data_ipa_cp =
516438fd1498Szrj {
516538fd1498Szrj   IPA_PASS, /* type */
516638fd1498Szrj   "cp", /* name */
516738fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
516838fd1498Szrj   TV_IPA_CONSTANT_PROP, /* tv_id */
516938fd1498Szrj   0, /* properties_required */
517038fd1498Szrj   0, /* properties_provided */
517138fd1498Szrj   0, /* properties_destroyed */
517238fd1498Szrj   0, /* todo_flags_start */
517338fd1498Szrj   ( TODO_dump_symtab | TODO_remove_functions ), /* todo_flags_finish */
517438fd1498Szrj };
517538fd1498Szrj 
517638fd1498Szrj class pass_ipa_cp : public ipa_opt_pass_d
517738fd1498Szrj {
517838fd1498Szrj public:
pass_ipa_cp(gcc::context * ctxt)517938fd1498Szrj   pass_ipa_cp (gcc::context *ctxt)
518038fd1498Szrj     : ipa_opt_pass_d (pass_data_ipa_cp, ctxt,
518138fd1498Szrj 		      ipcp_generate_summary, /* generate_summary */
518238fd1498Szrj 		      ipcp_write_summary, /* write_summary */
518338fd1498Szrj 		      ipcp_read_summary, /* read_summary */
518438fd1498Szrj 		      ipcp_write_transformation_summaries, /*
518538fd1498Szrj 		      write_optimization_summary */
518638fd1498Szrj 		      ipcp_read_transformation_summaries, /*
518738fd1498Szrj 		      read_optimization_summary */
518838fd1498Szrj 		      NULL, /* stmt_fixup */
518938fd1498Szrj 		      0, /* function_transform_todo_flags_start */
519038fd1498Szrj 		      ipcp_transform_function, /* function_transform */
519138fd1498Szrj 		      NULL) /* variable_transform */
519238fd1498Szrj   {}
519338fd1498Szrj 
519438fd1498Szrj   /* opt_pass methods: */
gate(function *)519538fd1498Szrj   virtual bool gate (function *)
519638fd1498Szrj     {
519738fd1498Szrj       /* FIXME: We should remove the optimize check after we ensure we never run
519838fd1498Szrj 	 IPA passes when not optimizing.  */
519938fd1498Szrj       return (flag_ipa_cp && optimize) || in_lto_p;
520038fd1498Szrj     }
520138fd1498Szrj 
execute(function *)520238fd1498Szrj   virtual unsigned int execute (function *) { return ipcp_driver (); }
520338fd1498Szrj 
520438fd1498Szrj }; // class pass_ipa_cp
520538fd1498Szrj 
520638fd1498Szrj } // anon namespace
520738fd1498Szrj 
520838fd1498Szrj ipa_opt_pass_d *
make_pass_ipa_cp(gcc::context * ctxt)520938fd1498Szrj make_pass_ipa_cp (gcc::context *ctxt)
521038fd1498Szrj {
521138fd1498Szrj   return new pass_ipa_cp (ctxt);
521238fd1498Szrj }
521338fd1498Szrj 
521438fd1498Szrj /* Reset all state within ipa-cp.c so that we can rerun the compiler
521538fd1498Szrj    within the same process.  For use by toplev::finalize.  */
521638fd1498Szrj 
521738fd1498Szrj void
ipa_cp_c_finalize(void)521838fd1498Szrj ipa_cp_c_finalize (void)
521938fd1498Szrj {
522038fd1498Szrj   max_count = profile_count::uninitialized ();
522138fd1498Szrj   overall_size = 0;
522238fd1498Szrj   max_new_size = 0;
522338fd1498Szrj }
5224