/* Interprocedural analyses.
- Copyright (C) 2005-2019 Free Software Foundation, Inc.
+ Copyright (C) 2005-2021 Free Software Foundation, Inc.
This file is part of GCC.
argument.
Unknown - neither of the above.
+ IPA_JF_LOAD_AGG is a compound pass-through jump function, in which primary
+ operation on formal parameter is memory dereference that loads a value from
+ a part of an aggregate, which is represented or pointed to by the formal
+ parameter. Moreover, an additional unary/binary operation can be applied on
+ the loaded value, and final result is passed as actual argument of callee
+ (e.g. *(param_1(D) + 4) op 24 ). It is meant to describe usage of aggregate
+ parameter or by-reference parameter referenced in argument passing, commonly
+ found in C++ and Fortran.
+
IPA_JF_ANCESTOR is a special pass-through jump function, which means that
the result is an address of a part of the object pointed to by the formal
parameter to which the function refers. It is mainly intended to represent
IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */
IPA_JF_CONST, /* represented by field costant */
IPA_JF_PASS_THROUGH, /* represented by field pass_through */
+ IPA_JF_LOAD_AGG, /* represented by field load_agg */
IPA_JF_ANCESTOR /* represented by field ancestor */
};
/* Number of the caller's formal parameter being passed. */
int formal_id;
/* Operation that is performed on the argument before it is passed on.
- NOP_EXPR means no operation. Otherwise oper must be a simple binary
- arithmetic operation where the caller's parameter is the first operand and
- operand field from this structure is the second one. */
+ Special values which have other meaning than in normal contexts:
+ - NOP_EXPR means no operation, not even type conversion.
+ - ASSERT_EXPR means that only the value in operand is allowed to pass
+ through (without any change), for all other values the result is
+ unknown.
+ Otherwise operation must be a simple binary or unary arithmetic operation
+ where the caller's parameter is the first operand and (for binary
+ operations) the operand field from this structure is the second one. */
enum tree_code operation;
/* When the passed value is a pointer, it is set to true only when we are
certain that no write to the object it points to has occurred since the
unsigned agg_preserved : 1;
};
+/* Structure holding data required to describe a load-value-from-aggregate
+ jump function. */
+
+struct GTY(()) ipa_load_agg_data
+{
+ /* Inherit from pass through jump function, describing unary/binary
+ operation on the value loaded from aggregate that is represented or
+ pointed to by the formal parameter, specified by formal_id in this
+ pass_through jump function data structure. */
+ struct ipa_pass_through_data pass_through;
+ /* Type of the value loaded from the aggregate. */
+ tree type;
+ /* Offset at which the value is located within the aggregate. */
+ HOST_WIDE_INT offset;
+ /* True if loaded by reference (the aggregate is pointed to by the formal
+ parameter) or false if loaded by value (the aggregate is represented
+ by the formal parameter). */
+ bool by_ref;
+};
+
/* Structure holding data required to describe an ancestor pass-through
jump function. */
unsigned agg_preserved : 1;
};
-/* An element in an aggegate part of a jump function describing a known value
- at a given offset. When it is part of a pass-through jump function with
- agg_preserved set or an ancestor jump function with agg_preserved set, all
- unlisted positions are assumed to be preserved but the value can be a type
- node, which means that the particular piece (starting at offset and having
- the size of the type) is clobbered with an unknown value. When
- agg_preserved is false or the type of the containing jump function is
- different, all unlisted parts are assumed to be unknown and all values must
- fulfill is_gimple_ip_invariant. */
+/* A jump function for an aggregate part at a given offset, which describes how
+ it content value is generated. All unlisted positions are assumed to have a
+ value defined in an unknown way. */
struct GTY(()) ipa_agg_jf_item
{
- /* The offset at which the known value is located within the aggregate. */
+ /* The offset for the aggregate part. */
HOST_WIDE_INT offset;
- /* The known constant or type if this is a clobber. */
- tree value;
-};
+ /* Data type of the aggregate part. */
+ tree type;
+
+ /* Jump function type. */
+ enum jump_func_type jftype;
+ /* Represents a value of jump function. constant represents the actual constant
+ in constant jump function content. pass_through is used only in simple pass
+ through jump function context. load_agg is for load-value-from-aggregate
+ jump function context. */
+ union jump_func_agg_value
+ {
+ tree GTY ((tag ("IPA_JF_CONST"))) constant;
+ struct ipa_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) pass_through;
+ struct ipa_load_agg_data GTY ((tag ("IPA_JF_LOAD_AGG"))) load_agg;
+ } GTY ((desc ("%1.jftype"))) value;
+};
-/* Aggregate jump function - i.e. description of contents of aggregates passed
- either by reference or value. */
+/* Jump functions describing a set of aggregate contents. */
struct GTY(()) ipa_agg_jump_function
{
- /* Description of the individual items. */
+ /* Description of the individual jump function item. */
vec<ipa_agg_jf_item, va_gc> *items;
- /* True if the data was passed by reference (as opposed to by value). */
+ /* True if the data was passed by reference (as opposed to by value). */
bool by_ref;
};
-typedef struct ipa_agg_jump_function *ipa_agg_jump_function_p;
+/* An element in an aggregate part describing a known value at a given offset.
+ All unlisted positions are assumed to be unknown and all listed values must
+ fulfill is_gimple_ip_invariant. */
+
+struct ipa_agg_value
+{
+ /* The offset at which the known value is located within the aggregate. */
+ HOST_WIDE_INT offset;
+
+ /* The known constant. */
+ tree value;
+
+ /* Return true if OTHER describes same agg value. */
+ bool equal_to (const ipa_agg_value &other);
+};
+
+/* Structure describing a set of known offset/value for aggregate. */
+
+struct ipa_agg_value_set
+{
+ /* Description of the individual item. */
+ vec<ipa_agg_value> items;
+ /* True if the data was passed by reference (as opposed to by value). */
+ bool by_ref;
+
+ /* Return true if OTHER describes same agg values. */
+ bool equal_to (const ipa_agg_value_set &other)
+ {
+ if (by_ref != other.by_ref)
+ return false;
+ if (items.length () != other.items.length ())
+ return false;
+ for (unsigned int i = 0; i < items.length (); i++)
+ if (!items[i].equal_to (other.items[i]))
+ return false;
+ return true;
+ }
+
+ /* Return true if there is any value for aggregate. */
+ bool is_empty () const
+ {
+ return items.is_empty ();
+ }
+
+ ipa_agg_value_set copy () const
+ {
+ ipa_agg_value_set new_copy;
+
+ new_copy.items = items.copy ();
+ new_copy.by_ref = by_ref;
+
+ return new_copy;
+ }
+
+ void release ()
+ {
+ items.release ();
+ }
+};
+
+/* Return copy of a vec<ipa_agg_value_set>. */
+
+static inline vec<ipa_agg_value_set>
+ipa_copy_agg_values (const vec<ipa_agg_value_set> &aggs)
+{
+ vec<ipa_agg_value_set> aggs_copy = vNULL;
+
+ if (!aggs.is_empty ())
+ {
+ ipa_agg_value_set *agg;
+ int i;
+
+ aggs_copy.reserve_exact (aggs.length ());
+
+ FOR_EACH_VEC_ELT (aggs, i, agg)
+ aggs_copy.quick_push (agg->copy ());
+ }
+
+ return aggs_copy;
+}
+
+/* For vec<ipa_agg_value_set>, DO NOT call release(), use below function
+ instead. Because ipa_agg_value_set contains a field of vector type, we
+ should release this child vector in each element before reclaiming the
+ whole vector. */
+
+static inline void
+ipa_release_agg_values (vec<ipa_agg_value_set> &aggs,
+ bool release_vector = true)
+{
+ ipa_agg_value_set *agg;
+ int i;
+
+ FOR_EACH_VEC_ELT (aggs, i, agg)
+ agg->release ();
+ if (release_vector)
+ aggs.release ();
+}
/* Information about zero/non-zero bits. */
class GTY(()) ipa_bits
types of jump functions supported. */
struct GTY (()) ipa_jump_func
{
- /* Aggregate contants description. See struct ipa_agg_jump_function and its
- description. */
+ /* Aggregate jump function description. See struct ipa_agg_jump_function
+ and its description. */
struct ipa_agg_jump_function agg;
/* Information about zero/non-zero bits. The pointed to structure is shared
/* Information about value range, containing valid data only when vr_known is
true. The pointed to structure is shared betweed different jump
functions. Use ipa_set_jfunc_vr to set this field. */
- class value_range_base *m_vr;
+ value_range *m_vr;
enum jump_func_type type;
/* Represents a value of a jump function. pass_through is used only in jump
return jfunc->value.ancestor.agg_preserved;
}
+/* Class for allocating a bundle of various potentially known properties about
+ actual arguments of a particular call on stack for the usual case and on
+ heap only if there are unusually many arguments. The data is deallocated
+ when the instance of this class goes out of scope or is otherwise
+ destructed. */
+
+class ipa_auto_call_arg_values
+{
+public:
+ ~ipa_auto_call_arg_values ();
+
+ /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
+ return its element at INDEX, otherwise return NULL. */
+ tree safe_sval_at (int index)
+ {
+ /* TODO: Assert non-negative index here and test. */
+ if ((unsigned) index < m_known_vals.length ())
+ return m_known_vals[index];
+ return NULL;
+ }
+
+ /* If m_known_aggs is sufficiantly long, return the pointer rto its element
+ at INDEX, otherwise return NULL. */
+ ipa_agg_value_set *safe_aggval_at (int index)
+ {
+ /* TODO: Assert non-negative index here and test. */
+ if ((unsigned) index < m_known_aggs.length ())
+ return &m_known_aggs[index];
+ return NULL;
+ }
+
+ /* Vector describing known values of parameters. */
+ auto_vec<tree, 32> m_known_vals;
+
+ /* Vector describing known polymorphic call contexts. */
+ auto_vec<ipa_polymorphic_call_context, 32> m_known_contexts;
+
+ /* Vector describing known aggregate values. */
+ auto_vec<ipa_agg_value_set, 32> m_known_aggs;
+
+ /* Vector describing known value ranges of arguments. */
+ auto_vec<value_range, 32> m_known_value_ranges;
+};
+
+/* Class bundling the various potentially known properties about actual
+ arguments of a particular call. This variant does not deallocate the
+ bundled data in any way. */
+
+class ipa_call_arg_values
+{
+public:
+ /* Default constructor, setting the vectors to empty ones. */
+ ipa_call_arg_values ()
+ {}
+
+ /* Construct this general variant of the bundle from the variant which uses
+ auto_vecs to hold the vectors. This means that vectors of objects
+ constructed with this constructor should not be changed because if they
+ get reallocated, the member vectors and the underlying auto_vecs would get
+ out of sync. */
+ ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
+ : m_known_vals (aavals->m_known_vals.to_vec_legacy ()),
+ m_known_contexts (aavals->m_known_contexts.to_vec_legacy ()),
+ m_known_aggs (aavals->m_known_aggs.to_vec_legacy ()),
+ m_known_value_ranges (aavals->m_known_value_ranges.to_vec_legacy ())
+ {}
+
+ /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
+ return its element at INDEX, otherwise return NULL. */
+ tree safe_sval_at (int index)
+ {
+ /* TODO: Assert non-negative index here and test. */
+ if ((unsigned) index < m_known_vals.length ())
+ return m_known_vals[index];
+ return NULL;
+ }
+
+ /* If m_known_aggs is sufficiantly long, return the pointer rto its element
+ at INDEX, otherwise return NULL. */
+ ipa_agg_value_set *safe_aggval_at (int index)
+ {
+ /* TODO: Assert non-negative index here and test. */
+ if ((unsigned) index < m_known_aggs.length ())
+ return &m_known_aggs[index];
+ return NULL;
+ }
+
+ /* Vector describing known values of parameters. */
+ vec<tree> m_known_vals = vNULL;
+
+ /* Vector describing known polymorphic call contexts. */
+ vec<ipa_polymorphic_call_context> m_known_contexts = vNULL;
+
+ /* Vector describing known aggregate values. */
+ vec<ipa_agg_value_set> m_known_aggs = vNULL;
+
+ /* Vector describing known value ranges of arguments. */
+ vec<value_range> m_known_value_ranges = vNULL;
+};
+
+
/* Summary describing a single formal parameter. */
struct GTY(()) ipa_param_descriptor
{
/* In analysis and modification phase, this is the PARAM_DECL of this
- parameter, in IPA LTO phase, this is the type of the the described
+ parameter, in IPA LTO phase, this is the type of the described
parameter or NULL if not known. Do not read this field directly but
through ipa_get_param and ipa_get_type as appropriate. */
tree decl_or_type;
/* If all uses of the parameter are described by ipa-prop structures, this
says how many there are. If any use could not be described by means of
- ipa-prop structures, this is IPA_UNDESCRIBED_USE. */
+ ipa-prop structures (which include flag dereferenced below), this is
+ IPA_UNDESCRIBED_USE. */
int controlled_uses;
- unsigned int move_cost : 31;
+ unsigned int move_cost : 27;
/* The parameter is used. */
unsigned used : 1;
+ unsigned used_by_ipa_predicates : 1;
+ unsigned used_by_indirect_call : 1;
+ unsigned used_by_polymorphic_call : 1;
+ /* Set to true when in addition to being used in call statements, the
+ parameter has also been used for loads (but not for writes, does not
+ escape, etc.). This allows us to identify parameters p which are only
+ used as *p, and so when we propagate a constant to them, we can generate a
+ LOAD and not ADDR reference to them. */
+ unsigned load_dereferenced : 1;
};
/* ipa_node_params stores information related to formal parameters of functions
unsigned node_dead : 1;
/* Node is involved in a recursion, potentionally indirect. */
unsigned node_within_scc : 1;
+ /* Node contains only direct recursion. */
+ unsigned node_is_self_scc : 1;
/* Node is calling a private function called only once. */
unsigned node_calling_single_call : 1;
/* False when there is something makes versioning impossible. */
ipa_node_params::~ipa_node_params ()
{
free (lattices);
+ vec_free (descriptors);
known_csts.release ();
known_contexts.release ();
}
ipa_get_param (class ipa_node_params *info, int i)
{
gcc_checking_assert (info->descriptors);
- gcc_checking_assert (!flag_wpa);
tree t = (*info->descriptors)[i].decl_or_type;
gcc_checking_assert (TREE_CODE (t) == PARM_DECL);
return t;
(*info->descriptors)[i].used = val;
}
+/* Set the used_by_ipa_predicates flag corresponding to the Ith formal
+ parameter of the function associated with INFO to VAL. */
+
+static inline void
+ipa_set_param_used_by_ipa_predicates (class ipa_node_params *info, int i, bool val)
+{
+ gcc_checking_assert (info->descriptors);
+ (*info->descriptors)[i].used_by_ipa_predicates = val;
+}
+
+/* Set the used_by_indirect_call flag corresponding to the Ith formal
+ parameter of the function associated with INFO to VAL. */
+
+static inline void
+ipa_set_param_used_by_indirect_call (class ipa_node_params *info, int i, bool val)
+{
+ gcc_checking_assert (info->descriptors);
+ (*info->descriptors)[i].used_by_indirect_call = val;
+}
+
+/* Set the .used_by_polymorphic_call flag corresponding to the Ith formal
+ parameter of the function associated with INFO to VAL. */
+
+static inline void
+ipa_set_param_used_by_polymorphic_call (class ipa_node_params *info, int i, bool val)
+{
+ gcc_checking_assert (info->descriptors);
+ (*info->descriptors)[i].used_by_polymorphic_call = val;
+}
+
/* Return how many uses described by ipa-prop a parameter has or
IPA_UNDESCRIBED_USE if there is a use that is not described by these
structures. */
(*info->descriptors)[i].controlled_uses = val;
}
+/* Assuming a parameter does not have IPA_UNDESCRIBED_USE controlled uses,
+ return flag which indicates it has been dereferenced but only in a load. */
+static inline int
+ipa_get_param_load_dereferenced (class ipa_node_params *info, int i)
+{
+ gcc_assert (ipa_get_controlled_uses (info, i) != IPA_UNDESCRIBED_USE);
+ return (*info->descriptors)[i].load_dereferenced;
+}
+
+/* Set the load_dereferenced flag of a given parameter. */
+
+static inline void
+ipa_set_param_load_dereferenced (class ipa_node_params *info, int i, bool val)
+{
+ gcc_checking_assert (info->descriptors);
+ (*info->descriptors)[i].load_dereferenced = val;
+}
+
/* Return the used flag corresponding to the Ith formal parameter of the
function associated with INFO. */
return (*info->descriptors)[i].used;
}
+/* Return the used_by_ipa_predicates flag corresponding to the Ith formal
+ parameter of the function associated with INFO. */
+
+static inline bool
+ipa_is_param_used_by_ipa_predicates (class ipa_node_params *info, int i)
+{
+ gcc_checking_assert (info->descriptors);
+ return (*info->descriptors)[i].used_by_ipa_predicates;
+}
+
+/* Return the used_by_indirect_call flag corresponding to the Ith formal
+ parameter of the function associated with INFO. */
+
+static inline bool
+ipa_is_param_used_by_indirect_call (class ipa_node_params *info, int i)
+{
+ gcc_checking_assert (info->descriptors);
+ return (*info->descriptors)[i].used_by_indirect_call;
+}
+
+/* Return the used_by_polymorphic_call flag corresponding to the Ith formal
+ parameter of the function associated with INFO. */
+
+static inline bool
+ipa_is_param_used_by_polymorphic_call (class ipa_node_params *info, int i)
+{
+ gcc_checking_assert (info->descriptors);
+ return (*info->descriptors)[i].used_by_polymorphic_call;
+}
+
/* Information about replacements done in aggregates for a given node (each
node has its linked list). */
struct GTY(()) ipa_agg_replacement_value
HOST_WIDE_INT offset;
/* The constant value. */
tree value;
- /* The paramter index. */
+ /* The parameter index. */
int index;
/* Whether the value was passed by reference. */
bool by_ref;
vec<ipa_bits *, va_gc> *bits;
/* Value range information. */
vec<ipa_vr, va_gc> *m_vr;
+
+ /* Default constructor. */
+ ipcp_transformation ()
+ : agg_values (NULL), bits (NULL), m_vr (NULL)
+ { }
+
+ /* Default destructor. */
+ ~ipcp_transformation ()
+ {
+ ipa_agg_replacement_value *agg = agg_values;
+ while (agg)
+ {
+ ipa_agg_replacement_value *next = agg->next;
+ ggc_free (agg);
+ agg = next;
+ }
+ vec_free (bits);
+ vec_free (m_vr);
+ }
};
void ipa_set_node_agg_value_chain (struct cgraph_node *node,
/* Destructor. */
~ipa_edge_args ()
{
+ unsigned int i;
+ ipa_jump_func *jf;
+ FOR_EACH_VEC_SAFE_ELT (jump_functions, i, jf)
+ vec_free (jf->agg.items);
vec_free (jump_functions);
vec_free (polymorphic_call_contexts);
}
{
public:
ipa_node_params_t (symbol_table *table, bool ggc):
- function_summary<ipa_node_params *> (table, ggc) { }
+ function_summary<ipa_node_params *> (table, ggc)
+ {
+ disable_insertion_hook ();
+ }
/* Hook that is called by summary when a node is duplicated. */
virtual void duplicate (cgraph_node *node,
ipa_edge_args_sum_t (symbol_table *table, bool ggc)
: call_summary<ipa_edge_args *> (table, ggc) { }
+ void remove (cgraph_edge *edge)
+ {
+ call_summary <ipa_edge_args *>::remove (edge);
+ }
+
/* Hook that is called by summary when an edge is removed. */
virtual void remove (cgraph_edge *cs, ipa_edge_args *args);
/* Hook that is called by summary when an edge is duplicated. */
static ipcp_transformation_t *create_ggc (symbol_table *symtab)
{
ipcp_transformation_t *summary
- = new (ggc_cleared_alloc <ipcp_transformation_t> ())
+ = new (ggc_alloc_no_dtor <ipcp_transformation_t> ())
ipcp_transformation_t (symtab, true);
return summary;
}
+ /* Hook that is called by summary when a node is duplicated. */
+ virtual void duplicate (cgraph_node *node,
+ cgraph_node *node2,
+ ipcp_transformation *data,
+ ipcp_transformation *data2);
};
/* Function summary where the IPA CP transformations are actually stored. */
extern GTY(()) function_summary <ipcp_transformation *> *ipcp_transformation_sum;
-/* Return the associated parameter/argument info corresponding to the given
- node/edge. */
-#define IPA_NODE_REF(NODE) (ipa_node_params_sum->get_create (NODE))
-#define IPA_EDGE_REF(EDGE) (ipa_edge_args_sum->get_create (EDGE))
-/* This macro checks validity of index returned by
- ipa_get_param_decl_index function. */
-#define IS_VALID_JUMP_FUNC_INDEX(I) ((I) != -1)
-
/* Creating and freeing ipa_node_params and ipa_edge_args. */
void ipa_create_all_node_params (void);
void ipa_create_all_edge_args (void);
{
if (!ipa_node_params_sum)
ipa_node_params_sum
- = (new (ggc_cleared_alloc <ipa_node_params_t> ())
+ = (new (ggc_alloc_no_dtor <ipa_node_params_t> ())
ipa_node_params_t (symtab, true));
}
bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
vec<cgraph_edge *> *new_edges);
-/* Indirect edge and binfo processing. */
+/* Indirect edge processing and target discovery. */
+tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
+ ipa_call_arg_values *avals,
+ bool *speculative);
tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
- vec<tree> ,
- vec<ipa_polymorphic_call_context>,
- vec<ipa_agg_jump_function_p>,
- bool *);
+ ipa_auto_call_arg_values *avals,
+ bool *speculative);
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
bool speculative = false);
tree ipa_impossible_devirt_target (struct cgraph_edge *, tree);
void ipa_analyze_node (struct cgraph_node *);
/* Aggregate jump function related functions. */
-tree ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, tree scalar,
+tree ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
HOST_WIDE_INT offset, bool by_ref,
bool *from_global_constant = NULL);
bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
cgraph_edge *,
int,
ipa_jump_func *);
+value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
+ ipa_jump_func *, tree);
+ipa_agg_value_set ipa_agg_value_set_from_jfunc (ipa_node_params *,
+ cgraph_node *,
+ ipa_agg_jump_function *);
void ipa_dump_param (FILE *, class ipa_node_params *info, int i);
void ipa_release_body_info (struct ipa_func_body_info *);
tree ipa_get_callee_param_type (struct cgraph_edge *e, int i);
+bool ipcp_get_parm_bits (tree, tree *, widest_int *);
+bool unadjusted_ptr_and_unit_offset (tree op, tree *ret,
+ poly_int64 *offset_ret);
/* From tree-sra.c: */
tree build_ref_for_offset (location_t, tree, poly_int64, bool, tree,