public inbox for gdb-cvs@sourceware.org
help / color / mirror / Atom feed
* [binutils-gdb] gdb: LoongArch: Add floating-point support
@ 2022-07-12 12:16 Tiezhu Yang
  0 siblings, 0 replies; only message in thread
From: Tiezhu Yang @ 2022-07-12 12:16 UTC (permalink / raw)
  To: gdb-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=657a50227bbd835c83aadc2405e649c4b982c241

commit 657a50227bbd835c83aadc2405e649c4b982c241
Author: Tiezhu Yang <yangtiezhu@loongson.cn>
Date:   Tue Jul 12 10:33:28 2022 +0800

    gdb: LoongArch: Add floating-point support
    
    This commit adds floating-point support for LoongArch gdb.
    
    Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>

Diff:
---
 gdb/arch/loongarch.c           |  9 ++++++
 gdb/arch/loongarch.h           | 17 ++++++++++-
 gdb/features/Makefile          |  1 +
 gdb/features/loongarch/fpu.c   | 55 +++++++++++++++++++++++++++++++++
 gdb/features/loongarch/fpu.xml | 50 ++++++++++++++++++++++++++++++
 gdb/loongarch-linux-nat.c      | 52 +++++++++++++++++++++++++++++++
 gdb/loongarch-linux-tdep.c     | 69 +++++++++++++++++++++++++++++++++++++++---
 gdb/loongarch-tdep.c           | 66 +++++++++++++++++++++++++++++++---------
 gdb/loongarch-tdep.h           |  1 +
 9 files changed, 300 insertions(+), 20 deletions(-)

diff --git a/gdb/arch/loongarch.c b/gdb/arch/loongarch.c
index 11310c1dd93..c48c2001e96 100644
--- a/gdb/arch/loongarch.c
+++ b/gdb/arch/loongarch.c
@@ -24,6 +24,7 @@
 
 #include "../features/loongarch/base32.c"
 #include "../features/loongarch/base64.c"
+#include "../features/loongarch/fpu.c"
 
 #ifndef GDBSERVER
 #define STATIC_IN_GDB static
@@ -44,6 +45,11 @@ loongarch_create_target_description (const struct loongarch_gdbarch_features fea
   else if (features.xlen == 8)
     arch_name.append ("64");
 
+  if (features.fputype == SINGLE_FLOAT)
+    arch_name.append ("f");
+  else if (features.fputype == DOUBLE_FLOAT)
+    arch_name.append ("d");
+
   set_tdesc_architecture (tdesc.get (), arch_name.c_str ());
 
   long regnum = 0;
@@ -54,6 +60,9 @@ loongarch_create_target_description (const struct loongarch_gdbarch_features fea
   else if (features.xlen == 8)
     regnum = create_feature_loongarch_base64 (tdesc.get (), regnum);
 
+  /* For now we only support creating single float and double float.  */
+  regnum = create_feature_loongarch_fpu (tdesc.get (), regnum);
+
   return tdesc;
 }
 
diff --git a/gdb/arch/loongarch.h b/gdb/arch/loongarch.h
index 5cf5498079a..799595b3e60 100644
--- a/gdb/arch/loongarch.h
+++ b/gdb/arch/loongarch.h
@@ -23,7 +23,7 @@
 #include "gdbsupport/tdesc.h"
 
 /* Register numbers of various important registers.  */
-enum
+enum loongarch_regnum
 {
   LOONGARCH_RA_REGNUM = 1,		/* Return Address.  */
   LOONGARCH_SP_REGNUM = 3,		/* Stack Pointer.  */
@@ -36,6 +36,16 @@ enum
   LOONGARCH_LINUX_NUM_GREGSET = 45,	/* 32 GPR, ORIG_A0, PC, BADV, RESERVED 10.  */
   LOONGARCH_ARG_REGNUM = 8,            /* r4-r11: general-purpose argument registers.
 					  f0-f7: floating-point argument registers.  */
+  LOONGARCH_FIRST_FP_REGNUM = LOONGARCH_LINUX_NUM_GREGSET,
+  LOONGARCH_FCC_REGNUM = LOONGARCH_FIRST_FP_REGNUM + 32,
+  LOONGARCH_FCSR_REGNUM = LOONGARCH_FCC_REGNUM + 1,
+  LOONGARCH_LINUX_NUM_FPREGSET = 34,
+};
+
+enum loongarch_fputype
+{
+  SINGLE_FLOAT = 1,
+  DOUBLE_FLOAT = 2,
 };
 
 /* The set of LoongArch architectural features that we track that impact how
@@ -56,6 +66,11 @@ struct loongarch_gdbarch_features
      0 value so we can spot if one of these is used uninitialised.  */
   int xlen = 0;
 
+  /* The type of floating-point.  This is either 1 (single float) or 2
+     (double float).  No other value is valid.  Initialise to the invalid
+     0 value so we can spot if one of these is used uninitialised.  */
+  int fputype = 0;
+
   /* Equality operator.  */
   bool operator== (const struct loongarch_gdbarch_features &rhs) const
   {
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 15d623c2681..061cb2ed032 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -231,6 +231,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	i386/x32-core.xml \
 	loongarch/base32.xml \
 	loongarch/base64.xml \
+	loongarch/fpu.xml \
 	riscv/rv32e-xregs.xml \
 	riscv/32bit-cpu.xml \
 	riscv/32bit-fpu.xml \
diff --git a/gdb/features/loongarch/fpu.c b/gdb/features/loongarch/fpu.c
new file mode 100644
index 00000000000..ea3e1dd9980
--- /dev/null
+++ b/gdb/features/loongarch/fpu.c
@@ -0,0 +1,55 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: fpu.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_loongarch_fpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.fpu");
+  tdesc_type_with_fields *type_with_fields;
+  type_with_fields = tdesc_create_union (feature, "fputype");
+  tdesc_type *field_type;
+  field_type = tdesc_named_type (feature, "ieee_single");
+  tdesc_add_field (type_with_fields, "f", field_type);
+  field_type = tdesc_named_type (feature, "ieee_double");
+  tdesc_add_field (type_with_fields, "d", field_type);
+
+  tdesc_create_reg (feature, "f0", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f1", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f2", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f3", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f4", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f5", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f6", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f7", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f8", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f9", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f10", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f11", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f12", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f13", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f14", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f15", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f16", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f17", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f18", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f19", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f20", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f21", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f22", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f23", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f24", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f25", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f26", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f27", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f28", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f29", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f30", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "f31", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "fcc", regnum++, 1, "float", 64, "fputype");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, "float", 32, "uint32");
+  return regnum;
+}
diff --git a/gdb/features/loongarch/fpu.xml b/gdb/features/loongarch/fpu.xml
new file mode 100644
index 00000000000..a61057ec442
--- /dev/null
+++ b/gdb/features/loongarch/fpu.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2021 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.loongarch.fpu">
+
+  <union id="fputype">
+    <field name="f" type="ieee_single"/>
+    <field name="d" type="ieee_double"/>
+  </union>
+
+  <reg name="f0" bitsize="64" type="fputype" group="float"/>
+  <reg name="f1" bitsize="64" type="fputype" group="float"/>
+  <reg name="f2" bitsize="64" type="fputype" group="float"/>
+  <reg name="f3" bitsize="64" type="fputype" group="float"/>
+  <reg name="f4" bitsize="64" type="fputype" group="float"/>
+  <reg name="f5" bitsize="64" type="fputype" group="float"/>
+  <reg name="f6" bitsize="64" type="fputype" group="float"/>
+  <reg name="f7" bitsize="64" type="fputype" group="float"/>
+  <reg name="f8" bitsize="64" type="fputype" group="float"/>
+  <reg name="f9" bitsize="64" type="fputype" group="float"/>
+  <reg name="f10" bitsize="64" type="fputype" group="float"/>
+  <reg name="f11" bitsize="64" type="fputype" group="float"/>
+  <reg name="f12" bitsize="64" type="fputype" group="float"/>
+  <reg name="f13" bitsize="64" type="fputype" group="float"/>
+  <reg name="f14" bitsize="64" type="fputype" group="float"/>
+  <reg name="f15" bitsize="64" type="fputype" group="float"/>
+  <reg name="f16" bitsize="64" type="fputype" group="float"/>
+  <reg name="f17" bitsize="64" type="fputype" group="float"/>
+  <reg name="f18" bitsize="64" type="fputype" group="float"/>
+  <reg name="f19" bitsize="64" type="fputype" group="float"/>
+  <reg name="f20" bitsize="64" type="fputype" group="float"/>
+  <reg name="f21" bitsize="64" type="fputype" group="float"/>
+  <reg name="f22" bitsize="64" type="fputype" group="float"/>
+  <reg name="f23" bitsize="64" type="fputype" group="float"/>
+  <reg name="f24" bitsize="64" type="fputype" group="float"/>
+  <reg name="f25" bitsize="64" type="fputype" group="float"/>
+  <reg name="f26" bitsize="64" type="fputype" group="float"/>
+  <reg name="f27" bitsize="64" type="fputype" group="float"/>
+  <reg name="f28" bitsize="64" type="fputype" group="float"/>
+  <reg name="f29" bitsize="64" type="fputype" group="float"/>
+  <reg name="f30" bitsize="64" type="fputype" group="float"/>
+  <reg name="f31" bitsize="64" type="fputype" group="float"/>
+  <reg name="fcc" bitsize="64" type="fputype" group="float"/>
+  <reg name="fcsr" bitsize="32" type="uint32" group="float"/>
+</feature>
diff --git a/gdb/loongarch-linux-nat.c b/gdb/loongarch-linux-nat.c
index 1b4a37c94fb..3baa891519a 100644
--- a/gdb/loongarch-linux-nat.c
+++ b/gdb/loongarch-linux-nat.c
@@ -100,6 +100,52 @@ store_gregs_to_thread (struct regcache *regcache, int regnum, pid_t tid)
   }
 }
 
+/* Fill GDB's register array with the fp, fcc and fcsr
+   register values from the current thread.  */
+
+static void
+fetch_fpregs_from_thread (struct regcache *regcache, int regnum, pid_t tid)
+{
+  elf_fpregset_t regset;
+
+  if ((regnum == -1)
+      || (regnum >= LOONGARCH_FIRST_FP_REGNUM && regnum <= LOONGARCH_FCSR_REGNUM))
+    {
+      struct iovec iovec = { .iov_base = &regset, .iov_len = sizeof (regset) };
+
+      if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, (long) &iovec) < 0)
+	perror_with_name (_("Couldn't get NT_FPREGSET registers"));
+      else
+	loongarch_fpregset.supply_regset (nullptr, regcache, regnum,
+					  &regset, sizeof (regset));
+    }
+}
+
+/* Store to the current thread the valid fp, fcc and fcsr
+   register values in the GDB's register array.  */
+
+static void
+store_fpregs_to_thread (struct regcache *regcache, int regnum, pid_t tid)
+{
+  elf_fpregset_t regset;
+
+  if ((regnum == -1)
+      || (regnum >= LOONGARCH_FIRST_FP_REGNUM && regnum <= LOONGARCH_FCSR_REGNUM))
+    {
+      struct iovec iovec = { .iov_base = &regset, .iov_len = sizeof (regset) };
+
+      if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, (long) &iovec) < 0)
+	perror_with_name (_("Couldn't get NT_FPREGSET registers"));
+      else
+	{
+	  loongarch_fpregset.collect_regset (nullptr, regcache, regnum,
+					     &regset, sizeof (regset));
+	  if (ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, (long) &iovec) < 0)
+	    perror_with_name (_("Couldn't set NT_FPREGSET registers"));
+	}
+    }
+}
+
 /* Implement the "fetch_registers" target_ops method.  */
 
 void
@@ -109,6 +155,7 @@ loongarch_linux_nat_target::fetch_registers (struct regcache *regcache,
   pid_t tid = get_ptrace_pid (regcache->ptid ());
 
   fetch_gregs_from_thread(regcache, regnum, tid);
+  fetch_fpregs_from_thread(regcache, regnum, tid);
 }
 
 /* Implement the "store_registers" target_ops method.  */
@@ -120,6 +167,7 @@ loongarch_linux_nat_target::store_registers (struct regcache *regcache,
   pid_t tid = get_ptrace_pid (regcache->ptid ());
 
   store_gregs_to_thread (regcache, regnum, tid);
+  store_fpregs_to_thread(regcache, regnum, tid);
 }
 
 /* Return the address in the core dump or inferior of register REGNO.  */
@@ -158,12 +206,16 @@ fill_gregset (const struct regcache *regcache, gdb_gregset_t *gregset,
 void
 supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregset)
 {
+  loongarch_fpregset.supply_regset (nullptr, regcache, -1, fpregset,
+				    sizeof (gdb_fpregset_t));
 }
 
 void
 fill_fpregset (const struct regcache *regcache, gdb_fpregset_t *fpregset,
 	       int regnum)
 {
+  loongarch_fpregset.collect_regset (nullptr, regcache, regnum, fpregset,
+				     sizeof (gdb_fpregset_t));
 }
 
 /* Initialize LoongArch Linux native support.  */
diff --git a/gdb/loongarch-linux-tdep.c b/gdb/loongarch-linux-tdep.c
index 1076e935997..0a3ea80c173 100644
--- a/gdb/loongarch-linux-tdep.c
+++ b/gdb/loongarch-linux-tdep.c
@@ -106,7 +106,7 @@ loongarch_fill_gregset (const struct regset *regset,
     }
 }
 
-/* Register set definitions.  */
+/* Define the general register regset.  */
 
 const struct regset loongarch_gregset =
 {
@@ -115,6 +115,62 @@ const struct regset loongarch_gregset =
   loongarch_fill_gregset,
 };
 
+/* Unpack an elf_fpregset_t into GDB's register cache.  */
+static void
+loongarch_supply_fpregset (const struct regset *r,
+			   struct regcache *regcache, int regnum,
+			   const void *fprs, size_t len)
+{
+  const gdb_byte *buf = nullptr;
+  int fprsize = register_size (regcache->arch (), LOONGARCH_FIRST_FP_REGNUM);
+
+  if (regnum == -1)
+    {
+      for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++)
+	{
+	  buf = (const gdb_byte *)fprs + fprsize * i;
+	  regcache->raw_supply (LOONGARCH_FIRST_FP_REGNUM + i, (const void *)buf);
+	}
+    }
+  else if (regnum >= LOONGARCH_FIRST_FP_REGNUM && regnum <= LOONGARCH_FCSR_REGNUM)
+    {
+      buf = (const gdb_byte *)fprs + fprsize * (regnum - LOONGARCH_FIRST_FP_REGNUM);
+      regcache->raw_supply (regnum, (const void *)buf);
+    }
+}
+
+/* Pack the GDB's register cache value into an elf_fpregset_t.  */
+static void
+loongarch_fill_fpregset (const struct regset *r,
+			 const struct regcache *regcache, int regnum,
+			 void *fprs, size_t len)
+{
+  gdb_byte *buf = nullptr;
+  int fprsize = register_size (regcache->arch (), LOONGARCH_FIRST_FP_REGNUM);
+
+  if (regnum == -1)
+    {
+      for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++)
+	{
+	  buf = (gdb_byte *)fprs + fprsize * i;
+	  regcache->raw_collect (LOONGARCH_FIRST_FP_REGNUM + i, (void *)buf);
+	}
+    }
+  else if (regnum >= LOONGARCH_FIRST_FP_REGNUM && regnum <= LOONGARCH_FCSR_REGNUM)
+    {
+      buf = (gdb_byte *)fprs + fprsize * (regnum - LOONGARCH_FIRST_FP_REGNUM);
+      regcache->raw_collect (regnum, (void *)buf);
+    }
+}
+
+/* Define the FP register regset.  */
+const struct regset loongarch_fpregset =
+{
+  nullptr,
+  loongarch_supply_fpregset,
+  loongarch_fill_fpregset,
+};
+
 /* Implement the "init" method of struct tramp_frame.  */
 
 #define LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET	128
@@ -152,7 +208,7 @@ static const struct tramp_frame loongarch_linux_rt_sigframe =
     { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
   },
   loongarch_linux_rt_sigframe_init,
-  NULL
+  nullptr
 };
 
 /* Implement the "iterate_over_regset_sections" gdbarch method.  */
@@ -163,10 +219,13 @@ loongarch_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					void *cb_data,
 					const struct regcache *regcache)
 {
-  int regsize = register_size (gdbarch, 0);
+  int gprsize = register_size (gdbarch, 0);
+  int fprsize = register_size (gdbarch, LOONGARCH_FIRST_FP_REGNUM);
 
-  cb (".reg", LOONGARCH_LINUX_NUM_GREGSET * regsize,
-      LOONGARCH_LINUX_NUM_GREGSET * regsize, &loongarch_gregset, NULL, cb_data);
+  cb (".reg", LOONGARCH_LINUX_NUM_GREGSET * gprsize,
+      LOONGARCH_LINUX_NUM_GREGSET * gprsize, &loongarch_gregset, nullptr, cb_data);
+  cb (".reg2", LOONGARCH_LINUX_NUM_FPREGSET * fprsize,
+      LOONGARCH_LINUX_NUM_FPREGSET * fprsize, &loongarch_fpregset, nullptr, cb_data);
 }
 
 /* The following value is derived from __NR_rt_sigreturn in
diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c
index b8f28a2b142..41422f0445d 100644
--- a/gdb/loongarch-tdep.c
+++ b/gdb/loongarch-tdep.c
@@ -462,7 +462,7 @@ pass_in_gar (struct regcache *regcache, unsigned int gar, const gdb_byte *val)
 static void
 pass_in_far (struct regcache *regcache, unsigned int far, const gdb_byte *val)
 {
-  unsigned int regnum = LOONGARCH_ARG_REGNUM - far + LOONGARCH_BADV_REGNUM + 1;
+  unsigned int regnum = LOONGARCH_ARG_REGNUM - far + LOONGARCH_FIRST_FP_REGNUM;
   regcache->cooked_write (regnum, val);
 }
 
@@ -1080,6 +1080,8 @@ loongarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int regnum)
 {
   if (regnum >= 0 && regnum < 32)
     return regnum;
+  else if (regnum >= 32 && regnum < 66)
+    return LOONGARCH_FIRST_FP_REGNUM + regnum - 32;
   else
     return -1;
 }
@@ -1104,6 +1106,7 @@ loongarch_features_from_bfd (const bfd *abfd)
   if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
     {
       unsigned char eclass = elf_elfheader (abfd)->e_ident[EI_CLASS];
+      int e_flags = elf_elfheader (abfd)->e_flags;
 
       if (eclass == ELFCLASS32)
 	features.xlen = 4;
@@ -1112,6 +1115,11 @@ loongarch_features_from_bfd (const bfd *abfd)
       else
 	internal_error (__FILE__, __LINE__,
 			_("unknown ELF header class %d"), eclass);
+
+      if (EF_LOONGARCH_IS_SINGLE_FLOAT (e_flags))
+	features.fputype = SINGLE_FLOAT;
+      else if (EF_LOONGARCH_IS_DOUBLE_FLOAT (e_flags))
+	features.fputype = DOUBLE_FLOAT;
     }
 
   return features;
@@ -1130,11 +1138,17 @@ loongarch_find_default_target_description (const struct gdbarch_info info)
 
   /* If the XLEN field is still 0 then we got nothing useful from INFO.BFD,
      maybe there was no bfd object.  In this case we fall back to a minimal
-     useful target with no floating point, the x-register size is selected
-     based on the architecture from INFO.  */
+     useful target, the x-register size is selected based on the architecture
+     from INFO.  */
   if (features.xlen == 0)
     features.xlen = info.bfd_arch_info->bits_per_address == 32 ? 4 : 8;
 
+  /* If the FPUTYPE field is still 0 then we got nothing useful from INFO.BFD,
+     maybe there was no bfd object.  In this case we fall back to a usual useful
+     target with double float.  */
+  if (features.fputype == 0)
+    features.fputype = DOUBLE_FLOAT;
+
   /* Now build a target description based on the feature set.  */
   return loongarch_lookup_target_description (features);
 }
@@ -1144,6 +1158,10 @@ loongarch_find_default_target_description (const struct gdbarch_info info)
 static struct gdbarch *
 loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
+  size_t regnum = 0;
+  struct loongarch_gdbarch_features features;
+  tdesc_arch_data_up tdesc_data = tdesc_data_alloc ();
+  loongarch_gdbarch_tdep *tdep = new loongarch_gdbarch_tdep;
   const struct target_desc *tdesc = info.target_desc;
 
   /* Ensure we always have a target description.  */
@@ -1155,13 +1173,6 @@ loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (feature_cpu == nullptr)
     return nullptr;
 
-  int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc");
-  struct loongarch_gdbarch_features features;
-  features.xlen = (xlen_bitsize / 8);
-
-  size_t regnum = 0;
-  tdesc_arch_data_up tdesc_data = tdesc_data_alloc ();
-  loongarch_gdbarch_tdep *tdep = new loongarch_gdbarch_tdep;
 
   /* Validate the description provides the mandatory base registers
      and allocate their numbers.  */
@@ -1175,6 +1186,22 @@ loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (!valid_p)
     return nullptr;
 
+  const struct tdesc_feature *feature_fpu
+    = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.fpu");
+  if (feature_fpu == nullptr)
+    return nullptr;
+
+  /* Validate the description provides the fpu registers and
+     allocate their numbers.  */
+  regnum = LOONGARCH_FIRST_FP_REGNUM;
+  for (int i = 0; i < 32; i++)
+    valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++,
+					loongarch_f_normal_name[i] + 1);
+  valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, "fcc");
+  valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, "fcsr");
+  if (!valid_p)
+    return nullptr;
+
   /* LoongArch code is always little-endian.  */
   info.byte_order_for_code = BFD_ENDIAN_LITTLE;
 
@@ -1184,11 +1211,22 @@ loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   struct loongarch_gdbarch_features abi_features
     = loongarch_features_from_bfd (info.abfd);
 
-  /* If the ABI_FEATURES xlen is 0 then this indicates we got no useful abi
-     features from the INFO object.  In this case we just treat the
-     hardware features as defining the abi.  */
+  /* If the ABI_FEATURES xlen or fputype is 0 then this indicates we got
+     no useful abi features from the INFO object.  In this case we just
+     treat the hardware features as defining the abi.  */
   if (abi_features.xlen == 0)
-    abi_features = features;
+    {
+      int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc");
+      features.xlen = (xlen_bitsize / 8);
+      features.fputype = abi_features.fputype;
+      abi_features = features;
+    }
+  if (abi_features.fputype == 0)
+    {
+      features.xlen = abi_features.xlen;
+      features.fputype = DOUBLE_FLOAT;
+      abi_features = features;
+    }
 
   /* Find a candidate among the list of pre-declared architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
diff --git a/gdb/loongarch-tdep.h b/gdb/loongarch-tdep.h
index b68a7892f2b..e35b6cf4c7a 100644
--- a/gdb/loongarch-tdep.h
+++ b/gdb/loongarch-tdep.h
@@ -29,6 +29,7 @@
 
 /* Register set definitions.  */
 extern const struct regset loongarch_gregset;
+extern const struct regset loongarch_fpregset;
 
 /* Target-dependent structure in gdbarch.  */
 struct loongarch_gdbarch_tdep : gdbarch_tdep


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-07-12 12:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-12 12:16 [binutils-gdb] gdb: LoongArch: Add floating-point support Tiezhu Yang

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).