diff mbox series

[v6] RISC-V: Implement __init_riscv_feature_bits, __riscv_feature_bits, and __riscv_vendor_feature_bits

Message ID 20241003182256.1765569-1-chenyangyu@isrc.iscas.ac.cn
State New
Headers show
Series [v6] RISC-V: Implement __init_riscv_feature_bits, __riscv_feature_bits, and __riscv_vendor_feature_bits | expand

Commit Message

Yangyu Chen Oct. 3, 2024, 6:22 p.m. UTC
From: Kito Cheng <kito.cheng@sifive.com>

This provides a common abstraction layer to probe the available extensions at
run-time. These functions can be used to implement function multi-versioning or
to detect available extensions.

The advantages of providing this abstraction layer are:
- Easy to port to other new platforms.
- Easier to maintain in GCC for function multi-versioning.
  - For example, maintaining platform-dependent code in C code/libgcc is much
    easier than maintaining it in GCC by creating GIMPLEs...

This API is intended to provide the capability to query minimal common available extensions on the system.

Proposal in riscv-c-api-doc: https://github.com/riscv-non-isa/riscv-c-api-doc/pull/74

Full function multi-versioning implementation will come later. We are posting
this first because we intend to backport it to the GCC 14 branch to unblock
LLVM 19 to use this with GCC 14.2, rather than waiting for GCC 15.

Changes since v5:
- Minor fixes on indentation.

Changes since v4:
- Bump to newest riscv-c-api-doc with some new extensions like Zve*, Zc*
  Zimop, Zcmop, Zawrs.
- Rename the return variable name of hwprobe syscall.
- Minor fixes on indentation.

Changes since v3:
- Fix non-linux build.
- Let __init_riscv_feature_bits become constructor

Changes since v2:
- Prevent it initialize more than once.

Changes since v1:
- Fix the format.
- Prevented race conditions by introducing a local variable to avoid load/store
  operations during the computation of the feature bit.

libgcc/ChangeLog:

	* config/riscv/feature_bits.c: New.
	* config/riscv/t-elf (LIB2ADD): Add feature_bits.c.

Co-Developed-by: Yangyu Chen <chenyangyu@isrc.iscas.ac.cn>
Signed-off-by: Yangyu Chen <chenyangyu@isrc.iscas.ac.cn>
---
 libgcc/config/riscv/feature_bits.c | 364 +++++++++++++++++++++++++++++
 libgcc/config/riscv/t-elf          |   1 +
 2 files changed, 365 insertions(+)
 create mode 100644 libgcc/config/riscv/feature_bits.c

Comments

Kito Cheng Oct. 7, 2024, 10:15 a.m. UTC | #1
Could you implement the latest API defined in the doc?

struct {
unsigned length;
unsigned long long features[];
} __riscv_feature_bits;

struct {
unsigned length;
unsigned long long features[];
} __riscv_vendor_feature_bits;

struct {
unsigned mvendorid;
unsigned marchid;
unsigned mimpid;
} __riscv_cpu_model;


On Fri, Oct 4, 2024 at 2:24 AM Yangyu Chen <chenyangyu@isrc.iscas.ac.cn> wrote:
>
> From: Kito Cheng <kito.cheng@sifive.com>
>
> This provides a common abstraction layer to probe the available extensions at
> run-time. These functions can be used to implement function multi-versioning or
> to detect available extensions.
>
> The advantages of providing this abstraction layer are:
> - Easy to port to other new platforms.
> - Easier to maintain in GCC for function multi-versioning.
>   - For example, maintaining platform-dependent code in C code/libgcc is much
>     easier than maintaining it in GCC by creating GIMPLEs...
>
> This API is intended to provide the capability to query minimal common available extensions on the system.
>
> Proposal in riscv-c-api-doc: https://github.com/riscv-non-isa/riscv-c-api-doc/pull/74
>
> Full function multi-versioning implementation will come later. We are posting
> this first because we intend to backport it to the GCC 14 branch to unblock
> LLVM 19 to use this with GCC 14.2, rather than waiting for GCC 15.
>
> Changes since v5:
> - Minor fixes on indentation.
>
> Changes since v4:
> - Bump to newest riscv-c-api-doc with some new extensions like Zve*, Zc*
>   Zimop, Zcmop, Zawrs.
> - Rename the return variable name of hwprobe syscall.
> - Minor fixes on indentation.
>
> Changes since v3:
> - Fix non-linux build.
> - Let __init_riscv_feature_bits become constructor
>
> Changes since v2:
> - Prevent it initialize more than once.
>
> Changes since v1:
> - Fix the format.
> - Prevented race conditions by introducing a local variable to avoid load/store
>   operations during the computation of the feature bit.
>
> libgcc/ChangeLog:
>
>         * config/riscv/feature_bits.c: New.
>         * config/riscv/t-elf (LIB2ADD): Add feature_bits.c.
>
> Co-Developed-by: Yangyu Chen <chenyangyu@isrc.iscas.ac.cn>
> Signed-off-by: Yangyu Chen <chenyangyu@isrc.iscas.ac.cn>
> ---
>  libgcc/config/riscv/feature_bits.c | 364 +++++++++++++++++++++++++++++
>  libgcc/config/riscv/t-elf          |   1 +
>  2 files changed, 365 insertions(+)
>  create mode 100644 libgcc/config/riscv/feature_bits.c
>
> diff --git a/libgcc/config/riscv/feature_bits.c b/libgcc/config/riscv/feature_bits.c
> new file mode 100644
> index 00000000000..c5339f065c1
> --- /dev/null
> +++ b/libgcc/config/riscv/feature_bits.c
> @@ -0,0 +1,364 @@
> +/* Helper function for function multi-versioning for RISC-V.
> +
> +   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.
> +
> +Under Section 7 of GPL version 3, you are granted additional
> +permissions described in the GCC Runtime Library Exception, version
> +3.1, as published by the Free Software Foundation.
> +
> +You should have received a copy of the GNU General Public License and
> +a copy of the GCC Runtime Library Exception along with this program;
> +see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#define RISCV_FEATURE_BITS_LENGTH 2
> +struct {
> +  unsigned length;
> +  unsigned long long features[RISCV_FEATURE_BITS_LENGTH];
> +} __riscv_feature_bits __attribute__ ((visibility ("hidden"), nocommon));
> +
> +#define RISCV_VENDOR_FEATURE_BITS_LENGTH 1
> +
> +struct {
> +  unsigned vendorID;
> +  unsigned length;
> +  unsigned long long features[RISCV_VENDOR_FEATURE_BITS_LENGTH];
> +} __riscv_vendor_feature_bits __attribute__ ((visibility ("hidden"), nocommon));
> +
> +#define A_GROUPID 0
> +#define A_BITMASK (1ULL << 0)
> +#define C_GROUPID 0
> +#define C_BITMASK (1ULL << 2)
> +#define D_GROUPID 0
> +#define D_BITMASK (1ULL << 3)
> +#define F_GROUPID 0
> +#define F_BITMASK (1ULL << 5)
> +#define I_GROUPID 0
> +#define I_BITMASK (1ULL << 8)
> +#define M_GROUPID 0
> +#define M_BITMASK (1ULL << 12)
> +#define V_GROUPID 0
> +#define V_BITMASK (1ULL << 21)
> +#define ZACAS_GROUPID 0
> +#define ZACAS_BITMASK (1ULL << 26)
> +#define ZBA_GROUPID 0
> +#define ZBA_BITMASK (1ULL << 27)
> +#define ZBB_GROUPID 0
> +#define ZBB_BITMASK (1ULL << 28)
> +#define ZBC_GROUPID 0
> +#define ZBC_BITMASK (1ULL << 29)
> +#define ZBKB_GROUPID 0
> +#define ZBKB_BITMASK (1ULL << 30)
> +#define ZBKC_GROUPID 0
> +#define ZBKC_BITMASK (1ULL << 31)
> +#define ZBKX_GROUPID 0
> +#define ZBKX_BITMASK (1ULL << 32)
> +#define ZBS_GROUPID 0
> +#define ZBS_BITMASK (1ULL << 33)
> +#define ZFA_GROUPID 0
> +#define ZFA_BITMASK (1ULL << 34)
> +#define ZFH_GROUPID 0
> +#define ZFH_BITMASK (1ULL << 35)
> +#define ZFHMIN_GROUPID 0
> +#define ZFHMIN_BITMASK (1ULL << 36)
> +#define ZICBOZ_GROUPID 0
> +#define ZICBOZ_BITMASK (1ULL << 37)
> +#define ZICOND_GROUPID 0
> +#define ZICOND_BITMASK (1ULL << 38)
> +#define ZIHINTNTL_GROUPID 0
> +#define ZIHINTNTL_BITMASK (1ULL << 39)
> +#define ZIHINTPAUSE_GROUPID 0
> +#define ZIHINTPAUSE_BITMASK (1ULL << 40)
> +#define ZKND_GROUPID 0
> +#define ZKND_BITMASK (1ULL << 41)
> +#define ZKNE_GROUPID 0
> +#define ZKNE_BITMASK (1ULL << 42)
> +#define ZKNH_GROUPID 0
> +#define ZKNH_BITMASK (1ULL << 43)
> +#define ZKSED_GROUPID 0
> +#define ZKSED_BITMASK (1ULL << 44)
> +#define ZKSH_GROUPID 0
> +#define ZKSH_BITMASK (1ULL << 45)
> +#define ZKT_GROUPID 0
> +#define ZKT_BITMASK (1ULL << 46)
> +#define ZTSO_GROUPID 0
> +#define ZTSO_BITMASK (1ULL << 47)
> +#define ZVBB_GROUPID 0
> +#define ZVBB_BITMASK (1ULL << 48)
> +#define ZVBC_GROUPID 0
> +#define ZVBC_BITMASK (1ULL << 49)
> +#define ZVFH_GROUPID 0
> +#define ZVFH_BITMASK (1ULL << 50)
> +#define ZVFHMIN_GROUPID 0
> +#define ZVFHMIN_BITMASK (1ULL << 51)
> +#define ZVKB_GROUPID 0
> +#define ZVKB_BITMASK (1ULL << 52)
> +#define ZVKG_GROUPID 0
> +#define ZVKG_BITMASK (1ULL << 53)
> +#define ZVKNED_GROUPID 0
> +#define ZVKNED_BITMASK (1ULL << 54)
> +#define ZVKNHA_GROUPID 0
> +#define ZVKNHA_BITMASK (1ULL << 55)
> +#define ZVKNHB_GROUPID 0
> +#define ZVKNHB_BITMASK (1ULL << 56)
> +#define ZVKSED_GROUPID 0
> +#define ZVKSED_BITMASK (1ULL << 57)
> +#define ZVKSH_GROUPID 0
> +#define ZVKSH_BITMASK (1ULL << 58)
> +#define ZVKT_GROUPID 0
> +#define ZVKT_BITMASK (1ULL << 59)
> +#define ZVE32X_GROUPID 0
> +#define ZVE32X_BITMASK (1ULL << 60)
> +#define ZVE32F_GROUPID 0
> +#define ZVE32F_BITMASK (1ULL << 61)
> +#define ZVE64X_GROUPID 0
> +#define ZVE64X_BITMASK (1ULL << 62)
> +#define ZVE64F_GROUPID 0
> +#define ZVE64F_BITMASK (1ULL << 63)
> +#define ZVE64D_GROUPID 1
> +#define ZVE64D_BITMASK (1ULL << 0)
> +#define ZIMOP_GROUPID 1
> +#define ZIMOP_BITMASK (1ULL << 1)
> +#define ZCA_GROUPID 1
> +#define ZCA_BITMASK (1ULL << 2)
> +#define ZCB_GROUPID 1
> +#define ZCB_BITMASK (1ULL << 3)
> +#define ZCD_GROUPID 1
> +#define ZCD_BITMASK (1ULL << 4)
> +#define ZCF_GROUPID 1
> +#define ZCF_BITMASK (1ULL << 5)
> +#define ZCMOP_GROUPID 1
> +#define ZCMOP_BITMASK (1ULL << 6)
> +#define ZAWRS_GROUPID 1
> +#define ZAWRS_BITMASK (1ULL << 7)
> +
> +#define SET_EXT(EXT) features[EXT##_GROUPID] |= EXT##_BITMASK
> +
> +#ifdef __linux
> +
> +#define __NR_riscv_hwprobe 258
> +#define RISCV_HWPROBE_KEY_MVENDORID 0
> +#define RISCV_HWPROBE_KEY_MARCHID 1
> +#define RISCV_HWPROBE_KEY_MIMPID 2
> +#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
> +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1ULL << 0)
> +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
> +#define RISCV_HWPROBE_IMA_FD (1ULL << 0)
> +#define RISCV_HWPROBE_IMA_C (1ULL << 1)
> +#define RISCV_HWPROBE_IMA_V (1ULL << 2)
> +#define RISCV_HWPROBE_EXT_ZBA (1ULL << 3)
> +#define RISCV_HWPROBE_EXT_ZBB (1ULL << 4)
> +#define RISCV_HWPROBE_EXT_ZBS (1ULL << 5)
> +#define RISCV_HWPROBE_EXT_ZICBOZ (1ULL << 6)
> +#define RISCV_HWPROBE_EXT_ZBC (1ULL << 7)
> +#define RISCV_HWPROBE_EXT_ZBKB (1ULL << 8)
> +#define RISCV_HWPROBE_EXT_ZBKC (1ULL << 9)
> +#define RISCV_HWPROBE_EXT_ZBKX (1ULL << 10)
> +#define RISCV_HWPROBE_EXT_ZKND (1ULL << 11)
> +#define RISCV_HWPROBE_EXT_ZKNE (1ULL << 12)
> +#define RISCV_HWPROBE_EXT_ZKNH (1ULL << 13)
> +#define RISCV_HWPROBE_EXT_ZKSED (1ULL << 14)
> +#define RISCV_HWPROBE_EXT_ZKSH (1ULL << 15)
> +#define RISCV_HWPROBE_EXT_ZKT (1ULL << 16)
> +#define RISCV_HWPROBE_EXT_ZVBB (1ULL << 17)
> +#define RISCV_HWPROBE_EXT_ZVBC (1ULL << 18)
> +#define RISCV_HWPROBE_EXT_ZVKB (1ULL << 19)
> +#define RISCV_HWPROBE_EXT_ZVKG (1ULL << 20)
> +#define RISCV_HWPROBE_EXT_ZVKNED (1ULL << 21)
> +#define RISCV_HWPROBE_EXT_ZVKNHA (1ULL << 22)
> +#define RISCV_HWPROBE_EXT_ZVKNHB (1ULL << 23)
> +#define RISCV_HWPROBE_EXT_ZVKSED (1ULL << 24)
> +#define RISCV_HWPROBE_EXT_ZVKSH (1ULL << 25)
> +#define RISCV_HWPROBE_EXT_ZVKT (1ULL << 26)
> +#define RISCV_HWPROBE_EXT_ZFH (1ULL << 27)
> +#define RISCV_HWPROBE_EXT_ZFHMIN (1ULL << 28)
> +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1ULL << 29)
> +#define RISCV_HWPROBE_EXT_ZVFH (1ULL << 30)
> +#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31)
> +#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32)
> +#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33)
> +#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34)
> +#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35)
> +#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36)
> +#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37)
> +#define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38)
> +#define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39)
> +#define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40)
> +#define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41)
> +#define RISCV_HWPROBE_EXT_ZIMOP  (1ULL << 42)
> +#define RISCV_HWPROBE_EXT_ZCA    (1ULL << 43)
> +#define RISCV_HWPROBE_EXT_ZCB    (1ULL << 44)
> +#define RISCV_HWPROBE_EXT_ZCD    (1ULL << 45)
> +#define RISCV_HWPROBE_EXT_ZCF    (1ULL << 46)
> +#define RISCV_HWPROBE_EXT_ZCMOP  (1ULL << 47)
> +#define RISCV_HWPROBE_EXT_ZAWRS  (1ULL << 48)
> +#define RISCV_HWPROBE_KEY_CPUPERF_0 5
> +#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
> +#define RISCV_HWPROBE_MISALIGNED_EMULATED (1ULL << 0)
> +#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0)
> +#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0)
> +#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
> +#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
> +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
> +
> +struct riscv_hwprobe {
> +  long long key;
> +  unsigned long long value;
> +};
> +
> +static long syscall_5_args (long number, long arg1, long arg2, long arg3,
> +                           long arg4, long arg5)
> +{
> +  register long a7 __asm__ ("a7") = number;
> +  register long a0 __asm__ ("a0") = arg1;
> +  register long a1 __asm__ ("a1") = arg2;
> +  register long a2 __asm__ ("a2") = arg3;
> +  register long a3 __asm__ ("a3") = arg4;
> +  register long a4 __asm__ ("a4") = arg5;
> +  __asm__ __volatile__ ("ecall\n\t"
> +                       : "=r"(a0)
> +                       : "r"(a7), "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
> +                       : "memory");
> +  return a0;
> +}
> +
> +#define SET_FROM_HWPROBE(HWPROBE_VAR, EXT) \
> +  if (HWPROBE_VAR.value & RISCV_HWPROBE_EXT_##EXT) \
> +    SET_EXT (EXT)
> +
> +#define SET_FROM_IMA_EXT(EXT) \
> +  SET_FROM_HWPROBE (hwprobe_ima_ext, EXT)
> +
> +static void __init_riscv_features_bits_linux ()
> +{
> +  struct riscv_hwprobe hwprobes[] = {
> +    {RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0},
> +    {RISCV_HWPROBE_KEY_IMA_EXT_0, 0},
> +    {RISCV_HWPROBE_KEY_MVENDORID, 0},
> +  };
> +
> +  long res = syscall_5_args (__NR_riscv_hwprobe, (long)&hwprobes,
> +                            sizeof (hwprobes) / sizeof (hwprobes[0]), 0,
> +                            0, 0);
> +
> +  if (res)
> +    return;
> +
> +  const struct riscv_hwprobe hwprobe_base_behavior = hwprobes[0];
> +  unsigned long long features[RISCV_FEATURE_BITS_LENGTH];
> +  int i;
> +  for (i = 0; i < RISCV_FEATURE_BITS_LENGTH; ++i)
> +    features[i] = 0;
> +
> +  if (hwprobe_base_behavior.value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA)
> +    {
> +      SET_EXT (I);
> +      SET_EXT (M);
> +      SET_EXT (A);
> +    }
> +
> +  const struct riscv_hwprobe hwprobe_mvendorid = hwprobes[2];
> +
> +  __riscv_vendor_feature_bits.length = 0;
> +  __riscv_vendor_feature_bits.vendorID = hwprobe_mvendorid.value;
> +
> +  const struct riscv_hwprobe hwprobe_ima_ext = hwprobes[1];
> +
> +  if (hwprobe_ima_ext.value & RISCV_HWPROBE_IMA_FD)
> +    {
> +      SET_EXT (F);
> +      SET_EXT (D);
> +    }
> +
> +  if (hwprobe_ima_ext.value & RISCV_HWPROBE_IMA_C)
> +    SET_EXT (C);
> +  if (hwprobe_ima_ext.value & RISCV_HWPROBE_IMA_V)
> +    SET_EXT (V);
> +
> +  SET_FROM_IMA_EXT (ZBA);
> +  SET_FROM_IMA_EXT (ZBB);
> +  SET_FROM_IMA_EXT (ZBS);
> +  SET_FROM_IMA_EXT (ZICBOZ);
> +  SET_FROM_IMA_EXT (ZBC);
> +  SET_FROM_IMA_EXT (ZBKB);
> +  SET_FROM_IMA_EXT (ZBKC);
> +  SET_FROM_IMA_EXT (ZBKX);
> +  SET_FROM_IMA_EXT (ZKND);
> +  SET_FROM_IMA_EXT (ZKNE);
> +  SET_FROM_IMA_EXT (ZKNH);
> +  SET_FROM_IMA_EXT (ZKSED);
> +  SET_FROM_IMA_EXT (ZKSH);
> +  SET_FROM_IMA_EXT (ZKT);
> +  SET_FROM_IMA_EXT (ZVBB);
> +  SET_FROM_IMA_EXT (ZVBC);
> +  SET_FROM_IMA_EXT (ZVKB);
> +  SET_FROM_IMA_EXT (ZVKG);
> +  SET_FROM_IMA_EXT (ZVKNED);
> +  SET_FROM_IMA_EXT (ZVKNHA);
> +  SET_FROM_IMA_EXT (ZVKNHB);
> +  SET_FROM_IMA_EXT (ZVKSED);
> +  SET_FROM_IMA_EXT (ZVKSH);
> +  SET_FROM_IMA_EXT (ZVKT);
> +  SET_FROM_IMA_EXT (ZFH);
> +  SET_FROM_IMA_EXT (ZFHMIN);
> +  SET_FROM_IMA_EXT (ZIHINTNTL);
> +  SET_FROM_IMA_EXT (ZIHINTPAUSE);
> +  SET_FROM_IMA_EXT (ZVFH);
> +  SET_FROM_IMA_EXT (ZVFHMIN);
> +  SET_FROM_IMA_EXT (ZFA);
> +  SET_FROM_IMA_EXT (ZTSO);
> +  SET_FROM_IMA_EXT (ZACAS);
> +  SET_FROM_IMA_EXT (ZICOND);
> +  SET_FROM_IMA_EXT (ZVE32X);
> +  SET_FROM_IMA_EXT (ZVE32F);
> +  SET_FROM_IMA_EXT (ZVE64X);
> +  SET_FROM_IMA_EXT (ZVE64F);
> +  SET_FROM_IMA_EXT (ZVE64D);
> +  SET_FROM_IMA_EXT (ZIMOP);
> +  SET_FROM_IMA_EXT (ZCA);
> +  SET_FROM_IMA_EXT (ZCB);
> +  SET_FROM_IMA_EXT (ZCD);
> +  SET_FROM_IMA_EXT (ZCF);
> +  SET_FROM_IMA_EXT (ZCMOP);
> +  SET_FROM_IMA_EXT (ZAWRS);
> +
> +  for (i = 0; i < RISCV_FEATURE_BITS_LENGTH; ++i)
> +    __riscv_feature_bits.features[i] = features[i];
> +
> +  __riscv_feature_bits.length = RISCV_FEATURE_BITS_LENGTH;
> +}
> +#endif
> +
> +
> +static int __init = 0;
> +
> +void
> +__attribute__ ((constructor (101)))
> +__init_riscv_feature_bits ()
> +{
> +  if (__init)
> +    return;
> +
> +#ifdef __linux
> +  __init_riscv_features_bits_linux ();
> +#else
> +  /* Unsupported, just initlizaed that into all zeros.  */
> +  __riscv_feature_bits.length = 0;
> +  __riscv_vendor_feature_bits.length = 0;
> +  __riscv_vendor_feature_bits.vendorID = 0;
> +#endif
> +
> +  __init = 1;
> +}
> diff --git a/libgcc/config/riscv/t-elf b/libgcc/config/riscv/t-elf
> index 415e1fffbe7..acb5e280676 100644
> --- a/libgcc/config/riscv/t-elf
> +++ b/libgcc/config/riscv/t-elf
> @@ -3,6 +3,7 @@ LIB2ADD += $(srcdir)/config/riscv/save-restore.S \
>            $(srcdir)/config/riscv/multi3.c \
>            $(srcdir)/config/riscv/div.S \
>            $(srcdir)/config/riscv/atomic.c \
> +          $(srcdir)/config/riscv/feature_bits.c \
>
>  # Avoid the full unwinder being pulled along with the division libcalls.
>  LIB2_DIVMOD_EXCEPTION_FLAGS := -fasynchronous-unwind-tables
> --
> 2.45.2
>
Yangyu Chen Oct. 13, 2024, 8:46 a.m. UTC | #2
> On Oct 7, 2024, at 18:15, Kito Cheng <kito.cheng@gmail.com> wrote:
> 
> Could you implement the latest API defined in the doc?
> 
> struct {
> unsigned length;
> unsigned long long features[];
> } __riscv_feature_bits;
> 
> struct {
> unsigned length;
> unsigned long long features[];
> } __riscv_vendor_feature_bits;
> 
> struct {
> unsigned mvendorid;
> unsigned marchid;
> unsigned mimpid;
> } __riscv_cpu_model;
> 

I doubt whether we should use unsigned instead of unsigned long for marchid and mimpid since they are XLEN-sized CSR:

https://github.com/riscv-non-isa/riscv-c-api-doc/pull/74#discussion_r1798166307

I will submit another patch when this question has been resolved.
diff mbox series

Patch

diff --git a/libgcc/config/riscv/feature_bits.c b/libgcc/config/riscv/feature_bits.c
new file mode 100644
index 00000000000..c5339f065c1
--- /dev/null
+++ b/libgcc/config/riscv/feature_bits.c
@@ -0,0 +1,364 @@ 
+/* Helper function for function multi-versioning for RISC-V.
+
+   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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#define RISCV_FEATURE_BITS_LENGTH 2
+struct {
+  unsigned length;
+  unsigned long long features[RISCV_FEATURE_BITS_LENGTH];
+} __riscv_feature_bits __attribute__ ((visibility ("hidden"), nocommon));
+
+#define RISCV_VENDOR_FEATURE_BITS_LENGTH 1
+
+struct {
+  unsigned vendorID;
+  unsigned length;
+  unsigned long long features[RISCV_VENDOR_FEATURE_BITS_LENGTH];
+} __riscv_vendor_feature_bits __attribute__ ((visibility ("hidden"), nocommon));
+
+#define A_GROUPID 0
+#define A_BITMASK (1ULL << 0)
+#define C_GROUPID 0
+#define C_BITMASK (1ULL << 2)
+#define D_GROUPID 0
+#define D_BITMASK (1ULL << 3)
+#define F_GROUPID 0
+#define F_BITMASK (1ULL << 5)
+#define I_GROUPID 0
+#define I_BITMASK (1ULL << 8)
+#define M_GROUPID 0
+#define M_BITMASK (1ULL << 12)
+#define V_GROUPID 0
+#define V_BITMASK (1ULL << 21)
+#define ZACAS_GROUPID 0
+#define ZACAS_BITMASK (1ULL << 26)
+#define ZBA_GROUPID 0
+#define ZBA_BITMASK (1ULL << 27)
+#define ZBB_GROUPID 0
+#define ZBB_BITMASK (1ULL << 28)
+#define ZBC_GROUPID 0
+#define ZBC_BITMASK (1ULL << 29)
+#define ZBKB_GROUPID 0
+#define ZBKB_BITMASK (1ULL << 30)
+#define ZBKC_GROUPID 0
+#define ZBKC_BITMASK (1ULL << 31)
+#define ZBKX_GROUPID 0
+#define ZBKX_BITMASK (1ULL << 32)
+#define ZBS_GROUPID 0
+#define ZBS_BITMASK (1ULL << 33)
+#define ZFA_GROUPID 0
+#define ZFA_BITMASK (1ULL << 34)
+#define ZFH_GROUPID 0
+#define ZFH_BITMASK (1ULL << 35)
+#define ZFHMIN_GROUPID 0
+#define ZFHMIN_BITMASK (1ULL << 36)
+#define ZICBOZ_GROUPID 0
+#define ZICBOZ_BITMASK (1ULL << 37)
+#define ZICOND_GROUPID 0
+#define ZICOND_BITMASK (1ULL << 38)
+#define ZIHINTNTL_GROUPID 0
+#define ZIHINTNTL_BITMASK (1ULL << 39)
+#define ZIHINTPAUSE_GROUPID 0
+#define ZIHINTPAUSE_BITMASK (1ULL << 40)
+#define ZKND_GROUPID 0
+#define ZKND_BITMASK (1ULL << 41)
+#define ZKNE_GROUPID 0
+#define ZKNE_BITMASK (1ULL << 42)
+#define ZKNH_GROUPID 0
+#define ZKNH_BITMASK (1ULL << 43)
+#define ZKSED_GROUPID 0
+#define ZKSED_BITMASK (1ULL << 44)
+#define ZKSH_GROUPID 0
+#define ZKSH_BITMASK (1ULL << 45)
+#define ZKT_GROUPID 0
+#define ZKT_BITMASK (1ULL << 46)
+#define ZTSO_GROUPID 0
+#define ZTSO_BITMASK (1ULL << 47)
+#define ZVBB_GROUPID 0
+#define ZVBB_BITMASK (1ULL << 48)
+#define ZVBC_GROUPID 0
+#define ZVBC_BITMASK (1ULL << 49)
+#define ZVFH_GROUPID 0
+#define ZVFH_BITMASK (1ULL << 50)
+#define ZVFHMIN_GROUPID 0
+#define ZVFHMIN_BITMASK (1ULL << 51)
+#define ZVKB_GROUPID 0
+#define ZVKB_BITMASK (1ULL << 52)
+#define ZVKG_GROUPID 0
+#define ZVKG_BITMASK (1ULL << 53)
+#define ZVKNED_GROUPID 0
+#define ZVKNED_BITMASK (1ULL << 54)
+#define ZVKNHA_GROUPID 0
+#define ZVKNHA_BITMASK (1ULL << 55)
+#define ZVKNHB_GROUPID 0
+#define ZVKNHB_BITMASK (1ULL << 56)
+#define ZVKSED_GROUPID 0
+#define ZVKSED_BITMASK (1ULL << 57)
+#define ZVKSH_GROUPID 0
+#define ZVKSH_BITMASK (1ULL << 58)
+#define ZVKT_GROUPID 0
+#define ZVKT_BITMASK (1ULL << 59)
+#define ZVE32X_GROUPID 0
+#define ZVE32X_BITMASK (1ULL << 60)
+#define ZVE32F_GROUPID 0
+#define ZVE32F_BITMASK (1ULL << 61)
+#define ZVE64X_GROUPID 0
+#define ZVE64X_BITMASK (1ULL << 62)
+#define ZVE64F_GROUPID 0
+#define ZVE64F_BITMASK (1ULL << 63)
+#define ZVE64D_GROUPID 1
+#define ZVE64D_BITMASK (1ULL << 0)
+#define ZIMOP_GROUPID 1
+#define ZIMOP_BITMASK (1ULL << 1)
+#define ZCA_GROUPID 1
+#define ZCA_BITMASK (1ULL << 2)
+#define ZCB_GROUPID 1
+#define ZCB_BITMASK (1ULL << 3)
+#define ZCD_GROUPID 1
+#define ZCD_BITMASK (1ULL << 4)
+#define ZCF_GROUPID 1
+#define ZCF_BITMASK (1ULL << 5)
+#define ZCMOP_GROUPID 1
+#define ZCMOP_BITMASK (1ULL << 6)
+#define ZAWRS_GROUPID 1
+#define ZAWRS_BITMASK (1ULL << 7)
+
+#define SET_EXT(EXT) features[EXT##_GROUPID] |= EXT##_BITMASK
+
+#ifdef __linux
+
+#define __NR_riscv_hwprobe 258
+#define RISCV_HWPROBE_KEY_MVENDORID 0
+#define RISCV_HWPROBE_KEY_MARCHID 1
+#define RISCV_HWPROBE_KEY_MIMPID 2
+#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
+#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1ULL << 0)
+#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
+#define RISCV_HWPROBE_IMA_FD (1ULL << 0)
+#define RISCV_HWPROBE_IMA_C (1ULL << 1)
+#define RISCV_HWPROBE_IMA_V (1ULL << 2)
+#define RISCV_HWPROBE_EXT_ZBA (1ULL << 3)
+#define RISCV_HWPROBE_EXT_ZBB (1ULL << 4)
+#define RISCV_HWPROBE_EXT_ZBS (1ULL << 5)
+#define RISCV_HWPROBE_EXT_ZICBOZ (1ULL << 6)
+#define RISCV_HWPROBE_EXT_ZBC (1ULL << 7)
+#define RISCV_HWPROBE_EXT_ZBKB (1ULL << 8)
+#define RISCV_HWPROBE_EXT_ZBKC (1ULL << 9)
+#define RISCV_HWPROBE_EXT_ZBKX (1ULL << 10)
+#define RISCV_HWPROBE_EXT_ZKND (1ULL << 11)
+#define RISCV_HWPROBE_EXT_ZKNE (1ULL << 12)
+#define RISCV_HWPROBE_EXT_ZKNH (1ULL << 13)
+#define RISCV_HWPROBE_EXT_ZKSED (1ULL << 14)
+#define RISCV_HWPROBE_EXT_ZKSH (1ULL << 15)
+#define RISCV_HWPROBE_EXT_ZKT (1ULL << 16)
+#define RISCV_HWPROBE_EXT_ZVBB (1ULL << 17)
+#define RISCV_HWPROBE_EXT_ZVBC (1ULL << 18)
+#define RISCV_HWPROBE_EXT_ZVKB (1ULL << 19)
+#define RISCV_HWPROBE_EXT_ZVKG (1ULL << 20)
+#define RISCV_HWPROBE_EXT_ZVKNED (1ULL << 21)
+#define RISCV_HWPROBE_EXT_ZVKNHA (1ULL << 22)
+#define RISCV_HWPROBE_EXT_ZVKNHB (1ULL << 23)
+#define RISCV_HWPROBE_EXT_ZVKSED (1ULL << 24)
+#define RISCV_HWPROBE_EXT_ZVKSH (1ULL << 25)
+#define RISCV_HWPROBE_EXT_ZVKT (1ULL << 26)
+#define RISCV_HWPROBE_EXT_ZFH (1ULL << 27)
+#define RISCV_HWPROBE_EXT_ZFHMIN (1ULL << 28)
+#define RISCV_HWPROBE_EXT_ZIHINTNTL (1ULL << 29)
+#define RISCV_HWPROBE_EXT_ZVFH (1ULL << 30)
+#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31)
+#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32)
+#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33)
+#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34)
+#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35)
+#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36)
+#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37)
+#define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38)
+#define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39)
+#define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40)
+#define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41)
+#define RISCV_HWPROBE_EXT_ZIMOP  (1ULL << 42)
+#define RISCV_HWPROBE_EXT_ZCA    (1ULL << 43)
+#define RISCV_HWPROBE_EXT_ZCB    (1ULL << 44)
+#define RISCV_HWPROBE_EXT_ZCD    (1ULL << 45)
+#define RISCV_HWPROBE_EXT_ZCF    (1ULL << 46)
+#define RISCV_HWPROBE_EXT_ZCMOP  (1ULL << 47)
+#define RISCV_HWPROBE_EXT_ZAWRS  (1ULL << 48)
+#define RISCV_HWPROBE_KEY_CPUPERF_0 5
+#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
+#define RISCV_HWPROBE_MISALIGNED_EMULATED (1ULL << 0)
+#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0)
+#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0)
+#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
+#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
+#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
+
+struct riscv_hwprobe {
+  long long key;
+  unsigned long long value;
+};
+
+static long syscall_5_args (long number, long arg1, long arg2, long arg3,
+			    long arg4, long arg5)
+{
+  register long a7 __asm__ ("a7") = number;
+  register long a0 __asm__ ("a0") = arg1;
+  register long a1 __asm__ ("a1") = arg2;
+  register long a2 __asm__ ("a2") = arg3;
+  register long a3 __asm__ ("a3") = arg4;
+  register long a4 __asm__ ("a4") = arg5;
+  __asm__ __volatile__ ("ecall\n\t"
+			: "=r"(a0)
+			: "r"(a7), "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
+			: "memory");
+  return a0;
+}
+
+#define SET_FROM_HWPROBE(HWPROBE_VAR, EXT) \
+  if (HWPROBE_VAR.value & RISCV_HWPROBE_EXT_##EXT) \
+    SET_EXT (EXT)
+
+#define SET_FROM_IMA_EXT(EXT) \
+  SET_FROM_HWPROBE (hwprobe_ima_ext, EXT)
+
+static void __init_riscv_features_bits_linux ()
+{
+  struct riscv_hwprobe hwprobes[] = {
+    {RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0},
+    {RISCV_HWPROBE_KEY_IMA_EXT_0, 0},
+    {RISCV_HWPROBE_KEY_MVENDORID, 0},
+  };
+
+  long res = syscall_5_args (__NR_riscv_hwprobe, (long)&hwprobes,
+			     sizeof (hwprobes) / sizeof (hwprobes[0]), 0,
+			     0, 0);
+
+  if (res)
+    return;
+
+  const struct riscv_hwprobe hwprobe_base_behavior = hwprobes[0];
+  unsigned long long features[RISCV_FEATURE_BITS_LENGTH];
+  int i;
+  for (i = 0; i < RISCV_FEATURE_BITS_LENGTH; ++i)
+    features[i] = 0;
+
+  if (hwprobe_base_behavior.value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA)
+    {
+      SET_EXT (I);
+      SET_EXT (M);
+      SET_EXT (A);
+    }
+
+  const struct riscv_hwprobe hwprobe_mvendorid = hwprobes[2];
+
+  __riscv_vendor_feature_bits.length = 0;
+  __riscv_vendor_feature_bits.vendorID = hwprobe_mvendorid.value;
+
+  const struct riscv_hwprobe hwprobe_ima_ext = hwprobes[1];
+
+  if (hwprobe_ima_ext.value & RISCV_HWPROBE_IMA_FD)
+    {
+      SET_EXT (F);
+      SET_EXT (D);
+    }
+
+  if (hwprobe_ima_ext.value & RISCV_HWPROBE_IMA_C)
+    SET_EXT (C);
+  if (hwprobe_ima_ext.value & RISCV_HWPROBE_IMA_V)
+    SET_EXT (V);
+
+  SET_FROM_IMA_EXT (ZBA);
+  SET_FROM_IMA_EXT (ZBB);
+  SET_FROM_IMA_EXT (ZBS);
+  SET_FROM_IMA_EXT (ZICBOZ);
+  SET_FROM_IMA_EXT (ZBC);
+  SET_FROM_IMA_EXT (ZBKB);
+  SET_FROM_IMA_EXT (ZBKC);
+  SET_FROM_IMA_EXT (ZBKX);
+  SET_FROM_IMA_EXT (ZKND);
+  SET_FROM_IMA_EXT (ZKNE);
+  SET_FROM_IMA_EXT (ZKNH);
+  SET_FROM_IMA_EXT (ZKSED);
+  SET_FROM_IMA_EXT (ZKSH);
+  SET_FROM_IMA_EXT (ZKT);
+  SET_FROM_IMA_EXT (ZVBB);
+  SET_FROM_IMA_EXT (ZVBC);
+  SET_FROM_IMA_EXT (ZVKB);
+  SET_FROM_IMA_EXT (ZVKG);
+  SET_FROM_IMA_EXT (ZVKNED);
+  SET_FROM_IMA_EXT (ZVKNHA);
+  SET_FROM_IMA_EXT (ZVKNHB);
+  SET_FROM_IMA_EXT (ZVKSED);
+  SET_FROM_IMA_EXT (ZVKSH);
+  SET_FROM_IMA_EXT (ZVKT);
+  SET_FROM_IMA_EXT (ZFH);
+  SET_FROM_IMA_EXT (ZFHMIN);
+  SET_FROM_IMA_EXT (ZIHINTNTL);
+  SET_FROM_IMA_EXT (ZIHINTPAUSE);
+  SET_FROM_IMA_EXT (ZVFH);
+  SET_FROM_IMA_EXT (ZVFHMIN);
+  SET_FROM_IMA_EXT (ZFA);
+  SET_FROM_IMA_EXT (ZTSO);
+  SET_FROM_IMA_EXT (ZACAS);
+  SET_FROM_IMA_EXT (ZICOND);
+  SET_FROM_IMA_EXT (ZVE32X);
+  SET_FROM_IMA_EXT (ZVE32F);
+  SET_FROM_IMA_EXT (ZVE64X);
+  SET_FROM_IMA_EXT (ZVE64F);
+  SET_FROM_IMA_EXT (ZVE64D);
+  SET_FROM_IMA_EXT (ZIMOP);
+  SET_FROM_IMA_EXT (ZCA);
+  SET_FROM_IMA_EXT (ZCB);
+  SET_FROM_IMA_EXT (ZCD);
+  SET_FROM_IMA_EXT (ZCF);
+  SET_FROM_IMA_EXT (ZCMOP);
+  SET_FROM_IMA_EXT (ZAWRS);
+
+  for (i = 0; i < RISCV_FEATURE_BITS_LENGTH; ++i)
+    __riscv_feature_bits.features[i] = features[i];
+
+  __riscv_feature_bits.length = RISCV_FEATURE_BITS_LENGTH;
+}
+#endif
+
+
+static int __init = 0;
+
+void
+__attribute__ ((constructor (101)))
+__init_riscv_feature_bits ()
+{
+  if (__init)
+    return;
+
+#ifdef __linux
+  __init_riscv_features_bits_linux ();
+#else
+  /* Unsupported, just initlizaed that into all zeros.  */
+  __riscv_feature_bits.length = 0;
+  __riscv_vendor_feature_bits.length = 0;
+  __riscv_vendor_feature_bits.vendorID = 0;
+#endif
+
+  __init = 1;
+}
diff --git a/libgcc/config/riscv/t-elf b/libgcc/config/riscv/t-elf
index 415e1fffbe7..acb5e280676 100644
--- a/libgcc/config/riscv/t-elf
+++ b/libgcc/config/riscv/t-elf
@@ -3,6 +3,7 @@  LIB2ADD += $(srcdir)/config/riscv/save-restore.S \
 	   $(srcdir)/config/riscv/multi3.c \
 	   $(srcdir)/config/riscv/div.S \
 	   $(srcdir)/config/riscv/atomic.c \
+	   $(srcdir)/config/riscv/feature_bits.c \
 
 # Avoid the full unwinder being pulled along with the division libcalls.
 LIB2_DIVMOD_EXCEPTION_FLAGS := -fasynchronous-unwind-tables