From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4977 invoked by alias); 24 Sep 2003 10:39:30 -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 4970 invoked from network); 24 Sep 2003 10:39:28 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 24 Sep 2003 10:39:28 -0000 Received: from int-mx2.corp.redhat.com (nat-pool-rdu-dmz.redhat.com [172.16.52.200]) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id h8OAdQ122261 for ; Wed, 24 Sep 2003 06:39: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 h8OAdOD16811 for ; Wed, 24 Sep 2003 06:39:25 -0400 Received: from cygbert.vinschen.de (vpn50-8.rdu.redhat.com [172.16.50.8]) by potter.sfbay.redhat.com (8.11.6/8.11.6) with ESMTP id h8OAdMw01628 for ; Wed, 24 Sep 2003 03:39:22 -0700 Received: by cygbert.vinschen.de (Postfix, from userid 500) id EE407580A8; Wed, 24 Sep 2003 12:39:16 +0200 (CEST) Date: Wed, 24 Sep 2003 10:39:00 -0000 From: Corinna Vinschen To: gdb-patches@sources.redhat.com Subject: SH follow up, part 2 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs) Message-ID: <20030924103916.GH9981@cygbert.vinschen.de> Reply-To: gdb-patches@sources.redhat.com Mail-Followup-To: gdb-patches@sources.redhat.com References: <20030917161127.GM9981@cygbert.vinschen.de> <16240.45203.260059.116019@localhost.redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <16240.45203.260059.116019@localhost.redhat.com> User-Agent: Mutt/1.4.1i X-SW-Source: 2003-09/txt/msg00524.txt.bz2 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. 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. 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.