This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[rfa] mips argument passing fixes for o32


These are based on testsuite failures (call-*-st, if I remember correctly)
and reading the argument passing code in GCC.  The struct alignment fix
definitely agrees with the ABI, though it's not always clear on this point -
it becomes necessary for us when the return value is a struct and thus there
is a hidden pointer as the first argument.  The shift fix matches this
comment in GCC and is not really specified by the ABI document:

      /* The following is a hack in order to pass 1 byte structures
         the same way that the MIPS compiler does (namely by passing
         the structure in the high byte or half word of the register).
         This also makes varargs work.  If we have such a structure,
         we save the adjustment RTL, and the call define expands will
         emit them.  For the VOIDmode argument (argument after the
         last real argument), pass back a parallel vector holding each
         of the adjustments.  */

      /* ??? function_arg can be called more than once for each argument.
         As a result, we compute more adjustments than we need here.
         See the CUMULATIVE_ARGS definition in mips.h.  */

      /* ??? This scheme requires everything smaller than the word size to
         shifted to the left, but when TARGET_64BIT and ! TARGET_INT64,
         that would mean every int needs to be shifted left, which is very
         inefficient.  Let's not carry this compatibility to the 64 bit
         calling convention for now.  */

      if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD
          && ! TARGET_64BIT && mips_abi != ABI_EABI)
        { 
          rtx amount = GEN_INT (BITS_PER_WORD
                                - int_size_in_bytes (type) * BITS_PER_UNIT);
          rtx reg = gen_rtx_REG (word_mode, regbase + *arg_words + bias);

          if (TARGET_64BIT)
            cum->adjust[cum->num_adjusts++] = gen_ashldi3 (reg, reg, amount);
          else
            cum->adjust[cum->num_adjusts++] = gen_ashlsi3 (reg, reg, amount);
        }


OK?

-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer

2001-07-06  Daniel Jacobowitz  <drow@mvista.com>

	* mips-tdep.c (mips_type_needs_double_align): New function.
	(mips_push_arguments): Align o32 structs to even argument
	registers if necessary.  Shift small structures to the left
	in registers even if the target is little endian.

Index: mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.56
diff -u -r1.56 mips-tdep.c
--- mips-tdep.c	2001/07/06 05:35:17	1.56
+++ mips-tdep.c	2001/07/06 18:03:57
@@ -2126,6 +2133,36 @@
 	   && MIPS_FPU_TYPE != MIPS_FPU_NONE);
 }
 
+/* On o32, argument passing in GPRs depends on the alignment of the type being
+   passed.  Return 1 if this type must be aligned to a doubleword boundary. */
+
+static int
+mips_type_needs_double_align (struct type *type)
+{
+  enum type_code typecode = TYPE_CODE (type);
+  
+  if (typecode == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8)
+    return 1;
+  else if (typecode == TYPE_CODE_STRUCT)
+    {
+      if (TYPE_NFIELDS (type) < 1)
+	return 0;
+      return mips_type_needs_double_align (TYPE_FIELD_TYPE (type, 0));
+    }
+  else if (typecode == TYPE_CODE_UNION)
+    {
+      int i, n;    
+
+      n = TYPE_NFIELDS (type);
+      for (i = 0; i < n; i++)
+	if (mips_type_needs_double_align (TYPE_FIELD_TYPE (type, i)))
+	  return 1;
+      return 0;
+    }
+  return 0;
+}
+
+
 CORE_ADDR
 mips_push_arguments (int nargs,
 		     value_ptr *args,
@@ -2312,6 +2349,13 @@
 	     compatibility, we will put them in both places.  */
 	  int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
 				  (len % MIPS_SAVED_REGSIZE != 0));
+	  /* Structures should be aligned to eight bytes (even arg registers)
+	     on MIPS_ABI_O32 if their first member has double precision. */
+	  if (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_O32
+	      && mips_type_needs_double_align (arg_type))
+	    {
+	      argreg += argreg & 1;
+	    }
 	  /* Note: Floating-point values that didn't fit into an FP
              register are only written to memory. */
 	  while (len > 0)
@@ -2393,7 +2437,8 @@
 
 		  if (!MIPS_EABI
 		      && MIPS_SAVED_REGSIZE < 8
-		      && TARGET_BYTE_ORDER == BIG_ENDIAN
+		      && (TARGET_BYTE_ORDER == BIG_ENDIAN
+			  || TYPE_LENGTH (arg_type) < MIPS_SAVED_REGSIZE)
 		      && partial_len < MIPS_SAVED_REGSIZE
 		      && (typecode == TYPE_CODE_STRUCT ||
 			  typecode == TYPE_CODE_UNION))


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]