aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonald Lindsay <dlindsay@hound.cygnus.com>2000-05-03 01:22:38 +0000
committerDon Lindsay <dlindsay@gcc.gnu.org>2000-05-03 01:22:38 +0000
commit4fe12442a868e92b226fecd9e015142a01bef9fb (patch)
treed2eeb06d23bbe0dee0f08db5da576abb0aa5a4cb
parentf4e79153b8cd88b21cc130ee076bddb9cd6a7bd3 (diff)
downloadgcc-4fe12442a868e92b226fecd9e015142a01bef9fb.zip
gcc-4fe12442a868e92b226fecd9e015142a01bef9fb.tar.gz
gcc-4fe12442a868e92b226fecd9e015142a01bef9fb.tar.bz2
change MIPS varargs ABI in config/mips/mips.c
From-SVN: r33621
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/config/mips/mips.c461
2 files changed, 332 insertions, 138 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dd1b243..e8262dd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+Tue May 2 18:20:31 2000 Donald Lindsay <dlindsay@hound.cygnus.com>
+
+ * config/mips/mips.c (mips_build_va_list,mips_va_start,mips_va_arg): new
+ ABI for varargs, across all MIPS. This is incompatible because the
+ va_list (__builtin_va_list) structure is different, so a compilation
+ unit passing a va_list and a compilation unit being passed one, should
+ both be compiled with the same ABI. (The old structure had two
+ pointers, now it has three.)
+
Tue May 2 19:18:43 2000 Jason Eckhardt <jle@cygnus.com>
* bb-reorder.c (struct reorder_block_def): Remove members end,
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index c19f35f..9af4afd 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -4138,41 +4138,71 @@ function_arg_partial_nregs (cum, mode, type, named)
return 0;
}
-/* Create the va_list data type. */
+/* Create the va_list data type.
+ We keep 3 pointers, and two offsets.
+ Two pointers are to the overflow area, which starts at the CFA.
+ One of these is constant, for addressing into the GPR save area below it.
+ The other is advanced up the stack through the overflow region.
+ The third pointer is to the GPR save area. Since the FPR save area
+ is just below it, we can address FPR slots off this pointer.
+ We also keep two one-byte offsets, which are to be subtracted from the
+ constant pointers to yield addresses in the GPR and FPR save areas.
+ These are downcounted as float or non-float arguments are used,
+ and when they get to zero, the argument must be obtained from the
+ overflow region.
+ If TARGET_SOFT_FLOAT or TARGET_SINGLE_FLOAT, then no FPR save area exists,
+ and a single pointer is enough. It's started at the GPR save area,
+ and is advanced, period.
+ Note that the GPR save area is not constant size, due to optimization
+ in the prologue. Hence, we can't use a design with two pointers
+ and two offsets, although we could have designed this with two pointers
+ and three offsets. */
+
tree
mips_build_va_list ()
{
if (mips_abi == ABI_EABI && !TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
{
- tree f_fpr, f_rem, f_gpr, record;
+ tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff, record;
record = make_node (RECORD_TYPE);
- f_fpr = build_decl (FIELD_DECL, get_identifier ("__fp_regs"),
+ f_ovfl = build_decl (FIELD_DECL, get_identifier ("__overflow_argptr"),
+ ptr_type_node);
+ f_gtop = build_decl (FIELD_DECL, get_identifier ("__gpr_top"),
ptr_type_node);
- f_rem = build_decl (FIELD_DECL, get_identifier ("__fp_left"),
- integer_type_node);
- f_gpr = build_decl (FIELD_DECL, get_identifier ("__gp_regs"),
+ f_ftop = build_decl (FIELD_DECL, get_identifier ("__fpr_top"),
ptr_type_node);
+ f_goff = build_decl (FIELD_DECL, get_identifier ("__gpr_offset"),
+ unsigned_char_type_node);
+ f_foff = build_decl (FIELD_DECL, get_identifier ("__fpr_offset"),
+ unsigned_char_type_node);
- DECL_FIELD_CONTEXT (f_fpr) = record;
- DECL_FIELD_CONTEXT (f_rem) = record;
- DECL_FIELD_CONTEXT (f_gpr) = record;
- TYPE_FIELDS (record) = f_fpr;
- TREE_CHAIN (f_fpr) = f_rem;
- TREE_CHAIN (f_rem) = f_gpr;
+ DECL_FIELD_CONTEXT (f_ovfl) = record;
+ DECL_FIELD_CONTEXT (f_gtop) = record;
+ DECL_FIELD_CONTEXT (f_ftop) = record;
+ DECL_FIELD_CONTEXT (f_goff) = record;
+ DECL_FIELD_CONTEXT (f_foff) = record;
- layout_type (record);
+ TYPE_FIELDS (record) = f_ovfl;
+ TREE_CHAIN (f_ovfl) = f_gtop;
+ TREE_CHAIN (f_gtop) = f_ftop;
+ TREE_CHAIN (f_ftop) = f_goff;
+ TREE_CHAIN (f_goff) = f_foff;
+ layout_type (record);
return record;
}
else
return ptr_type_node;
}
-/* Implement va_start. */
+/* Implement va_start. stdarg_p is 0 if implementing
+ __builtin_varargs_va_start, 1 if implementing __builtin_stdarg_va_start.
+ Note that this routine isn't called when compiling e.g. "_vfprintf_r".
+ (It doesn't have "...", so it inherits the pointers of its caller.) */
void
mips_va_start (stdarg_p, valist, nextarg)
@@ -4180,82 +4210,139 @@ mips_va_start (stdarg_p, valist, nextarg)
tree valist;
rtx nextarg;
{
- int arg_words;
+ int int_arg_words;
tree t;
- arg_words = current_function_args_info.arg_words;
+ /* Find out how many non-float named formals */
+ int_arg_words = current_function_args_info.arg_words;
if (mips_abi == ABI_EABI)
{
+ int gpr_save_area_size;
+ /* Note UNITS_PER_WORD is 4 bytes or 8, depending on TARGET_64BIT. */
+ if (int_arg_words < 8 )
+ /* Adjust for the prologue's economy measure */
+ gpr_save_area_size = (8 - int_arg_words) * UNITS_PER_WORD;
+ else
+ gpr_save_area_size = 0;
+
if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
{
- tree f_fpr, f_rem, f_gpr, fpr, rem, gpr;
- tree gprv, fprv;
- int gpro, fpro;
-
- fpro = (8 - current_function_args_info.fp_arg_words);
-
+ tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
+ tree ovfl, gtop, ftop, goff, foff;
+ tree gprv;
+ int float_formals, fpr_offset, size_excess, floats_passed_in_regs;
+ int fpr_save_offset;
+
+ float_formals = current_function_args_info.fp_arg_words;
+ /* If mips2, the number of formals is half the reported # of words */
+ if (!TARGET_64BIT)
+ float_formals /= 2;
+ floats_passed_in_regs = (TARGET_64BIT ? 8 : 4);
+
+ 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);
+
+ ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl);
+ gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop);
+ ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop);
+ goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff);
+ foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
+
+ /* Emit code setting a pointer into the overflow (shared-stack) area.
+ If there were more than 8 non-float formals, or more than 8
+ float formals, then this pointer isn't to the base of the area.
+ In that case, it must point to where the first vararg is. */
+ size_excess = 0;
+ if (float_formals > floats_passed_in_regs)
+ size_excess += (float_formals-floats_passed_in_regs) * 8;
+ if (int_arg_words > 8)
+ size_excess += (int_arg_words-8) * UNITS_PER_WORD;
+
+ /* FIXME: for mips2, the above size_excess can be wrong. Because the
+ overflow stack holds mixed size items, there can be alignments,
+ so that an 8 byte double following a 4 byte int will be on an
+ 8 byte boundary. This means that the above calculation should
+ take into account the exact sequence of floats and non-floats
+ which make up the excess. That calculation should be rolled
+ into the code which sets the current_function_args_info struct.
+ The above then reduces to a fetch from that struct. */
+
+
+ t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
+ if (size_excess)
+ t = build (PLUS_EXPR, TREE_TYPE (ovfl), t,
+ build_int_2 (size_excess, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ /* Emit code setting a ptr to the base of the overflow area. */
+ t = make_tree (TREE_TYPE (gtop), virtual_incoming_args_rtx);
+ t = build (MODIFY_EXPR, TREE_TYPE (gtop), gtop, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ /* Emit code setting a pointer to the GPR save area.
+ More precisely, a pointer to off-the-end of the FPR save area.
+ If mips4, this is gpr_save_area_size below the overflow area.
+ If mips2, also round down to an 8-byte boundary, since the FPR
+ save area is 8-byte aligned, and GPR is 4-byte-aligned.
+ Therefore there can be a 4-byte gap between the save areas. */
+ gprv = make_tree (TREE_TYPE (ftop), virtual_incoming_args_rtx);
+ fpr_save_offset = gpr_save_area_size;
if (!TARGET_64BIT)
- fpro /= 2;
-
- f_fpr = TYPE_FIELDS (va_list_type_node);
- f_rem = TREE_CHAIN (f_fpr);
- f_gpr = TREE_CHAIN (f_rem);
-
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- rem = build (COMPONENT_REF, TREE_TYPE (f_rem), valist, f_rem);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-
- if (arg_words < 8)
- gpro = (8 - arg_words) * UNITS_PER_WORD;
- else
- gpro = (stdarg_p ? 0 : UNITS_PER_WORD);
-
- gprv = make_tree (ptr_type_node, nextarg);
- if (gpro != 0)
{
- gprv = build (PLUS_EXPR, ptr_type_node, gprv,
- build_int_2 (-gpro, -1));
+ if (fpr_save_offset & 7)
+ fpr_save_offset += 4;
}
-
- t = build (MODIFY_EXPR, ptr_type_node, gpr, gprv);
- TREE_SIDE_EFFECTS (t) = 1;
+ if (fpr_save_offset)
+ gprv = build (PLUS_EXPR, TREE_TYPE (ftop), gprv,
+ build_int_2 (-fpr_save_offset,-1));
+ t = build (MODIFY_EXPR, TREE_TYPE (ftop), ftop, gprv);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- t = build (MODIFY_EXPR, integer_type_node, rem,
- build_int_2 (fpro, 0));
- TREE_SIDE_EFFECTS (t) = 1;
+ /* Emit code initting an offset to the size of the GPR save area */
+ t = build (MODIFY_EXPR, TREE_TYPE (goff), goff,
+ build_int_2 (gpr_save_area_size,0));
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- if (fpro == 0)
- fprv = gprv;
+ /* Emit code initting an offset from ftop to the first float
+ vararg. This varies in size, since any float
+ varargs are put in the FPR save area after the formals.
+ Note it's 8 bytes/formal regardless of TARGET_64BIT.
+ However, mips2 stores 4 GPRs, mips4 stores 8 GPRs.
+ If there are 8 or more float formals, init to zero.
+ (In fact, the formals aren't stored in the bottom of the
+ FPR save area: they are elsewhere, and the size of the FPR
+ save area is economized by the prologue. But this code doesn't
+ care. This design is unaffected by that fact.) */
+ if (float_formals >= floats_passed_in_regs)
+ fpr_offset = 0;
else
- fprv = fold (build (PLUS_EXPR, ptr_type_node, gprv,
- build_int_2 (-(fpro*8), -1)));
-
- if (! TARGET_64BIT)
- fprv = fold (build (BIT_AND_EXPR, ptr_type_node, fprv,
- build_int_2 (-8, -1)));
-
- t = build (MODIFY_EXPR, ptr_type_node, fpr, fprv);
- TREE_SIDE_EFFECTS (t) = 1;
+ fpr_offset = (floats_passed_in_regs - float_formals) * 8;
+ t = build (MODIFY_EXPR, TREE_TYPE (foff), foff,
+ build_int_2 (fpr_offset,0));
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
else
{
- int ofs;
+ /* TARGET_SOFT_FLOAT or TARGET_SINGLE_FLOAT */
- if (arg_words >= 8)
- ofs = (stdarg_p ? 0 : UNITS_PER_WORD);
- else
- ofs = (8 - arg_words) * UNITS_PER_WORD;
+ /* Everything is in the GPR save area, or in the overflow
+ area which is contiguous with it. */
- nextarg = plus_constant (nextarg, -ofs);
+ int offset = -gpr_save_area_size;
+ if (gpr_save_area_size == 0)
+ offset = (stdarg_p ? 0 : -UNITS_PER_WORD);
+ nextarg = plus_constant (nextarg, offset);
std_expand_builtin_va_start (1, valist, nextarg);
}
}
else
{
+ /* not EABI */
int ofs;
if (stdarg_p)
@@ -4266,7 +4353,7 @@ mips_va_start (stdarg_p, valist, nextarg)
_MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
and both iris5.h and iris6.h define _MIPS_SIM. */
if (mips_abi == ABI_N32 || mips_abi == ABI_64)
- ofs = (arg_words >= 8 ? -UNITS_PER_WORD : 0);
+ ofs = (int_arg_words >= 8 ? -UNITS_PER_WORD : 0);
else
ofs = -UNITS_PER_WORD;
}
@@ -4291,9 +4378,10 @@ mips_va_arg (valist, type)
if (mips_abi == ABI_EABI)
{
- tree gpr;
int indirect;
- rtx lab_over = NULL_RTX, lab_false, r;
+ rtx r, lab_over = NULL_RTX, lab_false;
+ tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
+ tree ovfl, gtop, ftop, goff, foff;
indirect
= function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
@@ -4302,93 +4390,191 @@ mips_va_arg (valist, type)
addr_rtx = gen_reg_rtx (Pmode);
- if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+ if (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
{
- tree f_fpr, f_rem, f_gpr, fpr, rem;
-
- f_fpr = TYPE_FIELDS (va_list_type_node);
- f_rem = TREE_CHAIN (f_fpr);
- f_gpr = TREE_CHAIN (f_rem);
+ /* Case of all args in a merged stack. No need to check bounds,
+ just advance valist along the stack. */
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- rem = build (COMPONENT_REF, TREE_TYPE (f_rem), valist, f_rem);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-
- if (TREE_CODE (type) == REAL_TYPE)
+ tree gpr = valist;
+ if (! indirect
+ && ! TARGET_64BIT
+ && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD)
{
- lab_false = gen_label_rtx ();
- lab_over = gen_label_rtx ();
-
- r = expand_expr (rem, NULL_RTX, TYPE_MODE (TREE_TYPE (rem)),
- EXPAND_NORMAL);
- emit_cmp_and_jump_insns (r, const0_rtx, LE, const1_rtx,
- GET_MODE (r), 1, 1, lab_false);
-
- t = build (PLUS_EXPR, TREE_TYPE (rem), rem,
- build_int_2 (-1, -1));
- t = build (MODIFY_EXPR, TREE_TYPE (rem), rem, t);
- TREE_SIDE_EFFECTS (t) = 1;
+ 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);
+ }
- t = build (POSTINCREMENT_EXPR, TREE_TYPE (fpr), fpr,
- build_int_2 (8, 0));
- TREE_SIDE_EFFECTS (t) = 1;
- r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
- if (r != addr_rtx)
- emit_move_insn (addr_rtx, r);
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr,
+ size_int (rsize));
+ r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+ if (r != addr_rtx)
+ emit_move_insn (addr_rtx, r);
- /* Ensure that the POSTINCREMENT is emitted before lab_over */
- emit_queue();
+ /* flush the POSTINCREMENT */
+ emit_queue();
- emit_jump (lab_over);
- emit_barrier ();
- emit_label (lab_false);
+ if (indirect)
+ {
+ r = gen_rtx_MEM (Pmode, addr_rtx);
+ MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+ emit_move_insn (addr_rtx, r);
}
- }
- else
- gpr = valist;
-
- if (! indirect
- && ! TARGET_64BIT
- && TYPE_ALIGN (type) > (unsigned) BITS_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);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ else
+ {
+ if (BYTES_BIG_ENDIAN && rsize != size)
+ addr_rtx = plus_constant (addr_rtx, rsize - size);
+ }
+ return addr_rtx;
}
- t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr, size_int (rsize));
- TREE_SIDE_EFFECTS (t) = 1;
- r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
- if (r != addr_rtx)
- emit_move_insn (addr_rtx, r);
+ /* Not a simple merged stack. Need ptrs and indexes left by va_start. */
+
+ 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);
+
+ ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl);
+ gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop);
+ ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop);
+ goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff);
+ foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
+
+ lab_false = gen_label_rtx ();
+ lab_over = gen_label_rtx ();
+
+ if (TREE_CODE (type) == REAL_TYPE)
+ {
+
+ /* Emit code to branch if foff == 0. */
+ r = expand_expr (foff, NULL_RTX, TYPE_MODE (TREE_TYPE (foff)),
+ EXPAND_NORMAL);
+ emit_cmp_and_jump_insns (r, const0_rtx, EQ,
+ const1_rtx, GET_MODE (r), 1, 1, lab_false);
+
+ /* Emit code for addr_rtx = ftop - foff */
+ t = build (MINUS_EXPR, TREE_TYPE (ftop), ftop, foff );
+ r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+ if (r != addr_rtx)
+ emit_move_insn (addr_rtx, r);
+
+ /* Emit code for foff-=8.
+ Advances the offset up FPR save area by one double */
+ t = build (MINUS_EXPR, TREE_TYPE (foff), foff, build_int_2 (8, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (foff), foff, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ emit_queue();
+ emit_jump (lab_over);
+ emit_barrier ();
+ emit_label (lab_false);
+
+ if (!TARGET_64BIT)
+ {
+ /* For mips2, the overflow area contains mixed size items.
+ If a 4-byte int is followed by an 8-byte float, then
+ natural alignment causes a 4 byte gap.
+ So, dynamically adjust ovfl up to a multiple of 8. */
+ t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), ovfl,
+ build_int_2 (7, 0));
+ t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, t);
+ t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
- /* Ensure that the above POSTINCREMENT is emitted before lab_over */
- emit_queue();
+ /* Emit code for addr_rtx = the ovfl pointer into overflow area.
+ Regardless of mips2, postincrement the ovfl pointer by 8. */
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
+ size_int (8));
+ 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);
+ return addr_rtx;
+ }
+ else
+ {
+ /* not REAL_TYPE */
+ int step_size;
- if (lab_over)
- emit_label (lab_over);
+ if (! TARGET_64BIT
+ && TREE_CODE (type) == INTEGER_TYPE
+ && TYPE_PRECISION (type) == 64)
+ {
+ /* In mips2, int takes 32 bits of the GPR save area, but
+ longlong takes an aligned 64 bits. So, emit code
+ to zero the low order bits of goff, thus aligning
+ the later calculation of (gtop-goff) upwards. */
+ t = build (BIT_AND_EXPR, TREE_TYPE (goff), goff,
+ build_int_2 (-8, -1));
+ t = build (MODIFY_EXPR, TREE_TYPE (goff), goff, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
- if (indirect)
- {
- r = gen_rtx_MEM (Pmode, addr_rtx);
- MEM_ALIAS_SET (r) = get_varargs_alias_set ();
- emit_move_insn (addr_rtx, r);
- }
- else
- {
- if (BYTES_BIG_ENDIAN && rsize != size)
- addr_rtx = plus_constant (addr_rtx, rsize - size);
+ /* Emit code to branch if goff == 0. */
+ r = expand_expr (goff, NULL_RTX, TYPE_MODE (TREE_TYPE (goff)),
+ EXPAND_NORMAL);
+ emit_cmp_and_jump_insns (r, const0_rtx, EQ,
+ const1_rtx, GET_MODE (r), 1, 1, lab_false);
+
+ /* Emit code for addr_rtx = gtop - goff. */
+ t = build (MINUS_EXPR, TREE_TYPE (gtop), gtop, goff);
+ r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+ if (r != addr_rtx)
+ emit_move_insn (addr_rtx, r);
+
+ /* Note that mips2 int is 32 bit, but mips2 longlong is 64. */
+ if (! TARGET_64BIT && TYPE_PRECISION (type) == 64)
+ step_size = 8;
+ else
+ step_size = UNITS_PER_WORD;
+
+ /* Emit code for goff = goff - step_size.
+ Advances the offset up GPR save area over the item. */
+ t = build (MINUS_EXPR, TREE_TYPE (goff), goff,
+ build_int_2 (step_size, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (goff), goff, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ emit_queue();
+ emit_jump (lab_over);
+ emit_barrier ();
+ emit_label (lab_false);
+
+ /* Emit code for addr_rtx -> overflow area, postinc by step_size */
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
+ size_int (step_size));
+ 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)
+ {
+ r = gen_rtx_MEM (Pmode, addr_rtx);
+ MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+ emit_move_insn (addr_rtx, r);
+ }
+ else
+ {
+ if (BYTES_BIG_ENDIAN && rsize != size)
+ addr_rtx = plus_constant (addr_rtx, rsize - size);
+ }
+ return addr_rtx;
}
-
- return addr_rtx;
}
else
{
+ /* Not EABI. */
int align;
/* ??? The original va-mips.h did always align, despite the fact
@@ -4406,7 +4592,6 @@ mips_va_arg (valist, type)
build_int_2 (align - 1, 0));
t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
- TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
/* Everything past the alignment is standard. */