[3/11] Add MIPS_MAX_REGISTER_SIZE (2/4)

Message ID F4BA5380-80DA-4A74-8D62-73E00325EEBF@arm.com
State New, archived
Headers

Commit Message

Alan Hayward May 16, 2017, 11:16 a.m. UTC
  > On 12 May 2017, at 09:53, Yao Qi <qiyaoltc@gmail.com> wrote:
> 
> Alan Hayward <Alan.Hayward@arm.com> writes:
> 
>> }
>> 
>> +/* Supply register REGNUM, whose contents are stored in signed VAL, to
>> +   REGCACHE.  */
>> +
>> +void
>> +regcache::raw_supply_signed (int regnum, LONGEST val)
> 
> The unsigned version of this function is also needed, because I see such
> pattern also exists,
> 
>      store_unsigned_integer (buf, 8, byte_order, sp + offset);
>      regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf);
> 
> this leads me thinking we need to use function template to define
> functions for both LONGEST and ULONGEST.
> 
> Secondly, this method can be named as raw_supply.
> 
>> +{
>> +  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
>> +  gdb_byte *regbuf;
>> +  size_t size;
>> +
>> +  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
>> +  gdb_assert (!m_readonly_p);
>> +
>> +  regbuf = register_buffer (regnum);
>> +  size = m_descr->sizeof_register[regnum];
>> +
>> +  store_signed_integer (regbuf, size, byte_order, val);
>> +  m_register_status[regnum] = REG_VALID;
>> +}
>> +
>> /* Collect register REGNUM from REGCACHE and store its contents in BUF.  */
>> 
>> void
>> @@ -1251,6 +1271,23 @@ regcache::raw_collect (int regnum, void *buf) const
>>   memcpy (buf, regbuf, size);
>> }
>> 
>> +/* Collect register REGNUM from REGCACHE and extract its contents into a signed
> 
> This line is too long.
> 
>> +   LONGEST.  */
>> +
>> +LONGEST
>> +regcache::raw_collect_signed (int regnum) const
> 
> We can define this method like this,
> 
> template<typename T>
> using LongType = typename std::enable_if<(std::is_same<T, LONGEST>::value
> 					  || std::is_same<T, ULONGEST>::value),
> 					 T>::type;
> 
>  template<typename T>
>  LongType<T> raw_collect (int regnum) const
>  {
>    ....
>    if (std::is_signed<T>::value)
>      return extract_signed_integer (regbuf, size, byte_order);
>    else
>      return extract_unsigned_integer (regbuf, size, byte_order);
>  }
> 
>> +{
>> +  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
>> +  const gdb_byte *regbuf;
>> +  size_t size;
>> +
>> +  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
>> +
>> +  regbuf = register_buffer (regnum);
>> +  size = m_descr->sizeof_register[regnum];
>> +  return extract_signed_integer (regbuf, size, byte_order);
>> +}
> 
> If you want, we can add a function template for extract_signed_integer
> and extract_unsigned_integer.
> 
> template<typename T>
> LongType<T>
> extract_integer (const gdb_byte *addr, int len, enum bfd_endian byte_order)
> {
>  T retval;
> 
>  ...
>  if (std::is_signed<T>::value)
>    {
>      ...
>    }
>  else
>    {
>      ...
>    }
>  return retval;
> }
> 
> so, the raw_collect above becomes, 
> 
>  template<typename T>
>  LongType<T> raw_collect (int regnum) const
>  {
>    ....
>    return extract_integer<T> (regbuf, size, byte_order);
>  }
> 
> and raw_read_{signed,unsigned}, cooked_read_{signed,unsigned} can be
> merged as function template too.
> 


Added templates for extract_integer and store_integer, raw_supply and raw_collect.
Did not add raw_read and cooked_read, as they are out of the scope of this patch.


Tested on a --enable-targets=all build using make check with board files
unix and native-gdbserver.
I do not have a MIPS machine to test on.
Ok to commit?

Alan.

2017-05-16  Alan Hayward  <alan.hayward@arm.com>

	* gdb/defs.h (LongType): New templated type.
	(extract_integer): New declaration.
	(extract_signed_integer): Switched to inline.
	(extract_unsigned_integer): Likewise.
	(store_integer): New declaration
	(store_signed_integer): Switched to inline.
	(store_unsigned_integer): Likewise.
	* gdb/findvar.c (extract_integer): New function and instantiations.
	(extract_signed_integer): Removed function.
	(extract_unsigned_integer): Likewise.
	(store_integer): New function and instantiations.
	(store_signed_integer): Removed function.
	(store_unsigned_integer): Likewise.
	* mips-fbsd-tdep.c (mips_fbsd_supply_reg): Use templated raw_supply.
	(mips_fbsd_collect_reg): Use templated raw_collect.
	* mips-linux-tdep.c (supply_32bit_reg): Use templated raw_supply.
	(mips64_fill_gregset): Use templated raw_collect.
	(mips64_fill_fpregset): Use templated raw_supply.
	* gdb/regcache.c (regcache::raw_supply): New function and
	instantiations.
	(LongType regcache::raw_collect): Likewise
	* gdb/regcache.h (regcache::raw_supply): New declaration.
	(regcache::raw_collect): Likewise
  

Comments

Yao Qi May 22, 2017, 12:07 p.m. UTC | #1
Alan Hayward <Alan.Hayward@arm.com> writes:

> -extern ULONGEST extract_unsigned_integer (const gdb_byte *, int,
> -					  enum bfd_endian);
> +inline ULONGEST extract_unsigned_integer (const gdb_byte *addr, int len,
> +					  enum bfd_endian byte_order)
> +{
> +  return extract_integer<LONGEST> (addr, len, byte_order);

s/LONGEST/ULONGEST/

> +}
>

[My C++ knowledge is still poor, so forgive me if I ask something stupid]

Is there any reason you do not put function template (extract_integer and
store_integer) in header?  Any benefit of doing this?

>  extern int extract_long_unsigned_integer (const gdb_byte *, int,
>  					  enum bfd_endian, LONGEST *);
> @@ -649,11 +664,21 @@ extern int extract_long_unsigned_integer (const gdb_byte *, int,
>  extern CORE_ADDR extract_typed_address (const gdb_byte *buf,
>  					struct type *type);
>
> -extern void store_signed_integer (gdb_byte *, int,
> -				  enum bfd_endian, LONGEST);
> +template<typename T> void store_integer (gdb_byte *addr, int len,
> +					 enum bfd_endian byte_order,
> +					 LongType<T> val);

We can define store_integer slightly differently, so that we can use
implicit instantiation,

template<typename T>
typename std::enable_if<(std::is_same<T, LONGEST>::value
			 || std::is_same<T, ULONGEST>::value),
			void>::type
store_integer (gdb_byte *addr, int len, enum bfd_endian byte_order, T val)
{} so that ...

>
> -extern void store_unsigned_integer (gdb_byte *, int,
> -				    enum bfd_endian, ULONGEST);
> +inline void store_signed_integer (gdb_byte *addr, int len,
> +				  enum bfd_endian byte_order, LONGEST val)
> +{
> +  store_integer<LONGEST> (addr, len, byte_order, val);

... the template argument can be deduced,

    store_integer (addr, len, byte_order, val);

should be OK.

> diff --git a/gdb/findvar.c b/gdb/findvar.c
> index ed4d5c1266c9de069981b306bc8229ae5fb02350..3bcc98ce3421cb800fc8222535b16ca94ee043da 100644
> --- a/gdb/findvar.c
> +++ b/gdb/findvar.c
> @@ -46,70 +46,54 @@
>  you lose
>  #endif
>
> -LONGEST
> -extract_signed_integer (const gdb_byte *addr, int len,
> -			enum bfd_endian byte_order)
> +template<typename T>
> +LongType<T>
> +extract_integer (const gdb_byte *addr, int len, enum bfd_endian byte_order)
>  {
> -  LONGEST retval;
> +  T retval;
>    const unsigned char *p;
>    const unsigned char *startaddr = addr;
>    const unsigned char *endaddr = startaddr + len;
>
> -  if (len > (int) sizeof (LONGEST))
> +  if (len > (int) sizeof (T))
>      error (_("\
>  That operation is not available on integers of more than %d bytes."),
> -	   (int) sizeof (LONGEST));
> +	   (int) sizeof (T));
>
>    /* Start at the most significant end of the integer, and work towards
>       the least significant.  */
>    if (byte_order == BFD_ENDIAN_BIG)
>      {
>        p = startaddr;
> -      /* Do the sign extension once at the start.  */
> -      retval = ((LONGEST) * p ^ 0x80) - 0x80;
> -      for (++p; p < endaddr; ++p)
> +      if (std::is_signed<T>::value)
> +	{
> +	  /* Do the sign extension once at the start.  */
> +	  retval = ((LONGEST) * p ^ 0x80) - 0x80;
> +	  ++p;
> +	}

Need to set retval to zero if (!std::is_signed<T>::value), otherwise,
retval might be not initialized.


> diff --git a/gdb/mips-fbsd-tdep.c b/gdb/mips-fbsd-tdep.c
> index 00fae0ec60ddc9e645d3236efe29f2f9e9ceab5c..1e391bfd16864d9d45f3b6e0de425aa5543515df 100644
> --- a/gdb/mips-fbsd-tdep.c
> +++ b/gdb/mips-fbsd-tdep.c
> @@ -48,9 +48,9 @@
>  #define MIPS_FBSD_NUM_FPREGS	34
>
>  /* Supply a single register.  If the source register size matches the
> -   size the regcache expects, this can use regcache_raw_supply().  If
> +   size the regcache expects, this can use regcache->raw_supply ().  If
>     they are different, this copies the source register into a buffer
> -   that can be passed to regcache_raw_supply().  */
> +   that can be passed to regcache->raw_supply ().  */
>
>  static void
>  mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
> @@ -63,20 +63,17 @@ mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
>    else
>      {
>        enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> -      gdb_byte buf[MAX_REGISTER_SIZE];
>        LONGEST val;
>
> -      val = extract_signed_integer ((const gdb_byte *) addr, len, byte_order);
> -      store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
> -			    val);
> -      regcache_raw_supply (regcache, regnum, buf);
> +      val = extract_integer<LONGEST> ((const gdb_byte *) addr, len, byte_order);
> +      regcache->raw_supply<LONGEST> (regnum, val);
>      }
>  }
>
>  /* Collect a single register.  If the destination register size
>     matches the size the regcache expects, this can use
> -   regcache_raw_supply().  If they are different, this fetches the
> -   register via regcache_raw_supply() into a buffer and then copies it
> +   regcache->raw_supply ().  If they are different, this fetches the
> +   register via regcache->raw_supply () into a buffer and then copies it
>     into the final destination.  */
>
>  static void
> @@ -90,13 +87,8 @@ mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
>    else
>      {
>        enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> -      gdb_byte buf[MAX_REGISTER_SIZE];
> -      LONGEST val;
> -
> -      regcache_raw_collect (regcache, regnum, buf);
> -      val = extract_signed_integer (buf, register_size (gdbarch, regnum),
> -				    byte_order);
> -      store_signed_integer ((gdb_byte *) addr, len, byte_order, val);
> +      LONGEST val = regcache->raw_collect<LONGEST> (regnum);
> +      store_integer<LONGEST> ((gdb_byte *) addr, len, byte_order, val);
>      }
>  }
>
> diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
> index 48a582a16c934abe6e8f87c46a6009649c606d49..bac106ed5e9e5d89285420beb52b33d6ce36265a 100644
> --- a/gdb/mips-linux-tdep.c
> +++ b/gdb/mips-linux-tdep.c
> @@ -118,11 +118,10 @@ supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr)
>  {
>    struct gdbarch *gdbarch = get_regcache_arch (regcache);
>    enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> -  gdb_byte buf[MAX_REGISTER_SIZE];
> -  store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
> -			extract_signed_integer ((const gdb_byte *) addr, 4,
> -						byte_order));
> -  regcache_raw_supply (regcache, regnum, buf);
> +  LONGEST val;
> +
> +  val = extract_integer<LONGEST> ((const gdb_byte *) addr, 4, byte_order);
> +  regcache->raw_supply<LONGEST> (regnum, val);

If we declare raw_supply a little bit differently (see below), we can do

   regcache->raw_supply (regnum, val);

>  }
>
>  /* Unpack an elf_gregset_t into GDB's register cache.  */
> @@ -460,14 +459,9 @@ mips64_fill_gregset (const struct regcache *regcache,
>
>    if (regaddr != -1)
>      {
> -      gdb_byte buf[MAX_REGISTER_SIZE];
> -      LONGEST val;
> -
> -      regcache_raw_collect (regcache, regno, buf);
> -      val = extract_signed_integer (buf, register_size (gdbarch, regno),
> -				    byte_order);
> +      LONGEST val = regcache->raw_collect<LONGEST> (regno);
>        dst = regp + regaddr;
> -      store_signed_integer ((gdb_byte *) dst, 8, byte_order, val);
> +      store_integer<LONGEST> ((gdb_byte *) dst, 8, byte_order, val);

Likewise,

        store_integer ((gdb_byte *) dst, 8, byte_order, val);

>      }
>  }
>

> diff --git a/gdb/regcache.h b/gdb/regcache.h
> index 4dcfccbac70f0f962bf5e5596d035fda42322795..1ec8b98aa79c58c413786351a715ee46a0f5d5c2 100644
> --- a/gdb/regcache.h
> +++ b/gdb/regcache.h
> @@ -21,6 +21,7 @@
>  #define REGCACHE_H
>
>  #include "common-regcache.h"
> +#include "defs.h"
>
>  struct regcache;
>  struct regset;
> @@ -294,8 +295,12 @@ public:
>
>    void raw_collect (int regnum, void *buf) const;
>
> +  template<typename T> LongType<T> raw_collect (int regnum) const;
> +
>    void raw_supply (int regnum, const void *buf);
>
> +  template<typename T> void raw_supply (int regnum, LongType<T> val);
> +

Similarly, we can do

  template<typename T>
  typename std::enable_if<(std::is_same<T, LONGEST>::value
			   || std::is_same<T, ULONGEST>::value),
			  void>::type
  raw_supply (int regnum, T val);

so that we don't need to explicit instantiate it.

>    void raw_supply_zeroed (int regnum);
>
>    void raw_copy (int regnum, struct regcache *src_regcache);
> diff --git a/gdb/regcache.c b/gdb/regcache.c
> index 957b265c28d929376c3b7d8c100ea355d8292b94..4facc6b55e2bd08972cce1081b27e669103b6717 100644
> --- a/gdb/regcache.c
> +++ b/gdb/regcache.c
> @@ -1208,6 +1208,31 @@ regcache::raw_supply (int regnum, const void *buf)
>      }
>  }
>
> +/* Supply register REGNUM, whose contents are stored in VAL, to
> +   REGCACHE.  */
> +
> +template<typename T>
> +void
> +regcache::raw_supply (int regnum, LongType<T> val)
> +{
> +  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
> +  gdb_byte *regbuf;
> +  size_t size;
> +
> +  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
> +  gdb_assert (!m_readonly_p);
> +
> +  regbuf = register_buffer (regnum);
> +  size = m_descr->sizeof_register[regnum];
> +
> +  store_integer<T> (regbuf, size, byte_order, val);
> +  m_register_status[regnum] = REG_VALID;
> +}

Again, why don't you put it in regcache.h?
  

Patch

diff --git a/gdb/defs.h b/gdb/defs.h
index a0b586f401eca205334e9f237081f4da97c83aa1..45c02f89d9c7a6326a82a6eaaf7d226175e24513 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -627,6 +627,11 @@  enum symbol_needs_kind
   SYMBOL_NEEDS_FRAME
 };

+template<typename T>
+using LongType = typename std::enable_if<(std::is_same<T, LONGEST>::value
+					  || std::is_same<T, ULONGEST>::value),
+					 T>::type;
+
 /* Dynamic target-system-dependent parameters for GDB.  */
 #include "gdbarch.h"

@@ -637,11 +642,21 @@  enum { MAX_REGISTER_SIZE = 64 };

 /* In findvar.c.  */

-extern LONGEST extract_signed_integer (const gdb_byte *, int,
-				       enum bfd_endian);
+template<typename T> LongType<T> extract_integer (const gdb_byte *addr,
+						  int len,
+						  enum bfd_endian byte_order);
+
+inline LONGEST extract_signed_integer (const gdb_byte *addr, int len,
+				       enum bfd_endian byte_order)
+{
+  return extract_integer<LONGEST> (addr, len, byte_order);
+}

-extern ULONGEST extract_unsigned_integer (const gdb_byte *, int,
-					  enum bfd_endian);
+inline ULONGEST extract_unsigned_integer (const gdb_byte *addr, int len,
+					  enum bfd_endian byte_order)
+{
+  return extract_integer<LONGEST> (addr, len, byte_order);
+}

 extern int extract_long_unsigned_integer (const gdb_byte *, int,
 					  enum bfd_endian, LONGEST *);
@@ -649,11 +664,21 @@  extern int extract_long_unsigned_integer (const gdb_byte *, int,
 extern CORE_ADDR extract_typed_address (const gdb_byte *buf,
 					struct type *type);

-extern void store_signed_integer (gdb_byte *, int,
-				  enum bfd_endian, LONGEST);
+template<typename T> void store_integer (gdb_byte *addr, int len,
+					 enum bfd_endian byte_order,
+					 LongType<T> val);

-extern void store_unsigned_integer (gdb_byte *, int,
-				    enum bfd_endian, ULONGEST);
+inline void store_signed_integer (gdb_byte *addr, int len,
+				  enum bfd_endian byte_order, LONGEST val)
+{
+  store_integer<LONGEST> (addr, len, byte_order, val);
+}
+
+inline void store_unsigned_integer (gdb_byte *addr, int len,
+				    enum bfd_endian byte_order, ULONGEST val)
+{
+  store_integer<ULONGEST> (addr, len, byte_order, val);
+}

 extern void store_typed_address (gdb_byte *buf, struct type *type,
 				 CORE_ADDR addr);
diff --git a/gdb/findvar.c b/gdb/findvar.c
index ed4d5c1266c9de069981b306bc8229ae5fb02350..3bcc98ce3421cb800fc8222535b16ca94ee043da 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -46,70 +46,54 @@ 
 you lose
 #endif

-LONGEST
-extract_signed_integer (const gdb_byte *addr, int len,
-			enum bfd_endian byte_order)
+template<typename T>
+LongType<T>
+extract_integer (const gdb_byte *addr, int len, enum bfd_endian byte_order)
 {
-  LONGEST retval;
+  T retval;
   const unsigned char *p;
   const unsigned char *startaddr = addr;
   const unsigned char *endaddr = startaddr + len;

-  if (len > (int) sizeof (LONGEST))
+  if (len > (int) sizeof (T))
     error (_("\
 That operation is not available on integers of more than %d bytes."),
-	   (int) sizeof (LONGEST));
+	   (int) sizeof (T));

   /* Start at the most significant end of the integer, and work towards
      the least significant.  */
   if (byte_order == BFD_ENDIAN_BIG)
     {
       p = startaddr;
-      /* Do the sign extension once at the start.  */
-      retval = ((LONGEST) * p ^ 0x80) - 0x80;
-      for (++p; p < endaddr; ++p)
+      if (std::is_signed<T>::value)
+	{
+	  /* Do the sign extension once at the start.  */
+	  retval = ((LONGEST) * p ^ 0x80) - 0x80;
+	  ++p;
+	}
+      for (; p < endaddr; ++p)
 	retval = (retval << 8) | *p;
     }
   else
     {
       p = endaddr - 1;
-      /* Do the sign extension once at the start.  */
-      retval = ((LONGEST) * p ^ 0x80) - 0x80;
-      for (--p; p >= startaddr; --p)
+      if (std::is_signed<T>::value)
+	{
+	  /* Do the sign extension once at the start.  */
+	  retval = ((LONGEST) * p ^ 0x80) - 0x80;
+	  --p;
+	}
+      for (; p >= startaddr; --p)
 	retval = (retval << 8) | *p;
     }
   return retval;
 }

-ULONGEST
-extract_unsigned_integer (const gdb_byte *addr, int len,
-			  enum bfd_endian byte_order)
-{
-  ULONGEST retval;
-  const unsigned char *p;
-  const unsigned char *startaddr = addr;
-  const unsigned char *endaddr = startaddr + len;
+template LongType<ULONGEST> extract_integer<ULONGEST>
+  (const gdb_byte *addr, int len, enum bfd_endian byte_order);

-  if (len > (int) sizeof (ULONGEST))
-    error (_("\
-That operation is not available on integers of more than %d bytes."),
-	   (int) sizeof (ULONGEST));
-
-  /* Start at the most significant end of the integer, and work towards
-     the least significant.  */
-  retval = 0;
-  if (byte_order == BFD_ENDIAN_BIG)
-    {
-      for (p = startaddr; p < endaddr; ++p)
-	retval = (retval << 8) | *p;
-    }
-  else
-    {
-      for (p = endaddr - 1; p >= startaddr; --p)
-	retval = (retval << 8) | *p;
-    }
-  return retval;
-}
+template LongType<LONGEST> extract_integer<LONGEST>
+  (const gdb_byte *addr, int len, enum bfd_endian byte_order);

 /* Sometimes a long long unsigned integer can be extracted as a
    LONGEST value.  This is done so that we can print these values
@@ -180,9 +164,10 @@  extract_typed_address (const gdb_byte *buf, struct type *type)
 /* All 'store' functions accept a host-format integer and store a
    target-format integer at ADDR which is LEN bytes long.  */

+template<typename T>
 void
-store_signed_integer (gdb_byte *addr, int len,
-		      enum bfd_endian byte_order, LONGEST val)
+store_integer (gdb_byte *addr, int len, enum bfd_endian byte_order,
+	       LongType<T> val)
 {
   gdb_byte *p;
   gdb_byte *startaddr = addr;
@@ -208,33 +193,12 @@  store_signed_integer (gdb_byte *addr, int len,
     }
 }

-void
-store_unsigned_integer (gdb_byte *addr, int len,
-			enum bfd_endian byte_order, ULONGEST val)
-{
-  unsigned char *p;
-  unsigned char *startaddr = (unsigned char *) addr;
-  unsigned char *endaddr = startaddr + len;
-
-  /* Start at the least significant end of the integer, and work towards
-     the most significant.  */
-  if (byte_order == BFD_ENDIAN_BIG)
-    {
-      for (p = endaddr - 1; p >= startaddr; --p)
-	{
-	  *p = val & 0xff;
-	  val >>= 8;
-	}
-    }
-  else
-    {
-      for (p = startaddr; p < endaddr; ++p)
-	{
-	  *p = val & 0xff;
-	  val >>= 8;
-	}
-    }
-}
+template void store_integer<ULONGEST> (gdb_byte *addr, int len,
+				       enum bfd_endian byte_order,
+				       LongType<ULONGEST> val);
+template void store_integer<LONGEST> (gdb_byte *addr, int len,
+				      enum bfd_endian byte_order,
+				      LongType<LONGEST> val);

 /* Store the address ADDR as a pointer of type TYPE at BUF, in target
    form.  */
diff --git a/gdb/mips-fbsd-tdep.c b/gdb/mips-fbsd-tdep.c
index 00fae0ec60ddc9e645d3236efe29f2f9e9ceab5c..1e391bfd16864d9d45f3b6e0de425aa5543515df 100644
--- a/gdb/mips-fbsd-tdep.c
+++ b/gdb/mips-fbsd-tdep.c
@@ -48,9 +48,9 @@ 
 #define MIPS_FBSD_NUM_FPREGS	34

 /* Supply a single register.  If the source register size matches the
-   size the regcache expects, this can use regcache_raw_supply().  If
+   size the regcache expects, this can use regcache->raw_supply ().  If
    they are different, this copies the source register into a buffer
-   that can be passed to regcache_raw_supply().  */
+   that can be passed to regcache->raw_supply ().  */

 static void
 mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
@@ -63,20 +63,17 @@  mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
   else
     {
       enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-      gdb_byte buf[MAX_REGISTER_SIZE];
       LONGEST val;

-      val = extract_signed_integer ((const gdb_byte *) addr, len, byte_order);
-      store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
-			    val);
-      regcache_raw_supply (regcache, regnum, buf);
+      val = extract_integer<LONGEST> ((const gdb_byte *) addr, len, byte_order);
+      regcache->raw_supply<LONGEST> (regnum, val);
     }
 }

 /* Collect a single register.  If the destination register size
    matches the size the regcache expects, this can use
-   regcache_raw_supply().  If they are different, this fetches the
-   register via regcache_raw_supply() into a buffer and then copies it
+   regcache->raw_supply ().  If they are different, this fetches the
+   register via regcache->raw_supply () into a buffer and then copies it
    into the final destination.  */

 static void
@@ -90,13 +87,8 @@  mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
   else
     {
       enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-      gdb_byte buf[MAX_REGISTER_SIZE];
-      LONGEST val;
-
-      regcache_raw_collect (regcache, regnum, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regnum),
-				    byte_order);
-      store_signed_integer ((gdb_byte *) addr, len, byte_order, val);
+      LONGEST val = regcache->raw_collect<LONGEST> (regnum);
+      store_integer<LONGEST> ((gdb_byte *) addr, len, byte_order, val);
     }
 }

diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 48a582a16c934abe6e8f87c46a6009649c606d49..bac106ed5e9e5d89285420beb52b33d6ce36265a 100644
--- a/gdb/mips-linux-tdep.c
+++ b/gdb/mips-linux-tdep.c
@@ -118,11 +118,10 @@  supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  gdb_byte buf[MAX_REGISTER_SIZE];
-  store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
-			extract_signed_integer ((const gdb_byte *) addr, 4,
-						byte_order));
-  regcache_raw_supply (regcache, regnum, buf);
+  LONGEST val;
+
+  val = extract_integer<LONGEST> ((const gdb_byte *) addr, 4, byte_order);
+  regcache->raw_supply<LONGEST> (regnum, val);
 }

 /* Unpack an elf_gregset_t into GDB's register cache.  */
@@ -460,14 +459,9 @@  mips64_fill_gregset (const struct regcache *regcache,

   if (regaddr != -1)
     {
-      gdb_byte buf[MAX_REGISTER_SIZE];
-      LONGEST val;
-
-      regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno),
-				    byte_order);
+      LONGEST val = regcache->raw_collect<LONGEST> (regno);
       dst = regp + regaddr;
-      store_signed_integer ((gdb_byte *) dst, 8, byte_order, val);
+      store_integer<LONGEST> ((gdb_byte *) dst, 8, byte_order, val);
     }
 }

@@ -564,25 +558,15 @@  mips64_fill_fpregset (const struct regcache *regcache,
     }
   else if (regno == mips_regnum (gdbarch)->fp_control_status)
     {
-      gdb_byte buf[MAX_REGISTER_SIZE];
-      LONGEST val;
-
-      regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno),
-				    byte_order);
+      LONGEST val = regcache->raw_collect<LONGEST> (regno);
       to = (gdb_byte *) (*fpregsetp + 32);
-      store_signed_integer (to, 4, byte_order, val);
+      store_integer<LONGEST> (to, 4, byte_order, val);
     }
   else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
     {
-      gdb_byte buf[MAX_REGISTER_SIZE];
-      LONGEST val;
-
-      regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno),
-				    byte_order);
+      LONGEST val = regcache->raw_collect<LONGEST> (regno);
       to = (gdb_byte *) (*fpregsetp + 32) + 4;
-      store_signed_integer (to, 4, byte_order, val);
+      store_integer<LONGEST> (to, 4, byte_order, val);
     }
   else if (regno == -1)
     {
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 4dcfccbac70f0f962bf5e5596d035fda42322795..1ec8b98aa79c58c413786351a715ee46a0f5d5c2 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -21,6 +21,7 @@ 
 #define REGCACHE_H

 #include "common-regcache.h"
+#include "defs.h"

 struct regcache;
 struct regset;
@@ -294,8 +295,12 @@  public:

   void raw_collect (int regnum, void *buf) const;

+  template<typename T> LongType<T> raw_collect (int regnum) const;
+
   void raw_supply (int regnum, const void *buf);

+  template<typename T> void raw_supply (int regnum, LongType<T> val);
+
   void raw_supply_zeroed (int regnum);

   void raw_copy (int regnum, struct regcache *src_regcache);
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 957b265c28d929376c3b7d8c100ea355d8292b94..4facc6b55e2bd08972cce1081b27e669103b6717 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -1208,6 +1208,31 @@  regcache::raw_supply (int regnum, const void *buf)
     }
 }

+/* Supply register REGNUM, whose contents are stored in VAL, to
+   REGCACHE.  */
+
+template<typename T>
+void
+regcache::raw_supply (int regnum, LongType<T> val)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+  gdb_byte *regbuf;
+  size_t size;
+
+  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+  gdb_assert (!m_readonly_p);
+
+  regbuf = register_buffer (regnum);
+  size = m_descr->sizeof_register[regnum];
+
+  store_integer<T> (regbuf, size, byte_order, val);
+  m_register_status[regnum] = REG_VALID;
+}
+
+template void regcache::raw_supply<ULONGEST> (int regnum,
+					      LongType<ULONGEST> val);
+template void regcache::raw_supply<LONGEST> (int regnum, LongType<LONGEST> val);
+
 /* Supply register REGNUM with zeroed value to REGCACHE.  This is not the same
    as calling raw_supply with NULL (which will set the state to
    unavailable).  */
@@ -1251,6 +1276,30 @@  regcache::raw_collect (int regnum, void *buf) const
   memcpy (buf, regbuf, size);
 }

+/* Collect register REGNUM from REGCACHE and extract its contents into a
+   LONGEST.  */
+
+template<typename T>
+LongType<T> regcache::raw_collect (int regnum) const
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+  const gdb_byte *regbuf;
+  size_t size;
+
+  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+
+  regbuf = register_buffer (regnum);
+  size = m_descr->sizeof_register[regnum];
+
+  if (std::is_signed<T>::value)
+    return extract_signed_integer (regbuf, size, byte_order);
+  else
+    return extract_unsigned_integer (regbuf, size, byte_order);
+}
+
+template LongType<ULONGEST> regcache::raw_collect<ULONGEST> (int regnum) const;
+template LongType<LONGEST> regcache::raw_collect<LONGEST> (int regnum) const;
+
 void
 regcache::raw_copy (int regnum, struct regcache *src_regcache)
 {