/* Scalar Replacement of Aggregates (SRA) converts some structure
references into scalar references, exposing them to the scalar
optimizers.
- Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2008-2015 Free Software Foundation, Inc.
Contributed by Martin Jambor <mjambor@suse.cz>
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
+#include "hash-map.h"
+#include "hash-table.h"
#include "alloc-pool.h"
#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
#include "tree.h"
+#include "fold-const.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
#include "gimple.h"
-#include "cgraph.h"
-#include "tree-flow.h"
+#include "stor-layout.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "gimple-walk.h"
+#include "bitmap.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "hashtab.h"
+#include "rtl.h"
+#include "flags.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
#include "tree-pass.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
#include "ipa-prop.h"
-#include "statistics.h"
#include "params.h"
#include "target.h"
-#include "flags.h"
#include "dbgcnt.h"
#include "tree-inline.h"
#include "gimple-pretty-print.h"
#include "ipa-inline.h"
+#include "ipa-utils.h"
+#include "builtins.h"
/* Enumeration of all aggregate reductions we can do. */
enum sra_mode { SRA_MODE_EARLY_IPA, /* early call regularization */
/* Set when a scalar replacement should be created for this variable. */
unsigned grp_to_be_replaced : 1;
+ /* Set when we want a replacement for the sole purpose of having it in
+ generated debug statements. */
+ unsigned grp_to_be_debug_replaced : 1;
+
/* Should TREE_NO_WARNING of a replacement be set? */
unsigned grp_no_warning : 1;
typedef struct access *access_p;
-DEF_VEC_P (access_p);
-DEF_VEC_ALLOC_P (access_p, heap);
/* Alloc pool for allocating access structures. */
static alloc_pool access_pool;
/* Alloc pool for allocating assign link structures. */
static alloc_pool link_pool;
-/* Base (tree) -> Vector (VEC(access_p,heap) *) map. */
-static struct pointer_map_t *base_access_vec;
+/* Base (tree) -> Vector (vec<access_p> *) map. */
+static hash_map<tree, auto_vec<access_p> > *base_access_vec;
+
+/* Candidate hash table helpers. */
+
+struct uid_decl_hasher : typed_noop_remove <tree_node>
+{
+ typedef tree_node value_type;
+ typedef tree_node compare_type;
+ static inline hashval_t hash (const value_type *);
+ static inline bool equal (const value_type *, const compare_type *);
+};
+
+/* Hash a tree in a uid_decl_map. */
+
+inline hashval_t
+uid_decl_hasher::hash (const value_type *item)
+{
+ return item->decl_minimal.uid;
+}
+
+/* Return true if the DECL_UID in both trees are equal. */
+
+inline bool
+uid_decl_hasher::equal (const value_type *a, const compare_type *b)
+{
+ return (a->decl_minimal.uid == b->decl_minimal.uid);
+}
/* Set of candidates. */
static bitmap candidate_bitmap;
-static htab_t candidates;
+static hash_table<uid_decl_hasher> *candidates;
/* For a candidate UID return the candidates decl. */
static inline tree
candidate (unsigned uid)
{
- struct tree_decl_minimal t;
- t.uid = uid;
- return (tree) htab_find_with_hash (candidates, &t, uid);
+ tree_node t;
+ t.decl_minimal.uid = uid;
+ return candidates->find_with_hash (&t, static_cast <hashval_t> (uid));
}
/* Bitmap of candidates which we should try to entirely scalarize away and
"grp_hint = %d, grp_covered = %d, "
"grp_unscalarizable_region = %d, grp_unscalarized_data = %d, "
"grp_partial_lhs = %d, grp_to_be_replaced = %d, "
- "grp_maybe_modified = %d, "
+ "grp_to_be_debug_replaced = %d, grp_maybe_modified = %d, "
"grp_not_necessarilly_dereferenced = %d\n",
access->grp_read, access->grp_write, access->grp_assignment_read,
access->grp_assignment_write, access->grp_scalar_read,
access->grp_hint, access->grp_covered,
access->grp_unscalarizable_region, access->grp_unscalarized_data,
access->grp_partial_lhs, access->grp_to_be_replaced,
- access->grp_maybe_modified,
+ access->grp_to_be_debug_replaced, access->grp_maybe_modified,
access->grp_not_necessarilly_dereferenced);
else
fprintf (f, ", write = %d, grp_total_scalarization = %d, "
/* Return a vector of pointers to accesses for the variable given in BASE or
NULL if there is none. */
-static VEC (access_p, heap) *
+static vec<access_p> *
get_base_access_vector (tree base)
{
- void **slot;
-
- slot = pointer_map_contains (base_access_vec, base);
- if (!slot)
- return NULL;
- else
- return *(VEC (access_p, heap) **) slot;
+ return base_access_vec->get (base);
}
/* Find an access with required OFFSET and SIZE in a subtree of accesses rooted
static struct access *
get_first_repr_for_decl (tree base)
{
- VEC (access_p, heap) *access_vec;
+ vec<access_p> *access_vec;
access_vec = get_base_access_vector (base);
if (!access_vec)
return NULL;
- return VEC_index (access_p, access_vec, 0);
+ return (*access_vec)[0];
}
/* Find an access representative for the variable BASE and given OFFSET and
sra_initialize (void)
{
candidate_bitmap = BITMAP_ALLOC (NULL);
- candidates = htab_create (VEC_length (tree, cfun->local_decls) / 2,
- uid_decl_map_hash, uid_decl_map_eq, NULL);
+ candidates = new hash_table<uid_decl_hasher>
+ (vec_safe_length (cfun->local_decls) / 2);
should_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
cannot_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
gcc_obstack_init (&name_obstack);
access_pool = create_alloc_pool ("SRA accesses", sizeof (struct access), 16);
link_pool = create_alloc_pool ("SRA links", sizeof (struct assign_link), 16);
- base_access_vec = pointer_map_create ();
+ base_access_vec = new hash_map<tree, auto_vec<access_p> >;
memset (&sra_stats, 0, sizeof (sra_stats));
encountered_apply_args = false;
encountered_recursive_call = false;
encountered_unchangable_recursive_call = false;
}
-/* Hook fed to pointer_map_traverse, deallocate stored vectors. */
-
-static bool
-delete_base_accesses (const void *key ATTRIBUTE_UNUSED, void **value,
- void *data ATTRIBUTE_UNUSED)
-{
- VEC (access_p, heap) *access_vec;
- access_vec = (VEC (access_p, heap) *) *value;
- VEC_free (access_p, heap, access_vec);
-
- return true;
-}
-
/* Deallocate all general structures. */
static void
sra_deinitialize (void)
{
BITMAP_FREE (candidate_bitmap);
- htab_delete (candidates);
+ delete candidates;
+ candidates = NULL;
BITMAP_FREE (should_scalarize_away_bitmap);
BITMAP_FREE (cannot_scalarize_away_bitmap);
free_alloc_pool (access_pool);
free_alloc_pool (link_pool);
obstack_free (&name_obstack, NULL);
- pointer_map_traverse (base_access_vec, delete_base_accesses, NULL);
- pointer_map_destroy (base_access_vec);
+ delete base_access_vec;
}
/* Remove DECL from candidates for SRA and write REASON to the dump file if
disqualify_candidate (tree decl, const char *reason)
{
if (bitmap_clear_bit (candidate_bitmap, DECL_UID (decl)))
- htab_clear_slot (candidates,
- htab_find_slot_with_hash (candidates, decl,
- DECL_UID (decl), NO_INSERT));
+ candidates->remove_elt_with_hash (decl, DECL_UID (decl));
if (dump_file && (dump_flags & TDF_DETAILS))
{
*msg = "zero structure field size";
return true;
}
- if (!host_integerp (DECL_FIELD_OFFSET (fld), 1))
+ if (!tree_fits_uhwi_p (DECL_FIELD_OFFSET (fld)))
{
*msg = "structure field offset not fixed";
return true;
}
- if (!host_integerp (DECL_SIZE (fld), 1))
+ if (!tree_fits_uhwi_p (DECL_SIZE (fld)))
{
*msg = "structure field size not fixed";
return true;
- }
+ }
+ if (!tree_fits_shwi_p (bit_position (fld)))
+ {
+ *msg = "structure field size too big";
+ return true;
+ }
if (AGGREGATE_TYPE_P (ft)
&& int_bit_position (fld) % BITS_PER_UNIT != 0)
{
static struct access *
create_access_1 (tree base, HOST_WIDE_INT offset, HOST_WIDE_INT size)
{
- VEC (access_p, heap) *vec;
struct access *access;
- void **slot;
access = (struct access *) pool_alloc (access_pool);
memset (access, 0, sizeof (struct access));
access->offset = offset;
access->size = size;
- slot = pointer_map_contains (base_access_vec, base);
- if (slot)
- vec = (VEC (access_p, heap) *) *slot;
- else
- vec = VEC_alloc (access_p, heap, 32);
-
- VEC_safe_push (access_p, heap, vec, access);
-
- *((struct VEC (access_p,heap) **)
- pointer_map_insert (base_access_vec, base)) = vec;
+ base_access_vec->get_or_insert (base).safe_push (access);
return access;
}
struct access *access;
HOST_WIDE_INT size;
- size = tree_low_cst (DECL_SIZE (fld), 1);
+ size = tree_to_uhwi (DECL_SIZE (fld));
access = create_access_1 (base, pos, size);
access->expr = nref;
access->type = ft;
static void
completely_scalarize_var (tree var)
{
- HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (var), 1);
+ HOST_WIDE_INT size = tree_to_uhwi (DECL_SIZE (var));
struct access *access;
access = create_access_1 (var, 0, size);
completely_scalarize_record (var, var, 0, var);
}
+/* Return true if REF has an VIEW_CONVERT_EXPR somewhere in it. */
+
+static inline bool
+contains_view_convert_expr_p (const_tree ref)
+{
+ while (handled_component_p (ref))
+ {
+ if (TREE_CODE (ref) == VIEW_CONVERT_EXPR)
+ return true;
+ ref = TREE_OPERAND (ref, 0);
+ }
+
+ return false;
+}
+
/* Search the given tree for a declaration by skipping handled components and
exclude it from the candidates. */
"component.");
return NULL;
}
+ if (TREE_THIS_VOLATILE (expr))
+ {
+ disqualify_base_of_expr (expr, "part of a volatile reference.");
+ return NULL;
+ }
switch (TREE_CODE (expr))
{
return false;
}
-/* Disqualify LHS and RHS for scalarization if STMT must end its basic block in
- modes in which it matters, return true iff they have been disqualified. RHS
- may be NULL, in that case ignore it. If we scalarize an aggregate in
- intra-SRA we may need to add statements after each statement. This is not
- possible if a statement unconditionally has to end the basic block. */
+/* Return the single non-EH successor edge of BB or NULL if there is none or
+ more than one. */
+
+static edge
+single_non_eh_succ (basic_block bb)
+{
+ edge e, res = NULL;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (!(e->flags & EDGE_EH))
+ {
+ if (res)
+ return NULL;
+ res = e;
+ }
+
+ return res;
+}
+
+/* Disqualify LHS and RHS for scalarization if STMT has to terminate its BB and
+ there is no alternative spot where to put statements SRA might need to
+ generate after it. The spot we are looking for is an edge leading to a
+ single non-EH successor, if it exists and is indeed single. RHS may be
+ NULL, in that case ignore it. */
+
static bool
-disqualify_ops_if_throwing_stmt (gimple stmt, tree lhs, tree rhs)
+disqualify_if_bad_bb_terminating_stmt (gimple stmt, tree lhs, tree rhs)
{
if ((sra_mode == SRA_MODE_EARLY_INTRA || sra_mode == SRA_MODE_INTRA)
- && (stmt_can_throw_internal (stmt) || stmt_ends_bb_p (stmt)))
+ && stmt_ends_bb_p (stmt))
{
+ if (single_non_eh_succ (gimple_bb (stmt)))
+ return false;
+
disqualify_base_of_expr (lhs, "LHS of a throwing stmt.");
if (rhs)
disqualify_base_of_expr (rhs, "RHS of a throwing stmt.");
lhs = gimple_assign_lhs (stmt);
rhs = gimple_assign_rhs1 (stmt);
- if (disqualify_ops_if_throwing_stmt (stmt, lhs, rhs))
+ if (disqualify_if_bad_bb_terminating_stmt (stmt, lhs, rhs))
return false;
racc = build_access_from_expr_1 (rhs, stmt, false);
GIMPLE_ASM operands with memory constrains which cannot be scalarized. */
static bool
-asm_visit_addr (gimple stmt ATTRIBUTE_UNUSED, tree op,
- void *data ATTRIBUTE_UNUSED)
+asm_visit_addr (gimple, tree op, tree, void *)
{
op = get_base_address (op);
if (op
}
/* Return true iff callsite CALL has at least as many actual arguments as there
- are formal parameters of the function currently processed by IPA-SRA. */
+ are formal parameters of the function currently processed by IPA-SRA and
+ that their types match. */
static inline bool
-callsite_has_enough_arguments_p (gimple call)
+callsite_arguments_match_p (gimple call)
{
- return gimple_call_num_args (call) >= (unsigned) func_param_count;
+ if (gimple_call_num_args (call) < (unsigned) func_param_count)
+ return false;
+
+ tree parm;
+ int i;
+ for (parm = DECL_ARGUMENTS (current_function_decl), i = 0;
+ parm;
+ parm = DECL_CHAIN (parm), i++)
+ {
+ tree arg = gimple_call_arg (call, i);
+ if (!useless_type_conversion_p (TREE_TYPE (parm), TREE_TYPE (arg)))
+ return false;
+ }
+ return true;
}
/* Scan function and look for interesting expressions and create access
basic_block bb;
bool ret = false;
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
switch (gimple_code (stmt))
{
case GIMPLE_RETURN:
- t = gimple_return_retval (stmt);
+ t = gimple_return_retval (as_a <greturn *> (stmt));
if (t != NULL_TREE)
ret |= build_access_from_expr (t, stmt, false);
if (final_bbs)
if (DECL_BUILT_IN_CLASS (dest) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (dest) == BUILT_IN_APPLY_ARGS)
encountered_apply_args = true;
- if (cgraph_get_node (dest)
- == cgraph_get_node (current_function_decl))
+ if (recursive_call_p (current_function_decl, dest))
{
encountered_recursive_call = true;
- if (!callsite_has_enough_arguments_p (stmt))
+ if (!callsite_arguments_match_p (stmt))
encountered_unchangable_recursive_call = true;
}
}
}
t = gimple_call_lhs (stmt);
- if (t && !disqualify_ops_if_throwing_stmt (stmt, t, NULL))
+ if (t && !disqualify_if_bad_bb_terminating_stmt (stmt, t, NULL))
ret |= build_access_from_expr (t, stmt, true);
break;
case GIMPLE_ASM:
- walk_stmt_load_store_addr_ops (stmt, NULL, NULL, NULL,
- asm_visit_addr);
- if (final_bbs)
- bitmap_set_bit (final_bbs, bb->index);
+ {
+ gasm *asm_stmt = as_a <gasm *> (stmt);
+ walk_stmt_load_store_addr_ops (asm_stmt, NULL, NULL, NULL,
+ asm_visit_addr);
+ if (final_bbs)
+ bitmap_set_bit (final_bbs, bb->index);
- for (i = 0; i < gimple_asm_ninputs (stmt); i++)
- {
- t = TREE_VALUE (gimple_asm_input_op (stmt, i));
- ret |= build_access_from_expr (t, stmt, false);
- }
- for (i = 0; i < gimple_asm_noutputs (stmt); i++)
- {
- t = TREE_VALUE (gimple_asm_output_op (stmt, i));
- ret |= build_access_from_expr (t, stmt, true);
- }
+ for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
+ {
+ t = TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
+ ret |= build_access_from_expr (t, asm_stmt, false);
+ }
+ for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+ {
+ t = TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+ ret |= build_access_from_expr (t, asm_stmt, true);
+ }
+ }
break;
default:
EXP_TYPE at the given OFFSET. If BASE is something for which
get_addr_base_and_unit_offset returns NULL, gsi must be non-NULL and is used
to insert new statements either before or below the current one as specified
- by INSERT_AFTER. This function is not capable of handling bitfields. */
+ by INSERT_AFTER. This function is not capable of handling bitfields.
+
+ BASE must be either a declaration or a memory reference that has correct
+ alignment ifformation embeded in it (e.g. a pre-existing one in SRA). */
tree
build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
{
tree prev_base = base;
tree off;
+ tree mem_ref;
HOST_WIDE_INT base_offset;
unsigned HOST_WIDE_INT misalign;
unsigned int align;
gcc_checking_assert (offset % BITS_PER_UNIT == 0);
-
+ get_object_alignment_1 (base, &align, &misalign);
base = get_addr_base_and_unit_offset (base, &base_offset);
/* get_addr_base_and_unit_offset returns NULL for references with a variable
offset such as array[var_index]. */
if (!base)
{
- gimple stmt;
+ gassign *stmt;
tree tmp, addr;
gcc_checking_assert (gsi);
- tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)), NULL);
+ tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)));
addr = build_fold_addr_expr (unshare_expr (prev_base));
STRIP_USELESS_TYPE_CONVERSION (addr);
stmt = gimple_build_assign (tmp, addr);
base = build_fold_addr_expr (unshare_expr (base));
}
- /* If prev_base were always an originally performed access
- we can extract more optimistic alignment information
- by looking at the access mode. That would constrain the
- alignment of base + base_offset which we would need to
- adjust according to offset. */
- if (!get_pointer_alignment_1 (base, &align, &misalign))
- {
- gcc_assert (misalign == 0);
- if (TREE_CODE (prev_base) == MEM_REF
- || TREE_CODE (prev_base) == TARGET_MEM_REF)
- align = TYPE_ALIGN (TREE_TYPE (prev_base));
- }
- misalign += (tree_to_double_int (off)
- .sext (TYPE_PRECISION (TREE_TYPE (off))).low
- * BITS_PER_UNIT);
- misalign = misalign & (align - 1);
+ misalign = (misalign + offset) & (align - 1);
if (misalign != 0)
align = (misalign & -misalign);
if (align < TYPE_ALIGN (exp_type))
exp_type = build_aligned_type (exp_type, align);
- return fold_build2_loc (loc, MEM_REF, exp_type, base, off);
+ mem_ref = fold_build2_loc (loc, MEM_REF, exp_type, base, off);
+ if (TREE_THIS_VOLATILE (prev_base))
+ TREE_THIS_VOLATILE (mem_ref) = 1;
+ if (TREE_SIDE_EFFECTS (prev_base))
+ TREE_SIDE_EFFECTS (mem_ref) = 1;
+ return mem_ref;
}
/* Construct a memory reference to a part of an aggregate BASE at the given
gsi, insert_after);
}
+/* Attempt to build a memory reference that we could but into a gimple
+ debug_bind statement. Similar to build_ref_for_model but punts if it has to
+ create statements and return s NULL instead. This function also ignores
+ alignment issues and so its results should never end up in non-debug
+ statements. */
+
+static tree
+build_debug_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
+ struct access *model)
+{
+ HOST_WIDE_INT base_offset;
+ tree off;
+
+ if (TREE_CODE (model->expr) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1)))
+ return NULL_TREE;
+
+ base = get_addr_base_and_unit_offset (base, &base_offset);
+ if (!base)
+ return NULL_TREE;
+ if (TREE_CODE (base) == MEM_REF)
+ {
+ off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
+ base_offset + offset / BITS_PER_UNIT);
+ off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off);
+ base = unshare_expr (TREE_OPERAND (base, 0));
+ }
+ else
+ {
+ off = build_int_cst (reference_alias_ptr_type (base),
+ base_offset + offset / BITS_PER_UNIT);
+ base = build_fold_addr_expr (unshare_expr (base));
+ }
+
+ return fold_build2_loc (loc, MEM_REF, model->type, base, off);
+}
+
/* Construct a memory reference consisting of component_refs and array_refs to
a part of an aggregate *RES (which is of type TYPE). The requested part
should have type EXP_TYPE at be the given OFFSET. This function might not
continue;
tr_pos = bit_position (fld);
- if (!tr_pos || !host_integerp (tr_pos, 1))
+ if (!tr_pos || !tree_fits_uhwi_p (tr_pos))
continue;
- pos = TREE_INT_CST_LOW (tr_pos);
+ pos = tree_to_uhwi (tr_pos);
gcc_assert (TREE_CODE (type) == RECORD_TYPE || pos == 0);
tr_size = DECL_SIZE (fld);
- if (!tr_size || !host_integerp (tr_size, 1))
+ if (!tr_size || !tree_fits_uhwi_p (tr_size))
continue;
- size = TREE_INT_CST_LOW (tr_size);
+ size = tree_to_uhwi (tr_size);
if (size == 0)
{
if (pos != offset)
case ARRAY_TYPE:
tr_size = TYPE_SIZE (TREE_TYPE (type));
- if (!tr_size || !host_integerp (tr_size, 1))
+ if (!tr_size || !tree_fits_uhwi_p (tr_size))
return false;
- el_size = tree_low_cst (tr_size, 1);
+ el_size = tree_to_uhwi (tr_size);
minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
if (TREE_CODE (minidx) != INTEGER_CST || el_size == 0)
{
tree type = TREE_TYPE (var);
const char *msg;
- void **slot;
+ tree_node **slot;
if (!AGGREGATE_TYPE_P (type))
{
reject (var, "has incomplete type");
return false;
}
- if (!host_integerp (TYPE_SIZE (type), 1))
+ if (!tree_fits_uhwi_p (TYPE_SIZE (type)))
{
reject (var, "type size not fixed");
return false;
}
- if (tree_low_cst (TYPE_SIZE (type), 1) == 0)
+ if (tree_to_uhwi (TYPE_SIZE (type)) == 0)
{
reject (var, "type size is zero");
return false;
}
bitmap_set_bit (candidate_bitmap, DECL_UID (var));
- slot = htab_find_slot_with_hash (candidates, var, DECL_UID (var), INSERT);
- *slot = (void *) var;
+ slot = candidates->find_slot_with_hash (var, DECL_UID (var), INSERT);
+ *slot = var;
if (dump_file && (dump_flags & TDF_DETAILS))
{
{
int i, j, access_count;
struct access *res, **prev_acc_ptr = &res;
- VEC (access_p, heap) *access_vec;
+ vec<access_p> *access_vec;
bool first = true;
HOST_WIDE_INT low = -1, high = 0;
access_vec = get_base_access_vector (var);
if (!access_vec)
return NULL;
- access_count = VEC_length (access_p, access_vec);
+ access_count = access_vec->length ();
/* Sort by <OFFSET, SIZE>. */
- VEC_qsort (access_p, access_vec, compare_access_positions);
+ access_vec->qsort (compare_access_positions);
i = 0;
while (i < access_count)
{
- struct access *access = VEC_index (access_p, access_vec, i);
+ struct access *access = (*access_vec)[i];
bool grp_write = access->write;
bool grp_read = !access->write;
bool grp_scalar_write = access->write
j = i + 1;
while (j < access_count)
{
- struct access *ac2 = VEC_index (access_p, access_vec, j);
+ struct access *ac2 = (*access_vec)[j];
if (ac2->offset != access->offset || ac2->size != access->size)
break;
if (ac2->write)
prev_acc_ptr = &access->next_grp;
}
- gcc_assert (res == VEC_index (access_p, access_vec, 0));
+ gcc_assert (res == (*access_vec)[0]);
return res;
}
{
tree repl;
- repl = create_tmp_var (access->type, "SR");
+ if (access->grp_to_be_debug_replaced)
+ {
+ repl = create_tmp_var_raw (access->type);
+ DECL_CONTEXT (repl) = current_function_decl;
+ }
+ else
+ repl = create_tmp_var (access->type, "SR");
if (TREE_CODE (access->type) == COMPLEX_TYPE
|| TREE_CODE (access->type) == VECTOR_TYPE)
{
&& !DECL_ARTIFICIAL (access->base))
{
char *pretty_name = make_fancy_name (access->expr);
- tree debug_expr = unshare_expr (access->expr), d;
+ tree debug_expr = unshare_expr_without_location (access->expr), d;
bool fail = false;
DECL_NAME (repl) = get_identifier (pretty_name);
and that get_ref_base_and_extent works properly on the
expression. It cannot handle accesses at a non-constant offset
though, so just give up in those cases. */
- for (d = debug_expr; !fail && handled_component_p (d);
+ for (d = debug_expr;
+ !fail && (handled_component_p (d) || TREE_CODE (d) == MEM_REF);
d = TREE_OPERAND (d, 0))
switch (TREE_CODE (d))
{
&& TREE_CODE (TREE_OPERAND (d, 2)) != INTEGER_CST)
fail = true;
break;
+ case MEM_REF:
+ if (TREE_CODE (TREE_OPERAND (d, 0)) != ADDR_EXPR)
+ fail = true;
+ else
+ d = TREE_OPERAND (d, 0);
+ break;
default:
break;
}
if (!fail)
{
SET_DECL_DEBUG_EXPR (repl, debug_expr);
- DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
+ DECL_HAS_DEBUG_EXPR_P (repl) = 1;
}
if (access->grp_no_warning)
TREE_NO_WARNING (repl) = 1;
if (dump_file)
{
- fprintf (dump_file, "Created a replacement for ");
- print_generic_expr (dump_file, access->base, 0);
- fprintf (dump_file, " offset: %u, size: %u: ",
- (unsigned) access->offset, (unsigned) access->size);
- print_generic_expr (dump_file, repl, 0);
- fprintf (dump_file, "\n");
+ if (access->grp_to_be_debug_replaced)
+ {
+ fprintf (dump_file, "Created a debug-only replacement for ");
+ print_generic_expr (dump_file, access->base, 0);
+ fprintf (dump_file, " offset: %u, size: %u\n",
+ (unsigned) access->offset, (unsigned) access->size);
+ }
+ else
+ {
+ fprintf (dump_file, "Created a replacement for ");
+ print_generic_expr (dump_file, access->base, 0);
+ fprintf (dump_file, " offset: %u, size: %u: ",
+ (unsigned) access->offset, (unsigned) access->size);
+ print_generic_expr (dump_file, repl, 0);
+ fprintf (dump_file, "\n");
+ }
}
sra_stats.replacements++;
static inline tree
get_access_replacement (struct access *access)
{
- if (!access->replacement_decl)
- access->replacement_decl = create_access_replacement (access);
+ gcc_checking_assert (access->replacement_decl);
return access->replacement_decl;
}
while (handled_component_p (expr))
{
if (TREE_CODE (expr) == ARRAY_REF
- && !host_integerp (array_ref_low_bound (expr), 0))
+ && !tree_fits_shwi_p (array_ref_low_bound (expr)))
return true;
expr = TREE_OPERAND (expr, 0);
}
|| ((root->grp_scalar_read || root->grp_assignment_read)
&& (root->grp_scalar_write || root->grp_assignment_write))))
{
- bool new_integer_type;
/* Always create access replacements that cover the whole access.
For integral types this means the precision has to match.
Avoid assumptions based on the integral type kind, too. */
root->expr = build_ref_for_offset (UNKNOWN_LOCATION,
root->base, root->offset,
root->type, NULL, false);
- new_integer_type = true;
- }
- else
- new_integer_type = false;
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Marking ");
- print_generic_expr (dump_file, root->base, 0);
- fprintf (dump_file, " offset: %u, size: %u ",
- (unsigned) root->offset, (unsigned) root->size);
- fprintf (dump_file, " to be replaced%s.\n",
- new_integer_type ? " with an integer": "");
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Changing the type of a replacement for ");
+ print_generic_expr (dump_file, root->base, 0);
+ fprintf (dump_file, " offset: %u, size: %u ",
+ (unsigned) root->offset, (unsigned) root->size);
+ fprintf (dump_file, " to an integer.\n");
+ }
}
root->grp_to_be_replaced = 1;
+ root->replacement_decl = create_access_replacement (root);
sth_created = true;
hole = false;
}
else
{
+ if (allow_replacements
+ && scalar && !root->first_child
+ && (root->grp_scalar_write || root->grp_assignment_write)
+ && !bitmap_bit_p (cannot_scalarize_away_bitmap,
+ DECL_UID (root->base)))
+ {
+ gcc_checking_assert (!root->grp_scalar_read
+ && !root->grp_assignment_read);
+ sth_created = true;
+ if (MAY_HAVE_DEBUG_STMTS)
+ {
+ root->grp_to_be_debug_replaced = 1;
+ root->replacement_decl = create_access_replacement (root);
+ }
+ }
+
if (covered_to < limit)
hole = true;
if (scalar)
root->grp_total_scalarization = 0;
}
- if (sth_created
- && (!hole || root->grp_total_scalarization))
- {
- root->grp_covered = 1;
- return true;
- }
- if (root->grp_write || TREE_CODE (root->base) == PARM_DECL)
+ if (!hole || root->grp_total_scalarization)
+ root->grp_covered = 1;
+ else if (root->grp_write || TREE_CODE (root->base) == PARM_DECL)
root->grp_unscalarized_data = 1; /* not covered and written to */
- if (sth_created)
- return true;
- return false;
+ return sth_created;
}
/* Analyze all access trees linked by next_grp by the means of
int res = 0;
bitmap tmp = BITMAP_ALLOC (NULL);
bitmap_iterator bi;
- unsigned i, max_total_scalarization_size;
-
- max_total_scalarization_size = UNITS_PER_WORD * BITS_PER_UNIT
- * MOVE_RATIO (optimize_function_for_speed_p (cfun));
+ unsigned i;
+ unsigned max_scalarization_size
+ = (optimize_function_for_size_p (cfun)
+ ? PARAM_VALUE (PARAM_SRA_MAX_SCALARIZATION_SIZE_SIZE)
+ : PARAM_VALUE (PARAM_SRA_MAX_SCALARIZATION_SIZE_SPEED))
+ * BITS_PER_UNIT;
EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)
if (bitmap_bit_p (should_scalarize_away_bitmap, i)
if (TREE_CODE (var) == VAR_DECL
&& type_consists_of_records_p (TREE_TYPE (var)))
{
- if ((unsigned) tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1)
- <= max_total_scalarization_size)
+ if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var)))
+ <= max_scalarization_size)
{
completely_scalarize_var (var);
if (dump_file && (dump_flags & TDF_DETAILS))
|| access->offset + access->size > start_offset))
{
tree expr, repl = get_access_replacement (access);
- gimple stmt;
+ gassign *stmt;
expr = build_ref_for_model (loc, agg, access->offset - top_offset,
access, gsi, insert_after);
update_stmt (stmt);
sra_stats.subtree_copies++;
}
+ else if (write
+ && access->grp_to_be_debug_replaced
+ && (chunk_size == 0
+ || access->offset + access->size > start_offset))
+ {
+ gdebug *ds;
+ tree drhs = build_debug_ref_for_model (loc, agg,
+ access->offset - top_offset,
+ access);
+ ds = gimple_build_debug_bind (get_access_replacement (access),
+ drhs, gsi_stmt (*gsi));
+ if (insert_after)
+ gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+ else
+ gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+ }
if (access->first_child)
generate_subtree_copies (access->first_child, agg, top_offset,
if (access->grp_to_be_replaced)
{
- gimple stmt;
+ gassign *stmt;
stmt = gimple_build_assign (get_access_replacement (access),
build_zero_cst (access->type));
update_stmt (stmt);
gimple_set_location (stmt, loc);
}
+ else if (access->grp_to_be_debug_replaced)
+ {
+ gdebug *ds
+ = gimple_build_debug_bind (get_access_replacement (access),
+ build_zero_cst (access->type),
+ gsi_stmt (*gsi));
+ if (insert_after)
+ gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+ else
+ gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+ }
for (child = access->first_child; child; child = child->next_sibling)
init_subtree_with_zero (child, gsi, insert_after, loc);
}
+/* Clobber all scalar replacements in an access subtree. ACCESS is the the
+ root of the subtree to be processed. GSI is the statement iterator used
+ for inserting statements which are added after the current statement if
+ INSERT_AFTER is true or before it otherwise. */
+
+static void
+clobber_subtree (struct access *access, gimple_stmt_iterator *gsi,
+ bool insert_after, location_t loc)
+
+{
+ struct access *child;
+
+ if (access->grp_to_be_replaced)
+ {
+ tree rep = get_access_replacement (access);
+ tree clobber = build_constructor (access->type, NULL);
+ TREE_THIS_VOLATILE (clobber) = 1;
+ gimple stmt = gimple_build_assign (rep, clobber);
+
+ if (insert_after)
+ gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
+ else
+ gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+ update_stmt (stmt);
+ gimple_set_location (stmt, loc);
+ }
+
+ for (child = access->first_child; child; child = child->next_sibling)
+ clobber_subtree (child, gsi, insert_after, loc);
+}
+
/* Search for an access representative for the given expression EXPR and
return it or NULL if it cannot be found. */
{
location_t loc;
struct access *access;
- tree type, bfr;
+ tree type, bfr, orig_expr;
if (TREE_CODE (*expr) == BIT_FIELD_REF)
{
if (!access)
return false;
type = TREE_TYPE (*expr);
+ orig_expr = *expr;
loc = gimple_location (gsi_stmt (*gsi));
+ gimple_stmt_iterator alt_gsi = gsi_none ();
+ if (write && stmt_ends_bb_p (gsi_stmt (*gsi)))
+ {
+ alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
+ gsi = &alt_gsi;
+ }
+
if (access->grp_to_be_replaced)
{
tree repl = get_access_replacement (access);
{
tree ref;
- ref = build_ref_for_model (loc, access->base, access->offset, access,
- NULL, false);
+ ref = build_ref_for_model (loc, orig_expr, 0, access, gsi, false);
if (write)
{
- gimple stmt;
+ gassign *stmt;
if (access->grp_partial_lhs)
ref = force_gimple_operand_gsi (gsi, ref, true, NULL_TREE,
}
else
{
- gimple stmt;
+ gassign *stmt;
if (access->grp_partial_lhs)
repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE,
*expr = repl;
sra_stats.exprs++;
}
+ else if (write && access->grp_to_be_debug_replaced)
+ {
+ gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
+ NULL_TREE,
+ gsi_stmt (*gsi));
+ gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+ }
if (access->first_child)
{
HOST_WIDE_INT start_offset, chunk_size;
if (bfr
- && host_integerp (TREE_OPERAND (bfr, 1), 1)
- && host_integerp (TREE_OPERAND (bfr, 2), 1))
+ && tree_fits_uhwi_p (TREE_OPERAND (bfr, 1))
+ && tree_fits_uhwi_p (TREE_OPERAND (bfr, 2)))
{
- chunk_size = tree_low_cst (TREE_OPERAND (bfr, 1), 1);
+ chunk_size = tree_to_uhwi (TREE_OPERAND (bfr, 1));
start_offset = access->offset
- + tree_low_cst (TREE_OPERAND (bfr, 2), 1);
+ + tree_to_uhwi (TREE_OPERAND (bfr, 2));
}
else
start_offset = chunk_size = 0;
- generate_subtree_copies (access->first_child, access->base, 0,
+ generate_subtree_copies (access->first_child, orig_expr, access->offset,
start_offset, chunk_size, gsi, write, write,
loc);
}
SRA_UDH_RIGHT, /* Data flushed to the RHS. */
SRA_UDH_LEFT }; /* Data flushed to the LHS. */
+struct subreplacement_assignment_data
+{
+ /* Offset of the access representing the lhs of the assignment. */
+ HOST_WIDE_INT left_offset;
+
+ /* LHS and RHS of the original assignment. */
+ tree assignment_lhs, assignment_rhs;
+
+ /* Access representing the rhs of the whole assignment. */
+ struct access *top_racc;
+
+ /* Stmt iterator used for statement insertions after the original assignment.
+ It points to the main GSI used to traverse a BB during function body
+ modification. */
+ gimple_stmt_iterator *new_gsi;
+
+ /* Stmt iterator used for statement insertions before the original
+ assignment. Keeps on pointing to the original statement. */
+ gimple_stmt_iterator old_gsi;
+
+ /* Location of the assignment. */
+ location_t loc;
+
+ /* Keeps the information whether we have needed to refresh replacements of
+ the LHS and from which side of the assignments this takes place. */
+ enum unscalarized_data_handling refreshed;
+};
+
/* Store all replacements in the access tree rooted in TOP_RACC either to their
base aggregate if there are unscalarized data or directly to LHS of the
statement that is pointed to by GSI otherwise. */
-static enum unscalarized_data_handling
-handle_unscalarized_data_in_subtree (struct access *top_racc,
- gimple_stmt_iterator *gsi)
+static void
+handle_unscalarized_data_in_subtree (struct subreplacement_assignment_data *sad)
{
- if (top_racc->grp_unscalarized_data)
+ tree src;
+ if (sad->top_racc->grp_unscalarized_data)
{
- generate_subtree_copies (top_racc->first_child, top_racc->base, 0, 0, 0,
- gsi, false, false,
- gimple_location (gsi_stmt (*gsi)));
- return SRA_UDH_RIGHT;
+ src = sad->assignment_rhs;
+ sad->refreshed = SRA_UDH_RIGHT;
}
else
{
- tree lhs = gimple_assign_lhs (gsi_stmt (*gsi));
- generate_subtree_copies (top_racc->first_child, lhs, top_racc->offset,
- 0, 0, gsi, false, false,
- gimple_location (gsi_stmt (*gsi)));
- return SRA_UDH_LEFT;
+ src = sad->assignment_lhs;
+ sad->refreshed = SRA_UDH_LEFT;
}
+ generate_subtree_copies (sad->top_racc->first_child, src,
+ sad->top_racc->offset, 0, 0,
+ &sad->old_gsi, false, false, sad->loc);
}
-
/* Try to generate statements to load all sub-replacements in an access subtree
- formed by children of LACC from scalar replacements in the TOP_RACC subtree.
- If that is not possible, refresh the TOP_RACC base aggregate and load the
- accesses from it. LEFT_OFFSET is the offset of the left whole subtree being
- copied. NEW_GSI is stmt iterator used for statement insertions after the
- original assignment, OLD_GSI is used to insert statements before the
- assignment. *REFRESHED keeps the information whether we have needed to
- refresh replacements of the LHS and from which side of the assignments this
- takes place. */
+ formed by children of LACC from scalar replacements in the SAD->top_racc
+ subtree. If that is not possible, refresh the SAD->top_racc base aggregate
+ and load the accesses from it. */
static void
-load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
- HOST_WIDE_INT left_offset,
- gimple_stmt_iterator *old_gsi,
- gimple_stmt_iterator *new_gsi,
- enum unscalarized_data_handling *refreshed)
+load_assign_lhs_subreplacements (struct access *lacc,
+ struct subreplacement_assignment_data *sad)
{
- location_t loc = gimple_location (gsi_stmt (*old_gsi));
for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling)
{
+ HOST_WIDE_INT offset;
+ offset = lacc->offset - sad->left_offset + sad->top_racc->offset;
+
if (lacc->grp_to_be_replaced)
{
struct access *racc;
- HOST_WIDE_INT offset = lacc->offset - left_offset + top_racc->offset;
- gimple stmt;
+ gassign *stmt;
tree rhs;
- racc = find_access_in_subtree (top_racc, offset, lacc->size);
+ racc = find_access_in_subtree (sad->top_racc, offset, lacc->size);
if (racc && racc->grp_to_be_replaced)
{
rhs = get_access_replacement (racc);
if (!useless_type_conversion_p (lacc->type, racc->type))
- rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, lacc->type, rhs);
+ rhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR,
+ lacc->type, rhs);
if (racc->grp_partial_lhs && lacc->grp_partial_lhs)
- rhs = force_gimple_operand_gsi (old_gsi, rhs, true, NULL_TREE,
- true, GSI_SAME_STMT);
+ rhs = force_gimple_operand_gsi (&sad->old_gsi, rhs, true,
+ NULL_TREE, true, GSI_SAME_STMT);
}
else
{
/* No suitable access on the right hand side, need to load from
the aggregate. See if we have to update it first... */
- if (*refreshed == SRA_UDH_NONE)
- *refreshed = handle_unscalarized_data_in_subtree (top_racc,
- old_gsi);
+ if (sad->refreshed == SRA_UDH_NONE)
+ handle_unscalarized_data_in_subtree (sad);
- if (*refreshed == SRA_UDH_LEFT)
- rhs = build_ref_for_model (loc, lacc->base, lacc->offset, lacc,
- new_gsi, true);
+ if (sad->refreshed == SRA_UDH_LEFT)
+ rhs = build_ref_for_model (sad->loc, sad->assignment_lhs,
+ lacc->offset - sad->left_offset,
+ lacc, sad->new_gsi, true);
else
- rhs = build_ref_for_model (loc, top_racc->base, offset, lacc,
- new_gsi, true);
+ rhs = build_ref_for_model (sad->loc, sad->assignment_rhs,
+ lacc->offset - sad->left_offset,
+ lacc, sad->new_gsi, true);
if (lacc->grp_partial_lhs)
- rhs = force_gimple_operand_gsi (new_gsi, rhs, true, NULL_TREE,
+ rhs = force_gimple_operand_gsi (sad->new_gsi,
+ rhs, true, NULL_TREE,
false, GSI_NEW_STMT);
}
stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
- gsi_insert_after (new_gsi, stmt, GSI_NEW_STMT);
- gimple_set_location (stmt, loc);
+ gsi_insert_after (sad->new_gsi, stmt, GSI_NEW_STMT);
+ gimple_set_location (stmt, sad->loc);
update_stmt (stmt);
sra_stats.subreplacements++;
}
- else if (*refreshed == SRA_UDH_NONE
- && lacc->grp_read && !lacc->grp_covered)
- *refreshed = handle_unscalarized_data_in_subtree (top_racc,
- old_gsi);
+ else
+ {
+ if (sad->refreshed == SRA_UDH_NONE
+ && lacc->grp_read && !lacc->grp_covered)
+ handle_unscalarized_data_in_subtree (sad);
+
+ if (lacc && lacc->grp_to_be_debug_replaced)
+ {
+ gdebug *ds;
+ tree drhs;
+ struct access *racc = find_access_in_subtree (sad->top_racc,
+ offset,
+ lacc->size);
+
+ if (racc && racc->grp_to_be_replaced)
+ {
+ if (racc->grp_write)
+ drhs = get_access_replacement (racc);
+ else
+ drhs = NULL;
+ }
+ else if (sad->refreshed == SRA_UDH_LEFT)
+ drhs = build_debug_ref_for_model (sad->loc, lacc->base,
+ lacc->offset, lacc);
+ else if (sad->refreshed == SRA_UDH_RIGHT)
+ drhs = build_debug_ref_for_model (sad->loc, sad->top_racc->base,
+ offset, lacc);
+ else
+ drhs = NULL_TREE;
+ if (drhs
+ && !useless_type_conversion_p (lacc->type, TREE_TYPE (drhs)))
+ drhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR,
+ lacc->type, drhs);
+ ds = gimple_build_debug_bind (get_access_replacement (lacc),
+ drhs, gsi_stmt (sad->old_gsi));
+ gsi_insert_after (sad->new_gsi, ds, GSI_NEW_STMT);
+ }
+ }
if (lacc->first_child)
- load_assign_lhs_subreplacements (lacc, top_racc, left_offset,
- old_gsi, new_gsi, refreshed);
+ load_assign_lhs_subreplacements (lacc, sad);
}
}
the same values as sra_modify_assign. */
static enum assignment_mod_result
-sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
+sra_modify_constructor_assign (gimple stmt, gimple_stmt_iterator *gsi)
{
- tree lhs = gimple_assign_lhs (*stmt);
- struct access *acc;
- location_t loc;
-
- acc = get_access_for_expr (lhs);
+ tree lhs = gimple_assign_lhs (stmt);
+ struct access *acc = get_access_for_expr (lhs);
if (!acc)
return SRA_AM_NONE;
+ location_t loc = gimple_location (stmt);
- if (gimple_clobber_p (*stmt))
+ if (gimple_clobber_p (stmt))
{
- /* Remove clobbers of fully scalarized variables, otherwise
- do nothing. */
+ /* Clobber the replacement variable. */
+ clobber_subtree (acc, gsi, !acc->grp_covered, loc);
+ /* Remove clobbers of fully scalarized variables, they are dead. */
if (acc->grp_covered)
{
- unlink_stmt_vdef (*stmt);
+ unlink_stmt_vdef (stmt);
gsi_remove (gsi, true);
- release_defs (*stmt);
+ release_defs (stmt);
return SRA_AM_REMOVED;
}
else
- return SRA_AM_NONE;
+ return SRA_AM_MODIFIED;
}
- loc = gimple_location (*stmt);
- if (VEC_length (constructor_elt,
- CONSTRUCTOR_ELTS (gimple_assign_rhs1 (*stmt))) > 0)
+ if (vec_safe_length (CONSTRUCTOR_ELTS (gimple_assign_rhs1 (stmt))) > 0)
{
/* I have never seen this code path trigger but if it can happen the
following should handle it gracefully. */
if (access_has_children_p (acc))
- generate_subtree_copies (acc->first_child, acc->base, 0, 0, 0, gsi,
+ generate_subtree_copies (acc->first_child, lhs, acc->offset, 0, 0, gsi,
true, true, loc);
return SRA_AM_MODIFIED;
}
if (acc->grp_covered)
{
init_subtree_with_zero (acc, gsi, false, loc);
- unlink_stmt_vdef (*stmt);
+ unlink_stmt_vdef (stmt);
gsi_remove (gsi, true);
- release_defs (*stmt);
+ release_defs (stmt);
return SRA_AM_REMOVED;
}
else
static tree
get_repl_default_def_ssa_name (struct access *racc)
{
- return get_or_create_ssa_default_def (cfun, get_access_replacement (racc));
-}
-
-/* Return true if REF has a COMPONENT_REF with a bit-field field declaration
- somewhere in it. */
-
-static inline bool
-contains_bitfld_comp_ref_p (const_tree ref)
-{
- while (handled_component_p (ref))
- {
- if (TREE_CODE (ref) == COMPONENT_REF
- && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))
- return true;
- ref = TREE_OPERAND (ref, 0);
- }
-
- return false;
+ gcc_checking_assert (!racc->grp_to_be_replaced
+ && !racc->grp_to_be_debug_replaced);
+ if (!racc->replacement_decl)
+ racc->replacement_decl = create_access_replacement (racc);
+ return get_or_create_ssa_default_def (cfun, racc->replacement_decl);
}
/* Return true if REF has an VIEW_CONVERT_EXPR or a COMPONENT_REF with a
copying. */
static enum assignment_mod_result
-sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
+sra_modify_assign (gimple stmt, gimple_stmt_iterator *gsi)
{
struct access *lacc, *racc;
tree lhs, rhs;
location_t loc;
gimple_stmt_iterator orig_gsi = *gsi;
- if (!gimple_assign_single_p (*stmt))
+ if (!gimple_assign_single_p (stmt))
return SRA_AM_NONE;
- lhs = gimple_assign_lhs (*stmt);
- rhs = gimple_assign_rhs1 (*stmt);
+ lhs = gimple_assign_lhs (stmt);
+ rhs = gimple_assign_rhs1 (stmt);
if (TREE_CODE (rhs) == CONSTRUCTOR)
return sra_modify_constructor_assign (stmt, gsi);
|| TREE_CODE (rhs) == IMAGPART_EXPR || TREE_CODE (lhs) == IMAGPART_EXPR
|| TREE_CODE (rhs) == BIT_FIELD_REF || TREE_CODE (lhs) == BIT_FIELD_REF)
{
- modify_this_stmt = sra_modify_expr (gimple_assign_rhs1_ptr (*stmt),
+ modify_this_stmt = sra_modify_expr (gimple_assign_rhs1_ptr (stmt),
gsi, false);
- modify_this_stmt |= sra_modify_expr (gimple_assign_lhs_ptr (*stmt),
+ modify_this_stmt |= sra_modify_expr (gimple_assign_lhs_ptr (stmt),
gsi, true);
return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
}
if (!lacc && !racc)
return SRA_AM_NONE;
- loc = gimple_location (*stmt);
+ loc = gimple_location (stmt);
if (lacc && lacc->grp_to_be_replaced)
{
lhs = get_access_replacement (lacc);
- gimple_assign_set_lhs (*stmt, lhs);
+ gimple_assign_set_lhs (stmt, lhs);
modify_this_stmt = true;
if (lacc->grp_partial_lhs)
force_gimple_rhs = true;
??? This should move to fold_stmt which we simply should
call after building a VIEW_CONVERT_EXPR here. */
if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))
- && !contains_bitfld_comp_ref_p (lhs)
- && !access_has_children_p (lacc))
+ && !contains_bitfld_component_ref_p (lhs))
{
lhs = build_ref_for_model (loc, lhs, 0, racc, gsi, false);
- gimple_assign_set_lhs (*stmt, lhs);
+ gimple_assign_set_lhs (stmt, lhs);
}
else if (AGGREGATE_TYPE_P (TREE_TYPE (rhs))
- && !contains_vce_or_bfcref_p (rhs)
- && !access_has_children_p (racc))
+ && !contains_vce_or_bfcref_p (rhs))
rhs = build_ref_for_model (loc, rhs, 0, lacc, gsi, false);
if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
}
}
+ if (lacc && lacc->grp_to_be_debug_replaced)
+ {
+ tree dlhs = get_access_replacement (lacc);
+ tree drhs = unshare_expr (rhs);
+ if (!useless_type_conversion_p (TREE_TYPE (dlhs), TREE_TYPE (drhs)))
+ {
+ if (AGGREGATE_TYPE_P (TREE_TYPE (drhs))
+ && !contains_vce_or_bfcref_p (drhs))
+ drhs = build_debug_ref_for_model (loc, drhs, 0, lacc);
+ if (drhs
+ && !useless_type_conversion_p (TREE_TYPE (dlhs),
+ TREE_TYPE (drhs)))
+ drhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
+ TREE_TYPE (dlhs), drhs);
+ }
+ gdebug *ds = gimple_build_debug_bind (dlhs, drhs, stmt);
+ gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+ }
+
/* From this point on, the function deals with assignments in between
aggregates when at least one has scalar reductions of some of its
components. There are three possible scenarios: Both the LHS and RHS have
This is what the first branch does. */
if (modify_this_stmt
- || gimple_has_volatile_ops (*stmt)
+ || gimple_has_volatile_ops (stmt)
|| contains_vce_or_bfcref_p (rhs)
- || contains_vce_or_bfcref_p (lhs))
+ || contains_vce_or_bfcref_p (lhs)
+ || stmt_ends_bb_p (stmt))
{
if (access_has_children_p (racc))
- generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
+ generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0,
gsi, false, false, loc);
if (access_has_children_p (lacc))
- generate_subtree_copies (lacc->first_child, lacc->base, 0, 0, 0,
- gsi, true, true, loc);
+ {
+ gimple_stmt_iterator alt_gsi = gsi_none ();
+ if (stmt_ends_bb_p (stmt))
+ {
+ alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
+ gsi = &alt_gsi;
+ }
+ generate_subtree_copies (lacc->first_child, lhs, lacc->offset, 0, 0,
+ gsi, true, true, loc);
+ }
sra_stats.separate_lhs_rhs_handling++;
/* This gimplification must be done after generate_subtree_copies,
if (force_gimple_rhs)
rhs = force_gimple_operand_gsi (&orig_gsi, rhs, true, NULL_TREE,
true, GSI_SAME_STMT);
- if (gimple_assign_rhs1 (*stmt) != rhs)
+ if (gimple_assign_rhs1 (stmt) != rhs)
{
modify_this_stmt = true;
gimple_assign_set_rhs_from_tree (&orig_gsi, rhs);
- gcc_assert (*stmt == gsi_stmt (orig_gsi));
+ gcc_assert (stmt == gsi_stmt (orig_gsi));
}
return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
&& !lacc->grp_unscalarizable_region
&& !racc->grp_unscalarizable_region)
{
- gimple_stmt_iterator orig_gsi = *gsi;
- enum unscalarized_data_handling refreshed;
+ struct subreplacement_assignment_data sad;
+
+ sad.left_offset = lacc->offset;
+ sad.assignment_lhs = lhs;
+ sad.assignment_rhs = rhs;
+ sad.top_racc = racc;
+ sad.old_gsi = *gsi;
+ sad.new_gsi = gsi;
+ sad.loc = gimple_location (stmt);
+ sad.refreshed = SRA_UDH_NONE;
if (lacc->grp_read && !lacc->grp_covered)
- refreshed = handle_unscalarized_data_in_subtree (racc, gsi);
- else
- refreshed = SRA_UDH_NONE;
+ handle_unscalarized_data_in_subtree (&sad);
- load_assign_lhs_subreplacements (lacc, racc, lacc->offset,
- &orig_gsi, gsi, &refreshed);
- if (refreshed != SRA_UDH_RIGHT)
+ load_assign_lhs_subreplacements (lacc, &sad);
+ if (sad.refreshed != SRA_UDH_RIGHT)
{
gsi_next (gsi);
- unlink_stmt_vdef (*stmt);
- gsi_remove (&orig_gsi, true);
- release_defs (*stmt);
+ unlink_stmt_vdef (stmt);
+ gsi_remove (&sad.old_gsi, true);
+ release_defs (stmt);
sra_stats.deleted++;
return SRA_AM_REMOVED;
}
if (dump_file)
{
fprintf (dump_file, "Removing load: ");
- print_gimple_stmt (dump_file, *stmt, 0, 0);
+ print_gimple_stmt (dump_file, stmt, 0, 0);
}
generate_subtree_copies (racc->first_child, lhs,
racc->offset, 0, 0, gsi,
false, false, loc);
- gcc_assert (*stmt == gsi_stmt (*gsi));
- unlink_stmt_vdef (*stmt);
+ gcc_assert (stmt == gsi_stmt (*gsi));
+ unlink_stmt_vdef (stmt);
gsi_remove (gsi, true);
- release_defs (*stmt);
+ release_defs (stmt);
sra_stats.deleted++;
return SRA_AM_REMOVED;
}
/* Restore the aggregate RHS from its components so the
prevailing aggregate copy does the right thing. */
if (access_has_children_p (racc))
- generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
+ generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0,
gsi, false, false, loc);
/* Re-load the components of the aggregate copy destination.
But use the RHS aggregate to load from to expose more
bool cfg_changed = false;
basic_block bb;
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
gimple_stmt_iterator gsi = gsi_start_bb (bb);
while (!gsi_end_p (gsi))
switch (gimple_code (stmt))
{
case GIMPLE_RETURN:
- t = gimple_return_retval_ptr (stmt);
+ t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
if (*t != NULL_TREE)
modified |= sra_modify_expr (t, &gsi, false);
break;
case GIMPLE_ASSIGN:
- assign_result = sra_modify_assign (&stmt, &gsi);
+ assign_result = sra_modify_assign (stmt, &gsi);
modified |= assign_result == SRA_AM_MODIFIED;
deleted = assign_result == SRA_AM_REMOVED;
break;
break;
case GIMPLE_ASM:
- for (i = 0; i < gimple_asm_ninputs (stmt); i++)
- {
- t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
- modified |= sra_modify_expr (t, &gsi, false);
- }
- for (i = 0; i < gimple_asm_noutputs (stmt); i++)
- {
- t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
- modified |= sra_modify_expr (t, &gsi, true);
- }
+ {
+ 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 |= sra_modify_expr (t, &gsi, false);
+ }
+ for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+ {
+ t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+ modified |= sra_modify_expr (t, &gsi, true);
+ }
+ }
break;
default:
}
}
+ gsi_commit_edge_inserts ();
return cfg_changed;
}
parm;
parm = DECL_CHAIN (parm))
{
- VEC (access_p, heap) *access_vec;
+ vec<access_p> *access_vec;
struct access *access;
if (!bitmap_bit_p (candidate_bitmap, DECL_UID (parm)))
if (!access_vec)
continue;
- for (access = VEC_index (access_p, access_vec, 0);
+ for (access = (*access_vec)[0];
access;
access = access->next_grp)
generate_subtree_copies (access, parm, 0, 0, 0, &gsi, true, true,
seq = gsi_seq (gsi);
if (seq)
- gsi_insert_seq_on_edge_immediate (single_succ_edge (ENTRY_BLOCK_PTR), seq);
+ gsi_insert_seq_on_edge_immediate (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
}
/* The "main" function of intraprocedural SRA passes. Runs the analysis and if
}
-struct gimple_opt_pass pass_sra_early =
+namespace {
+
+const pass_data pass_data_sra_early =
{
- {
- GIMPLE_PASS,
- "esra", /* name */
- gate_intra_sra, /* gate */
- early_intra_sra, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_SRA, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_update_ssa
- | TODO_ggc_collect
- | TODO_verify_ssa /* todo_flags_finish */
- }
+ GIMPLE_PASS, /* type */
+ "esra", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_TREE_SRA, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_update_ssa, /* todo_flags_finish */
};
-struct gimple_opt_pass pass_sra =
+class pass_sra_early : public gimple_opt_pass
{
- {
- GIMPLE_PASS,
- "sra", /* name */
- gate_intra_sra, /* gate */
- late_intra_sra, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_SRA, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- TODO_update_address_taken, /* todo_flags_start */
- TODO_update_ssa
- | TODO_ggc_collect
- | TODO_verify_ssa /* todo_flags_finish */
- }
+public:
+ pass_sra_early (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_sra_early, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return gate_intra_sra (); }
+ virtual unsigned int execute (function *) { return early_intra_sra (); }
+
+}; // class pass_sra_early
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_sra_early (gcc::context *ctxt)
+{
+ return new pass_sra_early (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_sra =
+{
+ GIMPLE_PASS, /* type */
+ "sra", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_TREE_SRA, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ TODO_update_address_taken, /* todo_flags_start */
+ TODO_update_ssa, /* todo_flags_finish */
};
+class pass_sra : public gimple_opt_pass
+{
+public:
+ pass_sra (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_sra, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return gate_intra_sra (); }
+ virtual unsigned int execute (function *) { return late_intra_sra (); }
+
+}; // class pass_sra
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_sra (gcc::context *ctxt)
+{
+ return new pass_sra (ctxt);
+}
+
/* Return true iff PARM (which must be a parm_decl) is an unused scalar
parameter. */
parm = DECL_CHAIN (parm))
{
tree type = TREE_TYPE (parm);
- void **slot;
+ tree_node **slot;
count++;
continue;
if (!COMPLETE_TYPE_P (type)
- || !host_integerp (TYPE_SIZE (type), 1)
- || tree_low_cst (TYPE_SIZE (type), 1) == 0
+ || !tree_fits_uhwi_p (TYPE_SIZE (type))
+ || tree_to_uhwi (TYPE_SIZE (type)) == 0
|| (AGGREGATE_TYPE_P (type)
&& type_internals_preclude_sra_p (type, &msg)))
continue;
bitmap_set_bit (candidate_bitmap, DECL_UID (parm));
- slot = htab_find_slot_with_hash (candidates, parm,
- DECL_UID (parm), INSERT);
- *slot = (void *) parm;
+ slot = candidates->find_slot_with_hash (parm, DECL_UID (parm), INSERT);
+ *slot = parm;
ret = true;
if (dump_file && (dump_flags & TDF_DETAILS))
current function. */
static void
-analyze_modified_params (VEC (access_p, heap) *representatives)
+analyze_modified_params (vec<access_p> representatives)
{
int i;
{
struct access *repr;
- for (repr = VEC_index (access_p, representatives, i);
+ for (repr = representatives[i];
repr;
repr = repr->next_grp)
{
static void
propagate_dereference_distances (void)
{
- VEC (basic_block, heap) *queue;
basic_block bb;
- queue = VEC_alloc (basic_block, heap, last_basic_block_for_function (cfun));
- VEC_quick_push (basic_block, queue, ENTRY_BLOCK_PTR);
- FOR_EACH_BB (bb)
+ auto_vec<basic_block> queue (last_basic_block_for_fn (cfun));
+ queue.quick_push (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ FOR_EACH_BB_FN (bb, cfun)
{
- VEC_quick_push (basic_block, queue, bb);
+ queue.quick_push (bb);
bb->aux = bb;
}
- while (!VEC_empty (basic_block, queue))
+ while (!queue.is_empty ())
{
edge_iterator ei;
edge e;
bool change = false;
int i;
- bb = VEC_pop (basic_block, queue);
+ bb = queue.pop ();
bb->aux = NULL;
if (bitmap_bit_p (final_bbs, bb->index))
{
int succ_idx = e->dest->index * func_param_count + i;
- if (e->src == EXIT_BLOCK_PTR)
+ if (e->src == EXIT_BLOCK_PTR_FOR_FN (cfun))
continue;
if (first)
continue;
e->src->aux = e->src;
- VEC_quick_push (basic_block, queue, e->src);
+ queue.quick_push (e->src);
}
}
-
- VEC_free (basic_block, heap, queue);
}
/* Dump a dereferences TABLE with heading STR to file F. */
{
basic_block bb;
- fprintf (dump_file, str);
- FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
+ fprintf (dump_file, "%s", str);
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun),
+ EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb)
{
fprintf (f, "%4i %i ", bb->index, bitmap_bit_p (final_bbs, bb->index));
- if (bb != EXIT_BLOCK_PTR)
+ if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
{
int i;
for (i = 0; i < func_param_count; i++)
distances of each representative of a (fraction of a) parameter. */
static void
-analyze_caller_dereference_legality (VEC (access_p, heap) *representatives)
+analyze_caller_dereference_legality (vec<access_p> representatives)
{
int i;
for (i = 0; i < func_param_count; i++)
{
- struct access *repr = VEC_index (access_p, representatives, i);
- int idx = ENTRY_BLOCK_PTR->index * func_param_count + i;
+ struct access *repr = representatives[i];
+ int idx = ENTRY_BLOCK_PTR_FOR_FN (cfun)->index * func_param_count + i;
if (!repr || no_accesses_p (repr))
continue;
{
int i, access_count;
struct access *repr;
- VEC (access_p, heap) *access_vec;
+ vec<access_p> *access_vec;
access_vec = get_base_access_vector (parm);
gcc_assert (access_vec);
- repr = VEC_index (access_p, access_vec, 0);
+ repr = (*access_vec)[0];
if (repr->write)
return NULL;
repr->group_representative = repr;
- access_count = VEC_length (access_p, access_vec);
+ access_count = access_vec->length ();
for (i = 1; i < access_count; i++)
{
- struct access *access = VEC_index (access_p, access_vec, i);
+ struct access *access = (*access_vec)[i];
if (access->write)
return NULL;
access->group_representative = repr;
return repr;
}
-/* Return true iff this access precludes IPA-SRA of the parameter it is
- associated with. */
+/* Return true iff this ACCESS precludes IPA-SRA of the parameter it is
+ associated with. REQ_ALIGN is the minimum required alignment. */
static bool
-access_precludes_ipa_sra_p (struct access *access)
+access_precludes_ipa_sra_p (struct access *access, unsigned int req_align)
{
+ unsigned int exp_align;
/* Avoid issues such as the second simple testcase in PR 42025. The problem
is incompatible assign in a call statement (and possibly even in asm
statements). This can be relaxed by using a new temporary but only for
|| gimple_code (access->stmt) == GIMPLE_ASM))
return true;
+ exp_align = get_object_alignment (access->expr);
+ if (exp_align < req_align)
+ return true;
+
return false;
}
int i, j, access_count, group_count;
int agg_size, total_size = 0;
struct access *access, *res, **prev_acc_ptr = &res;
- VEC (access_p, heap) *access_vec;
+ vec<access_p> *access_vec;
access_vec = get_base_access_vector (parm);
if (!access_vec)
return &no_accesses_representant;
- access_count = VEC_length (access_p, access_vec);
+ access_count = access_vec->length ();
- VEC_qsort (access_p, access_vec, compare_access_positions);
+ access_vec->qsort (compare_access_positions);
i = 0;
total_size = 0;
{
bool modification;
tree a1_alias_type;
- access = VEC_index (access_p, access_vec, i);
+ access = (*access_vec)[i];
modification = access->write;
- if (access_precludes_ipa_sra_p (access))
+ if (access_precludes_ipa_sra_p (access, TYPE_ALIGN (access->type)))
return NULL;
a1_alias_type = reference_alias_ptr_type (access->expr);
j = i + 1;
while (j < access_count)
{
- struct access *ac2 = VEC_index (access_p, access_vec, j);
+ struct access *ac2 = (*access_vec)[j];
if (ac2->offset != access->offset)
{
/* All or nothing law for parameters. */
else if (ac2->size != access->size)
return NULL;
- if (access_precludes_ipa_sra_p (ac2)
+ if (access_precludes_ipa_sra_p (ac2, TYPE_ALIGN (access->type))
|| (ac2->type != access->type
&& (TREE_ADDRESSABLE (ac2->type)
|| TREE_ADDRESSABLE (access->type)))
}
if (POINTER_TYPE_P (TREE_TYPE (parm)))
- agg_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))), 1);
+ agg_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))));
else
- agg_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (parm)), 1);
+ agg_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (parm)));
if (total_size >= agg_size)
return NULL;
tree parm;
parm = repr->base;
- cur_parm_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (parm)), 1);
+ cur_parm_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (parm)));
gcc_assert (cur_parm_size > 0);
if (POINTER_TYPE_P (TREE_TYPE (parm)))
{
by_ref = true;
- agg_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))), 1);
+ agg_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))));
}
else
{
IPA-SRA. Return result based on what representatives have been found. */
static enum ipa_splicing_result
-splice_all_param_accesses (VEC (access_p, heap) **representatives)
+splice_all_param_accesses (vec<access_p> &representatives)
{
enum ipa_splicing_result result = NO_GOOD_ACCESS;
tree parm;
struct access *repr;
- *representatives = VEC_alloc (access_p, heap, func_param_count);
+ representatives.create (func_param_count);
for (parm = DECL_ARGUMENTS (current_function_decl);
parm;
{
if (is_unused_scalar_param (parm))
{
- VEC_quick_push (access_p, *representatives,
- &no_accesses_representant);
+ representatives.quick_push (&no_accesses_representant);
if (result == NO_GOOD_ACCESS)
result = UNUSED_PARAMS;
}
&& bitmap_bit_p (candidate_bitmap, DECL_UID (parm)))
{
repr = unmodified_by_ref_scalar_representative (parm);
- VEC_quick_push (access_p, *representatives, repr);
+ representatives.quick_push (repr);
if (repr)
result = UNMODIF_BY_REF_ACCESSES;
}
{
bool ro_grp = false;
repr = splice_param_accesses (parm, &ro_grp);
- VEC_quick_push (access_p, *representatives, repr);
+ representatives.quick_push (repr);
if (repr && !no_accesses_p (repr))
{
result = UNUSED_PARAMS;
}
else
- VEC_quick_push (access_p, *representatives, NULL);
+ representatives.quick_push (NULL);
}
if (result == NO_GOOD_ACCESS)
{
- VEC_free (access_p, heap, *representatives);
- *representatives = NULL;
+ representatives.release ();
return NO_GOOD_ACCESS;
}
/* Return the index of BASE in PARMS. Abort if it is not found. */
static inline int
-get_param_index (tree base, VEC(tree, heap) *parms)
+get_param_index (tree base, vec<tree> parms)
{
int i, len;
- len = VEC_length (tree, parms);
+ len = parms.length ();
for (i = 0; i < len; i++)
- if (VEC_index (tree, parms, i) == base)
+ if (parms[i] == base)
return i;
gcc_unreachable ();
}
final number of adjustments. */
static ipa_parm_adjustment_vec
-turn_representatives_into_adjustments (VEC (access_p, heap) *representatives,
+turn_representatives_into_adjustments (vec<access_p> representatives,
int adjustments_count)
{
- VEC (tree, heap) *parms;
+ vec<tree> parms;
ipa_parm_adjustment_vec adjustments;
tree parm;
int i;
gcc_assert (adjustments_count > 0);
parms = ipa_get_vector_of_formal_parms (current_function_decl);
- adjustments = VEC_alloc (ipa_parm_adjustment_t, heap, adjustments_count);
+ adjustments.create (adjustments_count);
parm = DECL_ARGUMENTS (current_function_decl);
for (i = 0; i < func_param_count; i++, parm = DECL_CHAIN (parm))
{
- struct access *repr = VEC_index (access_p, representatives, i);
+ struct access *repr = representatives[i];
if (!repr || no_accesses_p (repr))
{
adj.base_index = get_param_index (parm, parms);
adj.base = parm;
if (!repr)
- adj.copy_param = 1;
+ adj.op = IPA_PARM_OP_COPY;
else
- adj.remove_param = 1;
- VEC_quick_push (ipa_parm_adjustment_t, adjustments, adj);
+ adj.op = IPA_PARM_OP_REMOVE;
+ adj.arg_prefix = "ISRA";
+ adjustments.quick_push (adj);
}
else
{
adj.by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base))
&& (repr->grp_maybe_modified
|| repr->grp_not_necessarilly_dereferenced));
- VEC_quick_push (ipa_parm_adjustment_t, adjustments, adj);
+ adj.arg_prefix = "ISRA";
+ adjustments.quick_push (adj);
}
}
}
- VEC_free (tree, heap, parms);
+ parms.release ();
return adjustments;
}
enum ipa_splicing_result repr_state;
bool proceed = false;
int i, adjustments_count = 0;
- VEC (access_p, heap) *representatives;
+ vec<access_p> representatives;
ipa_parm_adjustment_vec adjustments;
- repr_state = splice_all_param_accesses (&representatives);
+ repr_state = splice_all_param_accesses (representatives);
if (repr_state == NO_GOOD_ACCESS)
- return NULL;
+ return ipa_parm_adjustment_vec ();
/* If there are any parameters passed by reference which are not modified
directly, we need to check whether they can be modified indirectly. */
for (i = 0; i < func_param_count; i++)
{
- struct access *repr = VEC_index (access_p, representatives, i);
+ struct access *repr = representatives[i];
if (repr && !no_accesses_p (repr))
{
adjustments_count++;
if (repr->grp_not_necessarilly_dereferenced
|| repr->grp_maybe_modified)
- VEC_replace (access_p, representatives, i, NULL);
+ representatives[i] = NULL;
else
{
proceed = true;
if (new_components == 0)
{
- VEC_replace (access_p, representatives, i, NULL);
+ representatives[i] = NULL;
adjustments_count++;
}
else
adjustments = turn_representatives_into_adjustments (representatives,
adjustments_count);
else
- adjustments = NULL;
+ adjustments = ipa_parm_adjustment_vec ();
- VEC_free (access_p, heap, representatives);
+ representatives.release ();
return adjustments;
}
{
int i, len;
- len = VEC_length (ipa_parm_adjustment_t, adjustments);
+ len = adjustments.length ();
for (i = 0; i < len; i++)
{
struct ipa_parm_adjustment *adj;
- adj = &VEC_index (ipa_parm_adjustment_t, adjustments, i);
- if (!adj->copy_param && adj->base == base)
+ adj = &adjustments[i];
+ if (adj->op != IPA_PARM_OP_COPY && adj->base == base)
return adj;
}
else if (is_gimple_call (stmt))
gimple_call_set_lhs (stmt, name);
else
- gimple_phi_set_result (stmt, name);
+ gimple_phi_set_result (as_a <gphi *> (stmt), name);
replace_uses_by (lhs, name);
release_ssa_name (lhs);
return true;
}
-/* 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. */
-
-static bool
-sra_ipa_modify_expr (tree *expr, bool convert,
- ipa_parm_adjustment_vec adjustments)
-{
- int i, len;
- struct ipa_parm_adjustment *adj, *cand = NULL;
- HOST_WIDE_INT offset, size, max_size;
- tree base, src;
-
- len = VEC_length (ipa_parm_adjustment_t, adjustments);
-
- if (TREE_CODE (*expr) == BIT_FIELD_REF
- || TREE_CODE (*expr) == IMAGPART_EXPR
- || TREE_CODE (*expr) == REALPART_EXPR)
- {
- expr = &TREE_OPERAND (*expr, 0);
- convert = true;
- }
-
- base = get_ref_base_and_extent (*expr, &offset, &size, &max_size);
- if (!base || size == -1 || max_size == -1)
- return false;
-
- if (TREE_CODE (base) == MEM_REF)
- {
- offset += mem_ref_offset (base).low * BITS_PER_UNIT;
- base = TREE_OPERAND (base, 0);
- }
-
- base = get_ssa_base_param (base);
- if (!base || TREE_CODE (base) != PARM_DECL)
- return false;
-
- for (i = 0; i < len; i++)
- {
- adj = &VEC_index (ipa_parm_adjustment_t, adjustments, i);
-
- if (adj->base == base &&
- (adj->offset == offset || adj->remove_param))
- {
- cand = adj;
- break;
- }
- }
- if (!cand || cand->copy_param || cand->remove_param)
- return false;
-
- if (cand->by_ref)
- src = build_simple_mem_ref (cand->reduction);
- else
- src = cand->reduction;
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "About to replace expr ");
- print_generic_expr (dump_file, *expr, 0);
- fprintf (dump_file, " with ");
- print_generic_expr (dump_file, src, 0);
- fprintf (dump_file, "\n");
- }
-
- if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type))
- {
- tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src);
- *expr = vce;
- }
- else
- *expr = src;
- return true;
-}
-
-/* If the statement pointed to by STMT_PTR 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. */
+/* 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_ptr, gimple_stmt_iterator *gsi,
+sra_ipa_modify_assign (gimple stmt, gimple_stmt_iterator *gsi,
ipa_parm_adjustment_vec adjustments)
{
- gimple stmt = *stmt_ptr;
tree *lhs_p, *rhs_p;
bool any;
rhs_p = gimple_assign_rhs1_ptr (stmt);
lhs_p = gimple_assign_lhs_ptr (stmt);
- any = sra_ipa_modify_expr (rhs_p, false, adjustments);
- any |= sra_ipa_modify_expr (lhs_p, false, adjustments);
+ any = ipa_modify_expr (rhs_p, false, adjustments);
+ any |= ipa_modify_expr (lhs_p, false, adjustments);
if (any)
{
tree new_rhs = NULL_TREE;
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), 0);
+ *rhs_p = build_constructor (TREE_TYPE (*lhs_p),
+ NULL);
}
else
new_rhs = fold_build1_loc (gimple_location (stmt),
/* Traverse the function body and all modifications as described in
ADJUSTMENTS. Return true iff the CFG has been changed. */
-static bool
+bool
ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
{
bool cfg_changed = false;
basic_block bb;
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
gimple_stmt_iterator gsi;
switch (gimple_code (stmt))
{
case GIMPLE_RETURN:
- t = gimple_return_retval_ptr (stmt);
+ t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
if (*t != NULL_TREE)
- modified |= sra_ipa_modify_expr (t, true, adjustments);
+ modified |= ipa_modify_expr (t, true, adjustments);
break;
case GIMPLE_ASSIGN:
- modified |= sra_ipa_modify_assign (&stmt, &gsi, adjustments);
+ modified |= sra_ipa_modify_assign (stmt, &gsi, adjustments);
modified |= replace_removed_params_ssa_names (stmt, adjustments);
break;
for (i = 0; i < gimple_call_num_args (stmt); i++)
{
t = gimple_call_arg_ptr (stmt, i);
- modified |= sra_ipa_modify_expr (t, true, adjustments);
+ modified |= ipa_modify_expr (t, true, adjustments);
}
if (gimple_call_lhs (stmt))
{
t = gimple_call_lhs_ptr (stmt);
- modified |= sra_ipa_modify_expr (t, false, adjustments);
+ modified |= ipa_modify_expr (t, false, adjustments);
modified |= replace_removed_params_ssa_names (stmt,
adjustments);
}
break;
case GIMPLE_ASM:
- for (i = 0; i < gimple_asm_ninputs (stmt); i++)
- {
- t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
- modified |= sra_ipa_modify_expr (t, true, adjustments);
- }
- for (i = 0; i < gimple_asm_noutputs (stmt); i++)
- {
- t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
- modified |= sra_ipa_modify_expr (t, false, adjustments);
- }
+ {
+ 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:
int i, len;
gimple_stmt_iterator *gsip = NULL, gsi;
- if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR))
+ if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)))
{
- gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+ gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
gsip = &gsi;
}
- len = VEC_length (ipa_parm_adjustment_t, adjustments);
+ len = adjustments.length ();
for (i = 0; i < len; i++)
{
struct ipa_parm_adjustment *adj;
imm_use_iterator ui;
- gimple stmt, def_temp;
+ gimple stmt;
+ gdebug *def_temp;
tree name, vexpr, copy = NULL_TREE;
use_operand_p use_p;
- adj = &VEC_index (ipa_parm_adjustment_t, adjustments, i);
- if (adj->copy_param || !is_gimple_reg (adj->base))
+ 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));
}
}
-/* Return false iff all callers have at least as many actual arguments as there
- are formal parameters in the current function. */
+/* Return false if all callers have at least as many actual arguments as there
+ are formal parameters in the current function and that their types
+ match. */
static bool
-not_all_callers_have_enough_arguments_p (struct cgraph_node *node,
- void *data ATTRIBUTE_UNUSED)
+some_callers_have_mismatched_arguments_p (struct cgraph_node *node,
+ void *data ATTRIBUTE_UNUSED)
{
struct cgraph_edge *cs;
for (cs = node->callers; cs; cs = cs->next_caller)
- if (!callsite_has_enough_arguments_p (cs->call_stmt))
+ if (!cs->call_stmt || !callsite_arguments_match_p (cs->call_stmt))
+ return true;
+
+ return false;
+}
+
+/* Return false if all callers have vuse attached to a call statement. */
+
+static bool
+some_callers_have_no_vuse_p (struct cgraph_node *node,
+ void *data ATTRIBUTE_UNUSED)
+{
+ struct cgraph_edge *cs;
+ for (cs = node->callers; cs; cs = cs->next_caller)
+ if (!cs->call_stmt || !gimple_vuse (cs->call_stmt))
return true;
return false;
convert_callers_for_node (struct cgraph_node *node,
void *data)
{
- ipa_parm_adjustment_vec adjustments = (ipa_parm_adjustment_vec)data;
+ ipa_parm_adjustment_vec *adjustments = (ipa_parm_adjustment_vec *) data;
bitmap recomputed_callers = BITMAP_ALLOC (NULL);
struct cgraph_edge *cs;
for (cs = node->callers; cs; cs = cs->next_caller)
{
- push_cfun (DECL_STRUCT_FUNCTION (cs->caller->symbol.decl));
+ push_cfun (DECL_STRUCT_FUNCTION (cs->caller->decl));
if (dump_file)
- fprintf (dump_file, "Adjusting call (%i -> %i) %s -> %s\n",
- cs->caller->uid, cs->callee->uid,
- xstrdup (cgraph_node_name (cs->caller)),
- xstrdup (cgraph_node_name (cs->callee)));
+ fprintf (dump_file, "Adjusting call %s/%i -> %s/%i\n",
+ xstrdup (cs->caller->name ()),
+ cs->caller->order,
+ xstrdup (cs->callee->name ()),
+ cs->callee->order);
- ipa_modify_call_arguments (cs, cs->call_stmt, adjustments);
+ ipa_modify_call_arguments (cs, cs->call_stmt, *adjustments);
pop_cfun ();
}
for (cs = node->callers; cs; cs = cs->next_caller)
if (bitmap_set_bit (recomputed_callers, cs->caller->uid)
- && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->symbol.decl)))
+ && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->decl)))
compute_inline_parameters (cs->caller, true);
BITMAP_FREE (recomputed_callers);
{
basic_block this_block;
- cgraph_for_node_and_aliases (node, convert_callers_for_node,
- adjustments, false);
+ node->call_for_symbol_thunks_and_aliases (convert_callers_for_node,
+ &adjustments, false);
if (!encountered_recursive_call)
return;
- FOR_EACH_BB (this_block)
+ FOR_EACH_BB_FN (this_block, cfun)
{
gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
+ gcall *stmt;
tree call_fndecl;
- if (gimple_code (stmt) != GIMPLE_CALL)
+ stmt = dyn_cast <gcall *> (gsi_stmt (gsi));
+ if (!stmt)
continue;
call_fndecl = gimple_call_fndecl (stmt);
if (call_fndecl == old_decl)
{
if (dump_file)
fprintf (dump_file, "Adjusting recursive call");
- gimple_call_set_fndecl (stmt, node->symbol.decl);
+ gimple_call_set_fndecl (stmt, node->decl);
ipa_modify_call_arguments (NULL, stmt, adjustments);
}
}
{
struct cgraph_node *new_node;
bool cfg_changed;
- VEC (cgraph_edge_p, heap) * redirect_callers = collect_callers_of_node (node);
- rebuild_cgraph_edges ();
+ cgraph_edge::rebuild_edges ();
free_dominance_info (CDI_DOMINATORS);
pop_cfun ();
- new_node = cgraph_function_versioning (node, redirect_callers, NULL, NULL,
- false, NULL, NULL, "isra");
- VEC_free (cgraph_edge_p, heap, redirect_callers);
-
- push_cfun (DECL_STRUCT_FUNCTION (new_node->symbol.decl));
- ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA");
+ /* This must be done after rebuilding cgraph edges for node above.
+ Otherwise any recursive calls to node that are recorded in
+ redirect_callers will be corrupted. */
+ vec<cgraph_edge *> redirect_callers = node->collect_callers ();
+ new_node = node->create_version_clone_with_body (redirect_callers, NULL,
+ NULL, false, NULL, NULL,
+ "isra");
+ redirect_callers.release ();
+
+ 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->symbol.decl, adjustments);
- cgraph_make_node_local (new_node);
+ convert_callers (new_node, node->decl, adjustments);
+ new_node->make_local ();
return cfg_changed;
}
+/* Means of communication between ipa_sra_check_caller and
+ ipa_sra_preliminary_function_checks. */
+
+struct ipa_sra_check_caller_data
+{
+ bool has_callers;
+ bool bad_arg_alignment;
+};
+
+/* If NODE has a caller, mark that fact in DATA which is pointer to
+ ipa_sra_check_caller_data. Also check all aggregate arguments in all known
+ calls if they are unit aligned and if not, set the appropriate flag in DATA
+ too. */
+
+static bool
+ipa_sra_check_caller (struct cgraph_node *node, void *data)
+{
+ if (!node->callers)
+ return false;
+
+ struct ipa_sra_check_caller_data *iscc;
+ iscc = (struct ipa_sra_check_caller_data *) data;
+ iscc->has_callers = true;
+
+ for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller)
+ {
+ gimple call_stmt = cs->call_stmt;
+ unsigned count = gimple_call_num_args (call_stmt);
+ for (unsigned i = 0; i < count; i++)
+ {
+ tree arg = gimple_call_arg (call_stmt, i);
+ if (is_gimple_reg (arg))
+ continue;
+
+ tree offset;
+ HOST_WIDE_INT bitsize, bitpos;
+ machine_mode mode;
+ int unsignedp, volatilep = 0;
+ get_inner_reference (arg, &bitsize, &bitpos, &offset, &mode,
+ &unsignedp, &volatilep, false);
+ if (bitpos % BITS_PER_UNIT)
+ {
+ iscc->bad_arg_alignment = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
/* Return false the function is apparently unsuitable for IPA-SRA based on it's
attributes, return true otherwise. NODE is the cgraph node of the current
function. */
static bool
ipa_sra_preliminary_function_checks (struct cgraph_node *node)
{
- if (!cgraph_node_can_be_local_p (node))
+ if (!node->can_be_local_p ())
{
if (dump_file)
fprintf (dump_file, "Function not local to this compilation unit.\n");
return false;
}
- if (!tree_versionable_function_p (node->symbol.decl))
+ if (!tree_versionable_function_p (node->decl))
{
if (dump_file)
fprintf (dump_file, "Function is not versionable.\n");
return false;
}
+ if (!opt_for_fn (node->decl, optimize)
+ || !opt_for_fn (node->decl, flag_ipa_sra))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Function not optimized.\n");
+ return false;
+ }
+
if (DECL_VIRTUAL_P (current_function_decl))
{
if (dump_file)
return false;
}
- if ((DECL_COMDAT (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl))
- && inline_summary(node)->size >= MAX_INLINE_INSNS_AUTO)
+ if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
+ && inline_summaries->get (node)->size >= MAX_INLINE_INSNS_AUTO)
{
if (dump_file)
fprintf (dump_file, "Function too big to be made truly local.\n");
return false;
}
- if (!node->callers)
+ if (cfun->stdarg)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Function uses stdarg. \n");
+ return false;
+ }
+
+ if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
+ return false;
+
+ if (DECL_DISREGARD_INLINE_LIMITS (node->decl))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Always inline function will be inlined "
+ "anyway. \n");
+ return false;
+ }
+
+ struct ipa_sra_check_caller_data iscc;
+ memset (&iscc, 0, sizeof(iscc));
+ node->call_for_symbol_thunks_and_aliases (ipa_sra_check_caller, &iscc, true);
+ if (!iscc.has_callers)
{
if (dump_file)
fprintf (dump_file,
return false;
}
- if (cfun->stdarg)
+ if (iscc.bad_arg_alignment)
{
if (dump_file)
- fprintf (dump_file, "Function uses stdarg. \n");
+ fprintf (dump_file,
+ "A function call has an argument with non-unit alignment.\n");
return false;
}
- if (TYPE_ATTRIBUTES (TREE_TYPE (node->symbol.decl)))
- return false;
-
return true;
}
static unsigned int
ipa_early_sra (void)
{
- struct cgraph_node *node = cgraph_get_node (current_function_decl);
+ struct cgraph_node *node = cgraph_node::get (current_function_decl);
ipa_parm_adjustment_vec adjustments;
int ret = 0;
goto simple_out;
}
- if (cgraph_for_node_and_aliases (node, not_all_callers_have_enough_arguments_p,
- NULL, true))
+ if (node->call_for_symbol_thunks_and_aliases
+ (some_callers_have_mismatched_arguments_p, NULL, true))
{
if (dump_file)
fprintf (dump_file, "There are callers with insufficient number of "
- "arguments.\n");
+ "arguments or arguments with type mismatches.\n");
+ goto simple_out;
+ }
+
+ if (node->call_for_symbol_thunks_and_aliases
+ (some_callers_have_no_vuse_p, NULL, true))
+ {
+ if (dump_file)
+ fprintf (dump_file, "There are callers with no VUSE attached "
+ "to a call stmt.\n");
goto simple_out;
}
bb_dereferences = XCNEWVEC (HOST_WIDE_INT,
func_param_count
- * last_basic_block_for_function (cfun));
+ * last_basic_block_for_fn (cfun));
final_bbs = BITMAP_ALLOC (NULL);
scan_function ();
}
adjustments = analyze_all_param_acesses ();
- if (!adjustments)
+ if (!adjustments.exists ())
goto out;
if (dump_file)
ipa_dump_param_adjustments (dump_file, adjustments, current_function_decl);
ret = TODO_update_ssa | TODO_cleanup_cfg;
else
ret = TODO_update_ssa;
- VEC_free (ipa_parm_adjustment_t, heap, adjustments);
+ adjustments.release ();
statistics_counter_event (cfun, "Unused parameters deleted",
sra_stats.deleted_unused_parameters);
return ret;
}
-/* Return if early ipa sra shall be performed. */
-static bool
-ipa_early_sra_gate (void)
-{
- return flag_ipa_sra && dbg_cnt (eipa_sra);
-}
+namespace {
-struct gimple_opt_pass pass_early_ipa_sra =
+const pass_data pass_data_early_ipa_sra =
{
- {
- GIMPLE_PASS,
- "eipa_sra", /* name */
- ipa_early_sra_gate, /* gate */
- ipa_early_sra, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_IPA_SRA, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_symtab /* todo_flags_finish */
- }
+ GIMPLE_PASS, /* type */
+ "eipa_sra", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_IPA_SRA, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_symtab, /* todo_flags_finish */
};
+
+class pass_early_ipa_sra : public gimple_opt_pass
+{
+public:
+ pass_early_ipa_sra (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_early_ipa_sra, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return flag_ipa_sra && dbg_cnt (eipa_sra); }
+ virtual unsigned int execute (function *) { return ipa_early_sra (); }
+
+}; // class pass_early_ipa_sra
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_ipa_sra (gcc::context *ctxt)
+{
+ return new pass_early_ipa_sra (ctxt);
+}