public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tiezhu Yang <yangtiezhu@loongson.cn>
To: gdb-patches@sourceware.org
Subject: [COMMITTED PATCH 2/2] gdb: LoongArch: Handle the function return value
Date: Tue, 26 Jul 2022 22:22:53 +0800	[thread overview]
Message-ID: <20220726142253.4822-2-yangtiezhu@loongson.cn> (raw)
In-Reply-To: <20220726142253.4822-1-yangtiezhu@loongson.cn>

According to LoongArch ELF ABI specification [1], handle the function
return value of various types.

[1] https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_return_values

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 gdb/loongarch-tdep.c | 233 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 219 insertions(+), 14 deletions(-)

diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c
index 3fb7774d8af..85a1dd70ebd 100644
--- a/gdb/loongarch-tdep.c
+++ b/gdb/loongarch-tdep.c
@@ -1074,6 +1074,19 @@ loongarch_push_dummy_call (struct gdbarch *gdbarch,
   return sp;
 }
 
+/* Partial transfer of a cooked register.  */
+
+static void
+loongarch_xfer_reg (struct regcache *regcache,
+		    int regnum, int len, gdb_byte *readbuf,
+		    const gdb_byte *writebuf, size_t offset)
+{
+  if (readbuf)
+    regcache->cooked_read_part (regnum, 0, len, readbuf + offset);
+  if (writebuf)
+    regcache->cooked_write_part (regnum, 0, len, writebuf + offset);
+}
+
 /* Implement the return_value gdbarch method.  */
 
 static enum return_value_convention
@@ -1081,24 +1094,216 @@ loongarch_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *type, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  int len = TYPE_LENGTH (type);
-  int regnum = -1;
+  int regsize = register_size (gdbarch, 0);
+  enum type_code code = type->code ();
+  size_t len = TYPE_LENGTH (type);
+  unsigned int fixed_point_members;
+  unsigned int floating_point_members;
+  bool first_member_is_fixed_point;
+  int a0 = LOONGARCH_A0_REGNUM;
+  int a1 = LOONGARCH_A0_REGNUM + 1;
+  int f0 = LOONGARCH_FIRST_FP_REGNUM;
+  int f1 = LOONGARCH_FIRST_FP_REGNUM + 1;
 
-  /* See if our value is returned through a register.  If it is, then
-     store the associated register number in REGNUM.  */
-  switch (type->code ())
+  if (len > 2 * regsize)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  switch (code)
     {
-      case TYPE_CODE_INT:
-	regnum = LOONGARCH_A0_REGNUM;
-	break;
+    case TYPE_CODE_INT:
+    case TYPE_CODE_BOOL:
+    case TYPE_CODE_CHAR:
+    case TYPE_CODE_RANGE:
+    case TYPE_CODE_ENUM:
+    case TYPE_CODE_PTR:
+      {
+	/* integer or pointer type.
+	   The return value is passed in a0,
+	   the unsigned integer scalars are zero-extended to GRLEN bits,
+	   and the signed integer scalars are sign-extended.  */
+	if (writebuf)
+	  {
+	    gdb_byte buf[regsize];
+	    if (type->is_unsigned ())
+	      {
+		ULONGEST data = extract_unsigned_integer (writebuf, len, BFD_ENDIAN_LITTLE);
+		store_unsigned_integer (buf, regsize, BFD_ENDIAN_LITTLE, data);
+	      }
+	    else
+	      {
+		LONGEST data = extract_signed_integer (writebuf, len, BFD_ENDIAN_LITTLE);
+		store_signed_integer (buf, regsize, BFD_ENDIAN_LITTLE, data);
+	      }
+	    loongarch_xfer_reg (regcache, a0, regsize, nullptr, buf, 0);
+	  }
+	else
+	  loongarch_xfer_reg (regcache, a0, len, readbuf, nullptr, 0);
+      }
+      break;
+    case TYPE_CODE_FLT:
+      /* long double type.
+	 The return value is passed in a0 and a1.  */
+      if (len == 2 * regsize)
+	{
+	  loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0);
+	  loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize);
+	}
+      /* float or double type.
+	 The return value is passed in f0.  */
+      else
+	{
+	  loongarch_xfer_reg (regcache, f0, len, readbuf, writebuf, 0);
+	}
+      break;
+    case TYPE_CODE_STRUCT:
+      {
+	fixed_point_members = 0;
+	floating_point_members = 0;
+	first_member_is_fixed_point = false;
+	compute_struct_member (type,
+			       &fixed_point_members,
+			       &floating_point_members,
+			       &first_member_is_fixed_point);
+
+	if (len > 0 && len <= regsize)
+	  {
+	    /* The structure has only fixed-point members.  */
+	    if (fixed_point_members > 0 && floating_point_members == 0)
+	      {
+		/* The return value is passed in a0.  */
+		loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0);
+	      }
+	    /* The structure has only floating-point members.  */
+	    else if (fixed_point_members == 0 && floating_point_members > 0)
+	      {
+		/* The structure has one floating-point member.
+		   The return value is passed in f0.  */
+		if (floating_point_members == 1)
+		  {
+		    loongarch_xfer_reg (regcache, f0, len, readbuf, writebuf, 0);
+		  }
+		/* The structure has two floating-point members.
+		   The return value is passed in f0 and f1.  */
+		else if (floating_point_members == 2)
+		  {
+		    loongarch_xfer_reg (regcache, f0, len / 2, readbuf, writebuf, 0);
+		    loongarch_xfer_reg (regcache, f1, len / 2, readbuf, writebuf, len / 2);
+		  }
+	      }
+	    /* The structure has both fixed-point and floating-point members.  */
+	    else if (fixed_point_members > 0 && floating_point_members > 0)
+	      {
+		/* The structure has one float member and multiple fixed-point members.
+		   The return value is passed in a0.  */
+		if (floating_point_members == 1 && fixed_point_members > 1)
+		  {
+		    loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0);
+		  }
+		/* The structure has one float member and one fixed-point member.  */
+		else if (floating_point_members == 1 && fixed_point_members == 1)
+		  {
+		    /* The return value is passed in f0 and a0 if the first member is floating-point.  */
+		    if (first_member_is_fixed_point == false)
+		      {
+			loongarch_xfer_reg (regcache, f0, regsize / 2, readbuf, writebuf, 0);
+			loongarch_xfer_reg (regcache, a0, regsize / 2, readbuf, writebuf, regsize / 2);
+		      }
+		    /* The return value is passed in a0 and f0 if the first member is fixed-point.  */
+		    else
+		      {
+			loongarch_xfer_reg (regcache, a0, regsize / 2, readbuf, writebuf, 0);
+			loongarch_xfer_reg (regcache, f0, regsize / 2, readbuf, writebuf, regsize / 2);
+		      }
+		  }
+	      }
+	  }
+	else if (len > regsize && len <= 2 * regsize)
+	  {
+	    /* The structure has only fixed-point members.  */
+	    if (fixed_point_members > 0 && floating_point_members == 0)
+	      {
+		/* The return value is passed in a0 and a1.  */
+		loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0);
+		loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize);
+	      }
+	    /* The structure has only floating-point members.  */
+	    else if (fixed_point_members == 0 && floating_point_members > 0)
+	      {
+		/* The structure has one long double member
+		   or one double member and two adjacent float members
+		   or 3-4 float members.
+		   The return value is passed in a0 and a1.  */
+		if ((len == 16 && floating_point_members == 1)
+		    || (len == 16 && floating_point_members == 3)
+		    || (len == 12 && floating_point_members == 3)
+		    || (len == 16 && floating_point_members == 4))
+		  {
+		    loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0);
+		    loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize);
+		  }
+		/* The structure has two double members
+		   or one double member and one float member.
+		   The return value is passed in f0 and f1.  */
+		else if ((len == 16 && floating_point_members == 2)
+			 || (len == 12 && floating_point_members == 2))
+		  {
+		    loongarch_xfer_reg (regcache, f0, regsize, readbuf, writebuf, 0);
+		    loongarch_xfer_reg (regcache, f1, len - regsize, readbuf, writebuf, regsize);
+		  }
+	      }
+	    /* The structure has both fixed-point and floating-point members.  */
+	    else if (fixed_point_members > 0 && floating_point_members > 0)
+	      {
+		/* The structure has one floating-point member and one fixed-point member.  */
+		if (floating_point_members == 1 && fixed_point_members == 1)
+		  {
+		    /* The return value is passed in f0 and a0 if the first member is floating-point.  */
+		    if (first_member_is_fixed_point == false)
+		      {
+			loongarch_xfer_reg (regcache, f0, regsize, readbuf, writebuf, 0);
+			loongarch_xfer_reg (regcache, a0, len - regsize, readbuf, writebuf, regsize);
+		      }
+		    /* The return value is passed in a0 and f0 if the first member is fixed-point.  */
+		    else
+		      {
+			loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0);
+			loongarch_xfer_reg (regcache, f0, len - regsize, readbuf, writebuf, regsize);
+		      }
+		  }
+		else
+		  {
+		    /* The return value is passed in a0 and a1.  */
+		    loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0);
+		    loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize);
+		  }
+	      }
+	  }
+      }
+      break;
+    case TYPE_CODE_UNION:
+      if (len > 0 && len <= regsize)
+	{
+	  /* The return value is passed in a0.  */
+	  loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0);
+	}
+      else if (len > regsize && len <= 2 * regsize)
+	{
+	  /* The return value is passed in a0 and a1.  */
+	  loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0);
+	  loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize);
+	}
+      break;
+    case TYPE_CODE_COMPLEX:
+      {
+	/* The return value is passed in f0 and f1.  */
+	loongarch_xfer_reg (regcache, f0, len / 2, readbuf, writebuf, 0);
+	loongarch_xfer_reg (regcache, f1, len / 2, readbuf, writebuf, len / 2);
+      }
+      break;
+    default:
+      break;
     }
 
-  /* Extract the return value from the register where it was stored.  */
-  if (readbuf != nullptr)
-    regcache->raw_read_part (regnum, 0, len, readbuf);
-  if (writebuf != nullptr)
-    regcache->raw_write_part (regnum, 0, len, writebuf);
-
   return RETURN_VALUE_REGISTER_CONVENTION;
 }
 
-- 
2.27.0


      reply	other threads:[~2022-07-26 14:23 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-26 14:22 [COMMITTED PATCH 1/2] gdb: LoongArch: Fix code style issues Tiezhu Yang
2022-07-26 14:22 ` Tiezhu Yang [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220726142253.4822-2-yangtiezhu@loongson.cn \
    --to=yangtiezhu@loongson.cn \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).