aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorjle <jle@138bc75d-0d04-0410-961f-82ee72b054a4>2003-08-23 04:20:02 +0000
committerjle <jle@138bc75d-0d04-0410-961f-82ee72b054a4>2003-08-23 04:20:02 +0000
commit524613bd161b5588f94d4e97143f6e0537d2544d (patch)
treecf9b0ee56a6f8e098e7449ffca7e0704d5dc3e78 /gcc/config
parent4482474a467927ffe55e01cb039f052cb598fa9c (diff)
2003-08-22 Jason Eckhardt <jle@rice.edu>
* config/i860/i860.c (i860_build_va_list): Create the va_decl declaration. Document the va_list structure. (i860_va_start): Initialize the va_list structure. (i860_va_arg): Rewrite completely. * config/i860/i860.h (LIBGCC_NEEDS_DOUBLE): Don't define. * config/i860/varargs.asm: Do not allocate or initialize a va_list. Return the address of the register save area. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@70729 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/i860/i860.c330
-rw-r--r--gcc/config/i860/i860.h2
-rw-r--r--gcc/config/i860/varargs.asm11
3 files changed, 200 insertions, 143 deletions
diff --git a/gcc/config/i860/i860.c b/gcc/config/i860/i860.c
index 0e171a9a8de..5bc32edb3c5 100644
--- a/gcc/config/i860/i860.c
+++ b/gcc/config/i860/i860.c
@@ -47,6 +47,7 @@ Boston, MA 02111-1307, USA. */
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
+#include "langhooks.h"
static rtx find_addr_reg (rtx);
@@ -1772,6 +1773,7 @@ i860_output_function_epilogue (FILE *asm_file, HOST_WIDE_INT local_bytes)
/* Expand a library call to __builtin_saveregs. */
+
rtx
i860_saveregs (void)
{
@@ -1791,94 +1793,118 @@ i860_saveregs (void)
return ret;
}
+/* Create the va_list data type.
+ The SVR4 ABI requires the following structure:
+ typedef struct {
+ unsigned long ireg_used;
+ unsigned long freg_used;
+ long *reg_base;
+ long *mem_ptr;
+ } va_list;
+
+ Otherwise, this structure is used:
+ typedef struct {
+ long *reg_base;
+ long *mem_ptr;
+ unsigned long ireg_used;
+ unsigned long freg_used;
+ } va_list;
+
+ The tree representing the va_list declaration is returned. */
+
tree
i860_build_va_list (void)
{
- tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr;
- tree record;
+ tree f_gpr, f_fpr, f_mem, f_sav, record, type_decl;
+
+ record = (*lang_hooks.types.make_type) (RECORD_TYPE);
+ type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
- record = make_node (RECORD_TYPE);
+ f_gpr = build_decl (FIELD_DECL, get_identifier ("__ireg_used"),
+ unsigned_type_node);
+ f_fpr = build_decl (FIELD_DECL, get_identifier ("__freg_used"),
+ unsigned_type_node);
+ f_sav = build_decl (FIELD_DECL, get_identifier ("__reg_base"),
+ ptr_type_node);
+ f_mem = build_decl (FIELD_DECL, get_identifier ("__mem_ptr"),
+ ptr_type_node);
- field_ireg_used = build_decl (FIELD_DECL, get_identifier ("__ireg_used"),
- unsigned_type_node);
- field_freg_used = build_decl (FIELD_DECL, get_identifier ("__freg_used"),
- unsigned_type_node);
- field_reg_base = build_decl (FIELD_DECL, get_identifier ("__reg_base"),
- ptr_type_node);
- field_mem_ptr = build_decl (FIELD_DECL, get_identifier ("__mem_ptr"),
- ptr_type_node);
+ DECL_FIELD_CONTEXT (f_gpr) = record;
+ DECL_FIELD_CONTEXT (f_fpr) = record;
+ DECL_FIELD_CONTEXT (f_sav) = record;
+ DECL_FIELD_CONTEXT (f_mem) = record;
- DECL_FIELD_CONTEXT (field_ireg_used) = record;
- DECL_FIELD_CONTEXT (field_freg_used) = record;
- DECL_FIELD_CONTEXT (field_reg_base) = record;
- DECL_FIELD_CONTEXT (field_mem_ptr) = record;
+ TREE_CHAIN (record) = type_decl;
+ TYPE_NAME (record) = type_decl;
#ifdef I860_SVR4_VA_LIST
- TYPE_FIELDS (record) = field_ireg_used;
- TREE_CHAIN (field_ireg_used) = field_freg_used;
- TREE_CHAIN (field_freg_used) = field_reg_base;
- TREE_CHAIN (field_reg_base) = field_mem_ptr;
+ TYPE_FIELDS (record) = f_gpr;
+ TREE_CHAIN (f_gpr) = f_fpr;
+ TREE_CHAIN (f_fpr) = f_sav;
+ TREE_CHAIN (f_sav) = f_mem;
#else
- TYPE_FIELDS (record) = field_reg_base;
- TREE_CHAIN (field_reg_base) = field_mem_ptr;
- TREE_CHAIN (field_mem_ptr) = field_ireg_used;
- TREE_CHAIN (field_ireg_used) = field_freg_used;
+ TYPE_FIELDS (record) = f_sav;
+ TREE_CHAIN (f_sav) = f_mem;
+ TREE_CHAIN (f_mem) = f_gpr;
+ TREE_CHAIN (f_gpr) = f_fpr;
#endif
layout_type (record);
return record;
}
+/* Initialize the va_list structure. */
+
void
-i860_va_start (tree valist, rtx nextarg)
+i860_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
{
tree saveregs, t;
- tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr;
- tree ireg_used, freg_used, reg_base, mem_ptr;
-
- saveregs = make_tree (build_pointer_type (va_list_type_node),
- expand_builtin_saveregs ());
- saveregs = build1 (INDIRECT_REF, va_list_type_node, saveregs);
+ tree f_gpr, f_fpr, f_mem, f_sav;
+ tree gpr, fpr, mem, sav;
+ int off = 0;
+ saveregs = make_tree (ptr_type_node, expand_builtin_saveregs ());
#ifdef I860_SVR4_VA_LIST
- field_ireg_used = TYPE_FIELDS (va_list_type_node);
- field_freg_used = TREE_CHAIN (field_ireg_used);
- field_reg_base = TREE_CHAIN (field_freg_used);
- field_mem_ptr = TREE_CHAIN (field_reg_base);
+ f_gpr = TYPE_FIELDS (va_list_type_node);
+ f_fpr = TREE_CHAIN (f_gpr);
+ f_sav = TREE_CHAIN (f_fpr);
+ f_mem = TREE_CHAIN (f_sav);
#else
- field_reg_base = TYPE_FIELDS (va_list_type_node);
- field_mem_ptr = TREE_CHAIN (field_reg_base);
- field_ireg_used = TREE_CHAIN (field_mem_ptr);
- field_freg_used = TREE_CHAIN (field_ireg_used);
+ f_sav = TYPE_FIELDS (va_list_type_node);
+ f_mem = TREE_CHAIN (f_sav);
+ f_gpr = TREE_CHAIN (f_mem);
+ f_fpr = TREE_CHAIN (f_gpr);
#endif
- ireg_used = build (COMPONENT_REF, TREE_TYPE (field_ireg_used),
- valist, field_ireg_used);
- freg_used = build (COMPONENT_REF, TREE_TYPE (field_freg_used),
- valist, field_freg_used);
- reg_base = build (COMPONENT_REF, TREE_TYPE (field_reg_base),
- valist, field_reg_base);
- mem_ptr = build (COMPONENT_REF, TREE_TYPE (field_mem_ptr),
- valist, field_mem_ptr);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem);
+
+ /* Initialize the `mem_ptr' field to the address of the first anonymous
+ stack argument. */
+ t = make_tree (TREE_TYPE (mem), virtual_incoming_args_rtx);
+ off = INTVAL (current_function_arg_offset_rtx);
+ off = off < 0 ? 0 : off;
+ t = build (PLUS_EXPR, TREE_TYPE (mem), t, build_int_2 (off, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (mem), mem, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ /* Initialize the `ireg_used' field. */
t = build_int_2 (current_function_args_info.ints / UNITS_PER_WORD, 0);
- t = build (MODIFY_EXPR, TREE_TYPE (ireg_used), ireg_used, t);
+ t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- t = build_int_2 (ROUNDUP ((current_function_args_info.floats / UNITS_PER_WORD), 8), 0);
- t = build (MODIFY_EXPR, TREE_TYPE (freg_used), freg_used, t);
+
+ /* Initialize the `freg_used' field. */
+ t = build_int_2 (current_function_args_info.floats / UNITS_PER_WORD, 0);
+ t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- t = build (COMPONENT_REF, TREE_TYPE (field_reg_base),
- saveregs, field_reg_base);
- t = build (MODIFY_EXPR, TREE_TYPE (reg_base), reg_base, t);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- t = make_tree (ptr_type_node, nextarg);
- t = build (MODIFY_EXPR, TREE_TYPE (mem_ptr), mem_ptr, t);
+ /* Initialize the `reg_base' field. */
+ t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, saveregs);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
@@ -1893,116 +1919,136 @@ i860_va_start (tree valist, rtx nextarg)
#define IREG_OFFSET 0
#endif
+/* Update the VALIST structure as necessary for an
+ argument of the given TYPE, and return the argument. */
+
rtx
i860_va_arg (tree valist, tree type)
{
- tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr;
- tree type_ptr_node, t;
- rtx lab_over = NULL_RTX;
- rtx ret, val;
- HOST_WIDE_INT align;
+ tree f_gpr, f_fpr, f_mem, f_sav;
+ tree gpr, fpr, mem, sav, reg, t, u;
+ int size, n_reg, sav_ofs, sav_scale, max_reg;
+ rtx lab_false, lab_over, addr_rtx, r;
#ifdef I860_SVR4_VA_LIST
- field_ireg_used = TYPE_FIELDS (va_list_type_node);
- field_freg_used = TREE_CHAIN (field_ireg_used);
- field_reg_base = TREE_CHAIN (field_freg_used);
- field_mem_ptr = TREE_CHAIN (field_reg_base);
+ f_gpr = TYPE_FIELDS (va_list_type_node);
+ f_fpr = TREE_CHAIN (f_gpr);
+ f_sav = TREE_CHAIN (f_fpr);
+ f_mem = TREE_CHAIN (f_sav);
#else
- field_reg_base = TYPE_FIELDS (va_list_type_node);
- field_mem_ptr = TREE_CHAIN (field_reg_base);
- field_ireg_used = TREE_CHAIN (field_mem_ptr);
- field_freg_used = TREE_CHAIN (field_ireg_used);
+ f_sav = TYPE_FIELDS (va_list_type_node);
+ f_mem = TREE_CHAIN (f_sav);
+ f_gpr = TREE_CHAIN (f_mem);
+ f_fpr = TREE_CHAIN (f_gpr);
#endif
- field_ireg_used = build (COMPONENT_REF, TREE_TYPE (field_ireg_used),
- valist, field_ireg_used);
- field_freg_used = build (COMPONENT_REF, TREE_TYPE (field_freg_used),
- valist, field_freg_used);
- field_reg_base = build (COMPONENT_REF, TREE_TYPE (field_reg_base),
- valist, field_reg_base);
- field_mem_ptr = build (COMPONENT_REF, TREE_TYPE (field_mem_ptr),
- valist, field_mem_ptr);
+ gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+ fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+ mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem);
+ sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
- ret = gen_reg_rtx (Pmode);
- type_ptr_node = build_pointer_type (type);
+ size = int_size_in_bytes (type);
- if (! AGGREGATE_TYPE_P (type))
+ if (AGGREGATE_TYPE_P (type))
{
- int nparm, incr, ofs;
- tree field;
- rtx lab_false;
+ /* Aggregates are passed on the stack. */
+ HOST_WIDE_INT align;
+
+ align = TYPE_ALIGN (type);
+ if (align < BITS_PER_WORD)
+ align = BITS_PER_WORD;
+ align /= BITS_PER_UNIT;
+
+ addr_rtx = gen_reg_rtx (Pmode);
+ t = build (PLUS_EXPR, ptr_type_node, mem, build_int_2 (align - 1, 0));
+ t = build (BIT_AND_EXPR, ptr_type_node, t, build_int_2 (-align, -1));
+ r = expand_expr (t, addr_rtx, VOIDmode /* Pmode */, EXPAND_NORMAL);
+ if (r != addr_rtx)
+ emit_move_insn (addr_rtx, r);
+
+ t = fold (build (PLUS_EXPR, ptr_type_node,
+ make_tree (ptr_type_node, addr_rtx),
+ build_int_2 (size, 0)));
+ t = build (MODIFY_EXPR, ptr_type_node, mem, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- if (FLOAT_TYPE_P (type))
- {
- field = field_freg_used;
- nparm = NUM_PARM_FREGS;
- incr = 2;
- ofs = FREG_OFFSET;
- }
- else
- {
- field = field_ireg_used;
- nparm = NUM_PARM_IREGS;
- incr = int_size_in_bytes (type) / UNITS_PER_WORD;
- ofs = IREG_OFFSET;
- }
+ return addr_rtx;
+ }
+ else if (FLOAT_TYPE_P (type) || (INTEGRAL_TYPE_P (type) && size == 8))
+ {
+ /* Floats and long longs are passed in the floating-point registers. */
+ reg = fpr;
+ n_reg = size / UNITS_PER_WORD;
+ sav_ofs = FREG_OFFSET;
+ sav_scale = UNITS_PER_WORD;
+ max_reg = NUM_PARM_FREGS;
+ }
+ else
+ {
+ /* Everything else is passed in general registers. */
+ reg = gpr;
+ n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ sav_ofs = IREG_OFFSET;
+ sav_scale = UNITS_PER_WORD;
+ max_reg = NUM_PARM_IREGS;
+ if (n_reg > 1)
+ abort ();
+ }
- lab_false = gen_label_rtx ();
- lab_over = gen_label_rtx ();
+ /* The value was passed in a register, so read it from the register
+ save area initialized by __builtin_saveregs. */
- emit_cmp_and_jump_insns (expand_expr (field, NULL_RTX, 0, 0),
- GEN_INT (nparm - incr), GT, const0_rtx,
- TYPE_MODE (TREE_TYPE (field)),
- TREE_UNSIGNED (field), lab_false);
+ lab_false = gen_label_rtx ();
+ lab_over = gen_label_rtx ();
+ addr_rtx = gen_reg_rtx (Pmode);
- t = fold (build (POSTINCREMENT_EXPR, TREE_TYPE (field), field,
- build_int_2 (incr, 0)));
- TREE_SIDE_EFFECTS (t) = 1;
+ emit_cmp_and_jump_insns (expand_expr (reg, NULL_RTX, Pmode, EXPAND_NORMAL),
+ GEN_INT (max_reg - n_reg),
+ GT, const1_rtx, Pmode, 0, lab_false);
- t = fold (build (MULT_EXPR, TREE_TYPE (field), t /* field */,
- build_int_2 (UNITS_PER_WORD, 0)));
- TREE_SIDE_EFFECTS (t) = 1;
-
- t = fold (build (PLUS_EXPR, ptr_type_node, field_reg_base,
- fold (build (PLUS_EXPR, TREE_TYPE (field), t,
- build_int_2 (ofs, 0)))));
- TREE_SIDE_EFFECTS (t) = 1;
-
- val = expand_expr (t, ret, VOIDmode, EXPAND_NORMAL);
- if (val != ret)
- emit_move_insn (ret, val);
+ if (sav_ofs)
+ t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
+ else
+ t = sav;
- emit_jump_insn (gen_jump (lab_over));
- emit_barrier ();
- emit_label (lab_false);
- }
+ u = build (MULT_EXPR, long_integer_type_node,
+ reg, build_int_2 (sav_scale, 0));
+ TREE_SIDE_EFFECTS (u) = 1;
+
+ t = build (PLUS_EXPR, ptr_type_node, t, u);
+ TREE_SIDE_EFFECTS (t) = 1;
+
+ r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+ if (r != addr_rtx)
+ emit_move_insn (addr_rtx, r);
- align = TYPE_ALIGN (type);
- if (align < BITS_PER_WORD)
- align = BITS_PER_WORD;
- align /= BITS_PER_UNIT;
+ emit_jump_insn (gen_jump (lab_over));
+ emit_barrier ();
+ emit_label (lab_false);
- t = build (PLUS_EXPR, ptr_type_node, field_mem_ptr,
- build_int_2 (align - 1, 0));
- t = build (BIT_AND_EXPR, ptr_type_node, t, build_int_2 (-align, -1));
+ /* The value was passed in memory, so read it from the overflow area. */
- val = expand_expr (t, ret, VOIDmode, EXPAND_NORMAL);
- if (val != ret)
- emit_move_insn (ret, val);
+ t = save_expr (mem);
+ r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+ if (r != addr_rtx)
+ emit_move_insn (addr_rtx, r);
- t = fold (build (PLUS_EXPR, ptr_type_node,
- make_tree (ptr_type_node, ret),
- build_int_2 (int_size_in_bytes (type), 0)));
- t = build (MODIFY_EXPR, ptr_type_node, field_mem_ptr, t);
+ t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (mem), mem, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- if (lab_over)
- emit_label (lab_over);
+ emit_label (lab_over);
- return ret;
-}
+ /* Increment either the ireg_used or freg_used field. */
+ u = build (PREINCREMENT_EXPR, TREE_TYPE (reg), reg, build_int_2 (n_reg, 0));
+ TREE_SIDE_EFFECTS (u) = 1;
+ expand_expr (u, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ return addr_rtx;
+}
/* Compute a (partial) cost for rtx X. Return true if the complete
cost has been computed, and false if subexpressions should be
diff --git a/gcc/config/i860/i860.h b/gcc/config/i860/i860.h
index 231cbed45d7..38ddc1c75c1 100644
--- a/gcc/config/i860/i860.h
+++ b/gcc/config/i860/i860.h
@@ -836,7 +836,7 @@ struct cumulative_args { int ints, floats; };
/* #define CASE_VECTOR_PC_RELATIVE 1 */
/* Must pass floats to libgcc functions as doubles. */
-#define LIBGCC_NEEDS_DOUBLE 1
+/* #define LIBGCC_NEEDS_DOUBLE 1 */
#define DIVSI3_LIBCALL "*.div"
#define UDIVSI3_LIBCALL "*.udiv"
diff --git a/gcc/config/i860/varargs.asm b/gcc/config/i860/varargs.asm
index f740426172b..ff58d7325b0 100644
--- a/gcc/config/i860/varargs.asm
+++ b/gcc/config/i860/varargs.asm
@@ -38,9 +38,13 @@ __builtin_saveregs:
___builtin_saveregs:
andnot 0x0f,%sp,%sp /* round down to 16-byte boundary */
+#if 0
adds -96,%sp,%sp /* allocate stack space for reg save
area and also for a new va_list
structure */
+#else
+ adds -80,%sp,%sp /* allocate stack space for reg save area */
+#endif
/* Save all argument registers in the arg reg save area. The
arg reg save area must have the following layout (according
to the svr4 ABI):
@@ -70,10 +74,12 @@ ___builtin_saveregs:
st.l %r26,72(%sp)
st.l %r27,76(%sp)
+#if 0
adds 80,%sp,%r16 /* compute the address of the new
va_list structure. Put in into
r16 so that it will be returned
to the caller. */
+#endif
/* Initialize all fields of the new va_list structure. This
structure looks like:
@@ -86,11 +92,16 @@ ___builtin_saveregs:
} va_list;
*/
+#if 0
st.l %r0, 0(%r16) /* nfixed */
st.l %r0, 4(%r16) /* nfloating */
st.l %sp, 8(%r16) /* __va_ctl points to __va_struct. */
bri %r1 /* delayed return */
st.l %r28,12(%r16) /* pointer to overflow args */
+#else
+ bri %r1 /* delayed return */
+ or %sp,%r0,%r16 /* Return the address of the reg save area. */
+#endif
#else /* not __svr4__ */
#if defined(__PARAGON__)