diff --git a/gdb/defs.h b/gdb/defs.h
index a0b586f401eca205334e9f237081f4da97c83aa1..010fe55a4760ebc7a420115e7590199fcab899a0 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,69 @@ enum { MAX_REGISTER_SIZE = 64 };

 /* In findvar.c.  */

-extern LONGEST extract_signed_integer (const gdb_byte *, int,
-				       enum bfd_endian);
+/* All 'extract' functions return a host-format integer from a target-format
+   integer at ADDR which is LEN bytes long.  */

-extern ULONGEST extract_unsigned_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)
+{
+  T retval = 0;
+  const unsigned char *p;
+  const unsigned char *startaddr = addr;
+  const unsigned char *endaddr = startaddr + len;
+
+  if (len > (int) sizeof (T))
+    error (_("\
+That operation is not available on integers of more than %d bytes."),
+	   (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;
+      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;
+      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;
+}
+
+template LongType<ULONGEST> extract_integer<ULONGEST>
+  (const gdb_byte *addr, int len, enum bfd_endian byte_order);
+
+template LongType<LONGEST> extract_integer<LONGEST>
+  (const gdb_byte *addr, int len, enum bfd_endian byte_order);
+
+inline ULONGEST extract_unsigned_integer (const gdb_byte *addr, int len,
+					  enum bfd_endian byte_order)
+{
+  return extract_integer<ULONGEST> (addr, len, 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 int extract_long_unsigned_integer (const gdb_byte *, int,
 					  enum bfd_endian, LONGEST *);
@@ -649,11 +712,58 @@ 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);
+/* All 'store' functions accept a host-format integer and store a
+   target-format integer at ADDR which is LEN bytes long.  */

-extern void store_unsigned_integer (gdb_byte *, int,
-				    enum bfd_endian, ULONGEST);
+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)
+{
+  gdb_byte *p;
+  gdb_byte *startaddr = addr;
+  gdb_byte *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 (gdb_byte *addr, int len,
+				       enum bfd_endian byte_order,
+				       LongType<ULONGEST> val);
+template void store_integer (gdb_byte *addr, int len,
+				      enum bfd_endian byte_order,
+				      LongType<LONGEST> val);
+
+inline void store_signed_integer (gdb_byte *addr, int len,
+				  enum bfd_endian byte_order, LONGEST val)
+{
+  store_integer (addr, len, byte_order, val);
+}
+
+inline void store_unsigned_integer (gdb_byte *addr, int len,
+				    enum bfd_endian byte_order, ULONGEST val)
+{
+  store_integer (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..614d1291eac5a7438a1bf3f6dd0b5d012a0dfaa7 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -34,9 +34,7 @@
 #include "language.h"
 #include "dwarf2loc.h"

-/* Basic byte-swapping routines.  All 'extract' functions return a
-   host-format integer from a target-format integer at ADDR which is
-   LEN bytes long.  */
+/* Basic byte-swapping routines.  */

 #if TARGET_CHAR_BIT != 8 || HOST_CHAR_BIT != 8
   /* 8 bit characters are a pretty safe assumption these days, so we
@@ -46,70 +44,6 @@
 you lose
 #endif

-LONGEST
-extract_signed_integer (const gdb_byte *addr, int len,
-			enum bfd_endian byte_order)
-{
-  LONGEST retval;
-  const unsigned char *p;
-  const unsigned char *startaddr = addr;
-  const unsigned char *endaddr = startaddr + len;
-
-  if (len > (int) sizeof (LONGEST))
-    error (_("\
-That operation is not available on integers of more than %d bytes."),
-	   (int) sizeof (LONGEST));
-
-  /* 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)
-	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)
-	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;
-
-  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;
-}

 /* Sometimes a long long unsigned integer can be extracted as a
    LONGEST value.  This is done so that we can print these values
@@ -177,65 +111,6 @@ extract_typed_address (const gdb_byte *buf, struct type *type)
   return gdbarch_pointer_to_address (get_type_arch (type), type, buf);
 }

-/* All 'store' functions accept a host-format integer and store a
-   target-format integer at ADDR which is LEN bytes long.  */
-
-void
-store_signed_integer (gdb_byte *addr, int len,
-		      enum bfd_endian byte_order, LONGEST val)
-{
-  gdb_byte *p;
-  gdb_byte *startaddr = addr;
-  gdb_byte *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;
-	}
-    }
-}
-
-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;
-	}
-    }
-}
-
 /* Store the address ADDR as a pointer of type TYPE at BUF, in target
    form.  */
 void
diff --git a/gdb/mips-fbsd-tdep.c b/gdb/mips-fbsd-tdep.c
index 00fae0ec60ddc9e645d3236efe29f2f9e9ceab5c..7278fb71e3ad1f18d35cd696832d99bf90198620 100644
--- a/gdb/mips-fbsd-tdep.c
+++ b/gdb/mips-fbsd-tdep.c
@@ -48,9 +48,8 @@
 #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
-   they are different, this copies the source register into a buffer
-   that can be passed to regcache_raw_supply().  */
+   size the regcache expects, this can use regcache->raw_supply ().  If
+   they are different, this can use regcache->raw_supply_integer ().  */

 static void
 mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
@@ -59,25 +58,16 @@ mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
   struct gdbarch *gdbarch = get_regcache_arch (regcache);

   if (register_size (gdbarch, regnum) == len)
-    regcache_raw_supply (regcache, regnum, addr);
+    regcache->raw_supply (regnum, 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);
-    }
+    regcache->raw_supply_integer<LONGEST> (regnum, (const gdb_byte *) addr,
+					   len);
 }

 /* 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
-   into the final destination.  */
+   regcache->raw_collect ().  If they are different, this can use
+   regcache->raw_collect_integer ().  */

 static void
 mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
@@ -86,18 +76,9 @@ mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
   struct gdbarch *gdbarch = get_regcache_arch (regcache);

   if (register_size (gdbarch, regnum) == len)
-    regcache_raw_collect (regcache, regnum, addr);
+    regcache->raw_collect (regnum, 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);
-    }
+    regcache->raw_collect_integer<LONGEST> (regnum, (gdb_byte *) addr, len);
 }

 /* Supply the floating-point registers stored in FPREGS to REGCACHE.
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 48a582a16c934abe6e8f87c46a6009649c606d49..b30fe294a0bbbb815418e65149a88f59eb15befb 100644
--- a/gdb/mips-linux-tdep.c
+++ b/gdb/mips-linux-tdep.c
@@ -116,13 +116,7 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 static void
 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);
+  regcache->raw_supply_integer<LONGEST> (regnum, (const gdb_byte *) addr, 4);
 }

 /* Unpack an elf_gregset_t into GDB's register cache.  */
@@ -417,7 +411,6 @@ mips64_fill_gregset (const struct regcache *regcache,
 		     mips64_elf_gregset_t *gregsetp, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int regaddr, regi;
   mips64_elf_greg_t *regp = *gregsetp;
   void *dst;
@@ -460,14 +453,8 @@ 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);
       dst = regp + regaddr;
-      store_signed_integer ((gdb_byte *) dst, 8, byte_order, val);
+      regcache->raw_collect_integer<LONGEST> (regno, (gdb_byte *) dst, 8);
     }
 }

@@ -564,25 +551,13 @@ 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);
       to = (gdb_byte *) (*fpregsetp + 32);
-      store_signed_integer (to, 4, byte_order, val);
+      regcache->raw_collect_integer<LONGEST> (regno, to, 4);
     }
   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);
       to = (gdb_byte *) (*fpregsetp + 32) + 4;
-      store_signed_integer (to, 4, byte_order, val);
+      regcache->raw_collect_integer<LONGEST> (regno, to, 4);
     }
   else if (regno == -1)
     {
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 4dcfccbac70f0f962bf5e5596d035fda42322795..c47401948270b1c75d9d3b02cbbc3256db85f84e 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -294,8 +294,20 @@ public:

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

+  template<typename T>
+  typename std::enable_if<(std::is_same<T, LONGEST>::value
+			 || std::is_same<T, ULONGEST>::value),
+			void>::type
+  raw_collect_integer (int regnum, gdb_byte *addr, int addr_len) const;
+
   void raw_supply (int regnum, const void *buf);

+  template<typename T>
+  typename std::enable_if<(std::is_same<T, LONGEST>::value
+			   || std::is_same<T, ULONGEST>::value),
+			   void>::type
+  raw_supply_integer (int regnum, const gdb_byte *addr, int addr_len);
+
   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 660558f7ff10f9d8346b6e08422e16c38c3c4d7d..cc9ab74b087cbda2d79264674e9b463e1528363f 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -1189,6 +1189,39 @@ regcache::raw_supply (int regnum, const void *buf)
     }
 }

+/* Supply register REGNUM, whose contents are stored in ADDR, with length
+   ADDR_LEN to a (U)LONGEST, then store to REGCACHE, taking BYTE_ORDER into
+   account.  */
+
+template<typename T>
+typename std::enable_if<(std::is_same<T, LONGEST>::value
+			 || std::is_same<T, ULONGEST>::value),
+			void>::type
+regcache::raw_supply_integer (int regnum, const gdb_byte *addr, int addr_len)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+  gdb_byte *regbuf;
+  size_t regsize;
+  T val;
+
+  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+  gdb_assert (!m_readonly_p);
+
+  regbuf = register_buffer (regnum);
+  regsize = m_descr->sizeof_register[regnum];
+
+  val = extract_integer<T> (addr, addr_len, byte_order);
+  store_integer (regbuf, regsize, byte_order, val);
+  m_register_status[regnum] = REG_VALID;
+}
+
+template void regcache::raw_supply_integer<ULONGEST> (int regnum,
+						      const gdb_byte *addr,
+						      int addr_len);
+template void regcache::raw_supply_integer<LONGEST> (int regnum,
+						     const gdb_byte *addr,
+						     int addr_len);
+
 /* 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).  */
@@ -1232,6 +1265,37 @@ regcache::raw_collect (int regnum, void *buf) const
   memcpy (buf, regbuf, size);
 }

+/* Collect register REGNUM from REGCACHE into a (U)LONGEST, then store ADDR_LEN
+   bytes into buffer ADDR, taking BYTE_ORDER into account.  */
+
+template<typename T>
+typename std::enable_if<(std::is_same<T, LONGEST>::value
+			 || std::is_same<T, ULONGEST>::value),
+			void>::type
+regcache::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len) const
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+  const gdb_byte *regbuf;
+  size_t regsize;
+  T val;
+
+  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+
+  regbuf = register_buffer (regnum);
+  regsize = m_descr->sizeof_register[regnum];
+
+  val = extract_integer<T> (regbuf, regsize, byte_order);
+  store_integer (addr, addr_len, byte_order, val);
+}
+
+template void regcache::raw_collect_integer<ULONGEST> (int regnum,
+						       gdb_byte *addr,
+						       int addr_len) const;
+template void regcache::raw_collect_integer<LONGEST> (int regnum,
+						      gdb_byte *addr,
+						      int addr_len) const;
+
+
 void
 regcache::raw_copy (int regnum, struct regcache *src_regcache)
 {
