Newer
Older
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;
/* 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;
Andrew MacLeod
committed
/* Build a new GIMPLE_ASSIGN tuple and append it to the end of *SEQ_P.
DST/SRC are the destination and source respectively. You can pass
ungimplified trees in DST or SRC, in which case they will be
converted to a gimple operand if necessary.
This function returns the newly created GIMPLE_ASSIGN tuple. */
gimple
gimplify_assign (tree dst, tree src, gimple_seq *seq_p)
{
tree t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
gimplify_and_add (t, seq_p);
ggc_free (t);
return gimple_seq_last_stmt (*seq_p);
}
9117
9118
9119
9120
9121
9122
9123
9124
9125
9126
9127
9128
9129
9130
9131
9132
9133
9134
9135
9136
9137
9138
9139
9140
9141
9142
9143
9144
9145
inline hashval_t
gimplify_hasher::hash (const value_type *p)
{
tree t = p->val;
return iterative_hash_expr (t, 0);
}
inline bool
gimplify_hasher::equal (const value_type *p1, const compare_type *p2)
{
tree t1 = p1->val;
tree t2 = p2->val;
enum tree_code code = TREE_CODE (t1);
if (TREE_CODE (t2) != code
|| TREE_TYPE (t1) != TREE_TYPE (t2))
return false;
if (!operand_equal_p (t1, t2, 0))
return false;
#ifdef ENABLE_CHECKING
/* Only allow them to compare equal if they also hash equal; otherwise
results are nondeterminate, and we fail bootstrap comparison. */
gcc_assert (hash (p1) == hash (p2));
#endif
return true;
}