@@ -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. */
new file mode 100644
@@ -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
new file mode 100644
@@ -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 */
@@ -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);
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