diff mbox series

[v5,3/8] RISC-V: Implement riscv_minimal_hwprobe_feature_bits

Message ID tencent_010F58B0401BDC7100373EE63844A6F18705@qq.com
State New
Headers show
Series RISC-V: Add Function Multi-Versioning support | expand

Commit Message

Yangyu Chen Nov. 5, 2024, 3:22 a.m. UTC
This patch implements the riscv_minimal_hwprobe_feature_bits feature
for the RISC-V target. The feature bits are defined in the
libgcc/config/riscv/feature_bits.c to provide bitmasks of ISA extensions
that defined in RISC-V C-API. Thus, we need a function to generate the
feature bits for IFUNC resolver to dispatch between different functions
based on the hardware features.

The minimal feature bits means to use the earliest extension appeard in
the Linux hwprobe to cover the given ISA string. To allow older kernels
without some implied extensions probe to run the FMV dispatcher
correctly.

For example, V implies Zve32x, but Zve32x appears in the Linux kernel
since v6.11. If we use isa string directly to generate FMV dispatcher
with functions with "arch=+v" extension, since we have V implied the
Zve32x, FMV dispatcher will check if the Zve32x extension is supported
by the host. If the Linux kernel is older than v6.11, the FMV dispatcher
will fail to detect the Zve32x extension even it already implies by the
V extension, thus making the FMV dispatcher fail to dispatch the correct
function.

Thus, we need to generate the minimal feature bits to cover the given
ISA string to allow the FMV dispatcher to work correctly on older
kernels.

Signed-off-by: Yangyu Chen <cyy@cyyself.name>

gcc/ChangeLog:

	* common/config/riscv/riscv-common.cc
	(RISCV_EXT_BITMASK): New macro.
	(struct riscv_ext_bitmask_table_t): New struct.
	(riscv_minimal_hwprobe_feature_bits): New function.
	* common/config/riscv/riscv-ext-bitmask.def: New file.
	* config/riscv/riscv-subset.h (GCC_RISCV_SUBSET_H): Include
	riscv-feature-bits.h.
	(riscv_minimal_hwprobe_feature_bits): Declare the function.
	* config/riscv/riscv-feature-bits.h: New file.
---
 gcc/common/config/riscv/riscv-common.cc       | 94 +++++++++++++++++++
 gcc/common/config/riscv/riscv-ext-bitmask.def | 83 ++++++++++++++++
 gcc/config/riscv/riscv-feature-bits.h         | 44 +++++++++
 gcc/config/riscv/riscv-subset.h               |  5 +
 4 files changed, 226 insertions(+)
 create mode 100644 gcc/common/config/riscv/riscv-ext-bitmask.def
 create mode 100644 gcc/config/riscv/riscv-feature-bits.h
diff mbox series

Patch

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 60595a3e356..b0e49eb82c0 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 00000000000..ca5df1740f3
--- /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 00000000000..19b7630e339
--- /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 1914a5317d7..62aae4f2472 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);