| /* Helper function for function multi-versioning for RISC-V. |
| |
| Copyright (C) 2024-2025 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)); |
| |
| struct { |
| unsigned mvendorid; |
| unsigned long long marchid; |
| unsigned long long mimpid; |
| } __riscv_cpu_model __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_MVENDORID, 0}, |
| {RISCV_HWPROBE_KEY_MARCHID, 0}, |
| {RISCV_HWPROBE_KEY_MIMPID, 0}, |
| {RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0}, |
| {RISCV_HWPROBE_KEY_IMA_EXT_0, 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_mvendorid = hwprobes[0]; |
| |
| __riscv_cpu_model.mvendorid = hwprobe_mvendorid.value; |
| |
| const struct riscv_hwprobe hwprobe_marchid = hwprobes[1]; |
| |
| __riscv_cpu_model.marchid = hwprobe_marchid.value; |
| |
| const struct riscv_hwprobe hwprobe_mimpid = hwprobes[2]; |
| |
| __riscv_cpu_model.mimpid = hwprobe_mimpid.value; |
| |
| const struct riscv_hwprobe hwprobe_base_behavior = hwprobes[3]; |
| 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_ima_ext = hwprobes[4]; |
| /* Every time we add new extensions, we should check if previous extensions |
| imply the new extension and set the corresponding bit. |
| We don't need to handle cases where: |
| 1. The new extension implies a previous extension (e.g., Zve32f -> F). |
| 2. The extensions imply some other extensions appear in the same release |
| version of Linux Kernel (e.g., Zbc - > Zbkc). */ |
| |
| 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); |
| SET_EXT (ZCA); |
| if (hwprobe_ima_ext.value & RISCV_HWPROBE_IMA_FD) |
| { |
| #if __riscv_xlen == 32 |
| SET_EXT (ZCF); |
| #endif |
| SET_EXT (ZCD); |
| } |
| } |
| |
| /* Added since Linux v6.5. */ |
| if (hwprobe_ima_ext.value & RISCV_HWPROBE_IMA_V) |
| { |
| SET_EXT (V); |
| SET_EXT (ZVE32X); |
| SET_EXT (ZVE32F); |
| SET_EXT (ZVE64X); |
| SET_EXT (ZVE64F); |
| SET_EXT (ZVE64D); |
| } |
| |
| SET_FROM_IMA_EXT (ZBA); |
| SET_FROM_IMA_EXT (ZBB); |
| SET_FROM_IMA_EXT (ZBS); |
| /* Added since Linux v6.7. */ |
| SET_FROM_IMA_EXT (ZICBOZ); |
| /* Added since Linux v6.8. */ |
| 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 (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); |
| /* Added since Linux v6.10. */ |
| SET_FROM_IMA_EXT (ZIHINTPAUSE); |
| /* Added since Linux v6.11. */ |
| 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 initialize that into all zeros. */ |
| __riscv_feature_bits.length = 0; |
| __riscv_cpu_model.mvendorid = 0; |
| __riscv_cpu_model.marchid = 0; |
| __riscv_cpu_model.mimpid = 0; |
| #endif |
| |
| __init = 1; |
| } |