[patch]: Re-work stdargs for i860 (committed)

Jason Eckhardt jle@owlnet.rice.edu
Sat Aug 23 04:27:00 GMT 2003


This fixes most of the stdargs-related testsuite failures
for i860.

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.

Index: i860.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i860/i860.c,v
retrieving revision 1.36
diff -u -p -r1.36 i860.c
--- i860.c	23 Aug 2003 02:46:12 -0000	1.36
+++ i860.c	23 Aug 2003 03:48:53 -0000
@@ -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


 /* 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 = make_node (RECORD_TYPE);
+  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
+  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);

-  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 (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;
+  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);
+
+  DECL_FIELD_CONTEXT (f_gpr) = record;
+  DECL_FIELD_CONTEXT (f_fpr) = record;
+  DECL_FIELD_CONTEXT (f_sav) = record;
+  DECL_FIELD_CONTEXT (f_mem) = 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);
-
-  ret = gen_reg_rtx (Pmode);
-  type_ptr_node = build_pointer_type (type);
-
-  if (! AGGREGATE_TYPE_P (type))
-    {
-      int nparm, incr, ofs;
-      tree field;
-      rtx lab_false;
+  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);
+
+  size = int_size_in_bytes (type);
+
+  if (AGGREGATE_TYPE_P (type))
+    {
+      /* 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 ();
+    }
+
+  /* The value was passed in a register, so read it from the register
+     save area initialized by __builtin_saveregs.  */
+
+  lab_false = gen_label_rtx ();
+  lab_over = gen_label_rtx ();
+  addr_rtx = gen_reg_rtx (Pmode);
+
+  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);

-      lab_false = gen_label_rtx ();
-      lab_over = gen_label_rtx ();
+  if (sav_ofs)
+    t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
+  else
+    t = sav;

-      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);
+  u = build (MULT_EXPR, long_integer_type_node,
+	     reg, build_int_2 (sav_scale, 0));
+  TREE_SIDE_EFFECTS (u) = 1;

-      t = fold (build (POSTINCREMENT_EXPR, TREE_TYPE (field), field,
-		       build_int_2 (incr, 0)));
-      TREE_SIDE_EFFECTS (t) = 1;
+  t = build (PLUS_EXPR, ptr_type_node, t, u);
+  TREE_SIDE_EFFECTS (t) = 1;

-      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);
-
-      emit_jump_insn (gen_jump (lab_over));
-      emit_barrier ();
-      emit_label (lab_false);
-    }
-
-  align = TYPE_ALIGN (type);
-  if (align < BITS_PER_WORD)
-    align = BITS_PER_WORD;
-  align /= BITS_PER_UNIT;
-
-  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));
-
-  val = expand_expr (t, ret, VOIDmode, EXPAND_NORMAL);
-  if (val != ret)
-    emit_move_insn (ret, val);
-
-  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);
+  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+  if (r != addr_rtx)
+    emit_move_insn (addr_rtx, r);
+
+  emit_jump_insn (gen_jump (lab_over));
+  emit_barrier ();
+  emit_label (lab_false);
+
+  /* The value was passed in memory, so read it from the overflow area.  */
+
+  t = save_expr (mem);
+  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+  if (r != addr_rtx)
+    emit_move_insn (addr_rtx, r);
+
+  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: i860.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i860/i860.h,v
retrieving revision 1.33
diff -u -p -r1.33 i860.h
--- i860.h	23 Aug 2003 02:46:12 -0000	1.33
+++ i860.h	23 Aug 2003 03:49:13 -0000
@@ -836,7 +836,7 @@ struct cumulative_args { int ints, float
 /* #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: varargs.asm
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i860/varargs.asm,v
retrieving revision 1.5
diff -u -p -r1.5 varargs.asm
--- varargs.asm	23 Aug 2003 02:24:14 -0000	1.5
+++ varargs.asm	23 Aug 2003 03:49:33 -0000
@@ -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__)



More information about the Gcc-patches mailing list