From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8477 invoked by alias); 25 Sep 2003 21:44:56 -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 8468 invoked from network); 25 Sep 2003 21:44:54 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 25 Sep 2003 21:44:54 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id h8PLir111017 for ; Thu, 25 Sep 2003 17:44:53 -0400 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [172.16.52.156]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h8PLirc05793 for ; Thu, 25 Sep 2003 17:44:53 -0400 Received: from localhost.redhat.com (devserv.devel.redhat.com [172.16.58.1]) by pobox.corp.redhat.com (8.12.8/8.12.8) with ESMTP id h8PLirTX017446 for ; Thu, 25 Sep 2003 17:44:53 -0400 Received: by localhost.redhat.com (Postfix, from userid 469) id A35932CCA5; Thu, 25 Sep 2003 17:54:43 -0400 (EDT) From: Elena Zannoni MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <16243.25635.470137.318341@localhost.redhat.com> Date: Thu, 25 Sep 2003 21:44:00 -0000 To: gdb-patches@sources.redhat.com Subject: Re: SH follow up, part 2 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs) In-Reply-To: <20030924103916.GH9981@cygbert.vinschen.de> References: <20030917161127.GM9981@cygbert.vinschen.de> <16240.45203.260059.116019@localhost.redhat.com> <20030924103916.GH9981@cygbert.vinschen.de> X-SW-Source: 2003-09/txt/msg00579.txt.bz2 Corinna Vinschen writes: > On Tue, Sep 23, 2003 at 04:44:03PM -0400, Elena Zannoni wrote: > > Corinna Vinschen writes: > > And now part 2. > > > > - Add the commands `set calling_convention ' and > > > `show calling_convention' with being one of "gcc" and "renesas". > > > Default to "gcc". > > > > Should be using hyphen, not underscore. What happens if you have a > > Done. I followed Andrew's suggestion to change this to > > set sh calling-convention ... > show sh calling-convention > > > file compiled with renesas ABI but you set the calling convention to > > the gcc (or vice versa)? How are the abi supported by gcc? Is there a > > -with-abi-renesas to be given when one compiles the tests? I.e. is it > > possible to run the testsuite with the one specific abi? > > Currently there's no way to differ between these two ABIs automatically > though that might change at some later point. The user has to change > the ABI on the command line by hand. The compiler option was -mhitachi, > gcc is just changing to -mrenesas to reflect the company name change. Hmm but then the user can set the calling convention to the wrong one. Also the finish command, I am afraid, will be confused. There should be something detecting the calling convention from the executable. Is the info recorded in the file anywhere? I.e. would readelf/objdump show it? > > So the changes introduced with this patch are: > > - Differ between a fpu and a nofpu version of sh_use_struct_convention. > The nofpu version behaves like the fpu version, except that it uses > struct convention also for all types >= 8 bytes when the Renesas ABI > is active. This especially affects long longs and doubles which are > then passed on the stack. > > - The Renesas ABI passes the address in which structs have to be returned > not in r2 as the gcc ABI, but instead this return address is pushed > onto the stack after all arguments have been pushed. This affects > sh_extract_struct_value_address() as well as the sh_push_dummy_call*() > functions. > > - sh_next_flt_argreg() now also takes the ABI into account. The differences > are: > > - In Renesas ABI, the criss-crossing register usage in little endian > mode for doubles doesn't happen. > > - In both ABIs doubles are passed in even register pairs, fr4/fr5, > fr6/fr7, ... The difference is when a register is skipped to pass > the next double. Example: > > void foo(float a, double b, float c); > > In gcc ABI, a is passed in fr4, b then skips the odd-numbered fr5 > register, so it's passed in fr6/fr7 and c is then passed in the next > free register, fr8. > > In Renesas ABI, a is passed in fr4, b is passed as in gcc ABI in > fr6/fr7 but c is passed in the lowest unused register, in this example > in fr5. > > - In the Renesas ABI for CPUs with FPU, long longs are not passed in > registers but on stack. > > - The struct_return code in both sh_push_dummy_call*() functions is moved > to the end of the function since it must be done after the argument > passing for the Rensas ABI. > > - `pass_on_stack' takes the Renesas ABI into account: > > - On FPU CPUs, Renesas ABI passes long longs always on the stack. > > - On non-FPU CPUs, Renesas ABI passes doubles and long doubles always > on the stack. > These descriptions should be comments in the file, the more verbiage the better. I don't have anything in particular against these patches, but I'd like to have a better idea about how to solve this calling convention issue before the changes go in. elena > Corinna > > > ChangeLog: > ========== > > * sh-tdep.c (sh_cc_gcc): New static string. > (sh_cc_renesas): Ditto. > (sh_cc_enum): New array pointing to calling convention strings. > (sh_active_calling_convention): New variable pointing to > current active calling convention. > (sh_use_struct_convention_fpu): New function. > (sh_use_struct_convention_nofpu): New function. > (sh_use_struct_convention): Remove. Superseeded by the previous > two functions. > (sh_extract_struct_value_address): Care for Renesas ABI. > (sh_next_flt_argreg): Accomodate Renesas ABI. > (sh_push_dummy_call_fpu): Ditto. > (sh_push_dummy_call_nofpu): Ditto. > (sh_gdbarch_init): Accomodate new sh_use_struct_convention_fpu and > sh_use_struct_convention_nofpu functions. > (show_sh_command): New function. > (set_sh_command): New function. > (_initialize_sh_tdep): Initialize new "set sh calling-convention", > "show sh calling-convention" commands. > > --- sh-tdep.c.MIDNEW 2003-09-24 12:01:46.000000000 +0200 > +++ sh-tdep.c.NEW 2003-09-24 12:24:10.000000000 +0200 > @@ -55,6 +55,21 @@ > /* registers numbers shared with the simulator */ > #include "gdb/sim-sh.h" > > +/* List of "set sh ..." and "show sh ..." commands. */ > +static struct cmd_list_element *setshcmdlist = NULL; > +static struct cmd_list_element *showshcmdlist = NULL; > + > +static const char sh_cc_gcc[] = "gcc"; > +static const char sh_cc_renesas[] = "renesas"; > +static const char *sh_cc_enum[] = > +{ > + sh_cc_gcc, > + sh_cc_renesas, > + NULL > +}; > + > +static const char *sh_active_calling_convention = sh_cc_gcc; > + > static void (*sh_show_regs) (void); > > #define SH_NUM_REGS 59 > @@ -569,10 +584,25 @@ sh_skip_prologue (CORE_ADDR start_pc) > > /* Should call_function allocate stack space for a struct return? */ > static int > -sh_use_struct_convention (int gcc_p, struct type *type) > +sh_use_struct_convention_fpu (int gcc_p, struct type *type) > { > int len = TYPE_LENGTH (type); > int nelem = TYPE_NFIELDS (type); > + > + return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) && > + (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4); > +} > + > +static int > +sh_use_struct_convention_nofpu (int gcc_p, struct type *type) > +{ > + int len = TYPE_LENGTH (type); > + int nelem = TYPE_NFIELDS (type); > + > + /* The Renesas ABI returns long longs/doubles etc. always on stack. */ > + if (sh_active_calling_convention == sh_cc_renesas && len >= 8) > + return 1; > + > return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) && > (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4); > } > @@ -584,8 +614,13 @@ static CORE_ADDR > sh_extract_struct_value_address (struct regcache *regcache) > { > ULONGEST addr; > - > - regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr); > + if (sh_active_calling_convention != sh_cc_renesas) > + regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr); > + else > + { > + regcache_cooked_read_unsigned (regcache, SP_REGNUM, &addr); > + addr = read_memory_unsigned_integer (addr, 4); > + } > return addr; > } > > @@ -653,7 +688,7 @@ sh_justify_value_in_reg (struct value *v > { > static char valbuf[4]; > > - memset (valbuf, 0, sizeof (valbuf)); > + memset (valbuf, 0, sizeof (valbuf)); > if (len < 4) > { > /* value gets right-justified in the register or stack word */ > @@ -664,7 +699,7 @@ sh_justify_value_in_reg (struct value *v > return valbuf; > } > return (char *) VALUE_CONTENTS (val); > -} > +} > > /* Helper function to eval number of bytes to allocate on stack. */ > static CORE_ADDR > @@ -718,18 +753,22 @@ sh_next_flt_argreg (int len) > /* Doubles are always starting in a even register number. */ > if (argreg & 1) > { > - flt_argreg_array[argreg] = 1; > + /* In gcc ABI, the skipped register is lost for further argument > + passing now. Not so in Renesas ABI. */ > + if (sh_active_calling_convention != sh_cc_renesas) > + flt_argreg_array[argreg] = 1; > > ++argreg; > > - /* No register left? */ > + /* No register left? */ > if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM) > return FLOAT_ARGLAST_REGNUM + 1; > } > /* Also mark the next register as used. */ > flt_argreg_array[argreg + 1] = 1; > } > - else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE) > + else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE > + && sh_active_calling_convention != sh_cc_renesas) > { > /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */ > if (!flt_argreg_array[argreg + 1]) > @@ -761,13 +800,6 @@ sh_push_dummy_call_fpu (struct 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); > - > /* make room on stack for args */ > sp -= sh_stack_allocsize (nargs, args); > > @@ -787,7 +819,10 @@ sh_push_dummy_call_fpu (struct gdbarch * > This also differs in different ABIs. */ > pass_on_stack = 0; > if (len > 16) > - pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */ > + pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */ > + else if (sh_active_calling_convention == sh_cc_renesas > + && TYPE_CODE (type) == TYPE_CODE_INT && len == 8) > + pass_on_stack = 1; /* So are long longs in renesas ABI */ > > /* Find out the next register to use for a floating point value. */ > if (TYPE_CODE (type) == TYPE_CODE_FLT) > @@ -796,10 +831,10 @@ sh_push_dummy_call_fpu (struct gdbarch * > while (len > 0) > { > if ((TYPE_CODE (type) == TYPE_CODE_FLT > - && flt_argreg > FLOAT_ARGLAST_REGNUM) > + && flt_argreg > FLOAT_ARGLAST_REGNUM) > || argreg > ARGLAST_REGNUM > || pass_on_stack) > - { > + { > write_memory (sp + stack_offset, val, 4); > stack_offset += 4; > } > @@ -812,7 +847,7 @@ sh_push_dummy_call_fpu (struct gdbarch * > regcache_cooked_write_unsigned (regcache, flt_argreg++, regval); > } > else if (argreg <= ARGLAST_REGNUM) > - { > + { > /* there's room in a register */ > regval = extract_unsigned_integer (val, register_size (gdbarch, > argreg)); > @@ -826,6 +861,20 @@ sh_push_dummy_call_fpu (struct gdbarch * > } > } > > + if (struct_return) > + { > + if (sh_active_calling_convention != sh_cc_renesas) > + /* Using the gcc ABI, the "struct return pointer" pseudo-argument has > + its own dedicated register */ > + regcache_cooked_write_unsigned (regcache, > + STRUCT_RETURN_REGNUM, > + struct_addr); > + else > + /* If the function uses the renesas ABI, subtract another 4 bytes from > + the stack and store the struct return address there. */ > + write_memory_unsigned_integer (sp -= 4, 4, struct_addr); > + } > + > /* Store return address. */ > regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr); > > @@ -851,17 +900,11 @@ sh_push_dummy_call_nofpu (struct gdbarch > CORE_ADDR regval; > char *val; > int len; > + int pass_on_stack; > > /* 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); > - > /* make room on stack for args */ > sp -= sh_stack_allocsize (nargs, args); > > @@ -869,20 +912,27 @@ sh_push_dummy_call_nofpu (struct gdbarch > registers, and push the rest onto the stack. There are 16 bytes > in four registers available. Loop thru args from first to last. */ > for (argnum = 0; argnum < nargs; argnum++) > - { > + { > type = VALUE_TYPE (args[argnum]); > len = TYPE_LENGTH (type); > val = sh_justify_value_in_reg (args[argnum], len); > > + /* Some decisions have to be made how various types are handled. > + This also differs in different ABIs. */ > + pass_on_stack = 0; > + if (TYPE_CODE (type) == TYPE_CODE_FLT && len > 4 > + && sh_active_calling_convention == sh_cc_renesas) > + pass_on_stack = 1; /* Renesas ABI pushes doubles entirely on stack. */ > + > while (len > 0) > { > - if (argreg > ARGLAST_REGNUM) > - { > + if (argreg > ARGLAST_REGNUM || pass_on_stack) > + { > write_memory (sp + stack_offset, val, 4); > - stack_offset += 4; > + stack_offset += 4; > } > else if (argreg <= ARGLAST_REGNUM) > - { > + { > /* there's room in a register */ > regval = extract_unsigned_integer (val, register_size (gdbarch, > argreg)); > @@ -896,6 +946,20 @@ sh_push_dummy_call_nofpu (struct gdbarch > } > } > > + if (struct_return) > + { > + if (sh_active_calling_convention != sh_cc_renesas) > + /* Using the gcc ABI, the "struct return pointer" pseudo-argument has > + its own dedicated register */ > + regcache_cooked_write_unsigned (regcache, > + STRUCT_RETURN_REGNUM, > + struct_addr); > + else > + /* If the function uses the renesas ABI, subtract another 4 bytes from > + the stack and store the struct return address there. */ > + write_memory_unsigned_integer (sp -= 4, 4, struct_addr); > + } > + > /* Store return address. */ > regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr); > > @@ -2115,7 +2179,6 @@ sh_gdbarch_init (struct gdbarch_info inf > set_gdbarch_print_registers_info (gdbarch, sh_print_registers_info); > > set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc); > - set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention); > > set_gdbarch_print_insn (gdbarch, gdb_print_insn_sh); > set_gdbarch_register_sim_regno (gdbarch, legacy_register_sim_regno); > @@ -2134,6 +2197,7 @@ sh_gdbarch_init (struct gdbarch_info inf > > set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code); > set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu); > + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_nofpu); > > set_gdbarch_frame_args_skip (gdbarch, 0); > set_gdbarch_frameless_function_invocation (gdbarch, > @@ -2169,6 +2233,7 @@ sh_gdbarch_init (struct gdbarch_info inf > 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_use_struct_convention (gdbarch, sh_use_struct_convention_fpu); > break; > > case bfd_mach_sh_dsp: > @@ -2190,6 +2255,7 @@ sh_gdbarch_init (struct gdbarch_info inf > 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_use_struct_convention (gdbarch, sh_use_struct_convention_fpu); > break; > > case bfd_mach_sh3_dsp: > @@ -2207,6 +2273,7 @@ sh_gdbarch_init (struct gdbarch_info inf > 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_use_struct_convention (gdbarch, sh_use_struct_convention_fpu); > break; > > default: > @@ -2223,6 +2290,19 @@ sh_gdbarch_init (struct gdbarch_info inf > return gdbarch; > } > > +static void > +show_sh_command (char *args, int from_tty) > +{ > + help_list (showshcmdlist, "show sh ", all_commands, gdb_stdout); > +} > + > +static void > +set_sh_command (char *args, int from_tty) > +{ > + printf_unfiltered ("\"set sh\" must be followed by an appropriate subcommand.\n"); > + help_list (setshcmdlist, "set sh ", all_commands, gdb_stdout); > +} > + > extern initialize_file_ftype _initialize_sh_tdep; /* -Wmissing-prototypes */ > > void > @@ -2233,4 +2313,16 @@ _initialize_sh_tdep (void) > gdbarch_register (bfd_arch_sh, sh_gdbarch_init, NULL); > > add_com ("regs", class_vars, sh_show_regs_command, "Print all registers"); > + > + add_prefix_cmd ("sh", no_class, set_sh_command, "SH specific commands.", > + &setshcmdlist, "set sh ", 0, &setlist); > + add_prefix_cmd ("sh", no_class, show_sh_command, "SH specific commands.", > + &showshcmdlist, "show sh ", 0, &showlist); > + > + add_show_from_set ( > + add_set_enum_cmd ("calling-convention", class_vars, sh_cc_enum, > + &sh_active_calling_convention, > + "Set calling convention used when calling target " > + "functions from GDB.", > + &setshcmdlist), &showshcmdlist); > } > > -- > Corinna Vinschen > Cygwin Developer > Red Hat, Inc.