2
0
mirror of git://gcc.gnu.org/git/gcc.git synced 2025-04-13 12:31:16 +08:00

mips-protos.h (mips_va_arg): Delete.

* config/mips/mips-protos.h (mips_va_arg): Delete.
	* config/mips/mips.h (EXPAND_BUILTIN_VA_ARG): Delete.
	* config/mips/mips.c: Include tree-gimple.h.
	(TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
	(mips_arg_info): Remove special handling of must_pass_in_stck args.
	(mips_gimplify_va_arg_expr): Rewritten from mips_va_arg.
	(function_arg_pass_by_reference): Return true if must_pass_in_stack.

Co-Authored-By: Richard Sandiford <rsandifo@redhat.com>

From-SVN: r84671
This commit is contained in:
Richard Henderson 2004-07-13 22:58:30 -07:00 committed by Richard Sandiford
parent 1cb6d0da5f
commit 0310e5373b
4 changed files with 192 additions and 278 deletions

@ -1,3 +1,14 @@
2004-07-14 Richard Henderson <rth@redhat.com>
Richard Sandiford <rsandifo@redhat.com>
* config/mips/mips-protos.h (mips_va_arg): Delete.
* config/mips/mips.h (EXPAND_BUILTIN_VA_ARG): Delete.
* config/mips/mips.c: Include tree-gimple.h.
(TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
(mips_arg_info): Remove special handling of must_pass_in_stck args.
(mips_gimplify_va_arg_expr): Rewritten from mips_va_arg.
(function_arg_pass_by_reference): Return true if must_pass_in_stack.
2004-07-13 Bob Wilson <bob.wilson@acm.org>
* config/xtensa/xtensa.c (xtensa_gimplify_va_arg_expr): Swap

@ -143,7 +143,6 @@ extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *,
extern bool mips_pad_arg_upward (enum machine_mode, tree);
extern bool mips_pad_reg_upward (enum machine_mode, tree);
extern void mips_va_start (tree, rtx);
extern struct rtx_def *mips_va_arg (tree, tree);
extern bool mips_expand_unaligned_load (rtx, rtx, unsigned int, int);
extern bool mips_expand_unaligned_store (rtx, rtx, unsigned int, int);

@ -55,6 +55,7 @@ Boston, MA 02111-1307, USA. */
#include "langhooks.h"
#include "cfglayout.h"
#include "sched-int.h"
#include "tree-gimple.h"
/* Enumeration for all of the relational tests, so that we can build
arrays indexed by the test type, and not worry about the order
@ -288,6 +289,7 @@ static void mips_init_libfuncs (void);
static void mips_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
tree, int *, int);
static tree mips_build_builtin_va_list (void);
static tree mips_gimplify_va_arg_expr (tree, tree, tree *, tree *);
#if TARGET_IRIX
static void irix_asm_named_section_1 (const char *, unsigned int,
@ -716,6 +718,8 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
#undef TARGET_BUILD_BUILTIN_VA_LIST
#define TARGET_BUILD_BUILTIN_VA_LIST mips_build_builtin_va_list
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
#define TARGET_GIMPLIFY_VA_ARG_EXPR mips_gimplify_va_arg_expr
#undef TARGET_PROMOTE_FUNCTION_ARGS
#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
@ -3554,22 +3558,15 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
even_reg_p = true;
}
if (mips_abi != ABI_EABI && targetm.calls.must_pass_in_stack (mode, type))
/* This argument must be passed on the stack. Eat up all the
remaining registers. */
info->reg_offset = MAX_ARGS_IN_REGISTERS;
else
{
/* Set REG_OFFSET to the register count we're interested in.
The EABI allocates the floating-point registers separately,
but the other ABIs allocate them like integer registers. */
info->reg_offset = (mips_abi == ABI_EABI && info->fpr_p
? cum->num_fprs
: cum->num_gprs);
/* Set REG_OFFSET to the register count we're interested in.
The EABI allocates the floating-point registers separately,
but the other ABIs allocate them like integer registers. */
info->reg_offset = (mips_abi == ABI_EABI && info->fpr_p
? cum->num_fprs
: cum->num_gprs);
if (even_reg_p)
info->reg_offset += info->reg_offset & 1;
}
if (even_reg_p)
info->reg_offset += info->reg_offset & 1;
/* The alignment applied to registers is also applied to stack arguments. */
info->stack_offset = cum->stack_words;
@ -4041,272 +4038,179 @@ mips_va_start (tree valist, rtx nextarg)
/* Implement va_arg. */
rtx
mips_va_arg (tree valist, tree type)
static tree
mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
{
HOST_WIDE_INT size, rsize;
rtx addr_rtx;
tree t;
tree addr;
bool indirect;
indirect
= function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
if (indirect)
type = build_pointer_type (type);
size = int_size_in_bytes (type);
rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
if (mips_abi == ABI_EABI)
{
bool indirect;
rtx r;
indirect
= function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
if (indirect)
{
size = POINTER_SIZE / BITS_PER_UNIT;
rsize = UNITS_PER_WORD;
}
if (!EABI_FLOAT_VARARGS_P)
{
/* Case of all args in a merged stack. No need to check bounds,
just advance valist along the stack. */
tree gpr = valist;
if (!indirect
&& !TARGET_64BIT
&& TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD)
{
/* Align the pointer using: ap = (ap + align - 1) & -align,
where align is 2 * UNITS_PER_WORD. */
t = build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
build_int_2 (2 * UNITS_PER_WORD - 1, 0));
t = build (BIT_AND_EXPR, TREE_TYPE (t), t,
build_int_2 (-2 * UNITS_PER_WORD, -1));
t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
/* Emit code to set addr_rtx to the valist, and postincrement
the valist by the size of the argument, rounded up to the
next word. Account for padding on big-endian targets. */
t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr,
size_int (rsize));
addr_rtx = expand_expr (t, 0, Pmode, EXPAND_NORMAL);
if (BYTES_BIG_ENDIAN)
addr_rtx = plus_constant (addr_rtx, rsize - size);
/* Flush the POSTINCREMENT. */
emit_queue();
}
else
{
/* Not a simple merged stack. */
tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
tree ovfl, top, off;
rtx lab_over = NULL_RTX, lab_false;
HOST_WIDE_INT osize;
addr_rtx = gen_reg_rtx (Pmode);
f_ovfl = TYPE_FIELDS (va_list_type_node);
f_gtop = TREE_CHAIN (f_ovfl);
f_ftop = TREE_CHAIN (f_gtop);
f_goff = TREE_CHAIN (f_ftop);
f_foff = TREE_CHAIN (f_goff);
/* We maintain separate pointers and offsets for floating-point
and integer arguments, but we need similar code in both cases.
Let:
TOP be the top of the register save area;
OFF be the offset from TOP of the next register;
ADDR_RTX be the address of the argument;
RSIZE be the number of bytes used to store the argument
when it's in the register save area;
OSIZE be the number of bytes used to store it when it's
in the stack overflow area; and
PADDING be (BYTES_BIG_ENDIAN ? OSIZE - RSIZE : 0)
The code we want is:
1: off &= -rsize; // round down
2: if (off != 0)
3: {
4: addr_rtx = top - off;
5: off -= rsize;
6: }
7: else
8: {
9: ovfl += ((intptr_t) ovfl + osize - 1) & -osize;
10: addr_rtx = ovfl + PADDING;
11: ovfl += osize;
14: }
[1] and [9] can sometimes be optimized away. */
lab_false = gen_label_rtx ();
lab_over = gen_label_rtx ();
ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
NULL_TREE);
if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
&& GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
{
top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
NULL_TREE);
off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
NULL_TREE);
/* When floating-point registers are saved to the stack,
each one will take up UNITS_PER_HWFPVALUE bytes, regardless
of the float's precision. */
rsize = UNITS_PER_HWFPVALUE;
/* Overflow arguments are padded to UNITS_PER_WORD bytes
(= PARM_BOUNDARY bits). This can be different from RSIZE
in two cases:
(1) On 32-bit targets when TYPE is a structure such as:
struct s { float f; };
Such structures are passed in paired FPRs, so RSIZE
will be 8 bytes. However, the structure only takes
up 4 bytes of memory, so OSIZE will only be 4.
(2) In combinations such as -mgp64 -msingle-float
-fshort-double. Doubles passed in registers
will then take up 4 (UNITS_PER_HWFPVALUE) bytes,
but those passed on the stack take up
UNITS_PER_WORD bytes. */
osize = MAX (GET_MODE_SIZE (TYPE_MODE (type)), UNITS_PER_WORD);
}
else
{
top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
NULL_TREE);
off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
NULL_TREE);
if (rsize > UNITS_PER_WORD)
{
/* [1] Emit code for: off &= -rsize. */
t = build (BIT_AND_EXPR, TREE_TYPE (off), off,
build_int_2 (-rsize, -1));
t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
osize = rsize;
}
/* [2] Emit code to branch if off == 0. */
r = expand_expr (off, NULL_RTX, TYPE_MODE (TREE_TYPE (off)),
EXPAND_NORMAL);
emit_cmp_and_jump_insns (r, const0_rtx, EQ, const1_rtx, GET_MODE (r),
1, lab_false);
/* [4] Emit code for: addr_rtx = top - off. On big endian machines,
the argument has RSIZE - SIZE bytes of leading padding. */
t = build (MINUS_EXPR, TREE_TYPE (top), top, off);
if (BYTES_BIG_ENDIAN && rsize > size)
t = build (PLUS_EXPR, TREE_TYPE (t), t,
build_int_2 (rsize - size, 0));
r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
if (r != addr_rtx)
emit_move_insn (addr_rtx, r);
/* [5] Emit code for: off -= rsize. */
t = build (MINUS_EXPR, TREE_TYPE (off), off, build_int_2 (rsize, 0));
t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
/* [7] Emit code to jump over the else clause, then the label
that starts it. */
emit_queue();
emit_jump (lab_over);
emit_barrier ();
emit_label (lab_false);
if (osize > UNITS_PER_WORD)
{
/* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize. */
t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl,
build_int_2 (osize - 1, 0));
t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t,
build_int_2 (-osize, -1));
t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
/* [10, 11]. Emit code to store ovfl in addr_rtx, then
post-increment ovfl by osize. On big-endian machines,
the argument has OSIZE - SIZE bytes of leading padding. */
t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl,
size_int (osize));
if (BYTES_BIG_ENDIAN && osize > size)
t = build (PLUS_EXPR, TREE_TYPE (t), t,
build_int_2 (osize - size, 0));
r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
if (r != addr_rtx)
emit_move_insn (addr_rtx, r);
emit_queue();
emit_label (lab_over);
}
if (indirect)
{
addr_rtx = force_reg (Pmode, addr_rtx);
r = gen_rtx_MEM (Pmode, addr_rtx);
set_mem_alias_set (r, get_varargs_alias_set ());
emit_move_insn (addr_rtx, r);
}
return addr_rtx;
}
if (mips_abi != ABI_EABI || !EABI_FLOAT_VARARGS_P)
addr = std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
else
{
/* Not EABI. */
int align;
HOST_WIDE_INT min_offset;
/* Not a simple merged stack. */
/* ??? The original va-mips.h did always align, despite the fact
that alignments <= UNITS_PER_WORD are preserved by the va_arg
increment mechanism. */
tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
tree ovfl, top, off, align;
HOST_WIDE_INT osize;
tree t, u;
if (TARGET_NEWABI && TYPE_ALIGN (type) > 64)
align = 16;
else if (TARGET_64BIT)
align = 8;
else if (TYPE_ALIGN (type) > 32)
align = 8;
f_ovfl = TYPE_FIELDS (va_list_type_node);
f_gtop = TREE_CHAIN (f_ovfl);
f_ftop = TREE_CHAIN (f_gtop);
f_goff = TREE_CHAIN (f_ftop);
f_foff = TREE_CHAIN (f_goff);
/* We maintain separate pointers and offsets for floating-point
and integer arguments, but we need similar code in both cases.
Let:
TOP be the top of the register save area;
OFF be the offset from TOP of the next register;
ADDR_RTX be the address of the argument;
RSIZE be the number of bytes used to store the argument
when it's in the register save area;
OSIZE be the number of bytes used to store it when it's
in the stack overflow area; and
PADDING be (BYTES_BIG_ENDIAN ? OSIZE - RSIZE : 0)
The code we want is:
1: off &= -rsize; // round down
2: if (off != 0)
3: {
4: addr_rtx = top - off;
5: off -= rsize;
6: }
7: else
8: {
9: ovfl += ((intptr_t) ovfl + osize - 1) & -osize;
10: addr_rtx = ovfl + PADDING;
11: ovfl += osize;
14: }
[1] and [9] can sometimes be optimized away. */
ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
NULL_TREE);
if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
&& GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
{
top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
NULL_TREE);
off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
NULL_TREE);
/* When floating-point registers are saved to the stack,
each one will take up UNITS_PER_HWFPVALUE bytes, regardless
of the float's precision. */
rsize = UNITS_PER_HWFPVALUE;
/* Overflow arguments are padded to UNITS_PER_WORD bytes
(= PARM_BOUNDARY bits). This can be different from RSIZE
in two cases:
(1) On 32-bit targets when TYPE is a structure such as:
struct s { float f; };
Such structures are passed in paired FPRs, so RSIZE
will be 8 bytes. However, the structure only takes
up 4 bytes of memory, so OSIZE will only be 4.
(2) In combinations such as -mgp64 -msingle-float
-fshort-double. Doubles passed in registers
will then take up 4 (UNITS_PER_HWFPVALUE) bytes,
but those passed on the stack take up
UNITS_PER_WORD bytes. */
osize = MAX (GET_MODE_SIZE (TYPE_MODE (type)), UNITS_PER_WORD);
}
else
align = 4;
{
top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
NULL_TREE);
off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
NULL_TREE);
if (rsize > UNITS_PER_WORD)
{
/* [1] Emit code for: off &= -rsize. */
t = build (BIT_AND_EXPR, TREE_TYPE (off), off,
build_int_2 (-rsize, -1));
t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
gimplify_and_add (t, pre_p);
}
osize = rsize;
}
t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
build_int_2 (align - 1, 0));
t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
/* [2] Emit code to branch if off == 0. */
t = lang_hooks.truthvalue_conversion (off);
addr = build (COND_EXPR, ptr_type_node, t, NULL, NULL);
/* If arguments of type TYPE must be passed on the stack,
set MIN_OFFSET to the offset of the first stack parameter. */
if (!targetm.calls.must_pass_in_stack (TYPE_MODE (type), type))
min_offset = 0;
else if (TARGET_NEWABI)
min_offset = current_function_pretend_args_size;
/* [5] Emit code for: off -= rsize. We do this as a form of
post-increment not available to C. Also widen for the
coming pointer arithmetic. */
t = fold_convert (TREE_TYPE (off), build_int_2 (rsize, 0));
t = build (POSTDECREMENT_EXPR, TREE_TYPE (off), off, t);
t = fold_convert (sizetype, t);
t = fold_convert (TREE_TYPE (top), t);
/* [4] Emit code for: addr_rtx = top - off. On big endian machines,
the argument has RSIZE - SIZE bytes of leading padding. */
t = build (MINUS_EXPR, TREE_TYPE (top), top, t);
if (BYTES_BIG_ENDIAN && rsize > size)
{
u = fold_convert (TREE_TYPE (t), build_int_2 (rsize - size, 0));
t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
}
COND_EXPR_THEN (addr) = t;
if (osize > UNITS_PER_WORD)
{
/* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize. */
u = fold_convert (TREE_TYPE (ovfl), build_int_2 (osize - 1, 0));
t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u);
u = fold_convert (TREE_TYPE (ovfl), build_int_2 (-osize, -1));
t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u);
align = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
}
else
min_offset = REG_PARM_STACK_SPACE (current_function_decl);
align = NULL;
/* Make sure the new address is at least MIN_OFFSET bytes from
the incoming argument pointer. */
if (min_offset > 0)
t = build (MAX_EXPR, TREE_TYPE (valist), t,
make_tree (TREE_TYPE (valist),
plus_constant (virtual_incoming_args_rtx,
min_offset)));
/* [10, 11]. Emit code to store ovfl in addr_rtx, then
post-increment ovfl by osize. On big-endian machines,
the argument has OSIZE - SIZE bytes of leading padding. */
u = fold_convert (TREE_TYPE (ovfl), build_int_2 (osize, 0));
t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u);
if (BYTES_BIG_ENDIAN && osize > size)
{
u = fold_convert (TREE_TYPE (t), build_int_2 (osize - size, 0));
t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
}
t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
/* String [9] and [10,11] together. */
if (align)
t = build (COMPOUND_EXPR, TREE_TYPE (t), align, t);
COND_EXPR_ELSE (addr) = t;
/* Everything past the alignment is standard. */
return std_expand_builtin_va_arg (valist, type);
addr = fold_convert (build_pointer_type (type), addr);
addr = build_fold_indirect_ref (addr);
}
if (indirect)
addr = build_fold_indirect_ref (addr);
return addr;
}
/* Return true if it is possible to use left/right accesses for a
@ -7425,18 +7329,22 @@ function_arg_pass_by_reference (const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
enum machine_mode mode, tree type,
int named ATTRIBUTE_UNUSED)
{
int size;
if (mips_abi == ABI_EABI)
{
int size;
/* The EABI is the only one to pass args by reference. */
if (mips_abi != ABI_EABI)
return 0;
/* ??? How should SCmode be handled? */
if (type == NULL_TREE || mode == DImode || mode == DFmode)
return 0;
/* ??? How should SCmode be handled? */
if (type == NULL_TREE || mode == DImode || mode == DFmode)
return 0;
size = int_size_in_bytes (type);
return size == -1 || size > UNITS_PER_WORD;
size = int_size_in_bytes (type);
return size == -1 || size > UNITS_PER_WORD;
}
else
{
/* If we have a variable-sized parameter, we have no choice. */
return targetm.calls.must_pass_in_stack (mode, type);
}
}
/* Return the class of registers for which a mode change from FROM to TO

@ -2387,10 +2387,6 @@ typedef struct mips_args {
/* Implement `va_start' for varargs and stdarg. */
#define EXPAND_BUILTIN_VA_START(valist, nextarg) \
mips_va_start (valist, nextarg)
/* Implement `va_arg'. */
#define EXPAND_BUILTIN_VA_ARG(valist, type) \
mips_va_arg (valist, type)
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */