From: Daniel Jacobowitz Date: Wed, 22 Aug 2007 15:13:04 +0000 (+0000) Subject: gdb/testsuite/ X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8d26208a1e22d9720c1423625c7e15f1bc7d237c;p=binutils-gdb.git gdb/testsuite/ * gdb.base/callfuncs.exp (do_function_calls): Use t_double_int and t_int_double. * gdb.base/callfuncs.c (t_double_int, t_int_double): New. gdb/ * mips-tdep.c (mips_n32n64_fp_arg_chunk_p): New. (mips_n32n64_push_dummy_call): Always increment float_argreg along with argreg. Use mips_n32n64_fp_arg_chunk_p. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 17adcac4c02..cde1d095db8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2007-08-22 Daniel Jacobowitz + + * mips-tdep.c (mips_n32n64_fp_arg_chunk_p): New. + (mips_n32n64_push_dummy_call): Always increment float_argreg along + with argreg. Use mips_n32n64_fp_arg_chunk_p. + 2007-08-22 Daniel Jacobowitz * solib-svr4.c (scan_dyntag): Only read target memory when necessary. diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 531d93610bf..68621e1c40b 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -2781,6 +2781,59 @@ mips_eabi_return_value (struct gdbarch *gdbarch, /* N32/N64 ABI stuff. */ +/* Search for a naturally aligned double at OFFSET inside a struct + ARG_TYPE. The N32 / N64 ABIs pass these in floating point + registers. */ + +static int +mips_n32n64_fp_arg_chunk_p (struct type *arg_type, int offset) +{ + int i; + + if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT) + return 0; + + if (MIPS_FPU_TYPE != MIPS_FPU_DOUBLE) + return 0; + + if (TYPE_LENGTH (arg_type) < offset + MIPS64_REGSIZE) + return 0; + + for (i = 0; i < TYPE_NFIELDS (arg_type); i++) + { + int pos; + struct type *field_type; + + /* We're only looking at normal fields. */ + if (TYPE_FIELD_STATIC (arg_type, i) + || (TYPE_FIELD_BITPOS (arg_type, i) % 8) != 0) + continue; + + /* If we have gone past the offset, there is no double to pass. */ + pos = TYPE_FIELD_BITPOS (arg_type, i) / 8; + if (pos > offset) + return 0; + + field_type = check_typedef (TYPE_FIELD_TYPE (arg_type, i)); + + /* If this field is entirely before the requested offset, go + on to the next one. */ + if (pos + TYPE_LENGTH (field_type) <= offset) + continue; + + /* If this is our special aligned double, we can stop. */ + if (TYPE_CODE (field_type) == TYPE_CODE_FLT + && TYPE_LENGTH (field_type) == MIPS64_REGSIZE) + return 1; + + /* This field starts at or before the requested offset, and + overlaps it. If it is a structure, recurse inwards. */ + return mips_n32n64_fp_arg_chunk_p (field_type, offset - pos); + } + + return 0; +} + static CORE_ADDR mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, @@ -2855,23 +2908,22 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, val = value_contents (arg); if (fp_register_arg_p (typecode, arg_type) - && float_argreg <= MIPS_LAST_FP_ARG_REGNUM) + && argreg <= MIPS_LAST_ARG_REGNUM) { /* This is a floating point value that fits entirely in a single register. */ - /* On 32 bit ABI's the float_argreg is further adjusted - above to ensure that it is even register aligned. */ LONGEST regval = extract_unsigned_integer (val, len); if (mips_debug) fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s", float_argreg, phex (regval, len)); - regcache_cooked_write_unsigned (regcache, float_argreg++, regval); + regcache_cooked_write_unsigned (regcache, float_argreg, regval); if (mips_debug) fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s", argreg, phex (regval, len)); regcache_cooked_write_unsigned (regcache, argreg, regval); - argreg += 1; + float_argreg++; + argreg++; } else { @@ -2896,10 +2948,12 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, fprintf_unfiltered (gdb_stdlog, " -- partial=%d", partial_len); + if (fp_register_arg_p (typecode, arg_type)) + gdb_assert (argreg > MIPS_LAST_ARG_REGNUM); + /* Write this portion of the argument to the stack. */ if (argreg > MIPS_LAST_ARG_REGNUM - || odd_sized_struct - || fp_register_arg_p (typecode, arg_type)) + || odd_sized_struct) { /* Should shorter than int integer values be promoted to int before being stored? */ @@ -2940,12 +2994,10 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } /* Note!!! This is NOT an else clause. Odd sized - structs may go thru BOTH paths. Floating point - arguments will not. */ + structs may go thru BOTH paths. */ /* Write this portion of the argument to a general purpose register. */ - if (argreg <= MIPS_LAST_ARG_REGNUM - && !fp_register_arg_p (typecode, arg_type)) + if (argreg <= MIPS_LAST_ARG_REGNUM) { LONGEST regval = extract_unsigned_integer (val, partial_len); @@ -2971,6 +3023,19 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, argreg, phex (regval, MIPS64_REGSIZE)); regcache_cooked_write_unsigned (regcache, argreg, regval); + + if (mips_n32n64_fp_arg_chunk_p (arg_type, + TYPE_LENGTH (arg_type) - len)) + { + if (mips_debug) + fprintf_filtered (gdb_stdlog, " - fpreg=%d val=%s", + float_argreg, + phex (regval, MIPS64_REGSIZE)); + regcache_cooked_write_unsigned (regcache, float_argreg, + regval); + } + + float_argreg++; argreg++; } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 8f95b3ff2ec..89b7a1086fc 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2007-08-22 Daniel Jacobowitz + + * gdb.base/callfuncs.exp (do_function_calls): Use t_double_int + and t_int_double. + * gdb.base/callfuncs.c (t_double_int, t_int_double): New. + 2007-08-17 Joel Brobecker * gdb.base/step-line.c: Switch license to GPL version 3, and diff --git a/gdb/testsuite/gdb.base/callfuncs.c b/gdb/testsuite/gdb.base/callfuncs.c index 5a2bde2b38e..3eeebe57acf 100644 --- a/gdb/testsuite/gdb.base/callfuncs.c +++ b/gdb/testsuite/gdb.base/callfuncs.c @@ -334,6 +334,29 @@ char char_array_arg1[], char_array_arg2[]; !strcmp (char_array_arg2, char_array_val2)); } +#ifdef PROTOTYPES +int t_double_int (double double_arg1, int int_arg2) +#else +int t_double_int (double_arg1, int_arg2) +double double_arg1; +int int_arg2; +#endif +{ + return ((double_arg1 - int_arg2) < DELTA + && (double_arg1 - int_arg2) > -DELTA); +} + +#ifdef PROTOTYPES +int t_int_double (int int_arg1, double double_arg2) +#else +int t_int_double (int_arg1, double_arg2) +int int_arg1; +double double_arg2; +#endif +{ + return ((int_arg1 - double_arg2) < DELTA + && (int_arg1 - double_arg2) > -DELTA); +} /* This used to simply compare the function pointer arguments with known values for func_val1 and func_val2. Doing so is valid ANSI diff --git a/gdb/testsuite/gdb.base/callfuncs.exp b/gdb/testsuite/gdb.base/callfuncs.exp index 6839abfa3cf..7d53e98714e 100644 --- a/gdb/testsuite/gdb.base/callfuncs.exp +++ b/gdb/testsuite/gdb.base/callfuncs.exp @@ -163,6 +163,11 @@ proc do_function_calls {} { gdb_test "p t_double_values(double_val1,double_val2)" " = 1" 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_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" + gdb_test "p t_int_double(99, 99.0)" " = 1" } gdb_test "p t_string_values(string_val2,string_val1)" " = 0"