From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16151 invoked by alias); 1 Aug 2003 22:20:29 -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 16142 invoked from network); 1 Aug 2003 22:20:28 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 1 Aug 2003 22:20:28 -0000 Received: from int-mx2.corp.redhat.com (nat-pool-rdu-dmz.redhat.com [172.16.52.200] (may be forged)) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id h71MKQZ20682 for ; Fri, 1 Aug 2003 18:20:26 -0400 Received: from potter.sfbay.redhat.com (potter.sfbay.redhat.com [172.16.27.15]) by int-mx2.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h71MKO615257; Fri, 1 Aug 2003 18:20:24 -0400 Received: from redhat.com (reddwarf.sfbay.redhat.com [172.16.24.50]) by potter.sfbay.redhat.com (8.11.6/8.11.6) with ESMTP id h71MKNK31984; Fri, 1 Aug 2003 15:20:23 -0700 Message-ID: <3F2AE7A7.4070604@redhat.com> Date: Fri, 01 Aug 2003 22:20:00 -0000 From: Michael Snyder User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 X-Accept-Language: en-us, en MIME-Version: 1.0 To: gdb-patches@sources.redhat.com, ezannoni@redhat.com Subject: [RFA] sh-tdep: multi-arch the push_dummy_call method. Content-Type: multipart/mixed; boundary="------------030002080504090704080404" X-SW-Source: 2003-08/txt/msg00015.txt.bz2 This is a multi-part message in MIME format. --------------030002080504090704080404 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 305 Elena, this splits off two versions of push_dummy_call: one for sh2e, sh3e, and sh4, and the other for all the others. There are two differences: how they pass floats, and how they pass large structs. This wins us 6 new passes in call-ar-st, one in call-rt-st, 13 in callfuncs, and one in varargs. --------------030002080504090704080404 Content-Type: text/plain; name="push_args" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="push_args" Content-length: 18329 2003-07-30 Michael Snyder * sh-tdep.h (struct gdbarch_tdep): New member FLOAT_ARGLAST_REG. * sh-tdep.c (sh_gdbarch_init): For sh2e, sh3e, and sh4, set FLOAT_ARG0_REGNUM and FLOAT_ARGLAST_REGNUM, to be used for argument passing. (sh_push_dummy_call_fpu, sh_push_dummy_call_nofpu): New functions, replace sh_push_dummy_call. (sh_gdbarch_init): Set push_dummy_call to one of new methods. Index: sh-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/sh-tdep.c,v retrieving revision 1.135 diff -p -r1.135 sh-tdep.c *** sh-tdep.c 1 Aug 2003 19:52:49 -0000 1.135 --- sh-tdep.c 1 Aug 2003 22:00:40 -0000 *************** sh_frame_align (struct gdbarch *ignore, *** 2034,2040 **** return sp & ~3; } ! /* Function: push_arguments Setup the function arguments for calling a function in the inferior. On the Hitachi SH architecture, there are four registers (R4 to R7) --- 2034,2040 ---- return sp & ~3; } ! /* Function: sh_push_dummy_call (formerly push_arguments) Setup the function arguments for calling a function in the inferior. On the Hitachi SH architecture, there are four registers (R4 to R7) *************** sh_frame_align (struct gdbarch *ignore, *** 2042,2047 **** --- 2042,2051 ---- four arguments (depending on size) may go into these registers. The rest go on the stack. + MVS: Except on SH variants that have floating point registers. + In that case, float and double arguments are passed in the same + manner, but using FP registers instead of GP registers. + Arguments that are smaller than 4 bytes will still take up a whole register or a whole 32-bit word on the stack, and will be right-justified in the register or the stack word. This includes *************** sh_frame_align (struct gdbarch *ignore, *** 2055,2060 **** --- 2059,2069 ---- that will be passed in this way; in other words, the convention of passing a pointer to a large aggregate instead of a copy is not used. + MVS: The above appears to be true for the SH variants that do not + have an FPU, however those that have an FPU appear to copy the + aggregate argument onto the stack (and not place it in registers) + if it is larger than 16 bytes (four GP registers). + An exceptional case exists for struct arguments (and possibly other aggregates such as arrays) if the size is larger than 4 bytes but not a multiple of 4 bytes. In this case the argument is never split *************** sh_frame_align (struct gdbarch *ignore, *** 2078,2088 **** to R7. */ static CORE_ADDR ! sh_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, ! struct regcache *regcache, CORE_ADDR bp_addr, int nargs, ! struct value **args, CORE_ADDR sp, int struct_return, ! CORE_ADDR struct_addr) { int stack_offset, stack_alloc; int argreg; --- 2087,2210 ---- to R7. */ static CORE_ADDR ! sh_push_dummy_call_fpu (struct gdbarch *gdbarch, ! CORE_ADDR func_addr, ! struct regcache *regcache, ! CORE_ADDR bp_addr, int nargs, ! struct value **args, ! CORE_ADDR sp, int struct_return, ! CORE_ADDR struct_addr) ! { ! int stack_offset, stack_alloc; ! int argreg, flt_argreg; ! int argnum; ! struct type *type; ! CORE_ADDR regval; ! char *val; ! char valbuf[4]; ! int len; ! int odd_sized_struct; ! struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ! ! /* first force sp to a 4-byte alignment */ ! sp = sh_frame_align (gdbarch, sp); ! ! /* The "struct return pointer" pseudo-argument has its own dedicated ! register */ ! if (struct_return) ! regcache_cooked_write_unsigned (regcache, ! STRUCT_RETURN_REGNUM, ! struct_addr); ! ! /* Now make sure there's space on the stack */ ! for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++) ! stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3); ! sp -= stack_alloc; /* make room on stack for args */ ! ! /* Now load as many as possible of the first arguments into ! registers, and push the rest onto the stack. There are 16 bytes ! in four registers available. Loop thru args from first to last. */ ! ! argreg = tdep->ARG0_REGNUM; ! flt_argreg = tdep->FLOAT_ARG0_REGNUM; ! for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++) ! { ! type = VALUE_TYPE (args[argnum]); ! len = TYPE_LENGTH (type); ! memset (valbuf, 0, sizeof (valbuf)); ! if (len < 4) ! { ! /* value gets right-justified in the register or stack word */ ! if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) ! memcpy (valbuf + (4 - len), ! (char *) VALUE_CONTENTS (args[argnum]), len); ! else ! memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len); ! val = valbuf; ! } ! else ! val = (char *) VALUE_CONTENTS (args[argnum]); + if (len > 4 && (len & 3) != 0) + odd_sized_struct = 1; /* Such structs go entirely on stack. */ + else if (len > 16) + odd_sized_struct = 1; /* So do aggregates bigger than 4 words. */ + else + odd_sized_struct = 0; + while (len > 0) + { + if ((TYPE_CODE (type) == TYPE_CODE_FLT + && flt_argreg > tdep->FLOAT_ARGLAST_REGNUM) + || argreg > tdep->ARGLAST_REGNUM + || odd_sized_struct) + { + /* must go on the stack */ + write_memory (sp + stack_offset, val, 4); + stack_offset += 4; + } + /* NOTE WELL!!!!! This is not an "else if" clause!!! + That's because some *&^%$ things get passed on the stack + AND in the registers! */ + if (TYPE_CODE (type) == TYPE_CODE_FLT && + flt_argreg > 0 && flt_argreg <= tdep->FLOAT_ARGLAST_REGNUM) + { + /* Argument goes in a single-precision fp reg. */ + regval = extract_unsigned_integer (val, register_size (gdbarch, + argreg)); + regcache_cooked_write_unsigned (regcache, flt_argreg++, regval); + } + else if (argreg <= tdep->ARGLAST_REGNUM) + { + /* there's room in a register */ + regval = extract_unsigned_integer (val, register_size (gdbarch, + argreg)); + regcache_cooked_write_unsigned (regcache, argreg++, regval); + } + /* Store the value 4 bytes at a time. This means that things + larger than 4 bytes may go partly in registers and partly + on the stack. */ + len -= register_size (gdbarch, argreg); + val += register_size (gdbarch, argreg); + } + } + + /* Store return address. */ + regcache_cooked_write_unsigned (regcache, tdep->PR_REGNUM, bp_addr); + + /* Update stack pointer. */ + regcache_cooked_write_unsigned (regcache, SP_REGNUM, sp); + + return sp; + } + + static CORE_ADDR + sh_push_dummy_call_nofpu (struct gdbarch *gdbarch, + CORE_ADDR func_addr, + struct regcache *regcache, + CORE_ADDR bp_addr, + int nargs, struct value **args, + CORE_ADDR sp, int struct_return, + CORE_ADDR struct_addr) { int stack_offset, stack_alloc; int argreg; *************** sh_push_dummy_call (struct gdbarch *gdba *** 2101,2107 **** /* The "struct return pointer" pseudo-argument has its own dedicated register */ if (struct_return) ! regcache_cooked_write_unsigned (regcache, STRUCT_RETURN_REGNUM, struct_addr); /* Now make sure there's space on the stack */ for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++) --- 2223,2231 ---- /* The "struct return pointer" pseudo-argument has its own dedicated register */ if (struct_return) ! regcache_cooked_write_unsigned (regcache, ! STRUCT_RETURN_REGNUM, ! struct_addr); /* Now make sure there's space on the stack */ for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++) *************** sh_gdbarch_init (struct gdbarch_info inf *** 4374,4380 **** set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs); --- 4498,4504 ---- set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs); *************** sh_gdbarch_init (struct gdbarch_info inf *** 4387,4393 **** set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs); --- 4511,4517 ---- set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs); *************** sh_gdbarch_init (struct gdbarch_info inf *** 4404,4416 **** set_gdbarch_fp0_regnum (gdbarch, 25); set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->FPUL_REGNUM = 23; tdep->FPSCR_REGNUM = 24; tdep->FP_LAST_REGNUM = 40; ! set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs); break; case bfd_mach_sh_dsp: set_gdbarch_register_name (gdbarch, sh_sh_dsp_register_name); --- 4528,4543 ---- set_gdbarch_fp0_regnum (gdbarch, 25); set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->FPUL_REGNUM = 23; tdep->FPSCR_REGNUM = 24; tdep->FP_LAST_REGNUM = 40; + tdep->FLOAT_ARG0_REGNUM = 29; /* FIXME use constants! */ + tdep->FLOAT_ARGLAST_REGNUM = 36; /* FIXME use constants! */ ! set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, ! sh_nofp_frame_init_saved_regs); break; case bfd_mach_sh_dsp: set_gdbarch_register_name (gdbarch, sh_sh_dsp_register_name); *************** sh_gdbarch_init (struct gdbarch_info inf *** 4421,4427 **** set_gdbarch_register_sim_regno (gdbarch, sh_dsp_register_sim_regno); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->DSR_REGNUM = 24; tdep->A0G_REGNUM = 25; --- 4548,4554 ---- set_gdbarch_register_sim_regno (gdbarch, sh_dsp_register_sim_regno); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->DSR_REGNUM = 24; tdep->A0G_REGNUM = 25; *************** sh_gdbarch_init (struct gdbarch_info inf *** 4448,4454 **** set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->SSR_REGNUM = 41; tdep->SPC_REGNUM = 42; --- 4575,4581 ---- set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->SSR_REGNUM = 41; tdep->SPC_REGNUM = 42; *************** sh_gdbarch_init (struct gdbarch_info inf *** 4467,4477 **** set_gdbarch_fp0_regnum (gdbarch, 25); set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->FPUL_REGNUM = 23; tdep->FPSCR_REGNUM = 24; tdep->FP_LAST_REGNUM = 40; tdep->SSR_REGNUM = 41; tdep->SPC_REGNUM = 42; --- 4594,4606 ---- set_gdbarch_fp0_regnum (gdbarch, 25); set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->FPUL_REGNUM = 23; tdep->FPSCR_REGNUM = 24; tdep->FP_LAST_REGNUM = 40; + tdep->FLOAT_ARG0_REGNUM = 29; /* FIXME use constants! */ + tdep->FLOAT_ARGLAST_REGNUM = 36; /* FIXME use constants! */ tdep->SSR_REGNUM = 41; tdep->SPC_REGNUM = 42; *************** sh_gdbarch_init (struct gdbarch_info inf *** 4486,4492 **** set_gdbarch_register_sim_regno (gdbarch, sh_dsp_register_sim_regno); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->DSR_REGNUM = 24; tdep->A0G_REGNUM = 25; --- 4615,4621 ---- set_gdbarch_register_sim_regno (gdbarch, sh_dsp_register_sim_regno); set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->DSR_REGNUM = 24; tdep->A0G_REGNUM = 25; *************** sh_gdbarch_init (struct gdbarch_info inf *** 4519,4525 **** set_gdbarch_pseudo_register_write (gdbarch, sh_pseudo_register_write); set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->FPUL_REGNUM = 23; tdep->FPSCR_REGNUM = 24; --- 4648,4654 ---- set_gdbarch_pseudo_register_write (gdbarch, sh_pseudo_register_write); set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value); ! set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu); set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); tdep->FPUL_REGNUM = 23; tdep->FPSCR_REGNUM = 24; *************** sh_gdbarch_init (struct gdbarch_info inf *** 4530,4535 **** --- 4659,4666 ---- tdep->DR_LAST_REGNUM = 66; tdep->FV0_REGNUM = 67; tdep->FV_LAST_REGNUM = 70; + tdep->FLOAT_ARG0_REGNUM = 29; /* FIXME use constants! */ + tdep->FLOAT_ARGLAST_REGNUM = 36; /* FIXME use constants! */ set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, sh_fp_frame_init_saved_regs); break; Index: sh-tdep.h =================================================================== RCS file: /cvs/src/src/gdb/sh-tdep.h,v retrieving revision 1.3 diff -p -r1.3 sh-tdep.h *** sh-tdep.h 4 Jan 2003 23:38:45 -0000 1.3 --- sh-tdep.h 1 Aug 2003 22:00:40 -0000 *************** struct gdbarch_tdep *** 85,91 **** int FV_LAST_C_REGNUM; /* sh5-compact*/ int ARG0_REGNUM; int ARGLAST_REGNUM; ! int FLOAT_ARGLAST_REGNUM; int RETURN_REGNUM; enum sh_abi sh_abi; }; --- 85,92 ---- int FV_LAST_C_REGNUM; /* sh5-compact*/ int ARG0_REGNUM; int ARGLAST_REGNUM; ! int FLOAT_ARG0_REGNUM; /* sh4 */ ! int FLOAT_ARGLAST_REGNUM; /* sh4, sh5 */ int RETURN_REGNUM; enum sh_abi sh_abi; }; --------------030002080504090704080404--