+ PROP_ssa | PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_ggc_collect /* todo_flags_finish */
+ }
+};
+
+/* Determine (pessimistically) whether DEST is available for NRV
+ optimization, where DEST is expected to be the LHS of a modify
+ expression where the RHS is a function returning an aggregate.
+
+ DEST is available if it is not clobbered or used by the call. */
+
+static bool
+dest_safe_for_nrv_p (gimple call)
+{
+ tree dest = gimple_call_lhs (call);
+
+ dest = get_base_address (dest);
+ if (! dest)
+ return false;
+
+ if (TREE_CODE (dest) == SSA_NAME)
+ return true;
+
+ if (call_may_clobber_ref_p (call, dest)
+ || ref_maybe_used_by_stmt_p (call, dest))
+ return false;
+
+ return true;
+}
+
+/* Walk through the function looking for GIMPLE_ASSIGNs with calls that
+ return in memory on the RHS. For each of these, determine whether it is
+ safe to pass the address of the LHS as the return slot, and mark the
+ call appropriately if so.
+
+ The NRV shares the return slot with a local variable in the callee; this
+ optimization shares the return slot with the target of the call within
+ the caller. If the NRV is performed (which we can't know in general),
+ this optimization is safe if the address of the target has not
+ escaped prior to the call. If it has, modifications to the local
+ variable will produce visible changes elsewhere, as in PR c++/19317. */
+
+static unsigned int
+execute_return_slot_opt (void)
+{
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ {
+ gimple_stmt_iterator gsi;
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ bool slot_opt_p;
+
+ if (is_gimple_call (stmt)
+ && gimple_call_lhs (stmt)
+ && !gimple_call_return_slot_opt_p (stmt)
+ && aggregate_value_p (TREE_TYPE (gimple_call_lhs (stmt)),
+ gimple_call_fndecl (stmt)))
+ {
+ /* Check if the location being assigned to is
+ clobbered by the call. */
+ slot_opt_p = dest_safe_for_nrv_p (stmt);
+ gimple_call_set_return_slot_opt (stmt, slot_opt_p);
+ }
+ }
+ }
+ return 0;
+}
+
+struct gimple_opt_pass pass_return_slot =
+{
+ {
+ GIMPLE_PASS,
+ "retslot", /* name */
+ NULL, /* gate */
+ execute_return_slot_opt, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_NONE, /* tv_id */
+ PROP_ssa, /* properties_required */