I originally shuffled std_gimplify_va_arg_expr () to gimplify.c, but i
believe the suggestion was to eventually move it to targhooks.c.
build_va_arg_indirect_ref seems to hang around with it, and used by all
the same things that use std_gimplify_va_arg_expr, so this patch
currently lumps it in targhooks.c as well (which means they will get it
with the same header file). Really, I suppose it should go elsewhere..
and I'd guess tree.c... but its nots 100% obvious... suggestions
welcome. I'd think someday this file will get split into
gimple-targhooks and rtl-targhooks, but not today i think. :-)
It also seems appropriate to move gimplify_va_arg_expr from builtins.c
to gimplify.c since its a gimplification routiine.. This showed up as I
was splitting gimple.h into gimplify.h... the prototype is in gimple.h
and it made sense to become part of gimplify.h as I try to move towards
an interface from front-ends that only requires gimplfy.h and not
gimple.h or other middle end things.
bootstraps on x86_64-unknown-linux-gnu with no new regressions. OK?
Anrdew
* builtins.c (dummy_object, gimplify_va_arg_expr): Move to gimplify.c.
* gimplify.c (build_va_arg_indirect_ref, std_gimplify_va_arg_expr):
Move to targhooks.c.
(dummy_object, gimplify_va_arg_expr): Relocate from builtins.c.
* targhooks.c (build_va_arg_indirect_ref, std_gimplify_va_arg_expr):
Relocate from gimplify.c.
* targhooks.h: Add 2 prototypes.
* tree.h. Delete 2 prototypes.
Index: builtins.c
===================================================================
*** builtins.c (revision 203915)
--- builtins.c (working copy)
*************** expand_builtin_va_start (tree exp)
*** 4233,4342 ****
return const0_rtx;
}
-
- /* Return a dummy expression of type TYPE in order to keep going after an
- error. */
-
- static tree
- dummy_object (tree type)
- {
- tree t = build_int_cst (build_pointer_type (type), 0);
- return build2 (MEM_REF, type, t, t);
- }
-
- /* 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)
- {
- tree promoted_type, have_va_type;
- tree valist = TREE_OPERAND (*expr_p, 0);
- tree type = TREE_TYPE (*expr_p);
- tree t;
- location_t loc = EXPR_LOCATION (*expr_p);
-
- /* Verify that valist is of the proper type. */
- have_va_type = TREE_TYPE (valist);
- if (have_va_type == error_mark_node)
- return GS_ERROR;
- have_va_type = targetm.canonical_va_list_type (have_va_type);
-
- if (have_va_type == NULL_TREE)
- {
- error_at (loc, "first argument to %<va_arg%> not of type %<va_list%>");
- return GS_ERROR;
- }
-
- /* Generate a diagnostic for requesting data of a type that cannot
- be passed through `...' due to type promotion at the call site. */
- if ((promoted_type = lang_hooks.types.type_promotes_to (type))
- != type)
- {
- static bool gave_help;
- bool warned;
-
- /* Unfortunately, this is merely undefined, rather than a constraint
- violation, so we cannot make this an error. If this call is never
- executed, the program is still strictly conforming. */
- warned = warning_at (loc, 0,
- "%qT is promoted to %qT when passed through %<...%>",
- type, promoted_type);
- if (!gave_help && warned)
- {
- gave_help = true;
- inform (loc, "(so you should pass %qT not %qT to %<va_arg%>)",
- promoted_type, type);
- }
-
- /* We can, however, treat "undefined" any way we please.
- Call abort to encourage the user to fix the program. */
- if (warned)
- inform (loc, "if this code is reached, the program will abort");
- /* Before the abort, allow the evaluation of the va_list
- expression to exit or longjmp. */
- gimplify_and_add (valist, pre_p);
- t = build_call_expr_loc (loc,
- builtin_decl_implicit (BUILT_IN_TRAP), 0);
- gimplify_and_add (t, pre_p);
-
- /* This is dead code, but go ahead and finish so that the
- mode of the result comes out right. */
- *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;
-
- *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
- return GS_OK;
- }
- }
-
/* Expand EXP, a call to __builtin_va_end. */
static rtx
--- 4233,4238 ----
Index: gimplify.c
===================================================================
*** gimplify.c (revision 203915)
--- gimplify.c (working copy)
*************** force_gimple_operand_gsi (gimple_stmt_it
*** 9228,9345 ****
var, before, m);
}
! #ifndef PAD_VARARGS_DOWN
! #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
! #endif
!
! /* Build an indirect-ref expression over the given TREE, which represents a
! piece of a va_arg() expansion. */
! tree
! build_va_arg_indirect_ref (tree addr)
! {
! addr = build_simple_mem_ref_loc (EXPR_LOCATION (addr), addr);
!
! if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF. */
! mf_mark (addr);
! return addr;
}
! /* The "standard" implementation of va_arg: read the value from the
! current (padded) address and increment by the (padded) size. */
! tree
! std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
! gimple_seq *post_p)
{
! tree addr, t, type_size, rounded_size, valist_tmp;
! unsigned HOST_WIDE_INT align, boundary;
! bool indirect;
!
! #ifdef ARGS_GROW_DOWNWARD
! /* All of the alignment and movement below is for args-grow-up machines.
! As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all
! implement their own specialized gimplify_va_arg_expr routines. */
! gcc_unreachable ();
! #endif
!
! indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
! if (indirect)
! type = build_pointer_type (type);
!
! align = PARM_BOUNDARY / BITS_PER_UNIT;
! boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
!
! /* When we align parameter on stack for caller, if the parameter
! alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
! aligned at MAX_SUPPORTED_STACK_ALIGNMENT. We will match callee
! here with caller. */
! if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
! boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
!
! boundary /= BITS_PER_UNIT;
!
! /* Hoist the valist value into a temporary for the moment. */
! valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
!
! /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
! requires greater alignment, we must perform dynamic alignment. */
! if (boundary > align
! && !integer_zerop (TYPE_SIZE (type)))
! {
! t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
! fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
! gimplify_and_add (t, pre_p);
!
! t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
! fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
! valist_tmp,
! build_int_cst (TREE_TYPE (valist), -boundary)));
! gimplify_and_add (t, pre_p);
! }
! else
! boundary = align;
! /* If the actual alignment is less than the alignment of the type,
! adjust the type accordingly so that we don't assume strict alignment
! when dereferencing the pointer. */
! boundary *= BITS_PER_UNIT;
! if (boundary < TYPE_ALIGN (type))
{
! type = build_variant_type_copy (type);
! TYPE_ALIGN (type) = boundary;
}
! /* Compute the rounded size of the type. */
! type_size = size_in_bytes (type);
! rounded_size = round_up (type_size, align);
!
! /* Reduce rounded_size so it's sharable with the postqueue. */
! gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
!
! /* Get AP. */
! addr = valist_tmp;
! if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
{
! /* Small args are padded downward. */
! t = fold_build2_loc (input_location, GT_EXPR, sizetype,
! rounded_size, size_int (align));
! t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
! size_binop (MINUS_EXPR, rounded_size, type_size));
! addr = fold_build_pointer_plus (addr, t);
! }
! /* Compute new value for AP. */
! t = fold_build_pointer_plus (valist_tmp, rounded_size);
! t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
! gimplify_and_add (t, pre_p);
!
! addr = fold_convert (build_pointer_type (type), addr);
! if (indirect)
! addr = build_va_arg_indirect_ref (addr);
! return build_va_arg_indirect_ref (addr);
}
#include "gt-gimplify.h"
--- 9228,9334 ----
var, before, m);
}
! /* Return a dummy expression of type TYPE in order to keep going after an
! error. */
! static tree
! dummy_object (tree type)
! {
! tree t = build_int_cst (build_pointer_type (type), 0);
! return build2 (MEM_REF, type, t, t);
}
! /* 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)
{
! tree promoted_type, have_va_type;
! tree valist = TREE_OPERAND (*expr_p, 0);
! tree type = TREE_TYPE (*expr_p);
! tree t;
! location_t loc = EXPR_LOCATION (*expr_p);
!
! /* Verify that valist is of the proper type. */
! have_va_type = TREE_TYPE (valist);
! if (have_va_type == error_mark_node)
! return GS_ERROR;
! have_va_type = targetm.canonical_va_list_type (have_va_type);
! if (have_va_type == NULL_TREE)
{
! error_at (loc, "first argument to %<va_arg%> not of type %<va_list%>");
! return GS_ERROR;
}
! /* Generate a diagnostic for requesting data of a type that cannot
! be passed through `...' due to type promotion at the call site. */
! if ((promoted_type = lang_hooks.types.type_promotes_to (type))
! != type)
{
! static bool gave_help;
! bool warned;
! /* Unfortunately, this is merely undefined, rather than a constraint
! violation, so we cannot make this an error. If this call is never
! executed, the program is still strictly conforming. */
! warned = warning_at (loc, 0,
! "%qT is promoted to %qT when passed through %<...%>",
! type, promoted_type);
! if (!gave_help && warned)
! {
! gave_help = true;
! inform (loc, "(so you should pass %qT not %qT to %<va_arg%>)",
! promoted_type, type);
! }
!
! /* We can, however, treat "undefined" any way we please.
! Call abort to encourage the user to fix the program. */
! if (warned)
! inform (loc, "if this code is reached, the program will abort");
! /* Before the abort, allow the evaluation of the va_list
! expression to exit or longjmp. */
! gimplify_and_add (valist, pre_p);
! t = build_call_expr_loc (loc,
! builtin_decl_implicit (BUILT_IN_TRAP), 0);
! gimplify_and_add (t, pre_p);
! /* This is dead code, but go ahead and finish so that the
! mode of the result comes out right. */
! *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;
! *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
! return GS_OK;
! }
}
#include "gt-gimplify.h"
Index: targhooks.c
===================================================================
*** targhooks.c (revision 203915)
--- targhooks.c (working copy)
*************** along with GCC; see the file COPYING3.
*** 71,76 ****
--- 71,77 ----
#include "tree-ssa.h"
#include "tree-ssa-alias.h"
#include "insn-codes.h"
+ #include "tree-mudflap.h"
bool
*************** default_canonicalize_comparison (int *,
*** 1564,1567 ****
--- 1565,1683 ----
{
}
+ #ifndef PAD_VARARGS_DOWN
+ #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
+ #endif
+
+ /* Build an indirect-ref expression over the given TREE, which represents a
+ piece of a va_arg() expansion. */
+ tree
+ build_va_arg_indirect_ref (tree addr)
+ {
+ addr = build_simple_mem_ref_loc (EXPR_LOCATION (addr), addr);
+
+ if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF. */
+ mf_mark (addr);
+
+ return addr;
+ }
+
+ /* The "standard" implementation of va_arg: read the value from the
+ current (padded) address and increment by the (padded) size. */
+
+ tree
+ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
+ gimple_seq *post_p)
+ {
+ tree addr, t, type_size, rounded_size, valist_tmp;
+ unsigned HOST_WIDE_INT align, boundary;
+ bool indirect;
+
+ #ifdef ARGS_GROW_DOWNWARD
+ /* All of the alignment and movement below is for args-grow-up machines.
+ As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all
+ implement their own specialized gimplify_va_arg_expr routines. */
+ gcc_unreachable ();
+ #endif
+
+ indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
+ if (indirect)
+ type = build_pointer_type (type);
+
+ align = PARM_BOUNDARY / BITS_PER_UNIT;
+ boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
+
+ /* When we align parameter on stack for caller, if the parameter
+ alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
+ aligned at MAX_SUPPORTED_STACK_ALIGNMENT. We will match callee
+ here with caller. */
+ if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
+ boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
+
+ boundary /= BITS_PER_UNIT;
+
+ /* Hoist the valist value into a temporary for the moment. */
+ valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
+
+ /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
+ requires greater alignment, we must perform dynamic alignment. */
+ if (boundary > align
+ && !integer_zerop (TYPE_SIZE (type)))
+ {
+ t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
+ fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
+ gimplify_and_add (t, pre_p);
+
+ t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
+ fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
+ valist_tmp,
+ build_int_cst (TREE_TYPE (valist), -boundary)));
+ gimplify_and_add (t, pre_p);
+ }
+ else
+ boundary = align;
+
+ /* If the actual alignment is less than the alignment of the type,
+ adjust the type accordingly so that we don't assume strict alignment
+ when dereferencing the pointer. */
+ boundary *= BITS_PER_UNIT;
+ if (boundary < TYPE_ALIGN (type))
+ {
+ type = build_variant_type_copy (type);
+ TYPE_ALIGN (type) = boundary;
+ }
+
+ /* Compute the rounded size of the type. */
+ type_size = size_in_bytes (type);
+ rounded_size = round_up (type_size, align);
+
+ /* Reduce rounded_size so it's sharable with the postqueue. */
+ gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
+
+ /* Get AP. */
+ addr = valist_tmp;
+ if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
+ {
+ /* Small args are padded downward. */
+ t = fold_build2_loc (input_location, GT_EXPR, sizetype,
+ rounded_size, size_int (align));
+ t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
+ size_binop (MINUS_EXPR, rounded_size, type_size));
+ addr = fold_build_pointer_plus (addr, t);
+ }
+
+ /* Compute new value for AP. */
+ t = fold_build_pointer_plus (valist_tmp, rounded_size);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+ gimplify_and_add (t, pre_p);
+
+ addr = fold_convert (build_pointer_type (type), addr);
+
+ if (indirect)
+ addr = build_va_arg_indirect_ref (addr);
+
+ return build_va_arg_indirect_ref (addr);
+ }
+
+
#include "gt-targhooks.h"
Index: targhooks.h
===================================================================
*** targhooks.h (revision 203915)
--- targhooks.h (working copy)
*************** extern void default_asm_output_ident_dir
*** 202,204 ****
--- 202,206 ----
extern enum machine_mode default_cstore_mode (enum insn_code);
extern bool default_member_type_forces_blk (const_tree, enum machine_mode);
+ extern tree build_va_arg_indirect_ref (tree);
+ extern tree std_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
Index: tree.h
===================================================================
*** tree.h (revision 203915)
--- tree.h (working copy)
*************** extern tree build_call_expr_loc (locatio
*** 4508,4515 ****
extern tree build_call_expr (tree, int, ...);
extern tree mathfn_built_in (tree, enum built_in_function fn);
extern tree c_strlen (tree, int);
- extern tree std_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
- extern tree build_va_arg_indirect_ref (tree);
extern tree build_string_literal (int, const char *);
extern bool validate_arglist (const_tree, ...);
extern rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
--- 4508,4513 ----