From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15076 invoked by alias); 4 Oct 2003 12:11:12 -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 15069 invoked from network); 4 Oct 2003 12:11:11 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 4 Oct 2003 12:11:11 -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 h94CBA110674 for ; Sat, 4 Oct 2003 08:11:10 -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 h94CB9D11297 for ; Sat, 4 Oct 2003 08:11:09 -0400 Received: from cygbert.vinschen.de (vpn50-13.rdu.redhat.com [172.16.50.13]) by potter.sfbay.redhat.com (8.11.6/8.11.6) with ESMTP id h94CB7w02630 for ; Sat, 4 Oct 2003 05:11:08 -0700 Received: by cygbert.vinschen.de (Postfix, from userid 500) id 6E21258044; Sat, 4 Oct 2003 14:11:02 +0200 (CEST) Date: Sat, 04 Oct 2003 12:11:00 -0000 From: Corinna Vinschen To: gdb-patches@sources.redhat.com Subject: [RFA] sh-tdep.c: Fix float handling Message-ID: <20031004121102.GL11435@cygbert.vinschen.de> Reply-To: gdb-patches@sources.redhat.com Mail-Followup-To: gdb-patches@sources.redhat.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.1i X-SW-Source: 2003-10/txt/msg00077.txt.bz2 Hi, the below patch solves a problem which was unfortunately hidden by using the sh-hms-sim.exp baseboard file. Removing the following line from dejagnu/baseboards/sh-hms-sim.exp: set_board_info gdb,cannot_call_functions 1 uncovered that the current implementation doesn't get the ABI of floating point CPUs (sh2e, sh3e, sh4) right. First, in contrast to non-FPU CPUs, arguments are never split between registers and stack. If an argument doesn't fit in the remaining registers it's always pushed entirely on the stack. My testing led me to the wrong assumption that just types > 16 bytes are pushed entirely on the stack. Second, the FPU ABIs have a special way how to treat types as float types. Structures with exactly one member, which is of type float or double, are treated exactly as the base types float or double: struct sf { float f; }; struct sd { double d; }; are handled the same way as just float f; double d; As a result, arguments of these struct types are pushed into floating point registers exactly as floats or doubles, using the same decision algorithm. The same is valid if these types are used as function return types. The above structs are returned in fr0 resp. fr0,fr1 instead of in r0, r0,r1 or even using struct convention as it is for other structs. The below patch fixes this by adding a helper function sh_treat_as_flt(), which evaluates if a type is treated as float type. The result of this function is then used in sh_push_dummy_call_fpu(), sh3e_sh4_extract_return_value() and sh3e_sh4_store_return_value() to push resp. return these structs correctly. Over all, including the sh_use_struct_convention patch send 20 minutes ago the FAIL count is lowered by 1 FAIL on non-FPU ABIs and 5 FAILs on FPU ABIs, but that's only visible when tweaking sh-hms-sim.exp appropriately. Corinna * sh-tdep.c (sh_treat_as_flt): New function to recognize float types correctly. (sh_push_dummy_call_fpu): Fix argument passing rules. (sh3e_sh4_extract_return_value): Call sh_treat_as_flt to recognize float types. (sh3e_sh4_store_return_value): Ditto. Index: sh-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/sh-tdep.c,v retrieving revision 1.145 diff -u -p -r1.145 sh-tdep.c --- sh-tdep.c 3 Oct 2003 08:13:37 -0000 1.145 +++ sh-tdep.c 4 Oct 2003 11:32:00 -0000 @@ -732,6 +749,33 @@ sh_next_flt_argreg (int len) return FLOAT_ARG0_REGNUM + argreg; } +/* Helper function which figures out, if a type is treated like a float type. + The FPU based calling conventions (sh2e, sh3e, sh4, ...) are handling + structs with exactly one member, which is of type float or double the same + way as a simple float or double. That determines if such data is passed + in float or general registers both, as argument or as return value. */ +static int +sh_treat_as_flt (struct type *type) +{ + int len = TYPE_LENGTH (type); + + /* Ordinary float types are obviously treated as float. */ + if (TYPE_CODE (type) == TYPE_CODE_FLT) + return 1; + /* Otherwise non-struct types are not treated as float. */ + if (TYPE_CODE (type) != TYPE_CODE_STRUCT) + return 0; + /* Otherwise structs with more than one memeber are not treated as float. */ + if (TYPE_NFIELDS (type) != 1) + return 0; + /* Otherwise if the type of that member is float, the whole type is + treated as float. */ + if (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT) + return 1; + /* Otherwise it's not treated as float. */ + return 0; +} + static CORE_ADDR sh_push_dummy_call_fpu (struct gdbarch *gdbarch, CORE_ADDR func_addr, @@ -749,7 +793,8 @@ sh_push_dummy_call_fpu (struct gdbarch * CORE_ADDR regval; char *val; int len, reg_size = 0; - int pass_on_stack; + int pass_on_stack = 0; + int treat_as_flt; /* first force sp to a 4-byte alignment */ sp = sh_frame_align (gdbarch, sp); @@ -776,43 +821,41 @@ sh_push_dummy_call_fpu (struct gdbarch * /* Some decisions have to be made how various types are handled. 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. */ /* Find out the next register to use for a floating point value. */ - if (TYPE_CODE (type) == TYPE_CODE_FLT) + treat_as_flt = sh_treat_as_flt (type); + if (treat_as_flt) flt_argreg = sh_next_flt_argreg (len); + /* No data is passed partially in registers. */ + else if (len > ((ARGLAST_REGNUM - argreg + 1) * 4)) + pass_on_stack = 1; while (len > 0) { - if ((TYPE_CODE (type) == TYPE_CODE_FLT - && flt_argreg > FLOAT_ARGLAST_REGNUM) - || argreg > ARGLAST_REGNUM || pass_on_stack) + if ((treat_as_flt && flt_argreg > FLOAT_ARGLAST_REGNUM) + || (!treat_as_flt && (argreg > ARGLAST_REGNUM + || pass_on_stack))) { - /* The remainder of the data goes entirely on the stack, - 4-byte aligned. */ + /* The data goes entirely on the stack, 4-byte aligned. */ reg_size = (len + 3) & ~3; write_memory (sp + stack_offset, val, reg_size); stack_offset += reg_size; } - else if (TYPE_CODE (type) == TYPE_CODE_FLT - && flt_argreg <= FLOAT_ARGLAST_REGNUM) + else if (treat_as_flt && flt_argreg <= FLOAT_ARGLAST_REGNUM) { /* Argument goes in a float argument register. */ reg_size = register_size (gdbarch, flt_argreg); regval = extract_unsigned_integer (val, reg_size); regcache_cooked_write_unsigned (regcache, flt_argreg++, regval); } - else if (argreg <= ARGLAST_REGNUM) + else if (!treat_as_flt && argreg <= ARGLAST_REGNUM) { /* there's room in a register */ reg_size = register_size (gdbarch, argreg); regval = extract_unsigned_integer (val, reg_size); regcache_cooked_write_unsigned (regcache, argreg++, regval); } - /* Store the value reg_size bytes at a time. This means that things - larger than reg_size bytes may go partly in registers and partly - on the stack. */ + /* Store the value one register at a time or in one step on stack. */ len -= reg_size; val += reg_size; } @@ -930,7 +973,7 @@ static void sh3e_sh4_extract_return_value (struct type *type, struct regcache *regcache, void *valbuf) { - if (TYPE_CODE (type) == TYPE_CODE_FLT) + if (sh_treat_as_flt (type)) { int len = TYPE_LENGTH (type); int i, regnum = FP0_REGNUM; @@ -971,7 +1014,7 @@ static void sh3e_sh4_store_return_value (struct type *type, struct regcache *regcache, const void *valbuf) { - if (TYPE_CODE (type) == TYPE_CODE_FLT) + if (sh_treat_as_flt (type)) { int len = TYPE_LENGTH (type); int i, regnum = FP0_REGNUM; -- Corinna Vinschen Cygwin Developer Red Hat, Inc.