+2004-06-10 Jason Merrill <jason@redhat.com>
+
+ * target.h (struct gcc_target): Change gimplify_va_arg_expr
+ hook signature.
+ * tree-gimple.h: Adjust.
+ * config/alpha/alpha.c (alpha_gimplify_va_arg): Adjust.
+ * config/i386/i386.c (ix86_gimplify_va_arg): Adjust.
+ Use fold_convert.
+ * config/ia64/ia64.c (ia64_gimplify_va_arg): Adjust.
+ * config/rs6000/rs6000.c (rs6000_gimplify_va_arg): Adjust.
+ Use COMPLEX_EXPR for complex numbers. Use fold_convert.
+ * builtins.c (std_gimplify_va_arg_expr): Adjust. Use fold_convert.
+ (gimplify_va_arg_expr): Return GS_ERROR in error case.
+ Gimplify valist rather than calling stabilize_va_list.
+
2004-06-10 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* Makefile.in (df.o): Remove fibheap dependency.
(ia64_gimplify_va_arg): New fn.
* config/rs6000/rs6000.c (rs6000_gimplify_va_arg): New fn.
(TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
+<<<<<<< ChangeLog
+=======
* config/sparc/sparc.c (sparc_gimplify_va_arg): New fn.
+>>>>>>> 2.3910
* alias.c (get_varargs_alias_set): Just return 0 for now.
* c-objc-common.c (c_tree_printer): Improve handling of %T.
2004-06-08 Richard Henderson <rth@redhat.com>
+<<<<<<< ChangeLog
+ * gimple-low.c (struct lower_data): Replace the_return_label and
+ one_return_stmt with return_statements.
+ (lower_function_body): Process the entire list of return_statements.
+ (lower_return_expr): Check source value before unifying return_exprs.
+ * gimplify.c (gimplify_return_expr): Force the use of a temporary
+ for !aggregate_value_p.
+ * tree-gimple.c: Update RETURN_EXPR grammer.
+=======
* gimple-low.c (struct lower_data): Replace the_return_label and
one_return_stmt with return_statements.
(lower_function_body): Process the entire list of return_statements.
* gimplify.c (gimplify_return_expr): Force the use of a temporary
for !aggregate_value_p.
* tree-gimple.c: Update RETURN_EXPR grammer.
+>>>>>>> 2.3910
2004-06-08 Vladimir Makarov <vmakarov@redhat.com>
/* Like std_expand_builtin_va_arg, but gimplify instead of expanding. */
-void
-std_gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
+tree
+std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
{
tree addr, t, type_size = NULL;
tree align, alignm1;
tree rounded_size;
HOST_WIDE_INT boundary;
- tree valist = TREE_OPERAND (*expr_p, 0);
- tree type = TREE_TYPE (*expr_p);
/* Compute the rounded size of the type. */
align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
- /* Reduce valist it so it's sharable with the postqueue. */
- gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
-
/* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
requires greater alignment, we must perform dynamic alignment. */
type_size))))));
}
- addr = convert (build_pointer_type (type), addr);
- *expr_p = build1 (INDIRECT_REF, type, addr);
-
/* Compute new value for AP. */
if (! integer_zerop (rounded_size))
{
gimplify_stmt (&t);
append_to_statement_list (t, post_p);
}
+
+ addr = fold_convert (build_pointer_type (type), addr);
+ return build_fold_indirect_ref (addr);
}
/* Return a dummy expression of type TYPE in order to keep going after an
if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
{
error ("first argument to `va_arg' not of type `va_list'");
- *expr_p = dummy_object (type);
- return GS_ALL_DONE;
+ return GS_ERROR;
}
/* Generate a diagnostic for requesting data of a type that cannot
{
/* Make it easier for the backends by protecting the valist argument
from multiple evaluations. */
- valist = stabilize_va_list (valist, 0);
- TREE_OPERAND (*expr_p, 0) = valist;
+ if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+ {
+ /* For this case, the backends will be expecting a pointer to
+ TREE_TYPE (va_list_type_node), but it's possible we've
+ actually been given an array (an actual va_list_type_node).
+ So fix it. */
+ if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
+ {
+ tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+ valist = build_fold_addr_expr_with_type (valist, p1);
+ }
+ 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.calls.gimplify_va_arg_expr)
/* Once most targets are converted this should abort. */
return GS_ALL_DONE;
- targetm.calls.gimplify_va_arg_expr (expr_p, pre_p, post_p);
+ *expr_p = targetm.calls.gimplify_va_arg_expr (valist, type, pre_p, post_p);
return GS_OK;
}
}
else if (TREE_CODE (type) == COMPLEX_TYPE)
{
tree real_part, imag_part, real_temp;
+ tree post = NULL_TREE;
real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, offset,
- pre_p, post_p);
- append_to_statement_list (*post_p, pre_p);
- *post_p = NULL;
-
+ pre_p, &post);
/* Copy the value into a temporary, lest the formal temporary
be reused out from under us. */
- real_temp = create_tmp_var (TREE_TYPE (real_part), NULL);
- t = build (MODIFY_EXPR, void_type_node, real_temp, real_part);
- gimplify_and_add (t, pre_p);
+ real_temp = get_initialized_tmp_var (real_part, pre_p, &post);
+ append_to_statement_list (post, pre_p);
imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, offset,
pre_p, post_p);
return build_fold_indirect_ref (addr);
}
-static void
-alpha_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+static tree
+alpha_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
{
- tree valist, type, offset_field, base_field, offset, base, t;
+ tree offset_field, base_field, offset, base, t, r;
if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
- {
- std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
- return;
- }
-
- valist = TREE_OPERAND (*expr_p, 0);
- type = TREE_TYPE (*expr_p);
+ return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
base_field = TYPE_FIELDS (va_list_type_node);
offset_field = TREE_CHAIN (base_field);
/* Find the value. Note that this will be a stable indirection, or
a composite of stable indirections in the case of complex. */
- *expr_p = alpha_gimplify_va_arg_1 (type, base, offset, pre_p, post_p);
+ r = alpha_gimplify_va_arg_1 (type, base, offset, pre_p, post_p);
/* Stuff the offset temporary back into its field. */
t = build (MODIFY_EXPR, void_type_node, offset_field,
fold_convert (TREE_TYPE (offset_field), offset));
gimplify_and_add (t, pre_p);
+
+ return r;
}
\f
/* Builtins. */
static tree ix86_build_builtin_va_list (void);
static void ix86_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
tree, int *, int);
-static void ix86_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p);
+static tree ix86_gimplify_va_arg (tree, tree, tree *, tree *);
struct ix86_address
{
/* Lower VA_ARG_EXPR at gimplification time. */
-void
-ix86_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+tree
+ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
{
- tree valist = TREE_OPERAND (*expr_p, 0);
- tree type = TREE_TYPE (*expr_p);
static const int intreg[6] = { 0, 1, 2, 3, 4, 5 };
tree f_gpr, f_fpr, f_ovf, f_sav;
tree gpr, fpr, ovf, sav, t;
/* Only 64bit target needs something special. */
if (!TARGET_64BIT)
- {
- std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
- return;
- }
+ return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
f_fpr = TREE_CHAIN (f_gpr);
src_addr = int_addr;
src_offset = REGNO (reg) * 8;
}
- src_addr = convert (addr_type, src_addr);
+ src_addr = fold_convert (addr_type, src_addr);
src_addr = fold (build2 (PLUS_EXPR, addr_type, src_addr,
size_int (src_offset)));
src = build_fold_indirect_ref (src_addr);
- dest_addr = convert (addr_type, addr);
+ dest_addr = fold_convert (addr_type, addr);
dest_addr = fold (build2 (PLUS_EXPR, addr_type, dest_addr,
size_int (INTVAL (XEXP (slot, 1)))));
dest = build_fold_indirect_ref (dest_addr);
}
ptrtype = build_pointer_type (type);
- addr = convert (ptrtype, addr);
+ addr = fold_convert (ptrtype, addr);
if (indirect_p)
addr = build_fold_indirect_ref (addr);
- *expr_p = build_fold_indirect_ref (addr);
+ return build_fold_indirect_ref (addr);
}
\f
/* Return nonzero if OP is either a i387 or SSE fp register. */
static tree ia64_handle_model_attribute (tree *, tree, tree, int, bool *);
static void ia64_encode_section_info (tree, rtx, int);
static rtx ia64_struct_value_rtx (tree, int);
-static void ia64_gimplify_va_arg (tree *, tree *, tree *);
+static tree ia64_gimplify_va_arg (tree, tree, tree *, tree *);
\f
/* Table of valid machine attributes. */
return std_expand_builtin_va_arg (valist, type);
}
-static void
-ia64_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+static tree
+ia64_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
{
- tree valist = TREE_OPERAND (*expr_p, 0);
- tree type = TREE_TYPE (*expr_p);
-
/* Variable sized types are passed by reference. */
if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
{
- TREE_TYPE (*expr_p) = build_pointer_type (type);
- std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
- *expr_p = build_fold_indirect_ref (*expr_p);
- return;
+ tree ptrtype = build_pointer_type (type);
+ tree addr = std_gimplify_va_arg_expr (valist, ptrtype, pre_p, post_p);
+ return build_fold_indirect_ref (addr);
}
/* Aggregate arguments with alignment larger than 8 bytes start at
gimplify_and_add (t, pre_p);
}
- std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
+ return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
}
\f
/* Return 1 if function return value returned in memory. Return 0 if it is
#endif
static tree rs6000_build_builtin_va_list (void);
-static void rs6000_gimplify_va_arg (tree *, tree *, tree *);
+static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
/* Hash table stuff for keeping track of TOC entries. */
return addr_rtx;
}
-void
-rs6000_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+tree
+rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
{
- tree valist = TREE_OPERAND (*expr_p, 0);
- tree type = TREE_TYPE (*expr_p);
tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
tree gpr, fpr, ovf, sav, reg, t, u;
int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
t = build1 (NOP_EXPR, build_pointer_type (ptrtype), t);
t = build_fold_indirect_ref (t);
- t = build_fold_indirect_ref (t);
-
- *expr_p = t;
- return;
+ return build_fold_indirect_ref (t);
}
if (targetm.calls.split_complex_arg
&& TREE_CODE (type) == COMPLEX_TYPE)
if (elem_size < UNITS_PER_WORD)
{
- tree real_part, imag_addr, dest_real, rr;
+ tree real_part, imag_part;
tree post = NULL_TREE;
- /* This is a bit tricky because we can't just feed the
- VA_ARG_EXPRs back into gimplify_expr; if we did,
- gimplify_va_arg_expr would complain about trying to pass a
- float. */
- real_part = build1 (VA_ARG_EXPR, elem_type, valist);
- rs6000_gimplify_va_arg (&real_part, pre_p, &post);
- gimplify_expr (&real_part, pre_p, &post, is_gimple_val,
- fb_rvalue);
+ real_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p,
+ &post);
+ /* Copy the value into a temporary, lest the formal temporary
+ be reused out from under us. */
+ real_part = get_initialized_tmp_var (real_part, pre_p, &post);
append_to_statement_list (post, pre_p);
- imag_addr = build1 (VA_ARG_EXPR, elem_type, valist);
- rs6000_gimplify_va_arg (&imag_addr, pre_p, post_p);
- imag_addr = build_fold_addr_expr (imag_addr);
- gimplify_expr (&imag_addr, pre_p, post_p, is_gimple_val,
- fb_rvalue);
-
- /* We're not returning the value here, but the address.
- real_part and imag_part are not contiguous, and we know
- there is space available to pack real_part next to
- imag_part. float _Complex is not promoted to
- double _Complex by the default promotion rules that
- promote float to double. */
- if (2 * elem_size > UNITS_PER_WORD)
- abort ();
-
- dest_real = fold (build2 (MINUS_EXPR, TREE_TYPE (imag_addr),
- imag_addr, ssize_int (elem_size)));
- gimplify_expr (&dest_real, pre_p, post_p, is_gimple_val,
- fb_rvalue);
+ imag_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p,
+ post_p);
- rr = build_fold_indirect_ref (dest_real);
- rr = build2 (MODIFY_EXPR, void_type_node, rr, real_part);
- gimplify_and_add (rr, pre_p);
-
- dest_real = convert (build_pointer_type (type), dest_real);
- *expr_p = build_fold_indirect_ref (dest_real);
-
- return;
+ return build (COMPLEX_EXPR, type, real_part, imag_part);
}
}
- std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
- return;
+ return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
}
f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
if (indirect_p)
{
- addr = convert (build_pointer_type (ptrtype), addr);
+ addr = fold_convert (build_pointer_type (ptrtype), addr);
addr = build_fold_indirect_ref (addr);
}
else
- addr = convert (ptrtype, addr);
+ addr = fold_convert (ptrtype, addr);
- *expr_p = build_fold_indirect_ref (addr);
+ return build_fold_indirect_ref (addr);
}
/* Builtins. */
false.
@end deftypefn
+@deftypefn {Target Hook} tree TARGET_GIMPLIFY_VA_ARG_EXPR (tree @var{valist}, tree @var{type}, tree *@var{pre_p}, tree *@var{post_p})
+This hook performs target-specific gimplification of
+@code{VA_ARG_EXPR}. The first two parameters correspond to the
+arguments to @code{va_arg}; the latter two are as in
+@code{gimplify.c:gimplify_expr}.
+
+You only need to define this hook if you also define
+@code{EXPAND_BUILTIN_VA_ARG}; it is pretty easy to reuse the same code
+for both. One significant difference is that
+@code{EXPAND_BUILTIN_VA_ARG} returns an address, whereas this hook
+produces an expression of type @var{type}, usually an @code{INDIRECT_REF}.
+@end deftypefn
+
@node Scalar Return
@subsection How Scalar Function Values Are Returned
@cindex return values in registers
bool (* split_complex_arg) (tree type);
/* Gimplifies a VA_ARG_EXPR. */
- void (* gimplify_va_arg_expr) (tree *expr_p, tree *pre_p,
+ tree (* gimplify_va_arg_expr) (tree valist, tree type, tree *pre_p,
tree *post_p);
} calls;
void free_stmt_list (tree);
tree force_labels_r (tree *, int *, void *);
enum gimplify_status gimplify_va_arg_expr (tree *, tree *, tree *);
-void std_gimplify_va_arg_expr (tree *, tree *, tree *);
+tree std_gimplify_va_arg_expr (tree, tree, tree *, tree *);
/* In tree-nested.c. */
extern void lower_nested_functions (tree);