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