diff options
author | Tom de Vries <tom@codesourcery.com> | 2015-04-17 09:26:59 +0000 |
---|---|---|
committer | Tom de Vries <vries@gcc.gnu.org> | 2015-04-17 09:26:59 +0000 |
commit | f8e89441bc5518f450b6511c59c17c837859d109 (patch) | |
tree | 5d4de8b2de7d1bc521bef75e9c0cea144cf87699 /gcc/tree-stdarg.c | |
parent | 1691b2e1ca494eee178a70c73c0f941ff27118f6 (diff) | |
download | gcc-f8e89441bc5518f450b6511c59c17c837859d109.zip gcc-f8e89441bc5518f450b6511c59c17c837859d109.tar.gz gcc-f8e89441bc5518f450b6511c59c17c837859d109.tar.bz2 |
Postpone expanding va_arg until pass_stdarg
2015-04-17 Tom de Vries <tom@codesourcery.com>
Michael Matz <matz@suse.de>
* gimple-iterator.c (update_modified_stmts): Remove static.
* gimple-iterator.h (update_modified_stmts): Declare.
* gimplify.c (gimplify_modify_expr): Handle IFN_VA_ARG.
(gimplify_va_arg_internal): New function.
(gimplify_va_arg_expr): Use IFN_VA_ARG.
* gimplify.h (gimplify_va_arg_internal): Declare.
* internal-fn.c (expand_VA_ARG): New unreachable function.
* internal-fn.def (VA_ARG): New DEF_INTERNAL_FN.
* tree-stdarg.c (gimple_call_ifn_va_arg_p, expand_ifn_va_arg_1)
(expand_ifn_va_arg): New function.
(pass_data_stdarg): Add PROP_gimple_lva to properties_provided field.
(pass_stdarg::execute): Call expand_ifn_va_arg.
(pass_data_lower_vaarg): New pass_data.
(pass_lower_vaarg): New gimple_opt_pass.
(pass_lower_vaarg::gate, pass_lower_vaarg::execute)
(make_pass_lower_vaarg): New function.
* cfgexpand.c (pass_data_expand): Add PROP_gimple_lva to
properties_required field.
* passes.def (all_passes): Add pass_lower_vaarg.
* tree-pass.h (PROP_gimple_lva): Add define.
(make_pass_lower_vaarg): Declare.
* gcc.dg/tree-ssa/stdarg-2.c: Change f15 scan-tree-dump for target
x86_64-*-*.
Co-Authored-By: Michael Matz <matz@suse.de>
From-SVN: r222173
Diffstat (limited to 'gcc/tree-stdarg.c')
-rw-r--r-- | gcc/tree-stdarg.c | 184 |
1 files changed, 171 insertions, 13 deletions
diff --git a/gcc/tree-stdarg.c b/gcc/tree-stdarg.c index 8d221a4..16a9e2c 100644 --- a/gcc/tree-stdarg.c +++ b/gcc/tree-stdarg.c @@ -52,11 +52,14 @@ along with GCC; see the file COPYING3. If not see #include "gimple-iterator.h" #include "gimple-walk.h" #include "gimple-ssa.h" +#include "gimplify.h" #include "tree-phinodes.h" #include "ssa-iterators.h" #include "stringpool.h" #include "tree-ssanames.h" +#include "tree-into-ssa.h" #include "sbitmap.h" +#include "tree-cfg.h" #include "tree-pass.h" #include "tree-stdarg.h" @@ -1016,6 +1019,112 @@ finish: } } +/* Return true if STMT is IFN_VA_ARG. */ + +static bool +gimple_call_ifn_va_arg_p (gimple stmt) +{ + return (is_gimple_call (stmt) + && gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_VA_ARG); +} + +/* Expand IFN_VA_ARGs in FUN. */ + +static void +expand_ifn_va_arg_1 (function *fun) +{ + bool modified = false; + basic_block bb; + gimple_stmt_iterator i; + + FOR_EACH_BB_FN (bb, fun) + for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) + { + gimple stmt = gsi_stmt (i); + tree ap, expr, lhs, type; + gimple_seq pre = NULL, post = NULL; + + if (!gimple_call_ifn_va_arg_p (stmt)) + continue; + + modified = true; + + type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 1))); + ap = gimple_call_arg (stmt, 0); + ap = build_fold_indirect_ref (ap); + + push_gimplify_context (false); + + expr = gimplify_va_arg_internal (ap, type, gimple_location (stmt), + &pre, &post); + + lhs = gimple_call_lhs (stmt); + if (lhs != NULL_TREE) + { + gcc_assert (useless_type_conversion_p (TREE_TYPE (lhs), type)); + + if (gimple_call_num_args (stmt) == 3) + { + /* We've transported the size of with WITH_SIZE_EXPR here as + the 3rd argument of the internal fn call. Now reinstate + it. */ + tree size = gimple_call_arg (stmt, 2); + expr = build2 (WITH_SIZE_EXPR, TREE_TYPE (expr), expr, size); + } + + /* We use gimplify_assign here, rather than gimple_build_assign, + because gimple_assign knows how to deal with variable-sized + types. */ + gimplify_assign (lhs, expr, &pre); + } + + pop_gimplify_context (NULL); + + gimple_seq_add_seq (&pre, post); + update_modified_stmts (pre); + + /* Add the sequence after IFN_VA_ARG. This splits the bb right + after IFN_VA_ARG, and adds the sequence in one or more new bbs + inbetween. */ + gimple_find_sub_bbs (pre, &i); + + /* Remove the IFN_VA_ARG gimple_call. It's the last stmt in the + bb. */ + gsi_remove (&i, true); + gcc_assert (gsi_end_p (i)); + + /* We're walking here into the bbs which contain the expansion of + IFN_VA_ARG, and will not contain another IFN_VA_ARG that needs + expanding. We could try to skip walking these bbs, perhaps by + walking backwards over gimples and bbs. */ + break; + } + + if (!modified) + return; + + free_dominance_info (CDI_DOMINATORS); + update_ssa (TODO_update_ssa); +} + +/* Expand IFN_VA_ARGs in FUN, if necessary. */ + +static void +expand_ifn_va_arg (function *fun) +{ + if ((fun->curr_properties & PROP_gimple_lva) == 0) + expand_ifn_va_arg_1 (fun); + +#if ENABLE_CHECKING + basic_block bb; + gimple_stmt_iterator i; + FOR_EACH_BB_FN (bb, fun) + for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) + gcc_assert (!gimple_call_ifn_va_arg_p (gsi_stmt (i))); +#endif +} + namespace { const pass_data pass_data_stdarg = @@ -1025,7 +1134,7 @@ const pass_data pass_data_stdarg = OPTGROUP_NONE, /* optinfo_flags */ TV_NONE, /* tv_id */ ( PROP_cfg | PROP_ssa ), /* properties_required */ - 0, /* properties_provided */ + PROP_gimple_lva, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ 0, /* todo_flags_finish */ @@ -1039,18 +1148,13 @@ public: {} /* opt_pass methods: */ - virtual bool gate (function *fun) + virtual bool gate (function *) { - return (flag_stdarg_opt -#ifdef ACCEL_COMPILER - /* Disable for GCC5 in the offloading compilers, as - va_list and gpr/fpr counter fields are not merged. - In GCC6 when stdarg is lowered late this shouldn't be - an issue. */ - && !in_lto_p -#endif - /* This optimization is only for stdarg functions. */ - && fun->stdarg != 0); + /* Always run this pass, in order to expand va_arg internal_fns. We + also need to do that if fun->stdarg == 0, because a va_arg may also + occur in a function without varargs, f.i. if when passing a va_list to + another function. */ + return true; } virtual unsigned int execute (function *); @@ -1060,7 +1164,14 @@ public: unsigned int pass_stdarg::execute (function *fun) { - optimize_va_list_gpr_fpr_size (fun); + /* TODO: Postpone expand_ifn_va_arg till after + optimize_va_list_gpr_fpr_size. */ + expand_ifn_va_arg (fun); + + if (flag_stdarg_opt + /* This optimization is only for stdarg functions. */ + && fun->stdarg != 0) + optimize_va_list_gpr_fpr_size (fun); return 0; } @@ -1072,3 +1183,50 @@ make_pass_stdarg (gcc::context *ctxt) { return new pass_stdarg (ctxt); } + +namespace { + +const pass_data pass_data_lower_vaarg = +{ + GIMPLE_PASS, /* type */ + "lower_vaarg", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + ( PROP_cfg | PROP_ssa ), /* properties_required */ + PROP_gimple_lva, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_lower_vaarg : public gimple_opt_pass +{ +public: + pass_lower_vaarg (gcc::context *ctxt) + : gimple_opt_pass (pass_data_lower_vaarg, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + return (cfun->curr_properties & PROP_gimple_lva) == 0; + } + + virtual unsigned int execute (function *); + +}; // class pass_lower_vaarg + +unsigned int +pass_lower_vaarg::execute (function *fun) +{ + expand_ifn_va_arg (fun); + return 0; +} + +} // anon namespace + +gimple_opt_pass * +make_pass_lower_vaarg (gcc::context *ctxt) +{ + return new pass_lower_vaarg (ctxt); +} |