diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h
index 79f5ec622d4..68297a8b73e 100644
--- a/gdb/arch/riscv.h
+++ b/gdb/arch/riscv.h
@@ -46,19 +46,10 @@ struct riscv_gdbarch_features
      that there are no f-registers.  No other value is valid.  */
   int flen = 0;
 
-  /* This indicates if hardware floating point abi is in use.  If the FLEN
-     field is 0 then this value _must_ be false.  If the FLEN field is
-     non-zero and this field is false then this indicates the target has
-     floating point registers, but is still using the soft-float abi.  If
-     this field is true then the hardware floating point abi is in use, and
-     values are passed in f-registers matching the size of FLEN.  */
-  bool hw_float_abi = false;
-
   /* Equality operator.  */
   bool operator== (const struct riscv_gdbarch_features &rhs) const
   {
-    return (xlen == rhs.xlen && flen == rhs.flen
-	    && hw_float_abi == rhs.hw_float_abi);
+    return (xlen == rhs.xlen && flen == rhs.flen);
   }
 
   /* Inequality operator.  */
@@ -70,9 +61,7 @@ struct riscv_gdbarch_features
   /* Used by std::unordered_map to hash feature sets.  */
   std::size_t hash () const noexcept
   {
-    std::size_t val = ((xlen & 0x1f) << 6
-                       | (flen & 0x1f) << 1
-                       | (hw_float_abi ? 1 : 0));
+    std::size_t val = ((xlen & 0x1f) << 5 | (flen & 0x1f) << 0);
     return val;
   }
 };
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 88b79af866f..aeb9f2e5627 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -361,7 +361,18 @@ static unsigned int riscv_debug_gdbarch = 0;
 int
 riscv_isa_xlen (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->features.xlen;
+  return gdbarch_tdep (gdbarch)->isa_features.xlen;
+}
+
+/* Return the x-register length that is being used for the abi.  This
+   exists only so we have similar interfaces for flen and xlen, however,
+   this always calls RISCV_ISA_XLEN, as running a binary compiled for RV32
+   on an RV64 target doesn't make sense.  */
+
+static int
+riscv_abi_xlen (struct gdbarch *gdbarch)
+{
+  return riscv_isa_xlen (gdbarch);
 }
 
 /* See riscv-tdep.h.  */
@@ -369,7 +380,15 @@ riscv_isa_xlen (struct gdbarch *gdbarch)
 int
 riscv_isa_flen (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->features.flen;
+  return gdbarch_tdep (gdbarch)->isa_features.flen;
+}
+
+/* See riscv-tdep.h.  */
+
+int
+riscv_abi_flen (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep (gdbarch)->abi_features.flen;
 }
 
 /* Return true if the target for GDBARCH has floating point hardware.  */
@@ -385,7 +404,7 @@ riscv_has_fp_regs (struct gdbarch *gdbarch)
 static bool
 riscv_has_fp_abi (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->features.hw_float_abi;
+  return gdbarch_tdep (gdbarch)->abi_features.flen > 0;
 }
 
 /* Return true if REGNO is a floating pointer register.  */
@@ -1777,8 +1796,8 @@ struct riscv_call_info
     : int_regs (RISCV_A0_REGNUM, RISCV_A0_REGNUM + 7),
       float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7)
   {
-    xlen = riscv_isa_xlen (gdbarch);
-    flen = riscv_isa_flen (gdbarch);
+    xlen = riscv_abi_xlen (gdbarch);
+    flen = riscv_abi_flen (gdbarch);
 
     /* Disable use of floating point registers if needed.  */
     if (!riscv_has_fp_abi (gdbarch))
@@ -1798,7 +1817,7 @@ struct riscv_call_info
   struct riscv_arg_reg float_regs;
 
   /* The XLEN and FLEN are copied in to this structure for convenience, and
-     are just the results of calling RISCV_ISA_XLEN and RISCV_ISA_FLEN.  */
+     are just the results of calling RISCV_ABI_XLEN and RISCV_ABI_FLEN.  */
   int xlen;
   int flen;
 };
@@ -2139,9 +2158,6 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
 	{
 	  int len0, len1, offset;
 
-	  gdb_assert (TYPE_LENGTH (ainfo->type)
-		      <= (cinfo->flen + cinfo->xlen));
-
 	  len0 = TYPE_LENGTH (sinfo.field_type (0));
 	  if (!riscv_assign_reg_location (&ainfo->argloc[0],
 					  &cinfo->float_regs, len0, 0))
@@ -2165,9 +2181,6 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
 	{
 	  int len0, len1, offset;
 
-	  gdb_assert (TYPE_LENGTH (ainfo->type)
-		      <= (cinfo->flen + cinfo->xlen));
-
 	  len0 = TYPE_LENGTH (sinfo.field_type (0));
 	  len1 = TYPE_LENGTH (sinfo.field_type (1));
 	  offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1)));
@@ -2827,15 +2840,9 @@ riscv_features_from_gdbarch_info (const struct gdbarch_info info)
 			_("unknown ELF header class %d"), eclass);
 
       if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
-	{
-	  features.flen = 8;
-	  features.hw_float_abi = true;
-	}
+	features.flen = 8;
       else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
-	{
-	  features.flen = 4;
-	  features.hw_float_abi = true;
-	}
+	features.flen = 4;
     }
   else
     {
@@ -3039,25 +3046,25 @@ riscv_gdbarch_init (struct gdbarch_info info,
   /* Have a look at what the supplied (if any) bfd object requires of the
      target, then check that this matches with what the target is
      providing.  */
-  struct riscv_gdbarch_features info_features
+  struct riscv_gdbarch_features abi_features
     = riscv_features_from_gdbarch_info (info);
-  if (info_features.xlen != 0 && info_features.xlen != features.xlen)
+  if (abi_features.xlen != 0 && abi_features.xlen != features.xlen)
     error (_("bfd requires xlen %d, but target has xlen %d"),
-           info_features.xlen, features.xlen);
-  if (info_features.flen != 0 && info_features.flen != features.flen)
+            abi_features.xlen, features.xlen);
+  /* Unlike the x-register case, running a binary compiled for the 32-bit
+     float abi should work fine on a target with 64-bit (or more) floating
+     point hardware.  As a result, we only complain if the ABI_FEATURES
+     requires more than the target has to offer.  */
+  if (abi_features.flen > features.flen)
     error (_("bfd requires flen %d, but target has flen %d"),
-           info_features.flen, features.flen);
-
-  /* If the xlen from INFO_FEATURES is 0 then this indicates either there
-     is no bfd object, or nothing useful could be extracted from it, in
-     this case we enable hardware float abi if the target has floating
-     point registers.
+            abi_features.flen, features.flen);
 
-     If the xlen from INFO_FEATURES is not 0, and the flen in
-     INFO_FEATURES is also not 0, then this indicates that the supplied
-     bfd does require hardware floating point abi.  */
-  if (info_features.xlen == 0 || info_features.flen != 0)
-    features.hw_float_abi = (features.flen > 0);
+  /* If the ABI_FEATURES xlen is 0 then this indicates we got no useful abi
+     features from the INFO object.  In this case we assume that the xlen
+     abi matches the hardware type.  If we had gotten anything useful from
+     INFO then this would have been enforced above.  */
+  if (abi_features.xlen == 0)
+    abi_features.xlen = features.xlen;
 
   /* Find a candidate among the list of pre-declared architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
@@ -3069,7 +3076,8 @@ riscv_gdbarch_init (struct gdbarch_info info,
          gdbarch.  */
       struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
 
-      if (other_tdep->features != features)
+      if (other_tdep->isa_features != features
+	  || other_tdep->abi_features != abi_features)
         continue;
 
       break;
@@ -3084,7 +3092,8 @@ riscv_gdbarch_init (struct gdbarch_info info,
   /* None found, so create a new architecture from the information provided.  */
   tdep = new (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
-  tdep->features = features;
+  tdep->isa_features = features;
+  tdep->abi_features = abi_features;
 
   /* Target data types.  */
   set_gdbarch_short_bit (gdbarch, 16);
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index 59ad37df6ce..bfb65c002fa 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -59,9 +59,14 @@ enum
 /* RISC-V specific per-architecture information.  */
 struct gdbarch_tdep
 {
-  /* Features about the target that impact how the gdbarch is configured.
-     Two gdbarch instances are compatible only if this field matches.  */
-  struct riscv_gdbarch_features features;
+  /* Features about the target hardware that impact how the gdbarch is
+     configured.  Two gdbarch instances are compatible only if this field
+     matches.  */
+  struct riscv_gdbarch_features isa_features;
+
+  /* Features about the abi that impact how the gdbarch is configured.  Two
+     gdbarch instances are compatible only if this field matches.  */
+  struct riscv_gdbarch_features abi_features;
 
   /* ISA-specific data types.  */
   struct type *riscv_fpreg_d_type = nullptr;
@@ -73,12 +78,22 @@ struct gdbarch_tdep
    RV128.  */
 extern int riscv_isa_xlen (struct gdbarch *gdbarch);
 
-/* Return the width in bytes of the floating point registers for GDBARCH.
-   If this architecture has no floating point registers, then return 0.
-   Possible values are 4, 8, or 16 for depending on which of single, double
-   or quad floating point support is available.  */
+/* Return the width in bytes of the hardware floating point registers for
+   GDBARCH.  If this architecture has no floating point registers, then
+   return 0.  Possible values are 4, 8, or 16 for depending on which of
+   single, double or quad floating point support is available.  */
 extern int riscv_isa_flen (struct gdbarch *gdbarch);
 
+/* Return the width in bytes of the floating point register abi for
+   GDBARCH.  This reflects how the binary was compiled rather than the
+   hardware that is available.  It is possible that a binary is compiled
+   for single precision floating point, and then run on a target with
+   double precision floating point.  A return value of 0 indicates that no
+   floating point abi is in use (floating point arguments will be passed
+   in integer registers) other possible return value are 4, 8, or 16 as
+   with RISCV_ISA_FLEN.  */
+extern int riscv_abi_flen (struct gdbarch *gdbarch);
+
 /* Single step based on where the current instruction will take us.  */
 extern std::vector<CORE_ADDR> riscv_software_single_step
   (struct regcache *regcache);
