diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c
index 82c5154b6118..07afc1a365e3 100644
--- a/gcc/common/config/riscv/riscv-common.c
+++ b/gcc/common/config/riscv/riscv-common.c
@@ -79,7 +79,10 @@ private:
   /* X-len of m_arch. */
   unsigned m_xlen;
 
-  riscv_subset_list (const char *, location_t);
+  /* Silent mode, don't emit error if m_silent_p is true.  */
+  bool m_silent_p;
+
+  riscv_subset_list (const char *, location_t, bool);
 
   const char *parsing_subset_version (const char *, unsigned *, unsigned *,
 				      unsigned, unsigned, bool, bool *);
@@ -104,7 +107,7 @@ public:
 
   unsigned xlen() const {return m_xlen;};
 
-  static riscv_subset_list *parse (const char *, location_t);
+  static riscv_subset_list *parse (const char *, location_t, bool silent_p);
 
 };
 
@@ -118,8 +121,11 @@ riscv_subset_t::riscv_subset_t ()
 {
 }
 
-riscv_subset_list::riscv_subset_list (const char *arch, location_t loc)
-  : m_arch (arch), m_loc (loc), m_head (NULL), m_tail (NULL), m_xlen (0)
+riscv_subset_list::riscv_subset_list (const char *arch,
+				      location_t loc,
+				      bool silent_p)
+  : m_arch (arch), m_loc (loc), m_head (NULL), m_tail (NULL),
+    m_xlen (0), m_silent_p(silent_p)
 {
 }
 
@@ -283,8 +289,9 @@ riscv_subset_list::parsing_subset_version (const char *p,
 		}
 	      else
 		{
-		  error_at (m_loc, "%<-march=%s%>: Expect number "
-			    "after %<%dp%>.", m_arch, version);
+		  if (!m_silent_p)
+		    error_at (m_loc, "%<-march=%s%>: Expect number "
+			      "after %<%dp%>.", m_arch, version);
 		  return NULL;
 		}
 	    }
@@ -363,8 +370,9 @@ riscv_subset_list::parse_std_ext (const char *p)
 
       if (m_xlen > 32)
 	{
-	  error_at (m_loc, "%<-march=%s%>: rv%de is not a valid base ISA",
-		    m_arch, m_xlen);
+	  if (!m_silent_p)
+	    error_at (m_loc, "%<-march=%s%>: rv%de is not a valid base ISA",
+		      m_arch, m_xlen);
 	  return NULL;
 	}
       break;
@@ -386,8 +394,9 @@ riscv_subset_list::parse_std_ext (const char *p)
       break;
 
     default:
-      error_at (m_loc, "%<-march=%s%>: first ISA subset must be %<e%>, "
-		"%<i%> or %<g%>", m_arch);
+      if (!m_silent_p)
+	error_at (m_loc, "%<-march=%s%>: first ISA subset must be %<e%>, "
+		  "%<i%> or %<g%>", m_arch);
       return NULL;
     }
 
@@ -412,13 +421,16 @@ riscv_subset_list::parse_std_ext (const char *p)
 
       if (std_ext != *std_exts)
 	{
-	  if (strchr (all_std_exts, std_ext) == NULL)
-	    error_at (m_loc, "%<-march=%s%>: unsupported ISA subset %<%c%>",
-		      m_arch, *p);
-	  else
-	    error_at (m_loc,
-		      "%<-march=%s%>: ISA string is not in canonical order. "
-		      "%<%c%>", m_arch, *p);
+	  if (!m_silent_p)
+	    {
+	      if (strchr (all_std_exts, std_ext) == NULL)
+		error_at (m_loc, "%<-march=%s%>: unsupported ISA subset %<%c%>",
+			  m_arch, *p);
+	      else
+		error_at (m_loc,
+			  "%<-march=%s%>: ISA string is not in canonical order. "
+			  "%<%c%>", m_arch, *p);
+	    }
 	  return NULL;
 	}
 
@@ -522,8 +534,9 @@ riscv_subset_list::parse_multiletter_ext (const char *p,
 
       if (*p != '\0' && *p != '_')
 	{
-	  error_at (m_loc, "%<-march=%s%>: %s must separate with _",
-		    m_arch, ext_type_str);
+	  if (!m_silent_p)
+	    error_at (m_loc, "%<-march=%s%>: %s must separate with _",
+		      m_arch, ext_type_str);
 	  return NULL;
 	}
     }
@@ -534,9 +547,9 @@ riscv_subset_list::parse_multiletter_ext (const char *p,
 /* Parsing arch string to subset list, return NULL if parsing failed.  */
 
 riscv_subset_list *
-riscv_subset_list::parse (const char *arch, location_t loc)
+riscv_subset_list::parse (const char *arch, location_t loc, bool silent_p)
 {
-  riscv_subset_list *subset_list = new riscv_subset_list (arch, loc);
+  riscv_subset_list *subset_list = new riscv_subset_list (arch, loc, silent_p);
   const char *p = arch;
   if (strncmp (p, "rv32", 4) == 0)
     {
@@ -550,8 +563,9 @@ riscv_subset_list::parse (const char *arch, location_t loc)
     }
   else
     {
-      error_at (loc, "%<-march=%s%>: ISA string must begin with rv32 or rv64",
-		arch);
+      if (!silent_p)
+	error_at (loc, "%<-march=%s%>: ISA string must begin with rv32 or rv64",
+		  arch);
       goto fail;
     }
 
@@ -587,8 +601,9 @@ riscv_subset_list::parse (const char *arch, location_t loc)
 
   if (*p != '\0')
     {
-      error_at (loc, "%<-march=%s%>: unexpected ISA string at end: %qs",
-               arch, p);
+      if (!silent_p)
+	error_at (loc, "%<-march=%s%>: unexpected ISA string at end: %qs",
+		  arch, p);
       goto fail;
     }
 
@@ -604,18 +619,23 @@ fail:
 std::string
 riscv_arch_str (bool version_p)
 {
-  gcc_assert (current_subset_list);
-  return current_subset_list->to_string (version_p);
+  if (current_subset_list)
+    return current_subset_list->to_string (version_p);
+  else
+    return std::string();
 }
 
 /* Parse a RISC-V ISA string into an option mask.  Must clear or set all arch
    dependent mask bits, in case more than one -march string is passed.  */
 
 static void
-riscv_parse_arch_string (const char *isa, int *flags, location_t loc)
+riscv_parse_arch_string (const char *isa,
+			 int *flags,
+			 location_t loc,
+			 bool silent_p)
 {
   riscv_subset_list *subset_list;
-  subset_list = riscv_subset_list::parse (isa, loc);
+  subset_list = riscv_subset_list::parse (isa, loc, silent_p);
   if (!subset_list)
     return;
 
@@ -664,7 +684,7 @@ riscv_handle_option (struct gcc_options *opts,
   switch (decoded->opt_index)
     {
     case OPT_march_:
-      riscv_parse_arch_string (decoded->arg, &opts->x_target_flags, loc);
+      riscv_parse_arch_string (decoded->arg, &opts->x_target_flags, loc, false);
       return true;
 
     default:
@@ -678,13 +698,67 @@ const char *
 riscv_expand_arch (int argc ATTRIBUTE_UNUSED,
 		   const char **argv)
 {
-  static char *_arch_buf;
   gcc_assert (argc == 1);
   int flags;
   location_t loc = UNKNOWN_LOCATION;
-  riscv_parse_arch_string (argv[0], &flags, loc);
-  _arch_buf = xstrdup (riscv_arch_str (false).c_str ());
-  return _arch_buf;
+  riscv_parse_arch_string (argv[0], &flags, loc, true);
+  const std::string arch = riscv_arch_str (false);
+  if (arch.length())
+    return xasprintf ("-march=%s", arch.c_str());
+  else
+    return "";
+}
+
+/* Return -mabi option string accroding CURRENT_SUBSET_LIST,
+   return empty string if it's NULL.
+
+   Derivative rule:
+   - Using ilp32e E-extension is present.
+   - Using ilp32d or lp64d if D-extension is present.
+   - Otherwise using ilp32 or lp64.  */
+
+static const char *
+riscv_get_mabi_from_current_subset_list ()
+{
+  if (current_subset_list == NULL)
+    {
+      return "";
+    }
+
+  if (current_subset_list->xlen() == 32)
+    {
+      /* We don't have ilp32ef or ilp32ed.  */
+      if (current_subset_list->lookup ("e"))
+	return "-mabi=ilp32e";
+
+      if (current_subset_list->lookup ("d"))
+	return "-mabi=ilp32d";
+
+      return "-mabi=ilp32";
+    }
+  else
+    {
+      gcc_assert (current_subset_list->xlen() == 64);
+
+      if (current_subset_list->lookup ("d"))
+	return "-mabi=lp64d";
+
+      return "-mabi=lp64";
+    }
+}
+
+/* Derive default -mabi from -march.  */
+
+const char *
+riscv_implied_abi_from_arch (int argc, const char **argv)
+{
+  int flags;
+  location_t loc = UNKNOWN_LOCATION;
+
+  gcc_assert (argc == 1);
+
+  riscv_parse_arch_string (argv[0], &flags, loc, true);
+  return riscv_get_mabi_from_current_subset_list ();
 }
 
 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index b7b4a1c88a52..0c37dbd6f877 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -41,18 +41,20 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 
 extern const char *riscv_expand_arch (int argc, const char **argv);
+extern const char *riscv_implied_abi_from_arch (int argc, const char **argv);
 
 # define EXTRA_SPEC_FUNCTIONS						\
-  { "riscv_expand_arch", riscv_expand_arch },
+  { "riscv_expand_arch", riscv_expand_arch },				\
+  { "riscv_implied_abi_from_arch", riscv_implied_abi_from_arch },
 
 /* Support for a compile-time default CPU, et cetera.  The rules are:
    --with-arch is ignored if -march is specified.
-   --with-abi is ignored if -mabi is specified.
+   --with-abi is ignored if -mabi or -march is specified.
    --with-tune is ignored if -mtune is specified.  */
 #define OPTION_DEFAULT_SPECS \
   {"tune", "%{!mtune=*:-mtune=%(VALUE)}" }, \
   {"arch", "%{!march=*:-march=%(VALUE)}" }, \
-  {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
+  {"abi", "%{!mabi=*:%{!march=*:-mabi=%(VALUE)}}"},
 
 #ifdef IN_LIBGCC2
 #undef TARGET_64BIT
@@ -69,8 +71,9 @@ extern const char *riscv_expand_arch (int argc, const char **argv);
 %(subtarget_asm_spec)"
 
 #undef DRIVER_SELF_SPECS
-#define DRIVER_SELF_SPECS \
-"%{march=*:-march=%:riscv_expand_arch(%*)}"
+#define DRIVER_SELF_SPECS					\
+"%{march=*:%:riscv_expand_arch(%*)}"				\
+"%{!mabi=*:%{march=*:%:riscv_implied_abi_from_arch(%*)}}"
 
 #define TARGET_DEFAULT_CMODEL CM_MEDLOW
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f623467b7637..c6ba738aa0b7 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -25928,7 +25928,14 @@ allows floating-point values up to 32 bits long to be passed in registers; or
 @samp{-march=rv64ifd -mabi=lp64}, in which no floating-point arguments will be
 passed in registers.
 
-The default for this argument is system dependent, users who want a specific
+When @option{-mabi=} is not specified, the default value will derived from
+@option{-march=}, the rules is using @samp{d} ABI variant if D extension is
+enabled, otherwise using soft-float ABI variant even F extension is enabled,
+there is an special rule for @samp{rv32e} variant is it always use
+@samp{ilp32e}.
+
+If @option{-march} and @option{-mabi=} both are not specified, the default for
+this argument is system dependent, users who want a specific
 calling convention should specify one explicitly.  The valid calling
 conventions are: @samp{ilp32}, @samp{ilp32f}, @samp{ilp32d}, @samp{lp64},
 @samp{lp64f}, and @samp{lp64d}.  Some calling conventions are impossible to
diff --git a/gcc/testsuite/gcc.target/riscv/implied-abi-1.c b/gcc/testsuite/gcc.target/riscv/implied-abi-1.c
new file mode 100644
index 000000000000..0ed81d75fadc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/implied-abi-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-mabi given" { *-*-* } { "-mabi=*" } } */
+/* { dg-options "-O -march=rv32i" } */
+#if !(defined(__riscv_float_abi_soft) && (__riscv_xlen == 32))
+#error "Should be ilp32"
+#endif
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/implied-abi-2.c b/gcc/testsuite/gcc.target/riscv/implied-abi-2.c
new file mode 100644
index 000000000000..493990b1cadf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/implied-abi-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-mabi given" { *-*-* } { "-mabi=*" } } */
+/* { dg-options "-O -march=rv32e" } */
+#if !(defined(__riscv_float_abi_soft) && (__riscv_xlen == 32) && defined(__riscv_abi_rve))
+#error "Should be ilp32e"
+#endif
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/implied-abi-3.c b/gcc/testsuite/gcc.target/riscv/implied-abi-3.c
new file mode 100644
index 000000000000..09d64793c4e6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/implied-abi-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-mabi given" { *-*-* } { "-mabi=*" } } */
+/* { dg-options "-O -march=rv32if" } */
+#if !(defined(__riscv_float_abi_soft) && (__riscv_xlen == 32))
+#error "Should be ilp32"
+#endif
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/implied-abi-4.c b/gcc/testsuite/gcc.target/riscv/implied-abi-4.c
new file mode 100644
index 000000000000..432e5646d098
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/implied-abi-4.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-mabi given" { *-*-* } { "-mabi=*" } } */
+/* { dg-options "-O -march=rv32ifd" } */
+#if !(defined(__riscv_float_abi_double) && (__riscv_xlen == 32))
+#error "Should be ilp32d"
+#endif
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/implied-abi-5.c b/gcc/testsuite/gcc.target/riscv/implied-abi-5.c
new file mode 100644
index 000000000000..45e64e91e845
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/implied-abi-5.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-mabi given" { *-*-* } { "-mabi=*" } } */
+/* { dg-options "-O -march=rv64i" } */
+#if !(defined(__riscv_float_abi_soft) && (__riscv_xlen == 64))
+#error "Should be lp64"
+#endif
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/implied-abi-6.c b/gcc/testsuite/gcc.target/riscv/implied-abi-6.c
new file mode 100644
index 000000000000..7fe29c6206ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/implied-abi-6.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-mabi given" { *-*-* } { "-mabi=*" } } */
+/* { dg-options "-O -march=rv64if" } */
+#if !(defined(__riscv_float_abi_soft) && (__riscv_xlen == 64))
+#error "Should be lp64"
+#endif
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/implied-abi-7.c b/gcc/testsuite/gcc.target/riscv/implied-abi-7.c
new file mode 100644
index 000000000000..bb334f5f36cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/implied-abi-7.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-mabi given" { *-*-* } { "-mabi=*" } } */
+/* { dg-options "-O -march=rv64ifd" } */
+#if !(defined(__riscv_float_abi_double) && (__riscv_xlen == 64))
+#error "Should be lp64d"
+#endif
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/implied-abi-8.c b/gcc/testsuite/gcc.target/riscv/implied-abi-8.c
new file mode 100644
index 000000000000..a48a47366978
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/implied-abi-8.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-mabi given" { *-*-* } { "-mabi=*" } } */
+/* { dg-options "-O -march=rv64ifd -mabi=lp64" } */
+#if !(defined(__riscv_float_abi_soft) && (__riscv_xlen == 64))
+#error "Should be lp64"
+#endif
+int main()
+{
+  return 0;
+}
