diff --git a/libgcc/config/loongarch/cpuinfo.c b/libgcc/config/loongarch/cpuinfo.c new file mode 100644 index 000000000000..293eb52f047a --- /dev/null +++ b/libgcc/config/loongarch/cpuinfo.c @@ -0,0 +1,90 @@ +/* CPU feature detection for LoongArch architecture. + Copyright (C) 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 +. */ + +#include "common/config/loongarch/cpu-features.h" + +#if __has_include() +#include + +#define CPUCFG1_LA64 2ULL << 0 +#define CPUCFG1_UAL 1ULL << 20 +#define CPUCFG2_LSX 1ULL << 6 +#define CPUCFG2_LASX 1ULL << 7 +#define CPUCFG2_FRECIPE 1ULL << 25 +#define CPUCFG2_DIV32 1ULL << 26 +#define CPUCFG2_LAM_BH 1ULL << 27 +#define CPUCFG2_LAMCAS 1ULL << 28 +#define CPUCFG2_SCQ 1ULL << 30 +#define CPUCFG3_LD_SEQ_SA 1ULL << 23 + +struct { + loongarch_fmv_feature_mask features; +} __loongarch_feature_bits __attribute__ ((visibility ("hidden"), nocommon)); + +void __init_loongarch_features_resolver (void); +void +__init_loongarch_features_resolver (void) +{ + if (__atomic_load_n (&__loongarch_feature_bits.features, __ATOMIC_RELAXED)) + return; + + loongarch_fmv_feature_mask feat = 0ULL; +#define setCPUFeature(F) feat |= 1ULL << F; + unsigned int CPUCFG1 = __builtin_loongarch_cpucfg (1); + unsigned int CPUCFG2 = __builtin_loongarch_cpucfg (2); + unsigned int CPUCFG3 = __builtin_loongarch_cpucfg (3); + unsigned long hwcap = getauxval (AT_HWCAP); + + if (CPUCFG1 & CPUCFG1_LA64) + setCPUFeature (FEAT_LA64); + if (CPUCFG1 & CPUCFG1_UAL) + setCPUFeature (FEAT_UAL); + if (CPUCFG2 & CPUCFG2_FRECIPE) + setCPUFeature (FEAT_FRECIPE); + if (CPUCFG2 & CPUCFG2_DIV32) + setCPUFeature (FEAT_DIV32); + if (CPUCFG2 & CPUCFG2_LAM_BH) + setCPUFeature (FEAT_LAM_BH); + if (CPUCFG2 & CPUCFG2_LAMCAS) + setCPUFeature (FEAT_LAMCAS); + if (CPUCFG2 & CPUCFG2_SCQ) + setCPUFeature (FEAT_SCQ); + if (CPUCFG3 & CPUCFG3_LD_SEQ_SA) + setCPUFeature (FEAT_LD_SEQ_SA); + + /* LSX and LASX can be disabled/enabled by kernel: on some old kernel + versions the vector context switch wasn't implemented and so they are + always disabled, and on Linux >= 6.18-rc1 the user can pass simd= + parameter via kernel cmdline to disable LSX or LASX for debug or + powersave purpose: + https://git.kernel.org/torvalds/c/5dcddd268a8d + Thus for LSX and LASX HWCAP must be used.*/ + if (hwcap & HWCAP_LOONGARCH_LSX) + setCPUFeature (FEAT_LSX); + if (hwcap & HWCAP_LOONGARCH_LASX) + setCPUFeature (FEAT_LASX); +#undef setCPUFeature + __atomic_store_n (&__loongarch_feature_bits.features, feat, __ATOMIC_RELAXED); +} +#endif /* __has_include() */ diff --git a/libgcc/config/loongarch/t-loongarch64 b/libgcc/config/loongarch/t-loongarch64 index a1e3513e2884..20d15207515c 100644 --- a/libgcc/config/loongarch/t-loongarch64 +++ b/libgcc/config/loongarch/t-loongarch64 @@ -1 +1,3 @@ +LIB2ADD += $(srcdir)/config/loongarch/cpuinfo.c + softfp_int_modes += ti