Only one minor comment here, could you rename feature_bits.h to riscv_feature_bits.h, because the including path isn't really well organized in GCC, so always adding target name into prefix would be a better way.
On Thu, Oct 24, 2024 at 3:13 PM Yangyu Chen <c...@cyyself.name> wrote: > > This patch implements the riscv_minimal_hwprobe_feature_bits feature > for the RISC-V target. The feature bits are defined in the previous > patch [1] 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 final version of the target_clones support on RISC-V is > still under development, I am working on it. > > 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. > > [1] > https://patchwork.sourceware.org/project/gcc/patch/20241003182256.1765569-1-chenyan...@isrc.iscas.ac.cn/ > > 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): > (riscv_minimal_hwprobe_feature_bits): Declare the function. > * config/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/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/feature_bits.h > > diff --git a/gcc/common/config/riscv/riscv-common.cc > b/gcc/common/config/riscv/riscv-common.cc > index 2adebe0b6f2..ea5bfcd13fc 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 > @@ -1760,6 +1761,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 > @@ -1826,6 +1845,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 (c...@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/feature_bits.h b/gcc/config/riscv/feature_bits.h > new file mode 100644 > index 00000000000..19b7630e339 > --- /dev/null > +++ b/gcc/config/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..75008be6613 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 "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); > -- > 2.45.2 >