diff options
Diffstat (limited to 'gcc/tree-sra.c')
-rw-r--r-- | gcc/tree-sra.c | 178 |
1 files changed, 162 insertions, 16 deletions
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 5acb6125079..bf1a0f209f6 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -1,7 +1,7 @@ /* 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, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Martin Jambor <mjambor@suse.cz> This file is part of GCC. @@ -227,6 +227,10 @@ struct access /* 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; @@ -390,7 +394,7 @@ dump_access (FILE *f, struct access *access, bool grp) "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, @@ -398,7 +402,7 @@ dump_access (FILE *f, struct access *access, bool grp) 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, " @@ -1528,6 +1532,43 @@ build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset, 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 @@ -1861,7 +1902,13 @@ create_access_replacement (struct access *access) { tree repl; - repl = create_tmp_var (access->type, "SR"); + if (access->grp_to_be_debug_replaced) + { + repl = create_tmp_var_raw (access->type, NULL); + 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) { @@ -1894,7 +1941,8 @@ create_access_replacement (struct access *access) 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)) { @@ -1912,6 +1960,12 @@ create_access_replacement (struct access *access) && 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; } @@ -1930,12 +1984,22 @@ create_access_replacement (struct access *access) 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++; @@ -2144,6 +2208,23 @@ analyze_access_subtree (struct access *root, struct access *parent, } else { + if (MAY_HAVE_DEBUG_STMTS && allow_replacements + && scalar && !root->first_child + && (root->grp_scalar_write || root->grp_assignment_write)) + { + gcc_checking_assert (!root->grp_scalar_read + && !root->grp_assignment_read); + root->grp_to_be_debug_replaced = 1; + 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 with debug statements.\n"); + } + } + if (covered_to < limit) hole = true; if (scalar) @@ -2504,6 +2585,22 @@ generate_subtree_copies (struct access *access, tree agg, 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)) + { + gimple 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, @@ -2540,6 +2637,16 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi, update_stmt (stmt); gimple_set_location (stmt, loc); } + else if (access->grp_to_be_debug_replaced) + { + gimple 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); @@ -2646,6 +2753,13 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write) *expr = repl; sra_stats.exprs++; } + else if (write && access->grp_to_be_debug_replaced) + { + gimple 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) { @@ -2721,10 +2835,11 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc, location_t loc = gimple_location (gsi_stmt (*old_gsi)); for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling) { + HOST_WIDE_INT offset = lacc->offset - left_offset + 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; tree rhs; @@ -2764,10 +2879,34 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc, 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 (*refreshed == SRA_UDH_NONE + && lacc->grp_read && !lacc->grp_covered) + *refreshed = handle_unscalarized_data_in_subtree (top_racc, + old_gsi); + if (lacc && lacc->grp_to_be_debug_replaced) + { + gimple ds; + tree drhs; + struct access *racc = find_access_in_subtree (top_racc, offset, + lacc->size); + + if (racc && racc->grp_to_be_replaced) + drhs = get_access_replacement (racc); + else if (*refreshed == SRA_UDH_LEFT) + drhs = build_debug_ref_for_model (loc, lacc->base, lacc->offset, + lacc); + else if (*refreshed == SRA_UDH_RIGHT) + drhs = build_debug_ref_for_model (loc, top_racc->base, offset, + lacc); + else + drhs = NULL_TREE; + ds = gimple_build_debug_bind (get_access_replacement (lacc), + drhs, gsi_stmt (*old_gsi)); + gsi_insert_after (new_gsi, ds, GSI_NEW_STMT); + } + } if (lacc->first_child) load_assign_lhs_subreplacements (lacc, top_racc, left_offset, @@ -2982,6 +3121,13 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) } } + if (lacc && lacc->grp_to_be_debug_replaced) + { + gimple ds = gimple_build_debug_bind (get_access_replacement (lacc), + unshare_expr (rhs), *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 |