aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimplify.c
diff options
context:
space:
mode:
authorTom de Vries <tom@codesourcery.com>2015-04-17 09:26:59 +0000
committerTom de Vries <vries@gcc.gnu.org>2015-04-17 09:26:59 +0000
commitf8e89441bc5518f450b6511c59c17c837859d109 (patch)
tree5d4de8b2de7d1bc521bef75e9c0cea144cf87699 /gcc/gimplify.c
parent1691b2e1ca494eee178a70c73c0f941ff27118f6 (diff)
downloadgcc-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/gimplify.c')
-rw-r--r--gcc/gimplify.c111
1 files changed, 81 insertions, 30 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index ff0a225..e1ea204 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -4564,6 +4564,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
gimple assign;
location_t loc = EXPR_LOCATION (*expr_p);
gimple_stmt_iterator gsi;
+ tree ap = NULL_TREE, ap_copy = NULL_TREE;
gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
|| TREE_CODE (*expr_p) == INIT_EXPR);
@@ -4640,6 +4641,27 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
if (ret == GS_ERROR)
return ret;
+ /* In case of va_arg internal fn wrappped in a WITH_SIZE_EXPR, add the type
+ size as argument to the the call. */
+ if (TREE_CODE (*from_p) == WITH_SIZE_EXPR)
+ {
+ tree call = TREE_OPERAND (*from_p, 0);
+ tree vlasize = TREE_OPERAND (*from_p, 1);
+
+ if (TREE_CODE (call) == CALL_EXPR
+ && CALL_EXPR_IFN (call) == IFN_VA_ARG)
+ {
+ tree type = TREE_TYPE (call);
+ tree ap = CALL_EXPR_ARG (call, 0);
+ tree tag = CALL_EXPR_ARG (call, 1);
+ tree newcall = build_call_expr_internal_loc (EXPR_LOCATION (call),
+ IFN_VA_ARG, type, 3, ap,
+ tag, vlasize);
+ tree *call_p = &(TREE_OPERAND (*from_p, 0));
+ *call_p = newcall;
+ }
+ }
+
/* Now see if the above changed *from_p to something we handle specially. */
ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
want_value);
@@ -4703,12 +4725,16 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
enum internal_fn ifn = CALL_EXPR_IFN (*from_p);
auto_vec<tree> vargs (nargs);
+ if (ifn == IFN_VA_ARG)
+ ap = unshare_expr (CALL_EXPR_ARG (*from_p, 0));
for (i = 0; i < nargs; i++)
{
gimplify_arg (&CALL_EXPR_ARG (*from_p, i), pre_p,
EXPR_LOCATION (*from_p));
vargs.quick_push (CALL_EXPR_ARG (*from_p, i));
}
+ if (ifn == IFN_VA_ARG)
+ ap_copy = CALL_EXPR_ARG (*from_p, 0);
call_stmt = gimple_build_call_internal_vec (ifn, vargs);
gimple_set_location (call_stmt, EXPR_LOCATION (*expr_p));
}
@@ -4753,6 +4779,17 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
gsi = gsi_last (*pre_p);
maybe_fold_stmt (&gsi);
+ /* When gimplifying the &ap argument of va_arg, we might end up with
+ ap.1 = ap
+ va_arg (&ap.1, 0B)
+ We need to assign ap.1 back to ap, otherwise va_arg has no effect on
+ ap. */
+ if (ap != NULL_TREE
+ && TREE_CODE (ap) == ADDR_EXPR
+ && TREE_CODE (ap_copy) == ADDR_EXPR
+ && TREE_OPERAND (ap, 0) != TREE_OPERAND (ap_copy, 0))
+ gimplify_assign (TREE_OPERAND (ap, 0), TREE_OPERAND (ap_copy, 0), pre_p);
+
if (want_value)
{
*expr_p = TREE_THIS_VOLATILE (*to_p) ? *from_p : unshare_expr (*to_p);
@@ -9273,16 +9310,53 @@ dummy_object (tree type)
return build2 (MEM_REF, type, t, t);
}
+/* Call the target expander for evaluating a va_arg call of VALIST
+ and TYPE. */
+
+tree
+gimplify_va_arg_internal (tree valist, tree type, location_t loc,
+ gimple_seq *pre_p, gimple_seq *post_p)
+{
+ tree have_va_type = TREE_TYPE (valist);
+ tree cano_type = targetm.canonical_va_list_type (have_va_type);
+
+ if (cano_type != NULL_TREE)
+ have_va_type = cano_type;
+
+ /* Make it easier for the backends by protecting the valist argument
+ from multiple evaluations. */
+ if (TREE_CODE (have_va_type) == ARRAY_TYPE)
+ {
+ /* For this case, the backends will be expecting a pointer to
+ TREE_TYPE (abi), but it's possible we've
+ actually been given an array (an actual TARGET_FN_ABI_VA_LIST).
+ So fix it. */
+ if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
+ {
+ tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
+ valist = fold_convert_loc (loc, p1,
+ build_fold_addr_expr_loc (loc, valist));
+ }
+
+ gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
+ }
+ else
+ gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
+
+ return targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
+}
+
/* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a
builtin function, but a very special sort of operator. */
enum gimplify_status
-gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
+gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p,
+ gimple_seq *post_p ATTRIBUTE_UNUSED)
{
tree promoted_type, have_va_type;
tree valist = TREE_OPERAND (*expr_p, 0);
tree type = TREE_TYPE (*expr_p);
- tree t;
+ tree t, tag, ap;
location_t loc = EXPR_LOCATION (*expr_p);
/* Verify that valist is of the proper type. */
@@ -9334,36 +9408,13 @@ gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
*expr_p = dummy_object (type);
return GS_ALL_DONE;
}
- else
- {
- /* Make it easier for the backends by protecting the valist argument
- from multiple evaluations. */
- if (TREE_CODE (have_va_type) == ARRAY_TYPE)
- {
- /* For this case, the backends will be expecting a pointer to
- TREE_TYPE (abi), but it's possible we've
- actually been given an array (an actual TARGET_FN_ABI_VA_LIST).
- So fix it. */
- if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
- {
- tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
- valist = fold_convert_loc (loc, p1,
- build_fold_addr_expr_loc (loc, valist));
- }
-
- gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
- }
- else
- gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
- if (!targetm.gimplify_va_arg_expr)
- /* FIXME: Once most targets are converted we should merely
- assert this is non-null. */
- return GS_ALL_DONE;
+ /* Transform a VA_ARG_EXPR into an VA_ARG internal function. */
+ ap = build_fold_addr_expr_loc (loc, valist);
+ tag = build_int_cst (build_pointer_type (type), 0);
+ *expr_p = build_call_expr_internal_loc (loc, IFN_VA_ARG, type, 2, ap, tag);
- *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
- return GS_OK;
- }
+ return GS_OK;
}
/* Build a new GIMPLE_ASSIGN tuple and append it to the end of *SEQ_P.