Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-nrv.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/tree-nrv.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/tree-nrv.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,6 +1,5 @@ /* Language independent return value optimizations - Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2004-2017 Free Software Foundation, Inc. This file is part of GCC. @@ -21,19 +20,15 @@ #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" +#include "backend.h" #include "tree.h" -#include "function.h" -#include "basic-block.h" +#include "gimple.h" +#include "tree-pass.h" +#include "ssa.h" #include "tree-pretty-print.h" -#include "tree-flow.h" -#include "timevar.h" -#include "tree-dump.h" -#include "tree-pass.h" -#include "langhooks.h" -#include "flags.h" /* For "optimize" in gate_pass_return_slot. - FIXME: That should be up to the pass manager, - but pass_nrv is not in pass_all_optimizations. */ +#include "gimple-iterator.h" +#include "gimple-walk.h" +#include "internal-fn.h" /* This file implements return value optimizations for functions which return aggregate types. @@ -49,7 +44,7 @@ This is basically a generic equivalent to the C++ front-end's Named Return Value optimization. */ -struct nrv_data +struct nrv_data_t { /* This is the temporary (a VAR_DECL) which appears in all of this function's RETURN_EXPR statements. */ @@ -78,7 +73,7 @@ finalize_nrv_r (tree *tp, int *walk_subtrees, void *data) { struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - struct nrv_data *dp = (struct nrv_data *) wi->info; + struct nrv_data_t *dp = (struct nrv_data_t *) wi->info; /* No need to walk into types. */ if (TYPE_P (*tp)) @@ -107,15 +102,44 @@ then we could either have the languages register the optimization or we could change the gating function to check the current language. */ -static unsigned int -tree_nrv (void) +namespace { + +const pass_data pass_data_nrv = +{ + GIMPLE_PASS, /* type */ + "nrv", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_TREE_NRV, /* tv_id */ + ( PROP_ssa | PROP_cfg ), /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_nrv : public gimple_opt_pass +{ +public: + pass_nrv (gcc::context *ctxt) + : gimple_opt_pass (pass_data_nrv, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) { return optimize > 0; } + + virtual unsigned int execute (function *); + +}; // class pass_nrv + +unsigned int +pass_nrv::execute (function *fun) { tree result = DECL_RESULT (current_function_decl); tree result_type = TREE_TYPE (result); tree found = NULL; basic_block bb; gimple_stmt_iterator gsi; - struct nrv_data data; + struct nrv_data_t data; /* If this function does not return an aggregate type in memory, then there is nothing to do. */ @@ -138,19 +162,19 @@ return 0; /* Look through each block for assignments to the RESULT_DECL. */ - FOR_EACH_BB (bb) + FOR_EACH_BB_FN (bb, fun) { for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { - gimple stmt = gsi_stmt (gsi); + gimple *stmt = gsi_stmt (gsi); tree ret_val; - if (gimple_code (stmt) == GIMPLE_RETURN) + if (greturn *return_stmt = dyn_cast <greturn *> (stmt)) { /* In a function with an aggregate return value, the gimplifier has changed all non-empty RETURN_EXPRs to return the RESULT_DECL. */ - ret_val = gimple_return_retval (stmt); + ret_val = gimple_return_retval (return_stmt); if (ret_val) gcc_assert (ret_val == result); } @@ -179,10 +203,9 @@ /* The returned value must be a local automatic variable of the same type and alignment as the function's result. */ - if (TREE_CODE (found) != VAR_DECL + if (!VAR_P (found) || TREE_THIS_VOLATILE (found) - || DECL_CONTEXT (found) != current_function_decl - || TREE_STATIC (found) + || !auto_var_in_fn_p (found, current_function_decl) || TREE_ADDRESSABLE (found) || DECL_ALIGN (found) > DECL_ALIGN (result) || !useless_type_conversion_p (result_type, @@ -232,11 +255,11 @@ RESULT. */ data.var = found; data.result = result; - FOR_EACH_BB (bb) + FOR_EACH_BB_FN (bb, fun) { for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ) { - gimple stmt = gsi_stmt (gsi); + gimple *stmt = gsi_stmt (gsi); /* If this is a copy from VAR to RESULT, remove it. */ if (gimple_assign_copy_p (stmt) && gimple_assign_lhs (stmt) == result @@ -244,6 +267,7 @@ { unlink_stmt_vdef (stmt); gsi_remove (&gsi, true); + release_defs (stmt); } else { @@ -262,35 +286,16 @@ SET_DECL_VALUE_EXPR (found, result); DECL_HAS_VALUE_EXPR_P (found) = 1; - /* FOUND is no longer used. Ensure it gets removed. */ - clear_is_used (found); return 0; } -static bool -gate_pass_return_slot (void) -{ - return optimize > 0; -} +} // anon namespace -struct gimple_opt_pass pass_nrv = +gimple_opt_pass * +make_pass_nrv (gcc::context *ctxt) { - { - GIMPLE_PASS, - "nrv", /* name */ - gate_pass_return_slot, /* gate */ - tree_nrv, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_TREE_NRV, /* tv_id */ - PROP_ssa | PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ - } -}; + return new pass_nrv (ctxt); +} /* Determine (pessimistically) whether DEST is available for NRV optimization, where DEST is expected to be the LHS of a modify @@ -299,7 +304,7 @@ DEST is available if it is not clobbered or used by the call. */ static bool -dest_safe_for_nrv_p (gimple call) +dest_safe_for_nrv_p (gcall *call) { tree dest = gimple_call_lhs (call); @@ -329,27 +334,61 @@ 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) +namespace { + +const pass_data pass_data_return_slot = +{ + GIMPLE_PASS, /* type */ + "retslot", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_return_slot : public gimple_opt_pass +{ +public: + pass_return_slot (gcc::context *ctxt) + : gimple_opt_pass (pass_data_return_slot, ctxt) + {} + + /* opt_pass methods: */ + virtual unsigned int execute (function *); + +}; // class pass_return_slot + +unsigned int +pass_return_slot::execute (function *fun) { basic_block bb; - FOR_EACH_BB (bb) + FOR_EACH_BB_FN (bb, fun) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { - gimple stmt = gsi_stmt (gsi); + gcall *stmt; bool slot_opt_p; - if (is_gimple_call (stmt) + stmt = dyn_cast <gcall *> (gsi_stmt (gsi)); + if (stmt && gimple_call_lhs (stmt) && !gimple_call_return_slot_opt_p (stmt) + /* Ignore internal functions without direct optabs, + those are expanded specially and aggregate_value_p + on their result might result in undesirable warnings + with some backends. */ + && (!gimple_call_internal_p (stmt) + || direct_internal_fn_p (gimple_call_internal_fn (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. */ + clobbered by the call. */ slot_opt_p = dest_safe_for_nrv_p (stmt); gimple_call_set_return_slot_opt (stmt, slot_opt_p); } @@ -358,21 +397,10 @@ return 0; } -struct gimple_opt_pass pass_return_slot = +} // anon namespace + +gimple_opt_pass * +make_pass_return_slot (gcc::context *ctxt) { - { - 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 */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0 /* todo_flags_finish */ - } -}; + return new pass_return_slot (ctxt); +}