From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27246 invoked by alias); 15 Jan 2008 12:34:52 -0000 Received: (qmail 27230 invoked by uid 22791); 15 Jan 2008 12:34:51 -0000 X-Spam-Check-By: sourceware.org Received: from igw1.br.ibm.com (HELO igw1.br.ibm.com) (32.104.18.24) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 15 Jan 2008 12:34:05 +0000 Received: from mailhub3.br.ibm.com (mailhub3 [9.18.232.110]) by igw1.br.ibm.com (Postfix) with ESMTP id 084EA32C10C for ; Tue, 15 Jan 2008 10:12:59 -0200 (BRDT) Received: from d24av01.br.ibm.com (d24av01.br.ibm.com [9.18.232.46]) by mailhub3.br.ibm.com (8.13.8/8.13.8/NCO v8.7) with ESMTP id m0FCY1GK4300870 for ; Tue, 15 Jan 2008 10:34:01 -0200 Received: from d24av01.br.ibm.com (loopback [127.0.0.1]) by d24av01.br.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id m0FCXvMg015383 for ; Tue, 15 Jan 2008 10:33:57 -0200 Received: from [9.18.246.194] ([9.18.246.194]) by d24av01.br.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id m0FCXsUn015304 for ; Tue, 15 Jan 2008 10:33:54 -0200 Subject: [RFA] Fix float argument passing in inferior function calls for ppc64 From: Thiago Jung Bauermann To: gdb-patches Content-Type: multipart/mixed; boundary="=-l7TalYgv4STurkmPcq3m" Date: Tue, 15 Jan 2008 12:34:00 -0000 Message-Id: <1200400434.3158.64.camel@localhost.localdomain> Mime-Version: 1.0 X-Mailer: Evolution 2.12.2 X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-01/txt/msg00347.txt.bz2 --=-l7TalYgv4STurkmPcq3m Content-Type: text/plain Content-Transfer-Encoding: 7bit Content-length: 1416 Hi, The 64-bit PowerPC ELF ABI version 1.9 says that "single precision floating point values are mapped to the second word in a single doubleword". The ppc64_sysv_abi_push_dummy_call function in ppc-sysv-tdep.c, however, implements version 1.7 of the ABI which says that they should go in the first doubleword. Because of this, if you are calling a function with many arguments and some need to be passed on the stack, GDB will get it wrong for 32-bit floats. This is why in Linux/ppc64 GDB fails the "Call function with many float arguments" test posted here: http://sourceware.org/ml/gdb-patches/2008-01/msg00291.html This patch fixes the test. It makes GDB pass 32-bit floats in the second word when passing them in the stack as stated in the current ABI. I didn't touch the code which writes the float to a general register in the first word because I'm not sure how to test it. It is probably related to soft-float, I guess. Tested on Linux/ppc64 with no regressions. I believe this will also fix other operating systems supported by GDB on ppc64 since they use the same push_dummy_call implementation (assuming they also follow the current SysV ABI), but I don't have the means to test them either. Maybe someone could test the patch and the testcase in *BSD? Luis' patch which has the testcases would also need this testing. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center --=-l7TalYgv4STurkmPcq3m Content-Disposition: attachment; filename=ppc64-abi-float-fix.diff Content-Type: text/x-patch; name=ppc64-abi-float-fix.diff; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-length: 8324 2008-01-14 Thiago Jung Bauermann * ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): Use 64-bit slot to pass 32-bit float argument when writing it on the stack. Map it to second word in the doubleword. diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c index 9238f26..e993d1b 100644 --- a/gdb/ppc-sysv-tdep.c +++ b/gdb/ppc-sysv-tdep.c @@ -829,6 +829,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct value *arg = args[argno]; struct type *type = check_typedef (value_type (arg)); const bfd_byte *val = value_contents (arg); + if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8) { /* Floats and Doubles go in f1 .. f13. They also @@ -836,11 +837,14 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, memory. */ if (write_pass) { + gdb_byte regval[MAX_REGISTER_SIZE]; + const gdb_byte *p; + if (freg <= 13) { - gdb_byte regval[MAX_REGISTER_SIZE]; struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum); + convert_typed_floating (val, type, regval, regtype); regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, @@ -856,20 +860,35 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, general registers"). This code interprets that to mean: store it, - left aligned, in the general register. */ - gdb_byte regval[MAX_REGISTER_SIZE]; + left aligned, in the general register. + + NOTE: This was true in version 1.7 of the ABI, + but it is not in version 1.9. */ memset (regval, 0, sizeof regval); memcpy (regval, val, TYPE_LENGTH (type)); regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval); } - write_memory (gparam, val, TYPE_LENGTH (type)); + + /* "Single precision floating point values are mapped to + the second word in a single doubleword." + - 64-bit PowerPC ELF ABI version 1.9, page 16. */ + if (TYPE_LENGTH (type) == 4) + { + memcpy (regval + 4, val, 4); + p = regval; + } + else + p = val; + + write_memory (gparam, p, 8); } - /* Always consume parameter stack space. */ + freg++; greg++; - gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); + /* Always consume parameter stack space. */ + gparam = align_up (gparam + 8, tdep->wordsize); } else if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 16 diff --git a/gdb/testsuite/gdb.base/callfuncs.c b/gdb/testsuite/gdb.base/callfuncs.c index 4903868..d546051 100644 --- a/gdb/testsuite/gdb.base/callfuncs.c +++ b/gdb/testsuite/gdb.base/callfuncs.c @@ -46,9 +46,35 @@ long long_val2 = -321; float float_val1 = 3.14159; float float_val2 = -2.3765; +float float_val3 = 0.25; +float float_val4 = 1.25; +float float_val5 = 2.25; +float float_val6 = 3.25; +float float_val7 = 4.25; +float float_val8 = 5.25; +float float_val9 = 6.25; +float float_val10 = 7.25; +float float_val11 = 8.25; +float float_val12 = 9.25; +float float_val13 = 10.25; +float float_val14 = 11.25; +float float_val15 = 12.25; double double_val1 = 45.654; double double_val2 = -67.66; +double double_val3 = 0.25; +double double_val4 = 1.25; +double double_val5 = 2.25; +double double_val6 = 3.25; +double double_val7 = 4.25; +double double_val8 = 5.25; +double double_val9 = 6.25; +double double_val10 = 7.25; +double double_val11 = 8.25; +double double_val12 = 9.25; +double double_val13 = 10.25; +double double_val14 = 11.25; +double double_val15 = 12.25; #define DELTA (0.001) @@ -298,6 +324,39 @@ t_float_values2 (float float_arg1, float float_arg2) && (float_arg2 - float_val2) > -DELTA); } +/* This function has many arguments to force some of them to be passed via + the stack instead of registers, to test that GDB can construct correctly + the parameter save area. Note that Linux/ppc32 has 8 float registers to use + for float parameter passing and Linux/ppc64 has 13, so the number of + arguments has to be at least 14 to contemplate these platforms. */ + +float +#ifdef NO_PROTOTYPES +t_float_many_args (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, + f14, f15) + float f1, float f2, float f3, float f4, float f5, float f6, float f7, + float f8, float f9, float f10, float f11, float f12, float f13, float f14, + float f15; +#else +t_float_many_args (float f1, float f2, float f3, float f4, float f5, float f6, + float f7, float f8, float f9, float f10, float f11, + float f12, float f13, float f14, float f15) +#endif +{ + float sum_args; + float sum_values; + + sum_args = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + + f13 + f14 + f15; + sum_values = float_val1 + float_val2 + float_val3 + float_val4 + float_val5 + + float_val6 + float_val7 + float_val8 + float_val9 + + float_val10 + float_val11 + float_val12 + float_val13 + + float_val14 + float_val15; + + return ((sum_args - sum_values) < DELTA + && (sum_args - sum_values) > -DELTA); +} + #ifdef PROTOTYPES int t_double_values (double double_arg1, double double_arg2) #else @@ -311,6 +370,39 @@ double double_arg1, double_arg2; && (double_arg2 - double_val2) > -DELTA); } +/* This function has many arguments to force some of them to be passed via + the stack instead of registers, to test that GDB can construct correctly + the parameter save area. Note that Linux/ppc32 has 8 float registers to use + for float parameter passing and Linux/ppc64 has 13, so the number of + arguments has to be at least 14 to contemplate these platforms. */ + +double +#ifdef NO_PROTOTYPES +t_double_many_args (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, + f14, f15) + double f1, double f2, double f3, double f4, double f5, double f6, + double f7, double f8, double f9, double f10, double f11, double f12, + double f13, double f14, double f15; +#else +t_double_many_args (double f1, double f2, double f3, double f4, double f5, + double f6, double f7, double f8, double f9, double f10, + double f11, double f12, double f13, double f14, double f15) +#endif +{ + double sum_args; + double sum_values; + + sum_args = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + + f13 + f14 + f15; + sum_values = double_val1 + double_val2 + double_val3 + double_val4 + + double_val5 + double_val6 + double_val7 + double_val8 + + double_val9 + double_val10 + double_val11 + double_val12 + + double_val13 + double_val14 + double_val15; + + return ((sum_args - sum_values) < DELTA + && (sum_args - sum_values) > -DELTA); +} + #ifdef PROTOTYPES int t_string_values (char *string_arg1, char *string_arg2) #else diff --git a/gdb/testsuite/gdb.base/callfuncs.exp b/gdb/testsuite/gdb.base/callfuncs.exp index 7f605fd..6b53d82 100644 --- a/gdb/testsuite/gdb.base/callfuncs.exp +++ b/gdb/testsuite/gdb.base/callfuncs.exp @@ -155,6 +155,8 @@ proc do_function_calls {} { gdb_test "p t_float_values2(3.14159,float_val2)" " = 1" + gdb_test "p t_float_many_args (float_val1, float_val2, float_val3, float_val4, float_val5, float_val6, float_val7, float_val8, float_val9, float_val10, float_val11, float_val12, float_val13, float_val14, float_val15)" " = 1" "Call function with many float arguments." + gdb_test "p t_small_values(1,2,3,4,5,6,7,8,9,10)" " = 55" gdb_test "p t_double_values(0.0,0.0)" " = 0" @@ -163,6 +165,8 @@ proc do_function_calls {} { gdb_test "p t_double_values(45.654,double_val2)" " = 1" gdb_test "p t_double_values(double_val1,-67.66)" " = 1" + gdb_test "p t_double_many_args (double_val1, double_val2, double_val3, double_val4, double_val5, double_val6, double_val7, double_val8, double_val9, double_val10, double_val11, double_val12, double_val13, double_val14, double_val15)" " = 1" "Call function with many double arguments." + gdb_test "p t_double_int(99.0, 1)" " = 0" gdb_test "p t_double_int(99.0, 99)" " = 1" gdb_test "p t_int_double(99, 1.0)" " = 0" --=-l7TalYgv4STurkmPcq3m--