OSDN Git Service

2003-08-22 Jason Eckhardt <jle@rice.edu>
authorjle <jle@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 23 Aug 2003 04:20:02 +0000 (04:20 +0000)
committerjle <jle@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 23 Aug 2003 04:20:02 +0000 (04:20 +0000)
* 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

gcc/ChangeLog
gcc/config/i860/i860.c
gcc/config/i860/i860.h
gcc/config/i860/varargs.asm

index d0b957e..a86131c 100644 (file)
@@ -1,3 +1,13 @@
+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.
+
 2003-08-22  Kazu Hirata  <kazu@cs.umass.edu>
 
        * config/iq2000/iq2000.c: Fix comment typos.
index 0e171a9..5bc32ed 100644 (file)
@@ -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)
 \f
 
 /* 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
index 231cbed..38ddc1c 100644 (file)
@@ -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"
index f740426..ff58d73 100644 (file)
@@ -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__)