diff mbox series

RISC-V: Add support for -mcpu option.

Message ID 20201013100902.73118-1-kito.cheng@sifive.com
State New
Headers show
Series RISC-V: Add support for -mcpu option. | expand

Commit Message

Kito Cheng Oct. 13, 2020, 10:09 a.m. UTC
- The behavior of -mcpu basically equal to -march plus -mtune, but it
   has lower priority than -march and -mtune.

 - The behavior and available options has sync with clang except we don't add
   few LLVM specific value, and add more sifive processor to the list.

 - -mtune also accept all available options of -mcpu, and use it setting.

gcc/ChangeLog:

	* common/config/riscv/riscv-common.c (riscv_cpu_tables): New.
	(riscv_arch_str): Return empty string if current_subset_list
	is NULL.
	(riscv_find_cpu): New.
	(riscv_handle_option): Verify option value of -mcpu.
	(riscv_expand_arch): Using std::string.
	(riscv_default_mtune): New.
	(riscv_expand_arch_from_cpu): Ditto.
	* config/riscv/riscv-cores.def: New.
	* config/riscv/riscv-protos.h (riscv_find_cpu): New.
	(riscv_cpu_info): New.
	* config/riscv/riscv.c (riscv_tune_info): Rename ...
	(riscv_tune_param): ... to this.
	(riscv_cpu_info): Rename ...
	(riscv_tune_info): ... to this.
	(tune_info): Rename ...
	(tune_param): ... to this.
	(rocket_tune_info): Update data type name.
	(sifive_7_tune_info): Ditto.
	(optimize_size_tune_info): Ditto.
	(riscv_cpu_info_table): Rename ...
	(riscv_tune_info_table): ... to this.
	(riscv_parse_cpu): Rename ...
	(riscv_parse_tune): ... to this, and translate valid -mcpu option to
	-mtune option.
	(riscv_rtx_costs): Rename tune_info to tune_param.
	(riscv_class_max_nregs): Ditto.
	(riscv_memory_move_cost): Ditto.
	(riscv_init_machine_status): Use value of -mcpu if -mtune is not
	given, and rename tune_info to tune_param.
	* config/riscv/riscv.h (riscv_expand_arch_from_cpu): New.
	(riscv_default_mtune): Ditto.
	(EXTRA_SPEC_FUNCTIONS): Add riscv_expand_arch_from_cpu and
	riscv_default_mtune.
	(OPTION_DEFAULT_SPECS): Handle default value of -march/-mabi.
	(DRIVER_SELF_SPECS): Expand -march from -mcpu if -march is not
	given.
	* config/riscv/riscv.opt (-mcpu): New option.
	* config/riscv/t-riscv ($(common_out_file)): Add
	riscv-cores.def to dependency.
	* doc/invoke.texi (RISC-V Option): Add -mcpu, and update the
	description of default value for -mtune and -march.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/mcpu-1.c: New.
	* gcc.target/riscv/mcpu-2.c: Ditto.
	* gcc.target/riscv/mcpu-3.c: Ditto.
	* gcc.target/riscv/mcpu-4.c: Ditto.
	* gcc.target/riscv/mcpu-5.c: Ditto.
	* gcc.target/riscv/mcpu-6.c: Ditto.
	* gcc.target/riscv/mcpu-7.c: Ditto.
---
 gcc/common/config/riscv/riscv-common.c  | 91 +++++++++++++++++++++--
 gcc/config/riscv/riscv-cores.def        | 49 +++++++++++++
 gcc/config/riscv/riscv-protos.h         | 14 ++++
 gcc/config/riscv/riscv.c                | 97 +++++++++++++------------
 gcc/config/riscv/riscv.h                | 25 +++++--
 gcc/config/riscv/riscv.opt              |  4 +
 gcc/config/riscv/t-riscv                |  2 +
 gcc/doc/invoke.texi                     | 24 +++++-
 gcc/testsuite/gcc.target/riscv/mcpu-1.c | 18 +++++
 gcc/testsuite/gcc.target/riscv/mcpu-2.c | 18 +++++
 gcc/testsuite/gcc.target/riscv/mcpu-3.c | 18 +++++
 gcc/testsuite/gcc.target/riscv/mcpu-4.c | 18 +++++
 gcc/testsuite/gcc.target/riscv/mcpu-5.c | 19 +++++
 gcc/testsuite/gcc.target/riscv/mcpu-6.c | 10 +++
 gcc/testsuite/gcc.target/riscv/mcpu-7.c | 10 +++
 15 files changed, 356 insertions(+), 61 deletions(-)
 create mode 100644 gcc/config/riscv/riscv-cores.def
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-7.c

Comments

Jim Wilson Oct. 14, 2020, 9:40 p.m. UTC | #1
On Tue, Oct 13, 2020 at 3:09 AM Kito Cheng <kito.cheng@sifive.com> wrote:
>  - The behavior of -mcpu basically equal to -march plus -mtune, but it
>    has lower priority than -march and -mtune.

This looks OK to me.

I noticed a few things while testing.  These don't need to be fixed
before the patch is committed.

Using an invalid cpu name results in two errors.
    rohan:2116$ ./xgcc -B./ -mcpu=sifive-e51 tmp.c
    cc1: error: ‘-mcpu=sifive-e51’: unknown CPU
    cc1: error: unknown cpu ‘sifive-e51’ for ‘-mtune’
Ideally that should be one error.  The second error may be confusing
as the user did not specify the -mtune option.  Maybe riscv_parse_tune
can have another option to indicate whether it was passed a tune
string or cpu string, and only error if it was given a tune string,
since the cpu string would already have given an error.  Or maybe pass
in both the cpu and tune strings, and it can ignore the cpu string if
a tune string was specified.  And only give an error if we are using
the tune string.  You can also avoid passing the tune string to
riscv_find_cpu which doesn't appear to be useful.

Using a valid cpu name that has different default arch than configured
gives a possibly confusing error
    rohan:2117$ ./xgcc -B./ -mcpu=sifive-s51 tmp.c
    cc1: error: requested ABI requires ‘-march’ to subsume the ‘D’ extension
This is for a toolchain with lp64d as default ABI.  There is a
deliberate choice here not to force the ABI from the -mcpu option, but
maybe the error can be improved, as using -mabi to fix this is more
likely to be correct than using -march.  Also, I never liked the use
of "subsume" here.  We shouldn't force users to crack open a
dictionary to figure out what an error message means.  Also, the user
didn't request an ABI, the compiler is using the configured default,
nor did the user specify a -march option.  Maybe something like
   cc1: error: ABI %s requires the 'D' extension, arch %s does not include it
where the %s expands to the ABi and arch that the compiler is using.
There is also another similar error that uses "subsume" to keep these
warnings consistent.  If we want to fix this, this should be a
separate patch.

Jim
Kito Cheng Oct. 15, 2020, 6:52 a.m. UTC | #2
Committed, thanks, other improvement changes will be sent in separate
patches in the next few days :)

On Thu, Oct 15, 2020 at 5:41 AM Jim Wilson <jimw@sifive.com> wrote:
>
> On Tue, Oct 13, 2020 at 3:09 AM Kito Cheng <kito.cheng@sifive.com> wrote:
> >  - The behavior of -mcpu basically equal to -march plus -mtune, but it
> >    has lower priority than -march and -mtune.
>
> This looks OK to me.
>
> I noticed a few things while testing.  These don't need to be fixed
> before the patch is committed.
>
> Using an invalid cpu name results in two errors.
>     rohan:2116$ ./xgcc -B./ -mcpu=sifive-e51 tmp.c
>     cc1: error: ‘-mcpu=sifive-e51’: unknown CPU
>     cc1: error: unknown cpu ‘sifive-e51’ for ‘-mtune’
> Ideally that should be one error.  The second error may be confusing
> as the user did not specify the -mtune option.  Maybe riscv_parse_tune
> can have another option to indicate whether it was passed a tune
> string or cpu string, and only error if it was given a tune string,
> since the cpu string would already have given an error.  Or maybe pass
> in both the cpu and tune strings, and it can ignore the cpu string if
> a tune string was specified.  And only give an error if we are using
> the tune string.  You can also avoid passing the tune string to
> riscv_find_cpu which doesn't appear to be useful.
>
> Using a valid cpu name that has different default arch than configured
> gives a possibly confusing error
>     rohan:2117$ ./xgcc -B./ -mcpu=sifive-s51 tmp.c
>     cc1: error: requested ABI requires ‘-march’ to subsume the ‘D’ extension
> This is for a toolchain with lp64d as default ABI.  There is a
> deliberate choice here not to force the ABI from the -mcpu option, but
> maybe the error can be improved, as using -mabi to fix this is more
> likely to be correct than using -march.  Also, I never liked the use
> of "subsume" here.  We shouldn't force users to crack open a
> dictionary to figure out what an error message means.  Also, the user
> didn't request an ABI, the compiler is using the configured default,
> nor did the user specify a -march option.  Maybe something like
>    cc1: error: ABI %s requires the 'D' extension, arch %s does not include it
> where the %s expands to the ABi and arch that the compiler is using.
> There is also another similar error that uses "subsume" to keep these
> warnings consistent.  If we want to fix this, this should be a
> separate patch.
>
> Jim
diff mbox series

Patch

diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c
index 82c5154b6118..4b6bdf8685d7 100644
--- a/gcc/common/config/riscv/riscv-common.c
+++ b/gcc/common/config/riscv/riscv-common.c
@@ -60,6 +60,14 @@  riscv_implied_info_t riscv_implied_info[] =
   {NULL, NULL}
 };
 
+static const riscv_cpu_info riscv_cpu_tables[] =
+{
+#define RISCV_CORE(CORE_NAME, ARCH, TUNE) \
+    {CORE_NAME, ARCH, TUNE},
+#include "../../../config/riscv/riscv-cores.def"
+    {NULL, NULL, NULL}
+};
+
 /* Subset list.  */
 class riscv_subset_list
 {
@@ -604,8 +612,10 @@  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
@@ -653,6 +663,21 @@  riscv_parse_arch_string (const char *isa, int *flags, location_t loc)
   current_subset_list = subset_list;
 }
 
+/* Return the riscv_cpu_info entry for CPU, NULL if not found.  */
+
+const riscv_cpu_info *
+riscv_find_cpu (const char *cpu)
+{
+  const riscv_cpu_info *cpu_info = &riscv_cpu_tables[0];
+  for (;cpu_info->name != NULL; ++cpu_info)
+    {
+      const char *name = cpu_info->name;
+      if (strcmp (cpu, name) == 0)
+	return cpu_info;
+    }
+  return NULL;
+}
+
 /* Implement TARGET_HANDLE_OPTION.  */
 
 static bool
@@ -667,6 +692,12 @@  riscv_handle_option (struct gcc_options *opts,
       riscv_parse_arch_string (decoded->arg, &opts->x_target_flags, loc);
       return true;
 
+    case OPT_mcpu_:
+      if (riscv_find_cpu (decoded->arg) == NULL)
+	error_at (loc, "%<-mcpu=%s%>: unknown CPU",
+		  decoded->arg);
+      return true;
+
     default:
       return true;
     }
@@ -678,15 +709,65 @@  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;
+  const std::string arch = riscv_arch_str (false);
+  if (arch.length())
+    return xasprintf ("-march=%s", arch.c_str());
+  else
+    return "";
 }
 
+/* Expand default -mtune option from -mcpu option, use default --with-tune value
+   if -mcpu don't have valid value.  */
+
+const char *
+riscv_default_mtune (int argc, const char **argv)
+{
+  gcc_assert (argc == 2);
+  const riscv_cpu_info *cpu = riscv_find_cpu (argv[0]);
+  const char *default_mtune = argv[1];
+  if (cpu)
+    return cpu->tune;
+  else
+    return default_mtune;
+}
+
+/* Expand arch string with implied extensions from -mcpu option.  */
+
+const char *
+riscv_expand_arch_from_cpu (int argc ATTRIBUTE_UNUSED,
+			    const char **argv)
+{
+  gcc_assert (argc > 0 && argc <= 2);
+  const char *default_arch_str = NULL;
+  const char *arch_str = NULL;
+  if (argc >= 2)
+    default_arch_str = argv[1];
+
+  const riscv_cpu_info *cpu = riscv_find_cpu (argv[0]);
+
+  if (cpu == NULL)
+    {
+      if (default_arch_str == NULL)
+	return "";
+      else
+	arch_str = default_arch_str;
+    }
+  else
+    arch_str = cpu->arch;
+
+  location_t loc = UNKNOWN_LOCATION;
+  int flags;
+
+  riscv_parse_arch_string (arch_str, &flags, loc);
+  const std::string arch = riscv_arch_str (false);
+  return xasprintf ("-march=%s", arch.c_str());
+}
+
+
 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
 static const struct default_options riscv_option_optimization_table[] =
   {
diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def
new file mode 100644
index 000000000000..6a13f3e453c4
--- /dev/null
+++ b/gcc/config/riscv/riscv-cores.def
@@ -0,0 +1,49 @@ 
+/* List of supported core and tune info for RISC-V.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This is a list of cores that implement RISC-V.
+
+   Before using #include to read this file, define a macro:
+
+      RISCV_CORE(CORE_NAME, ARCH, MICRO_ARCH, TUNE_INFO)
+
+   The CORE_NAME is the name of the core, represented as a string.
+   The ARCH is the default arch of the core, represented as a string,
+   can be NULL if no default arch.
+   The MICRO_ARCH is the name of the core for which scheduling decisions
+   will be made, represented as an identifier.
+   The TUNE_INFO is the detail cost model for this core, represented as an
+   identifier, reference to riscv-tunes.def.  */
+
+RISCV_CORE("sifive-e20",      "rv32imc",    "rocket")
+RISCV_CORE("sifive-e21",      "rv32imac",   "rocket")
+RISCV_CORE("sifive-e24",      "rv32imafc",  "rocket")
+RISCV_CORE("sifive-e31",      "rv32imac",   "sifive-3-series")
+RISCV_CORE("sifive-e34",      "rv32imafc",  "sifive-3-series")
+RISCV_CORE("sifive-e76",      "rv32imafc",  "sifive-7-series")
+
+RISCV_CORE("sifive-s21",      "rv64imac",   "rocket")
+RISCV_CORE("sifive-s51",      "rv64imac",   "sifive-5-series")
+RISCV_CORE("sifive-s54",      "rv64imafdc", "sifive-5-series")
+RISCV_CORE("sifive-s76",      "rv64imafdc", "sifive-7-series")
+
+RISCV_CORE("sifive-u54",      "rv64imafdc", "sifive-5-series")
+RISCV_CORE("sifive-u74",      "rv64imafdc", "sifive-7-series")
+
+#undef RISCV_CORE
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 358224af8988..256dab1d0cff 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -94,4 +94,18 @@  extern bool riscv_hard_regno_rename_ok (unsigned, unsigned);
 
 rtl_opt_pass * make_pass_shorten_memrefs (gcc::context *ctxt);
 
+/* Information about one CPU we know about.  */
+struct riscv_cpu_info {
+  /* This CPU's canonical name.  */
+  const char *name;
+
+  /* Default arch for this CPU, could be NULL if no default arch.  */
+  const char *arch;
+
+  /* Which automaton to use for tuning.  */
+  const char *tune;
+};
+
+extern const riscv_cpu_info *riscv_find_cpu (const char *);
+
 #endif /* ! GCC_RISCV_PROTOS_H */
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 63b0c3877b0d..989a9f15250c 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -209,7 +209,7 @@  struct riscv_integer_op {
 
 /* Costs of various operations on the different architectures.  */
 
-struct riscv_tune_info
+struct riscv_tune_param
 {
   unsigned short fp_add[2];
   unsigned short fp_mul[2];
@@ -222,16 +222,16 @@  struct riscv_tune_info
   bool slow_unaligned_access;
 };
 
-/* Information about one CPU we know about.  */
-struct riscv_cpu_info {
-  /* This CPU's canonical name.  */
+/* Information about one micro-arch we know about.  */
+struct riscv_tune_info {
+  /* This micro-arch canonical name.  */
   const char *name;
 
   /* Which automaton to use for tuning.  */
   enum riscv_microarchitecture_type microarchitecture;
 
-  /* Tuning parameters for this CPU.  */
-  const struct riscv_tune_info *tune_info;
+  /* Tuning parameters for this micro-arch.  */
+  const struct riscv_tune_param *tune_param;
 };
 
 /* Global variables for machine-dependent things.  */
@@ -248,7 +248,7 @@  unsigned riscv_stack_boundary;
 static int epilogue_cfa_sp_offset;
 
 /* Which tuning parameters to use.  */
-static const struct riscv_tune_info *tune_info;
+static const struct riscv_tune_param *tune_param;
 
 /* Which automaton to use for tuning.  */
 enum riscv_microarchitecture_type riscv_microarchitecture;
@@ -275,7 +275,7 @@  const enum reg_class riscv_regno_to_class[FIRST_PSEUDO_REGISTER] = {
 };
 
 /* Costs to use when optimizing for rocket.  */
-static const struct riscv_tune_info rocket_tune_info = {
+static const struct riscv_tune_param rocket_tune_info = {
   {COSTS_N_INSNS (4), COSTS_N_INSNS (5)},	/* fp_add */
   {COSTS_N_INSNS (4), COSTS_N_INSNS (5)},	/* fp_mul */
   {COSTS_N_INSNS (20), COSTS_N_INSNS (20)},	/* fp_div */
@@ -288,7 +288,7 @@  static const struct riscv_tune_info rocket_tune_info = {
 };
 
 /* Costs to use when optimizing for Sifive 7 Series.  */
-static const struct riscv_tune_info sifive_7_tune_info = {
+static const struct riscv_tune_param sifive_7_tune_info = {
   {COSTS_N_INSNS (4), COSTS_N_INSNS (5)},	/* fp_add */
   {COSTS_N_INSNS (4), COSTS_N_INSNS (5)},	/* fp_mul */
   {COSTS_N_INSNS (20), COSTS_N_INSNS (20)},	/* fp_div */
@@ -301,7 +301,7 @@  static const struct riscv_tune_info sifive_7_tune_info = {
 };
 
 /* Costs to use when optimizing for size.  */
-static const struct riscv_tune_info optimize_size_tune_info = {
+static const struct riscv_tune_param optimize_size_tune_info = {
   {COSTS_N_INSNS (1), COSTS_N_INSNS (1)},	/* fp_add */
   {COSTS_N_INSNS (1), COSTS_N_INSNS (1)},	/* fp_mul */
   {COSTS_N_INSNS (1), COSTS_N_INSNS (1)},	/* fp_div */
@@ -343,7 +343,7 @@  static const unsigned gpr_save_reg_order[] = {
 };
 
 /* A table describing all the processors GCC knows about.  */
-static const struct riscv_cpu_info riscv_cpu_info_table[] = {
+static const struct riscv_tune_info riscv_tune_info_table[] = {
   { "rocket", generic, &rocket_tune_info },
   { "sifive-3-series", generic, &rocket_tune_info },
   { "sifive-5-series", generic, &rocket_tune_info },
@@ -351,17 +351,22 @@  static const struct riscv_cpu_info riscv_cpu_info_table[] = {
   { "size", generic, &optimize_size_tune_info },
 };
 
-/* Return the riscv_cpu_info entry for the given name string.  */
+/* Return the riscv_tune_info entry for the given name string.  */
 
-static const struct riscv_cpu_info *
-riscv_parse_cpu (const char *cpu_string)
+static const struct riscv_tune_info *
+riscv_parse_tune (const char *tune_string)
 {
-  for (unsigned i = 0; i < ARRAY_SIZE (riscv_cpu_info_table); i++)
-    if (strcmp (riscv_cpu_info_table[i].name, cpu_string) == 0)
-      return riscv_cpu_info_table + i;
+  const riscv_cpu_info *cpu = riscv_find_cpu (tune_string);
 
-  error ("unknown cpu %qs for %<-mtune%>", cpu_string);
-  return riscv_cpu_info_table;
+  if (cpu)
+    tune_string = cpu->tune;
+
+  for (unsigned i = 0; i < ARRAY_SIZE (riscv_tune_info_table); i++)
+    if (strcmp (riscv_tune_info_table[i].name, tune_string) == 0)
+      return riscv_tune_info_table + i;
+
+  error ("unknown cpu %qs for %<-mtune%>", tune_string);
+  return riscv_tune_info_table;
 }
 
 /* Helper function for riscv_build_integer; arguments are as for
@@ -1703,7 +1708,7 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	 instructions it needs.  */
       if ((cost = riscv_address_insns (XEXP (x, 0), mode, true)) > 0)
 	{
-	  *total = COSTS_N_INSNS (cost + tune_info->memory_cost);
+	  *total = COSTS_N_INSNS (cost + tune_param->memory_cost);
 	  return true;
 	}
       /* Otherwise use the default handling.  */
@@ -1770,7 +1775,7 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	 mode instead.  */
       mode = GET_MODE (XEXP (x, 0));
       if (float_mode_p)
-	*total = tune_info->fp_add[mode == DFmode];
+	*total = tune_param->fp_add[mode == DFmode];
       else
 	*total = riscv_binary_cost (x, 1, 3);
       return false;
@@ -1779,19 +1784,19 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
     case ORDERED:
       /* (FEQ(A, A) & FEQ(B, B)) compared against 0.  */
       mode = GET_MODE (XEXP (x, 0));
-      *total = tune_info->fp_add[mode == DFmode] + COSTS_N_INSNS (2);
+      *total = tune_param->fp_add[mode == DFmode] + COSTS_N_INSNS (2);
       return false;
 
     case UNEQ:
       /* (FEQ(A, A) & FEQ(B, B)) compared against FEQ(A, B).  */
       mode = GET_MODE (XEXP (x, 0));
-      *total = tune_info->fp_add[mode == DFmode] + COSTS_N_INSNS (3);
+      *total = tune_param->fp_add[mode == DFmode] + COSTS_N_INSNS (3);
       return false;
 
     case LTGT:
       /* (FLT(A, A) || FGT(B, B)).  */
       mode = GET_MODE (XEXP (x, 0));
-      *total = tune_info->fp_add[mode == DFmode] + COSTS_N_INSNS (2);
+      *total = tune_param->fp_add[mode == DFmode] + COSTS_N_INSNS (2);
       return false;
 
     case UNGE:
@@ -1800,13 +1805,13 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
     case UNLT:
       /* FLT or FLE, but guarded by an FFLAGS read and write.  */
       mode = GET_MODE (XEXP (x, 0));
-      *total = tune_info->fp_add[mode == DFmode] + COSTS_N_INSNS (4);
+      *total = tune_param->fp_add[mode == DFmode] + COSTS_N_INSNS (4);
       return false;
 
     case MINUS:
     case PLUS:
       if (float_mode_p)
-	*total = tune_info->fp_add[mode == DFmode];
+	*total = tune_param->fp_add[mode == DFmode];
       else
 	*total = riscv_binary_cost (x, 1, 4);
       return false;
@@ -1816,7 +1821,7 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	rtx op = XEXP (x, 0);
 	if (GET_CODE (op) == FMA && !HONOR_SIGNED_ZEROS (mode))
 	  {
-	    *total = (tune_info->fp_mul[mode == DFmode]
+	    *total = (tune_param->fp_mul[mode == DFmode]
 		      + set_src_cost (XEXP (op, 0), mode, speed)
 		      + set_src_cost (XEXP (op, 1), mode, speed)
 		      + set_src_cost (XEXP (op, 2), mode, speed));
@@ -1825,23 +1830,23 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
       }
 
       if (float_mode_p)
-	*total = tune_info->fp_add[mode == DFmode];
+	*total = tune_param->fp_add[mode == DFmode];
       else
 	*total = COSTS_N_INSNS (GET_MODE_SIZE (mode) > UNITS_PER_WORD ? 4 : 1);
       return false;
 
     case MULT:
       if (float_mode_p)
-	*total = tune_info->fp_mul[mode == DFmode];
+	*total = tune_param->fp_mul[mode == DFmode];
       else if (!TARGET_MUL)
 	/* Estimate the cost of a library call.  */
 	*total = COSTS_N_INSNS (speed ? 32 : 6);
       else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
-	*total = 3 * tune_info->int_mul[0] + COSTS_N_INSNS (2);
+	*total = 3 * tune_param->int_mul[0] + COSTS_N_INSNS (2);
       else if (!speed)
 	*total = COSTS_N_INSNS (1);
       else
-	*total = tune_info->int_mul[mode == DImode];
+	*total = tune_param->int_mul[mode == DImode];
       return false;
 
     case DIV:
@@ -1849,7 +1854,7 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
     case MOD:
       if (float_mode_p)
 	{
-	  *total = tune_info->fp_div[mode == DFmode];
+	  *total = tune_param->fp_div[mode == DFmode];
 	  return false;
 	}
       /* Fall through.  */
@@ -1860,7 +1865,7 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	/* Estimate the cost of a library call.  */
 	*total = COSTS_N_INSNS (speed ? 32 : 6);
       else if (speed)
-	*total = tune_info->int_div[mode == DImode];
+	*total = tune_param->int_div[mode == DImode];
       else
 	*total = COSTS_N_INSNS (1);
       return false;
@@ -1882,11 +1887,11 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
     case FIX:
     case FLOAT_EXTEND:
     case FLOAT_TRUNCATE:
-      *total = tune_info->fp_add[mode == DFmode];
+      *total = tune_param->fp_add[mode == DFmode];
       return false;
 
     case FMA:
-      *total = (tune_info->fp_mul[mode == DFmode]
+      *total = (tune_param->fp_mul[mode == DFmode]
 		+ set_src_cost (XEXP (x, 0), mode, speed)
 		+ set_src_cost (XEXP (x, 1), mode, speed)
 		+ set_src_cost (XEXP (x, 2), mode, speed));
@@ -4546,7 +4551,7 @@  riscv_class_max_nregs (reg_class_t rclass, machine_mode mode)
 static int
 riscv_memory_move_cost (machine_mode mode, reg_class_t rclass, bool in)
 {
-  return (tune_info->memory_cost
+  return (tune_param->memory_cost
 	  + memory_move_secondary_cost (mode, rclass, in));
 }
 
@@ -4555,7 +4560,7 @@  riscv_memory_move_cost (machine_mode mode, reg_class_t rclass, bool in)
 static int
 riscv_issue_rate (void)
 {
-  return tune_info->issue_rate;
+  return tune_param->issue_rate;
 }
 
 /* Auxiliary function to emit RISC-V ELF attribute. */
@@ -4683,7 +4688,7 @@  riscv_init_machine_status (void)
 static void
 riscv_option_override (void)
 {
-  const struct riscv_cpu_info *cpu;
+  const struct riscv_tune_info *cpu;
 
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
@@ -4705,26 +4710,28 @@  riscv_option_override (void)
   if (TARGET_HARD_FLOAT && (target_flags_explicit & MASK_FDIV) == 0)
     target_flags |= MASK_FDIV;
 
-  /* Handle -mtune.  */
-  cpu = riscv_parse_cpu (riscv_tune_string ? riscv_tune_string :
-			 RISCV_TUNE_STRING_DEFAULT);
+  /* Handle -mtune, use -mcpu if -mtune is not given, and use default -mtune
+     if -mtune and -mcpu both not not given.  */
+  cpu = riscv_parse_tune (riscv_tune_string ? riscv_tune_string :
+			  (riscv_cpu_string ? riscv_cpu_string :
+			   RISCV_TUNE_STRING_DEFAULT));
   riscv_microarchitecture = cpu->microarchitecture;
-  tune_info = optimize_size ? &optimize_size_tune_info : cpu->tune_info;
+  tune_param = optimize_size ? &optimize_size_tune_info : cpu->tune_param;
 
   /* Use -mtune's setting for slow_unaligned_access, even when optimizing
      for size.  For architectures that trap and emulate unaligned accesses,
      the performance cost is too great, even for -Os.  Similarly, if
      -m[no-]strict-align is left unspecified, heed -mtune's advice.  */
-  riscv_slow_unaligned_access_p = (cpu->tune_info->slow_unaligned_access
+  riscv_slow_unaligned_access_p = (cpu->tune_param->slow_unaligned_access
 				   || TARGET_STRICT_ALIGN);
   if ((target_flags_explicit & MASK_STRICT_ALIGN) == 0
-      && cpu->tune_info->slow_unaligned_access)
+      && cpu->tune_param->slow_unaligned_access)
     target_flags |= MASK_STRICT_ALIGN;
 
   /* If the user hasn't specified a branch cost, use the processor's
      default.  */
   if (riscv_branch_cost == 0)
-    riscv_branch_cost = tune_info->branch_cost;
+    riscv_branch_cost = tune_param->branch_cost;
 
   /* Function to allocate machine-dependent function status.  */
   init_machine_status = &riscv_init_machine_status;
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index b7b4a1c88a52..172c7ca7c98b 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -41,17 +41,27 @@  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_expand_arch_from_cpu (int argc, const char **argv);
+extern const char *riscv_default_mtune (int argc, const char **argv);
 
 # define EXTRA_SPEC_FUNCTIONS						\
-  { "riscv_expand_arch", riscv_expand_arch },
+  { "riscv_expand_arch", riscv_expand_arch },				\
+  { "riscv_expand_arch_from_cpu", riscv_expand_arch_from_cpu },		\
+  { "riscv_default_mtune", riscv_default_mtune },
 
 /* Support for a compile-time default CPU, et cetera.  The rules are:
-   --with-arch is ignored if -march is specified.
+   --with-arch is ignored if -march or -mcpu is specified.
    --with-abi is ignored if -mabi is specified.
-   --with-tune is ignored if -mtune is specified.  */
+   --with-tune is ignored if -mtune or -mcpu is specified.
+
+   But using default -march/-mtune value if -mcpu don't have valid option.  */
 #define OPTION_DEFAULT_SPECS \
-  {"tune", "%{!mtune=*:-mtune=%(VALUE)}" }, \
-  {"arch", "%{!march=*:-march=%(VALUE)}" }, \
+  {"tune", "%{!mtune=*:"						\
+	   "  %{!mcpu=*:-mtune=%(VALUE)}"				\
+	   "  %{mcpu=*:-mtune=%:riscv_default_mtune(%* %(VALUE))}}" },	\
+  {"arch", "%{!march=*:"						\
+	   "  %{!mcpu=*:-march=%(VALUE)}"				\
+	   "  %{mcpu=*:%:riscv_expand_arch_from_cpu(%* %(VALUE))}}" },	\
   {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
 
 #ifdef IN_LIBGCC2
@@ -69,8 +79,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(%*)} "				\
+"%{!march=*:%{mcpu=*:%:riscv_expand_arch_from_cpu(%*)}} "
 
 #define TARGET_DEFAULT_CMODEL CM_MEDLOW
 
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index f01d3ab79c3b..808b4a044054 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -79,6 +79,10 @@  mtune=
 Target RejectNegative Joined Var(riscv_tune_string)
 -mtune=PROCESSOR	Optimize the output for PROCESSOR.
 
+mcpu=
+Target RejectNegative Joined Var(riscv_cpu_string)
+-mcpu=PROCESSOR	Use architecture of and optimize the output for PROCESSOR.
+
 msmall-data-limit=
 Target Joined Separate UInteger Var(g_switch_value) Init(8)
 -msmall-data-limit=N	Put global and static data smaller than <number> bytes into a special section (on some targets).
diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv
index 4820fb35d317..702767c17362 100644
--- a/gcc/config/riscv/t-riscv
+++ b/gcc/config/riscv/t-riscv
@@ -24,3 +24,5 @@  riscv-shorten-memrefs.o: $(srcdir)/config/riscv/riscv-shorten-memrefs.c
 	$(POSTCOMPILE)
 
 PASSES_EXTRA += $(srcdir)/config/riscv/riscv-passes.def
+
+$(common_out_file): $(srcdir)/config/riscv/riscv-cores.def
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c8281ecf5021..b8429592bb64 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -25998,14 +25998,30 @@  Generate code for given RISC-V ISA (e.g.@: @samp{rv64im}).  ISA strings must be
 lower-case.  Examples include @samp{rv64i}, @samp{rv32g}, @samp{rv32e}, and
 @samp{rv32imaf}.
 
+When @option{-march=} is not specified, use the setting from @option{-mcpu}.
+
+If both @option{-march} and @option{-mcpu=} are not specified, the default for
+this argument is system dependent, users who want a specific architecture
+extensions should specify one explicitly.
+
+@item -mcpu=@var{processor-string}
+@opindex mcpu
+Use architecture of and optimize the output for the given processor, specified
+by particular CPU name.
+Permissible values for this option are: @samp{sifive-e20}, @samp{sifive-e21},
+@samp{sifive-e24}, @samp{sifive-e31}, @samp{sifive-e34}, @samp{sifive-e76},
+@samp{sifive-s21}, @samp{sifive-s51}, @samp{sifive-s54}, @samp{sifive-s76},
+@samp{sifive-u54}, and @samp{sifive-u74}.
+
 @item -mtune=@var{processor-string}
 @opindex mtune
-Optimize the output for the given processor, specified by microarchitecture
-name.  Permissible values for this option are: @samp{rocket},
+Optimize the output for the given processor, specified by microarchitecture or
+particular CPU name.  Permissible values for this option are: @samp{rocket},
 @samp{sifive-3-series}, @samp{sifive-5-series}, @samp{sifive-7-series},
-and @samp{size}.
+@samp{size}, and all valid options for @option{-mcpu=}.
 
-When @option{-mtune=} is not specified, the default is @samp{rocket}.
+When @option{-mtune=} is not specified, use the setting from @option{-mcpu},
+the default is @samp{rocket} if both are not specified.
 
 The @samp{size} choice is not intended for use by end-users.  This is used
 when @option{-Os} is specified.  It overrides the instruction cost info
diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-1.c b/gcc/testsuite/gcc.target/riscv/mcpu-1.c
new file mode 100644
index 000000000000..6f6005c79eb0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/mcpu-1.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */
+/* { dg-options "-mcpu=sifive-e20 -mabi=ilp32" } */
+/* sifive-e20 = rv32imc */
+
+#if !((__riscv_xlen == 32)		\
+      && !defined(__riscv_32e)		\
+      && defined(__riscv_mul)		\
+      && !defined(__riscv_atomic)	\
+      && !defined(__riscv_flen)		\
+      && defined(__riscv_compressed))
+#error "unexpected arch"
+#endif
+
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-2.c b/gcc/testsuite/gcc.target/riscv/mcpu-2.c
new file mode 100644
index 000000000000..2992f4e10836
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/mcpu-2.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */
+/* { dg-options "-mcpu=sifive-e34 -mabi=ilp32" } */
+/* sifive-e34 = rv32imafc */
+
+#if !((__riscv_xlen == 32)		\
+      && !defined(__riscv_32e)		\
+      && defined(__riscv_mul)		\
+      && defined(__riscv_atomic)	\
+      && (__riscv_flen == 32)		\
+      && defined(__riscv_compressed))
+#error "unexpected arch"
+#endif
+
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-3.c b/gcc/testsuite/gcc.target/riscv/mcpu-3.c
new file mode 100644
index 000000000000..97b3f8190faf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/mcpu-3.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */
+/* { dg-options "-mcpu=sifive-s51 -mabi=lp64" } */
+/* sifive-s51 = rv64imac */
+
+#if !((__riscv_xlen == 64)		\
+      && !defined(__riscv_32e)		\
+      && defined(__riscv_mul)		\
+      && defined(__riscv_atomic)	\
+      && !defined(__riscv_flen)		\
+      && defined(__riscv_compressed))
+#error "unexpected arch"
+#endif
+
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-4.c b/gcc/testsuite/gcc.target/riscv/mcpu-4.c
new file mode 100644
index 000000000000..52c598754227
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/mcpu-4.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */
+/* { dg-options "-mcpu=sifive-u74 -mabi=lp64" } */
+/* sifive-u74 = rv64imafdc */
+
+#if !((__riscv_xlen == 64)		\
+      && !defined(__riscv_32e)		\
+      && defined(__riscv_mul)		\
+      && defined(__riscv_atomic)	\
+      && (__riscv_flen == 64)		\
+      && defined(__riscv_compressed))
+#error "unexpected arch"
+#endif
+
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-5.c b/gcc/testsuite/gcc.target/riscv/mcpu-5.c
new file mode 100644
index 000000000000..c4ea7b5e41a3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/mcpu-5.c
@@ -0,0 +1,19 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */
+/* Verify -march will override arch option from -mcpu.  */
+/* { dg-options "-mcpu=sifive-u74 -march=rv32ic -mabi=ilp32" } */
+/* sifive-s51 = rv64imafdc */
+
+#if !((__riscv_xlen == 32)		\
+      && !defined(__riscv_32e)		\
+      && !defined(__riscv_mul)		\
+      && !defined(__riscv_atomic)	\
+      && !defined(__riscv_flen)		\
+      && defined(__riscv_compressed))
+#error "unexpected arch"
+#endif
+
+int main()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-6.c b/gcc/testsuite/gcc.target/riscv/mcpu-6.c
new file mode 100644
index 000000000000..57e3345630c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/mcpu-6.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* Verify -mtune has higher priority than -mcpu for pipeline model .  */
+/* { dg-options "-mcpu=sifive-u74 -mtune=rocket -fdump-rtl-sched2-details -O3 -march=rv32i -mabi=ilp32" } */
+/* { dg-final { scan-rtl-dump "simple_return\[ \]+:alu" "sched2" } } */
+
+int main()
+{
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-7.c b/gcc/testsuite/gcc.target/riscv/mcpu-7.c
new file mode 100644
index 000000000000..fe3c04be4b6d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/mcpu-7.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* Verify -mtune has higher priority than -mcpu for pipeline model .  */
+/* { dg-options "-mcpu=sifive-s21 -mtune=sifive-u74 -fdump-rtl-sched2-details -O3 -march=rv32i -mabi=ilp32" } */
+/* { dg-final { scan-rtl-dump "simple_return\[ \]+:sifive_7_B" "sched2" } } */
+
+int main()
+{
+  return 0;
+}
+