diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 60595a3e3561869c0c77404717f2aad21ced43e0..b0e49eb82c0e81a7c8df40d843755684a3546528 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include <sstream>
 #include <vector>
+#include <queue>
 
 #define INCLUDE_STRING
 #define INCLUDE_SET
@@ -1762,6 +1763,24 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {NULL, NULL, NULL, 0}
 };
 
+/* Types for recording extension to RISC-V C-API bitmask.  */
+struct riscv_ext_bitmask_table_t {
+  const char *ext;
+  int groupid;
+  int bit_position;
+};
+
+/* Mapping table between extension to RISC-V C-API extension bitmask.
+   This table should sort the extension by Linux hwprobe order to get the
+   minimal feature bits.  */
+static const riscv_ext_bitmask_table_t riscv_ext_bitmask_table[] =
+{
+#define RISCV_EXT_BITMASK(NAME, GROUPID, BITPOS) \
+  {NAME, GROUPID, BITPOS},
+#include "riscv-ext-bitmask.def"
+  {NULL,	       -1, -1}
+};
+
 /* Apply SUBSET_LIST to OPTS if OPTS is not null.  */
 
 void
@@ -1828,6 +1847,81 @@ riscv_x_target_flags_isa_mask (void)
   return mask;
 }
 
+/* Get the minimal feature bits in Linux hwprobe of the given ISA string.
+
+   Used for generating Function Multi-Versioning (FMV) dispatcher for RISC-V.
+
+   The minimal feature bits refer to using the earliest extension that appeared
+   in the Linux hwprobe to support the specified ISA string.  This ensures that
+   older kernels, which may lack certain implied extensions, can still run the
+   FMV dispatcher correctly.  */
+
+bool
+riscv_minimal_hwprobe_feature_bits (const char *isa,
+				    struct riscv_feature_bits *res,
+				    location_t loc)
+{
+  riscv_subset_list *subset_list;
+  subset_list = riscv_subset_list::parse (isa, loc);
+  if (!subset_list)
+    return false;
+
+  /* Initialize the result feature bits to zero.  */
+  res->length = RISCV_FEATURE_BITS_LENGTH;
+  for (int i = 0; i < RISCV_FEATURE_BITS_LENGTH; ++i)
+    res->features[i] = 0;
+
+  /* Use a std::set to record all visited implied extensions.  */
+  std::set <std::string> implied_exts;
+
+  /* Iterate through the extension bitmask table in Linux hwprobe order to get
+     the minimal covered feature bits.  Avoiding some sub-extensions which will
+     be implied by the super-extensions like V implied Zve32x.  */
+  const riscv_ext_bitmask_table_t *ext_bitmask_tab;
+  for (ext_bitmask_tab = &riscv_ext_bitmask_table[0];
+       ext_bitmask_tab->ext;
+       ++ext_bitmask_tab)
+    {
+      /* Skip the extension if it is not in the subset list or already implied
+	 by previous extension.  */
+      if (subset_list->lookup (ext_bitmask_tab->ext) == NULL
+	  || implied_exts.count (ext_bitmask_tab->ext))
+	continue;
+
+      res->features[ext_bitmask_tab->groupid]
+	|= 1ULL << ext_bitmask_tab->bit_position;
+
+      /* Find the sub-extension using BFS and set the corresponding bit.  */
+      std::queue <const char *> search_q;
+      search_q.push (ext_bitmask_tab->ext);
+
+      while (!search_q.empty ())
+	{
+	  const char * search_ext = search_q.front ();
+	  search_q.pop ();
+
+	  /* Iterate through the implied extension table.  */
+	  const riscv_implied_info_t *implied_info;
+	  for (implied_info = &riscv_implied_info[0];
+	      implied_info->ext;
+	      ++implied_info)
+	    {
+	      /* When the search extension matches the implied extension and
+		 the implied extension has not been visited, mark the implied
+		 extension in the implied_exts set and push it into the
+		 queue.  */
+	      if (implied_info->match (subset_list, search_ext)
+		  && implied_exts.count (implied_info->implied_ext) == 0)
+		{
+		  implied_exts.insert (implied_info->implied_ext);
+		  search_q.push (implied_info->implied_ext);
+		}
+	    }
+	}
+    }
+  return true;
+}
+
 /* 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.  */
 
diff --git a/gcc/common/config/riscv/riscv-ext-bitmask.def b/gcc/common/config/riscv/riscv-ext-bitmask.def
new file mode 100644
index 0000000000000000000000000000000000000000..ca5df1740f3f11f9bd8c4cdbe43b376ccd30225b
--- /dev/null
+++ b/gcc/common/config/riscv/riscv-ext-bitmask.def
@@ -0,0 +1,83 @@
+/* RISC-V Extension Bitmask Definitions, corresponding to Extension Bitmask
+   Definitions in RISC-V C API Specification.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Contributed by Yangyu Chen (cyy@cyyself.name).
+
+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/>.  */
+
+#ifndef RISCV_EXT_BITMASK
+#define RISCV_EXT_BITMASK(NAME, GROUP_ID, BIT_POSITION)
+#endif
+
+/* This table should sort the extension by Linux hwprobe order to calculate the
+   minimal feature bits.  */
+
+RISCV_EXT_BITMASK ("i",			0,  8)
+RISCV_EXT_BITMASK ("m",			0, 12)
+RISCV_EXT_BITMASK ("a",			0,  0)
+RISCV_EXT_BITMASK ("f",			0,  5)
+RISCV_EXT_BITMASK ("d",			0,  3)
+RISCV_EXT_BITMASK ("c",			0,  2)
+RISCV_EXT_BITMASK ("v",			0, 21)
+RISCV_EXT_BITMASK ("zba",		0, 27)
+RISCV_EXT_BITMASK ("zbb",		0, 28)
+RISCV_EXT_BITMASK ("zbs",		0, 33)
+RISCV_EXT_BITMASK ("zicboz",		0, 37)
+RISCV_EXT_BITMASK ("zbc",		0, 29)
+RISCV_EXT_BITMASK ("zbkb",		0, 30)
+RISCV_EXT_BITMASK ("zbkc",		0, 31)
+RISCV_EXT_BITMASK ("zbkx",		0, 32)
+RISCV_EXT_BITMASK ("zknd",		0, 41)
+RISCV_EXT_BITMASK ("zkne",		0, 42)
+RISCV_EXT_BITMASK ("zknh",		0, 43)
+RISCV_EXT_BITMASK ("zksed",		0, 44)
+RISCV_EXT_BITMASK ("zksh",		0, 45)
+RISCV_EXT_BITMASK ("zkt",		0, 46)
+RISCV_EXT_BITMASK ("zvbb",		0, 48)
+RISCV_EXT_BITMASK ("zvbc",		0, 49)
+RISCV_EXT_BITMASK ("zvkb",		0, 52)
+RISCV_EXT_BITMASK ("zvkg",		0, 53)
+RISCV_EXT_BITMASK ("zvkned",		0, 54)
+RISCV_EXT_BITMASK ("zvknha",		0, 55)
+RISCV_EXT_BITMASK ("zvknhb",		0, 56)
+RISCV_EXT_BITMASK ("zvksed",		0, 57)
+RISCV_EXT_BITMASK ("zvksh",		0, 58)
+RISCV_EXT_BITMASK ("zvkt",		0, 59)
+RISCV_EXT_BITMASK ("zfh",		0, 35)
+RISCV_EXT_BITMASK ("zfhmin",		0, 36)
+RISCV_EXT_BITMASK ("zihintntl",		0, 39)
+RISCV_EXT_BITMASK ("zvfh",		0, 50)
+RISCV_EXT_BITMASK ("zvfhmin",		0, 51)
+RISCV_EXT_BITMASK ("zfa",		0, 34)
+RISCV_EXT_BITMASK ("ztso",		0, 47)
+RISCV_EXT_BITMASK ("zacas",		0, 26)
+RISCV_EXT_BITMASK ("zicond",		0, 38)
+RISCV_EXT_BITMASK ("zihintpause",	0, 40)
+RISCV_EXT_BITMASK ("zve32x",		0, 60)
+RISCV_EXT_BITMASK ("zve32f",		0, 61)
+RISCV_EXT_BITMASK ("zve64x",		0, 62)
+RISCV_EXT_BITMASK ("zve64f",		0, 63)
+RISCV_EXT_BITMASK ("zve64d",		1,  0)
+RISCV_EXT_BITMASK ("zimop",		1,  1)
+RISCV_EXT_BITMASK ("zca",		1,  2)
+RISCV_EXT_BITMASK ("zcb",		1,  3)
+RISCV_EXT_BITMASK ("zcd",		1,  4)
+RISCV_EXT_BITMASK ("zcf",		1,  5)
+RISCV_EXT_BITMASK ("zcmop",		1,  6)
+RISCV_EXT_BITMASK ("zawrs",		1,  7)
+
+#undef RISCV_EXT_BITMASK
diff --git a/gcc/config/riscv/riscv-feature-bits.h b/gcc/config/riscv/riscv-feature-bits.h
new file mode 100644
index 0000000000000000000000000000000000000000..19b7630e3399cfd8ea5d5474972bb6a69966cd94
--- /dev/null
+++ b/gcc/config/riscv/riscv-feature-bits.h
@@ -0,0 +1,44 @@
+/* Definition of RISC-V feature bits corresponding to
+   libgcc/config/riscv/feature_bits.c
+   Copyright (C) 2024 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/>.  */
+
+#ifndef GCC_RISCV_FEATURE_BITS_H
+#define GCC_RISCV_FEATURE_BITS_H
+
+#define RISCV_FEATURE_BITS_LENGTH 2
+
+struct riscv_feature_bits {
+  unsigned length;
+  unsigned long long features[RISCV_FEATURE_BITS_LENGTH];
+};
+
+#define RISCV_VENDOR_FEATURE_BITS_LENGTH 1
+
+struct riscv_vendor_feature_bits {
+  unsigned length;
+  unsigned long long features[RISCV_VENDOR_FEATURE_BITS_LENGTH];
+};
+
+struct riscv_cpu_model {
+  unsigned mvendorid;
+  unsigned long long marchid;
+  unsigned long long mimpid;
+};
+
+#endif /* GCC_RISCV_FEATURE_BITS_H */
diff --git a/gcc/config/riscv/riscv-subset.h b/gcc/config/riscv/riscv-subset.h
index 1914a5317d7e5069b4d957abadae7ebc7922f5a4..62aae4f2472783cea42733f220258f5beee71e9f 100644
--- a/gcc/config/riscv/riscv-subset.h
+++ b/gcc/config/riscv/riscv-subset.h
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_RISCV_SUBSET_H
 #define GCC_RISCV_SUBSET_H
 
+#include "riscv-feature-bits.h"
+
 #define RISCV_DONT_CARE_VERSION -1
 
 /* Subset info.  */
@@ -120,6 +122,9 @@ public:
 extern const riscv_subset_list *riscv_cmdline_subset_list (void);
 extern void
 riscv_set_arch_by_subset_list (riscv_subset_list *, struct gcc_options *);
+extern bool riscv_minimal_hwprobe_feature_bits (const char *,
+						struct riscv_feature_bits *,
+						location_t);
 extern bool
 riscv_ext_is_subset (struct cl_target_option *, struct cl_target_option *);
 extern int riscv_x_target_flags_isa_mask (void);