X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-sra.c;h=e1dd0d777e377ea9c380153c48f7be8cc3102b06;hb=c88fdff58434a1649af63179686c73ee38b339d3;hp=bc729ba5256db0ad4cc82f99d11628a9676af4a8;hpb=00bba8d6e417b2a2a86dc65acb05aa05417bb649;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index bc729ba5256..e1dd0d777e3 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -77,6 +77,7 @@ along with GCC; see the file COPYING3. If not see #include "alloc-pool.h" #include "tm.h" #include "tree.h" +#include "expr.h" #include "gimple.h" #include "cgraph.h" #include "tree-flow.h" @@ -166,6 +167,10 @@ struct access /* Is this particular access write access? */ unsigned write : 1; + /* Is this access an artificial one created to scalarize some record + entirely? */ + unsigned total_scalarization : 1; + /* Is this access currently in the work queue? */ unsigned grp_queued : 1; @@ -244,6 +249,10 @@ static struct pointer_map_t *base_access_vec; /* Bitmap of candidates. */ static bitmap candidate_bitmap; +/* Bitmap of candidates which we should try to entirely scalarize away and + those which cannot be (because they are and need be used as a whole). */ +static bitmap should_scalarize_away_bitmap, cannot_scalarize_away_bitmap; + /* Obstack for creation of fancy names. */ static struct obstack name_obstack; @@ -343,18 +352,22 @@ dump_access (FILE *f, struct access *access, bool grp) fprintf (f, ", type = "); print_generic_expr (f, access->type, 0); if (grp) - fprintf (f, ", grp_write = %d, grp_read = %d, grp_hint = %d, " + fprintf (f, ", grp_write = %d, total_scalarization = %d, " + "grp_read = %d, 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_not_necessarilly_dereferenced = %d\n", - access->grp_write, access->grp_read, access->grp_hint, + access->grp_write, access->total_scalarization, + access->grp_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_not_necessarilly_dereferenced); else - fprintf (f, ", write = %d, grp_partial_lhs = %d\n", access->write, + fprintf (f, ", write = %d, total_scalarization = %d, " + "grp_partial_lhs = %d\n", + access->write, access->total_scalarization, access->grp_partial_lhs); } @@ -546,6 +559,8 @@ static void sra_initialize (void) { candidate_bitmap = BITMAP_ALLOC (NULL); + 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); @@ -575,6 +590,8 @@ static void sra_deinitialize (void) { BITMAP_FREE (candidate_bitmap); + 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); @@ -685,6 +702,37 @@ mark_parm_dereference (tree base, HOST_WIDE_INT dist, gimple stmt) bb_dereferences[idx] = dist; } +/* Allocate an access structure for BASE, OFFSET and SIZE, clear it, fill in + the three fields. Also add it to the vector of accesses corresponding to + the base. Finally, return the new access. */ + +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->base = base; + 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; + + return access; +} + /* Create and insert access for EXPR. Return created access, or NULL if it is not possible. */ @@ -692,8 +740,6 @@ static struct access * create_access (tree expr, gimple stmt, bool write) { struct access *access; - void **slot; - VEC (access_p,heap) *vec; HOST_WIDE_INT offset, size, max_size; tree base = expr; bool ptr, unscalarizable_region = false; @@ -744,30 +790,87 @@ create_access (tree expr, gimple stmt, bool write) } } - access = (struct access *) pool_alloc (access_pool); - memset (access, 0, sizeof (struct access)); - - access->base = base; - access->offset = offset; - access->size = size; + access = create_access_1 (base, offset, size); access->expr = expr; access->type = TREE_TYPE (expr); access->write = write; access->grp_unscalarizable_region = unscalarizable_region; access->stmt = stmt; - slot = pointer_map_contains (base_access_vec, base); - if (slot) - vec = (VEC (access_p, heap) *) *slot; - else - vec = VEC_alloc (access_p, heap, 32); + return access; +} - VEC_safe_push (access_p, heap, vec, access); - *((struct VEC (access_p,heap) **) - pointer_map_insert (base_access_vec, base)) = vec; +/* Return true iff TYPE is a RECORD_TYPE with fields that are either of gimple + register types or (recursively) records with only these two kinds of fields. + It also returns false if any of these records has a zero-size field as its + last field. */ - return access; +static bool +type_consists_of_records_p (tree type) +{ + tree fld; + bool last_fld_has_zero_size = false; + + if (TREE_CODE (type) != RECORD_TYPE) + return false; + + for (fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld)) + if (TREE_CODE (fld) == FIELD_DECL) + { + tree ft = TREE_TYPE (fld); + + if (!is_gimple_reg_type (ft) + && !type_consists_of_records_p (ft)) + return false; + + last_fld_has_zero_size = tree_low_cst (DECL_SIZE (fld), 1) == 0; + } + + if (last_fld_has_zero_size) + return false; + + return true; +} + +/* Create total_scalarization accesses for all scalar type fields in DECL that + must be of a RECORD_TYPE conforming to type_consists_of_records_p. BASE + must be the top-most VAR_DECL representing the variable, OFFSET must be the + offset of DECL within BASE. */ + +static void +completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset) +{ + tree fld, decl_type = TREE_TYPE (decl); + + for (fld = TYPE_FIELDS (decl_type); fld; fld = TREE_CHAIN (fld)) + if (TREE_CODE (fld) == FIELD_DECL) + { + HOST_WIDE_INT pos = offset + int_bit_position (fld); + tree ft = TREE_TYPE (fld); + + if (is_gimple_reg_type (ft)) + { + struct access *access; + HOST_WIDE_INT size; + tree expr; + bool ok; + + size = tree_low_cst (DECL_SIZE (fld), 1); + expr = base; + ok = build_ref_for_offset (&expr, TREE_TYPE (base), pos, + ft, false); + gcc_assert (ok); + + access = create_access_1 (base, pos, size); + access->expr = expr; + access->type = ft; + access->total_scalarization = 1; + /* Accesses for intraprocedural SRA can have their stmt NULL. */ + } + else + completely_scalarize_record (base, fld, pos); + } } @@ -860,7 +963,19 @@ build_access_from_expr (tree *expr_ptr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, bool write, void *data ATTRIBUTE_UNUSED) { - return build_access_from_expr_1 (expr_ptr, gsi_stmt (*gsi), write) != NULL; + struct access *access; + + 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 + assign statement and thus cannot be removed even if we had a scalar + replacement for everything. */ + if (cannot_scalarize_away_bitmap) + bitmap_set_bit (cannot_scalarize_away_bitmap, DECL_UID (access->base)); + return true; + } + return false; } /* Disqualify LHS and RHS for scalarization if STMT must end its basic block in @@ -916,6 +1031,10 @@ build_accesses_from_assign (gimple *stmt_ptr, racc = build_access_from_expr_1 (rhs_ptr, stmt, false); lacc = build_access_from_expr_1 (lhs_ptr, stmt, true); + 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 @@ -1321,7 +1440,7 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset, el_size = tree_low_cst (tr_size, 1); minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); - if (TREE_CODE (minidx) != INTEGER_CST) + if (TREE_CODE (minidx) != INTEGER_CST || el_size == 0) return false; if (res) { @@ -1460,6 +1579,7 @@ sort_and_splice_var_accesses (tree var) bool grp_write = access->write; bool grp_read = !access->write; bool multiple_reads = false; + bool total_scalarization = access->total_scalarization; bool grp_partial_lhs = access->grp_partial_lhs; bool first_scalar = is_gimple_reg_type (access->type); bool unscalarizable_region = access->grp_unscalarizable_region; @@ -1493,6 +1613,7 @@ sort_and_splice_var_accesses (tree var) } grp_partial_lhs |= ac2->grp_partial_lhs; unscalarizable_region |= ac2->grp_unscalarizable_region; + total_scalarization |= ac2->total_scalarization; relink_to_new_repr (access, ac2); /* If there are both aggregate-type and scalar-type accesses with @@ -1508,7 +1629,7 @@ sort_and_splice_var_accesses (tree var) access->group_representative = access; access->grp_write = grp_write; access->grp_read = grp_read; - access->grp_hint = multiple_reads; + access->grp_hint = multiple_reads || total_scalarization; access->grp_partial_lhs = grp_partial_lhs; access->grp_unscalarizable_region = unscalarizable_region; if (access->first_link) @@ -1543,6 +1664,7 @@ create_access_replacement (struct access *access) DECL_SOURCE_LOCATION (repl) = DECL_SOURCE_LOCATION (access->base); DECL_ARTIFICIAL (repl) = 1; + DECL_IGNORED_P (repl) = DECL_IGNORED_P (access->base); if (DECL_NAME (access->base) && !DECL_IGNORED_P (access->base) @@ -1555,11 +1677,10 @@ create_access_replacement (struct access *access) SET_DECL_DEBUG_EXPR (repl, access->expr); DECL_DEBUG_EXPR_IS_FROM (repl) = 1; - DECL_IGNORED_P (repl) = 0; + TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base); } - - DECL_IGNORED_P (repl) = DECL_IGNORED_P (access->base); - TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base); + else + TREE_NO_WARNING (repl) = 1; if (dump_file) { @@ -1918,7 +2039,31 @@ analyze_all_variable_accesses (void) int res = 0; bitmap tmp = BITMAP_ALLOC (NULL); bitmap_iterator bi; - unsigned i; + unsigned i, max_total_scalarization_size; + + max_total_scalarization_size = UNITS_PER_WORD * BITS_PER_UNIT + * MOVE_RATIO (optimize_function_for_speed_p (cfun)); + + EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi) + if (bitmap_bit_p (should_scalarize_away_bitmap, i) + && !bitmap_bit_p (cannot_scalarize_away_bitmap, i)) + { + tree var = referenced_var (i); + + if (TREE_CODE (var) == VAR_DECL + && ((unsigned) tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1) + <= max_total_scalarization_size) + && type_consists_of_records_p (TREE_TYPE (var))) + { + completely_scalarize_record (var, var, 0); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Will attempt to totally scalarize "); + print_generic_expr (dump_file, var, 0); + fprintf (dump_file, " (UID: %u): \n", DECL_UID (var)); + } + } + } bitmap_copy (tmp, candidate_bitmap); EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi) @@ -2398,6 +2543,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi, bool modify_this_stmt = false; bool force_gimple_rhs = false; location_t loc = gimple_location (*stmt); + gimple_stmt_iterator orig_gsi = *gsi; if (!gimple_assign_single_p (*stmt)) return SRA_SA_NONE; @@ -2476,15 +2622,6 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi, force_gimple_rhs = true; } } - - if (force_gimple_rhs) - rhs = force_gimple_operand_gsi (gsi, rhs, true, NULL_TREE, - true, GSI_SAME_STMT); - if (gimple_assign_rhs1 (*stmt) != rhs) - { - gimple_assign_set_rhs_from_tree (gsi, rhs); - gcc_assert (*stmt == gsi_stmt (*gsi)); - } } /* From this point on, the function deals with assignments in between @@ -2520,7 +2657,9 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi, there to do the copying and then load the scalar replacements of the LHS. This is what the first branch does. */ - if (contains_view_convert_expr_p (rhs) || contains_view_convert_expr_p (lhs) + if (gimple_has_volatile_ops (*stmt) + || contains_view_convert_expr_p (rhs) + || contains_view_convert_expr_p (lhs) || (access_has_children_p (racc) && !ref_expr_for_all_replacements_p (racc, lhs, racc->offset)) || (access_has_children_p (lacc) @@ -2586,6 +2725,18 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi, 0, 0, gsi, true, true); } } + + /* This gimplification must be done after generate_subtree_copies, lest we + insert the subtree copies in the middle of the gimplified sequence. */ + 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) + { + gimple_assign_set_rhs_from_tree (&orig_gsi, rhs); + gcc_assert (*stmt == gsi_stmt (orig_gsi)); + } + return modify_this_stmt ? SRA_SA_PROCESSED : SRA_SA_NONE; } @@ -2764,42 +2915,51 @@ ptr_parm_has_direct_uses (tree parm) FOR_EACH_IMM_USE_STMT (stmt, ui, name) { - if (gimple_assign_single_p (stmt)) + int uses_ok = 0; + use_operand_p use_p; + + if (is_gimple_debug (stmt)) + continue; + + /* Valid uses include dereferences on the lhs and the rhs. */ + if (gimple_has_lhs (stmt)) { - tree rhs = gimple_assign_rhs1 (stmt); - if (rhs == name) - ret = true; - else if (TREE_CODE (rhs) == ADDR_EXPR) - { - do - { - rhs = TREE_OPERAND (rhs, 0); - } - while (handled_component_p (rhs)); - if (INDIRECT_REF_P (rhs) && TREE_OPERAND (rhs, 0) == name) - ret = true; - } + tree lhs = gimple_get_lhs (stmt); + while (handled_component_p (lhs)) + lhs = TREE_OPERAND (lhs, 0); + if (INDIRECT_REF_P (lhs) + && TREE_OPERAND (lhs, 0) == name) + uses_ok++; } - else if (gimple_code (stmt) == GIMPLE_RETURN) + if (gimple_assign_single_p (stmt)) { - tree t = gimple_return_retval (stmt); - if (t == name) - ret = true; + tree rhs = gimple_assign_rhs1 (stmt); + while (handled_component_p (rhs)) + rhs = TREE_OPERAND (rhs, 0); + if (INDIRECT_REF_P (rhs) + && TREE_OPERAND (rhs, 0) == name) + uses_ok++; } else if (is_gimple_call (stmt)) { unsigned i; - for (i = 0; i < gimple_call_num_args (stmt); i++) + for (i = 0; i < gimple_call_num_args (stmt); ++i) { tree arg = gimple_call_arg (stmt, i); - if (arg == name) - { - ret = true; - break; - } + while (handled_component_p (arg)) + arg = TREE_OPERAND (arg, 0); + if (INDIRECT_REF_P (arg) + && TREE_OPERAND (arg, 0) == name) + uses_ok++; } } - else if (!is_gimple_debug (stmt)) + + /* If the number of valid uses does not match the number of + uses in this stmt there is an unhandled use. */ + FOR_EACH_IMM_USE_ON_STMT (use_p, ui) + --uses_ok; + + if (uses_ok != 0) ret = true; if (ret) @@ -3888,6 +4048,26 @@ convert_callers (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments) return; } +/* Create an abstract origin declaration for OLD_DECL and make it an abstract + origin of the provided decl so that there are preserved parameters for debug + information. */ + +static void +create_abstract_origin (tree old_decl) +{ + if (!DECL_ABSTRACT_ORIGIN (old_decl)) + { + tree new_decl = copy_node (old_decl); + + DECL_ABSTRACT (new_decl) = 1; + SET_DECL_ASSEMBLER_NAME (new_decl, NULL_TREE); + SET_DECL_RTL (new_decl, NULL); + DECL_STRUCT_FUNCTION (new_decl) = NULL; + DECL_ARTIFICIAL (old_decl) = 1; + DECL_ABSTRACT_ORIGIN (old_decl) = new_decl; + } +} + /* Perform all the modification required in IPA-SRA for NODE to have parameters as given in ADJUSTMENTS. */ @@ -3899,6 +4079,7 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments) ipa_modify_formal_parameters (alias->decl, adjustments, "ISRA"); /* current_function_decl must be handled last, after same_body aliases, as following functions will use what it computed. */ + create_abstract_origin (current_function_decl); ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA"); scan_function (sra_ipa_modify_expr, sra_ipa_modify_assign, replace_removed_params_ssa_names, false, adjustments);