gdb: mips: Fix the handling of complex type of function return value
authorYouling Tang <tangyouling@loongson.cn>
Wed, 6 Apr 2022 22:38:21 +0000 (23:38 +0100)
committerMaciej W. Rozycki <macro@orcam.me.uk>
Wed, 6 Apr 2022 22:38:21 +0000 (23:38 +0100)
$ objdump -d outputs/gdb.base/varargs/varargs
00000001200012e8 <find_max_float_real>:
...
   1200013b8:   c7c10000        lwc1    $f1,0(s8)
   1200013bc:   c7c00004        lwc1    $f0,4(s8)
   1200013c0:   46000886        mov.s   $f2,$f1
   1200013c4:   46000046        mov.s   $f1,$f0
   1200013c8:   46001006        mov.s   $f0,$f2
   1200013cc:   46000886        mov.s   $f2,$f1
   1200013d0:   03c0e825        move    sp,s8
   1200013d4:   dfbe0038        ld      s8,56(sp)
   1200013d8:   67bd0080        daddiu  sp,sp,128
   1200013dc:   03e00008        jr      ra
   1200013e0:   00000000        nop

From the above disassembly, we can see that when the return value of the
function is a complex type and len <= 2 * MIPS64_REGSIZE, the return value
will be passed through $f0 and $f2, so fix the corresponding processing
in mips_n32n64_return_value().

$ make check RUNTESTFLAGS='GDB=../gdb gdb.base/varargs.exp --outdir=test'

Before applying the patch:
 FAIL: gdb.base/varargs.exp: print find_max_float_real(4, fc1, fc2, fc3, fc4)
 FAIL: gdb.base/varargs.exp: print find_max_double_real(4, dc1, dc2, dc3, dc4)

 # of expected passes            9
 # of unexpected failures        2

After applying the patch:
 # of expected passes            11

This also fixes:
 FAIL: gdb.base/callfuncs.exp: call inferior func with struct - returns float _Complex

Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Co-Authored-By: Maciej W. Rozycki <macro@orcam.me.uk>
gdb/mips-tdep.c

index 93945891407a366faab15d379085c28bea31b10a..4bdbf0fcdb73d9d5b0b536aeab99ce6baad92fed 100644 (file)
@@ -5217,30 +5217,44 @@ mips_n32n64_return_value (struct gdbarch *gdbarch, struct value *function,
      that all composite results be handled by conversion to implicit first
      parameters.  The MIPS/SGI Fortran implementation has always made a
      specific exception to return COMPLEX results in the floating point
-     registers.]  */
+     registers.]
+
+     From MIPSpro Assembly Language Programmer's Guide, Document Number:
+     007-2418-004
+
+              Software
+     Register Name(from
+     Name     fgregdef.h) Use and Linkage
+     -----------------------------------------------------------------
+     $f0, $f2 fv0, fv1    Hold results of floating-point type function
+                          ($f0) and complex type function ($f0 has the
+                          real part, $f2 has the imaginary part.)  */
 
   if (TYPE_LENGTH (type) > 2 * MIPS64_REGSIZE)
     return RETURN_VALUE_STRUCT_CONVENTION;
-  else if (type->code () == TYPE_CODE_FLT
-          && TYPE_LENGTH (type) == 16
+  else if ((type->code () == TYPE_CODE_COMPLEX
+           || (type->code () == TYPE_CODE_FLT && TYPE_LENGTH (type) == 16))
           && tdep->mips_fpu_type != MIPS_FPU_NONE)
     {
-      /* A 128-bit floating-point value fills both $f0 and $f2.  The
-        two registers are used in the same as memory order, so the
-        eight bytes with the lower memory address are in $f0.  */
+      /* A complex value of up to 128 bits in width as well as a 128-bit
+        floating-point value goes in both $f0 and $f2.  A single complex
+        value is held in the lower halves only of the respective registers.
+        The two registers are used in the same as memory order, so the
+        bytes with the lower memory address are in $f0.  */
       if (mips_debug)
        gdb_printf (gdb_stderr, "Return float in $f0 and $f2\n");
       mips_xfer_register (gdbarch, regcache,
                          (gdbarch_num_regs (gdbarch)
                           + mips_regnum (gdbarch)->fp0),
-                         8, gdbarch_byte_order (gdbarch),
+                         TYPE_LENGTH (type) / 2, gdbarch_byte_order (gdbarch),
                          readbuf, writebuf, 0);
       mips_xfer_register (gdbarch, regcache,
                          (gdbarch_num_regs (gdbarch)
                           + mips_regnum (gdbarch)->fp0 + 2),
-                         8, gdbarch_byte_order (gdbarch),
-                         readbuf ? readbuf + 8 : readbuf,
-                         writebuf ? writebuf + 8 : writebuf, 0);
+                         TYPE_LENGTH (type) / 2, gdbarch_byte_order (gdbarch),
+                         readbuf ? readbuf + TYPE_LENGTH (type) / 2 : readbuf,
+                         (writebuf
+                          ? writebuf + TYPE_LENGTH (type) / 2 : writebuf), 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else if (type->code () == TYPE_CODE_FLT