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
>

Reply via email to