new file mode 100644
@@ -0,0 +1,403 @@
+/* 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));
+
+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_vendor_feature_bits.length = 0;
+ __riscv_vendor_feature_bits.vendorID = hwprobe_mvendorid.value;
+ __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. */
+
+ 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)
+ {
+ SET_EXT (ZCF);
+ SET_EXT (ZCD);
+ }
+ }
+
+ 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.8. */
+ 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 (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 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;
+}
@@ -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