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]
Other format: [Raw text]

PATCH: S/390: match GCC arg-passing bugs



It's not clear that the GCC bugs should ever be fixed --- argument
passing works fine as it stands, and fixing GCC would cause it to
generate binary-incompatible executables.  So for now, I've changed
GDB to match GCC's (rather odd) behavior.  If the S/390 GCC
maintainers decide to make GCC conform to the ABI, then we can back
out this patch.

2001-11-16  Jim Blandy  <jimb@redhat.com>

	* s390-tdep.c: Tweak argument-passing to match GCC bugs.
	(is_float_singleton, is_struct_like, is_float_like): New
 	functions, that isolate the weirdness.
	(is_double_or_float, is_simple_arg, pass_by_copy_ref,
 	is_double_arg): Use is_struct_like and is_float_like, rather than
 	testing the type codes ourselves.
	(s390_push_arguments): When passing args on the stack, align each
 	on to a four-byte boundary, regardless of what the type itself
 	needs.

Index: gdb/s390-tdep.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/s390-tdep.c,v
retrieving revision 2.16
diff -c -r2.16 s390-tdep.c
*** gdb/s390-tdep.c	2001/11/16 02:43:03	2.16
--- gdb/s390-tdep.c	2001/11/16 21:32:35
***************
*** 1221,1226 ****
--- 1221,1288 ----
  }
  
  
+ /* Return non-zero if TYPE is a `float singleton' or `double
+    singleton', zero otherwise.
+ 
+    A `T singleton' is a struct type with one member, whose type is
+    either T or a `T singleton'.  So, the following are all float
+    singletons:
+ 
+    struct { float x };
+    struct { struct { float x; } x; };
+    struct { struct { struct { float x; } x; } x; };
+ 
+    ... and so on.
+ 
+    WHY THE HECK DO WE CARE ABOUT THIS???  Well, it turns out that GCC
+    passes all float singletons and double singletons as if they were
+    simply floats or doubles.  This is *not* what the ABI says it
+    should do.  */
+ static int
+ is_float_singleton (struct type *type)
+ {
+   return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+           && TYPE_NFIELDS (type) == 1
+           && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT
+               || is_float_singleton (TYPE_FIELD_TYPE (type, 0))));
+ }
+ 
+ 
+ /* Return non-zero if TYPE is a struct-like type, zero otherwise.
+    "Struct-like" types are those that should be passed as structs are:
+    structs and unions.
+ 
+    As an odd quirk, not mentioned in the ABI, GCC passes float and
+    double singletons as if they were a plain float, double, etc.  (The
+    corresponding union types are handled normally.)  So we exclude
+    those types here.  *shrug* */
+ static int
+ is_struct_like (struct type *type)
+ {
+   enum type_code code = TYPE_CODE (type);
+ 
+   return (code == TYPE_CODE_UNION
+           || (code == TYPE_CODE_STRUCT && ! is_float_singleton (type)));
+ }
+ 
+ 
+ /* Return non-zero if TYPE is a float-like type, zero otherwise.
+    "Float-like" types are those that should be passed as
+    floating-point values are.
+ 
+    You'd think this would just be floats, doubles, long doubles, etc.
+    But as an odd quirk, not mentioned in the ABI, GCC passes float and
+    double singletons as if they were a plain float, double, etc.  (The
+    corresponding union types are handled normally.)  So we exclude
+    those types here.  *shrug* */
+ static int
+ is_float_like (struct type *type)
+ {
+   return (TYPE_CODE (type) == TYPE_CODE_FLT
+           || is_float_singleton (type));
+ }
+ 
+ 
  /* Return non-zero if TYPE is considered a `DOUBLE_OR_FLOAT', as
     defined by the parameter passing conventions described in the
     "Linux for S/390 ELF Application Binary Interface Supplement".
***************
*** 1228,1234 ****
  static int
  is_double_or_float (struct type *type)
  {
!   return (TYPE_CODE (type) == TYPE_CODE_FLT
            && (TYPE_LENGTH (type) == 4
                || TYPE_LENGTH (type) == 8));
  }
--- 1290,1296 ----
  static int
  is_double_or_float (struct type *type)
  {
!   return (is_float_like (type)
            && (TYPE_LENGTH (type) == 4
                || TYPE_LENGTH (type) == 8));
  }
***************
*** 1240,1256 ****
  static int
  is_simple_arg (struct type *type)
  {
-   enum type_code code = TYPE_CODE (type);
    unsigned length = TYPE_LENGTH (type);
  
    /* This is almost a direct translation of the ABI's language, except
       that we have to exclude 8-byte structs; those are DOUBLE_ARGs.  */
    return ((is_integer_like (type) && length <= 4)
            || is_pointer_like (type)
!           || ((code == TYPE_CODE_STRUCT
!                || code == TYPE_CODE_UNION)
!               && length != 8)
!           || (code == TYPE_CODE_FLT && length == 16));
  }
  
  
--- 1302,1315 ----
  static int
  is_simple_arg (struct type *type)
  {
    unsigned length = TYPE_LENGTH (type);
  
    /* This is almost a direct translation of the ABI's language, except
       that we have to exclude 8-byte structs; those are DOUBLE_ARGs.  */
    return ((is_integer_like (type) && length <= 4)
            || is_pointer_like (type)
!           || (is_struct_like (type) && length != 8)
!           || (is_float_like (type) && length == 16));
  }
  
  
***************
*** 1260,1271 ****
  static int
  pass_by_copy_ref (struct type *type)
  {
-   enum type_code code = TYPE_CODE (type);
    unsigned length = TYPE_LENGTH (type);
  
!   return (((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
!            && length != 1 && length != 2 && length != 4)
!           || (code == TYPE_CODE_FLT && length == 16));
  }
  
  
--- 1319,1328 ----
  static int
  pass_by_copy_ref (struct type *type)
  {
    unsigned length = TYPE_LENGTH (type);
  
!   return ((is_struct_like (type) && length != 1 && length != 2 && length != 4)
!           || (is_float_like (type) && length == 16));
  }
  
  
***************
*** 1294,1305 ****
  static int
  is_double_arg (struct type *type)
  {
-   enum type_code code = TYPE_CODE (type);
    unsigned length = TYPE_LENGTH (type);
  
    return ((is_integer_like (type)
!            || code == TYPE_CODE_STRUCT
!            || code == TYPE_CODE_UNION)
            && length == 8);
  }
  
--- 1351,1360 ----
  static int
  is_double_arg (struct type *type)
  {
    unsigned length = TYPE_LENGTH (type);
  
    return ((is_integer_like (type)
!            || is_struct_like (type))
            && length == 8);
  }
  
***************
*** 1512,1518 ****
                }
              else
                {
!                 starg = round_up (starg, alignment_of (type));
                  write_memory (starg, VALUE_CONTENTS (arg), length);
                  starg += length;
                }
--- 1567,1577 ----
                }
              else
                {
!                 /* You'd think we should say:
!                    starg = round_up (starg, alignment_of (type));
!                    Unfortunately, GCC seems to simply align the stack on
!                    a four-byte boundary, even when passing doubles.  */
!                 starg = round_up (starg, 4);
                  write_memory (starg, VALUE_CONTENTS (arg), length);
                  starg += length;
                }


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