X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-sra.c;h=0635aa7f4a813c7a288042a329479b0a274673ab;hb=0395dc5ef775b63c96fcb017b334b4fae14447d2;hp=ae038f9a441028231c15a1c2f63e2282496ec864;hpb=ce084dfc1cd60d867d38dbed86a914d82fa908d1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index ae038f9a441..0635aa7f4a8 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -83,7 +83,6 @@ along with GCC; see the file COPYING3. If not see #include "tree-flow.h" #include "ipa-prop.h" #include "diagnostic.h" -#include "tree-pretty-print.h" #include "statistics.h" #include "tree-dump.h" #include "timevar.h" @@ -183,10 +182,6 @@ struct access access tree. */ unsigned grp_read : 1; - /* Does this group contain a read access that comes from an assignment - statement? This flag is propagated down the access tree. */ - unsigned grp_assignment_read : 1; - /* Other passes of the analysis use this bit to make function analyze_access_subtree create scalar replacements for this group if possible. */ @@ -904,9 +899,10 @@ disqualify_base_of_expr (tree t, const char *reason) created. */ static struct access * -build_access_from_expr_1 (tree expr, gimple stmt, bool write) +build_access_from_expr_1 (tree *expr_ptr, gimple stmt, bool write) { struct access *ret = NULL; + tree expr = *expr_ptr; bool partial_ref; if (TREE_CODE (expr) == BIT_FIELD_REF @@ -958,17 +954,18 @@ build_access_from_expr_1 (tree expr, gimple stmt, bool write) return ret; } -/* Scan expression EXPR and create access structures for all accesses to - candidates for scalarization. Return true if any access has been inserted. - STMT must be the statement from which the expression is taken, WRITE must be - true if the expression is a store and false otherwise. */ +/* Callback of scan_function. Scan expression EXPR and create access + structures for all accesses to candidates for scalarization. Return true if + any access has been inserted. */ static bool -build_access_from_expr (tree expr, gimple stmt, bool write) +build_access_from_expr (tree *expr_ptr, + gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, bool write, + void *data ATTRIBUTE_UNUSED) { struct access *access; - access = build_access_from_expr_1 (expr, stmt, write); + access = build_access_from_expr_1 (expr_ptr, gsi_stmt (*gsi), write); if (access) { /* This means the aggregate is accesses as a whole in a way other than an @@ -1000,42 +997,49 @@ disqualify_ops_if_throwing_stmt (gimple stmt, tree lhs, tree rhs) return false; } -/* Scan expressions occuring in STMT, create access structures for all accesses - to candidates for scalarization and remove those candidates which occur in + +/* Result code for scan_assign callback for scan_function. */ +enum scan_assign_result { SRA_SA_NONE, /* nothing done for the stmt */ + SRA_SA_PROCESSED, /* stmt analyzed/changed */ + SRA_SA_REMOVED }; /* stmt redundant and eliminated */ + + +/* Callback of scan_function. Scan expressions occuring in the statement + pointed to by STMT_EXPR, create access structures for all accesses to + candidates for scalarization and remove those candidates which occur in statements or expressions that prevent them from being split apart. Return true if any access has been inserted. */ -static bool -build_accesses_from_assign (gimple stmt) +static enum scan_assign_result +build_accesses_from_assign (gimple *stmt_ptr, + gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) { - tree lhs, rhs; + gimple stmt = *stmt_ptr; + tree *lhs_ptr, *rhs_ptr; struct access *lacc, *racc; if (!gimple_assign_single_p (stmt)) - return false; + return SRA_SA_NONE; - lhs = gimple_assign_lhs (stmt); - rhs = gimple_assign_rhs1 (stmt); + lhs_ptr = gimple_assign_lhs_ptr (stmt); + rhs_ptr = gimple_assign_rhs1_ptr (stmt); - if (disqualify_ops_if_throwing_stmt (stmt, lhs, rhs)) - return false; + if (disqualify_ops_if_throwing_stmt (stmt, *lhs_ptr, *rhs_ptr)) + return SRA_SA_NONE; - racc = build_access_from_expr_1 (rhs, stmt, false); - lacc = build_access_from_expr_1 (lhs, stmt, true); + racc = build_access_from_expr_1 (rhs_ptr, stmt, false); + lacc = build_access_from_expr_1 (lhs_ptr, stmt, true); - if (racc) - { - racc->grp_assignment_read = 1; - if (should_scalarize_away_bitmap && !gimple_has_volatile_ops (stmt) - && !is_gimple_reg_type (racc->type)) - bitmap_set_bit (should_scalarize_away_bitmap, DECL_UID (racc->base)); - } + if (should_scalarize_away_bitmap && !gimple_has_volatile_ops (stmt) + && racc && !is_gimple_reg_type (racc->type)) + bitmap_set_bit (should_scalarize_away_bitmap, DECL_UID (racc->base)); if (lacc && racc && (sra_mode == SRA_MODE_EARLY_INTRA || sra_mode == SRA_MODE_INTRA) && !lacc->grp_unscalarizable_region && !racc->grp_unscalarizable_region - && AGGREGATE_TYPE_P (TREE_TYPE (lhs)) + && AGGREGATE_TYPE_P (TREE_TYPE (*lhs_ptr)) /* FIXME: Turn the following line into an assert after PR 40058 is fixed. */ && lacc->size == racc->size @@ -1052,7 +1056,7 @@ build_accesses_from_assign (gimple stmt) add_link_to_rhs (racc, link); } - return lacc || racc; + return (lacc || racc) ? SRA_SA_PROCESSED : SRA_SA_NONE; } /* Callback of walk_stmt_load_store_addr_ops visit_addr used to determine @@ -1079,46 +1083,76 @@ callsite_has_enough_arguments_p (gimple call) return gimple_call_num_args (call) >= (unsigned) func_param_count; } -/* Scan function and look for interesting expressions and create access - structures for them. Return true iff any access is created. */ +/* Scan function and look for interesting statements. Return true if any has + been found or processed, as indicated by callbacks. SCAN_EXPR is a callback + called on all expressions within statements except assign statements and + those deemed entirely unsuitable for some reason (all operands in such + statements and expression are removed from candidate_bitmap). SCAN_ASSIGN + is a callback called on all assign statements, HANDLE_SSA_DEFS is a callback + called on assign statements and those call statements which have a lhs, it + can be NULL. ANALYSIS_STAGE is true when running in the analysis stage of a + pass and thus no statement is being modified. DATA is a pointer passed to + all callbacks. If any single callback returns true, this function also + returns true, otherwise it returns false. */ static bool -scan_function (void) +scan_function (bool (*scan_expr) (tree *, gimple_stmt_iterator *, bool, void *), + enum scan_assign_result (*scan_assign) (gimple *, + gimple_stmt_iterator *, + void *), + bool (*handle_ssa_defs)(gimple, void *), + bool analysis_stage, void *data) { + gimple_stmt_iterator gsi; basic_block bb; + unsigned i; + tree *t; bool ret = false; FOR_EACH_BB (bb) { - gimple_stmt_iterator gsi; - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + bool bb_changed = false; + + if (handle_ssa_defs) + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + ret |= handle_ssa_defs (gsi_stmt (gsi), data); + + gsi = gsi_start_bb (bb); + while (!gsi_end_p (gsi)) { gimple stmt = gsi_stmt (gsi); - tree t; - unsigned i; + enum scan_assign_result assign_result; + bool any = false, deleted = false; - if (final_bbs && stmt_can_throw_external (stmt)) + if (analysis_stage && final_bbs && stmt_can_throw_external (stmt)) bitmap_set_bit (final_bbs, bb->index); switch (gimple_code (stmt)) { case GIMPLE_RETURN: - t = gimple_return_retval (stmt); - if (t != NULL_TREE) - ret |= build_access_from_expr (t, stmt, false); - if (final_bbs) + t = gimple_return_retval_ptr (stmt); + if (*t != NULL_TREE) + any |= scan_expr (t, &gsi, false, data); + if (analysis_stage && final_bbs) bitmap_set_bit (final_bbs, bb->index); break; case GIMPLE_ASSIGN: - ret |= build_accesses_from_assign (stmt); + assign_result = scan_assign (&stmt, &gsi, data); + any |= assign_result == SRA_SA_PROCESSED; + deleted = assign_result == SRA_SA_REMOVED; + if (handle_ssa_defs && assign_result != SRA_SA_REMOVED) + any |= handle_ssa_defs (stmt, data); break; case GIMPLE_CALL: + /* Operands must be processed before the lhs. */ for (i = 0; i < gimple_call_num_args (stmt); i++) - ret |= build_access_from_expr (gimple_call_arg (stmt, i), - stmt, false); + { + tree *argp = gimple_call_arg_ptr (stmt, i); + any |= scan_expr (argp, &gsi, false, data); + } - if (sra_mode == SRA_MODE_EARLY_IPA) + if (analysis_stage && sra_mode == SRA_MODE_EARLY_IPA) { tree dest = gimple_call_fndecl (stmt); int flags = gimple_call_flags (stmt); @@ -1142,33 +1176,65 @@ scan_function (void) bitmap_set_bit (final_bbs, bb->index); } - t = gimple_call_lhs (stmt); - if (t && !disqualify_ops_if_throwing_stmt (stmt, t, NULL)) - ret |= build_access_from_expr (t, stmt, true); + if (gimple_call_lhs (stmt)) + { + tree *lhs_ptr = gimple_call_lhs_ptr (stmt); + if (!analysis_stage + || !disqualify_ops_if_throwing_stmt (stmt, + *lhs_ptr, NULL)) + { + any |= scan_expr (lhs_ptr, &gsi, true, data); + if (handle_ssa_defs) + any |= handle_ssa_defs (stmt, data); + } + } 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); - + if (analysis_stage) + { + walk_stmt_load_store_addr_ops (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); + tree *op = &TREE_VALUE (gimple_asm_input_op (stmt, i)); + any |= scan_expr (op, &gsi, false, data); } 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); + tree *op = &TREE_VALUE (gimple_asm_output_op (stmt, i)); + any |= scan_expr (op, &gsi, true, data); } break; default: break; } + + if (any) + { + ret = true; + + if (!analysis_stage) + { + bb_changed = true; + update_stmt (stmt); + maybe_clean_eh_stmt (stmt); + } + } + if (deleted) + bb_changed = true; + else + { + gsi_next (&gsi); + ret = true; + } } + if (!analysis_stage && bb_changed && sra_mode == SRA_MODE_EARLY_IPA) + gimple_purge_dead_eh_edges (bb); } return ret; @@ -1514,7 +1580,6 @@ sort_and_splice_var_accesses (tree var) struct access *access = VEC_index (access_p, access_vec, i); bool grp_write = access->write; bool grp_read = !access->write; - bool grp_assignment_read = access->grp_assignment_read; bool multiple_reads = false; bool total_scalarization = access->total_scalarization; bool grp_partial_lhs = access->grp_partial_lhs; @@ -1548,7 +1613,6 @@ sort_and_splice_var_accesses (tree var) else grp_read = true; } - grp_assignment_read |= ac2->grp_assignment_read; grp_partial_lhs |= ac2->grp_partial_lhs; unscalarizable_region |= ac2->grp_unscalarizable_region; total_scalarization |= ac2->total_scalarization; @@ -1567,7 +1631,6 @@ sort_and_splice_var_accesses (tree var) access->group_representative = access; access->grp_write = grp_write; access->grp_read = grp_read; - access->grp_assignment_read = grp_assignment_read; access->grp_hint = multiple_reads || total_scalarization; access->grp_partial_lhs = grp_partial_lhs; access->grp_unscalarizable_region = unscalarizable_region; @@ -1587,15 +1650,14 @@ sort_and_splice_var_accesses (tree var) ACCESS->replacement. */ static tree -create_access_replacement (struct access *access, bool rename) +create_access_replacement (struct access *access) { tree repl; repl = create_tmp_var (access->type, "SR"); get_var_ann (repl); add_referenced_var (repl); - if (rename) - mark_sym_for_renaming (repl); + mark_sym_for_renaming (repl); if (!access->grp_partial_lhs && (TREE_CODE (access->type) == COMPLEX_TYPE @@ -1611,38 +1673,11 @@ create_access_replacement (struct access *access, bool rename) && !DECL_ARTIFICIAL (access->base)) { char *pretty_name = make_fancy_name (access->expr); - tree debug_expr = unshare_expr (access->expr), d; DECL_NAME (repl) = get_identifier (pretty_name); obstack_free (&name_obstack, pretty_name); - /* Get rid of any SSA_NAMEs embedded in debug_expr, - as DECL_DEBUG_EXPR isn't considered when looking for still - used SSA_NAMEs and thus they could be freed. All debug info - generation cares is whether something is constant or variable - and that get_ref_base_and_extent works properly on the - expression. */ - for (d = debug_expr; handled_component_p (d); d = TREE_OPERAND (d, 0)) - switch (TREE_CODE (d)) - { - case ARRAY_REF: - case ARRAY_RANGE_REF: - if (TREE_OPERAND (d, 1) - && TREE_CODE (TREE_OPERAND (d, 1)) == SSA_NAME) - TREE_OPERAND (d, 1) = SSA_NAME_VAR (TREE_OPERAND (d, 1)); - if (TREE_OPERAND (d, 3) - && TREE_CODE (TREE_OPERAND (d, 3)) == SSA_NAME) - TREE_OPERAND (d, 3) = SSA_NAME_VAR (TREE_OPERAND (d, 3)); - /* FALLTHRU */ - case COMPONENT_REF: - if (TREE_OPERAND (d, 2) - && TREE_CODE (TREE_OPERAND (d, 2)) == SSA_NAME) - TREE_OPERAND (d, 2) = SSA_NAME_VAR (TREE_OPERAND (d, 2)); - break; - default: - break; - } - SET_DECL_DEBUG_EXPR (repl, debug_expr); + SET_DECL_DEBUG_EXPR (repl, access->expr); DECL_DEBUG_EXPR_IS_FROM (repl) = 1; TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base); } @@ -1671,24 +1706,10 @@ get_access_replacement (struct access *access) gcc_assert (access->grp_to_be_replaced); if (!access->replacement_decl) - access->replacement_decl = create_access_replacement (access, true); - return access->replacement_decl; -} - -/* Return ACCESS scalar replacement, create it if it does not exist yet but do - not mark it for renaming. */ - -static inline tree -get_unrenamed_access_replacement (struct access *access) -{ - gcc_assert (!access->grp_to_be_replaced); - - if (!access->replacement_decl) - access->replacement_decl = create_access_replacement (access, false); + access->replacement_decl = create_access_replacement (access); return access->replacement_decl; } - /* Build a subtree of accesses rooted in *ACCESS, and move the pointer in the linked list along the way. Stop when *ACCESS is NULL or the access pointed to it is not "within" the root. */ @@ -1744,17 +1765,14 @@ expr_with_var_bounded_array_refs_p (tree expr) return false; } -enum mark_read_status { SRA_MR_NOT_READ, SRA_MR_READ, SRA_MR_ASSIGN_READ}; - /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when - both seeming beneficial and when ALLOW_REPLACEMENTS allows it. Also set all - sorts of access flags appropriately along the way, notably always set - grp_read and grp_assign_read according to MARK_READ and grp_write when - MARK_WRITE is true. */ + both seeming beneficial and when ALLOW_REPLACEMENTS allows it. Also set + all sorts of access flags appropriately along the way, notably always ser + grp_read when MARK_READ is true and grp_write when MARK_WRITE is true. */ static bool analyze_access_subtree (struct access *root, bool allow_replacements, - enum mark_read_status mark_read, bool mark_write) + bool mark_read, bool mark_write) { struct access *child; HOST_WIDE_INT limit = root->offset + root->size; @@ -1763,17 +1781,10 @@ analyze_access_subtree (struct access *root, bool allow_replacements, bool hole = false, sth_created = false; bool direct_read = root->grp_read; - if (mark_read == SRA_MR_ASSIGN_READ) - { - root->grp_read = 1; - root->grp_assignment_read = 1; - } - if (mark_read == SRA_MR_READ) - root->grp_read = 1; - else if (root->grp_assignment_read) - mark_read = SRA_MR_ASSIGN_READ; + if (mark_read) + root->grp_read = true; else if (root->grp_read) - mark_read = SRA_MR_READ; + mark_read = true; if (mark_write) root->grp_write = true; @@ -1802,7 +1813,7 @@ analyze_access_subtree (struct access *root, bool allow_replacements, if (allow_replacements && scalar && !root->first_child && (root->grp_hint - || (root->grp_write && (direct_read || root->grp_assignment_read))) + || (direct_read && root->grp_write)) /* We must not ICE later on when trying to build an access to the original data within the aggregate even when it is impossible to do in a defined way like in the PR 42703 testcase. Therefore we check @@ -1847,7 +1858,7 @@ analyze_access_trees (struct access *access) while (access) { - if (analyze_access_subtree (access, true, SRA_MR_NOT_READ, false)) + if (analyze_access_subtree (access, true, false, false)) ret = true; access = access->next_grp; } @@ -2268,14 +2279,15 @@ get_access_for_expr (tree expr) return get_var_base_offset_size_access (base, offset, max_size); } -/* Replace the expression EXPR with a scalar replacement if there is one and - generate other statements to do type conversion or subtree copying if - necessary. GSI is used to place newly created statements, WRITE is true if - the expression is being written to (it is on a LHS of a statement or output - in an assembly statement). */ +/* Callback for scan_function. Replace the expression EXPR with a scalar + replacement if there is one and generate other statements to do type + conversion or subtree copying if necessary. GSI is used to place newly + created statements, WRITE is true if the expression is being written to (it + is on a LHS of a statement or output in an assembly statement). */ static bool -sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write) +sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write, + void *data ATTRIBUTE_UNUSED) { struct access *access; tree type, bfr; @@ -2477,17 +2489,11 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc, while (lacc); } -/* Result code for SRA assignment modification. */ -enum assignment_mod_result { SRA_AM_NONE, /* nothing done for the stmt */ - SRA_AM_MODIFIED, /* stmt changed but not - removed */ - SRA_AM_REMOVED }; /* stmt eliminated */ - /* Modify assignments with a CONSTRUCTOR on their RHS. STMT contains a pointer to the assignment and GSI is the statement iterator pointing at it. Returns the same values as sra_modify_assign. */ -static enum assignment_mod_result +static enum scan_assign_result sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi) { tree lhs = gimple_assign_lhs (*stmt); @@ -2495,7 +2501,7 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi) acc = get_access_for_expr (lhs); if (!acc) - return SRA_AM_NONE; + return SRA_SA_NONE; if (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (gimple_assign_rhs1 (*stmt))) > 0) @@ -2505,7 +2511,7 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi) if (access_has_children_p (acc)) generate_subtree_copies (acc->first_child, acc->base, 0, 0, 0, gsi, true, true); - return SRA_AM_MODIFIED; + return SRA_SA_PROCESSED; } if (acc->grp_covered) @@ -2513,44 +2519,54 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi) init_subtree_with_zero (acc, gsi, false); unlink_stmt_vdef (*stmt); gsi_remove (gsi, true); - return SRA_AM_REMOVED; + return SRA_SA_REMOVED; } else { init_subtree_with_zero (acc, gsi, true); - return SRA_AM_MODIFIED; + return SRA_SA_PROCESSED; } } /* Create a new suitable default definition SSA_NAME and replace all uses of - SSA with it, RACC is access describing the uninitialized part of an - aggregate that is being loaded. */ + SSA with it. */ static void -replace_uses_with_default_def_ssa_name (tree ssa, struct access *racc) +replace_uses_with_default_def_ssa_name (tree ssa) { - tree repl, decl; - - decl = get_unrenamed_access_replacement (racc); + tree repl, decl = SSA_NAME_VAR (ssa); + if (TREE_CODE (decl) == PARM_DECL) + { + tree tmp = create_tmp_reg (TREE_TYPE (decl), "SR"); - repl = gimple_default_def (cfun, decl); - if (!repl) + get_var_ann (tmp); + add_referenced_var (tmp); + repl = make_ssa_name (tmp, gimple_build_nop ()); + set_default_def (tmp, repl); + } + else { - repl = make_ssa_name (decl, gimple_build_nop ()); - set_default_def (decl, repl); + repl = gimple_default_def (cfun, decl); + if (!repl) + { + repl = make_ssa_name (decl, gimple_build_nop ()); + set_default_def (decl, repl); + } } replace_uses_by (ssa, repl); } -/* Examine both sides of the assignment statement pointed to by STMT, replace - them with a scalare replacement if there is one and generate copying of - replacements if scalarized aggregates have been used in the assignment. GSI - is used to hold generated statements for type conversions and subtree +/* Callback of scan_function to process assign statements. It examines both + sides of the statement, replaces them with a scalare replacement if there is + one and generating copying of replacements if scalarized aggregates have been + used in the assignment. STMT is a pointer to the assign statement, GSI is + used to hold generated statements for type conversions and subtree copying. */ -static enum assignment_mod_result -sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) +static enum scan_assign_result +sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi, + void *data ATTRIBUTE_UNUSED) { struct access *lacc, *racc; tree lhs, rhs; @@ -2560,7 +2576,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) gimple_stmt_iterator orig_gsi = *gsi; if (!gimple_assign_single_p (*stmt)) - return SRA_AM_NONE; + return SRA_SA_NONE; lhs = gimple_assign_lhs (*stmt); rhs = gimple_assign_rhs1 (*stmt); @@ -2572,16 +2588,16 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) || TREE_CODE (rhs) == BIT_FIELD_REF || TREE_CODE (lhs) == BIT_FIELD_REF) { modify_this_stmt = sra_modify_expr (gimple_assign_rhs1_ptr (*stmt), - gsi, false); + gsi, false, data); modify_this_stmt |= sra_modify_expr (gimple_assign_lhs_ptr (*stmt), - gsi, true); - return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE; + gsi, true, data); + return modify_this_stmt ? SRA_SA_PROCESSED : SRA_SA_NONE; } lacc = get_access_for_expr (lhs); racc = get_access_for_expr (rhs); if (!lacc && !racc) - return SRA_AM_NONE; + return SRA_SA_NONE; if (lacc && lacc->grp_to_be_replaced) { @@ -2710,7 +2726,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) unlink_stmt_vdef (*stmt); gsi_remove (&orig_gsi, true); sra_stats.deleted++; - return SRA_AM_REMOVED; + return SRA_SA_REMOVED; } } else @@ -2725,12 +2741,12 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) false, false); gcc_assert (*stmt == gsi_stmt (*gsi)); if (TREE_CODE (lhs) == SSA_NAME) - replace_uses_with_default_def_ssa_name (lhs, racc); + replace_uses_with_default_def_ssa_name (lhs); unlink_stmt_vdef (*stmt); gsi_remove (gsi, true); sra_stats.deleted++; - return SRA_AM_REMOVED; + return SRA_SA_REMOVED; } else if (racc->first_child) generate_subtree_copies (racc->first_child, lhs, @@ -2753,83 +2769,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) gcc_assert (*stmt == gsi_stmt (orig_gsi)); } - return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE; -} - -/* Traverse the function body and all modifications as decided in - analyze_all_variable_accesses. */ - -static void -sra_modify_function_body (void) -{ - basic_block bb; - - FOR_EACH_BB (bb) - { - gimple_stmt_iterator gsi = gsi_start_bb (bb); - while (!gsi_end_p (gsi)) - { - gimple stmt = gsi_stmt (gsi); - enum assignment_mod_result assign_result; - bool modified = false, deleted = false; - tree *t; - unsigned i; - - switch (gimple_code (stmt)) - { - case GIMPLE_RETURN: - t = gimple_return_retval_ptr (stmt); - if (*t != NULL_TREE) - modified |= sra_modify_expr (t, &gsi, false); - break; - - case GIMPLE_ASSIGN: - assign_result = sra_modify_assign (&stmt, &gsi); - modified |= assign_result == SRA_AM_MODIFIED; - deleted = assign_result == SRA_AM_REMOVED; - 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 |= sra_modify_expr (t, &gsi, false); - } - - if (gimple_call_lhs (stmt)) - { - t = gimple_call_lhs_ptr (stmt); - modified |= sra_modify_expr (t, &gsi, true); - } - 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); - } - break; - - default: - break; - } - - if (modified) - { - update_stmt (stmt); - maybe_clean_eh_stmt (stmt); - } - if (!deleted) - gsi_next (&gsi); - } - } + return modify_this_stmt ? SRA_SA_PROCESSED : SRA_SA_NONE; } /* Generate statements initializing scalar replacements of parts of function @@ -2883,13 +2823,14 @@ perform_intra_sra (void) if (!find_var_candidates ()) goto out; - if (!scan_function ()) + if (!scan_function (build_access_from_expr, build_accesses_from_assign, NULL, + true, NULL)) goto out; if (!analyze_all_variable_accesses ()) goto out; - sra_modify_function_body (); + scan_function (sra_modify_expr, sra_modify_assign, NULL, false, NULL); initialize_parameter_reductions (); statistics_counter_event (cfun, "Scalar replacements created", @@ -3824,18 +3765,20 @@ get_adjustment_for_base (ipa_parm_adjustment_vec adjustments, tree base) return NULL; } -/* If the statement STMT defines an SSA_NAME of a parameter which is to be - removed because its value is not used, replace the SSA_NAME with a one - relating to a created VAR_DECL together all of its uses and return true. - ADJUSTMENTS is a pointer to an adjustments vector. */ +/* Callback for scan_function. If the statement STMT defines an SSA_NAME of a + parameter which is to be removed because its value is not used, replace the + SSA_NAME with a one relating to a created VAR_DECL and replace all of its + uses too and return true (update_stmt is then issued for the statement by + the caller). DATA is a pointer to an adjustments vector. */ static bool -replace_removed_params_ssa_names (gimple stmt, - ipa_parm_adjustment_vec adjustments) +replace_removed_params_ssa_names (gimple stmt, void *data) { + VEC (ipa_parm_adjustment_t, heap) *adjustments; struct ipa_parm_adjustment *adj; tree lhs, decl, repl, name; + adjustments = (VEC (ipa_parm_adjustment_t, heap) *) data; if (gimple_code (stmt) == GIMPLE_PHI) lhs = gimple_phi_result (stmt); else if (is_gimple_assign (stmt)) @@ -3878,22 +3821,27 @@ replace_removed_params_ssa_names (gimple stmt, 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. */ +/* Callback for scan_function and helper to sra_ipa_modify_assign. If the + expression *EXPR should be replaced by a reduction of a parameter, do so. + DATA is a pointer to a vector of adjustments. DONT_CONVERT specifies + whether the function should care about type incompatibility the current and + new expressions. If it is true, the function will leave incompatibility + issues to the caller. + + When called directly by scan_function, DONT_CONVERT is true when the EXPR is + a write (LHS) expression. */ static bool -sra_ipa_modify_expr (tree *expr, bool convert, - ipa_parm_adjustment_vec adjustments) +sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, + bool dont_convert, void *data) { + 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; + adjustments = (VEC (ipa_parm_adjustment_t, heap) *) data; len = VEC_length (ipa_parm_adjustment_t, adjustments); if (TREE_CODE (*expr) == BIT_FIELD_REF @@ -3901,7 +3849,7 @@ sra_ipa_modify_expr (tree *expr, bool convert, || TREE_CODE (*expr) == REALPART_EXPR) { expr = &TREE_OPERAND (*expr, 0); - convert = true; + dont_convert = false; } base = get_ref_base_and_extent (*expr, &offset, &size, &max_size); @@ -3950,7 +3898,8 @@ sra_ipa_modify_expr (tree *expr, bool convert, fprintf (dump_file, "\n"); } - if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type)) + if (!dont_convert + && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type)) { tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src); *expr = vce; @@ -3960,28 +3909,24 @@ sra_ipa_modify_expr (tree *expr, bool convert, 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. */ +/* Callback for scan_function to process assign statements. Performs + essentially the same function like sra_ipa_modify_expr. */ -static bool -sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi, - ipa_parm_adjustment_vec adjustments) +static enum scan_assign_result +sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi, void *data) { gimple stmt = *stmt_ptr; tree *lhs_p, *rhs_p; bool any; if (!gimple_assign_single_p (stmt)) - return false; + return SRA_SA_NONE; 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 = sra_ipa_modify_expr (rhs_p, gsi, true, data); + any |= sra_ipa_modify_expr (lhs_p, gsi, true, data); if (any) { tree new_rhs = NULL_TREE; @@ -4017,94 +3962,10 @@ sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi, gimple_assign_set_rhs_from_tree (gsi, tmp); } - return true; + return SRA_SA_PROCESSED; } - return false; -} - -/* Traverse the function body and all modifications as described in - ADJUSTMENTS. */ - -static void -ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments) -{ - basic_block bb; - - FOR_EACH_BB (bb) - { - gimple_stmt_iterator gsi; - bool bb_changed = false; - - for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - replace_removed_params_ssa_names (gsi_stmt (gsi), adjustments); - - 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 (stmt); - if (*t != NULL_TREE) - modified |= sra_ipa_modify_expr (t, true, adjustments); - break; - - case GIMPLE_ASSIGN: - modified |= sra_ipa_modify_assign (&stmt, &gsi, adjustments); - modified |= replace_removed_params_ssa_names (stmt, 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 |= sra_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 |= 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); - } - break; - - default: - break; - } - - if (modified) - { - bb_changed = true; - update_stmt (stmt); - maybe_clean_eh_stmt (stmt); - } - gsi_next (&gsi); - } - if (bb_changed) - gimple_purge_dead_eh_edges (bb); - } + return SRA_SA_NONE; } /* Call gimple_debug_bind_reset_value on all debug statements describing @@ -4131,8 +3992,7 @@ sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments) continue; FOR_EACH_IMM_USE_STMT (stmt, ui, name) { - /* All other users must have been removed by - ipa_sra_modify_function_body. */ + /* All other users must have been removed by scan_function. */ gcc_assert (is_gimple_debug (stmt)); gimple_debug_bind_reset_value (stmt); update_stmt (stmt); @@ -4250,7 +4110,8 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments) as following functions will use what it computed. */ create_abstract_origin (current_function_decl); ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA"); - ipa_sra_modify_function_body (adjustments); + scan_function (sra_ipa_modify_expr, sra_ipa_modify_assign, + replace_removed_params_ssa_names, false, adjustments); sra_ipa_reset_debug_stmts (adjustments); convert_callers (node, adjustments); cgraph_make_node_local (node); @@ -4301,9 +4162,6 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node) return false; } - if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl))) - return false; - return true; } @@ -4342,7 +4200,8 @@ ipa_early_sra (void) * last_basic_block_for_function (cfun)); final_bbs = BITMAP_ALLOC (NULL); - scan_function (); + scan_function (build_access_from_expr, build_accesses_from_assign, + NULL, true, NULL); if (encountered_apply_args) { if (dump_file)