@@ -2510,7 +2510,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \
$(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
$(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-utils.h \
- $(srcdir)/dbxout.c \
+ $(srcdir)/ipa-param-manipulation.h $(srcdir)/dbxout.c \
$(srcdir)/signop.h \
$(srcdir)/dwarf2out.h \
$(srcdir)/dwarf2asm.c \
@@ -28,15 +28,23 @@ along with GCC; see the file COPYING3. If not see
#include "ssa.h"
#include "cgraph.h"
#include "fold-const.h"
+#include "tree-eh.h"
#include "stor-layout.h"
#include "gimplify.h"
#include "gimple-iterator.h"
#include "gimplify-me.h"
+#include "tree-cfg.h"
#include "tree-dfa.h"
#include "ipa-param-manipulation.h"
#include "print-tree.h"
#include "gimple-pretty-print.h"
#include "builtins.h"
+#include "tree-ssa.h"
+
+const char *ipa_param_prefixes[] = {"SYNTH",
+ "ISRA",
+ "simd",
+ "mask"};
/* Return a heap allocated vector containing formal parameters of FNDECL. */
@@ -79,336 +87,236 @@ ipa_get_vector_of_formal_parm_types (tree fntype)
return types;
}
-/* Modify the function declaration FNDECL and its type according to the plan in
- ADJUSTMENTS. It also sets base fields of individual adjustments structures
- to reflect the actual parameters being modified which are determined by the
- base_index field. */
+/* Constructor from NEW_PARAMS showing how new parameters should look like and
+ CUR_PARAMS, which is either known vector of current parameter declarations
+ or NULL if no debug information for removed parameters should or can be
+ recorded. */
-void
-ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments)
+ipa_param_adjustments
+::ipa_param_adjustments (vec<ipa_adjusted_param, va_gc> *new_params,
+ vec<tree> *cur_params)
+ : m_adj_params (new_params), m_vanishing_decls (NULL),
+ m_vanishing_indices (NULL)
{
- vec<tree> oparms = ipa_get_vector_of_formal_parms (fndecl);
- tree orig_type = TREE_TYPE (fndecl);
- tree old_arg_types = TYPE_ARG_TYPES (orig_type);
-
- /* The following test is an ugly hack, some functions simply don't have any
- arguments in their type. This is probably a bug but well... */
- bool care_for_types = (old_arg_types != NULL_TREE);
- bool last_parm_void;
- vec<tree> otypes;
- if (care_for_types)
- {
- last_parm_void = (TREE_VALUE (tree_last (old_arg_types))
- == void_type_node);
- otypes = ipa_get_vector_of_formal_parm_types (orig_type);
- if (last_parm_void)
- gcc_assert (oparms.length () + 1 == otypes.length ());
- else
- gcc_assert (oparms.length () == otypes.length ());
- }
- else
- {
- last_parm_void = false;
- otypes.create (0);
- }
-
- int len = adjustments.length ();
- tree *link = &DECL_ARGUMENTS (fndecl);
- tree new_arg_types = NULL;
- for (int i = 0; i < len; i++)
- {
- struct ipa_parm_adjustment *adj;
- gcc_assert (link);
-
- adj = &adjustments[i];
- tree parm;
- if (adj->op == IPA_PARM_OP_NEW)
- parm = NULL;
- else
- parm = oparms[adj->base_index];
- adj->base = parm;
-
- if (adj->op == IPA_PARM_OP_COPY)
- {
- if (care_for_types)
- new_arg_types = tree_cons (NULL_TREE, otypes[adj->base_index],
- new_arg_types);
- *link = parm;
- link = &DECL_CHAIN (parm);
- }
- else if (adj->op != IPA_PARM_OP_REMOVE)
- {
- tree new_parm;
- tree ptype;
-
- if (adj->by_ref)
- ptype = build_pointer_type (adj->type);
- else
- {
- ptype = adj->type;
- if (is_gimple_reg_type (ptype)
- && TYPE_MODE (ptype) != BLKmode)
- {
- unsigned malign = GET_MODE_ALIGNMENT (TYPE_MODE (ptype));
- if (TYPE_ALIGN (ptype) != malign)
- ptype = build_aligned_type (ptype, malign);
- }
- }
-
- if (care_for_types)
- new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types);
-
- new_parm = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL_TREE,
- ptype);
- const char *prefix = adj->arg_prefix ? adj->arg_prefix : "SYNTH";
- DECL_NAME (new_parm) = create_tmp_var_name (prefix);
- DECL_ARTIFICIAL (new_parm) = 1;
- DECL_ARG_TYPE (new_parm) = ptype;
- DECL_CONTEXT (new_parm) = fndecl;
- TREE_USED (new_parm) = 1;
- DECL_IGNORED_P (new_parm) = 1;
- layout_decl (new_parm, 0);
+ if (cur_params)
+ init (cur_params);
+}
- if (adj->op == IPA_PARM_OP_NEW)
- adj->base = NULL;
- else
- adj->base = parm;
- adj->new_decl = new_parm;
+/* Constructor from NEW_PARAMS showing how new parameters should look like
+ and a FNDECL of the function they should be applied to. */
- *link = new_parm;
- link = &DECL_CHAIN (new_parm);
- }
- }
+ipa_param_adjustments
+::ipa_param_adjustments (vec<ipa_adjusted_param, va_gc> *new_params,
+ tree fndecl)
+ : m_adj_params (new_params), m_vanishing_decls (NULL),
+ m_vanishing_indices (NULL)
+{
+ vec<tree> cur_params = ipa_get_vector_of_formal_parms (fndecl);
+ init (&cur_params);
+ cur_params.release ();
+}
- *link = NULL_TREE;
- tree new_reversed = NULL;
- if (care_for_types)
- {
- new_reversed = nreverse (new_arg_types);
- if (last_parm_void)
- {
- if (new_reversed)
- TREE_CHAIN (new_arg_types) = void_list_node;
- else
- new_reversed = void_list_node;
- }
- }
+/* Initialize m_vanishing_decls and m_vanishing_decls based on m_adj_params and
+ CUR_PARAMS. */
- /* Use copy_node to preserve as much as possible from original type
- (debug info, attribute lists etc.)
- Exception is METHOD_TYPEs must have THIS argument.
- When we are asked to remove it, we need to build new FUNCTION_TYPE
- instead. */
- tree new_type = NULL;
- if (TREE_CODE (orig_type) != METHOD_TYPE
- || (adjustments[0].op == IPA_PARM_OP_COPY
- && adjustments[0].base_index == 0))
- {
- new_type = build_distinct_type_copy (orig_type);
- TYPE_ARG_TYPES (new_type) = new_reversed;
- }
- else
- {
- new_type
- = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type),
- new_reversed));
- TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type);
- DECL_VINDEX (fndecl) = NULL_TREE;
- }
-
- /* When signature changes, we need to clear builtin info. */
- if (DECL_BUILT_IN (fndecl))
+void
+ipa_param_adjustments::init (vec<tree> *cur_params)
+{
+ unsigned cp_len = cur_params ? cur_params->length() : 0;
+ auto_vec<bool, 16> kept (cp_len);
+ kept.quick_grow_cleared (cp_len);
+ unsigned adj_len = vec_safe_length (m_adj_params);
+ for (unsigned i = 0; i < adj_len ; i++)
{
- DECL_BUILT_IN_CLASS (fndecl) = NOT_BUILT_IN;
- DECL_FUNCTION_CODE (fndecl) = (enum built_in_function) 0;
+ ipa_adjusted_param *apm = &(*m_adj_params)[i];
+ gcc_assert (apm->op != IPA_PARAM_OP_UNDEFINED);
+ if (apm->op == IPA_PARAM_OP_COPY)
+ kept[apm->base_index] = true;
}
-
- TREE_TYPE (fndecl) = new_type;
- DECL_VIRTUAL_P (fndecl) = 0;
- DECL_LANG_SPECIFIC (fndecl) = NULL;
- otypes.release ();
- oparms.release ();
+ for (unsigned i = 0; i < cp_len; i++)
+ if (!kept[i])
+ {
+ vec_safe_push (m_vanishing_decls, (*cur_params)[i]);
+ vec_safe_push (m_vanishing_indices, i);
+ }
}
-/* Modify actual arguments of a function call CS as indicated in ADJUSTMENTS.
- If this is a directly recursive call, CS must be NULL. Otherwise it must
- contain the corresponding call graph edge. */
+/* Modify actual arguments of a function call in statement STMT, assuming it
+ calls CALLEE_DECL. Return the new statement that replaced the old one. */
-void
-ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
- ipa_parm_adjustment_vec adjustments)
+gcall *
+ipa_param_adjustments::modify_call_arguments (gcall *stmt, tree callee_decl)
{
- struct cgraph_node *current_node = cgraph_node::get (current_function_decl);
- vec<tree> vargs;
- vec<tree, va_gc> **debug_args = NULL;
- gcall *new_stmt;
- gimple_stmt_iterator gsi, prev_gsi;
- tree callee_decl;
- int i, len;
+ unsigned len = vec_safe_length (m_adj_params);
+ auto_vec<tree, 16> vargs (len);
- len = adjustments.length ();
- vargs.create (len);
- callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl;
+ cgraph_node *current_node = cgraph_node::get (current_function_decl);
current_node->remove_stmt_references (stmt);
- gsi = gsi_for_stmt (stmt);
- prev_gsi = gsi;
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ gimple_stmt_iterator prev_gsi = gsi;
gsi_prev (&prev_gsi);
- for (i = 0; i < len; i++)
+ for (unsigned i = 0; i < len; i++)
{
- struct ipa_parm_adjustment *adj;
+ ipa_adjusted_param *apm = &(*m_adj_params)[i];
- adj = &adjustments[i];
+ gcc_assert (apm->op != IPA_PARAM_OP_UNDEFINED);
+ /* Any transformation that introduces unspecified new parameters needs
+ to transform actual arguments itself. */
+ gcc_assert (apm->op != IPA_PARAM_OP_NEW);
- if (adj->op == IPA_PARM_OP_COPY)
+ if (apm->op == IPA_PARAM_OP_COPY)
{
- tree arg = gimple_call_arg (stmt, adj->base_index);
+ tree arg = gimple_call_arg (stmt, apm->base_index);
vargs.quick_push (arg);
+ continue;
}
- else if (adj->op != IPA_PARM_OP_REMOVE)
+ gcc_assert (apm->op == IPA_PARAM_OP_SPLIT);
+
+ /* We create a new parameter out of the value of the old one, we can
+ do the following kind of transformations:
+
+ - A scalar passed by reference is converted to a scalar passed by
+ value. (apm->by_ref is false and the type of the original
+ actual argument is a pointer to a scalar).
+
+ - A part of an aggregate is passed instead of the whole aggregate.
+ The part can be passed either by value or by reference, this is
+ determined by value of apm->by_ref. Moreover, the code below
+ handles both situations when the original aggregate is passed by
+ value (its type is not a pointer) and when it is passed by
+ reference (it is a pointer to an aggregate).
+
+ When the new argument is passed by reference (apm->by_ref is true)
+ it must be a part of an aggregate and therefore we form it by
+ simply taking the address of a reference inside the original
+ aggregate. */
+
+ tree base = gimple_call_arg (stmt, apm->base_index);
+ location_t loc = DECL_P (base) ? DECL_SOURCE_LOCATION (base)
+ : EXPR_LOCATION (base);
+
+ tree off;
+ bool deref_base = false;
+ unsigned int deref_align = 0;
+ if (TREE_CODE (base) != ADDR_EXPR && POINTER_TYPE_P (TREE_TYPE (base)))
+ off = build_int_cst (apm->alias_ptr_type, apm->unit_offset);
+ else
{
- tree expr, base, off;
- location_t loc;
- unsigned int deref_align = 0;
- bool deref_base = false;
-
- /* We create a new parameter out of the value of the old one, we can
- do the following kind of transformations:
-
- - A scalar passed by reference is converted to a scalar passed by
- value. (adj->by_ref is false and the type of the original
- actual argument is a pointer to a scalar).
-
- - A part of an aggregate is passed instead of the whole aggregate.
- The part can be passed either by value or by reference, this is
- determined by value of adj->by_ref. Moreover, the code below
- handles both situations when the original aggregate is passed by
- value (its type is not a pointer) and when it is passed by
- reference (it is a pointer to an aggregate).
-
- When the new argument is passed by reference (adj->by_ref is true)
- it must be a part of an aggregate and therefore we form it by
- simply taking the address of a reference inside the original
- aggregate. */
-
- gcc_checking_assert (adj->offset % BITS_PER_UNIT == 0);
- base = gimple_call_arg (stmt, adj->base_index);
- loc = DECL_P (base) ? DECL_SOURCE_LOCATION (base)
- : EXPR_LOCATION (base);
-
- if (TREE_CODE (base) != ADDR_EXPR
- && POINTER_TYPE_P (TREE_TYPE (base)))
- off = build_int_cst (adj->alias_ptr_type,
- adj->offset / BITS_PER_UNIT);
- else
+ bool addrof;
+ if (TREE_CODE (base) == ADDR_EXPR)
{
- HOST_WIDE_INT base_offset;
- tree prev_base;
- bool addrof;
+ base = TREE_OPERAND (base, 0);
+ addrof = true;
+ }
+ else
+ addrof = false;
- if (TREE_CODE (base) == ADDR_EXPR)
- {
- base = TREE_OPERAND (base, 0);
- addrof = true;
- }
- else
- addrof = false;
- prev_base = base;
- base = get_addr_base_and_unit_offset (base, &base_offset);
- /* Aggregate arguments can have non-invariant addresses. */
- if (!base)
- {
- base = build_fold_addr_expr (prev_base);
- off = build_int_cst (adj->alias_ptr_type,
- adj->offset / BITS_PER_UNIT);
- }
- else if (TREE_CODE (base) == MEM_REF)
- {
- if (!addrof)
- {
- deref_base = true;
- deref_align = TYPE_ALIGN (TREE_TYPE (base));
- }
- off = build_int_cst (adj->alias_ptr_type,
- base_offset
- + adj->offset / BITS_PER_UNIT);
- off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1),
- off);
- base = TREE_OPERAND (base, 0);
- }
- else
+ tree prev_base = base;
+ HOST_WIDE_INT base_offset;
+ base = get_addr_base_and_unit_offset (base, &base_offset);
+
+ /* Aggregate arguments can have non-invariant addresses. */
+ if (!base)
+ {
+ base = build_fold_addr_expr (prev_base);
+ off = build_int_cst (apm->alias_ptr_type, apm->unit_offset);
+ }
+ else if (TREE_CODE (base) == MEM_REF)
+ {
+ if (!addrof)
{
- off = build_int_cst (adj->alias_ptr_type,
- base_offset
- + adj->offset / BITS_PER_UNIT);
- base = build_fold_addr_expr (base);
+ deref_base = true;
+ deref_align = TYPE_ALIGN (TREE_TYPE (base));
}
+ off = build_int_cst (apm->alias_ptr_type,
+ base_offset + apm->unit_offset);
+ off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1),
+ off);
+ base = TREE_OPERAND (base, 0);
}
-
- if (!adj->by_ref)
+ else
{
- tree type = adj->type;
- unsigned int align;
- unsigned HOST_WIDE_INT misalign;
+ off = build_int_cst (apm->alias_ptr_type,
+ base_offset + apm->unit_offset);
+ base = build_fold_addr_expr (base);
+ }
+ }
- if (deref_base)
- {
- align = deref_align;
- misalign = 0;
- }
- else
- {
- get_pointer_alignment_1 (base, &align, &misalign);
- if (TYPE_ALIGN (type) > align)
- align = TYPE_ALIGN (type);
- }
- misalign += (offset_int::from (wi::to_wide (off),
- SIGNED).to_short_addr ()
- * BITS_PER_UNIT);
- misalign = misalign & (align - 1);
- if (misalign != 0)
- align = least_bit_hwi (misalign);
- if (align < TYPE_ALIGN (type))
- type = build_aligned_type (type, align);
- base = force_gimple_operand_gsi (&gsi, base,
- true, NULL, true, GSI_SAME_STMT);
- expr = fold_build2_loc (loc, MEM_REF, type, base, off);
- REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse;
- /* If expr is not a valid gimple call argument emit
- a load into a temporary. */
- if (is_gimple_reg_type (TREE_TYPE (expr)))
- {
- gimple *tem = gimple_build_assign (NULL_TREE, expr);
- if (gimple_in_ssa_p (cfun))
- {
- gimple_set_vuse (tem, gimple_vuse (stmt));
- expr = make_ssa_name (TREE_TYPE (expr), tem);
- }
- else
- expr = create_tmp_reg (TREE_TYPE (expr));
- gimple_assign_set_lhs (tem, expr);
- gsi_insert_before (&gsi, tem, GSI_SAME_STMT);
- }
+ tree expr;
+ if (!apm->by_ref)
+ {
+ tree type = apm->type;
+ unsigned int align;
+ unsigned HOST_WIDE_INT misalign;
+
+ if (deref_base)
+ {
+ align = deref_align;
+ misalign = 0;
}
else
{
- expr = fold_build2_loc (loc, MEM_REF, adj->type, base, off);
- REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse;
- expr = build_fold_addr_expr (expr);
- expr = force_gimple_operand_gsi (&gsi, expr,
- true, NULL, true, GSI_SAME_STMT);
+ get_pointer_alignment_1 (base, &align, &misalign);
+ /* All users must make sure that we can be optimistic when it
+ comes to alignment in this case (by inspecting the final users
+ of these new parameters). */
+ if (TYPE_ALIGN (type) > align)
+ align = TYPE_ALIGN (type);
+ }
+ misalign += (offset_int::from (wi::to_wide (off),
+ SIGNED).to_short_addr ()
+ * BITS_PER_UNIT);
+ misalign = misalign & (align - 1);
+ if (misalign != 0)
+ align = least_bit_hwi (misalign);
+ if (align < TYPE_ALIGN (type))
+ type = build_aligned_type (type, align);
+ base = force_gimple_operand_gsi (&gsi, base,
+ true, NULL, true, GSI_SAME_STMT);
+ expr = fold_build2_loc (loc, MEM_REF, type, base, off);
+ REF_REVERSE_STORAGE_ORDER (expr) = apm->reverse;
+ /* If expr is not a valid gimple call argument emit
+ a load into a temporary. */
+ if (is_gimple_reg_type (TREE_TYPE (expr)))
+ {
+ gimple *tem = gimple_build_assign (NULL_TREE, expr);
+ if (gimple_in_ssa_p (cfun))
+ {
+ gimple_set_vuse (tem, gimple_vuse (stmt));
+ expr = make_ssa_name (TREE_TYPE (expr), tem);
+ }
+ else
+ expr = create_tmp_reg (TREE_TYPE (expr));
+ gimple_assign_set_lhs (tem, expr);
+ gsi_insert_before (&gsi, tem, GSI_SAME_STMT);
}
- vargs.quick_push (expr);
}
- if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS)
+ else
{
- unsigned int ix;
- tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg;
- gimple *def_temp;
+ expr = fold_build2_loc (loc, MEM_REF, apm->type, base, off);
+ REF_REVERSE_STORAGE_ORDER (expr) = apm->reverse;
+ expr = build_fold_addr_expr (expr);
+ expr = force_gimple_operand_gsi (&gsi, expr,
+ true, NULL, true, GSI_SAME_STMT);
+ }
+ vargs.quick_push (expr);
+ }
+
+ if (callee_decl && MAY_HAVE_DEBUG_STMTS && m_vanishing_decls)
+ {
+ vec<tree, va_gc> **debug_args = NULL;
+ unsigned van_len = vec_safe_length (m_vanishing_decls);
+ for (unsigned i = 0; i < van_len; i++)
+ {
+ tree vanished_decl = (*m_vanishing_decls)[i];
+ if (!vanished_decl)
+ continue;
+ tree origin = DECL_ORIGIN (vanished_decl);
+ tree arg = gimple_call_arg (stmt, (*m_vanishing_indices)[i]);
- arg = gimple_call_arg (stmt, adj->base_index);
if (!useless_type_conversion_p (TREE_TYPE (origin), TREE_TYPE (arg)))
{
if (!fold_convertible_p (TREE_TYPE (origin), arg))
@@ -418,6 +326,8 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
}
if (debug_args == NULL)
debug_args = decl_debug_args_insert (callee_decl);
+ unsigned int ix;
+ tree ddecl = NULL_TREE;
for (ix = 0; vec_safe_iterate (*debug_args, ix, &ddecl); ix += 2)
if (ddecl == origin)
{
@@ -434,7 +344,8 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
vec_safe_push (*debug_args, origin);
vec_safe_push (*debug_args, ddecl);
}
- def_temp = gimple_build_debug_bind (ddecl, unshare_expr (arg), stmt);
+ gimple *def_temp = gimple_build_debug_bind (ddecl,
+ unshare_expr (arg), stmt);
gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
}
}
@@ -445,8 +356,8 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
print_gimple_stmt (dump_file, gsi_stmt (gsi), 0);
}
- new_stmt = gimple_build_call_vec (callee_decl, vargs);
- vargs.release ();
+ gcall *new_stmt = gimple_build_call_vec (callee_decl, vargs);
+
if (gimple_call_lhs (stmt))
gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
@@ -472,120 +383,264 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
fprintf (dump_file, "\n");
}
gsi_replace (&gsi, new_stmt, true);
- if (cs)
- cs->set_call_stmt (new_stmt);
do
{
current_node->record_stmt_references (gsi_stmt (gsi));
gsi_prev (&gsi);
}
while (gsi_stmt (gsi) != gsi_stmt (prev_gsi));
+ return new_stmt;
}
-/* Return true iff BASE_INDEX is in ADJUSTMENTS more than once. */
+void
+ipa_param_adjustments::modify_call_arguments (struct cgraph_edge *cs)
+{
+ gcall *old_call = cs->call_stmt;
+ tree callee_decl = cs->callee ? cs->callee->decl : NULL;
+ /* TODO: Optionally set current_function_decl */
+ gcall *new_call = modify_call_arguments (old_call, callee_decl);
+ cs->set_call_stmt (new_call);
+}
+
+/* Names of parameters for dumping. Keep in sync with enum ipa_parm_op. */
+
+static const char *ipa_param_op_names[] = {"IPA_PARAM_OP_UNDEFINED",
+ "IPA_PARAM_OP_COPY",
+ "IPA_PARAM_OP_NEW",
+ "IPA_PARAM_OP_SPLIT"};
+
+/* Dump the adjustments in the vector ADJUSTMENTS to dump_file in a human
+ friendly way, assuming they are meant to be applied to FNDECL. */
-static bool
-index_in_adjustments_multiple_times_p (int base_index,
- ipa_parm_adjustment_vec adjustments)
+void
+ipa_dump_adjusted_parameters (FILE *f,
+ vec<ipa_adjusted_param, va_gc> *adj_params)
{
- int i, len = adjustments.length ();
- bool one = false;
+ unsigned i, len = vec_safe_length (adj_params);
+ bool first = true;
+ fprintf (f, "IPA adjusted parameters: ");
for (i = 0; i < len; i++)
{
- struct ipa_parm_adjustment *adj;
- adj = &adjustments[i];
+ struct ipa_adjusted_param *apm;
+ apm = &(*adj_params)[i];
+
+ if (!first)
+ fprintf (f, " ");
+ else
+ first = false;
- if (adj->base_index == base_index)
+ fprintf (f, "%i. %s", i, ipa_param_op_names[apm->op]);
+ switch (apm->op)
{
- if (one)
- return true;
- else
- one = true;
+ case IPA_PARAM_OP_UNDEFINED:
+ break;
+
+ case IPA_PARAM_OP_COPY:
+ fprintf (f, ", base_index: %u", apm->base_index);
+ break;
+
+ case IPA_PARAM_OP_SPLIT:
+ fprintf (f, ", offset: %u", apm->unit_offset);
+ /* fall-through */
+ case IPA_PARAM_OP_NEW:
+ fprintf (f, ", base_index: %u", apm->base_index);
+ print_node_brief (f, ", type: ", apm->type, 0);
+ print_node_brief (f, ", type: ", apm->alias_ptr_type, 0);
+ fprintf (f, " prefix: %s, reverse: %u, by_ref: %u",
+ ipa_param_prefixes[apm->param_prefix_index],
+ apm->reverse, apm->by_ref);
+ break;
}
+ fprintf (f, "\n");
}
- return false;
}
-/* Return adjustments that should have the same effect on function parameters
- and call arguments as if they were first changed according to adjustments in
- INNER and then by adjustments in OUTER. */
-ipa_parm_adjustment_vec
-ipa_combine_adjustments (ipa_parm_adjustment_vec inner,
- ipa_parm_adjustment_vec outer)
+/* Constructor of ipa_param_body_adjustments performing all necessary
+ initializations. */
+
+ipa_param_body_adjustments
+::ipa_param_body_adjustments (vec<ipa_adjusted_param, va_gc> *adj_params,
+ tree fndecl)
+ : m_adj_params (adj_params), m_fndecl (fndecl), m_oparms (),
+ m_replacements (), m_new_decls (vec_safe_length (adj_params)),
+ m_new_types (vec_safe_length (adj_params)), m_reset_debug_decls (),
+ m_removed_decls (), m_removed_map (), m_method2func ()
{
- int i, outlen = outer.length ();
- int inlen = inner.length ();
- int removals = 0;
- ipa_parm_adjustment_vec adjustments, tmp;
+ for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
+ m_oparms.safe_push (parm);
- tmp.create (inlen);
- for (i = 0; i < inlen; i++)
- {
- struct ipa_parm_adjustment *n;
- n = &inner[i];
+ bool care_for_types = (TYPE_ARG_TYPES (TREE_TYPE (m_fndecl)) != NULL_TREE);
+ vec<tree> otypes;
+ if (care_for_types)
+ otypes = ipa_get_vector_of_formal_parm_types (TREE_TYPE (m_fndecl));
+ else
+ otypes = vNULL;
- if (n->op == IPA_PARM_OP_REMOVE)
- removals++;
- else
- {
- /* FIXME: Handling of new arguments are not implemented yet. */
- gcc_assert (n->op != IPA_PARM_OP_NEW);
- tmp.quick_push (*n);
- }
- }
+ auto_vec<bool, 16> kept (m_oparms.length ());
+ kept.quick_grow_cleared (m_oparms.length ());
+ m_method2func = (TREE_CODE (TREE_TYPE (m_fndecl)) == METHOD_TYPE);
- adjustments.create (outlen + removals);
- for (i = 0; i < outlen; i++)
+ unsigned adj_len = vec_safe_length (m_adj_params);
+ for (unsigned i = 0; i < adj_len ; i++)
{
- struct ipa_parm_adjustment r;
- struct ipa_parm_adjustment *out = &outer[i];
- struct ipa_parm_adjustment *in = &tmp[out->base_index];
-
- memset (&r, 0, sizeof (r));
- gcc_assert (in->op != IPA_PARM_OP_REMOVE);
- if (out->op == IPA_PARM_OP_REMOVE)
+ ipa_adjusted_param *apm = &(*m_adj_params)[i];
+ tree new_parm, new_type;
+ if (apm->op == IPA_PARAM_OP_COPY)
+ {
+ kept[apm->base_index] = true;
+ if (care_for_types)
+ new_type = otypes[apm->base_index];
+ else
+ new_type = NULL;
+ new_parm = m_oparms[apm->base_index];
+ if (apm->base_index == 0)
+ m_method2func = false;
+ }
+ else if (apm->op == IPA_PARAM_OP_NEW
+ || apm->op == IPA_PARAM_OP_SPLIT)
{
- if (!index_in_adjustments_multiple_times_p (in->base_index, tmp))
+ if (apm->by_ref)
{
- r.op = IPA_PARM_OP_REMOVE;
- adjustments.quick_push (r);
+ new_type = build_pointer_type (apm->type);
+ if (is_gimple_reg_type (new_type)
+ && TYPE_MODE (new_type) != BLKmode)
+ {
+ unsigned malign = GET_MODE_ALIGNMENT (TYPE_MODE (new_type));
+ if (TYPE_ALIGN (new_type) != malign)
+ new_type = build_aligned_type (new_type, malign);
+ }
}
- continue;
- }
+ else
+ new_type = apm->type;
+ new_parm = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL_TREE,
+ new_type);
+ const char *prefix = ipa_param_prefixes[apm->param_prefix_index];
+ DECL_NAME (new_parm) = create_tmp_var_name (prefix);
+ DECL_ARTIFICIAL (new_parm) = 1;
+ DECL_ARG_TYPE (new_parm) = new_type;
+ DECL_CONTEXT (new_parm) = m_fndecl;
+ TREE_USED (new_parm) = 1;
+ DECL_IGNORED_P (new_parm) = 1;
+ layout_decl (new_parm, 0);
+
+ if (apm->op == IPA_PARAM_OP_SPLIT)
+ register_replacement (apm, new_parm);
+ }
else
- {
- /* FIXME: Handling of new arguments are not implemented yet. */
- gcc_assert (out->op != IPA_PARM_OP_NEW);
- }
+ gcc_unreachable ();
+ m_new_decls.quick_push (new_parm);
+ if (care_for_types)
+ m_new_types.quick_push (new_type);
+ }
- r.base_index = in->base_index;
- r.type = out->type;
+ unsigned op_len = m_oparms.length ();
+ for (unsigned i = 0; i < op_len; i++)
+ if (!kept[i])
+ {
+ if (is_gimple_reg (m_oparms[i]))
+ m_reset_debug_decls.safe_push (m_oparms[i]);
+ m_removed_decls.safe_push(m_oparms[i]);
+ m_removed_map.put (m_oparms[i], m_removed_decls.length () - 1);
+ }
- /* FIXME: Create nonlocal value too. */
+ otypes.release ();
+}
- if (in->op == IPA_PARM_OP_COPY && out->op == IPA_PARM_OP_COPY)
- r.op = IPA_PARM_OP_COPY;
- else if (in->op == IPA_PARM_OP_COPY)
- r.offset = out->offset;
- else if (out->op == IPA_PARM_OP_COPY)
- r.offset = in->offset;
- else
- r.offset = in->offset + out->offset;
- adjustments.quick_push (r);
+/* Register that REPLACEMENT should replace parameter described in APM. */
+
+void
+ipa_param_body_adjustments::register_replacement (ipa_adjusted_param *apm,
+ tree replacement)
+{
+ gcc_checking_assert (apm->op == IPA_PARAM_OP_SPLIT
+ || apm->op == IPA_PARAM_OP_NEW);
+ ipa_param_body_replacement psr;
+ psr.base = m_oparms[apm->base_index];
+ psr.unit_offset = apm->unit_offset;
+ psr.repl = replacement;
+ psr.by_ref = apm->by_ref;
+ psr.reverse = apm->reverse;
+ m_replacements.safe_push (psr);
+}
+
+/* Modify the function declaration FNDECL and its type according to the plan in
+ ADJUSTMENTS. It also sets base fields of individual adjustments structures
+ to reflect the actual parameters being modified which are determined by the
+ base_index field. */
+
+void
+ipa_param_body_adjustments::modify_formal_parameters ()
+{
+ tree orig_type = TREE_TYPE (m_fndecl);
+ tree old_arg_types = TYPE_ARG_TYPES (orig_type);
+
+ bool care_for_types = (old_arg_types != NULL_TREE);
+ bool last_parm_void = care_for_types
+ && (TREE_VALUE (tree_last (old_arg_types)) == void_type_node);;
+
+ unsigned len = vec_safe_length (m_adj_params);
+ gcc_assert (len == m_new_decls.length());
+ gcc_assert (len == m_new_types.length() || !care_for_types);
+ tree *link = &DECL_ARGUMENTS (m_fndecl);
+ tree new_arg_types = NULL;
+
+ for (unsigned i = 0; i < len; i++)
+ {
+ tree new_decl = m_new_decls[i];
+
+ if (care_for_types)
+ new_arg_types = tree_cons (NULL_TREE, m_new_types[i], new_arg_types);
+ *link = new_decl;
+ link = &DECL_CHAIN (new_decl);
}
+ *link = NULL_TREE;
- for (i = 0; i < inlen; i++)
+ tree new_reversed;
+ if (care_for_types)
+ {
+ new_reversed = nreverse (new_arg_types);
+ if (last_parm_void)
+ {
+ if (new_reversed)
+ TREE_CHAIN (new_arg_types) = void_list_node;
+ else
+ new_reversed = void_list_node;
+ }
+ }
+ else
+ new_reversed = NULL;
+
+ /* Use copy_node to preserve as much as possible from original type
+ (debug info, attribute lists etc.)
+ Exception is METHOD_TYPEs which must have THIS argument and when we are
+ asked to remove it, we need to build new FUNCTION_TYPE instead. */
+ tree new_type = NULL;
+ if (m_method2func)
+ {
+ new_type
+ = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type),
+ new_reversed));
+ TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type);
+ DECL_VINDEX (m_fndecl) = NULL_TREE;
+ }
+ else
{
- struct ipa_parm_adjustment *n = &inner[i];
+ new_type = build_distinct_type_copy (orig_type);
+ TYPE_ARG_TYPES (new_type) = new_reversed;
+ }
- if (n->op == IPA_PARM_OP_REMOVE)
- adjustments.quick_push (*n);
+ /* When signature changes, we need to clear builtin info. */
+ if (DECL_BUILT_IN (m_fndecl))
+ {
+ DECL_BUILT_IN_CLASS (m_fndecl) = NOT_BUILT_IN;
+ DECL_FUNCTION_CODE (m_fndecl) = (enum built_in_function) 0;
}
- tmp.release ();
- return adjustments;
+ TREE_TYPE (m_fndecl) = new_type;
+ DECL_VIRTUAL_P (m_fndecl) = 0;
+ DECL_LANG_SPECIFIC (m_fndecl) = NULL;
}
/* If T is an SSA_NAME, return NULL if it is not a default def or
@@ -606,162 +661,460 @@ get_ssa_base_param (tree t, bool ignore_default_def)
return t;
}
-/* Given an expression, return an adjustment entry specifying the
- transformation to be done on EXPR. If no suitable adjustment entry
- was found, returns NULL.
+/* Given BASE and UNIT_OFFSET, find the corresponding record among replacement
+ structures. */
- If IGNORE_DEFAULT_DEF is set, consider SSA_NAMEs which are not a
- default def, otherwise bail on them.
-
- If CONVERT is non-NULL, this function will set *CONVERT if the
- expression provided is a component reference. ADJUSTMENTS is the
- adjustments vector. */
-
-ipa_parm_adjustment *
-ipa_get_adjustment_candidate (tree **expr, bool *convert,
- ipa_parm_adjustment_vec adjustments,
- bool ignore_default_def)
+ipa_param_body_replacement *
+ipa_param_body_adjustments::lookup_replacement (tree base, unsigned unit_offset)
{
- if (TREE_CODE (**expr) == BIT_FIELD_REF
- || TREE_CODE (**expr) == IMAGPART_EXPR
- || TREE_CODE (**expr) == REALPART_EXPR)
+ unsigned int len = m_replacements.length ();
+ for (unsigned i = 0; i < len; i++)
{
- *expr = &TREE_OPERAND (**expr, 0);
- if (convert)
- *convert = true;
+ ipa_param_body_replacement *pbr = &m_replacements[i];
+
+ if (pbr->base == base
+ && (pbr->unit_offset == unit_offset))
+ return pbr;
}
+ return NULL;
+}
+
+/* Given an expression, return the structure describing how it should be
+ replaced if it accesses a part of a split parameter or NULL otherwise.
+
+ Do not free the result, it will be deallocated when the object is destroyed.
+
+ If IGNORE_DEFAULT_DEF is cleared, consider only SSA_NAMEs of PARM_DECLs
+ which are default definitions, if set, consider all SSA_NAMEs of
+ PARM_DECLs. */
+
+ipa_param_body_replacement *
+ipa_param_body_adjustments::get_expr_replacement (tree expr,
+ bool ignore_default_def)
+{
HOST_WIDE_INT offset, size, max_size;
bool reverse;
tree base
- = get_ref_base_and_extent (**expr, &offset, &size, &max_size, &reverse);
+ = get_ref_base_and_extent (expr, &offset, &size, &max_size, &reverse);
if (!base || size == -1 || max_size == -1)
return NULL;
+ if ((offset % BITS_PER_UNIT) != 0)
+ return NULL;
+
if (TREE_CODE (base) == MEM_REF)
{
offset += mem_ref_offset (base).to_short_addr () * BITS_PER_UNIT;
base = TREE_OPERAND (base, 0);
}
+ if (offset < 0 || (offset / BITS_PER_UNIT) > UINT_MAX)
+ return NULL;
+ unsigned unit_offset = offset / BITS_PER_UNIT;
+
base = get_ssa_base_param (base, ignore_default_def);
if (!base || TREE_CODE (base) != PARM_DECL)
return NULL;
- struct ipa_parm_adjustment *cand = NULL;
- unsigned int len = adjustments.length ();
- for (unsigned i = 0; i < len; i++)
- {
- struct ipa_parm_adjustment *adj = &adjustments[i];
+ return lookup_replacement (base, unit_offset);
+}
- if (adj->base == base
- && (adj->offset == offset || adj->op == IPA_PARM_OP_REMOVE))
- {
- cand = adj;
- break;
- }
+/* Given OLD_DECL, which is a PARM_DECL of a parameter that is being removed
+ (which includes it being split or replaced), return a new variable that
+ should be used for any SSA names that will remain in the function that
+ previously belonged to OLD_DECL. */
+
+tree
+ipa_param_body_adjustments::get_replacement_ssa_base (tree old_decl)
+{
+ unsigned *idx = m_removed_map.get (old_decl);
+ if (!idx)
+ return NULL;
+
+ tree repl;
+ if (TREE_CODE (m_removed_decls [*idx]) == PARM_DECL)
+ {
+ gcc_assert (m_removed_decls [*idx] == old_decl);
+ repl = copy_var_decl (old_decl, DECL_NAME (old_decl),
+ TREE_TYPE (old_decl));
+ m_removed_decls [*idx] = repl;
}
+ else
+ repl = m_removed_decls [*idx];
+ return repl;
+}
+
+/* If OLD_NAME, which is being defined by statement STMT, is an SSA_NAME of a
+ parameter which is to be removed because its value is not used, create a new
+ SSA_NAME relating to a replacement VAR_DECL, replace all uses of the
+ original with it and return it. If there is no need to re-map, return NULL.
+ ADJUSTMENTS is a pointer to a vector of IPA-SRA adjustments. */
- if (!cand || cand->op == IPA_PARM_OP_COPY || cand->op == IPA_PARM_OP_REMOVE)
+tree
+ipa_param_body_adjustments::replace_removed_params_ssa_names (tree old_name,
+ gimple *stmt)
+{
+ if (TREE_CODE (old_name) != SSA_NAME)
+ return NULL;
+
+ tree decl = SSA_NAME_VAR (old_name);
+ if (decl == NULL_TREE
+ || TREE_CODE (decl) != PARM_DECL)
return NULL;
- return cand;
+
+ tree repl = get_replacement_ssa_base (decl);
+ if (!repl)
+ return NULL;
+
+ tree new_name = make_ssa_name (repl, stmt);
+ SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_name)
+ = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (old_name);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "replacing an SSA name of a removed param ");
+ print_generic_expr (dump_file, old_name);
+ fprintf (dump_file, " with ");
+ print_generic_expr (dump_file, new_name);
+ fprintf (dump_file, "\n");
+ }
+
+ replace_uses_by (old_name, new_name);
+ return new_name;
}
-/* If the expression *EXPR should be replaced by a reduction of a parameter, do
- so. ADJUSTMENTS is a pointer to a vector of adjustments. CONVERT
- specifies whether the function should care about type incompatibility the
- current and new expressions. If it is false, the function will leave
- incompatibility issues to the caller. Return true iff the expression
- was modified. */
+/* If the expression *EXPR_P should be replaced by a reduction of a parameter,
+ do so. CONVERT specifies whether the function should care about type
+ incompatibility of the current and new expressions. If it is false, the
+ function will leave incompatibility issues to the caller, but it will be
+ overridden if BIT_FIELD_REF, IMAGPART_EXPR or REALPART_EXPR is encountered.
+ Return true iff the expression was modified. */
bool
-ipa_modify_expr (tree *expr, bool convert,
- ipa_parm_adjustment_vec adjustments)
+ipa_param_body_adjustments::modify_expr (tree *expr_p, bool convert)
{
- struct ipa_parm_adjustment *cand
- = ipa_get_adjustment_candidate (&expr, &convert, adjustments, false);
- if (!cand)
+ tree expr = *expr_p;
+
+ if (TREE_CODE (expr) == BIT_FIELD_REF
+ || TREE_CODE (expr) == IMAGPART_EXPR
+ || TREE_CODE (expr) == REALPART_EXPR)
+ {
+ expr_p = &TREE_OPERAND (expr, 0);
+ expr = *expr_p;
+ convert = true;
+ }
+
+ ipa_param_body_replacement *pbr = get_expr_replacement (expr, false);
+ if (!pbr)
return false;
- tree src;
- if (cand->by_ref)
+ tree repl;
+ if (pbr->by_ref)
{
- src = build_simple_mem_ref (cand->new_decl);
- REF_REVERSE_STORAGE_ORDER (src) = cand->reverse;
+ repl = build_simple_mem_ref (pbr->repl);
+ REF_REVERSE_STORAGE_ORDER (repl) = pbr->reverse;
}
else
- src = cand->new_decl;
+ repl = pbr->repl;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "About to replace expr ");
- print_generic_expr (dump_file, *expr);
+ print_generic_expr (dump_file, expr);
fprintf (dump_file, " with ");
- print_generic_expr (dump_file, src);
+ print_generic_expr (dump_file, repl);
fprintf (dump_file, "\n");
}
- if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type))
+ if (convert && !useless_type_conversion_p (TREE_TYPE (expr),
+ TREE_TYPE (repl)))
{
- tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src);
- *expr = vce;
+ tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (expr), repl);
+ *expr_p = vce;
}
else
- *expr = src;
+ *expr_p = repl;
return true;
}
-/* Dump the adjustments in the vector ADJUSTMENTS to dump_file in a human
- friendly way, assuming they are meant to be applied to FNDECL. */
+/* If the statement STMT contains any expressions that need to replaced with a
+ different one as noted by ADJUSTMENTS, do so. Handle any potential type
+ incompatibilities (GSI is used to accommodate conversion statements and must
+ point to the statement). Return true iff the statement was modified. */
-void
-ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments,
- tree fndecl)
+bool
+ipa_param_body_adjustments::modify_assignment (gimple *stmt,
+ gimple_stmt_iterator *gsi)
{
- int i, len = adjustments.length ();
- bool first = true;
- vec<tree> parms = ipa_get_vector_of_formal_parms (fndecl);
+ tree *lhs_p, *rhs_p;
+ bool any;
- fprintf (file, "IPA param adjustments: ");
- for (i = 0; i < len; i++)
- {
- struct ipa_parm_adjustment *adj;
- adj = &adjustments[i];
+ if (!gimple_assign_single_p (stmt))
+ return false;
- if (!first)
- fprintf (file, " ");
- else
- first = false;
+ rhs_p = gimple_assign_rhs1_ptr (stmt);
+ lhs_p = gimple_assign_lhs_ptr (stmt);
+
+ any = modify_expr (lhs_p, false);
+ any |= modify_expr (rhs_p, false);
+ if (any)
+ {
+ tree new_rhs = NULL_TREE;
- fprintf (file, "%i. base_index: %i - ", i, adj->base_index);
- print_generic_expr (file, parms[adj->base_index]);
- if (adj->base)
+ if (!useless_type_conversion_p (TREE_TYPE (*lhs_p), TREE_TYPE (*rhs_p)))
{
- fprintf (file, ", base: ");
- print_generic_expr (file, adj->base);
+ if (TREE_CODE (*rhs_p) == CONSTRUCTOR)
+ {
+ /* V_C_Es of constructors can cause trouble (PR 42714). */
+ if (is_gimple_reg_type (TREE_TYPE (*lhs_p)))
+ *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
+ else
+ *rhs_p = build_constructor (TREE_TYPE (*lhs_p),
+ NULL);
+ }
+ else
+ new_rhs = fold_build1_loc (gimple_location (stmt),
+ VIEW_CONVERT_EXPR, TREE_TYPE (*lhs_p),
+ *rhs_p);
}
- if (adj->new_decl)
+ else if (REFERENCE_CLASS_P (*rhs_p)
+ && is_gimple_reg_type (TREE_TYPE (*lhs_p))
+ && !is_gimple_reg (*lhs_p))
+ /* This can happen when an assignment in between two single field
+ structures is turned into an assignment in between two pointers to
+ scalars (PR 42237). */
+ new_rhs = *rhs_p;
+
+ if (new_rhs)
{
- fprintf (file, ", new_decl: ");
- print_generic_expr (file, adj->new_decl);
+ tree tmp = force_gimple_operand_gsi (gsi, new_rhs, true, NULL_TREE,
+ true, GSI_SAME_STMT);
+
+ gimple_assign_set_rhs_from_tree (gsi, tmp);
}
- if (adj->new_ssa_base)
+
+ return true;
+ }
+
+ return any;
+}
+
+/* Traverse body of the current function and perform the requested adjustments.
+ Return true iff the CFG has been changed. */
+
+bool
+ipa_param_body_adjustments::modify_cfun_body ()
+{
+ bool cfg_changed = false;
+ basic_block bb;
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- fprintf (file, ", new_ssa_base: ");
- print_generic_expr (file, adj->new_ssa_base);
+ gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
+ tree new_lhs, old_lhs = gimple_phi_result (phi);
+ new_lhs = replace_removed_params_ssa_names (old_lhs, phi);
+ if (new_lhs)
+ {
+ gimple_phi_set_result (phi, new_lhs);
+ release_ssa_name (old_lhs);
+ }
}
- if (adj->op == IPA_PARM_OP_COPY)
- fprintf (file, ", copy_param");
- else if (adj->op == IPA_PARM_OP_REMOVE)
- fprintf (file, ", remove_param");
- else
- fprintf (file, ", offset %li", (long) adj->offset);
- if (adj->by_ref)
- fprintf (file, ", by_ref");
- print_node_brief (file, ", type: ", adj->type, 0);
- fprintf (file, "\n");
+ gsi = gsi_start_bb (bb);
+ while (!gsi_end_p (gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ bool modified = false;
+ tree *t;
+
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_RETURN:
+ t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
+ if (*t != NULL_TREE)
+ modified |= modify_expr (t, true);
+ break;
+
+ case GIMPLE_ASSIGN:
+ modified |= modify_assignment (stmt, &gsi);
+ break;
+
+ case GIMPLE_CALL:
+ /* Operands must be processed before the lhs. */
+ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
+ {
+ t = gimple_call_arg_ptr (stmt, i);
+ modified |= modify_expr (t, true);
+ }
+
+ if (gimple_call_lhs (stmt))
+ {
+ t = gimple_call_lhs_ptr (stmt);
+ modified |= modify_expr (t, false);
+ }
+ break;
+
+ case GIMPLE_ASM:
+ {
+ gasm *asm_stmt = as_a <gasm *> (stmt);
+ for (unsigned i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
+ {
+ t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
+ modified |= modify_expr (t, true);
+ }
+ for (unsigned i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+ {
+ t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+ modified |= modify_expr (t, false);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ def_operand_p defp;
+ ssa_op_iter iter;
+ FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_DEF)
+ {
+ tree old_def = DEF_FROM_PTR (defp);
+ if (tree new_def = replace_removed_params_ssa_names (old_def,
+ stmt))
+ {
+ SET_DEF (defp, new_def);
+ release_ssa_name (old_def);
+ modified = true;
+ }
+ }
+
+ if (modified)
+ {
+ update_stmt (stmt);
+ if (maybe_clean_eh_stmt (stmt)
+ && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
+ cfg_changed = true;
+ }
+ gsi_next (&gsi);
+ }
}
- parms.release ();
+
+ return cfg_changed;
+}
+
+/* Call gimple_debug_bind_reset_value on all debug statements describing
+ gimple register parameters that are being removed or replaced. */
+
+void
+ipa_param_body_adjustments::reset_debug_stmts ()
+{
+ int i, len;
+ gimple_stmt_iterator *gsip = NULL, gsi;
+
+ if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)))
+ {
+ gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+ gsip = &gsi;
+ }
+ len = m_reset_debug_decls.length ();
+ for (i = 0; i < len; i++)
+ {
+ imm_use_iterator ui;
+ gimple *stmt;
+ gdebug *def_temp;
+ tree name, vexpr, copy = NULL_TREE;
+ use_operand_p use_p;
+ tree decl = m_reset_debug_decls[i];
+
+ gcc_checking_assert (is_gimple_reg (decl));
+ name = ssa_default_def (cfun, decl);
+ vexpr = NULL;
+ if (name)
+ FOR_EACH_IMM_USE_STMT (stmt, ui, name)
+ {
+ if (gimple_clobber_p (stmt))
+ {
+ gimple_stmt_iterator cgsi = gsi_for_stmt (stmt);
+ unlink_stmt_vdef (stmt);
+ gsi_remove (&cgsi, true);
+ release_defs (stmt);
+ continue;
+ }
+ /* All other users must have been removed by function body
+ modification. */
+ gcc_assert (is_gimple_debug (stmt));
+ if (vexpr == NULL && gsip != NULL)
+ {
+ vexpr = make_node (DEBUG_EXPR_DECL);
+ def_temp = gimple_build_debug_source_bind (vexpr, decl, NULL);
+ DECL_ARTIFICIAL (vexpr) = 1;
+ TREE_TYPE (vexpr) = TREE_TYPE (name);
+ SET_DECL_MODE (vexpr, DECL_MODE (decl));
+ gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
+ }
+ if (vexpr)
+ {
+ FOR_EACH_IMM_USE_ON_STMT (use_p, ui)
+ SET_USE (use_p, vexpr);
+ }
+ else
+ gimple_debug_bind_reset_value (stmt);
+ update_stmt (stmt);
+ }
+ /* Create a VAR_DECL for debug info purposes. */
+ if (!DECL_IGNORED_P (decl))
+ {
+ copy = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
+ VAR_DECL, DECL_NAME (decl),
+ TREE_TYPE (decl));
+ if (DECL_PT_UID_SET_P (decl))
+ SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
+ TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
+ TREE_READONLY (copy) = TREE_READONLY (decl);
+ TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
+ DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (decl);
+ DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (decl);
+ DECL_IGNORED_P (copy) = DECL_IGNORED_P (decl);
+ DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (decl);
+ DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
+ SET_DECL_RTL (copy, 0);
+ TREE_USED (copy) = 1;
+ DECL_CONTEXT (copy) = current_function_decl;
+ add_local_decl (cfun, copy);
+ DECL_CHAIN (copy) =
+ BLOCK_VARS (DECL_INITIAL (current_function_decl));
+ BLOCK_VARS (DECL_INITIAL (current_function_decl)) = copy;
+ }
+ if (gsip != NULL && copy && target_for_debug_bind (decl))
+ {
+ gcc_assert (TREE_CODE (decl) == PARM_DECL);
+ if (vexpr)
+ def_temp = gimple_build_debug_bind (copy, vexpr, NULL);
+ else
+ def_temp = gimple_build_debug_source_bind (copy, decl,
+ NULL);
+ gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
+ }
+ }
+}
+
+/* Perform all necessary body changes to change signature, body and debug info
+ of fun according to adjustments passed at construction. Return true if CFG
+ was changed in any way. */
+
+bool
+ipa_param_body_adjustments::perform_cfun_body_modifications ()
+{
+ bool cfg_changed;
+ modify_formal_parameters ();
+ cfg_changed = modify_cfun_body ();
+ reset_debug_stmts ();
+
+ return cfg_changed;
}
@@ -21,100 +21,157 @@ along with GCC; see the file COPYING3. If not see
#ifndef IPA_PARAM_MANIPULATION_H
#define IPA_PARAM_MANIPULATION_H
+/* Indices into ipa_param_prefixes to identify a human-readable prefix for newly
+ synthesized parameters. Keep in sync with the array. */
+#define IPA_PARAM_PREFIX_SYNTH 0
+#define IPA_PARAM_PREFIX_ISRA 1
+#define IPA_PARAM_PREFIX_SIMD 2
+#define IPA_PARAM_PREFIX_MASK 3
+
+/* We do not support manipulating functions with more than
+ 1<<IPA_PARAM_MAX_INDEX_BITS parameters. */
+#define IPA_PARAM_MAX_INDEX_BITS 16
+
/* Operation to be performed for the parameter in ipa_parm_adjustment
below. */
-enum ipa_parm_op {
- IPA_PARM_OP_NONE,
-
- /* This describes a brand new parameter.
- The field `type' should be set to the new type, `arg_prefix'
- should be set to the string prefix for the new DECL_NAME, and
- `new_decl' will ultimately hold the newly created argument. */
- IPA_PARM_OP_NEW,
+enum ipa_parm_op {
+ /* Do not use or you will trigger an assert. */
+ IPA_PARAM_OP_UNDEFINED,
/* This new parameter is an unmodified parameter at index base_index. */
- IPA_PARM_OP_COPY,
+ IPA_PARAM_OP_COPY,
+
+ /* This describes a brand new parameter. If it somehow relates to any
+ original parameters, the user needs to manage the transition itself. */
+ IPA_PARAM_OP_NEW,
- /* This adjustment describes a parameter that is about to be removed
- completely. Most users will probably need to book keep those so that they
- don't leave behinfd any non default def ssa names belonging to them. */
- IPA_PARM_OP_REMOVE
+ /* Split parameter as indicated by fields base_index, offset, type and
+ by_ref. */
+ IPA_PARAM_OP_SPLIT
};
-/* Structure to describe transformations of formal parameters and actual
- arguments. Each instance describes one new parameter and they are meant to
- be stored in a vector. Additionally, most users will probably want to store
- adjustments about parameters that are being removed altogether so that SSA
- names belonging to them can be replaced by SSA names of an artificial
- variable. */
-struct ipa_parm_adjustment
-{
- /* The original PARM_DECL itself, helpful for processing of the body of the
- function itself. Intended for traversing function bodies.
- ipa_modify_formal_parameters, ipa_modify_call_arguments and
- ipa_combine_adjustments ignore this and use base_index.
- ipa_modify_formal_parameters actually sets this. */
- tree base;
+/* Structure that describes one parameter of a function after transformation.
+ Omitted parameters will be removed. */
+struct GTY(()) ipa_adjusted_param
+{
/* Type of the new parameter. However, if by_ref is true, the real type will
- be a pointer to this type. */
+ be a pointer to this type. Required for all operations except
+ IPA_PARM_OP_COPY when the original type will be preserved. */
tree type;
- /* Alias refrerence type to be used in MEM_REFs when adjusting caller
- arguments. */
+ /* Alias reference type to be used in MEM_REFs when adjusting caller
+ arguments. Required for IPA_PARM_OP_SPLIT operation. */
tree alias_ptr_type;
- /* The new declaration when creating/replacing a parameter. Created
- by ipa_modify_formal_parameters, useful for functions modifying
- the body accordingly. For brand new arguments, this is the newly
- created argument. */
- tree new_decl;
-
- /* New declaration of a substitute variable that we may use to replace all
- non-default-def ssa names when a parm decl is going away. */
- tree new_ssa_base;
-
- /* If non-NULL and the original parameter is to be removed (copy_param below
- is NULL), this is going to be its nonlocalized vars value. */
- tree nonlocal_value;
-
- /* This holds the prefix to be used for the new DECL_NAME. */
- const char *arg_prefix;
-
/* Offset into the original parameter (for the cases when the new parameter
- is a component of an original one). */
- HOST_WIDE_INT offset;
+ is a component of an original one). Required for IPA_PARM_OP_SPLIT
+ operation. */
+ unsigned unit_offset;
+
+ /* Specify the operation, if any, to be performed on the parameter. */
+ enum ipa_parm_op op : 2;
- /* Zero based index of the original parameter this one is based on. */
- int base_index;
+ /* Zero based index of the original parameter this one is based on. Required
+ for IPA_PARAM_OP_COPY and IPA_PARAM_OP_SPLIT, users of IPA_PARAM_OP_NEW
+ only need to specify it if they use replacement lookup provided by
+ ipa_param_body_adjustments. */
+ unsigned base_index : IPA_PARAM_MAX_INDEX_BITS;
- /* Whether this parameter is a new parameter, a copy of an old one,
- or one about to be removed. */
- enum ipa_parm_op op;
+ /* Index into ipa_param_prefixes specifying a prefix to be used with
+ DECL_NAMEs of newly synthesized parameters. */
+ unsigned param_prefix_index : 2;
/* Storage order of the original parameter (for the cases when the new
parameter is a component of an original one). */
unsigned reverse : 1;
- /* The parameter is to be passed by reference. */
+ /* Set when the parameter is to be passed by reference. */
unsigned by_ref : 1;
+
+ /* A bit free for the user. */
+ unsigned user_flag : 1;
};
-typedef vec<ipa_parm_adjustment> ipa_parm_adjustment_vec;
+void ipa_dump_adjusted_parameters (FILE *f,
+ vec<ipa_adjusted_param, va_gc> *adj_params);
+
+/* Class used to record planned modifications to parameters of a function and
+ also to perform necessary modifications at the caller side at the gimple
+ level. */
+
+class GTY(()) ipa_param_adjustments
+{
+public:
+ ipa_param_adjustments (vec<ipa_adjusted_param, va_gc> *new_params,
+ tree fndecl);
+ ipa_param_adjustments (vec<ipa_adjusted_param, va_gc> *new_params,
+ vec<tree> *cur_params = NULL);
+
+ gcall *modify_call_arguments (gcall *stmt, tree callee_decl);
+ void modify_call_arguments (struct cgraph_edge *cs);
+
+ vec<ipa_adjusted_param, va_gc> *m_adj_params;
+ vec<tree, va_gc> *m_vanishing_decls;
+ vec<unsigned, va_gc> *m_vanishing_indices;
+private:
+ ipa_param_adjustments () {}
+
+ void init (vec<tree> *cur_params);
+};
+
+/* Structure used to map expressions accessing split or replaced parameters to
+ new PARM_DECLs. TODO: Even though there usually be only few, but should we
+ use a hash? */
+
+struct ipa_param_body_replacement
+{
+ tree base, repl;
+ unsigned unit_offset;
+ bool by_ref;
+ bool reverse;
+};
+
+
+/* Class used when actually performing adjustments to formal parameters of
+ a function to map accesses that need to be replaced to replacements. */
+
+class ipa_param_body_adjustments
+{
+public:
+ ipa_param_body_adjustments (vec<ipa_adjusted_param, va_gc> *adj_params,
+ tree fndecl);
+
+ bool perform_cfun_body_modifications ();
+ void modify_formal_parameters ();
+ void register_replacement (ipa_adjusted_param *apm, tree replacement);
+ ipa_param_body_replacement *lookup_replacement (tree base,
+ unsigned unit_offset);
+ ipa_param_body_replacement *get_expr_replacement (tree expr,
+ bool ignore_default_def);
+ tree get_replacement_ssa_base (tree old_decl);
+
+ vec<ipa_adjusted_param, va_gc> *m_adj_params;
+private:
+ tree replace_removed_params_ssa_names (tree old_name, gimple *stmt);
+ bool modify_expr (tree *expr_p, bool convert);
+ bool modify_assignment (gimple *stmt, gimple_stmt_iterator *gsi);
+ bool modify_cfun_body ();
+ void reset_debug_stmts ();
+
+ tree m_fndecl;
+ auto_vec<tree, 16> m_oparms;
+ auto_vec<ipa_param_body_replacement, 16> m_replacements;
+ auto_vec<tree, 16> m_new_decls;
+ auto_vec<tree, 16> m_new_types;
+ auto_vec<tree, 16> m_reset_debug_decls;
+ auto_vec<tree, 16> m_removed_decls;
+ hash_map<tree, unsigned> m_removed_map;
+ bool m_method2func;
+};
vec<tree> ipa_get_vector_of_formal_parms (tree fndecl);
vec<tree> ipa_get_vector_of_formal_parm_types (tree fntype);
-void ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec);
-void ipa_modify_call_arguments (struct cgraph_edge *, gcall *,
- ipa_parm_adjustment_vec);
-ipa_parm_adjustment_vec ipa_combine_adjustments (ipa_parm_adjustment_vec,
- ipa_parm_adjustment_vec);
-void ipa_dump_param_adjustments (FILE *, ipa_parm_adjustment_vec, tree);
-
-bool ipa_modify_expr (tree *, bool, ipa_parm_adjustment_vec);
-ipa_parm_adjustment *ipa_get_adjustment_candidate (tree **, bool *,
- ipa_parm_adjustment_vec,
- bool);
#endif /* IPA_PARAM_MANIPULATION_H */
@@ -558,28 +558,27 @@ create_tmp_simd_array (const char *prefix, tree type, int simdlen)
Returns an adjustment vector that will be filled describing how the
argument types will be adjusted. */
-static ipa_parm_adjustment_vec
+static ipa_param_body_adjustments *
simd_clone_adjust_argument_types (struct cgraph_node *node)
{
vec<tree> args;
- ipa_parm_adjustment_vec adjustments;
if (node->definition)
args = ipa_get_vector_of_formal_parms (node->decl);
else
args = simd_clone_vector_of_formal_parm_types (node->decl);
- adjustments.create (args.length ());
+ vec<ipa_adjusted_param, va_gc> *new_params = NULL;
+ vec_safe_reserve_exact (new_params, args.length ());
unsigned i, j, veclen;
- struct ipa_parm_adjustment adj;
struct cgraph_simd_clone *sc = node->simdclone;
for (i = 0; i < sc->nargs; ++i)
{
- memset (&adj, 0, sizeof (adj));
+ ipa_adjusted_param apm;
+ memset (&apm, 0, sizeof (apm));
tree parm = args[i];
tree parm_type = node->definition ? TREE_TYPE (parm) : parm;
- adj.base_index = i;
- adj.base = parm;
+ apm.base_index = i;
sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
sc->args[i].orig_type = parm_type;
@@ -588,7 +587,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
{
default:
/* No adjustment necessary for scalar arguments. */
- adj.op = IPA_PARM_OP_COPY;
+ apm.op = IPA_PARAM_OP_COPY;
break;
case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
@@ -597,7 +596,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
= create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)),
TREE_TYPE (parm_type),
sc->simdlen);
- adj.op = IPA_PARM_OP_COPY;
+ apm.op = IPA_PARAM_OP_COPY;
break;
case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
@@ -609,22 +608,24 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type));
if (veclen > sc->simdlen)
veclen = sc->simdlen;
- adj.arg_prefix = "simd";
+ apm.op = IPA_PARAM_OP_NEW;
+ apm.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
if (POINTER_TYPE_P (parm_type))
- adj.type = build_vector_type (pointer_sized_int_node, veclen);
+ apm.type = build_vector_type (pointer_sized_int_node, veclen);
else
- adj.type = build_vector_type (parm_type, veclen);
- sc->args[i].vector_type = adj.type;
+ apm.type = build_vector_type (parm_type, veclen);
+ sc->args[i].vector_type = apm.type;
for (j = veclen; j < sc->simdlen; j += veclen)
{
- adjustments.safe_push (adj);
+ vec_safe_push (new_params, apm);
if (j == veclen)
{
- memset (&adj, 0, sizeof (adj));
- adj.op = IPA_PARM_OP_NEW;
- adj.arg_prefix = "simd";
- adj.base_index = i;
- adj.type = sc->args[i].vector_type;
+ memset (&apm, 0, sizeof (apm));
+ apm.op = IPA_PARAM_OP_NEW;
+ apm.user_flag = 1;
+ apm.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
+ apm.base_index = i;
+ apm.type = sc->args[i].vector_type;
}
}
@@ -634,18 +635,19 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
? IDENTIFIER_POINTER (DECL_NAME (parm))
: NULL, parm_type, sc->simdlen);
}
- adjustments.safe_push (adj);
+ vec_safe_push (new_params, apm);
}
if (sc->inbranch)
{
tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
+ ipa_adjusted_param apm;
+ memset (&apm, 0, sizeof (apm));
+ apm.op = IPA_PARAM_OP_NEW;
+ apm.user_flag = 1;
+ apm.param_prefix_index = IPA_PARAM_PREFIX_MASK;
- memset (&adj, 0, sizeof (adj));
- adj.op = IPA_PARM_OP_NEW;
- adj.arg_prefix = "mask";
-
- adj.base_index = i;
+ apm.base_index = i;
if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
veclen = sc->vecsize_int;
else
@@ -654,16 +656,16 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
if (veclen > sc->simdlen)
veclen = sc->simdlen;
if (sc->mask_mode != VOIDmode)
- adj.type
+ apm.type
= lang_hooks.types.type_for_mode (sc->mask_mode, 1);
else if (POINTER_TYPE_P (base_type))
- adj.type = build_vector_type (pointer_sized_int_node, veclen);
+ apm.type = build_vector_type (pointer_sized_int_node, veclen);
else
- adj.type = build_vector_type (base_type, veclen);
- adjustments.safe_push (adj);
+ apm.type = build_vector_type (base_type, veclen);
+ vec_safe_push (new_params, apm);
for (j = veclen; j < sc->simdlen; j += veclen)
- adjustments.safe_push (adj);
+ vec_safe_push (new_params, apm);
/* We have previously allocated one extra entry for the mask. Use
it and fill it. */
@@ -679,7 +681,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
= create_tmp_simd_array ("mask", base_type, sc->simdlen);
else if (veclen < sc->simdlen)
sc->args[i].simd_array
- = create_tmp_simd_array ("mask", adj.type, sc->simdlen / veclen);
+ = create_tmp_simd_array ("mask", apm.type, sc->simdlen / veclen);
else
sc->args[i].simd_array = NULL_TREE;
}
@@ -688,7 +690,14 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
}
if (node->definition)
- ipa_modify_formal_parameters (node->decl, adjustments);
+ {
+ args.release ();
+ ipa_param_body_adjustments *adjustments
+ = new ipa_param_body_adjustments (new_params, node->decl);
+
+ adjustments->modify_formal_parameters ();
+ return adjustments;
+ }
else
{
tree new_arg_types = NULL_TREE, new_reversed;
@@ -697,15 +706,15 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
last_parm_void = true;
gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
- j = adjustments.length ();
+ j = vec_safe_length (new_params);
for (i = 0; i < j; i++)
{
- struct ipa_parm_adjustment *adj = &adjustments[i];
+ struct ipa_adjusted_param *apm = &(*new_params)[i];
tree ptype;
- if (adj->op == IPA_PARM_OP_COPY)
- ptype = args[adj->base_index];
+ if (apm->op == IPA_PARAM_OP_COPY)
+ ptype = args[apm->base_index];
else
- ptype = adj->type;
+ ptype = apm->type;
new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types);
}
new_reversed = nreverse (new_arg_types);
@@ -720,11 +729,9 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
tree new_type = build_distinct_type_copy (TREE_TYPE (node->decl));
TYPE_ARG_TYPES (new_type) = new_reversed;
TREE_TYPE (node->decl) = new_type;
-
- adjustments.release ();
+ args.release ();
+ return NULL;
}
- args.release ();
- return adjustments;
}
/* Initialize and copy the function arguments in NODE to their
@@ -733,7 +740,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
static gimple_seq
simd_clone_init_simd_arrays (struct cgraph_node *node,
- ipa_parm_adjustment_vec adjustments)
+ ipa_param_body_adjustments *adjustments)
{
gimple_seq seq = NULL;
unsigned i = 0, j = 0, k;
@@ -742,7 +749,7 @@ simd_clone_init_simd_arrays (struct cgraph_node *node,
arg;
arg = DECL_CHAIN (arg), i++, j++)
{
- if (adjustments[j].op == IPA_PARM_OP_COPY
+ if ((*adjustments->m_adj_params)[j].op == IPA_PARAM_OP_COPY
|| POINTER_TYPE_P (TREE_TYPE (arg)))
continue;
@@ -807,7 +814,7 @@ simd_clone_init_simd_arrays (struct cgraph_node *node,
/* Callback info for ipa_simd_modify_stmt_ops below. */
struct modify_stmt_info {
- ipa_parm_adjustment_vec adjustments;
+ ipa_param_body_adjustments *adjustments;
gimple *stmt;
/* True if the parent statement was modified by
ipa_simd_modify_stmt_ops. */
@@ -827,9 +834,15 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
tree *orig_tp = tp;
if (TREE_CODE (*tp) == ADDR_EXPR)
tp = &TREE_OPERAND (*tp, 0);
- struct ipa_parm_adjustment *cand = NULL;
+
+ if (TREE_CODE (*tp) == BIT_FIELD_REF
+ || TREE_CODE (*tp) == IMAGPART_EXPR
+ || TREE_CODE (*tp) == REALPART_EXPR)
+ tp = &TREE_OPERAND (*tp, 0);
+
+ ipa_param_body_replacement *pbr = NULL;
if (TREE_CODE (*tp) == PARM_DECL)
- cand = ipa_get_adjustment_candidate (&tp, NULL, info->adjustments, true);
+ pbr = info->adjustments->get_expr_replacement (*tp, true);
else
{
if (TYPE_P (*tp))
@@ -837,8 +850,8 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
}
tree repl = NULL_TREE;
- if (cand)
- repl = unshare_expr (cand->new_decl);
+ if (pbr)
+ repl = unshare_expr (pbr->repl);
else
{
if (tp != orig_tp)
@@ -904,70 +917,57 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
static void
ipa_simd_modify_function_body (struct cgraph_node *node,
- ipa_parm_adjustment_vec adjustments,
+ ipa_param_body_adjustments *adjustments,
tree retval_array, tree iter)
{
basic_block bb;
- unsigned int i, j, l;
+ unsigned int i, j;
+
- /* Re-use the adjustments array, but this time use it to replace
- every function argument use to an offset into the corresponding
- simd_array. */
+ /* Register replacements for every function argument use to an offset into
+ the corresponding simd_array. */
for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
{
- if (!node->simdclone->args[i].vector_arg)
+ if (!node->simdclone->args[i].vector_arg
+ || (*adjustments->m_adj_params)[j].user_flag)
continue;
tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
- adjustments[j].new_decl
- = build4 (ARRAY_REF,
- basetype,
- node->simdclone->args[i].simd_array,
- iter,
- NULL_TREE, NULL_TREE);
- if (adjustments[j].op == IPA_PARM_OP_NONE
- && TYPE_VECTOR_SUBPARTS (vectype) < node->simdclone->simdlen)
+ tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array,
+ iter, NULL_TREE, NULL_TREE);
+ adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r);
+
+ if (TYPE_VECTOR_SUBPARTS (vectype) < node->simdclone->simdlen)
j += node->simdclone->simdlen / TYPE_VECTOR_SUBPARTS (vectype) - 1;
}
- l = adjustments.length ();
tree name;
-
FOR_EACH_SSA_NAME (i, name, cfun)
{
+ tree base_var;
if (SSA_NAME_VAR (name)
- && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL)
+ && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
+ && (base_var
+ = adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name))))
{
- for (j = 0; j < l; j++)
- if (SSA_NAME_VAR (name) == adjustments[j].base
- && adjustments[j].new_decl)
- {
- tree base_var;
- if (adjustments[j].new_ssa_base == NULL_TREE)
- {
- base_var
- = copy_var_decl (adjustments[j].base,
- DECL_NAME (adjustments[j].base),
- TREE_TYPE (adjustments[j].base));
- adjustments[j].new_ssa_base = base_var;
- }
- else
- base_var = adjustments[j].new_ssa_base;
- if (SSA_NAME_IS_DEFAULT_DEF (name))
- {
- bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
- gimple_stmt_iterator gsi = gsi_after_labels (bb);
- tree new_decl = unshare_expr (adjustments[j].new_decl);
- set_ssa_default_def (cfun, adjustments[j].base, NULL_TREE);
- SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
- SSA_NAME_IS_DEFAULT_DEF (name) = 0;
- gimple *stmt = gimple_build_assign (name, new_decl);
- gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
- }
- else
- SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
- }
+ if (SSA_NAME_IS_DEFAULT_DEF (name))
+ {
+ tree old_decl = SSA_NAME_VAR (name);
+ bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_stmt_iterator gsi = gsi_after_labels (bb);
+ ipa_param_body_replacement *pbr
+ = adjustments->lookup_replacement (old_decl, 0);
+ gcc_checking_assert (pbr && !pbr->by_ref && !pbr->reverse);
+ tree repl = unshare_expr (pbr->repl);
+ set_ssa_default_def (cfun, old_decl, NULL_TREE);
+ SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
+ SSA_NAME_IS_DEFAULT_DEF (name) = 0;
+ gimple *stmt = gimple_build_assign (name, repl);
+ gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
+ }
+ else
+ SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
}
}
@@ -1097,8 +1097,9 @@ simd_clone_adjust (struct cgraph_node *node)
targetm.simd_clone.adjust (node);
tree retval = simd_clone_adjust_return_type (node);
- ipa_parm_adjustment_vec adjustments
+ ipa_param_body_adjustments *adjustments
= simd_clone_adjust_argument_types (node);
+ gcc_assert (adjustments);
push_gimplify_context ();
@@ -1110,7 +1111,7 @@ simd_clone_adjust (struct cgraph_node *node)
tree iter1 = make_ssa_name (iter);
tree iter2 = NULL_TREE;
ipa_simd_modify_function_body (node, adjustments, retval, iter1);
- adjustments.release ();
+ delete adjustments;
/* Initialize the iteration variable. */
basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
@@ -34,5 +34,6 @@ void caller (void)
return;
}
-/* { dg-final { scan-tree-dump "base: z, remove_param" "eipa_sra" } } */
-/* { dg-final { scan-tree-dump "base: calf, remove_param" "eipa_sra" } } */
+/* { dg-final { scan-tree-dump "ox.isra" "eipa_sra" } } */
+/* { dg-final { scan-tree-dump-not "\\nox.isra\[^;)]*z" "eipa_sra" } } */
+/* { dg-final { scan-tree-dump-not "\\nox.isra\[^;)]*calf" "eipa_sra" } } */
@@ -4697,84 +4697,81 @@ get_param_index (tree base, vec<tree> parms)
gcc_unreachable ();
}
-/* Convert the decisions made at the representative level into compact
- parameter adjustments. REPRESENTATIVES are pointers to first
- representatives of each param accesses, ADJUSTMENTS_COUNT is the expected
- final number of adjustments. */
+/* Convert the decisions made at the representative level into description of
+ new arguments for parameter manipulation. REPRESENTATIVES are pointers to
+ first representatives of each param accesses, EXPECTED_COUNT is the expected
+ final number of new number of parameters. */
-static ipa_parm_adjustment_vec
+static vec<ipa_adjusted_param, va_gc> *
turn_representatives_into_adjustments (vec<access_p> representatives,
- int adjustments_count)
+ int expected_count)
{
vec<tree> parms;
- ipa_parm_adjustment_vec adjustments;
+ vec<ipa_adjusted_param, va_gc> *adj_params = NULL;
tree parm;
int i;
- gcc_assert (adjustments_count > 0);
parms = ipa_get_vector_of_formal_parms (current_function_decl);
- adjustments.create (adjustments_count);
+ vec_safe_reserve_exact (adj_params, expected_count);
parm = DECL_ARGUMENTS (current_function_decl);
for (i = 0; i < func_param_count; i++, parm = DECL_CHAIN (parm))
{
struct access *repr = representatives[i];
- if (!repr || no_accesses_p (repr))
+ if (!repr)
{
- struct ipa_parm_adjustment adj;
+ struct ipa_adjusted_param apm;
- memset (&adj, 0, sizeof (adj));
- adj.base_index = get_param_index (parm, parms);
- adj.base = parm;
- if (!repr)
- adj.op = IPA_PARM_OP_COPY;
- else
- adj.op = IPA_PARM_OP_REMOVE;
- adj.arg_prefix = "ISRA";
- adjustments.quick_push (adj);
+ memset (&apm, 0, sizeof (apm));
+ apm.op = IPA_PARAM_OP_COPY;
+ apm.base_index = get_param_index (parm, parms);
+ apm.param_prefix_index = IPA_PARAM_PREFIX_ISRA;
+ adj_params->quick_push (apm);
}
+ else if (no_accesses_p (repr))
+ continue;
else
{
- struct ipa_parm_adjustment adj;
int index = get_param_index (parm, parms);
for (; repr; repr = repr->next_grp)
{
- memset (&adj, 0, sizeof (adj));
+ struct ipa_adjusted_param apm;
+ memset (&apm, 0, sizeof (apm));
gcc_assert (repr->base == parm);
- adj.base_index = index;
- adj.base = repr->base;
- adj.type = repr->type;
- adj.alias_ptr_type = reference_alias_ptr_type (repr->expr);
- adj.offset = repr->offset;
- adj.reverse = repr->reverse;
- adj.by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base))
+ apm.op = IPA_PARAM_OP_SPLIT;
+ apm.base_index = index;
+ apm.type = repr->type;
+ apm.alias_ptr_type = reference_alias_ptr_type (repr->expr);
+ apm.unit_offset = repr->offset / BITS_PER_UNIT;
+ apm.reverse = repr->reverse;
+ apm.by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base))
&& (repr->grp_maybe_modified
|| repr->grp_not_necessarilly_dereferenced));
- adj.arg_prefix = "ISRA";
- adjustments.quick_push (adj);
+ apm.param_prefix_index = IPA_PARAM_PREFIX_ISRA;
+ adj_params->quick_push (apm);
}
}
}
parms.release ();
- return adjustments;
+ return adj_params;
}
/* Analyze the collected accesses and produce a plan what to do with the
- parameters in the form of adjustments, NULL meaning nothing. */
+ parameters in the form of a vector of adjusted parameters and store it to
+ ADJ_PARAMS_P or return NULL if no adjustments are to be made. */
-static ipa_parm_adjustment_vec
-analyze_all_param_acesses (void)
+static bool
+analyze_all_param_acesses (vec<ipa_adjusted_param, va_gc> **adj_params_p)
{
enum ipa_splicing_result repr_state;
bool proceed = false;
- int i, adjustments_count = 0;
+ int i, expected_count = 0;
vec<access_p> representatives;
- ipa_parm_adjustment_vec adjustments;
repr_state = splice_all_param_accesses (representatives);
if (repr_state == NO_GOOD_ACCESS)
- return ipa_parm_adjustment_vec ();
+ return NULL;;
/* If there are any parameters passed by reference which are not modified
directly, we need to check whether they can be modified indirectly. */
@@ -4792,7 +4789,7 @@ analyze_all_param_acesses (void)
{
if (repr->grp_scalar_ptr)
{
- adjustments_count++;
+ expected_count++;
if (repr->grp_not_necessarilly_dereferenced
|| repr->grp_maybe_modified)
representatives[i] = NULL;
@@ -4809,11 +4806,11 @@ analyze_all_param_acesses (void)
if (new_components == 0)
{
representatives[i] = NULL;
- adjustments_count++;
+ expected_count++;
}
else
{
- adjustments_count += new_components;
+ expected_count += new_components;
sra_stats.aggregate_params_reduced++;
sra_stats.param_reductions_created += new_components;
proceed = true;
@@ -4827,7 +4824,8 @@ analyze_all_param_acesses (void)
proceed = true;
sra_stats.deleted_unused_parameters++;
}
- adjustments_count++;
+ else
+ expected_count++;
}
}
@@ -4835,372 +4833,10 @@ analyze_all_param_acesses (void)
fprintf (dump_file, "NOT proceeding to change params.\n");
if (proceed)
- adjustments = turn_representatives_into_adjustments (representatives,
- adjustments_count);
- else
- adjustments = ipa_parm_adjustment_vec ();
-
+ *adj_params_p = turn_representatives_into_adjustments (representatives,
+ expected_count);
representatives.release ();
- return adjustments;
-}
-
-/* If a parameter replacement identified by ADJ does not yet exist in the form
- of declaration, create it and record it, otherwise return the previously
- created one. */
-
-static tree
-get_replaced_param_substitute (struct ipa_parm_adjustment *adj)
-{
- tree repl;
- if (!adj->new_ssa_base)
- {
- char *pretty_name = make_fancy_name (adj->base);
-
- repl = create_tmp_reg (TREE_TYPE (adj->base), "ISR");
- DECL_NAME (repl) = get_identifier (pretty_name);
- DECL_NAMELESS (repl) = 1;
- obstack_free (&name_obstack, pretty_name);
-
- adj->new_ssa_base = repl;
- }
- else
- repl = adj->new_ssa_base;
- return repl;
-}
-
-/* Find the first adjustment for a particular parameter BASE in a vector of
- ADJUSTMENTS which is not a copy_param. Return NULL if there is no such
- adjustment. */
-
-static struct ipa_parm_adjustment *
-get_adjustment_for_base (ipa_parm_adjustment_vec adjustments, tree base)
-{
- int i, len;
-
- len = adjustments.length ();
- for (i = 0; i < len; i++)
- {
- struct ipa_parm_adjustment *adj;
-
- adj = &adjustments[i];
- if (adj->op != IPA_PARM_OP_COPY && adj->base == base)
- return adj;
- }
-
- return NULL;
-}
-
-/* If OLD_NAME, which is being defined by statement STMT, is an SSA_NAME of a
- parameter which is to be removed because its value is not used, create a new
- SSA_NAME relating to a replacement VAR_DECL, replace all uses of the
- original with it and return it. If there is no need to re-map, return NULL.
- ADJUSTMENTS is a pointer to a vector of IPA-SRA adjustments. */
-
-static tree
-replace_removed_params_ssa_names (tree old_name, gimple *stmt,
- ipa_parm_adjustment_vec adjustments)
-{
- struct ipa_parm_adjustment *adj;
- tree decl, repl, new_name;
-
- if (TREE_CODE (old_name) != SSA_NAME)
- return NULL;
-
- decl = SSA_NAME_VAR (old_name);
- if (decl == NULL_TREE
- || TREE_CODE (decl) != PARM_DECL)
- return NULL;
-
- adj = get_adjustment_for_base (adjustments, decl);
- if (!adj)
- return NULL;
-
- repl = get_replaced_param_substitute (adj);
- new_name = make_ssa_name (repl, stmt);
- SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_name)
- = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (old_name);
-
- if (dump_file)
- {
- fprintf (dump_file, "replacing an SSA name of a removed param ");
- print_generic_expr (dump_file, old_name);
- fprintf (dump_file, " with ");
- print_generic_expr (dump_file, new_name);
- fprintf (dump_file, "\n");
- }
-
- replace_uses_by (old_name, new_name);
- return new_name;
-}
-
-/* If the statement STMT contains any expressions that need to replaced with a
- different one as noted by ADJUSTMENTS, do so. Handle any potential type
- incompatibilities (GSI is used to accommodate conversion statements and must
- point to the statement). Return true iff the statement was modified. */
-
-static bool
-sra_ipa_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
- ipa_parm_adjustment_vec adjustments)
-{
- tree *lhs_p, *rhs_p;
- bool any;
-
- if (!gimple_assign_single_p (stmt))
- return false;
-
- rhs_p = gimple_assign_rhs1_ptr (stmt);
- lhs_p = gimple_assign_lhs_ptr (stmt);
-
- any = ipa_modify_expr (rhs_p, false, adjustments);
- any |= ipa_modify_expr (lhs_p, false, adjustments);
- if (any)
- {
- tree new_rhs = NULL_TREE;
-
- if (!useless_type_conversion_p (TREE_TYPE (*lhs_p), TREE_TYPE (*rhs_p)))
- {
- if (TREE_CODE (*rhs_p) == CONSTRUCTOR)
- {
- /* V_C_Es of constructors can cause trouble (PR 42714). */
- if (is_gimple_reg_type (TREE_TYPE (*lhs_p)))
- *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
- else
- *rhs_p = build_constructor (TREE_TYPE (*lhs_p),
- NULL);
- }
- else
- new_rhs = fold_build1_loc (gimple_location (stmt),
- VIEW_CONVERT_EXPR, TREE_TYPE (*lhs_p),
- *rhs_p);
- }
- else if (REFERENCE_CLASS_P (*rhs_p)
- && is_gimple_reg_type (TREE_TYPE (*lhs_p))
- && !is_gimple_reg (*lhs_p))
- /* This can happen when an assignment in between two single field
- structures is turned into an assignment in between two pointers to
- scalars (PR 42237). */
- new_rhs = *rhs_p;
-
- if (new_rhs)
- {
- tree tmp = force_gimple_operand_gsi (gsi, new_rhs, true, NULL_TREE,
- true, GSI_SAME_STMT);
-
- gimple_assign_set_rhs_from_tree (gsi, tmp);
- }
-
- return true;
- }
-
- return false;
-}
-
-/* Traverse the function body and all modifications as described in
- ADJUSTMENTS. Return true iff the CFG has been changed. */
-
-bool
-ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
-{
- bool cfg_changed = false;
- basic_block bb;
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
- tree new_lhs, old_lhs = gimple_phi_result (phi);
- new_lhs = replace_removed_params_ssa_names (old_lhs, phi, adjustments);
- if (new_lhs)
- {
- gimple_phi_set_result (phi, new_lhs);
- release_ssa_name (old_lhs);
- }
- }
-
- gsi = gsi_start_bb (bb);
- while (!gsi_end_p (gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
- bool modified = false;
- tree *t;
- unsigned i;
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_RETURN:
- t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
- if (*t != NULL_TREE)
- modified |= ipa_modify_expr (t, true, adjustments);
- break;
-
- case GIMPLE_ASSIGN:
- modified |= sra_ipa_modify_assign (stmt, &gsi, adjustments);
- break;
-
- case GIMPLE_CALL:
- /* Operands must be processed before the lhs. */
- for (i = 0; i < gimple_call_num_args (stmt); i++)
- {
- t = gimple_call_arg_ptr (stmt, i);
- modified |= ipa_modify_expr (t, true, adjustments);
- }
-
- if (gimple_call_lhs (stmt))
- {
- t = gimple_call_lhs_ptr (stmt);
- modified |= ipa_modify_expr (t, false, adjustments);
- }
- break;
-
- case GIMPLE_ASM:
- {
- gasm *asm_stmt = as_a <gasm *> (stmt);
- for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
- {
- t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
- modified |= ipa_modify_expr (t, true, adjustments);
- }
- for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
- {
- t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
- modified |= ipa_modify_expr (t, false, adjustments);
- }
- }
- break;
-
- default:
- break;
- }
-
- def_operand_p defp;
- ssa_op_iter iter;
- FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_DEF)
- {
- tree old_def = DEF_FROM_PTR (defp);
- if (tree new_def = replace_removed_params_ssa_names (old_def, stmt,
- adjustments))
- {
- SET_DEF (defp, new_def);
- release_ssa_name (old_def);
- modified = true;
- }
- }
-
- if (modified)
- {
- update_stmt (stmt);
- if (maybe_clean_eh_stmt (stmt)
- && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
- cfg_changed = true;
- }
- gsi_next (&gsi);
- }
- }
-
- return cfg_changed;
-}
-
-/* Call gimple_debug_bind_reset_value on all debug statements describing
- gimple register parameters that are being removed or replaced. */
-
-static void
-sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments)
-{
- int i, len;
- gimple_stmt_iterator *gsip = NULL, gsi;
-
- if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)))
- {
- gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
- gsip = &gsi;
- }
- len = adjustments.length ();
- for (i = 0; i < len; i++)
- {
- struct ipa_parm_adjustment *adj;
- imm_use_iterator ui;
- gimple *stmt;
- gdebug *def_temp;
- tree name, vexpr, copy = NULL_TREE;
- use_operand_p use_p;
-
- adj = &adjustments[i];
- if (adj->op == IPA_PARM_OP_COPY || !is_gimple_reg (adj->base))
- continue;
- name = ssa_default_def (cfun, adj->base);
- vexpr = NULL;
- if (name)
- FOR_EACH_IMM_USE_STMT (stmt, ui, name)
- {
- if (gimple_clobber_p (stmt))
- {
- gimple_stmt_iterator cgsi = gsi_for_stmt (stmt);
- unlink_stmt_vdef (stmt);
- gsi_remove (&cgsi, true);
- release_defs (stmt);
- continue;
- }
- /* All other users must have been removed by
- ipa_sra_modify_function_body. */
- gcc_assert (is_gimple_debug (stmt));
- if (vexpr == NULL && gsip != NULL)
- {
- gcc_assert (TREE_CODE (adj->base) == PARM_DECL);
- vexpr = make_node (DEBUG_EXPR_DECL);
- def_temp = gimple_build_debug_source_bind (vexpr, adj->base,
- NULL);
- DECL_ARTIFICIAL (vexpr) = 1;
- TREE_TYPE (vexpr) = TREE_TYPE (name);
- SET_DECL_MODE (vexpr, DECL_MODE (adj->base));
- gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
- }
- if (vexpr)
- {
- FOR_EACH_IMM_USE_ON_STMT (use_p, ui)
- SET_USE (use_p, vexpr);
- }
- else
- gimple_debug_bind_reset_value (stmt);
- update_stmt (stmt);
- }
- /* Create a VAR_DECL for debug info purposes. */
- if (!DECL_IGNORED_P (adj->base))
- {
- copy = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
- VAR_DECL, DECL_NAME (adj->base),
- TREE_TYPE (adj->base));
- if (DECL_PT_UID_SET_P (adj->base))
- SET_DECL_PT_UID (copy, DECL_PT_UID (adj->base));
- TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (adj->base);
- TREE_READONLY (copy) = TREE_READONLY (adj->base);
- TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (adj->base);
- DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (adj->base);
- DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (adj->base);
- DECL_IGNORED_P (copy) = DECL_IGNORED_P (adj->base);
- DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (adj->base);
- DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
- SET_DECL_RTL (copy, 0);
- TREE_USED (copy) = 1;
- DECL_CONTEXT (copy) = current_function_decl;
- add_local_decl (cfun, copy);
- DECL_CHAIN (copy) =
- BLOCK_VARS (DECL_INITIAL (current_function_decl));
- BLOCK_VARS (DECL_INITIAL (current_function_decl)) = copy;
- }
- if (gsip != NULL && copy && target_for_debug_bind (adj->base))
- {
- gcc_assert (TREE_CODE (adj->base) == PARM_DECL);
- if (vexpr)
- def_temp = gimple_build_debug_bind (copy, vexpr, NULL);
- else
- def_temp = gimple_build_debug_source_bind (copy, adj->base,
- NULL);
- gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
- }
- }
+ return proceed;
}
/* Return false if all callers have at least as many actual arguments as there
@@ -5233,13 +4869,21 @@ some_callers_have_no_vuse_p (struct cgraph_node *node,
return false;
}
+struct convert_callers_data
+{
+ /* Declaration of the callee. */
+ tree callee_fndecl;
+ /* List of adjusted parameters together with their operations. */
+ vec<ipa_adjusted_param, va_gc> *adj_params;
+};
+
/* Convert all callers of NODE. */
static bool
convert_callers_for_node (struct cgraph_node *node,
void *data)
{
- ipa_parm_adjustment_vec *adjustments = (ipa_parm_adjustment_vec *) data;
+ struct convert_callers_data *ccd = (struct convert_callers_data *) data;
bitmap recomputed_callers = BITMAP_ALLOC (NULL);
struct cgraph_edge *cs;
@@ -5251,8 +4895,8 @@ convert_callers_for_node (struct cgraph_node *node,
fprintf (dump_file, "Adjusting call %s -> %s\n",
cs->caller->dump_name (), cs->callee->dump_name ());
- ipa_modify_call_arguments (cs, cs->call_stmt, *adjustments);
-
+ ipa_param_adjustments adjustments (ccd->adj_params, ccd->callee_fndecl);
+ adjustments.modify_call_arguments (cs);
pop_cfun ();
}
@@ -5265,16 +4909,17 @@ convert_callers_for_node (struct cgraph_node *node,
return true;
}
-/* Convert all callers of NODE to pass parameters as given in ADJUSTMENTS. */
+/* Convert all callers of NODE to pass parameters as given in ADJ_PARAMS. */
static void
convert_callers (struct cgraph_node *node, tree old_decl,
- ipa_parm_adjustment_vec adjustments)
+ vec<ipa_adjusted_param, va_gc> *adj_params)
{
basic_block this_block;
-
- node->call_for_symbol_and_aliases (convert_callers_for_node,
- &adjustments, false);
+ struct convert_callers_data ccd;
+ ccd.callee_fndecl = node->decl;
+ ccd.adj_params = adj_params;
+ node->call_for_symbol_and_aliases (convert_callers_for_node, &ccd, false);
if (!encountered_recursive_call)
return;
@@ -5295,8 +4940,8 @@ convert_callers (struct cgraph_node *node, tree old_decl,
{
if (dump_file)
fprintf (dump_file, "Adjusting recursive call");
- gimple_call_set_fndecl (stmt, node->decl);
- ipa_modify_call_arguments (NULL, stmt, adjustments);
+ ipa_param_adjustments adjustments (adj_params);
+ adjustments.modify_call_arguments (stmt, node->decl);
}
}
}
@@ -5305,10 +4950,11 @@ convert_callers (struct cgraph_node *node, tree old_decl,
}
/* Perform all the modification required in IPA-SRA for NODE to have parameters
- as given in ADJUSTMENTS. Return true iff the CFG has been changed. */
+ as given in ADJ_PARAMS. Return true iff the CFG has been changed. */
static bool
-modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
+modify_function (struct cgraph_node *node,
+ vec<ipa_adjusted_param, va_gc> *adj_params)
{
struct cgraph_node *new_node;
bool cfg_changed;
@@ -5325,13 +4971,12 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
NULL, false, NULL, NULL,
"isra");
redirect_callers.release ();
+ new_node->make_local ();
push_cfun (DECL_STRUCT_FUNCTION (new_node->decl));
- ipa_modify_formal_parameters (current_function_decl, adjustments);
- cfg_changed = ipa_sra_modify_function_body (adjustments);
- sra_ipa_reset_debug_stmts (adjustments);
- convert_callers (new_node, node->decl, adjustments);
- new_node->make_local ();
+ convert_callers (new_node, node->decl, adj_params);
+ ipa_param_body_adjustments body_adj (adj_params, new_node->decl);
+ cfg_changed = body_adj.perform_cfun_body_modifications ();
return cfg_changed;
}
@@ -5497,7 +5142,7 @@ static unsigned int
ipa_early_sra (void)
{
struct cgraph_node *node = cgraph_node::get (current_function_decl);
- ipa_parm_adjustment_vec adjustments;
+ vec<ipa_adjusted_param, va_gc> *adj_params;
int ret = 0;
if (!ipa_sra_preliminary_function_checks (node))
@@ -5552,17 +5197,15 @@ ipa_early_sra (void)
goto out;
}
- adjustments = analyze_all_param_acesses ();
- if (!adjustments.exists ())
+ if (!analyze_all_param_acesses (&adj_params))
goto out;
if (dump_file)
- ipa_dump_param_adjustments (dump_file, adjustments, current_function_decl);
+ ipa_dump_adjusted_parameters (dump_file, adj_params);
- if (modify_function (node, adjustments))
+ if (modify_function (node, adj_params))
ret = TODO_update_ssa | TODO_cleanup_cfg;
else
ret = TODO_update_ssa;
- adjustments.release ();
statistics_counter_event (cfun, "Unused parameters deleted",
sra_stats.deleted_unused_parameters);