From 20a940cc8c7878821b93e69069918b327047a34e Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Fri, 16 Nov 2001 21:40:36 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 12 +++++++ gdb/s390-tdep.c | 87 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a679219380..e0b5a1637f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2001-11-16 Jim Blandy + + * 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. + 2001-11-16 Ben Harris * Makefile.in (os9kread.o): Replace $< with autoconf-approved diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c index d79654d878..20c2f647d0 100644 --- a/gdb/s390-tdep.c +++ b/gdb/s390-tdep.c @@ -1221,6 +1221,68 @@ is_pointer_like (struct type *type) } +/* 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,7 +1290,7 @@ is_pointer_like (struct type *type) static int is_double_or_float (struct type *type) { - return (TYPE_CODE (type) == TYPE_CODE_FLT + return (is_float_like (type) && (TYPE_LENGTH (type) == 4 || TYPE_LENGTH (type) == 8)); } @@ -1240,17 +1302,14 @@ is_double_or_float (struct type *type) 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)); + || (is_struct_like (type) && length != 8) + || (is_float_like (type) && length == 16)); } @@ -1260,12 +1319,10 @@ is_simple_arg (struct type *type) 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)); + return ((is_struct_like (type) && length != 1 && length != 2 && length != 4) + || (is_float_like (type) && length == 16)); } @@ -1294,12 +1351,10 @@ extend_simple_arg (struct value *arg) 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) + || is_struct_like (type)) && length == 8); } @@ -1512,7 +1567,11 @@ s390_push_arguments (int nargs, struct value **args, CORE_ADDR sp, } else { - starg = round_up (starg, alignment_of (type)); + /* 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; }