11debfc3dSmrg /* Language independent return value optimizations
2*8feb0f0bSmrg Copyright (C) 2004-2020 Free Software Foundation, Inc.
31debfc3dSmrg
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify
71debfc3dSmrg it under the terms of the GNU General Public License as published by
81debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
91debfc3dSmrg any later version.
101debfc3dSmrg
111debfc3dSmrg GCC is distributed in the hope that it will be useful,
121debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
131debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
141debfc3dSmrg GNU General Public License for more details.
151debfc3dSmrg
161debfc3dSmrg You should have received a copy of the GNU General Public License
171debfc3dSmrg along with GCC; see the file COPYING3. If not see
181debfc3dSmrg <http://www.gnu.org/licenses/>. */
191debfc3dSmrg
201debfc3dSmrg #include "config.h"
211debfc3dSmrg #include "system.h"
221debfc3dSmrg #include "coretypes.h"
231debfc3dSmrg #include "backend.h"
241debfc3dSmrg #include "tree.h"
251debfc3dSmrg #include "gimple.h"
261debfc3dSmrg #include "tree-pass.h"
271debfc3dSmrg #include "ssa.h"
281debfc3dSmrg #include "tree-pretty-print.h"
291debfc3dSmrg #include "gimple-iterator.h"
301debfc3dSmrg #include "gimple-walk.h"
311debfc3dSmrg #include "internal-fn.h"
321debfc3dSmrg
331debfc3dSmrg /* This file implements return value optimizations for functions which
341debfc3dSmrg return aggregate types.
351debfc3dSmrg
361debfc3dSmrg Basically this pass searches the function for return statements which
371debfc3dSmrg return a local aggregate. When converted to RTL such statements will
381debfc3dSmrg generate a copy from the local aggregate to final return value destination
391debfc3dSmrg mandated by the target's ABI.
401debfc3dSmrg
411debfc3dSmrg That copy can often be avoided by directly constructing the return value
421debfc3dSmrg into the final destination mandated by the target's ABI.
431debfc3dSmrg
441debfc3dSmrg This is basically a generic equivalent to the C++ front-end's
451debfc3dSmrg Named Return Value optimization. */
461debfc3dSmrg
471debfc3dSmrg struct nrv_data_t
481debfc3dSmrg {
491debfc3dSmrg /* This is the temporary (a VAR_DECL) which appears in all of
501debfc3dSmrg this function's RETURN_EXPR statements. */
511debfc3dSmrg tree var;
521debfc3dSmrg
531debfc3dSmrg /* This is the function's RESULT_DECL. We will replace all occurrences
541debfc3dSmrg of VAR with RESULT_DECL when we apply this optimization. */
551debfc3dSmrg tree result;
561debfc3dSmrg int modified;
571debfc3dSmrg };
581debfc3dSmrg
591debfc3dSmrg static tree finalize_nrv_r (tree *, int *, void *);
601debfc3dSmrg
611debfc3dSmrg /* Callback for the tree walker.
621debfc3dSmrg
631debfc3dSmrg If TP refers to a RETURN_EXPR, then set the expression being returned
641debfc3dSmrg to nrv_data->result.
651debfc3dSmrg
661debfc3dSmrg If TP refers to nrv_data->var, then replace nrv_data->var with
671debfc3dSmrg nrv_data->result.
681debfc3dSmrg
691debfc3dSmrg If we reach a node where we know all the subtrees are uninteresting,
701debfc3dSmrg then set *WALK_SUBTREES to zero. */
711debfc3dSmrg
721debfc3dSmrg static tree
finalize_nrv_r(tree * tp,int * walk_subtrees,void * data)731debfc3dSmrg finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
741debfc3dSmrg {
751debfc3dSmrg struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
761debfc3dSmrg struct nrv_data_t *dp = (struct nrv_data_t *) wi->info;
771debfc3dSmrg
781debfc3dSmrg /* No need to walk into types. */
791debfc3dSmrg if (TYPE_P (*tp))
801debfc3dSmrg *walk_subtrees = 0;
811debfc3dSmrg
821debfc3dSmrg /* Otherwise replace all occurrences of VAR with RESULT. */
831debfc3dSmrg else if (*tp == dp->var)
841debfc3dSmrg {
851debfc3dSmrg *tp = dp->result;
861debfc3dSmrg dp->modified = 1;
871debfc3dSmrg }
881debfc3dSmrg
891debfc3dSmrg /* Keep iterating. */
901debfc3dSmrg return NULL_TREE;
911debfc3dSmrg }
921debfc3dSmrg
931debfc3dSmrg /* Main entry point for return value optimizations.
941debfc3dSmrg
951debfc3dSmrg If this function always returns the same local variable, and that
961debfc3dSmrg local variable is an aggregate type, then replace the variable with
971debfc3dSmrg the function's DECL_RESULT.
981debfc3dSmrg
991debfc3dSmrg This is the equivalent of the C++ named return value optimization
1001debfc3dSmrg applied to optimized trees in a language independent form. If we
1011debfc3dSmrg ever encounter languages which prevent this kind of optimization,
1021debfc3dSmrg then we could either have the languages register the optimization or
1031debfc3dSmrg we could change the gating function to check the current language. */
1041debfc3dSmrg
1051debfc3dSmrg namespace {
1061debfc3dSmrg
1071debfc3dSmrg const pass_data pass_data_nrv =
1081debfc3dSmrg {
1091debfc3dSmrg GIMPLE_PASS, /* type */
1101debfc3dSmrg "nrv", /* name */
1111debfc3dSmrg OPTGROUP_NONE, /* optinfo_flags */
1121debfc3dSmrg TV_TREE_NRV, /* tv_id */
1131debfc3dSmrg ( PROP_ssa | PROP_cfg ), /* properties_required */
1141debfc3dSmrg 0, /* properties_provided */
1151debfc3dSmrg 0, /* properties_destroyed */
1161debfc3dSmrg 0, /* todo_flags_start */
1171debfc3dSmrg 0, /* todo_flags_finish */
1181debfc3dSmrg };
1191debfc3dSmrg
1201debfc3dSmrg class pass_nrv : public gimple_opt_pass
1211debfc3dSmrg {
1221debfc3dSmrg public:
pass_nrv(gcc::context * ctxt)1231debfc3dSmrg pass_nrv (gcc::context *ctxt)
1241debfc3dSmrg : gimple_opt_pass (pass_data_nrv, ctxt)
1251debfc3dSmrg {}
1261debfc3dSmrg
1271debfc3dSmrg /* opt_pass methods: */
gate(function *)1281debfc3dSmrg virtual bool gate (function *) { return optimize > 0; }
1291debfc3dSmrg
1301debfc3dSmrg virtual unsigned int execute (function *);
1311debfc3dSmrg
1321debfc3dSmrg }; // class pass_nrv
1331debfc3dSmrg
1341debfc3dSmrg unsigned int
execute(function * fun)1351debfc3dSmrg pass_nrv::execute (function *fun)
1361debfc3dSmrg {
1371debfc3dSmrg tree result = DECL_RESULT (current_function_decl);
1381debfc3dSmrg tree result_type = TREE_TYPE (result);
1391debfc3dSmrg tree found = NULL;
1401debfc3dSmrg basic_block bb;
1411debfc3dSmrg gimple_stmt_iterator gsi;
1421debfc3dSmrg struct nrv_data_t data;
1431debfc3dSmrg
1441debfc3dSmrg /* If this function does not return an aggregate type in memory, then
1451debfc3dSmrg there is nothing to do. */
1461debfc3dSmrg if (!aggregate_value_p (result, current_function_decl))
1471debfc3dSmrg return 0;
1481debfc3dSmrg
1491debfc3dSmrg /* If a GIMPLE type is returned in memory, finalize_nrv_r might create
1501debfc3dSmrg non-GIMPLE. */
1511debfc3dSmrg if (is_gimple_reg_type (result_type))
1521debfc3dSmrg return 0;
1531debfc3dSmrg
1541debfc3dSmrg /* If the front end already did something like this, don't do it here. */
1551debfc3dSmrg if (DECL_NAME (result))
1561debfc3dSmrg return 0;
1571debfc3dSmrg
1581debfc3dSmrg /* If the result has its address taken then it might be modified
1591debfc3dSmrg by means not detected in the following loop. Bail out in this
1601debfc3dSmrg case. */
1611debfc3dSmrg if (TREE_ADDRESSABLE (result))
1621debfc3dSmrg return 0;
1631debfc3dSmrg
1641debfc3dSmrg /* Look through each block for assignments to the RESULT_DECL. */
1651debfc3dSmrg FOR_EACH_BB_FN (bb, fun)
1661debfc3dSmrg {
1671debfc3dSmrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1681debfc3dSmrg {
1691debfc3dSmrg gimple *stmt = gsi_stmt (gsi);
1701debfc3dSmrg tree ret_val;
1711debfc3dSmrg
1721debfc3dSmrg if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
1731debfc3dSmrg {
1741debfc3dSmrg /* In a function with an aggregate return value, the
1751debfc3dSmrg gimplifier has changed all non-empty RETURN_EXPRs to
1761debfc3dSmrg return the RESULT_DECL. */
1771debfc3dSmrg ret_val = gimple_return_retval (return_stmt);
1781debfc3dSmrg if (ret_val)
1791debfc3dSmrg gcc_assert (ret_val == result);
1801debfc3dSmrg }
1811debfc3dSmrg else if (gimple_has_lhs (stmt)
1821debfc3dSmrg && gimple_get_lhs (stmt) == result)
1831debfc3dSmrg {
1841debfc3dSmrg tree rhs;
1851debfc3dSmrg
1861debfc3dSmrg if (!gimple_assign_copy_p (stmt))
1871debfc3dSmrg return 0;
1881debfc3dSmrg
1891debfc3dSmrg rhs = gimple_assign_rhs1 (stmt);
1901debfc3dSmrg
1911debfc3dSmrg /* Now verify that this return statement uses the same value
1921debfc3dSmrg as any previously encountered return statement. */
1931debfc3dSmrg if (found != NULL)
1941debfc3dSmrg {
1951debfc3dSmrg /* If we found a return statement using a different variable
1961debfc3dSmrg than previous return statements, then we cannot perform
1971debfc3dSmrg NRV optimizations. */
1981debfc3dSmrg if (found != rhs)
1991debfc3dSmrg return 0;
2001debfc3dSmrg }
2011debfc3dSmrg else
2021debfc3dSmrg found = rhs;
2031debfc3dSmrg
2041debfc3dSmrg /* The returned value must be a local automatic variable of the
2051debfc3dSmrg same type and alignment as the function's result. */
2061debfc3dSmrg if (!VAR_P (found)
2071debfc3dSmrg || TREE_THIS_VOLATILE (found)
2081debfc3dSmrg || !auto_var_in_fn_p (found, current_function_decl)
2091debfc3dSmrg || TREE_ADDRESSABLE (found)
2101debfc3dSmrg || DECL_ALIGN (found) > DECL_ALIGN (result)
2111debfc3dSmrg || !useless_type_conversion_p (result_type,
2121debfc3dSmrg TREE_TYPE (found)))
2131debfc3dSmrg return 0;
2141debfc3dSmrg }
2151debfc3dSmrg else if (gimple_has_lhs (stmt))
2161debfc3dSmrg {
2171debfc3dSmrg tree addr = get_base_address (gimple_get_lhs (stmt));
2181debfc3dSmrg /* If there's any MODIFY of component of RESULT,
2191debfc3dSmrg then bail out. */
2201debfc3dSmrg if (addr && addr == result)
2211debfc3dSmrg return 0;
2221debfc3dSmrg }
2231debfc3dSmrg }
2241debfc3dSmrg }
2251debfc3dSmrg
2261debfc3dSmrg if (!found)
2271debfc3dSmrg return 0;
2281debfc3dSmrg
2291debfc3dSmrg /* If dumping details, then note once and only the NRV replacement. */
2301debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
2311debfc3dSmrg {
2321debfc3dSmrg fprintf (dump_file, "NRV Replaced: ");
2331debfc3dSmrg print_generic_expr (dump_file, found, dump_flags);
2341debfc3dSmrg fprintf (dump_file, " with: ");
2351debfc3dSmrg print_generic_expr (dump_file, result, dump_flags);
2361debfc3dSmrg fprintf (dump_file, "\n");
2371debfc3dSmrg }
2381debfc3dSmrg
2391debfc3dSmrg TREE_ADDRESSABLE (result) |= TREE_ADDRESSABLE (found);
2401debfc3dSmrg
2411debfc3dSmrg /* Now walk through the function changing all references to VAR to be
2421debfc3dSmrg RESULT. */
2431debfc3dSmrg data.var = found;
2441debfc3dSmrg data.result = result;
2451debfc3dSmrg FOR_EACH_BB_FN (bb, fun)
2461debfc3dSmrg {
2471debfc3dSmrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2481debfc3dSmrg {
2491debfc3dSmrg gimple *stmt = gsi_stmt (gsi);
2501debfc3dSmrg /* If this is a copy from VAR to RESULT, remove it. */
2511debfc3dSmrg if (gimple_assign_copy_p (stmt)
2521debfc3dSmrg && gimple_assign_lhs (stmt) == result
2531debfc3dSmrg && gimple_assign_rhs1 (stmt) == found)
2541debfc3dSmrg {
2551debfc3dSmrg unlink_stmt_vdef (stmt);
2561debfc3dSmrg gsi_remove (&gsi, true);
2571debfc3dSmrg release_defs (stmt);
2581debfc3dSmrg }
2591debfc3dSmrg else
2601debfc3dSmrg {
2611debfc3dSmrg struct walk_stmt_info wi;
2621debfc3dSmrg memset (&wi, 0, sizeof (wi));
2631debfc3dSmrg wi.info = &data;
2641debfc3dSmrg data.modified = 0;
2651debfc3dSmrg walk_gimple_op (stmt, finalize_nrv_r, &wi);
2661debfc3dSmrg if (data.modified)
2671debfc3dSmrg update_stmt (stmt);
2681debfc3dSmrg gsi_next (&gsi);
2691debfc3dSmrg }
2701debfc3dSmrg }
2711debfc3dSmrg }
2721debfc3dSmrg
2731debfc3dSmrg SET_DECL_VALUE_EXPR (found, result);
2741debfc3dSmrg DECL_HAS_VALUE_EXPR_P (found) = 1;
2751debfc3dSmrg
2761debfc3dSmrg return 0;
2771debfc3dSmrg }
2781debfc3dSmrg
2791debfc3dSmrg } // anon namespace
2801debfc3dSmrg
2811debfc3dSmrg gimple_opt_pass *
make_pass_nrv(gcc::context * ctxt)2821debfc3dSmrg make_pass_nrv (gcc::context *ctxt)
2831debfc3dSmrg {
2841debfc3dSmrg return new pass_nrv (ctxt);
2851debfc3dSmrg }
2861debfc3dSmrg
2871debfc3dSmrg /* Determine (pessimistically) whether DEST is available for NRV
2881debfc3dSmrg optimization, where DEST is expected to be the LHS of a modify
2891debfc3dSmrg expression where the RHS is a function returning an aggregate.
2901debfc3dSmrg
2911debfc3dSmrg DEST is available if it is not clobbered or used by the call. */
2921debfc3dSmrg
2931debfc3dSmrg static bool
dest_safe_for_nrv_p(gcall * call)2941debfc3dSmrg dest_safe_for_nrv_p (gcall *call)
2951debfc3dSmrg {
2961debfc3dSmrg tree dest = gimple_call_lhs (call);
2971debfc3dSmrg
2981debfc3dSmrg dest = get_base_address (dest);
2991debfc3dSmrg if (! dest)
3001debfc3dSmrg return false;
3011debfc3dSmrg
3021debfc3dSmrg if (TREE_CODE (dest) == SSA_NAME)
3031debfc3dSmrg return true;
3041debfc3dSmrg
3051debfc3dSmrg if (call_may_clobber_ref_p (call, dest)
3061debfc3dSmrg || ref_maybe_used_by_stmt_p (call, dest))
3071debfc3dSmrg return false;
3081debfc3dSmrg
3091debfc3dSmrg return true;
3101debfc3dSmrg }
3111debfc3dSmrg
3121debfc3dSmrg /* Walk through the function looking for GIMPLE_ASSIGNs with calls that
3131debfc3dSmrg return in memory on the RHS. For each of these, determine whether it is
3141debfc3dSmrg safe to pass the address of the LHS as the return slot, and mark the
3151debfc3dSmrg call appropriately if so.
3161debfc3dSmrg
3171debfc3dSmrg The NRV shares the return slot with a local variable in the callee; this
3181debfc3dSmrg optimization shares the return slot with the target of the call within
3191debfc3dSmrg the caller. If the NRV is performed (which we can't know in general),
3201debfc3dSmrg this optimization is safe if the address of the target has not
3211debfc3dSmrg escaped prior to the call. If it has, modifications to the local
3221debfc3dSmrg variable will produce visible changes elsewhere, as in PR c++/19317. */
3231debfc3dSmrg
3241debfc3dSmrg namespace {
3251debfc3dSmrg
3261debfc3dSmrg const pass_data pass_data_return_slot =
3271debfc3dSmrg {
3281debfc3dSmrg GIMPLE_PASS, /* type */
3291debfc3dSmrg "retslot", /* name */
3301debfc3dSmrg OPTGROUP_NONE, /* optinfo_flags */
3311debfc3dSmrg TV_NONE, /* tv_id */
3321debfc3dSmrg PROP_ssa, /* properties_required */
3331debfc3dSmrg 0, /* properties_provided */
3341debfc3dSmrg 0, /* properties_destroyed */
3351debfc3dSmrg 0, /* todo_flags_start */
3361debfc3dSmrg 0, /* todo_flags_finish */
3371debfc3dSmrg };
3381debfc3dSmrg
3391debfc3dSmrg class pass_return_slot : public gimple_opt_pass
3401debfc3dSmrg {
3411debfc3dSmrg public:
pass_return_slot(gcc::context * ctxt)3421debfc3dSmrg pass_return_slot (gcc::context *ctxt)
3431debfc3dSmrg : gimple_opt_pass (pass_data_return_slot, ctxt)
3441debfc3dSmrg {}
3451debfc3dSmrg
3461debfc3dSmrg /* opt_pass methods: */
3471debfc3dSmrg virtual unsigned int execute (function *);
3481debfc3dSmrg
3491debfc3dSmrg }; // class pass_return_slot
3501debfc3dSmrg
3511debfc3dSmrg unsigned int
execute(function * fun)3521debfc3dSmrg pass_return_slot::execute (function *fun)
3531debfc3dSmrg {
3541debfc3dSmrg basic_block bb;
3551debfc3dSmrg
3561debfc3dSmrg FOR_EACH_BB_FN (bb, fun)
3571debfc3dSmrg {
3581debfc3dSmrg gimple_stmt_iterator gsi;
3591debfc3dSmrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
3601debfc3dSmrg {
3611debfc3dSmrg gcall *stmt;
3621debfc3dSmrg bool slot_opt_p;
3631debfc3dSmrg
3641debfc3dSmrg stmt = dyn_cast <gcall *> (gsi_stmt (gsi));
3651debfc3dSmrg if (stmt
3661debfc3dSmrg && gimple_call_lhs (stmt)
3671debfc3dSmrg && !gimple_call_return_slot_opt_p (stmt)
368*8feb0f0bSmrg /* Ignore internal functions, those are expanded specially
369*8feb0f0bSmrg and aggregate_value_p on their result might result in
370*8feb0f0bSmrg undesirable warnings with some backends. */
371*8feb0f0bSmrg && !gimple_call_internal_p (stmt)
3721debfc3dSmrg && aggregate_value_p (TREE_TYPE (gimple_call_lhs (stmt)),
3731debfc3dSmrg gimple_call_fndecl (stmt)))
3741debfc3dSmrg {
3751debfc3dSmrg /* Check if the location being assigned to is
3761debfc3dSmrg clobbered by the call. */
3771debfc3dSmrg slot_opt_p = dest_safe_for_nrv_p (stmt);
3781debfc3dSmrg gimple_call_set_return_slot_opt (stmt, slot_opt_p);
3791debfc3dSmrg }
3801debfc3dSmrg }
3811debfc3dSmrg }
3821debfc3dSmrg return 0;
3831debfc3dSmrg }
3841debfc3dSmrg
3851debfc3dSmrg } // anon namespace
3861debfc3dSmrg
3871debfc3dSmrg gimple_opt_pass *
make_pass_return_slot(gcc::context * ctxt)3881debfc3dSmrg make_pass_return_slot (gcc::context *ctxt)
3891debfc3dSmrg {
3901debfc3dSmrg return new pass_return_slot (ctxt);
3911debfc3dSmrg }
392