return changed;
}
+
+/* Helper function for optimize_agr_copyprop.
+ For aggregate copies in USE_STMT, see if DEST
+ is on the lhs of USE_STMT and replace it with SRC. */
+static bool
+optimize_agr_copyprop_1 (gimple *stmt, gimple *use_stmt,
+ tree dest, tree src)
+{
+ gcc_assert (gimple_assign_load_p (use_stmt)
+ && gimple_store_p (use_stmt));
+ if (gimple_has_volatile_ops (use_stmt))
+ return false;
+ tree dest2 = gimple_assign_lhs (use_stmt);
+ tree src2 = gimple_assign_rhs1 (use_stmt);
+ /* If the new store is `src2 = src2;` skip over it. */
+ if (operand_equal_p (src2, dest2, 0))
+ return false;
+ if (!operand_equal_p (dest, src2, 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; #DEST = SRC;
+ *b = t; #DEST2 = SRC2;
+ 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 (dest2, src, 0)
+ && !DECL_P (dest2) && !DECL_P (src))
+ return false;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Simplified\n ");
+ print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
+ fprintf (dump_file, "after previous\n ");
+ print_gimple_stmt (dump_file, stmt, 0, dump_flags);
+ }
+ gimple *orig_stmt = use_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+ gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (src));
+ update_stmt (use_stmt);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "into\n ");
+ print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
+ }
+ if (maybe_clean_or_replace_eh_stmt (orig_stmt, use_stmt))
+ bitmap_set_bit (to_purge, gimple_bb (stmt)->index);
+ statistics_counter_event (cfun, "copy prop for aggregate", 1);
+ return true;
+}
+
+/* Helper function for optimize_agr_copyprop_1, propagate aggregates
+ into the arguments of USE_STMT if the argument matches with DEST;
+ replacing it with SRC. */
+static bool
+optimize_agr_copyprop_arg (gimple *defstmt, gcall *call,
+ tree dest, tree src)
+{
+ bool changed = false;
+ for (unsigned arg = 0; arg < gimple_call_num_args (call); arg++)
+ {
+ tree *argptr = gimple_call_arg_ptr (call, arg);
+ if (TREE_CODE (*argptr) == SSA_NAME
+ || is_gimple_min_invariant (*argptr)
+ || TYPE_VOLATILE (TREE_TYPE (*argptr)))
+ continue;
+ if (!operand_equal_p (*argptr, dest, 0))
+ continue;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Simplified\n ");
+ print_gimple_stmt (dump_file, call, 0, dump_flags);
+ fprintf (dump_file, "after previous\n ");
+ print_gimple_stmt (dump_file, defstmt, 0, dump_flags);
+ }
+ *argptr = unshare_expr (src);
+ changed = true;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "into\n ");
+ print_gimple_stmt (dump_file, call, 0, dump_flags);
+ }
+ }
+ if (changed)
+ update_stmt (call);
+ return changed;
+}
+
/* Optimizes
DEST = SRC;
DEST2 = DEST; # DEST2 = SRC2;
DEST2 = SRC;
GSIP is the first statement and SRC is the common
between the statements.
+
+ Also optimizes:
+ DEST = SRC;
+ call_func(..., DEST, ...);
+ into:
+ DEST = SRC;
+ call_func(..., SRC, ...);
+
*/
static bool
optimize_agr_copyprop (gimple_stmt_iterator *gsip)
bool changed = false;
FOR_EACH_IMM_USE_STMT (use_stmt, iter, vdef)
{
- if (!gimple_assign_load_p (use_stmt)
- || !gimple_store_p (use_stmt))
- continue;
- if (gimple_has_volatile_ops (use_stmt))
- continue;
- tree dest2 = gimple_assign_lhs (use_stmt);
- tree src2 = gimple_assign_rhs1 (use_stmt);
- /* If the new store is `src2 = src2;` skip over it. */
- if (operand_equal_p (src2, dest2, 0))
- continue;
- if (!operand_equal_p (dest, src2, 0))
- continue;
- /* 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; #DEST = SRC;
- *b = t; #DEST2 = SRC2;
- 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 (dest2, src, 0)
- && !DECL_P (dest2) && !DECL_P (src))
- continue;
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Simplified\n ");
- print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
- fprintf (dump_file, "after previous\n ");
- print_gimple_stmt (dump_file, stmt, 0, dump_flags);
- }
- gimple *orig_stmt = use_stmt;
- gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
- gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (src));
- update_stmt (use_stmt);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "into\n ");
- print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
- }
-
- /* Mark the bb for eh cleanup if needed. */
- if (maybe_clean_or_replace_eh_stmt (orig_stmt, use_stmt))
- bitmap_set_bit (to_purge, gimple_bb (stmt)->index);
- statistics_counter_event (cfun, "copy prop for aggregate", 1);
- changed = true;
+ if (gimple_assign_load_p (use_stmt)
+ && gimple_store_p (use_stmt)
+ && optimize_agr_copyprop_1 (stmt, use_stmt, dest, src))
+ changed = true;
+ else if (is_gimple_call (use_stmt)
+ && optimize_agr_copyprop_arg (stmt, as_a<gcall*>(use_stmt),
+ dest, src))
+ changed = true;
}
return changed;
}