From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28836 invoked by alias); 1 Jul 2003 00:06:47 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 28760 invoked from network); 1 Jul 2003 00:06:44 -0000 Received: from unknown (HELO zenia.home) (12.223.225.216) by sources.redhat.com with SMTP; 1 Jul 2003 00:06:44 -0000 Received: by zenia.home (Postfix, from userid 5433) id DF8AE202BC; Mon, 30 Jun 2003 19:06:14 -0500 (EST) To: gdb-patches@sources.redhat.com Subject: [patch]: fix argument passing on S/390 and S/390x From: Jim Blandy Date: Tue, 01 Jul 2003 00:06:00 -0000 Message-ID: User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-SW-Source: 2003-07/txt/msg00000.txt.bz2 This is a patch that was discussed and approved long ago; only recently has the legal paperwork finally come through. 2003-06-30 Jim Blandy Patch from IBM (authors unspecified, probably Ulrich Weigand and Gerhard Tonn) for argument passing on the S/390 and S/390x: * s390-tdep.c (S390_STACK_FRAME_OVERHEAD): This is always space for 16 registers, and then 32 more bytes. (S390_STACK_PARAMETER_ALIGNMENT, S390_NUM_FP_PARAMETER_REGISTERS): New macros. (is_double_arg): The s390x doesn't handle DOUBLE_ARGS specially. Move up in the file, since it's now used by is_simple_arg. (is_simple_arg): Don't assume registers are four bytes long. Exclude all double arguments. Extended floats are not simple args. (is_power_of_two): New function. (pass_by_copy_ref): Call is_power_of_two, and check that the length fits in a register, rather than listing all the acceptable sizes. Extended floats are not passed by reference. (s390_push_arguments): Don't assume registers are four bytes long. Reserve an argument register to point to the buffer for structures returned by value. Use S390_NUM_FP_PARAMETER_REGISTERS and S390_STACK_FRAME_OVERHEAD. Index: gdb/s390-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/s390-tdep.c,v retrieving revision 1.105 diff -c -r1.105 s390-tdep.c *** gdb/s390-tdep.c 20 Jun 2003 13:57:28 -0000 1.105 --- gdb/s390-tdep.c 1 Jul 2003 00:04:28 -0000 *************** *** 93,99 **** #define S390X_SIGREGS_FP0_OFFSET (216) #define S390_UC_MCONTEXT_OFFSET (256) #define S390X_UC_MCONTEXT_OFFSET (344) ! #define S390_STACK_FRAME_OVERHEAD (GDB_TARGET_IS_ESAME ? 160:96) #define S390_SIGNAL_FRAMESIZE (GDB_TARGET_IS_ESAME ? 160:96) #define s390_NR_sigreturn 119 #define s390_NR_rt_sigreturn 173 --- 93,101 ---- #define S390X_SIGREGS_FP0_OFFSET (216) #define S390_UC_MCONTEXT_OFFSET (256) #define S390X_UC_MCONTEXT_OFFSET (344) ! #define S390_STACK_FRAME_OVERHEAD 16*DEPRECATED_REGISTER_SIZE+32 ! #define S390_STACK_PARAMETER_ALIGNMENT DEPRECATED_REGISTER_SIZE ! #define S390_NUM_FP_PARAMETER_REGISTERS (GDB_TARGET_IS_ESAME ? 4:2) #define S390_SIGNAL_FRAMESIZE (GDB_TARGET_IS_ESAME ? 160:96) #define s390_NR_sigreturn 119 #define s390_NR_rt_sigreturn 173 *************** *** 1331,1337 **** 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) --- 1333,1339 ---- 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 include those types here. *shrug* */ static int is_float_like (struct type *type) *************** *** 1354,1359 **** --- 1356,1380 ---- } + /* Return non-zero if TYPE is a `DOUBLE_ARG', as defined by the + parameter passing conventions described in the "GNU/Linux for S/390 + ELF Application Binary Interface Supplement". Return zero + otherwise. */ + static int + is_double_arg (struct type *type) + { + unsigned length = TYPE_LENGTH (type); + + /* The s390x ABI doesn't handle DOUBLE_ARGS specially. */ + if (GDB_TARGET_IS_ESAME) + return 0; + + return ((is_integer_like (type) + || is_struct_like (type)) + && length == 8); + } + + /* Return non-zero if TYPE is considered a `SIMPLE_ARG', as defined by the parameter passing conventions described in the "GNU/Linux for S/390 ELF Application Binary Interface Supplement". Return zero *************** *** 1365,1377 **** /* 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)); } /* Return non-zero if TYPE should be passed as a pointer to a copy, zero otherwise. TYPE must be a SIMPLE_ARG, as recognized by `is_simple_arg'. */ --- 1386,1403 ---- /* 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 <= DEPRECATED_REGISTER_SIZE) || is_pointer_like (type) ! || (is_struct_like (type) && !is_double_arg (type))); } + static int + is_power_of_two (unsigned int n) + { + return ((n & (n - 1)) == 0); + } + /* Return non-zero if TYPE should be passed as a pointer to a copy, zero otherwise. TYPE must be a SIMPLE_ARG, as recognized by `is_simple_arg'. */ *************** *** 1380,1387 **** { unsigned length = TYPE_LENGTH (type); ! return ((is_struct_like (type) && length != 1 && length != 2 && length != 4) ! || (is_float_like (type) && length == 16)); } --- 1406,1413 ---- { unsigned length = TYPE_LENGTH (type); ! return (is_struct_like (type) ! && !(is_power_of_two (length) && length <= DEPRECATED_REGISTER_SIZE)); } *************** *** 1404,1424 **** } - /* Return non-zero if TYPE is a `DOUBLE_ARG', as defined by the - parameter passing conventions described in the "GNU/Linux for S/390 - ELF Application Binary Interface Supplement". Return zero - otherwise. */ - static int - is_double_arg (struct type *type) - { - unsigned length = TYPE_LENGTH (type); - - return ((is_integer_like (type) - || is_struct_like (type)) - && length == 8); - } - - /* Round ADDR up to the next N-byte boundary. N must be a power of two. */ static CORE_ADDR --- 1430,1435 ---- *************** *** 1538,1546 **** sp = round_down (sp, alignment_of (type)); ! /* SIMPLE_ARG values get extended to 32 bits. Assume every ! argument is. */ ! if (length < 4) length = 4; sp -= length; } } --- 1549,1557 ---- sp = round_down (sp, alignment_of (type)); ! /* SIMPLE_ARG values get extended to DEPRECATED_REGISTER_SIZE bytes. ! Assume every argument is. */ ! if (length < DEPRECATED_REGISTER_SIZE) length = DEPRECATED_REGISTER_SIZE; sp -= length; } } *************** *** 1561,1573 **** int gr = 2; CORE_ADDR starg = sp; for (i = 0; i < nargs; i++) { struct value *arg = args[i]; struct type *type = VALUE_TYPE (arg); if (is_double_or_float (type) ! && fr <= 2) { /* When we store a single-precision value in an FP register, it occupies the leftmost bits. */ --- 1572,1588 ---- int gr = 2; CORE_ADDR starg = sp; + /* A struct is returned using general register 2 */ + if (struct_return) + gr++; + for (i = 0; i < nargs; i++) { struct value *arg = args[i]; struct type *type = VALUE_TYPE (arg); if (is_double_or_float (type) ! && fr <= S390_NUM_FP_PARAMETER_REGISTERS * 2 - 2) { /* When we store a single-precision value in an FP register, it occupies the leftmost bits. */ *************** *** 1594,1600 **** deprecated_write_register_gen (S390_GP0_REGNUM + gr, VALUE_CONTENTS (arg)); deprecated_write_register_gen (S390_GP0_REGNUM + gr + 1, ! VALUE_CONTENTS (arg) + 4); gr += 2; } else --- 1609,1615 ---- deprecated_write_register_gen (S390_GP0_REGNUM + gr, VALUE_CONTENTS (arg)); deprecated_write_register_gen (S390_GP0_REGNUM + gr + 1, ! VALUE_CONTENTS (arg) + DEPRECATED_REGISTER_SIZE); gr += 2; } else *************** *** 1610,1618 **** if (is_simple_arg (type)) { ! /* Simple args are always either extended to 32 bits, ! or pointers. */ ! starg = round_up (starg, 4); /* Do we need to pass a pointer to our copy of this argument? */ --- 1625,1633 ---- if (is_simple_arg (type)) { ! /* Simple args are always extended to ! DEPRECATED_REGISTER_SIZE bytes. */ ! starg = round_up (starg, DEPRECATED_REGISTER_SIZE); /* Do we need to pass a pointer to our copy of this argument? */ *************** *** 1620,1637 **** write_memory_signed_integer (starg, pointer_size, copy_addr[i]); else ! /* Simple args are always extended to 32 bits. */ ! write_memory_signed_integer (starg, 4, extend_simple_arg (arg)); ! starg += 4; } 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; } --- 1635,1653 ---- write_memory_signed_integer (starg, pointer_size, copy_addr[i]); else ! /* Simple args are always extended to ! DEPRECATED_REGISTER_SIZE bytes. */ ! write_memory_signed_integer (starg, DEPRECATED_REGISTER_SIZE, extend_simple_arg (arg)); ! starg += DEPRECATED_REGISTER_SIZE; } 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/eight-byte boundary, even when passing doubles. */ ! starg = round_up (starg, S390_STACK_PARAMETER_ALIGNMENT); write_memory (starg, VALUE_CONTENTS (arg), length); starg += length; } *************** *** 1642,1648 **** /* Allocate the standard frame areas: the register save area, the word reserved for the compiler (which seems kind of meaningless), and the back chain pointer. */ ! sp -= 96; /* Write the back chain pointer into the first word of the stack frame. This will help us get backtraces from within functions --- 1658,1664 ---- /* Allocate the standard frame areas: the register save area, the word reserved for the compiler (which seems kind of meaningless), and the back chain pointer. */ ! sp -= S390_STACK_FRAME_OVERHEAD; /* Write the back chain pointer into the first word of the stack frame. This will help us get backtraces from within functions