diff options
Diffstat (limited to 'gcc/tree-ssa-forwprop.cc')
-rw-r--r-- | gcc/tree-ssa-forwprop.cc | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index 4c048a9..27197bb 100644 --- a/gcc/tree-ssa-forwprop.cc +++ b/gcc/tree-ssa-forwprop.cc @@ -205,7 +205,6 @@ struct _vec_perm_simplify_seq typedef struct _vec_perm_simplify_seq *vec_perm_simplify_seq; static bool forward_propagate_addr_expr (tree, tree, bool); -static void optimize_vector_load (gimple_stmt_iterator *); /* Set to true if we delete dead edges during the optimization. */ static bool cfg_changed; @@ -1226,7 +1225,8 @@ optimize_memcpy_to_memset (gimple_stmt_iterator *gsip, tree dest, tree src, tree gimple *defstmt; unsigned limit = param_sccvn_max_alias_queries_per_access; do { - if (vuse == NULL || TREE_CODE (vuse) != SSA_NAME) + /* If the vuse is the default definition, then there is no stores beforhand. */ + if (SSA_NAME_IS_DEFAULT_DEF (vuse)) return false; defstmt = SSA_NAME_DEF_STMT (vuse); if (is_a <gphi*>(defstmt)) @@ -1323,6 +1323,7 @@ optimize_memcpy_to_memset (gimple_stmt_iterator *gsip, tree dest, tree src, tree tree ctor = build_constructor (TREE_TYPE (dest), NULL); gimple_assign_set_rhs_from_tree (gsip, ctor); update_stmt (stmt); + statistics_counter_event (cfun, "copy zeroing propagation of aggregate", 1); } else /* If stmt is memcpy, transform it into memset. */ { @@ -1332,6 +1333,7 @@ optimize_memcpy_to_memset (gimple_stmt_iterator *gsip, tree dest, tree src, tree gimple_call_set_fntype (call, TREE_TYPE (fndecl)); gimple_call_set_arg (call, 1, val); update_stmt (stmt); + statistics_counter_event (cfun, "memcpy to memset changed", 1); } if (dump_file && (dump_flags & TDF_DETAILS)) @@ -1341,6 +1343,88 @@ optimize_memcpy_to_memset (gimple_stmt_iterator *gsip, tree dest, tree src, tree } return true; } +/* Optimizes + a = c; + b = a; + into + a = c; + b = c; + GSIP is the second statement and SRC is the common + between the statements. +*/ +static bool +optimize_agr_copyprop (gimple_stmt_iterator *gsip) +{ + gimple *stmt = gsi_stmt (*gsip); + if (gimple_has_volatile_ops (stmt)) + return false; + + tree dest = gimple_assign_lhs (stmt); + tree src = gimple_assign_rhs1 (stmt); + /* If the statement is `src = src;` then ignore it. */ + if (operand_equal_p (dest, src, 0)) + return false; + + tree vuse = gimple_vuse (stmt); + /* If the vuse is the default definition, then there is no store beforehand. */ + if (SSA_NAME_IS_DEFAULT_DEF (vuse)) + return false; + gimple *defstmt = SSA_NAME_DEF_STMT (vuse); + if (!gimple_assign_load_p (defstmt) + || !gimple_store_p (defstmt)) + return false; + if (gimple_has_volatile_ops (defstmt)) + return false; + + tree dest2 = gimple_assign_lhs (defstmt); + tree src2 = gimple_assign_rhs1 (defstmt); + + /* If the original store is `src2 = src2;` skip over it. */ + if (operand_equal_p (src2, dest2, 0)) + return false; + if (!operand_equal_p (src, dest2, 0)) + return false; + + + /* For 2 memory refences and using a temporary to do the copy, + don't remove the temporary as the 2 memory references might overlap. + Note t does not need to be decl as it could be field. + See PR 22237 for full details. + E.g. + t = *a; + *b = t; + Cannot be convert into + t = *a; + *b = *a; + Though the following is allowed to be done: + t = *a; + *a = t; + And convert it into: + t = *a; + *a = *a; + */ + if (!operand_equal_p (src2, dest, 0) + && !DECL_P (dest) && !DECL_P (src2)) + return false; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Simplified\n "); + print_gimple_stmt (dump_file, stmt, 0, dump_flags); + fprintf (dump_file, "after previous\n "); + print_gimple_stmt (dump_file, defstmt, 0, dump_flags); + } + gimple_assign_set_rhs_from_tree (gsip, unshare_expr (src2)); + update_stmt (stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "into\n "); + print_gimple_stmt (dump_file, stmt, 0, dump_flags); + } + statistics_counter_event (cfun, "copy prop for aggregate", 1); + return true; +} /* *GSI_P is a GIMPLE_CALL to a builtin function. Optimize @@ -3384,6 +3468,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi) gimple *stmt = gsi_stmt (*gsi); tree lhs = gimple_assign_lhs (stmt); tree rhs = gimple_assign_rhs1 (stmt); + tree vuse = gimple_vuse (stmt); /* Gather BIT_FIELD_REFs to rewrite, looking through VEC_UNPACK_{LO,HI}_EXPR. */ @@ -3492,6 +3577,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi) gimple *new_stmt = gimple_build_assign (tem, new_rhs); location_t loc = gimple_location (use_stmt); gimple_set_location (new_stmt, loc); + gimple_set_vuse (new_stmt, vuse); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); /* Perform scalar promotion. */ new_stmt = gimple_build_assign (gimple_assign_lhs (use_stmt), @@ -3511,6 +3597,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi) new_rhs); location_t loc = gimple_location (use_stmt); gimple_set_location (new_stmt, loc); + gimple_set_vuse (new_stmt, vuse); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); } gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt); @@ -4164,7 +4251,7 @@ const pass_data pass_data_forwprop = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_update_ssa, /* todo_flags_finish */ + 0, /* todo_flags_finish */ }; class pass_forwprop : public gimple_opt_pass @@ -4401,6 +4488,7 @@ pass_forwprop::execute (function *fun) component-wise loads. */ use_operand_p use_p; imm_use_iterator iter; + tree vuse = gimple_vuse (stmt); bool rewrite = true; FOR_EACH_IMM_USE_FAST (use_p, iter, lhs) { @@ -4440,6 +4528,7 @@ pass_forwprop::execute (function *fun) location_t loc = gimple_location (use_stmt); gimple_set_location (new_stmt, loc); + gimple_set_vuse (new_stmt, vuse); gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt); unlink_stmt_vdef (use_stmt); gsi_remove (&gsi2, true); @@ -4717,6 +4806,11 @@ pass_forwprop::execute (function *fun) changed = true; break; } + if (optimize_agr_copyprop (&gsi)) + { + changed = true; + break; + } } if (TREE_CODE_CLASS (code) == tcc_comparison) |