From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24755 invoked by alias); 12 Sep 2003 15:02:15 -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 24691 invoked from network); 12 Sep 2003 15:01:36 -0000 Received: from unknown (HELO localhost.redhat.com) (207.219.125.105) by sources.redhat.com with SMTP; 12 Sep 2003 15:01:36 -0000 Received: from redhat.com (localhost [127.0.0.1]) by localhost.redhat.com (Postfix) with ESMTP id 4A1E42B89; Fri, 12 Sep 2003 11:01:07 -0400 (EDT) Message-ID: <3F61DFB3.7000706@redhat.com> Date: Fri, 12 Sep 2003 15:02:00 -0000 From: Andrew Cagney User-Agent: Mozilla/5.0 (X11; U; NetBSD macppc; en-US; rv:1.0.2) Gecko/20030820 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Andrew Cagney Cc: gdb-patches@sources.redhat.com Subject: Re: [rfa:ppc] Cleanup SVR4 push dummy call References: <3F61DC59.5040706@redhat.com> Content-Type: multipart/mixed; boundary="------------050605020104030807060704" X-SW-Source: 2003-09/txt/msg00260.txt.bz2 This is a multi-part message in MIME format. --------------050605020104030807060704 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Content-length: 601 > Hello, > > This patch rewrites ppc_svr4_push_dummy_call so that it implements the two-pass push-arguments algorithm using a "for" loop. > > The simplification identified and fixed the bugs: > > - Altivec registers on the stack weren't being 16 byte aligned > - Floats weren't being converted to doubles before being stored in register/memory ("gdb.base/callfuncs.exp: p t_float_values2" now passes). > > Ok? > > Andrew > > PS: I intend moving align_{up,down} to utils.c but that is separate. Oops, try this. It's got the up-to-date changelog and uses a more readable context diff. Andrew --------------050605020104030807060704 Content-Type: text/plain; name="diffs" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="diffs" Content-length: 18966 2003-09-12 Andrew Cagney * ppc-sysv-tdep.c (align_up, align_down): Replace "round2" macro. (ppc_sysv_abi_push_dummy_call): Rewrite, use a two pass loop. Index: ppc-sysv-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v retrieving revision 1.9 diff -c -r1.9 ppc-sysv-tdep.c *** ppc-sysv-tdep.c 11 Sep 2003 19:27:25 -0000 1.9 --- ppc-sysv-tdep.c 12 Sep 2003 14:57:41 -0000 *************** *** 29,39 **** #include "ppc-tdep.h" ! /* round2 rounds x up to the nearest multiple of s assuming that s is a ! power of 2 */ ! #undef round2 ! #define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s)) /* Pass the arguments in either registers, or in the stack. Using the ppc sysv ABI, the first eight words of the argument list (that might --- 29,48 ---- #include "ppc-tdep.h" ! /* Ensure that X is aligned to an S byte boundary (assuming that S is ! a power of 2) rounding up/down where necessary. */ ! static ULONGEST ! align_up (ULONGEST x, int s) ! { ! return (x + s - 1) & -s; ! } ! ! static ULONGEST ! align_down (ULONGEST x, int s) ! { ! return (x & -s); ! } /* Pass the arguments in either registers, or in the stack. Using the ppc sysv ABI, the first eight words of the argument list (that might *************** *** 52,349 **** int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr) { - int argno; - /* Next available general register for non-float, non-vector arguments. */ - int greg; - /* Next available floating point register for float arguments. */ - int freg; - /* Next available vector register for vector arguments. */ - int vreg; - int argstkspace; - int structstkspace; - int argoffset; - int structoffset; - struct type *type; - int len; - char old_sp_buf[4]; - CORE_ADDR saved_sp; struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); ! greg = 3; ! freg = 1; ! vreg = 2; ! argstkspace = 0; ! structstkspace = 0; ! ! /* If the function is returning a `struct', then the first word ! (which will be passed in r3) is used for struct return address. ! In that case we should advance one word and start from r4 ! register to copy parameters. */ ! if (struct_return) ! { ! regcache_raw_write_signed (regcache, tdep->ppc_gp0_regnum + greg, ! struct_addr); ! greg++; ! } ! /* Figure out how much new stack space is required for arguments ! which don't fit in registers. Unlike the PowerOpen ABI, the ! SysV ABI doesn't reserve any extra space for parameters which ! are put in registers. */ ! for (argno = 0; argno < nargs; argno++) { ! struct value *arg = args[argno]; ! type = check_typedef (VALUE_TYPE (arg)); ! len = TYPE_LENGTH (type); ! ! if (TYPE_CODE (type) == TYPE_CODE_FLT ! && ppc_floating_point_unit_p (current_gdbarch)) { ! if (freg <= 8) ! freg++; ! else ! { ! /* SysV ABI converts floats to doubles when placed in ! memory and requires 8 byte alignment */ ! if (argstkspace & 0x4) ! argstkspace += 4; ! argstkspace += 8; ! } } ! else if (len == 8 ! && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */ ! || (!ppc_floating_point_unit_p (current_gdbarch) ! && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */ { ! if (greg > 9) ! { ! greg = 11; ! if (argstkspace & 0x4) ! argstkspace += 4; ! argstkspace += 8; ! } ! else ! { ! if ((greg & 1) == 0) ! greg++; ! greg += 2; ! } ! } ! else if (!TYPE_VECTOR (type)) ! { ! if (len > 4 ! || TYPE_CODE (type) == TYPE_CODE_STRUCT ! || TYPE_CODE (type) == TYPE_CODE_UNION) ! { ! /* Rounding to the nearest multiple of 8 may not be necessary, ! but it is safe. Particularly since we don't know the ! field types of the structure */ ! structstkspace += round2 (len, 8); ! } ! if (greg <= 10) ! greg++; ! else ! argstkspace += 4; ! } ! else ! { ! if (len == 16 ! && TYPE_CODE (type) == TYPE_CODE_ARRAY ! && TYPE_VECTOR (type)) ! { ! if (vreg <= 13) ! vreg++; else { ! /* Vector arguments must be aligned to 16 bytes on ! the stack. */ ! argstkspace += round2 (argstkspace, 16); ! argstkspace += 16; } } ! else if (len == 8 ! && TYPE_CODE (type) == TYPE_CODE_ARRAY ! && TYPE_VECTOR (type)) ! { ! if (greg <= 10) ! greg++; ! else ! { ! /* Vector arguments must be aligned to 8 bytes on ! the stack. */ ! argstkspace += round2 (argstkspace, 8); ! argstkspace += 8; ! } ! } ! } ! } ! ! /* Get current SP location */ ! saved_sp = read_sp (); ! ! sp -= argstkspace + structstkspace; ! ! /* Allocate space for backchain and callee's saved lr */ ! sp -= 8; ! ! /* Make sure that we maintain 16 byte alignment */ ! sp &= ~0x0f; ! ! /* Update %sp before proceeding any further. */ ! regcache_raw_write_signed (regcache, SP_REGNUM, sp); ! ! /* write the backchain */ ! store_unsigned_integer (old_sp_buf, 4, saved_sp); ! write_memory (sp, old_sp_buf, 4); ! ! argoffset = 8; ! structoffset = argoffset + argstkspace; ! freg = 1; ! greg = 3; ! vreg = 2; ! ! /* Fill in r3 with the return structure, if any */ ! if (struct_return) ! { ! write_register (tdep->ppc_gp0_regnum + greg, struct_addr); ! greg++; ! } ! ! /* Now fill in the registers and stack... */ ! for (argno = 0; argno < nargs; argno++) ! { ! struct value *arg = args[argno]; ! char *val = VALUE_CONTENTS (arg); ! type = check_typedef (VALUE_TYPE (arg)); ! len = TYPE_LENGTH (type); ! ! if (TYPE_CODE (type) == TYPE_CODE_FLT ! && ppc_floating_point_unit_p (current_gdbarch)) ! { ! if (freg <= 8) ! { ! ULONGEST regval; ! if (len > 8) ! printf_unfiltered ( ! "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno); ! regval = extract_unsigned_integer (val, len); ! write_register (FP0_REGNUM + freg, regval); ! freg++; ! } ! else ! { ! /* SysV ABI converts floats to doubles when placed in ! memory and requires 8 byte alignment */ ! /* FIXME: Convert floats to doubles */ ! if (argoffset & 0x4) ! argoffset += 4; ! write_memory (sp + argoffset, val, len); ! argoffset += 8; ! } ! } ! else if (len == 8 ! && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */ ! || (!ppc_floating_point_unit_p (current_gdbarch) ! && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */ ! { ! if (greg > 9) ! { ! greg = 11; ! if (argoffset & 0x4) ! argoffset += 4; ! write_memory (sp + argoffset, val, len); ! argoffset += 8; ! } ! else ! { ! ULONGEST regval; ! if ((greg & 1) == 0) ! greg++; ! regval = extract_unsigned_integer (val, 4); ! write_register (tdep->ppc_gp0_regnum + greg, regval); ! regval = extract_unsigned_integer (val + 4, 4); ! write_register (tdep->ppc_gp0_regnum + greg + 1, regval); ! greg += 2; ! } ! } ! else if (!TYPE_VECTOR (type)) ! { ! char val_buf[4]; ! if (len > 4 ! || TYPE_CODE (type) == TYPE_CODE_STRUCT ! || TYPE_CODE (type) == TYPE_CODE_UNION) ! { ! write_memory (sp + structoffset, val, len); ! store_unsigned_integer (val_buf, 4, sp + structoffset); ! structoffset += round2 (len, 8); ! } ! else ! { ! memset (val_buf, 0, 4); ! memcpy (val_buf, val, len); ! } ! if (greg <= 10) ! { ! ULONGEST regval = extract_unsigned_integer (val_buf, 4); ! write_register (tdep->ppc_gp0_regnum + greg, regval); ! greg++; ! } ! else ! { ! write_memory (sp + argoffset, val_buf, 4); ! argoffset += 4; } ! } ! else ! { ! if (len == 16 ! && TYPE_CODE (type) == TYPE_CODE_ARRAY ! && TYPE_VECTOR (type)) { ! char *v_val_buf = alloca (16); ! memset (v_val_buf, 0, 16); ! memcpy (v_val_buf, val, len); if (vreg <= 13) { ! regcache_cooked_write (current_regcache, ! tdep->ppc_vr0_regnum + vreg, ! v_val_buf); vreg++; } else { ! write_memory (sp + argoffset, v_val_buf, 16); argoffset += 16; } } else if (len == 8 && TYPE_CODE (type) == TYPE_CODE_ARRAY ! && TYPE_VECTOR (type)) { ! char *v_val_buf = alloca (8); ! memset (v_val_buf, 0, 8); ! memcpy (v_val_buf, val, len); if (greg <= 10) { ! regcache_cooked_write (current_regcache, ! tdep->ppc_ev0_regnum + greg, ! v_val_buf); greg++; } else { ! write_memory (sp + argoffset, v_val_buf, 8); argoffset += 8; } } ! } } /* Point the inferior function call's return address at the dummy's breakpoint. */ ! regcache_raw_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); - target_store_registers (-1); return sp; } --- 61,330 ---- int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr) { struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + const CORE_ADDR saved_sp = read_sp (); + int argspace = 0; /* 0 is an initial wrong guess. */ + int write_pass; + + /* Go through the argument list twice. + + Pass 1: Figure out how much new stack space is required for + arguments and pushed values. Unlike the PowerOpen ABI, the SysV + ABI doesn't reserve any extra space for parameters which are put + in registers, but does always push structures and then pass their + address. ! Pass 2: Replay the same computation but this time also write the ! values out to the target. */ ! for (write_pass = 0; write_pass < 2; write_pass++) { ! int argno; ! /* Next available floating point register for float and double ! arguments. */ ! int freg = 1; ! /* Next available general register for non-float, non-vector ! arguments. */ ! int greg = 3; ! /* Next available vector register for vector arguments. */ ! int vreg = 2; ! /* Arguments start above the "LR save word" and "Back chain". */ ! int argoffset = 2 * tdep->wordsize; ! /* Structures start after the arguments. */ ! int structoffset = argoffset + argspace; ! ! /* If the function is returning a `struct', then the first word ! (which will be passed in r3) is used for struct return ! address. In that case we should advance one word and start ! from r4 register to copy parameters. */ ! if (struct_return) { ! if (write_pass) ! regcache_cooked_write_signed (regcache, ! tdep->ppc_gp0_regnum + greg, ! struct_addr); ! greg++; } ! ! for (argno = 0; argno < nargs; argno++) { ! struct value *arg = args[argno]; ! struct type *type = check_typedef (VALUE_TYPE (arg)); ! int len = TYPE_LENGTH (type); ! char *val = VALUE_CONTENTS (arg); ! ! if (TYPE_CODE (type) == TYPE_CODE_FLT ! && ppc_floating_point_unit_p (current_gdbarch) ! && len <= 8) ! { ! /* Floating point value converted to "double" then ! passed in an FP register, when the registers run out, ! 8 byte aligned stack is used. */ ! if (freg <= 8) ! { ! if (write_pass) ! { ! /* Always store the floating point value using ! the register's floating-point format. */ ! char regval[MAX_REGISTER_SIZE]; ! struct type *regtype ! = register_type (gdbarch, FP0_REGNUM + freg); ! convert_typed_floating (val, type, regval, regtype); ! regcache_cooked_write (regcache, FP0_REGNUM + freg, ! regval); ! } ! freg++; ! } else { ! /* SysV ABI converts floats to doubles before ! writing them to an 8 byte aligned stack location. */ ! argoffset = align_up (argoffset, 8); ! if (write_pass) ! { ! char memval[8]; ! struct type *memtype; ! switch (TARGET_BYTE_ORDER) ! { ! case BFD_ENDIAN_BIG: ! memtype = builtin_type_ieee_double_big; ! break; ! case BFD_ENDIAN_LITTLE: ! memtype = builtin_type_ieee_double_little; ! break; ! default: ! internal_error (__FILE__, __LINE__, "bad switch"); ! } ! convert_typed_floating (val, type, memval, memtype); ! write_memory (sp + argoffset, val, len); ! } ! argoffset += 8; } } ! else if (len == 8 ! && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */ ! || (!ppc_floating_point_unit_p (current_gdbarch) ! && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */ ! { ! /* "long long" or "double" passed in an odd/even ! register pair with the low addressed word in the odd ! register and the high addressed word in the even ! register, or when the registers run out an 8 byte ! aligned stack location. */ ! if (greg > 9) ! { ! /* Just in case GREG was 10. */ ! greg = 11; ! argoffset = align_up (argoffset, 8); ! write_memory (sp + argoffset, val, len); ! argoffset += 8; ! } ! else if (tdep->wordsize == 8) ! { ! if (write_pass) ! regcache_cooked_write (regcache, ! tdep->ppc_gp0_regnum + greg, ! val); ! greg += 1; ! } ! else ! { ! /* Must start on an odd register - r3/r4 etc. */ ! if ((greg & 1) == 0) ! greg++; ! if (write_pass) ! { ! regcache_cooked_write (regcache, ! tdep->ppc_gp0_regnum + greg + 0, ! val + 0); ! regcache_cooked_write (regcache, ! tdep->ppc_gp0_regnum + greg + 1, ! val + 4); ! } ! greg += 2; ! } } ! else if (len == 16 ! && TYPE_CODE (type) == TYPE_CODE_ARRAY ! && TYPE_VECTOR (type) ! && tdep->ppc_vr0_regnum >= 0) { ! /* Vector parameter passed in an Altivec register, or ! when that runs out, 16 byte aligned stack location. */ if (vreg <= 13) { ! if (write_pass) ! regcache_cooked_write (current_regcache, ! tdep->ppc_vr0_regnum + vreg, ! val); vreg++; } else { ! argoffset = align_up (argoffset, 16); ! if (write_pass) ! write_memory (sp + argoffset, val, 16); argoffset += 16; } } else if (len == 8 && TYPE_CODE (type) == TYPE_CODE_ARRAY ! && TYPE_VECTOR (type) ! && tdep->ppc_ev0_regnum >= 0) { ! /* Vector parameter passed in an e500 register, or when ! that runs out, 8 byte aligned stack location. Note ! that since e500 vector and general purpose registers ! both map onto the same underlying register set, a ! "greg" and not a "vreg" is consumed here. A cooked ! write stores the value in the correct locations ! within the raw register cache. */ if (greg <= 10) { ! if (write_pass) ! regcache_cooked_write (current_regcache, ! tdep->ppc_ev0_regnum + greg, ! val); greg++; } else { ! argoffset = align_up (argoffset, 8); ! if (write_pass) ! write_memory (sp + argoffset, val, 8); argoffset += 8; } } ! else ! { ! /* Reduce the parameter down to something that fits in a ! "word". */ ! char word[MAX_REGISTER_SIZE]; ! memset (word, 0, MAX_REGISTER_SIZE); ! if (len > tdep->wordsize ! || TYPE_CODE (type) == TYPE_CODE_STRUCT ! || TYPE_CODE (type) == TYPE_CODE_UNION) ! { ! /* Structs and large values are put on an 8 byte ! aligned stack ... */ ! structoffset = align_up (structoffset, 8); ! if (write_pass) ! write_memory (sp + structoffset, val, len); ! /* ... and then a "word" pointing to that address is ! passed as the parameter. */ ! store_unsigned_integer (word, tdep->wordsize, ! sp + structoffset); ! structoffset += len; ! } ! else if (TYPE_CODE (type) == TYPE_CODE_INT) ! /* Sign or zero extend the "int" into a "word". */ ! store_unsigned_integer (word, tdep->wordsize, ! unpack_long (type, val)); ! else ! /* Always goes in the low address. */ ! memcpy (word, val, len); ! /* Store that "word" in a register, or on the stack. ! The words have "4" byte alignment. */ ! if (greg <= 10) ! { ! if (write_pass) ! regcache_cooked_write (regcache, ! tdep->ppc_gp0_regnum + greg, ! word); ! greg++; ! } ! else ! { ! argoffset = align_up (argoffset, tdep->wordsize); ! if (write_pass) ! write_memory (sp + argoffset, word, tdep->wordsize); ! argoffset += tdep->wordsize; ! } ! } ! } ! ! /* Compute the actual stack space requirements. */ ! if (!write_pass) ! { ! /* Remember the amount of space needed by the arguments. */ ! argspace = argoffset; ! /* Allocate space for both the arguments and the structures. */ ! sp -= (argoffset + structoffset); ! /* Ensure that the stack is still 16 byte aligned. */ ! sp = align_down (sp, 16); ! } } + /* Update %sp. */ + regcache_cooked_write_signed (regcache, SP_REGNUM, sp); + + /* Write the backchain (it occupies WORDSIZED bytes). */ + write_memory_signed_integer (sp, tdep->wordsize, saved_sp); + /* Point the inferior function call's return address at the dummy's breakpoint. */ ! regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); return sp; } --------------050605020104030807060704--