diff --git a/0034-Add-Loongarch-backend-support.patch b/0034-LoongArch-ABI2.01-support.patch similarity index 43% rename from 0034-Add-Loongarch-backend-support.patch rename to 0034-LoongArch-ABI2.01-support.patch index 748a7af662f0679f0ebb912af9f1803e101f5079..e9c56efd1ac479715af5a1b73815faa5259fd63f 100644 --- a/0034-Add-Loongarch-backend-support.patch +++ b/0034-LoongArch-ABI2.01-support.patch @@ -1,31 +1,48 @@ -diff -uNr gcc-10.3.0.org/config.guess gcc-10.3.0/config.guess ---- gcc-10.3.0.org/config.guess 2021-04-08 19:56:27.573734691 +0800 -+++ gcc-10.3.0/config.guess 2022-03-23 17:40:29.339280184 +0800 -@@ -980,6 +980,9 @@ +diff --git a/config.guess b/config.guess +index 97ad07333..0739a4cce 100755 +--- a/config.guess ++++ b/config.guess +@@ -980,6 +980,9 @@ EOF k1om:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; -+ loongarch*:Linux:*:*) -+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" ++ loongarch*:Linux:*:*) ++ echo "$UNAME_MACHINE"-linux-"$LIBC" + exit ;; m32r*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; -diff -uNr gcc-10.3.0.org/config.sub gcc-10.3.0/config.sub ---- gcc-10.3.0.org/config.sub 2021-04-08 19:56:27.573734691 +0800 -+++ gcc-10.3.0/config.sub 2022-03-23 17:40:29.339280184 +0800 -@@ -1183,6 +1183,7 @@ +diff --git a/config.sub b/config.sub +index a318a4686..cb3b2f848 100755 +--- a/config.sub ++++ b/config.sub +@@ -1183,6 +1183,7 @@ case $cpu-$vendor in | k1om \ | le32 | le64 \ | lm32 \ -+ | loongarch32 | loongarchx32 | loongarch64 \ ++ | loongarch32 | loongarch64 | loongarchx32 \ | m32c | m32r | m32rle \ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ -diff -uNr gcc-10.3.0.org/configure gcc-10.3.0/configure ---- gcc-10.3.0.org/configure 2022-03-23 17:25:14.304350355 +0800 -+++ gcc-10.3.0/configure 2022-03-28 11:15:09.028369464 +0800 -@@ -3029,7 +3029,7 @@ +diff --git a/config/picflag.m4 b/config/picflag.m4 +index 8b106f9af..0aefcf619 100644 +--- a/config/picflag.m4 ++++ b/config/picflag.m4 +@@ -44,6 +44,9 @@ case "${$2}" in + # sets the default TLS model and affects inlining. + $1=-fPIC + ;; ++ loongarch*-*-*) ++ $1=-fpic ++ ;; + mips-sgi-irix6*) + # PIC is the default. + ;; +diff --git a/configure b/configure +index f2ec106a8..b117bb5da 100755 +--- a/configure ++++ b/configure +@@ -3027,7 +3027,7 @@ case "${ENABLE_GOLD}" in # Check for target supported by gold. case "${target}" in i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-* \ @@ -34,7 +51,7 @@ diff -uNr gcc-10.3.0.org/configure gcc-10.3.0/configure configdirs="$configdirs gold" if test x${ENABLE_GOLD} = xdefault; then default_ld=gold -@@ -3641,6 +3641,9 @@ +@@ -3639,6 +3639,9 @@ case "${target}" in i[3456789]86-*-*) libgloss_dir=i386 ;; @@ -44,7 +61,7 @@ diff -uNr gcc-10.3.0.org/configure gcc-10.3.0/configure m68hc11-*-*|m6811-*-*|m68hc12-*-*|m6812-*-*) libgloss_dir=m68hc11 ;; -@@ -4025,6 +4028,11 @@ +@@ -4023,6 +4026,11 @@ case "${target}" in wasm32-*-*) noconfigdirs="$noconfigdirs ld" ;; @@ -56,20 +73,11 @@ diff -uNr gcc-10.3.0.org/configure gcc-10.3.0/configure esac # If we aren't building newlib, then don't build libgloss, since libgloss -@@ -7134,6 +7142,9 @@ - mips*-*-*linux* | mips*-*-gnu*) - target_makefile_frag="config/mt-mips-gnu" - ;; -+ loongarch*-*-*linux* | loongarch*-*-gnu*) -+ target_makefile_frag="config/mt-loongarch-gnu" -+ ;; - nios2-*-elf*) - target_makefile_frag="config/mt-nios2-elf" - ;; -diff -uNr gcc-10.3.0.org/configure.ac gcc-10.3.0/configure.ac ---- gcc-10.3.0.org/configure.ac 2022-03-23 17:25:14.304350355 +0800 -+++ gcc-10.3.0/configure.ac 2022-03-23 17:40:29.342280160 +0800 -@@ -345,7 +345,7 @@ +diff --git a/configure.ac b/configure.ac +index 115db3f40..31e8fe6df 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -345,7 +345,7 @@ case "${ENABLE_GOLD}" in # Check for target supported by gold. case "${target}" in i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-* \ @@ -78,7 +86,7 @@ diff -uNr gcc-10.3.0.org/configure.ac gcc-10.3.0/configure.ac configdirs="$configdirs gold" if test x${ENABLE_GOLD} = xdefault; then default_ld=gold -@@ -914,6 +914,9 @@ +@@ -914,6 +914,9 @@ case "${target}" in i[[3456789]]86-*-*) libgloss_dir=i386 ;; @@ -88,7 +96,7 @@ diff -uNr gcc-10.3.0.org/configure.ac gcc-10.3.0/configure.ac m68hc11-*-*|m6811-*-*|m68hc12-*-*|m6812-*-*) libgloss_dir=m68hc11 ;; -@@ -1298,6 +1301,11 @@ +@@ -1298,6 +1301,11 @@ case "${target}" in wasm32-*-*) noconfigdirs="$noconfigdirs ld" ;; @@ -100,20 +108,11 @@ diff -uNr gcc-10.3.0.org/configure.ac gcc-10.3.0/configure.ac esac # If we aren't building newlib, then don't build libgloss, since libgloss -@@ -2639,6 +2647,9 @@ - mips*-*-*linux* | mips*-*-gnu*) - target_makefile_frag="config/mt-mips-gnu" - ;; -+ loongarch*-*-*linux* | loongarch*-*-gnu*) -+ target_makefile_frag="config/mt-loongarch-gnu" -+ ;; - nios2-*-elf*) - target_makefile_frag="config/mt-nios2-elf" - ;; -diff -uNr gcc-10.3.0.org/contrib/config-list.mk gcc-10.3.0/contrib/config-list.mk ---- gcc-10.3.0.org/contrib/config-list.mk 2021-04-08 19:56:27.581734786 +0800 -+++ gcc-10.3.0/contrib/config-list.mk 2022-03-23 17:40:29.342280160 +0800 -@@ -57,7 +57,10 @@ +diff --git a/contrib/config-list.mk b/contrib/config-list.mk +index d154286a4..c06e2b924 100644 +--- a/contrib/config-list.mk ++++ b/contrib/config-list.mk +@@ -57,7 +57,10 @@ LIST = aarch64-elf aarch64-linux-gnu aarch64-rtems \ i686-wrs-vxworksae \ i686-cygwinOPT-enable-threads=yes i686-mingw32crt ia64-elf \ ia64-freebsd6 ia64-linux ia64-hpux ia64-hp-vms iq2000-elf lm32-elf \ @@ -125,23 +124,14 @@ diff -uNr gcc-10.3.0.org/contrib/config-list.mk gcc-10.3.0/contrib/config-list.m m32r-linux m32rle-linux m68k-elf m68k-netbsdelf \ m68k-openbsd m68k-uclinux m68k-linux m68k-rtems \ mcore-elf microblaze-linux microblaze-elf \ -diff -uNr gcc-10.3.0.org/gcc/cfg.h gcc-10.3.0/gcc/cfg.h ---- gcc-10.3.0.org/gcc/cfg.h 2021-04-08 19:56:28.021740099 +0800 -+++ gcc-10.3.0/gcc/cfg.h 2022-03-23 17:40:29.342280160 +0800 -@@ -21,6 +21,7 @@ - #define GCC_CFG_H - - #include "dominance.h" -+#include "function.h" - - /* What sort of profiling information we have. */ - enum profile_status_d -diff -uNr gcc-10.3.0.org/gcc/common/config/loongarch/loongarch-common.c gcc-10.3.0/gcc/common/config/loongarch/loongarch-common.c ---- gcc-10.3.0.org/gcc/common/config/loongarch/loongarch-common.c 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/common/config/loongarch/loongarch-common.c 2022-03-23 17:40:29.342280160 +0800 -@@ -0,0 +1,63 @@ +diff --git a/gcc/common/config/loongarch/loongarch-common.c b/gcc/common/config/loongarch/loongarch-common.c +new file mode 100644 +index 000000000..f8b4660fa +--- /dev/null ++++ b/gcc/common/config/loongarch/loongarch-common.c +@@ -0,0 +1,41 @@ +/* Common hooks for LoongArch. -+ Copyright (C) 2021 Free Software Foundation, Inc. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. + +This file is part of GCC. + @@ -169,43 +159,496 @@ diff -uNr gcc-10.3.0.org/gcc/common/config/loongarch/loongarch-common.c gcc-10.3 +#include "flags.h" +#include "diagnostic-core.h" + -+/* Implement TARGET_HANDLE_OPTION. */ ++#undef TARGET_OPTION_OPTIMIZATION_TABLE ++#define TARGET_OPTION_OPTIMIZATION_TABLE loongarch_option_optimization_table + -+static bool -+loongarch_handle_option (struct gcc_options *opts, -+ struct gcc_options *opts_set ATTRIBUTE_UNUSED, -+ const struct cl_decoded_option *decoded, -+ location_t loc ATTRIBUTE_UNUSED) ++/* Set default optimization options. */ ++static const struct default_options loongarch_option_optimization_table[] = +{ -+ size_t code = decoded->opt_index; -+ int value = decoded->value; ++ { OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 }, ++ { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 }, ++ { OPT_LEVELS_NONE, 0, NULL, 0 } ++}; + -+ switch (code) -+ { -+ case OPT_mmemcpy: -+ if (value) -+ { -+ if (opts->x_optimize_size) -+ opts->x_target_flags |= MASK_MEMCPY; -+ } -+ else -+ opts->x_target_flags &= ~MASK_MEMCPY; -+ return true; ++struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; +diff --git a/gcc/config.gcc b/gcc/config.gcc +index 6fcdd771d..63d1b47a4 100644 +--- a/gcc/config.gcc ++++ b/gcc/config.gcc +@@ -180,7 +180,7 @@ + # the --with-sysroot configure option or the + # --sysroot command line option is used this + # will be relative to the sysroot. +-# target_type_format_char ++# target_type_format_char + # The default character to be used for formatting + # the attribute in a + # .type symbol_name, ${t_t_f_c} +@@ -477,6 +477,13 @@ mips*-*-*) + extra_objs="frame-header-opt.o" + extra_options="${extra_options} g.opt fused-madd.opt mips/mips-tables.opt" + ;; ++loongarch*-*-*) ++ cpu_type=loongarch ++ extra_headers="larchintrin.h" ++ extra_objs="loongarch-c.o loongarch-builtins.o loongarch-cpu.o loongarch-opts.o loongarch-def.o" ++ extra_gcc_objs="loongarch-driver.o loongarch-cpu.o loongarch-opts.o loongarch-def.o" ++ extra_options="${extra_options} g.opt fused-madd.opt" ++ ;; + nds32*) + cpu_type=nds32 + extra_headers="nds32_intrinsic.h nds32_isr.h nds32_init.inc" +@@ -2503,6 +2510,20 @@ riscv*-*-freebsd*) + # automatically detect that GAS supports it, yet we require it. + gcc_cv_initfini_array=yes + ;; + -+ default: -+ return true; -+ } -+} ++loongarch*-*-linux-gnu*) ++ tm_file="dbxelf.h elfos.h gnu-user.h linux.h linux-android.h glibc-stdint.h ${tm_file}" ++ tm_file="${tm_file} loongarch/gnu-user.h loongarch/linux.h" ++ extra_options="${extra_options} linux-android.opt" ++ tmake_file="${tmake_file} loongarch/t-linux" ++ gnu_ld=yes ++ gas=yes + -+#undef TARGET_DEFAULT_TARGET_FLAGS -+#define TARGET_DEFAULT_TARGET_FLAGS MASK_CHECK_ZERO_DIV -+#undef TARGET_HANDLE_OPTION -+#define TARGET_HANDLE_OPTION loongarch_handle_option ++ # Force .init_array support. The configure script cannot always ++ # automatically detect that GAS supports it, yet we require it. ++ gcc_cv_initfini_array=yes ++ ;; + -+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; -diff -uNr gcc-10.3.0.org/gcc/config/host-linux.c gcc-10.3.0/gcc/config/host-linux.c ---- gcc-10.3.0.org/gcc/config/host-linux.c 2021-04-08 19:56:28.093740970 +0800 -+++ gcc-10.3.0/gcc/config/host-linux.c 2022-03-23 17:40:29.342280160 +0800 + mips*-*-netbsd*) # NetBSD/mips, either endian. + target_cpu_default="MASK_ABICALLS" + tm_file="elfos.h ${tm_file} mips/elf.h ${nbsd_tm_file} mips/netbsd.h" +@@ -3575,7 +3596,7 @@ case ${target} in + ;; + *-*-linux* | *-*-gnu*) + case ${target} in +- aarch64*-* | arm*-* | i[34567]86-* | powerpc*-* | s390*-* | sparc*-* | x86_64-*) ++ aarch64*-* | arm*-* | i[34567]86-* | powerpc*-* | s390*-* | sparc*-* | x86_64-* | loongarch*-*) + default_gnu_indirect_function=yes + ;; + esac +@@ -4854,6 +4875,338 @@ case "${target}" in + esac + ;; + ++ loongarch*-*-*) ++ supported_defaults="abi arch tune fpu" ++ ++ # Local variables ++ unset \ ++ abi_pattern abi_default \ ++ abiext_pattern abiext_default \ ++ arch_pattern arch_default \ ++ fpu_pattern fpu_default \ ++ tune_pattern tune_default ++ ++ # Inferring ABI from the triplet: pass 1 ++ case ${target} in ++ loongarch64-*) ++ abiext_pattern="*" ++ abiext_default="base" ++ ;; ++ esac ++ ++ # Inferring ABI from the triplet: pass 2 ++ case ${target} in ++ loongarch64-*-linux-gnuf64) ++ la_canonical_triplet="loongarch64-linux-gnuf64" ++ abi_pattern="lp64d" ++ ;; ++ loongarch64-*-linux-gnuf32) ++ la_canonical_triplet="loongarch64-linux-gnuf32" ++ abi_pattern="lp64f" ++ ;; ++ loongarch64-*-linux-gnusf) ++ la_canonical_triplet="loongarch64-linux-gnusf" ++ abi_pattern="lp64s" ++ ;; ++ loongarch64-*-linux-gnu) ++ la_canonical_triplet="loongarch64-linux-gnuf64" ++ abi_pattern="lp64[dfs]" ++ abi_default="lp64d" ++ ;; ++ *) ++ echo "Unsupported target ${target}." 1>&2 ++ exit 1 ++ esac ++ ++ ## Setting default value for with_abi. ++ case ${with_abi} in ++ "") ++ if test x${abi_default} != x; then ++ with_abi=${abi_default} ++ else ++ with_abi=${abi_pattern} ++ fi ++ ;; ++ ++ *) ++ if echo "${with_abi}" | grep -E "^${abi_pattern}$"; then ++ : # OK ++ else ++ echo "Incompatible options:" \ ++ "--with-abi=${with_abi} and --target=${target}." 1>&2 ++ exit 1 ++ fi ++ ;; ++ esac ++ ++ ## Setting default value for with_abiext (internal) ++ case ${with_abiext} in ++ "") ++ if test x${abiext_default} != x; then ++ with_abiext=${abiext_default} ++ else ++ with_abiext=${abiext_pattern} ++ fi ++ ;; ++ ++ *) ++ if echo "${with_abiext}" | grep -E "^${abiext_pattern}$"; then ++ : # OK ++ else ++ echo "The ABI extension type \"${with_abiext}\"" \ ++ "is incompatible with --target=${target}." 1>&2 ++ exit 1 ++ fi ++ ++ ;; ++ esac ++ ++ ++ # Inferring ISA-related default options from the ABI: pass 1 ++ case ${with_abi}/${with_abiext} in ++ lp64*/base) ++ # architectures that support lp64* ABI ++ arch_pattern="native|loongarch64|la464" ++ # default architecture for lp64* ABI ++ arch_default="loongarch64" ++ ;; ++ *) ++ echo "Unsupported ABI type ${with_abi}/${with_abiext}." 1>&2 ++ exit 1 ++ ;; ++ esac ++ ++ # Inferring ISA-related default options from the ABI: pass 2 ++ case ${with_abi}/${with_abiext} in ++ lp64d/base) ++ fpu_pattern="64" ++ ;; ++ lp64f/base) ++ fpu_pattern="32|64" ++ fpu_default="32" ++ ;; ++ lp64s/base) ++ fpu_pattern="none|32|64" ++ fpu_default="none" ++ ;; ++ *) ++ echo "Unsupported ABI type ${with_abi}/${with_abiext}." 1>&2 ++ exit 1 ++ ;; ++ esac ++ ++ ## Setting default value for with_arch. ++ case ${with_arch} in ++ "") ++ if test x${arch_default} != x; then ++ with_arch=${arch_default} ++ else ++ with_arch=${arch_pattern} ++ fi ++ ;; ++ ++ *) ++ if echo "${with_arch}" | grep -E "^${arch_pattern}$"; then ++ : # OK ++ else ++ echo "${with_abi}/${with_abiext} ABI cannot be implemented with" \ ++ "--with-arch=${with_arch}." 1>&2 ++ exit 1 ++ fi ++ ;; ++ esac ++ ++ ## Setting default value for with_fpu. ++ if test x${with_fpu} == xnone; then ++ with_fpu="0" ++ fi ++ ++ case ${with_fpu} in ++ "") ++ if test x${fpu_default} != x; then ++ with_fpu=${fpu_default} ++ else ++ with_fpu=${fpu_pattern} ++ fi ++ ;; ++ ++ *) ++ if echo "${with_fpu}" | grep -E "^${fpu_pattern}$"; then ++ : # OK ++ else ++ echo "${with_abi}/${with_abiext} ABI cannot be implemented with" \ ++ "--with-fpu=${with_fpu}." 1>&2 ++ exit 1 ++ fi ++ ;; ++ esac ++ ++ ++ # Inferring default with_tune from with_arch: pass 1 ++ case ${with_arch} in ++ native) ++ tune_pattern="*" ++ tune_default="native" ++ ;; ++ loongarch64) ++ tune_pattern="loongarch64 | la464" ++ tune_default="la464" ++ ;; ++ *) ++ # By default, $with_tune == $with_arch ++ tune_pattern="$with_arch" ++ ;; ++ esac ++ ++ ## Setting default value for with_tune. ++ case ${with_tune} in ++ "") ++ if test x${tune_default} != x; then ++ with_tune=${tune_default} ++ else ++ with_tune=${tune_pattern} ++ fi ++ ;; ++ ++ *) ++ if echo "${with_tune}" | grep -E "^${tune_pattern}$"; then ++ : # OK ++ else ++ echo "Incompatible options: --with-tune=${with_tune}" \ ++ "and --with-arch=${with_arch}." 1>&2 ++ exit 1 ++ fi ++ ;; ++ esac ++ ++ ++ # Perform final sanity checks. ++ case ${with_arch} in ++ loongarch64 | la464) ;; # OK, append here. ++ native) ++ if test x${host} != x${target}; then ++ echo "--with-arch=native is illegal for cross-compiler." 1>&2 ++ exit 1 ++ fi ++ ;; ++ "") ++ echo "Please set a default value for \${with_arch}" \ ++ "according to your target triplet \"${target}\"." 1>&2 ++ exit 1 ++ ;; ++ *) ++ echo "Unknown arch in --with-arch=$with_arch" 1>&2 ++ exit 1 ++ ;; ++ esac ++ ++ case ${with_abi} in ++ lp64d | lp64f | lp64s) ;; # OK, append here. ++ *) ++ echo "Unsupported ABI given in --with-abi=$with_abi" 1>&2 ++ exit 1 ++ ;; ++ esac ++ ++ case ${with_abiext} in ++ base) ;; # OK, append here. ++ *) ++ echo "Unsupported ABI extention type $with_abiext" 1>&2 ++ exit 1 ++ ;; ++ esac ++ ++ case ${with_fpu} in ++ none | 32 | 64) ;; # OK, append here. ++ *) ++ echo "Unknown fpu type in --with-fpu=$with_fpu" 1>&2 ++ exit 1 ++ ;; ++ esac ++ ++ # Handle --with-multilib-list. ++ if test x${with_multilib_list} == x \ ++ || test x${with_multilib_list} == xno \ ++ || test x${with_multilib_list} == xdefault \ ++ || test x${enable_multilib} != xyes; then ++ ++ with_multilib_list="${with_abi}/${with_abiext}" ++ fi ++ ++ # Check if the configured default ABI combination is included in ++ # ${with_multilib_list}. ++ loongarch_multilib_list_sane=no ++ ++ # This one goes to TM_MULTILIB_CONFIG, for use in t-linux. ++ loongarch_multilib_list_make="" ++ ++ # This one goes to tm_defines, for use in loongarch-driver.c. ++ loongarch_multilib_list_c="" ++ ++ for e in $(tr ',' ' ' <<< "${with_multilib_list}"); do ++ e=($(tr '/' ' ' <<< "$e")) ++ ++ # Base ABI type ++ case ${e[0]} in ++ lp64d) loongarch_multilib_list_c+="ABI_BASE_LP64D,";; ++ lp64f) loongarch_multilib_list_c+="ABI_BASE_LP64F,";; ++ lp64s) loongarch_multilib_list_c+="ABI_BASE_LP64S,";; ++ *) ++ echo "Unknown base ABI \"${e[0]}\" in --with-multilib-list." 1>&2 ++ exit 1 ++ ;; ++ esac ++ loongarch_multilib_list_make+="mabi=${e[0]}" ++ ++ # ABI extension type ++ case ${e[1]} in ++ "" | base) ++ loongarch_multilib_list_make+="" ++ loongarch_multilib_list_c+="ABI_EXT_BASE," ++ e[1]="base" ++ ;; ++ *) ++ echo "Unknown ABI extension \"${e[1]}\" in --with-multilib-list." 1>&2 ++ exit 1 ++ ;; ++ esac ++ ++ case ${e[2]} in ++ "") ;; # OK ++ *) ++ echo "Unknown ABI in --with-multilib-list." 1>&2 ++ exit 1 ++ ;; ++ esac ++ ++ if test x${with_abi} != x && test x${with_abiext} != x; then ++ if test x${e[0]} == x${with_abi} \ ++ && test x${e[1]} == x${with_abiext}; then ++ loongarch_multilib_list_sane=yes ++ fi ++ fi ++ ++ loongarch_multilib_list_make+="," ++ done ++ ++ # Check if the default ABI combination is in the default list. ++ if test x${loongarch_multilib_list_sane} == xno; then ++ if test x${with_abiext} == xbase; then ++ with_abiext="" ++ else ++ with_abiext="/${with_abiext}" ++ fi ++ ++ echo "Default ABI combination (${with_abi}${with_abiext})" \ ++ "not found in --with-multilib-list." 1>&2 ++ exit 1 ++ fi ++ ++ # Remove the excessive appending comma. ++ loongarch_multilib_list_c=${loongarch_multilib_list_c:0:-1} ++ loongarch_multilib_list_make=${loongarch_multilib_list_make:0:-1} ++ ;; ++ + nds32*-*-*) + supported_defaults="arch cpu nds32_lib float fpu_config" + +@@ -5301,6 +5654,51 @@ case ${target} in + tmake_file="mips/t-mips $tmake_file" + ;; + ++ loongarch*-*-*) ++ # Export canonical triplet. ++ tm_defines+=" LA_MULTIARCH_TRIPLET=${la_canonical_triplet}" ++ ++ # Define macro __DISABLE_MULTILIB if --disable-multilib ++ tm_defines+=" TM_MULTILIB_LIST=${loongarch_multilib_list_c}" ++ if test x$enable_multilib == xyes; then ++ TM_MULTILIB_CONFIG="${loongarch_multilib_list_make}" ++ else ++ tm_defines+=" __DISABLE_MULTILIB" ++ fi ++ ++ # Let --with- flags initialize the enum variables from loongarch.opt. ++ # See macro definitions from loongarch-opts.h and loongarch-cpu.h. ++ case ${with_arch} in ++ native) tm_defines+=" DEFAULT_CPU_ARCH=CPU_NATIVE" ;; ++ la464) tm_defines+=" DEFAULT_CPU_ARCH=CPU_LA464" ;; ++ loongarch64) tm_defines+=" DEFAULT_CPU_ARCH=CPU_LOONGARCH64" ;; ++ esac ++ ++ case ${with_tune} in ++ native) tm_defines+=" DEFAULT_CPU_TUNE=CPU_NATIVE" ;; ++ la464) tm_defines+=" DEFAULT_CPU_TUNE=CPU_LA464" ;; ++ loongarch64) tm_defines+=" DEFAULT_CPU_TUNE=CPU_LOONGARCH64" ;; ++ esac ++ ++ case ${with_abi} in ++ lp64d) tm_defines+=" DEFAULT_ABI_BASE=ABI_BASE_LP64D" ;; ++ lp64f) tm_defines+=" DEFAULT_ABI_BASE=ABI_BASE_LP64F" ;; ++ lp64s) tm_defines+=" DEFAULT_ABI_BASE=ABI_BASE_LP64S" ;; ++ esac ++ ++ case ${with_abiext} in ++ base) tm_defines+=" DEFAULT_ABI_EXT=ABI_EXT_BASE" ;; ++ esac ++ ++ case ${with_fpu} in ++ none) tm_defines="$tm_defines DEFAULT_ISA_EXT_FPU=ISA_EXT_NOFPU" ;; ++ 32) tm_defines="$tm_defines DEFAULT_ISA_EXT_FPU=ISA_EXT_FPU32" ;; ++ 64) tm_defines="$tm_defines DEFAULT_ISA_EXT_FPU=ISA_EXT_FPU64" ;; ++ esac ++ ++ tmake_file="loongarch/t-loongarch $tmake_file" ++ ;; ++ + powerpc*-*-* | rs6000-*-*) + # FIXME: The PowerPC port uses the value set at compile time, + # although it's only cosmetic. +@@ -5364,7 +5762,7 @@ case ${target} in + esac + + t= +-all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu nan fp_32 odd_spreg_32 divide llsc mips-plt synci tls lxc1-sxc1 madd4" ++all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu nan fp_32 odd_spreg_32 divide llsc mips-plt synci tls lxc1-sxc1 madd4 fix-loongson3-llsc" + for option in $all_defaults + do + eval "val=\$with_"`echo $option | sed s/-/_/g` +diff --git a/gcc/config.in b/gcc/config.in +index 364eba477..d944819b4 100644 +--- a/gcc/config.in ++++ b/gcc/config.in +@@ -376,6 +376,12 @@ + #endif + + ++/* Define if your assembler supports eh_frame pcrel encoding. */ ++#ifndef USED_FOR_TARGET ++#undef HAVE_AS_EH_FRAME_PCREL_ENCODING_SUPPORT ++#endif ++ ++ + /* Define if your assembler supports the R_PPC64_ENTRY relocation. */ + #ifndef USED_FOR_TARGET + #undef HAVE_AS_ENTRY_MARKERS +diff --git a/gcc/config/host-linux.c b/gcc/config/host-linux.c +index 268725441..38f9d4ce7 100644 +--- a/gcc/config/host-linux.c ++++ b/gcc/config/host-linux.c @@ -98,6 +98,8 @@ # define TRY_EMPTY_VM_SPACE 0x60000000 #elif defined(__riscv) && defined (__LP64__) @@ -215,12 +658,15 @@ diff -uNr gcc-10.3.0.org/gcc/config/host-linux.c gcc-10.3.0/gcc/config/host-linu #else # define TRY_EMPTY_VM_SPACE 0 #endif -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/constraints.md gcc-10.3.0/gcc/config/loongarch/constraints.md ---- gcc-10.3.0.org/gcc/config/loongarch/constraints.md 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/constraints.md 2022-03-23 17:40:29.343280152 +0800 -@@ -0,0 +1,287 @@ -+;; Constraint definitions for LARCH. -+;; Copyright (C) 2006-2018 Free Software Foundation, Inc. +diff --git a/gcc/config/loongarch/constraints.md b/gcc/config/loongarch/constraints.md +new file mode 100644 +index 000000000..43cb7b5f0 +--- /dev/null ++++ b/gcc/config/loongarch/constraints.md +@@ -0,0 +1,192 @@ ++;; Constraint definitions for LoongArch. ++;; Copyright (C) 2021-2022 Free Software Foundation, Inc. ++;; Contributed by Loongson Ltd. +;; +;; This file is part of GCC. +;; @@ -240,136 +686,141 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/constraints.md gcc-10.3.0/gcc/conf + +;; Register constraints + -+;; "a" A constant call global and noplt address. -+;; "b" ALL_REGS -+;; "c" A constant call local address. -+;; "d" GR_REGS -+;; "e" JALR_REGS ++;; "a" <-----unused ++;; "b" "A constant call not local address." ++;; "c" "A constant call local address." ++;; "d" <-----unused ++;; "e" JIRL_REGS +;; "f" FP_REGS -+;; "g" * -+;; "h" A constant call plt address. -+;; "i" "Matches a general integer constant." ++;; "g" <-----unused ++;; "h" <-----unused ++;; "i" "Matches a general integer constant." (Global non-architectural) +;; "j" SIBCALL_REGS -+;; "k" - -+;; "l" "A signed 16-bit constant ." ++;; "k" "A memory operand whose address is formed by a base register and ++;; (optionally scaled) index register." ++;; "l" "A signed 16-bit constant." +;; "m" "A memory operand whose address is formed by a base register and offset +;; that is suitable for use in instructions with the same addressing mode +;; as @code{st.w} and @code{ld.w}." -+;; "n" "Matches a non-symbolic integer constant." -+;; "o" "Matches an offsettable memory reference." -+;; "p" "Matches a general address." -+;; "q" LVZ_REGS -+;; "r" GENERAL_REGS -+;; "s" "Matches a symbolic integer constant." -+;; "t" A constant call weak address -+;; "u" - -+;; "v" - ++;; "n" "Matches a non-symbolic integer constant." (Global non-architectural) ++;; "o" "Matches an offsettable memory reference." (Global non-architectural) ++;; "p" "Matches a general address." (Global non-architectural) ++;; "q" CSR_REGS ++;; "r" GENERAL_REGS (Global non-architectural) ++;; "s" "Matches a symbolic integer constant." (Global non-architectural) ++;; "t" <-----unused ++;; "u" "A signed 52bit constant and low 32-bit is zero (for logic instructions)" ++;; "v" "A signed 64-bit constant and low 44-bit is zero (for logic instructions)." +;; "w" "Matches any valid memory." -+;; "x" - -+;; "y" GR_REGS -+;; "z" ST_REGS -+;; "A" - -+;; "B" - -+;; "C" - -+;; "D" - -+;; "E" "Matches a floating-point constant." -+;; "F" "Matches a floating-point constant." ++;; "x" <-----unused ++;; "y" <-----unused ++;; "z" FCC_REGS ++;; "A" <-----unused ++;; "B" <-----unused ++;; "C" <-----unused ++;; "D" <-----unused ++;; "E" "Matches a floating-point constant." (Global non-architectural) ++;; "F" "Matches a floating-point constant." (Global non-architectural) +;; "G" "Floating-point zero." -+;; "H" - ++;; "H" <-----unused +;; "I" "A signed 12-bit constant (for arithmetic instructions)." +;; "J" "Integer zero." +;; "K" "An unsigned 12-bit constant (for logic instructions)." -+;; "L" "A signed 32-bit constant in which the lower 12 bits are zero. -+;; "M" "A constant that cannot be loaded using @code{lui}, @code{addiu} or @code{ori}." -+;; "N" "A constant in the range -65535 to -1 (inclusive)." -+;; "O" "A signed 15-bit constant." -+;; "P" "A constant in the range 1 to 65535 (inclusive)." -+;; "Q" "A signed 12-bit constant" -+;; "R" "An address that can be used in a non-macro load or store." -+;; "S" "A constant call address." -+;; "T" - -+;; "U" - -+;; "V" "Matches a non-offsettable memory reference." -+;; "W" "A memory address based on a member of @code{BASE_REG_CLASS}. This is -+;; true for all references (although it can sometimes be implicit -+;; if @samp{!TARGET_EXPLICIT_RELOCS})." -+;; "X" "Matches anything." ++;; "L" <-----unused ++;; "M" <-----unused ++;; "N" <-----unused ++;; "O" <-----unused ++;; "P" <-----unused ++;; "Q" <-----unused ++;; "R" <-----unused ++;; "S" <-----unused ++;; "T" <-----unused ++;; "U" <-----unused ++;; "V" "Matches a non-offsettable memory reference." (Global non-architectural) ++;; "W" <-----unused ++;; "X" "Matches anything." (Global non-architectural) +;; "Y" - -+;; "Yb" +;; "Yd" -+;; "A constant @code{move_operand} that can be safely loaded into @code{$25} -+;; using @code{la}." -+;; "Yh" -+;; "Yw" ++;; "A constant @code{move_operand} that can be safely loaded using ++;; @code{la}." +;; "Yx" +;; "Z" - +;; "ZC" +;; "A memory operand whose address is formed by a base register and offset +;; that is suitable for use in instructions with the same addressing mode +;; as @code{ll.w} and @code{sc.w}." -+;; "ZD" -+;; "An address suitable for a @code{prefetch} instruction, or for any other -+;; instruction with the same addressing mode as @code{prefetch}." +;; "ZB" +;; "An address that is held in a general-purpose register. +;; The offset is zero" ++;; "<" "Matches a pre-dec or post-dec operand." (Global non-architectural) ++;; ">" "Matches a pre-inc or post-inc operand." (Global non-architectural) + ++(define_constraint "b" ++ "@internal ++ A constant call no local address." ++ (match_operand 0 "is_const_call_no_local_symbol")) + +(define_constraint "c" + "@internal + A constant call local address." + (match_operand 0 "is_const_call_local_symbol")) + -+(define_constraint "a" -+ "@internal -+ A constant call global and noplt address." -+ (match_operand 0 "is_const_call_global_noplt_symbol")) -+ -+(define_constraint "h" -+ "@internal -+ A constant call plt address." -+ (match_operand 0 "is_const_call_plt_symbol")) -+ -+(define_constraint "t" -+ "@internal -+ A constant call weak address." -+ (match_operand 0 "is_const_call_weak_symbol")) -+ -+(define_register_constraint "d" "GR_REGS" -+ "A general-purpose register. This is equivalent to @code{r}.") -+ -+(define_register_constraint "e" "JALR_REGS" ++(define_register_constraint "e" "JIRL_REGS" + "@internal") + -+(define_register_constraint "q" "LVZ_REGS" -+ "A general-purpose register except for $r0 and $r1 for lvz.") -+ +(define_register_constraint "f" "TARGET_HARD_FLOAT ? FP_REGS : NO_REGS" + "A floating-point register (if available).") + -+(define_register_constraint "b" "ALL_REGS" -+ "@internal") -+ +(define_register_constraint "j" "SIBCALL_REGS" + "@internal") + ++(define_memory_constraint "k" ++ "A memory operand whose address is formed by a base register and (optionally scaled) ++ index register." ++ (and (match_code "mem") ++ (match_test "loongarch_base_index_address_p (XEXP (op, 0), mode)"))) ++ +(define_constraint "l" -+ "A signed 16-bit constant ." ++"A signed 16-bit constant." ++(and (match_code "const_int") ++ (match_test "IMM16_OPERAND (ival)"))) ++ ++(define_memory_constraint "m" ++ "A memory operand whose address is formed by a base register and offset ++ that is suitable for use in instructions with the same addressing mode ++ as @code{st.w} and @code{ld.w}." ++ (and (match_code "mem") ++ (match_test "loongarch_12bit_offset_address_p (XEXP (op, 0), mode)"))) ++ ++(define_register_constraint "q" "CSR_REGS" ++ "A general-purpose register except for $r0 and $r1 for lcsr.") ++ ++(define_constraint "u" ++ "A signed 52bit constant and low 32-bit is zero (for logic instructions)." + (and (match_code "const_int") -+ (match_test "IMM16_OPERAND (ival)"))) ++ (match_test "LU32I_OPERAND (ival)"))) + -+(define_register_constraint "y" "GR_REGS" -+ "Equivalent to @code{r}; retained for backwards compatibility.") ++(define_constraint "v" ++ "A signed 64-bit constant and low 44-bit is zero (for logic instructions)." ++ (and (match_code "const_int") ++ (match_test "LU52I_OPERAND (ival)"))) + -+(define_register_constraint "z" "ST_REGS" ++(define_register_constraint "z" "FCC_REGS" + "A floating-point condition code register.") + ++;; Floating-point constraints ++ ++(define_constraint "G" ++ "Floating-point zero." ++ (and (match_code "const_double") ++ (match_test "op == CONST0_RTX (mode)"))) ++ +;; Integer constraints + +(define_constraint "I" + "A signed 12-bit constant (for arithmetic instructions)." + (and (match_code "const_int") -+ (match_test "SMALL_OPERAND (ival)"))) ++ (match_test "IMM12_OPERAND (ival)"))) + +(define_constraint "J" + "Integer zero." @@ -379,106 +830,14 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/constraints.md gcc-10.3.0/gcc/conf +(define_constraint "K" + "An unsigned 12-bit constant (for logic instructions)." + (and (match_code "const_int") -+ (match_test "SMALL_OPERAND_UNSIGNED (ival)"))) -+ -+(define_constraint "u" -+ "An unsigned 12-bit constant (for logic instructions)." -+ (and (match_code "const_int") -+ (match_test "LU32I_OPERAND (ival)"))) ++ (match_test "IMM12_OPERAND_UNSIGNED (ival)"))) + -+(define_constraint "v" -+ "An unsigned 12-bit constant (for logic instructions)." -+ (and (match_code "const_int") -+ (match_test "LU52I_OPERAND (ival)"))) -+ -+(define_constraint "L" -+ "A signed 32-bit constant in which the lower 12 bits are zero. -+ Such constants can be loaded using @code{lui}." -+ (and (match_code "const_int") -+ (match_test "LUI_OPERAND (ival)"))) -+ -+(define_constraint "M" -+ "A constant that cannot be loaded using @code{lui}, @code{addiu} -+ or @code{ori}." -+ (and (match_code "const_int") -+ (not (match_test "SMALL_OPERAND (ival)")) -+ (not (match_test "SMALL_OPERAND_UNSIGNED (ival)")) -+ (not (match_test "LUI_OPERAND (ival)")))) -+ -+(define_constraint "N" -+ "A constant in the range -65535 to -1 (inclusive)." -+ (and (match_code "const_int") -+ (match_test "ival >= -0xffff && ival < 0"))) -+ -+(define_constraint "O" -+ "A signed 15-bit constant." -+ (and (match_code "const_int") -+ (match_test "ival >= -0x4000 && ival < 0x4000"))) -+ -+(define_constraint "P" -+ "A constant in the range 1 to 65535 (inclusive)." -+ (and (match_code "const_int") -+ (match_test "ival > 0 && ival < 0x10000"))) -+ -+;; Floating-point constraints -+ -+(define_constraint "G" -+ "Floating-point zero." -+ (and (match_code "const_double") -+ (match_test "op == CONST0_RTX (mode)"))) -+ -+;; General constraints -+ -+(define_constraint "Q" -+ "@internal" -+ (match_operand 0 "const_arith_operand")) -+ -+(define_memory_constraint "R" -+ "An address that can be used in a non-macro load or store." -+ (and (match_code "mem") -+ (match_test "loongarch_address_insns (XEXP (op, 0), mode, false) == 1"))) -+ -+(define_memory_constraint "m" -+ "A memory operand whose address is formed by a base register and offset -+ that is suitable for use in instructions with the same addressing mode -+ as @code{st.w} and @code{ld.w}." -+ (and (match_code "mem") -+ (match_test "loongarch_12bit_offset_address_p (XEXP (op, 0), mode)"))) -+ -+(define_constraint "S" -+ "@internal -+ A constant call address." -+ (and (match_operand 0 "call_insn_operand") -+ (match_test "CONSTANT_P (op)"))) -+ -+(define_memory_constraint "W" -+ "@internal -+ A memory address based on a member of @code{BASE_REG_CLASS}. This is -+ true for allreferences (although it can sometimes be implicit -+ if @samp{!TARGET_EXPLICIT_RELOCS})." -+ (and (match_code "mem") -+ (match_operand 0 "memory_operand") -+ (and (not (match_operand 0 "stack_operand")) -+ (not (match_test "CONSTANT_P (XEXP (op, 0))"))))) -+ -+(define_constraint "Yb" -+ "@internal" -+ (match_operand 0 "qi_mask_operand")) -+ -+(define_constraint "Yd" -+ "@internal -+ A constant @code{move_operand} that can be safely loaded into @code{$25} -+ using @code{la}." -+ (and (match_operand 0 "move_operand") -+ (match_test "CONSTANT_P (op)"))) -+ -+(define_constraint "Yh" -+ "@internal" -+ (match_operand 0 "hi_mask_operand")) -+ -+(define_constraint "Yw" -+ "@internal" -+ (match_operand 0 "si_mask_operand")) ++(define_constraint "Yd" ++ "@internal ++ A constant @code{move_operand} that can be safely loaded using ++ @code{la}." ++ (and (match_operand 0 "move_operand") ++ (match_test "CONSTANT_P (op)"))) + +(define_constraint "Yx" + "@internal" @@ -491,113 +850,174 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/constraints.md gcc-10.3.0/gcc/conf + (and (match_code "mem") + (match_test "loongarch_14bit_shifted_offset_address_p (XEXP (op, 0), mode)"))) + -+;;(define_address_constraint "ZD" -+;; "An address suitable for a @code{prefetch} instruction, or for any other -+;; instruction with the same addressing mode as @code{prefetch}." -+;; (if_then_else (match_test "ISA_HAS_9BIT_DISPLACEMENT") -+;; (match_test "loongarch_9bit_offset_address_p (op, mode)") -+;; (match_test "loongarch_address_insns (op, mode, false)"))) -+ -+ +(define_memory_constraint "ZB" + "@internal + An address that is held in a general-purpose register. + The offset is zero" + (and (match_code "mem") -+ (match_test "GET_CODE(XEXP(op,0)) == REG"))) ++ (match_test "REG_P (XEXP (op, 0))"))) +diff --git a/gcc/config/loongarch/generic.md b/gcc/config/loongarch/generic.md +new file mode 100644 +index 000000000..6e5a0934d +--- /dev/null ++++ b/gcc/config/loongarch/generic.md +@@ -0,0 +1,118 @@ ++;; Generic DFA-based pipeline description for LoongArch targets ++;; Copyright (C) 2021-2022 Free Software Foundation, Inc. ++;; Contributed by Loongson Ltd. ++;; Based on MIPS target for GNU compiler. + -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/driver-native.c gcc-10.3.0/gcc/config/loongarch/driver-native.c ---- gcc-10.3.0.org/gcc/config/loongarch/driver-native.c 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/driver-native.c 2022-03-23 17:40:29.343280152 +0800 -@@ -0,0 +1,82 @@ -+/* Subroutines for the gcc driver. -+ Copyright (C) 2008-2018 Free Software Foundation, Inc. ++;; This file is part of GCC. + -+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 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. + -+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 ++;; . + -+You should have received a copy of the GNU General Public License -+along with GCC; see the file COPYING3. If not see -+. */ ++(define_automaton "alu,imuldiv") + -+#define IN_TARGET_CODE 1 ++(define_cpu_unit "alu" "alu") ++(define_cpu_unit "imuldiv" "imuldiv") + -+#include "config.h" -+#include "system.h" -+#include "coretypes.h" -+#include "tm.h" ++;; Ghost instructions produce no real code. ++;; They exist purely to express an effect on dataflow. ++(define_insn_reservation "ghost" 0 ++ (eq_attr "type" "ghost") ++ "nothing") + ++(define_insn_reservation "generic_alu" 1 ++ (eq_attr "type" "unknown,prefetch,prefetchx,condmove,const,arith, ++ shift,slt,clz,trap,multi,nop,logical,signext,move") ++ "alu") + -+/* This function must set to noinline. Otherwise the arg can not be passed. */ -+int loongson_cpucfg (int arg) -+{ -+ int ret; -+ __asm__ __volatile__ ("cpucfg %0,%1\n\t" /* cpucfg $2,$4. */ -+ :"=r"(ret) -+ :"r"(arg) -+ :); -+ return ret; -+} ++(define_insn_reservation "generic_load" 3 ++ (eq_attr "type" "load,fpload,fpidxload") ++ "alu") + -+/* This will be called by the spec parser in gcc.c when it sees -+ a %:local_cpu_detect(args) construct. Currently it will be called -+ with either "arch" or "tune" as argument depending on if -march=native -+ or -mtune=native is to be substituted. ++(define_insn_reservation "generic_store" 1 ++ (eq_attr "type" "store,fpstore,fpidxstore") ++ "alu") + -+ It returns a string containing new command line parameters to be -+ put at the place of the above two options, depending on what CPU -+ this is executed. E.g. "-march=loongson2f" on a Loongson 2F for -+ -march=native. If the routine can't detect a known processor, -+ the -march or -mtune option is discarded. ++(define_insn_reservation "generic_xfer" 2 ++ (eq_attr "type" "mftg,mgtf") ++ "alu") + -+ ARGC and ARGV are set depending on the actual arguments given -+ in the spec. */ -+const char * -+host_detect_local_cpu (int argc, const char **argv) -+{ -+ const char *cpu = NULL; -+ bool arch; -+ int cpucfg_arg; -+ int cpucfg_ret; ++(define_insn_reservation "generic_branch" 1 ++ (eq_attr "type" "branch,jump,call") ++ "alu") + -+ if (argc < 1) -+ return NULL; ++(define_insn_reservation "generic_imul" 17 ++ (eq_attr "type" "imul") ++ "imuldiv*17") + -+ arch = strcmp (argv[0], "arch") == 0; -+ if (!arch && strcmp (argv[0], "tune")) -+ return NULL; ++(define_insn_reservation "generic_fcvt" 1 ++ (eq_attr "type" "fcvt") ++ "alu") + -+ cpucfg_arg = 0; -+ cpucfg_ret = loongson_cpucfg (cpucfg_arg); -+ if (((cpucfg_ret >> 16) & 0xff) == 0x14) -+ { -+ if (((cpucfg_ret >> 8) & 0xff) == 0xc0) -+ cpu = "gs464v"; -+ else -+ cpu = NULL; -+ } ++(define_insn_reservation "generic_fmove" 2 ++ (eq_attr "type" "fabs,fneg,fmove") ++ "alu") + ++(define_insn_reservation "generic_fcmp" 3 ++ (eq_attr "type" "fcmp") ++ "alu") + -+ if (cpu == NULL) -+ return NULL; ++(define_insn_reservation "generic_fadd" 4 ++ (eq_attr "type" "fadd") ++ "alu") + -+ return concat ("-m", argv[0], "=", cpu, NULL); -+} -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/elf.h gcc-10.3.0/gcc/config/loongarch/elf.h ---- gcc-10.3.0.org/gcc/config/loongarch/elf.h 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/elf.h 2022-03-23 17:40:29.343280152 +0800 -@@ -0,0 +1,50 @@ -+/* Target macros for loongarch*-elf targets. -+ Copyright (C) 1994-2018 Free Software Foundation, Inc. ++(define_insn_reservation "generic_fmul_single" 7 ++ (and (eq_attr "type" "fmul,fmadd") ++ (eq_attr "mode" "SF")) ++ "alu") ++ ++(define_insn_reservation "generic_fmul_double" 8 ++ (and (eq_attr "type" "fmul,fmadd") ++ (eq_attr "mode" "DF")) ++ "alu") ++ ++(define_insn_reservation "generic_fdiv_single" 23 ++ (and (eq_attr "type" "fdiv,frdiv") ++ (eq_attr "mode" "SF")) ++ "alu") ++ ++(define_insn_reservation "generic_fdiv_double" 36 ++ (and (eq_attr "type" "fdiv,frdiv") ++ (eq_attr "mode" "DF")) ++ "alu") ++ ++(define_insn_reservation "generic_fsqrt_single" 54 ++ (and (eq_attr "type" "fsqrt,frsqrt") ++ (eq_attr "mode" "SF")) ++ "alu") ++ ++(define_insn_reservation "generic_fsqrt_double" 112 ++ (and (eq_attr "type" "fsqrt,frsqrt") ++ (eq_attr "mode" "DF")) ++ "alu") ++ ++(define_insn_reservation "generic_atomic" 10 ++ (eq_attr "type" "atomic") ++ "alu") ++ ++;; Sync loop consists of (in order) ++;; (1) optional sync, ++;; (2) LL instruction, ++;; (3) branch and 1-2 ALU instructions, ++;; (4) SC instruction, ++;; (5) branch and ALU instruction. ++;; The net result of this reservation is a big delay with a flush of ++;; ALU pipeline. ++(define_insn_reservation "generic_sync_loop" 40 ++ (eq_attr "type" "syncloop") ++ "alu*39") +diff --git a/gcc/config/loongarch/genopts/genstr.sh b/gcc/config/loongarch/genopts/genstr.sh +new file mode 100755 +index 000000000..972ef125f +--- /dev/null ++++ b/gcc/config/loongarch/genopts/genstr.sh +@@ -0,0 +1,104 @@ ++#!/bin/sh ++# A simple script that generates loongarch-str.h and loongarch.opt ++# from genopt/loongarch-optstr. ++# ++# Copyright (C) 2021-2022 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 ++# . ++ ++cd "$(dirname "$0")" ++ ++# Generate a header containing definitions from the string table. ++gen_defines() { ++ cat <. */ + -+/* LARCH assemblers don't have the usual .set foo,bar construct; -+ .set is used for assembler options instead. */ -+#undef SET_ASM_OP -+#define ASM_OUTPUT_DEF(FILE, LABEL1, LABEL2) \ -+ do \ -+ { \ -+ fputc ('\t', FILE); \ -+ assemble_name (FILE, LABEL1); \ -+ fputs (" = ", FILE); \ -+ assemble_name (FILE, LABEL2); \ -+ fputc ('\n', FILE); \ -+ } \ -+ while (0) ++#ifndef LOONGARCH_STR_H ++#define LOONGARCH_STR_H ++EOF + -+#undef ASM_DECLARE_OBJECT_NAME -+#define ASM_DECLARE_OBJECT_NAME loongarch_declare_object_name ++ sed -e '/^$/n' -e 's@#.*$@@' -e '/^$/d' \ ++ -e 's@^\([^ \t]\+\)[ \t]*\([^ \t]*\)@#define \1 "\2"@' \ ++ loongarch-strings + -+#undef ASM_FINISH_DECLARE_OBJECT -+#define ASM_FINISH_DECLARE_OBJECT loongarch_finish_declare_object ++ echo ++ echo "#endif /* LOONGARCH_STR_H */" ++} + -+/* Leave the linker script to choose the appropriate libraries. */ -+#undef LIB_SPEC -+#define LIB_SPEC "" + -+#undef STARTFILE_SPEC -+#define STARTFILE_SPEC "crti%O%s crtbegin%O%s" ++# Substitute all "@@@@" to "" in loongarch.opt.in ++# according to the key-value pairs defined in loongarch-strings. + -+#undef ENDFILE_SPEC -+#define ENDFILE_SPEC "crtend%O%s crtn%O%s" ++gen_options() { + -+#define NO_IMPLICIT_EXTERN_C 1 -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/frame-header-opt.c gcc-10.3.0/gcc/config/loongarch/frame-header-opt.c ---- gcc-10.3.0.org/gcc/config/loongarch/frame-header-opt.c 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/frame-header-opt.c 2022-03-23 17:40:29.343280152 +0800 -@@ -0,0 +1,292 @@ -+/* Analyze functions to determine if callers need to allocate a frame header -+ on the stack. The frame header is used by callees to save their arguments. -+ This optimization is specific to TARGET_OLDABI targets. For TARGET_NEWABI -+ targets, if a frame header is required, it is allocated by the callee. ++ sed -e '/^$/n' -e 's@#.*$@@' -e '/^$/d' \ ++ -e 's@^\([^ \t]\+\)[ \t]*\([^ \t]*\)@\1="\2"@' \ ++ loongarch-strings | { \ + ++ # read the definitions ++ while read -r line; do ++ eval "$line" ++ done + -+ Copyright (C) 2015-2018 Free Software Foundation, Inc. ++ # print a header ++ cat << EOF ++; Generated by "genstr" from the template "loongarch.opt.in" ++; and definitions from "loongarch-strings". ++; ++; Please do not edit this file directly. ++; It will be automatically updated during a gcc build ++; if you change "loongarch.opt.in" or "loongarch-strings". ++; ++EOF + -+This file is part of GCC. ++ # make the substitutions ++ sed -e 's@"@\\"@g' -e 's/@@\([^@]\+\)@@/${\1}/g' loongarch.opt.in | \ ++ while read -r line; do ++ eval "echo \"$line\"" ++ done ++ } ++} + -+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. ++main() { ++ case "$1" in ++ header) gen_defines;; ++ opt) gen_options;; ++ *) echo "Unknown Command: \"$1\". Available: header, opt"; exit 1;; ++ esac ++} + -+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. ++main "$@" +diff --git a/gcc/config/loongarch/genopts/loongarch-strings b/gcc/config/loongarch/genopts/loongarch-strings +new file mode 100644 +index 000000000..44ebb7ab1 +--- /dev/null ++++ b/gcc/config/loongarch/genopts/loongarch-strings +@@ -0,0 +1,59 @@ ++# Defines the key strings for LoongArch compiler options. ++# ++# Copyright (C) 2021-2022 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 ++# . + -+You should have received a copy of the GNU General Public License -+along with GCC; see the file COPYING3. If not see -+. */ ++# -march= / -mtune= ++OPTSTR_ARCH arch ++OPTSTR_TUNE tune ++ ++STR_CPU_NATIVE native ++STR_CPU_LOONGARCH64 loongarch64 ++STR_CPU_LA464 la464 ++ ++# Base architecture ++STR_ISA_BASE_LA64V100 la64 ++ ++# -mfpu ++OPTSTR_ISA_EXT_FPU fpu ++STR_ISA_EXT_NOFPU none ++STR_ISA_EXT_FPU0 0 ++STR_ISA_EXT_FPU32 32 ++STR_ISA_EXT_FPU64 64 ++ ++OPTSTR_SOFT_FLOAT soft-float ++OPTSTR_SINGLE_FLOAT single-float ++OPTSTR_DOUBLE_FLOAT double-float ++ ++# -mabi= ++OPTSTR_ABI_BASE abi ++STR_ABI_BASE_LP64D lp64d ++STR_ABI_BASE_LP64F lp64f ++STR_ABI_BASE_LP64S lp64s ++ ++# ABI extension types ++STR_ABI_EXT_BASE base ++ ++# -mcmodel= ++OPTSTR_CMODEL cmodel ++STR_CMODEL_NORMAL normal ++STR_CMODEL_TINY tiny ++STR_CMODEL_TS tiny-static ++STR_CMODEL_MEDIUM medium ++STR_CMODEL_LARGE large ++STR_CMODEL_EXTREME extreme +diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in b/gcc/config/loongarch/genopts/loongarch.opt.in +new file mode 100644 +index 000000000..ebdd9538d +--- /dev/null ++++ b/gcc/config/loongarch/genopts/loongarch.opt.in +@@ -0,0 +1,186 @@ ++; Copyright (C) 2021-2022 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 ++; . ++; + ++; Variables (macros) that should be exported by loongarch.opt: ++; la_opt_switches, ++; la_opt_abi_base, la_opt_abi_ext, ++; la_opt_cpu_arch, la_opt_cpu_tune, ++; la_opt_fpu, ++; la_cmodel. + -+#define IN_TARGET_CODE 1 ++HeaderInclude ++config/loongarch/loongarch-opts.h + -+#include "config.h" -+#include "system.h" -+#include "context.h" -+#include "coretypes.h" -+#include "tree.h" -+#include "tree-core.h" -+#include "tree-pass.h" -+#include "target.h" -+#include "target-globals.h" -+#include "profile-count.h" -+#include "function.h" -+#include "cfg.h" -+#include "cgraph.h" -+#include "basic-block.h" -+#include "gimple.h" -+#include "gimple-iterator.h" -+#include "gimple-walk.h" ++HeaderInclude ++config/loongarch/loongarch-str.h + -+static unsigned int frame_header_opt (void); ++Variable ++HOST_WIDE_INT la_opt_switches = 0 + -+namespace { ++; ISA related options ++;; Base ISA ++Enum ++Name(isa_base) Type(int) ++Basic ISAs of LoongArch: + -+const pass_data pass_data_ipa_frame_header_opt = -+{ -+ IPA_PASS, /* type */ -+ "frame-header-opt", /* name */ -+ OPTGROUP_NONE, /* optinfo_flags */ -+ TV_CGRAPHOPT, /* tv_id */ -+ 0, /* properties_required */ -+ 0, /* properties_provided */ -+ 0, /* properties_destroyed */ -+ 0, /* todo_flags_start */ -+ 0, /* todo_flags_finish */ -+}; ++EnumValue ++Enum(isa_base) String(@@STR_ISA_BASE_LA64V100@@) Value(ISA_BASE_LA64V100) + -+class pass_ipa_frame_header_opt : public ipa_opt_pass_d -+{ -+public: -+ pass_ipa_frame_header_opt (gcc::context *ctxt) -+ : ipa_opt_pass_d (pass_data_ipa_frame_header_opt, ctxt, -+ NULL, /* generate_summary */ -+ NULL, /* write_summary */ -+ NULL, /* read_summary */ -+ NULL, /* write_optimization_summary */ -+ NULL, /* read_optimization_summary */ -+ NULL, /* stmt_fixup */ -+ 0, /* function_transform_todo_flags_start */ -+ NULL, /* function_transform */ -+ NULL) /* variable_transform */ -+ {} + -+ /* opt_pass methods: */ -+ virtual bool gate (function *) -+ { -+ /* This optimization has no affect if TARGET_NEWABI. If optimize -+ is not at least 1 then the data needed for the optimization is -+ not available and nothing will be done anyway. */ -+ return TARGET_OLDABI && flag_frame_header_optimization && optimize > 0; -+ } ++;; ISA extensions / adjustments ++Enum ++Name(isa_ext_fpu) Type(int) ++FPU types of LoongArch: + -+ virtual unsigned int execute (function *) { return frame_header_opt (); } ++EnumValue ++Enum(isa_ext_fpu) String(@@STR_ISA_EXT_NOFPU@@) Value(ISA_EXT_NOFPU) + -+}; // class pass_ipa_frame_header_opt ++EnumValue ++Enum(isa_ext_fpu) String(@@STR_ISA_EXT_FPU32@@) Value(ISA_EXT_FPU32) + -+} // anon namespace ++EnumValue ++Enum(isa_ext_fpu) String(@@STR_ISA_EXT_FPU64@@) Value(ISA_EXT_FPU64) + -+static ipa_opt_pass_d * -+make_pass_ipa_frame_header_opt (gcc::context *ctxt) -+{ -+ return new pass_ipa_frame_header_opt (ctxt); -+} -+ -+void -+loongarch_register_frame_header_opt (void) -+{ -+ opt_pass *p = make_pass_ipa_frame_header_opt (g); -+ struct register_pass_info f = { p, "comdats", 1, PASS_POS_INSERT_AFTER }; -+ register_pass (&f); -+} -+ -+ -+/* Return true if it is certain that this is a leaf function. False if it is -+ not a leaf function or if it is impossible to tell. */ -+ -+static bool -+is_leaf_function (function *fn) -+{ -+ basic_block bb; -+ gimple_stmt_iterator gsi; -+ -+ /* If we do not have a cfg for this function be conservative and assume -+ it is not a leaf function. */ -+ if (fn->cfg == NULL) -+ return false; -+ -+ FOR_EACH_BB_FN (bb, fn) -+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) -+ if (is_gimple_call (gsi_stmt (gsi))) -+ return false; -+ return true; -+} -+ -+/* Return true if this function has inline assembly code or if we cannot -+ be certain that it does not. False if we know that there is no inline -+ assembly. */ -+ -+static bool -+has_inlined_assembly (function *fn) -+{ -+ basic_block bb; -+ gimple_stmt_iterator gsi; -+ -+ /* If we do not have a cfg for this function be conservative and assume -+ it is may have inline assembly. */ -+ if (fn->cfg == NULL) -+ return true; -+ -+ FOR_EACH_BB_FN (bb, fn) -+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) -+ if (gimple_code (gsi_stmt (gsi)) == GIMPLE_ASM) -+ return true; -+ -+ return false; -+} -+ -+/* Return true if this function will use the stack space allocated by its -+ caller or if we cannot determine for certain that it does not. */ -+ -+static bool -+needs_frame_header_p (function *fn) -+{ -+ tree t; -+ -+ if (fn->decl == NULL) -+ return true; -+ -+ if (fn->stdarg) -+ return true; -+ -+ for (t = DECL_ARGUMENTS (fn->decl); t; t = TREE_CHAIN (t)) -+ { -+ if (!use_register_for_decl (t)) -+ return true; -+ -+ /* Some 64-bit types may get copied to general registers using the frame -+ header, see loongarch_output_64bit_xfer. Checking for SImode only may be -+ overly restrictive but it is guaranteed to be safe. */ -+ if (DECL_MODE (t) != SImode) -+ return true; -+ } -+ -+ return false; -+} -+ -+/* Return true if the argument stack space allocated by function FN is used. -+ Return false if the space is needed or if the need for the space cannot -+ be determined. */ -+ -+static bool -+callees_functions_use_frame_header (function *fn) -+{ -+ basic_block bb; -+ gimple_stmt_iterator gsi; -+ gimple *stmt; -+ tree called_fn_tree; -+ function *called_fn; -+ -+ if (fn->cfg == NULL) -+ return true; -+ -+ FOR_EACH_BB_FN (bb, fn) -+ { -+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) -+ { -+ stmt = gsi_stmt (gsi); -+ if (is_gimple_call (stmt)) -+ { -+ called_fn_tree = gimple_call_fndecl (stmt); -+ if (called_fn_tree != NULL) -+ { -+ called_fn = DECL_STRUCT_FUNCTION (called_fn_tree); -+ if (called_fn == NULL -+ || DECL_WEAK (called_fn_tree) -+ || has_inlined_assembly (called_fn) -+ || !is_leaf_function (called_fn) -+ || !called_fn->machine->does_not_use_frame_header) -+ return true; -+ } -+ else -+ return true; -+ } -+ } -+ } -+ return false; -+} -+ -+/* Set the callers_may_not_allocate_frame flag for any function which -+ function FN calls because FN may not allocate a frame header. */ -+ -+static void -+set_callers_may_not_allocate_frame (function *fn) -+{ -+ basic_block bb; -+ gimple_stmt_iterator gsi; -+ gimple *stmt; -+ tree called_fn_tree; -+ function *called_fn; -+ -+ if (fn->cfg == NULL) -+ return; ++m@@OPTSTR_ISA_EXT_FPU@@= ++Target RejectNegative Joined ToLower Enum(isa_ext_fpu) Var(la_opt_fpu) Init(M_OPTION_NOT_SEEN) ++-m@@OPTSTR_ISA_EXT_FPU@@=FPU Generate code for the given FPU. + -+ FOR_EACH_BB_FN (bb, fn) -+ { -+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) -+ { -+ stmt = gsi_stmt (gsi); -+ if (is_gimple_call (stmt)) -+ { -+ called_fn_tree = gimple_call_fndecl (stmt); -+ if (called_fn_tree != NULL) -+ { -+ called_fn = DECL_STRUCT_FUNCTION (called_fn_tree); -+ if (called_fn != NULL) -+ called_fn->machine->callers_may_not_allocate_frame = true; -+ } -+ } -+ } -+ } -+ return; -+} -+ -+/* Scan each function to determine those that need its frame headers. Perform -+ a second scan to determine if the allocation can be skipped because none of -+ their callees require the frame header. */ -+ -+static unsigned int -+frame_header_opt () -+{ -+ struct cgraph_node *node; -+ function *fn; -+ -+ FOR_EACH_DEFINED_FUNCTION (node) -+ { -+ fn = node->get_fun (); -+ if (fn != NULL) -+ fn->machine->does_not_use_frame_header = !needs_frame_header_p (fn); -+ } -+ -+ FOR_EACH_DEFINED_FUNCTION (node) -+ { -+ fn = node->get_fun (); -+ if (fn != NULL) -+ fn->machine->optimize_call_stack -+ = !callees_functions_use_frame_header (fn) && !is_leaf_function (fn); -+ } -+ -+ FOR_EACH_DEFINED_FUNCTION (node) -+ { -+ fn = node->get_fun (); -+ if (fn != NULL && fn->machine->optimize_call_stack) -+ set_callers_may_not_allocate_frame (fn); -+ } ++m@@OPTSTR_ISA_EXT_FPU@@=@@STR_ISA_EXT_FPU0@@ ++Target RejectNegative Alias(m@@OPTSTR_ISA_EXT_FPU@@=,@@STR_ISA_EXT_NOFPU@@) + -+ return 0; -+} -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/generic.md gcc-10.3.0/gcc/config/loongarch/generic.md ---- gcc-10.3.0.org/gcc/config/loongarch/generic.md 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/generic.md 2022-03-23 17:40:29.343280152 +0800 -@@ -0,0 +1,109 @@ -+;; Generic DFA-based pipeline description for LARCH targets -+;; Copyright (C) 2004-2018 Free Software Foundation, Inc. -+;; -+;; This file is part of GCC. ++m@@OPTSTR_SOFT_FLOAT@@ ++Target Driver RejectNegative Var(la_opt_switches) Mask(FORCE_SOFTF) Negative(m@@OPTSTR_SINGLE_FLOAT@@) ++Prevent the use of all hardware floating-point instructions. + -+;; 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. ++m@@OPTSTR_SINGLE_FLOAT@@ ++Target Driver RejectNegative Var(la_opt_switches) Mask(FORCE_F32) Negative(m@@OPTSTR_DOUBLE_FLOAT@@) ++Restrict the use of hardware floating-point instructions to 32-bit operations. + -+;; 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. ++m@@OPTSTR_DOUBLE_FLOAT@@ ++Target Driver RejectNegative Var(la_opt_switches) Mask(FORCE_F64) Negative(m@@OPTSTR_SOFT_FLOAT@@) ++Allow hardware floating-point instructions to cover both 32-bit and 64-bit operations. + -+;; You should have received a copy of the GNU General Public License -+;; along with GCC; see the file COPYING3. If not see -+;; . + ++;; Base target models (implies ISA & tune parameters) ++Enum ++Name(cpu_type) Type(int) ++LoongArch CPU types: + -+;; This file is derived from the old define_function_unit description. -+;; Each reservation can be overridden on a processor-by-processor basis. ++EnumValue ++Enum(cpu_type) String(@@STR_CPU_NATIVE@@) Value(CPU_NATIVE) + -+(define_insn_reservation "generic_alu" 1 -+ (eq_attr "type" "unknown,prefetch,prefetchx,condmove,const,arith, -+ shift,slt,clz,trap,multi,nop,logical,signext,move") -+ "alu") ++EnumValue ++Enum(cpu_type) String(@@STR_CPU_LOONGARCH64@@) Value(CPU_LOONGARCH64) + -+(define_insn_reservation "generic_load" 3 -+ (eq_attr "type" "load,fpload,fpidxload") -+ "alu") ++EnumValue ++Enum(cpu_type) String(@@STR_CPU_LA464@@) Value(CPU_LA464) + -+(define_insn_reservation "generic_store" 1 -+ (eq_attr "type" "store,fpstore,fpidxstore") -+ "alu") ++m@@OPTSTR_ARCH@@= ++Target RejectNegative Joined Enum(cpu_type) Var(la_opt_cpu_arch) Init(M_OPTION_NOT_SEEN) ++-m@@OPTSTR_ARCH@@=PROCESSOR Generate code for the given PROCESSOR ISA. + -+(define_insn_reservation "generic_xfer" 2 -+ (eq_attr "type" "mftg,mgtf") -+ "alu") ++m@@OPTSTR_TUNE@@= ++Target RejectNegative Joined Enum(cpu_type) Var(la_opt_cpu_tune) Init(M_OPTION_NOT_SEEN) ++-m@@OPTSTR_TUNE@@=PROCESSOR Generate optimized code for PROCESSOR. + -+(define_insn_reservation "generic_branch" 1 -+ (eq_attr "type" "branch,jump,call") -+ "alu") + -+(define_insn_reservation "generic_imul" 17 -+ (eq_attr "type" "imul,imul3") -+ "imuldiv*17") ++; ABI related options ++; (ISA constraints on ABI are handled dynamically) + -+(define_insn_reservation "generic_fcvt" 1 -+ (eq_attr "type" "fcvt") -+ "alu") ++;; Base ABI ++Enum ++Name(abi_base) Type(int) ++Base ABI types for LoongArch: + -+(define_insn_reservation "generic_fmove" 2 -+ (eq_attr "type" "fabs,fneg,fmove") -+ "alu") ++EnumValue ++Enum(abi_base) String(@@STR_ABI_BASE_LP64D@@) Value(ABI_BASE_LP64D) + -+(define_insn_reservation "generic_fcmp" 3 -+ (eq_attr "type" "fcmp") -+ "alu") ++EnumValue ++Enum(abi_base) String(@@STR_ABI_BASE_LP64F@@) Value(ABI_BASE_LP64F) + -+(define_insn_reservation "generic_fadd" 4 -+ (eq_attr "type" "fadd") -+ "alu") ++EnumValue ++Enum(abi_base) String(@@STR_ABI_BASE_LP64S@@) Value(ABI_BASE_LP64S) + -+(define_insn_reservation "generic_fmul_single" 7 -+ (and (eq_attr "type" "fmul,fmadd") -+ (eq_attr "mode" "SF")) -+ "alu") ++m@@OPTSTR_ABI_BASE@@= ++Target RejectNegative Joined ToLower Enum(abi_base) Var(la_opt_abi_base) Init(M_OPTION_NOT_SEEN) ++-m@@OPTSTR_ABI_BASE@@=BASEABI Generate code that conforms to the given BASEABI. + -+(define_insn_reservation "generic_fmul_double" 8 -+ (and (eq_attr "type" "fmul,fmadd") -+ (eq_attr "mode" "DF")) -+ "alu") ++;; ABI Extension ++Variable ++int la_opt_abi_ext = M_OPTION_NOT_SEEN + -+(define_insn_reservation "generic_fdiv_single" 23 -+ (and (eq_attr "type" "fdiv,frdiv") -+ (eq_attr "mode" "SF")) -+ "alu") + -+(define_insn_reservation "generic_fdiv_double" 36 -+ (and (eq_attr "type" "fdiv,frdiv") -+ (eq_attr "mode" "DF")) -+ "alu") ++mbranch-cost= ++Target RejectNegative Joined UInteger Var(loongarch_branch_cost) ++-mbranch-cost=COST Set the cost of branches to roughly COST instructions. + -+(define_insn_reservation "generic_fsqrt_single" 54 -+ (and (eq_attr "type" "fsqrt,frsqrt") -+ (eq_attr "mode" "SF")) -+ "alu") ++mcheck-zero-division ++Target Mask(CHECK_ZERO_DIV) ++Trap on integer divide by zero. + -+(define_insn_reservation "generic_fsqrt_double" 112 -+ (and (eq_attr "type" "fsqrt,frsqrt") -+ (eq_attr "mode" "DF")) -+ "alu") ++mcond-move-int ++Target Var(TARGET_COND_MOVE_INT) Init(1) ++Conditional moves for integral are enabled. + -+(define_insn_reservation "generic_atomic" 10 -+ (eq_attr "type" "atomic") -+ "alu") ++mcond-move-float ++Target Var(TARGET_COND_MOVE_FLOAT) Init(1) ++Conditional moves for float are enabled. + -+;; Sync loop consists of (in order) -+;; (1) optional sync, -+;; (2) LL instruction, -+;; (3) branch and 1-2 ALU instructions, -+;; (4) SC instruction, -+;; (5) branch and ALU instruction. -+;; The net result of this reservation is a big delay with a flush of -+;; ALU pipeline. -+(define_insn_reservation "generic_sync_loop" 40 -+ (eq_attr "type" "syncloop") -+ "alu*39") -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/genopt.sh gcc-10.3.0/gcc/config/loongarch/genopt.sh ---- gcc-10.3.0.org/gcc/config/loongarch/genopt.sh 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/genopt.sh 2022-03-23 17:40:29.343280152 +0800 -@@ -0,0 +1,123 @@ -+#!/bin/sh -+# Generate loongarch-tables.opt from the list of CPUs in loongarch-cpus.def. -+# Copyright (C) 2011-2018 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 -+# . ++mmemcpy ++Target Mask(MEMCPY) ++Prevent optimizing block moves, which is also the default behavior of -Os. + -+cat <. ++mmax-inline-memcpy-size= ++Target Joined RejectNegative UInteger Var(loongarch_max_inline_memcpy_size) Init(1024) ++-mmax-inline-memcpy-size=SIZE Set the max size of memcpy to inline, default is 1024. + -+Enum -+Name(loongarch_arch_opt_value) Type(int) -+Known LARCH CPUs (for use with the -march= and -mtune= options): ++mexplicit-relocs ++Target Var(TARGET_EXPLICIT_RELOCS) Init(HAVE_AS_EXPLICIT_RELOCS) ++Use %reloc() assembly operators. + ++; The code model option names for -mcmodel. +Enum -+Name(loongarch_loongarch_opt_value) Type(int) -+Known LARCH ISA levels (for use with the -loongarch option): ++Name(cmodel) Type(int) ++The code model option names for -mcmodel: + +EnumValue -+Enum(loongarch_arch_opt_value) String(from-abi) Value(LARCH_ARCH_OPTION_FROM_ABI) ++Enum(cmodel) String(@@STR_CMODEL_NORMAL@@) Value(CMODEL_NORMAL) + +EnumValue -+Enum(loongarch_arch_opt_value) String(native) Value(LARCH_ARCH_OPTION_NATIVE) DriverOnly -+ -+EOF -+ -+awk -F'[(, ]+' ' -+BEGIN { -+ value = 0 -+} -+ -+# Write an entry for a single string accepted as a -march= argument. -+ -+function write_one_arch_value(name, value, flags) -+{ -+ print "EnumValue" -+ print "Enum(loongarch_arch_opt_value) String(" name ") Value(" value ")" flags -+ print "" -+ if (name ~ "^loongarch") { -+ sub("^loongarch", "", name) -+ print "EnumValue" -+ print "Enum(loongarch_loongarch_opt_value) String(" name ") Value(" value ")" -+ print "" -+ } -+} -+ -+# The logic for matching CPU name variants should be the same as in GAS. ++Enum(cmodel) String(@@STR_CMODEL_TINY@@) Value(CMODEL_TINY) + -+# Write an entry for a single string accepted as a -march= argument, -+# plus any variant with a final "000" replaced by "k". ++EnumValue ++Enum(cmodel) String(@@STR_CMODEL_TS@@) Value(CMODEL_TINY_STATIC) + -+function write_arch_value_maybe_k(name, value, flags) -+{ -+ write_one_arch_value(name, value, flags) -+ if (name ~ "000$") { -+ sub("000$", "k", name) -+ write_one_arch_value(name, value, "") -+ } -+} ++EnumValue ++Enum(cmodel) String(@@STR_CMODEL_MEDIUM@@) Value(CMODEL_MEDIUM) + -+# Write all the entries for a -march= argument. In addition to -+# replacement of a final "000" with "k", an argument starting with -+# "vr", "rm" or "r" followed by a number, or just a plain number, -+# matches a plain number or "r" followed by a plain number. ++EnumValue ++Enum(cmodel) String(@@STR_CMODEL_LARGE@@) Value(CMODEL_LARGE) + -+function write_all_arch_values(name, value) -+{ -+ write_arch_value_maybe_k(name, value, " Canonical") -+ cname = name -+ if (cname ~ "^vr") { -+ sub("^vr", "", cname) -+ } else if (cname ~ "^rm") { -+ sub("^rm", "", cname) -+ } else if (cname ~ "^r") { -+ sub("^r", "", cname) -+ } -+ if (cname ~ "^[0-9]") { -+ if (cname != name) -+ write_arch_value_maybe_k(cname, value, "") -+ rname = "r" cname -+ if (rname != name) -+ write_arch_value_maybe_k(rname, value, "") -+ } -+} ++EnumValue ++Enum(cmodel) String(@@STR_CMODEL_EXTREME@@) Value(CMODEL_EXTREME) + -+/^LARCH_CPU/ { -+ name = $2 -+ gsub("\"", "", name) -+ write_all_arch_values(name, value) -+ value++ -+}' $1/loongarch-cpus.def -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/gnu-user.h gcc-10.3.0/gcc/config/loongarch/gnu-user.h ---- gcc-10.3.0.org/gcc/config/loongarch/gnu-user.h 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/gnu-user.h 2022-03-23 17:40:29.343280152 +0800 -@@ -0,0 +1,132 @@ -+/* Definitions for LARCH systems using GNU userspace. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. ++mcmodel= ++Target RejectNegative Joined Enum(cmodel) Var(la_opt_cmodel) Init(CMODEL_NORMAL) ++Specify the code model. +diff --git a/gcc/config/loongarch/gnu-user.h b/gcc/config/loongarch/gnu-user.h +new file mode 100644 +index 000000000..664dc9206 +--- /dev/null ++++ b/gcc/config/loongarch/gnu-user.h +@@ -0,0 +1,80 @@ ++/* Definitions for LoongArch systems using GNU (glibc-based) userspace, ++ or other userspace with libc derived from glibc. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. + +This file is part of GCC. + @@ -1205,515 +1373,573 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/gnu-user.h gcc-10.3.0/gcc/config/l +along with GCC; see the file COPYING3. If not see +. */ + ++/* Define the size of the wide character type. */ +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + -+#undef ASM_DECLARE_OBJECT_NAME -+#define ASM_DECLARE_OBJECT_NAME loongarch_declare_object_name -+ -+/* If we don't set MASK_ABICALLS, we can't default to PIC. */ -+/* #undef TARGET_DEFAULT */ -+/* #define TARGET_DEFAULT MASK_ABICALLS */ -+ -+#define TARGET_OS_CPP_BUILTINS() \ -+ do { \ -+ GNU_USER_TARGET_OS_CPP_BUILTINS(); \ -+ /* The GNU C++ standard library requires this. */ \ -+ if (c_dialect_cxx ()) \ -+ builtin_define ("_GNU_SOURCE"); \ -+ } while (0) + -+#undef SUBTARGET_CPP_SPEC -+#define SUBTARGET_CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" ++/* GNU-specific SPEC definitions. */ ++#define GNU_USER_LINK_EMULATION "elf" ABI_GRLEN_SPEC "loongarch" + -+/* A standard GNU/Linux mapping. On most targets, it is included in -+ CC1_SPEC itself by config/linux.h, but loongarch.h overrides CC1_SPEC -+ and provides this hook instead. */ -+#undef SUBTARGET_CC1_SPEC -+#define SUBTARGET_CC1_SPEC GNU_USER_TARGET_CC1_SPEC ++#undef GLIBC_DYNAMIC_LINKER ++#define GLIBC_DYNAMIC_LINKER \ ++ "/lib" ABI_GRLEN_SPEC "/ld-linux-loongarch-" ABI_SPEC ".so.1" + -+/* -G is incompatible with -KPIC which is the default, so only allow objects -+ in the small data section if the user explicitly asks for it. */ -+#undef LARCH_DEFAULT_GVALUE -+#define LARCH_DEFAULT_GVALUE 0 ++#undef MUSL_DYNAMIC_LINKER ++#define MUSL_DYNAMIC_LINKER \ ++ "/lib" ABI_GRLEN_SPEC "/ld-musl-loongarch-" ABI_SPEC ".so.1" + +#undef GNU_USER_TARGET_LINK_SPEC -+#define GNU_USER_TARGET_LINK_SPEC "\ -+ %{G*} %{EB} %{EL} %{shared} \ -+ %{!shared: \ -+ %{!static: \ -+ %{rdynamic:-export-dynamic} \ -+ %{mabi=lp32: -dynamic-linker " GNU_USER_DYNAMIC_LINKERLP32 "} \ -+ %{mabi=lp64: -dynamic-linker " GNU_USER_DYNAMIC_LINKERLP64 "}} \ -+ %{static}} \ -+ %{mabi=lp32:-m" GNU_USER_LINK_EMULATION32 "} \ -+ %{mabi=lp64:-m" GNU_USER_LINK_EMULATION64 "}" ++#define GNU_USER_TARGET_LINK_SPEC \ ++ "%{G*} %{shared} -m " GNU_USER_LINK_EMULATION \ ++ "%{!shared: %{static} %{!static: %{rdynamic:-export-dynamic} " \ ++ "-dynamic-linker " GNU_USER_DYNAMIC_LINKER "}}" + -+#undef LINK_SPEC -+#define LINK_SPEC GNU_USER_TARGET_LINK_SPEC + -+/* The LARCH assembler has different syntax for .set. We set it to -+ .dummy to trap any errors. */ -+#undef SET_ASM_OP -+#define SET_ASM_OP "\t.dummy\t" -+ -+#undef ASM_OUTPUT_DEF -+#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ -+ do { \ -+ fputc ( '\t', FILE); \ -+ assemble_name (FILE, LABEL1); \ -+ fputs ( " = ", FILE); \ -+ assemble_name (FILE, LABEL2); \ -+ fputc ( '\n', FILE); \ -+ } while (0) -+ -+/* The glibc _mcount stub will save $v0 for us. Don't mess with saving -+ it, since ASM_OUTPUT_REG_PUSH/ASM_OUTPUT_REG_POP do not work in the -+ presence of $gp-relative calls. */ -+#undef ASM_OUTPUT_REG_PUSH -+#undef ASM_OUTPUT_REG_POP ++/* Similar to standard Linux, but adding -ffast-math support. */ ++#undef GNU_USER_TARGET_MATHFILE_SPEC ++#define GNU_USER_TARGET_MATHFILE_SPEC \ ++ "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s}" + +#undef LIB_SPEC +#define LIB_SPEC GNU_USER_TARGET_LIB_SPEC + -+#define NO_SHARED_SPECS "" ++#undef LINK_SPEC ++#define LINK_SPEC GNU_USER_TARGET_LINK_SPEC + -+/* -march=native handling only makes sense with compiler running on -+ a LARCH chip. */ -+#if defined(__loongarch__) -+extern const char *host_detect_local_cpu (int argc, const char **argv); -+# define EXTRA_SPEC_FUNCTIONS \ -+ { "local_cpu_detect", host_detect_local_cpu }, ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC \ ++ GNU_USER_TARGET_MATHFILE_SPEC " " \ ++ GNU_USER_TARGET_ENDFILE_SPEC + -+# define MARCH_MTUNE_NATIVE_SPECS \ -+ " %{march=native:%. + -+ Copyright (C) 2019 Free Software Foundation, Inc. -+ Contributed by xuchenghua@loongson.cn. ++;; Uncomment the following line to output automata for debugging. ++;; (automata_option "v") ++ ++;; Automaton for integer instructions. ++(define_automaton "la464_a_alu") ++ ++;; Automaton for floating-point instructions. ++(define_automaton "la464_a_falu") ++ ++;; Automaton for memory operations. ++(define_automaton "la464_a_mem") ++ ++;; Describe the resources. ++ ++(define_cpu_unit "la464_alu1" "la464_a_alu") ++(define_cpu_unit "la464_alu2" "la464_a_alu") ++(define_cpu_unit "la464_mem1" "la464_a_mem") ++(define_cpu_unit "la464_mem2" "la464_a_mem") ++(define_cpu_unit "la464_falu1" "la464_a_falu") ++(define_cpu_unit "la464_falu2" "la464_a_falu") ++ ++;; Describe instruction reservations. ++ ++(define_insn_reservation "la464_arith" 1 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "arith,clz,const,logical, ++ move,nop,shift,signext,slt")) ++ "la464_alu1 | la464_alu2") ++ ++(define_insn_reservation "la464_branch" 1 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "branch,jump,call,condmove,trap")) ++ "la464_alu1 | la464_alu2") ++ ++(define_insn_reservation "la464_imul" 7 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "imul")) ++ "la464_alu1 | la464_alu2") ++ ++(define_insn_reservation "la464_idiv_si" 12 ++ (and (match_test "TARGET_TUNE_LA464") ++ (and (eq_attr "type" "idiv") ++ (eq_attr "mode" "SI"))) ++ "la464_alu1 | la464_alu2") ++ ++(define_insn_reservation "la464_idiv_di" 25 ++ (and (match_test "TARGET_TUNE_LA464") ++ (and (eq_attr "type" "idiv") ++ (eq_attr "mode" "DI"))) ++ "la464_alu1 | la464_alu2") ++ ++(define_insn_reservation "la464_load" 4 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "load")) ++ "la464_mem1 | la464_mem2") ++ ++(define_insn_reservation "la464_gpr_fp" 16 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "mftg,mgtf")) ++ "la464_mem1") ++ ++(define_insn_reservation "la464_fpload" 4 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "fpload")) ++ "la464_mem1 | la464_mem2") ++ ++(define_insn_reservation "la464_prefetch" 0 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "prefetch,prefetchx")) ++ "la464_mem1 | la464_mem2") ++ ++(define_insn_reservation "la464_store" 0 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "store,fpstore,fpidxstore")) ++ "la464_mem1 | la464_mem2") ++ ++(define_insn_reservation "la464_fadd" 4 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "fadd,fmul,fmadd")) ++ "la464_falu1 | la464_falu2") ++ ++(define_insn_reservation "la464_fcmp" 2 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "fabs,fcmp,fmove,fneg")) ++ "la464_falu1 | la464_falu2") ++ ++(define_insn_reservation "la464_fcvt" 4 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "fcvt")) ++ "la464_falu1 | la464_falu2") ++ ++(define_insn_reservation "la464_fdiv_sf" 12 ++ (and (match_test "TARGET_TUNE_LA464") ++ (and (eq_attr "type" "fdiv,frdiv,fsqrt,frsqrt") ++ (eq_attr "mode" "SF"))) ++ "la464_falu1 | la464_falu2") ++ ++(define_insn_reservation "la464_fdiv_df" 19 ++ (and (match_test "TARGET_TUNE_LA464") ++ (and (eq_attr "type" "fdiv,frdiv,fsqrt,frsqrt") ++ (eq_attr "mode" "DF"))) ++ "la464_falu1 | la464_falu2") ++ ++;; Force single-dispatch for unknown or multi. ++(define_insn_reservation "la464_unknown" 1 ++ (and (match_test "TARGET_TUNE_LA464") ++ (eq_attr "type" "unknown,multi,atomic,syncloop")) ++ "la464_alu1 + la464_alu2 + la464_falu1 ++ + la464_falu2 + la464_mem1 + la464_mem2") ++ ++;; End of DFA-based pipeline description for la464 +diff --git a/gcc/config/loongarch/larchintrin.h b/gcc/config/loongarch/larchintrin.h +new file mode 100644 +index 000000000..2833f1487 +--- /dev/null ++++ b/gcc/config/loongarch/larchintrin.h +@@ -0,0 +1,355 @@ ++/* Intrinsics for LoongArch BASE operations. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. ++ Contributed by Loongson Ltd. + -+ This file is part of GCC. ++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 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. ++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. ++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 -+ . */ ++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 ++. */ + +#ifndef _GCC_LOONGARCH_BASE_INTRIN_H +#define _GCC_LOONGARCH_BASE_INTRIN_H + +#ifdef __cplusplus -+extern "C"{ ++extern "C" { +#endif + -+typedef struct drdtime{ -+ unsigned long dvalue; -+ unsigned long dtimeid; ++typedef struct drdtime ++{ ++ unsigned long dvalue; ++ unsigned long dtimeid; +} __drdtime_t; + -+typedef struct rdtime{ -+ unsigned int value; -+ unsigned int timeid; ++typedef struct rdtime ++{ ++ unsigned int value; ++ unsigned int timeid; +} __rdtime_t; + +#ifdef __loongarch64 -+extern __inline __drdtime_t __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_rdtime_d (void) ++extern __inline __drdtime_t ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__rdtime_d (void) +{ -+ __drdtime_t drdtime; ++ __drdtime_t __drdtime; + __asm__ volatile ( + "rdtime.d\t%[val],%[tid]\n\t" -+ : [val]"=&r"(drdtime.dvalue),[tid]"=&r"(drdtime.dtimeid) -+ : -+ ); -+ return drdtime; ++ : [val]"=&r"(__drdtime.dvalue),[tid]"=&r"(__drdtime.dtimeid) ++ :); ++ return __drdtime; +} -+#define __rdtime_d __builtin_loongarch_rdtime_d +#endif + -+extern __inline __rdtime_t __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_rdtimeh_w (void) ++extern __inline __rdtime_t ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__rdtimeh_w (void) +{ -+ __rdtime_t rdtime; ++ __rdtime_t __rdtime; + __asm__ volatile ( + "rdtimeh.w\t%[val],%[tid]\n\t" -+ : [val]"=&r"(rdtime.value),[tid]"=&r"(rdtime.timeid) -+ : -+ ); -+ return rdtime; ++ : [val]"=&r"(__rdtime.value),[tid]"=&r"(__rdtime.timeid) ++ :); ++ return __rdtime; +} -+#define __rdtimel_w __builtin_loongarch_rdtimel_w + -+extern __inline __rdtime_t __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_rdtimel_w (void) ++extern __inline __rdtime_t ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__rdtimel_w (void) +{ -+ __rdtime_t rdtime; ++ __rdtime_t __rdtime; + __asm__ volatile ( + "rdtimel.w\t%[val],%[tid]\n\t" -+ : [val]"=&r"(rdtime.value),[tid]"=&r"(rdtime.timeid) -+ : -+ ); -+ return rdtime; -+} -+#define __rdtimeh_w __builtin_loongarch_rdtimeh_w -+ -+/* Assembly instruction format: rj, fcsr */ -+/* Data types in instruction templates: USI, UQI */ -+#define __movfcsr2gr(/*ui5*/_1) __builtin_loongarch_movfcsr2gr((_1)); -+ -+/* Assembly instruction format: 0, fcsr, rj */ -+/* Data types in instruction templates: VOID, UQI, USI */ -+#define __movgr2fcsr(/*ui5*/ _1, _2) __builtin_loongarch_movgr2fcsr((unsigned short)_1, (unsigned int)_2); -+ -+#ifdef __loongarch32 -+/* Assembly instruction format: ui5, rj, si12 */ -+/* Data types in instruction templates: VOID, USI, USI, SI */ -+#define __cacop(/*ui5*/ _1, /*unsigned int*/ _2, /*si12*/ _3) ((void)__builtin_loongarch_cacop((_1), (unsigned int)(_2), (_3))) -+#elif defined __loongarch64 -+/* Assembly instruction format: ui5, rj, si12 */ -+/* Data types in instruction templates: VOID, USI, UDI, SI */ -+#define __dcacop(/*ui5*/ _1, /*unsigned long int*/ _2, /*si12*/ _3) ((void)__builtin_loongarch_dcacop((_1), (unsigned long int)(_2), (_3))) ++ : [val]"=&r"(__rdtime.value),[tid]"=&r"(__rdtime.timeid) ++ :); ++ return __rdtime; ++} ++ ++/* Assembly instruction format: rj, fcsr. */ ++/* Data types in instruction templates: USI, UQI. */ ++#define __movfcsr2gr(/*ui5*/ _1) __builtin_loongarch_movfcsr2gr ((_1)); ++ ++/* Assembly instruction format: fcsr, rj. */ ++/* Data types in instruction templates: VOID, UQI, USI. */ ++#define __movgr2fcsr(/*ui5*/ _1, _2) \ ++ __builtin_loongarch_movgr2fcsr ((_1), (unsigned int) _2); ++ ++#if defined __loongarch64 ++/* Assembly instruction format: ui5, rj, si12. */ ++/* Data types in instruction templates: VOID, USI, UDI, SI. */ ++#define __cacop_d(/*ui5*/ _1, /*unsigned long int*/ _2, /*si12*/ _3) \ ++ ((void) __builtin_loongarch_cacop_d ((_1), (unsigned long int) (_2), (_3))) +#else -+# error "Don't support this ABI." ++#error "Unsupported ABI." +#endif + -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: USI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+unsigned int __cpucfg(unsigned int _1) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: USI, USI. */ ++extern __inline unsigned int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__cpucfg (unsigned int _1) +{ -+ return (unsigned int)__builtin_loongarch_cpucfg((unsigned int)_1); ++ return (unsigned int) __builtin_loongarch_cpucfg ((unsigned int) _1); +} + +#ifdef __loongarch64 -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: DI, DI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+void __asrtle_d(long int _1, long int _2) ++/* Assembly instruction format: rj, rk. */ ++/* Data types in instruction templates: DI, DI. */ ++extern __inline void ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__asrtle_d (long int _1, long int _2) +{ -+ __builtin_loongarch_asrtle_d((long int)_1, (long int)_2); ++ __builtin_loongarch_asrtle_d ((long int) _1, (long int) _2); +} + -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: DI, DI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+void __asrtgt_d(long int _1, long int _2) ++/* Assembly instruction format: rj, rk. */ ++/* Data types in instruction templates: DI, DI. */ ++extern __inline void ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__asrtgt_d (long int _1, long int _2) +{ -+ __builtin_loongarch_asrtgt_d((long int)_1, (long int)_2); ++ __builtin_loongarch_asrtgt_d ((long int) _1, (long int) _2); +} +#endif + -+#ifdef __loongarch32 -+/* Assembly instruction format: rd, rj, ui5 */ -+/* Data types in instruction templates: SI, SI, UQI */ -+#define __lddir(/*int*/ _1, /*ui5*/ _2) ((int)__builtin_loongarch_lddir((int)(_1), (_2))) -+#elif defined __loongarch64 -+/* Assembly instruction format: rd, rj, ui5 */ -+/* Data types in instruction templates: DI, DI, UQI */ -+#define __dlddir(/*long int*/ _1, /*ui5*/ _2) ((long int)__builtin_loongarch_dlddir((long int)(_1), (_2))) ++#if defined __loongarch64 ++/* Assembly instruction format: rd, rj, ui5. */ ++/* Data types in instruction templates: DI, DI, UQI. */ ++#define __lddir_d(/*long int*/ _1, /*ui5*/ _2) \ ++ ((long int) __builtin_loongarch_lddir_d ((long int) (_1), (_2))) +#else -+# error "Don't support this ABI." ++#error "Unsupported ABI." +#endif + -+#ifdef __loongarch32 -+/* Assembly instruction format: rj, ui5 */ -+/* Data types in instruction templates: VOID, SI, UQI */ -+#define __ldpte(/*int*/ _1, /*ui5*/ _2) ((void)__builtin_loongarch_ldpte((int)(_1), (_2))) -+#elif defined __loongarch64 -+/* Assembly instruction format: rj, ui5 */ -+/* Data types in instruction templates: VOID, DI, UQI */ -+#define __dldpte(/*long int*/ _1, /*ui5*/ _2) ((void)__builtin_loongarch_dldpte((long int)(_1), (_2))) ++#if defined __loongarch64 ++/* Assembly instruction format: rj, ui5. */ ++/* Data types in instruction templates: VOID, DI, UQI. */ ++#define __ldpte_d(/*long int*/ _1, /*ui5*/ _2) \ ++ ((void) __builtin_loongarch_ldpte_d ((long int) (_1), (_2))) +#else -+# error "Don't support this ABI." ++#error "Unsupported ABI." +#endif + -+/* Assembly instruction format: rd, rj, rk */ -+/* Data types in instruction templates: SI, QI, SI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+int __crc_w_b_w(char _1, int _2) ++/* Assembly instruction format: rd, rj, rk. */ ++/* Data types in instruction templates: SI, QI, SI. */ ++extern __inline int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__crc_w_b_w (char _1, int _2) +{ -+ return (int)__builtin_loongarch_crc_w_b_w((char)_1, (int)_2); ++ return (int) __builtin_loongarch_crc_w_b_w ((char) _1, (int) _2); +} + -+/* Assembly instruction format: rd, rj, rk */ -+/* Data types in instruction templates: SI, HI, SI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+int __crc_w_h_w(short _1, int _2) ++/* Assembly instruction format: rd, rj, rk. */ ++/* Data types in instruction templates: SI, HI, SI. */ ++extern __inline int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__crc_w_h_w (short _1, int _2) +{ -+ return (int)__builtin_loongarch_crc_w_h_w((short)_1, (int)_2); ++ return (int) __builtin_loongarch_crc_w_h_w ((short) _1, (int) _2); +} + -+/* Assembly instruction format: rd, rj, rk */ -+/* Data types in instruction templates: SI, SI, SI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+int __crc_w_w_w(int _1, int _2) ++/* Assembly instruction format: rd, rj, rk. */ ++/* Data types in instruction templates: SI, SI, SI. */ ++extern __inline int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__crc_w_w_w (int _1, int _2) +{ -+ return (int)__builtin_loongarch_crc_w_w_w((int)_1, (int)_2); ++ return (int) __builtin_loongarch_crc_w_w_w ((int) _1, (int) _2); +} + +#ifdef __loongarch64 -+/* Assembly instruction format: rd, rj, rk */ -+/* Data types in instruction templates: SI, DI, SI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+int __crc_w_d_w(long int _1, int _2) ++/* Assembly instruction format: rd, rj, rk. */ ++/* Data types in instruction templates: SI, DI, SI. */ ++extern __inline int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__crc_w_d_w (long int _1, int _2) +{ -+ return (int)__builtin_loongarch_crc_w_d_w((long int)_1, (int)_2); ++ return (int) __builtin_loongarch_crc_w_d_w ((long int) _1, (int) _2); +} +#endif + -+/* Assembly instruction format: rd, rj, rk */ -+/* Data types in instruction templates: SI, QI, SI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+int __crcc_w_b_w(char _1, int _2) ++/* Assembly instruction format: rd, rj, rk. */ ++/* Data types in instruction templates: SI, QI, SI. */ ++extern __inline int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__crcc_w_b_w (char _1, int _2) +{ -+ return (int)__builtin_loongarch_crcc_w_b_w((char)_1, (int)_2); ++ return (int) __builtin_loongarch_crcc_w_b_w ((char) _1, (int) _2); +} + -+/* Assembly instruction format: rd, rj, rk */ -+/* Data types in instruction templates: SI, HI, SI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+int __crcc_w_h_w(short _1, int _2) ++/* Assembly instruction format: rd, rj, rk. */ ++/* Data types in instruction templates: SI, HI, SI. */ ++extern __inline int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__crcc_w_h_w (short _1, int _2) +{ -+ return (int)__builtin_loongarch_crcc_w_h_w((short)_1, (int)_2); ++ return (int) __builtin_loongarch_crcc_w_h_w ((short) _1, (int) _2); +} + -+/* Assembly instruction format: rd, rj, rk */ -+/* Data types in instruction templates: SI, SI, SI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+int __crcc_w_w_w(int _1, int _2) ++/* Assembly instruction format: rd, rj, rk. */ ++/* Data types in instruction templates: SI, SI, SI. */ ++extern __inline int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__crcc_w_w_w (int _1, int _2) +{ -+ return (int)__builtin_loongarch_crcc_w_w_w((int)_1, (int)_2); ++ return (int) __builtin_loongarch_crcc_w_w_w ((int) _1, (int) _2); +} + +#ifdef __loongarch64 -+/* Assembly instruction format: rd, rj, rk */ -+/* Data types in instruction templates: SI, DI, SI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+int __crcc_w_d_w(long int _1, int _2) ++/* Assembly instruction format: rd, rj, rk. */ ++/* Data types in instruction templates: SI, DI, SI. */ ++extern __inline int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__crcc_w_d_w (long int _1, int _2) +{ -+ return (int)__builtin_loongarch_crcc_w_d_w((long int)_1, (int)_2); ++ return (int) __builtin_loongarch_crcc_w_d_w ((long int) _1, (int) _2); +} +#endif + -+/* Assembly instruction format: rd, ui14 */ -+/* Data types in instruction templates: USI, USI */ -+#define __csrrd(/*ui14*/ _1) ((unsigned int)__builtin_loongarch_csrrd((_1))) ++/* Assembly instruction format: rd, ui14. */ ++/* Data types in instruction templates: USI, USI. */ ++#define __csrrd_w(/*ui14*/ _1) \ ++ ((unsigned int) __builtin_loongarch_csrrd_w ((_1))) + -+/* Assembly instruction format: rd, ui14 */ -+/* Data types in instruction templates: USI, USI, USI */ -+#define __csrwr(/*unsigned int*/ _1, /*ui14*/ _2) ((unsigned int)__builtin_loongarch_csrwr((unsigned int)(_1), (_2))) ++/* Assembly instruction format: rd, ui14. */ ++/* Data types in instruction templates: USI, USI, USI. */ ++#define __csrwr_w(/*unsigned int*/ _1, /*ui14*/ _2) \ ++ ((unsigned int) __builtin_loongarch_csrwr_w ((unsigned int) (_1), (_2))) + -+/* Assembly instruction format: rd, rj, ui14 */ -+/* Data types in instruction templates: USI, USI, USI, USI */ -+#define __csrxchg(/*unsigned int*/ _1, /*unsigned int*/ _2, /*ui14*/ _3) ((unsigned int)__builtin_loongarch_csrxchg((unsigned int)(_1), (unsigned int)(_2), (_3))) ++/* Assembly instruction format: rd, rj, ui14. */ ++/* Data types in instruction templates: USI, USI, USI, USI. */ ++#define __csrxchg_w(/*unsigned int*/ _1, /*unsigned int*/ _2, /*ui14*/ _3) \ ++ ((unsigned int) __builtin_loongarch_csrxchg_w ((unsigned int) (_1), \ ++ (unsigned int) (_2), (_3))) + +#ifdef __loongarch64 -+/* Assembly instruction format: rd, ui14 */ -+/* Data types in instruction templates: UDI, USI */ -+#define __dcsrrd(/*ui14*/ _1) ((unsigned long int)__builtin_loongarch_dcsrrd((_1))) -+ -+/* Assembly instruction format: rd, ui14 */ -+/* Data types in instruction templates: UDI, UDI, USI */ -+#define __dcsrwr(/*unsigned long int*/ _1, /*ui14*/ _2) ((unsigned long int)__builtin_loongarch_dcsrwr((unsigned long int)(_1), (_2))) -+ -+/* Assembly instruction format: rd, rj, ui14 */ -+/* Data types in instruction templates: UDI, UDI, UDI, USI */ -+#define __dcsrxchg(/*unsigned long int*/ _1, /*unsigned long int*/ _2, /*ui14*/ _3) ((unsigned long int)__builtin_loongarch_dcsrxchg((unsigned long int)(_1), (unsigned long int)(_2), (_3))) ++/* Assembly instruction format: rd, ui14. */ ++/* Data types in instruction templates: UDI, USI. */ ++#define __csrrd_d(/*ui14*/ _1) \ ++ ((unsigned long int) __builtin_loongarch_csrrd_d ((_1))) ++ ++/* Assembly instruction format: rd, ui14. */ ++/* Data types in instruction templates: UDI, UDI, USI. */ ++#define __csrwr_d(/*unsigned long int*/ _1, /*ui14*/ _2) \ ++ ((unsigned long int) __builtin_loongarch_csrwr_d ((unsigned long int) (_1), \ ++ (_2))) ++ ++/* Assembly instruction format: rd, rj, ui14. */ ++/* Data types in instruction templates: UDI, UDI, UDI, USI. */ ++#define __csrxchg_d(/*unsigned long int*/ _1, /*unsigned long int*/ _2, \ ++ /*ui14*/ _3) \ ++ ((unsigned long int) __builtin_loongarch_csrxchg_d ( \ ++ (unsigned long int) (_1), (unsigned long int) (_2), (_3))) +#endif + -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: UQI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+unsigned char __iocsrrd_b(unsigned int _1) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: UQI, USI. */ ++extern __inline unsigned char ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__iocsrrd_b (unsigned int _1) +{ -+ return (unsigned char)__builtin_loongarch_iocsrrd_b((unsigned int)_1); ++ return (unsigned char) __builtin_loongarch_iocsrrd_b ((unsigned int) _1); +} + -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: UHI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+unsigned short __iocsrrd_h(unsigned int _1) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: UHI, USI. */ ++extern __inline unsigned char ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__iocsrrd_h (unsigned int _1) +{ -+ return (unsigned short)__builtin_loongarch_iocsrrd_h((unsigned int)_1); ++ return (unsigned short) __builtin_loongarch_iocsrrd_h ((unsigned int) _1); +} + -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: USI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+unsigned int __iocsrrd_w(unsigned int _1) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: USI, USI. */ ++extern __inline unsigned int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__iocsrrd_w (unsigned int _1) +{ -+ return (unsigned int)__builtin_loongarch_iocsrrd_w((unsigned int)_1); ++ return (unsigned int) __builtin_loongarch_iocsrrd_w ((unsigned int) _1); +} + +#ifdef __loongarch64 -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: UDI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+unsigned long int __iocsrrd_d(unsigned int _1) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: UDI, USI. */ ++extern __inline unsigned long int ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__iocsrrd_d (unsigned int _1) +{ -+ return (unsigned long int)__builtin_loongarch_iocsrrd_d((unsigned int)_1); ++ return (unsigned long int) __builtin_loongarch_iocsrrd_d ((unsigned int) _1); +} +#endif + -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: VOID, UQI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+void __iocsrwr_b(unsigned char _1, unsigned int _2) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: VOID, UQI, USI. */ ++extern __inline void ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__iocsrwr_b (unsigned char _1, unsigned int _2) +{ -+ return (void)__builtin_loongarch_iocsrwr_b((unsigned char)_1, (unsigned int)_2); ++ __builtin_loongarch_iocsrwr_b ((unsigned char) _1, (unsigned int) _2); +} + -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: VOID, UHI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+void __iocsrwr_h(unsigned short _1, unsigned int _2) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: VOID, UHI, USI. */ ++extern __inline void ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__iocsrwr_h (unsigned short _1, unsigned int _2) +{ -+ return (void)__builtin_loongarch_iocsrwr_h((unsigned short)_1, (unsigned int)_2); ++ __builtin_loongarch_iocsrwr_h ((unsigned short) _1, (unsigned int) _2); +} + -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: VOID, USI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+void __iocsrwr_w(unsigned int _1, unsigned int _2) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: VOID, USI, USI. */ ++extern __inline void ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__iocsrwr_w (unsigned int _1, unsigned int _2) +{ -+ return (void)__builtin_loongarch_iocsrwr_w((unsigned int)_1, (unsigned int)_2); ++ __builtin_loongarch_iocsrwr_w ((unsigned int) _1, (unsigned int) _2); +} + +#ifdef __loongarch64 -+/* Assembly instruction format: rd, rj */ -+/* Data types in instruction templates: VOID, UDI, USI */ -+extern __inline __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+void __iocsrwr_d(unsigned long int _1, unsigned int _2) ++/* Assembly instruction format: rd, rj. */ ++/* Data types in instruction templates: VOID, UDI, USI. */ ++extern __inline void ++__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) ++__iocsrwr_d (unsigned long int _1, unsigned int _2) +{ -+ return (void)__builtin_loongarch_iocsrwr_d((unsigned long int)_1, (unsigned int)_2); ++ __builtin_loongarch_iocsrwr_d ((unsigned long int) _1, (unsigned int) _2); +} +#endif + -+/* Assembly instruction format: ui15 */ -+/* Data types in instruction templates: UQI */ -+#define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar((_1)) -+ -+/* Assembly instruction format: ui15 */ -+/* Data types in instruction templates: UQI */ -+#define __ibar(/*ui15*/ _1) __builtin_loongarch_ibar((_1)) -+ -+#define __builtin_loongarch_syscall(a) \ -+{ \ -+ __asm__ volatile ("syscall %0\n\t" \ -+ ::"I"(a)); \ -+} -+#define __syscall __builtin_loongarch_syscall -+ -+#define __builtin_loongarch_break(a) \ -+{ \ -+ __asm__ volatile ("break %0\n\t" \ -+ ::"I"(a)); \ -+} -+#define __break __builtin_loongarch_break -+ -+ -+extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_tlbsrch (void) -+{ -+ __asm__ volatile ("tlbsrch\n\t"); -+} -+#define __tlbsrch __builtin_loongarch_tlbsrch -+ -+extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_tlbrd (void) -+{ -+ __asm__ volatile ("tlbrd\n\t"); -+} -+#define __tlbrd __builtin_loongarch_tlbrd -+ -+extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_tlbwr (void) -+{ -+ __asm__ volatile ("tlbwr\n\t"); -+} -+#define __tlbwr __builtin_loongarch_tlbwr -+ -+extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_tlbfill (void) -+{ -+ __asm__ volatile ("tlbfill\n\t"); -+} -+#define __tlbfill __builtin_loongarch_tlbfill ++/* Assembly instruction format: ui15. */ ++/* Data types in instruction templates: USI. */ ++#define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar ((_1)) + -+extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_tlbclr (void) -+{ -+ __asm__ volatile ("tlbclr\n\t"); -+} -+#define __tlbclr __builtin_loongarch_tlbclr ++/* Assembly instruction format: ui15. */ ++/* Data types in instruction templates: USI. */ ++#define __ibar(/*ui15*/ _1) __builtin_loongarch_ibar ((_1)) + -+extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -+__builtin_loongarch_tlbflush (void) -+{ -+ __asm__ volatile ("tlbflush\n\t"); -+} -+#define __tlbflush __builtin_loongarch_tlbflush ++/* Assembly instruction format: ui15. */ ++/* Data types in instruction templates: USI. */ ++#define __syscall(/*ui15*/ _1) __builtin_loongarch_syscall ((_1)) + ++/* Assembly instruction format: ui15. */ ++/* Data types in instruction templates: USI. */ ++#define __break(/*ui15*/ _1) __builtin_loongarch_break ((_1)) + +#ifdef __cplusplus +} +#endif +#endif /* _GCC_LOONGARCH_BASE_INTRIN_H */ -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/linux-common.h gcc-10.3.0/gcc/config/loongarch/linux-common.h ---- gcc-10.3.0.org/gcc/config/loongarch/linux-common.h 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/linux-common.h 2022-03-23 17:40:29.343280152 +0800 -@@ -0,0 +1,68 @@ -+/* Definitions for LARCH running Linux-based GNU systems with ELF format. -+ Copyright (C) 2012-2018 Free Software Foundation, Inc. +diff --git a/gcc/config/loongarch/linux.h b/gcc/config/loongarch/linux.h +new file mode 100644 +index 000000000..110d0fab9 +--- /dev/null ++++ b/gcc/config/loongarch/linux.h +@@ -0,0 +1,50 @@ ++/* Definitions for Linux-based systems with libraries in ELF format. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. + +This file is part of GCC. + @@ -1731,95 +1957,46 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/linux-common.h gcc-10.3.0/gcc/conf +along with GCC; see the file COPYING3. If not see +. */ + -+#undef TARGET_OS_CPP_BUILTINS -+#define TARGET_OS_CPP_BUILTINS() \ -+ do { \ -+ GNU_USER_TARGET_OS_CPP_BUILTINS(); \ -+ /* The GNU C++ standard library requires this. */ \ -+ if (c_dialect_cxx ()) \ -+ builtin_define ("_GNU_SOURCE"); \ -+ ANDROID_TARGET_OS_CPP_BUILTINS(); \ -+ } while (0) -+ -+#define EXTRA_TARGET_D_OS_VERSIONS() \ -+ ANDROID_TARGET_D_OS_VERSIONS(); -+ -+#undef LINK_SPEC -+#define LINK_SPEC \ -+ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_LINK_SPEC, \ -+ GNU_USER_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC) -+ -+#undef SUBTARGET_CC1_SPEC -+#define SUBTARGET_CC1_SPEC \ -+ LINUX_OR_ANDROID_CC (GNU_USER_TARGET_CC1_SPEC, \ -+ GNU_USER_TARGET_CC1_SPEC " " ANDROID_CC1_SPEC) -+ -+#undef CC1PLUS_SPEC -+#define CC1PLUS_SPEC \ -+ LINUX_OR_ANDROID_CC ("", ANDROID_CC1PLUS_SPEC) -+ -+#undef LIB_SPEC -+#define LIB_SPEC \ -+ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_LIB_SPEC, \ -+ GNU_USER_TARGET_NO_PTHREADS_LIB_SPEC " " ANDROID_LIB_SPEC) -+ -+#undef STARTFILE_SPEC -+#define STARTFILE_SPEC \ -+ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_STARTFILE_SPEC, ANDROID_STARTFILE_SPEC) -+ -+#undef ENDFILE_SPEC -+#define ENDFILE_SPEC \ -+ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_MATHFILE_SPEC " " \ -+ GNU_USER_TARGET_ENDFILE_SPEC, \ -+ GNU_USER_TARGET_MATHFILE_SPEC " " \ -+ ANDROID_ENDFILE_SPEC) ++/* Default system library search paths. ++ * This ensures that a compiler configured with --disable-multilib ++ * can work in a multilib environment. */ + -+/* Define this to be nonzero if static stack checking is supported. */ -+#define STACK_CHECK_STATIC_BUILTIN 1 ++#if defined(LA_DISABLE_MULTILIB) && defined(LA_DISABLE_MULTIARCH) + -+/* FIXME*/ -+/* The default value isn't sufficient in 64-bit mode. */ -+#define STACK_CHECK_PROTECT (TARGET_64BIT ? 16 * 1024 : 12 * 1024) -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/linux.h gcc-10.3.0/gcc/config/loongarch/linux.h ---- gcc-10.3.0.org/gcc/config/loongarch/linux.h 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/linux.h 2022-03-23 17:40:29.344280144 +0800 -@@ -0,0 +1,29 @@ -+/* Definitions for LARCH running Linux-based GNU systems with ELF format. -+ Copyright (C) 1998-2018 Free Software Foundation, Inc. ++ #if DEFAULT_ABI_BASE == ABI_BASE_LP64D ++ #define ABI_LIBDIR "lib64" ++ #elif DEFAULT_ABI_BASE == ABI_BASE_LP64F ++ #define ABI_LIBDIR "lib64/f32" ++ #elif DEFAULT_ABI_BASE == ABI_BASE_LP64S ++ #define ABI_LIBDIR "lib64/sf" ++ #endif + -+This file is part of GCC. ++#endif + -+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. ++#ifndef ABI_LIBDIR ++#define ABI_LIBDIR "lib" ++#endif + -+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. ++#define STANDARD_STARTFILE_PREFIX_1 "/" ABI_LIBDIR "/" ++#define STANDARD_STARTFILE_PREFIX_2 "/usr/" ABI_LIBDIR "/" + -+You should have received a copy of the GNU General Public License -+along with GCC; see the file COPYING3. If not see -+. */ + -+#define GNU_USER_LINK_EMULATION32 "elf32loongarch" -+#define GNU_USER_LINK_EMULATION64 "elf64loongarch" ++/* Define this to be nonzero if static stack checking is supported. */ ++#define STACK_CHECK_STATIC_BUILTIN 1 + -+#define GLIBC_DYNAMIC_LINKERLP32 \ -+ "/lib32/ld.so.1" -+#define GLIBC_DYNAMIC_LINKERLP64 \ -+ "/lib64/ld.so.1" ++/* The default value isn't sufficient in 64-bit mode. */ ++#define STACK_CHECK_PROTECT (TARGET_64BIT ? 16 * 1024 : 12 * 1024) + -+#define GNU_USER_DYNAMIC_LINKERLP32 GLIBC_DYNAMIC_LINKERLP32 -+#define GNU_USER_DYNAMIC_LINKERLP64 GLIBC_DYNAMIC_LINKERLP64 -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gcc/config/loongarch/loongarch-builtins.c ---- gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/loongarch-builtins.c 2022-03-23 17:40:29.344280144 +0800 -@@ -0,0 +1,593 @@ -+/* Subroutines used for expanding LOONGARCH builtins. -+ Copyright (C) 2011-2018 Free Software Foundation, Inc. -+ Contributed by Andrew Waterman (andrew@sifive.com). ++#define TARGET_ASM_FILE_END file_end_indicate_exec_stack +diff --git a/gcc/config/loongarch/loongarch-builtins.c b/gcc/config/loongarch/loongarch-builtins.c +new file mode 100644 +index 000000000..64fe11168 +--- /dev/null ++++ b/gcc/config/loongarch/loongarch-builtins.c +@@ -0,0 +1,424 @@ ++/* Subroutines used for expanding LoongArch builtins. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. ++ Contributed by Loongson Ltd. + +This file is part of GCC. + @@ -1860,10 +2037,10 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc +#define LARCH_FTYPE_NAME1(A, B) LARCH_##A##_FTYPE_##B +#define LARCH_FTYPE_NAME2(A, B, C) LARCH_##A##_FTYPE_##B##_##C +#define LARCH_FTYPE_NAME3(A, B, C, D) LARCH_##A##_FTYPE_##B##_##C##_##D -+#define LARCH_FTYPE_NAME4(A, B, C, D, E) LARCH_##A##_FTYPE_##B##_##C##_##D##_##E + +/* Classifies the prototype of a built-in function. */ -+enum loongarch_function_type { ++enum loongarch_function_type ++{ +#define DEF_LARCH_FTYPE(NARGS, LIST) LARCH_FTYPE_NAME##NARGS LIST, +#include "config/loongarch/loongarch-ftypes.def" +#undef DEF_LARCH_FTYPE @@ -1871,7 +2048,8 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc +}; + +/* Specifies how a built-in function should be converted into rtl. */ -+enum loongarch_builtin_type { ++enum loongarch_builtin_type ++{ + /* The function corresponds directly to an .md pattern. The return + value is mapped to operand 0 and the arguments are mapped to + operands 1 and above. */ @@ -1883,47 +2061,14 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + +}; + -+/* Invoke MACRO (COND) for each C.cond.fmt condition. */ -+#define LARCH_FP_CONDITIONS(MACRO) \ -+ MACRO (f), \ -+ MACRO (un), \ -+ MACRO (eq), \ -+ MACRO (ueq), \ -+ MACRO (olt), \ -+ MACRO (ult), \ -+ MACRO (ole), \ -+ MACRO (ule), \ -+ MACRO (sf), \ -+ MACRO (ngle), \ -+ MACRO (seq), \ -+ MACRO (ngl), \ -+ MACRO (lt), \ -+ MACRO (nge), \ -+ MACRO (le), \ -+ MACRO (ngt) -+ -+/* Enumerates the codes above as LARCH_FP_COND_. */ -+#define DECLARE_LARCH_COND(X) LARCH_FP_COND_ ## X -+enum loongarch_fp_condition { -+ LARCH_FP_CONDITIONS (DECLARE_LARCH_COND) -+}; -+#undef DECLARE_LARCH_COND -+ -+/* Index X provides the string representation of LARCH_FP_COND_. */ -+#define STRINGIFY(X) #X -+const char *const loongarch_fp_conditions[16] = { -+ LARCH_FP_CONDITIONS (STRINGIFY) -+}; -+#undef STRINGIFY -+ -+/* Declare an availability predicate for built-in functions that require ++/* Declare an availability predicate for built-in functions that require + * COND to be true. NAME is the main part of the predicate's name. */ -+#define AVAIL_ALL(NAME, COND) \ -+ static unsigned int \ -+ loongarch_builtin_avail_##NAME (void) \ -+ { \ -+ return (COND) ? 1 : 0; \ -+ } ++#define AVAIL_ALL(NAME, COND) \ ++ static unsigned int \ ++ loongarch_builtin_avail_##NAME (void) \ ++ { \ ++ return (COND) ? 1 : 0; \ ++ } + +static unsigned int +loongarch_builtin_avail_default (void) @@ -1931,14 +2076,12 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + return 1; +} +/* This structure describes a single built-in function. */ -+struct loongarch_builtin_description { ++struct loongarch_builtin_description ++{ + /* The code of the main .md file instruction. See loongarch_builtin_type + for more information. */ + enum insn_code icode; + -+ /* The floating-point comparison code to use with ICODE, if any. */ -+ enum loongarch_fp_condition cond; -+ + /* The name of the built-in function. */ + const char *name; + @@ -1953,7 +2096,6 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc +}; + +AVAIL_ALL (hard_float, TARGET_HARD_FLOAT_ABI) -+AVAIL_ALL (lvz, TARGET_LVZ) + +/* Construct a loongarch_builtin_description from the given arguments. + @@ -1970,87 +2112,25 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + + AVAIL is the name of the availability predicate, without the leading + loongarch_builtin_avail_. */ -+#define LARCH_BUILTIN(INSN, COND, NAME, BUILTIN_TYPE, \ -+ FUNCTION_TYPE, AVAIL) \ -+ { CODE_FOR_loongarch_ ## INSN, LARCH_FP_COND_ ## COND, \ -+ "__builtin_loongarch_" NAME, BUILTIN_TYPE, FUNCTION_TYPE, \ -+ loongarch_builtin_avail_ ## AVAIL } ++#define LARCH_BUILTIN(INSN, NAME, BUILTIN_TYPE, FUNCTION_TYPE, AVAIL) \ ++ { \ ++ CODE_FOR_loongarch_##INSN, "__builtin_loongarch_" NAME, \ ++ BUILTIN_TYPE, FUNCTION_TYPE, \ ++ loongarch_builtin_avail_##AVAIL \ ++ } + +/* Define __builtin_loongarch_, which is a LARCH_BUILTIN_DIRECT function + mapped to instruction CODE_FOR_loongarch_, FUNCTION_TYPE and AVAIL + are as for LARCH_BUILTIN. */ -+#define DIRECT_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \ -+ LARCH_BUILTIN (INSN, f, #INSN, LARCH_BUILTIN_DIRECT, FUNCTION_TYPE, AVAIL) ++#define DIRECT_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \ ++ LARCH_BUILTIN (INSN, #INSN, LARCH_BUILTIN_DIRECT, FUNCTION_TYPE, AVAIL) + +/* Define __builtin_loongarch_, which is a LARCH_BUILTIN_DIRECT_NO_TARGET + function mapped to instruction CODE_FOR_loongarch_, FUNCTION_TYPE + and AVAIL are as for LARCH_BUILTIN. */ -+#define DIRECT_NO_TARGET_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \ -+ LARCH_BUILTIN (INSN, f, #INSN, LARCH_BUILTIN_DIRECT_NO_TARGET, \ -+ FUNCTION_TYPE, AVAIL) -+ -+/* Define an LVZ LARCH_BUILTIN_DIRECT function __builtin_lvz_ -+ for instruction CODE_FOR_lvz_. FUNCTION_TYPE is a builtin_description -+ field. */ -+#define LVZ_BUILTIN(INSN, FUNCTION_TYPE) \ -+ { CODE_FOR_lvz_ ## INSN, LARCH_FP_COND_f, \ -+ "__builtin_lvz_" #INSN, LARCH_BUILTIN_DIRECT, \ -+ FUNCTION_TYPE, loongarch_builtin_avail_lvz } -+ -+ /* Loongson support loongarch64r6 */ -+#define CODE_FOR_loongarch_fmax_sf CODE_FOR_smaxsf3 -+#define CODE_FOR_loongarch_fmax_df CODE_FOR_smaxdf3 -+#define CODE_FOR_loongarch_fmin_sf CODE_FOR_sminsf3 -+#define CODE_FOR_loongarch_fmin_df CODE_FOR_smindf3 -+#define CODE_FOR_loongarch_fmaxa_sf CODE_FOR_smaxasf3 -+#define CODE_FOR_loongarch_fmaxa_df CODE_FOR_smaxadf3 -+#define CODE_FOR_loongarch_fmina_sf CODE_FOR_sminasf3 -+#define CODE_FOR_loongarch_fmina_df CODE_FOR_sminadf3 -+#define CODE_FOR_loongarch_fclass_s CODE_FOR_fclass_s -+#define CODE_FOR_loongarch_fclass_d CODE_FOR_fclass_d -+#define CODE_FOR_loongarch_frint_s CODE_FOR_frint_s -+#define CODE_FOR_loongarch_frint_d CODE_FOR_frint_d -+#define CODE_FOR_loongarch_bytepick_w CODE_FOR_bytepick_w -+#define CODE_FOR_loongarch_bytepick_d CODE_FOR_bytepick_d -+#define CODE_FOR_loongarch_bitrev_4b CODE_FOR_bitrev_4b -+#define CODE_FOR_loongarch_bitrev_8b CODE_FOR_bitrev_8b -+ -+/* Loongson support crc */ -+#define CODE_FOR_loongarch_crc_w_b_w CODE_FOR_crc_w_b_w -+#define CODE_FOR_loongarch_crc_w_h_w CODE_FOR_crc_w_h_w -+#define CODE_FOR_loongarch_crc_w_w_w CODE_FOR_crc_w_w_w -+#define CODE_FOR_loongarch_crc_w_d_w CODE_FOR_crc_w_d_w -+#define CODE_FOR_loongarch_crcc_w_b_w CODE_FOR_crcc_w_b_w -+#define CODE_FOR_loongarch_crcc_w_h_w CODE_FOR_crcc_w_h_w -+#define CODE_FOR_loongarch_crcc_w_w_w CODE_FOR_crcc_w_w_w -+#define CODE_FOR_loongarch_crcc_w_d_w CODE_FOR_crcc_w_d_w -+ -+/* Privileged state instruction */ -+#define CODE_FOR_loongarch_cpucfg CODE_FOR_cpucfg -+#define CODE_FOR_loongarch_asrtle_d CODE_FOR_asrtle_d -+#define CODE_FOR_loongarch_asrtgt_d CODE_FOR_asrtgt_d -+#define CODE_FOR_loongarch_csrrd CODE_FOR_csrrd -+#define CODE_FOR_loongarch_dcsrrd CODE_FOR_dcsrrd -+#define CODE_FOR_loongarch_csrwr CODE_FOR_csrwr -+#define CODE_FOR_loongarch_dcsrwr CODE_FOR_dcsrwr -+#define CODE_FOR_loongarch_csrxchg CODE_FOR_csrxchg -+#define CODE_FOR_loongarch_dcsrxchg CODE_FOR_dcsrxchg -+#define CODE_FOR_loongarch_iocsrrd_b CODE_FOR_iocsrrd_b -+#define CODE_FOR_loongarch_iocsrrd_h CODE_FOR_iocsrrd_h -+#define CODE_FOR_loongarch_iocsrrd_w CODE_FOR_iocsrrd_w -+#define CODE_FOR_loongarch_iocsrrd_d CODE_FOR_iocsrrd_d -+#define CODE_FOR_loongarch_iocsrwr_b CODE_FOR_iocsrwr_b -+#define CODE_FOR_loongarch_iocsrwr_h CODE_FOR_iocsrwr_h -+#define CODE_FOR_loongarch_iocsrwr_w CODE_FOR_iocsrwr_w -+#define CODE_FOR_loongarch_iocsrwr_d CODE_FOR_iocsrwr_d -+#define CODE_FOR_loongarch_lddir CODE_FOR_lddir -+#define CODE_FOR_loongarch_dlddir CODE_FOR_dlddir -+#define CODE_FOR_loongarch_ldpte CODE_FOR_ldpte -+#define CODE_FOR_loongarch_dldpte CODE_FOR_dldpte -+#define CODE_FOR_loongarch_cacop CODE_FOR_cacop -+#define CODE_FOR_loongarch_dcacop CODE_FOR_dcacop -+#define CODE_FOR_loongarch_dbar CODE_FOR_dbar -+#define CODE_FOR_loongarch_ibar CODE_FOR_ibar ++#define DIRECT_NO_TARGET_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \ ++ LARCH_BUILTIN (INSN, #INSN, LARCH_BUILTIN_DIRECT_NO_TARGET, \ ++ FUNCTION_TYPE, AVAIL) + +static const struct loongarch_builtin_description loongarch_builtins[] = { +#define LARCH_MOVFCSR2GR 0 @@ -2058,36 +2138,17 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc +#define LARCH_MOVGR2FCSR 1 + DIRECT_NO_TARGET_BUILTIN (movgr2fcsr, LARCH_VOID_FTYPE_UQI_USI, hard_float), + -+ DIRECT_NO_TARGET_BUILTIN (cacop, LARCH_VOID_FTYPE_USI_USI_SI, default), -+ DIRECT_NO_TARGET_BUILTIN (dcacop, LARCH_VOID_FTYPE_USI_UDI_SI, default), ++ DIRECT_NO_TARGET_BUILTIN (cacop_w, LARCH_VOID_FTYPE_USI_USI_SI, default), ++ DIRECT_NO_TARGET_BUILTIN (cacop_d, LARCH_VOID_FTYPE_USI_UDI_SI, default), + DIRECT_NO_TARGET_BUILTIN (dbar, LARCH_VOID_FTYPE_USI, default), + DIRECT_NO_TARGET_BUILTIN (ibar, LARCH_VOID_FTYPE_USI, default), + -+ DIRECT_BUILTIN (fmax_sf, LARCH_SF_FTYPE_SF_SF, hard_float), -+ DIRECT_BUILTIN (fmax_df, LARCH_DF_FTYPE_DF_DF, hard_float), -+ DIRECT_BUILTIN (fmin_sf, LARCH_SF_FTYPE_SF_SF, hard_float), -+ DIRECT_BUILTIN (fmin_df, LARCH_DF_FTYPE_DF_DF, hard_float), -+ DIRECT_BUILTIN (fmaxa_sf, LARCH_SF_FTYPE_SF_SF, hard_float), -+ DIRECT_BUILTIN (fmaxa_df, LARCH_DF_FTYPE_DF_DF, hard_float), -+ DIRECT_BUILTIN (fmina_sf, LARCH_SF_FTYPE_SF_SF, hard_float), -+ DIRECT_BUILTIN (fmina_df, LARCH_DF_FTYPE_DF_DF, hard_float), -+ DIRECT_BUILTIN (fclass_s, LARCH_SF_FTYPE_SF, hard_float), -+ DIRECT_BUILTIN (fclass_d, LARCH_DF_FTYPE_DF, hard_float), -+ DIRECT_BUILTIN (frint_s, LARCH_SF_FTYPE_SF, hard_float), -+ DIRECT_BUILTIN (frint_d, LARCH_DF_FTYPE_DF, hard_float), -+ DIRECT_BUILTIN (bytepick_w, LARCH_SI_FTYPE_SI_SI_QI, default), -+ DIRECT_BUILTIN (bytepick_d, LARCH_DI_FTYPE_DI_DI_QI, default), -+ DIRECT_BUILTIN (bitrev_4b, LARCH_SI_FTYPE_SI, default), -+ DIRECT_BUILTIN (bitrev_8b, LARCH_DI_FTYPE_DI, default), -+ DIRECT_BUILTIN (cpucfg, LARCH_USI_FTYPE_USI, default), -+ DIRECT_BUILTIN (asrtle_d, LARCH_VOID_FTYPE_DI_DI, default), -+ DIRECT_BUILTIN (asrtgt_d, LARCH_VOID_FTYPE_DI_DI, default), -+ DIRECT_BUILTIN (dlddir, LARCH_DI_FTYPE_DI_UQI, default), -+ DIRECT_BUILTIN (lddir, LARCH_SI_FTYPE_SI_UQI, default), -+ DIRECT_NO_TARGET_BUILTIN (dldpte, LARCH_VOID_FTYPE_DI_UQI, default), -+ DIRECT_NO_TARGET_BUILTIN (ldpte, LARCH_VOID_FTYPE_SI_UQI, default), ++ DIRECT_BUILTIN (lddir_d, LARCH_DI_FTYPE_DI_UQI, default), ++ DIRECT_BUILTIN (lddir_w, LARCH_SI_FTYPE_SI_UQI, default), ++ DIRECT_NO_TARGET_BUILTIN (ldpte_d, LARCH_VOID_FTYPE_DI_UQI, default), ++ DIRECT_NO_TARGET_BUILTIN (ldpte_w, LARCH_VOID_FTYPE_SI_UQI, default), + -+ /* CRC Instrinsic */ ++ /* CRC Instrinsic */ + + DIRECT_BUILTIN (crc_w_b_w, LARCH_SI_FTYPE_QI_SI, default), + DIRECT_BUILTIN (crc_w_h_w, LARCH_SI_FTYPE_HI_SI, default), @@ -2098,20 +2159,12 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + DIRECT_BUILTIN (crcc_w_w_w, LARCH_SI_FTYPE_SI_SI, default), + DIRECT_BUILTIN (crcc_w_d_w, LARCH_SI_FTYPE_DI_SI, default), + -+ /* Built-in functions for LVZ. */ -+ LVZ_BUILTIN (gcsrrd, LARCH_USI_FTYPE_USI), -+ LVZ_BUILTIN (gcsrwr, LARCH_USI_FTYPE_USI_USI), -+ LVZ_BUILTIN (gcsrxchg, LARCH_USI_FTYPE_USI_USI_USI), -+ LVZ_BUILTIN (dgcsrrd, LARCH_UDI_FTYPE_USI), -+ LVZ_BUILTIN (dgcsrwr, LARCH_UDI_FTYPE_UDI_USI), -+ LVZ_BUILTIN (dgcsrxchg, LARCH_UDI_FTYPE_UDI_UDI_USI), -+ -+ DIRECT_BUILTIN (csrrd, LARCH_USI_FTYPE_USI, default), -+ DIRECT_BUILTIN (dcsrrd, LARCH_UDI_FTYPE_USI, default), -+ DIRECT_BUILTIN (csrwr, LARCH_USI_FTYPE_USI_USI, default), -+ DIRECT_BUILTIN (dcsrwr, LARCH_UDI_FTYPE_UDI_USI, default), -+ DIRECT_BUILTIN (csrxchg, LARCH_USI_FTYPE_USI_USI_USI, default), -+ DIRECT_BUILTIN (dcsrxchg, LARCH_UDI_FTYPE_UDI_UDI_USI, default), ++ DIRECT_BUILTIN (csrrd_w, LARCH_USI_FTYPE_USI, default), ++ DIRECT_BUILTIN (csrrd_d, LARCH_UDI_FTYPE_USI, default), ++ DIRECT_BUILTIN (csrwr_w, LARCH_USI_FTYPE_USI_USI, default), ++ DIRECT_BUILTIN (csrwr_d, LARCH_UDI_FTYPE_UDI_USI, default), ++ DIRECT_BUILTIN (csrxchg_w, LARCH_USI_FTYPE_USI_USI_USI, default), ++ DIRECT_BUILTIN (csrxchg_d, LARCH_UDI_FTYPE_UDI_UDI_USI, default), + DIRECT_BUILTIN (iocsrrd_b, LARCH_UQI_FTYPE_USI, default), + DIRECT_BUILTIN (iocsrrd_h, LARCH_UHI_FTYPE_USI, default), + DIRECT_BUILTIN (iocsrrd_w, LARCH_USI_FTYPE_USI, default), @@ -2120,34 +2173,25 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + DIRECT_NO_TARGET_BUILTIN (iocsrwr_h, LARCH_VOID_FTYPE_UHI_USI, default), + DIRECT_NO_TARGET_BUILTIN (iocsrwr_w, LARCH_VOID_FTYPE_USI_USI, default), + DIRECT_NO_TARGET_BUILTIN (iocsrwr_d, LARCH_VOID_FTYPE_UDI_USI, default), ++ ++ DIRECT_BUILTIN (cpucfg, LARCH_USI_FTYPE_USI, default), ++ DIRECT_NO_TARGET_BUILTIN (asrtle_d, LARCH_VOID_FTYPE_DI_DI, default), ++ DIRECT_NO_TARGET_BUILTIN (asrtgt_d, LARCH_VOID_FTYPE_DI_DI, default), ++ DIRECT_NO_TARGET_BUILTIN (syscall, LARCH_VOID_FTYPE_USI, default), ++ DIRECT_NO_TARGET_BUILTIN (break, LARCH_VOID_FTYPE_USI, default), +}; + -+/* Index I is the function declaration for loongarch_builtins[I], or null if the -+ function isn't defined on this target. */ -+static GTY(()) tree loongarch_builtin_decls[ARRAY_SIZE (loongarch_builtins)]; ++/* Index I is the function declaration for loongarch_builtins[I], or null if ++ the function isn't defined on this target. */ ++static GTY (()) tree loongarch_builtin_decls[ARRAY_SIZE (loongarch_builtins)]; +/* Get the index I of the function declaration for loongarch_builtin_decls[I] + using the instruction code or return null if not defined for the target. */ -+static GTY(()) int loongarch_get_builtin_decl_index[NUM_INSN_CODES]; -+ -+/* Return a type for 'const volatile void *'. */ -+ -+static tree -+loongarch_build_cvpointer_type (void) -+{ -+ static tree cache; -+ -+ if (cache == NULL_TREE) -+ cache = build_pointer_type (build_qualified_type -+ (void_type_node, -+ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)); -+ return cache; -+} ++static GTY (()) int loongarch_get_builtin_decl_index[NUM_INSN_CODES]; + +/* Source-level argument types. */ +#define LARCH_ATYPE_VOID void_type_node +#define LARCH_ATYPE_INT integer_type_node +#define LARCH_ATYPE_POINTER ptr_type_node -+#define LARCH_ATYPE_CVPOINTER loongarch_build_cvpointer_type () + +/* Standard mode-based argument types. */ +#define LARCH_ATYPE_QI intQI_type_node @@ -2163,8 +2207,7 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + +/* LARCH_FTYPE_ATYPESN takes N LARCH_FTYPES-like type codes and lists + their associated LARCH_ATYPEs. */ -+#define LARCH_FTYPE_ATYPES1(A, B) \ -+ LARCH_ATYPE_##A, LARCH_ATYPE_##B ++#define LARCH_FTYPE_ATYPES1(A, B) LARCH_ATYPE_##A, LARCH_ATYPE_##B + +#define LARCH_FTYPE_ATYPES2(A, B, C) \ + LARCH_ATYPE_##A, LARCH_ATYPE_##B, LARCH_ATYPE_##C @@ -2186,11 +2229,10 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + if (types[(int) type] == NULL_TREE) + switch (type) + { -+#define DEF_LARCH_FTYPE(NUM, ARGS) \ -+ case LARCH_FTYPE_NAME##NUM ARGS: \ -+ types[(int) type] \ -+ = build_function_type_list (LARCH_FTYPE_ATYPES##NUM ARGS, \ -+ NULL_TREE); \ ++#define DEF_LARCH_FTYPE(NUM, ARGS) \ ++ case LARCH_FTYPE_NAME##NUM ARGS: \ ++ types[(int) type] \ ++ = build_function_type_list (LARCH_FTYPE_ATYPES##NUM ARGS, NULL_TREE); \ + break; +#include "config/loongarch/loongarch-ftypes.def" +#undef DEF_LARCH_FTYPE @@ -2208,6 +2250,7 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc +{ + const struct loongarch_builtin_description *d; + unsigned int i; ++ tree type; + + /* Iterate through all of the bdesc arrays, initializing all of the + builtin functions. */ @@ -2216,10 +2259,10 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + d = &loongarch_builtins[i]; + if (d->avail ()) + { ++ type = loongarch_build_function_type (d->function_type); + loongarch_builtin_decls[i] -+ = add_builtin_function (d->name, -+ loongarch_build_function_type (d->function_type), -+ i, BUILT_IN_MD, NULL, NULL); ++ = add_builtin_function (d->name, type, i, BUILT_IN_MD, NULL, ++ NULL); + loongarch_get_builtin_decl_index[d->icode] = i; + } + } @@ -2240,7 +2283,7 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + +static void +loongarch_prepare_builtin_arg (struct expand_operand *op, tree exp, -+ unsigned int argno) ++ unsigned int argno) +{ + tree arg; + rtx value; @@ -2259,48 +2302,13 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + +static rtx +loongarch_expand_builtin_insn (enum insn_code icode, unsigned int nops, -+ struct expand_operand *ops, bool has_target_p) -+{ -+ int error_opno = 0, rangelo = 0, rangehi =0 ; -+ -+ switch(icode){ -+ case CODE_FOR_csrrd: -+ case CODE_FOR_dcsrrd: -+ case CODE_FOR_csrwr: -+ case CODE_FOR_dcsrwr: -+ case CODE_FOR_csrxchg: -+ case CODE_FOR_dcsrxchg: -+ case CODE_FOR_iocsrrd_b: -+ case CODE_FOR_iocsrrd_h: -+ case CODE_FOR_iocsrrd_w: -+ case CODE_FOR_iocsrrd_d: -+ case CODE_FOR_iocsrwr_b: -+ case CODE_FOR_iocsrwr_h: -+ case CODE_FOR_iocsrwr_w: -+ case CODE_FOR_iocsrwr_d: -+ if (!maybe_expand_insn (icode, nops, ops)) -+ { -+ error ("invalid argument to built-in function"); -+ return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx; -+ } -+ emit_barrier(); -+ break; -+ default: -+ break; -+ } -+ -+ if (error_opno != 0) -+ { -+ error ("argument %d to the built-in must be a constant" -+ " in range %d to %d", error_opno, rangelo, rangehi); -+ return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx; -+ } -+ else if (!maybe_expand_insn (icode, nops, ops)) -+ { -+ error ("invalid argument to built-in function"); -+ return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx; -+ } -+ ++ struct expand_operand *ops, bool has_target_p) ++{ ++ if (!maybe_expand_insn (icode, nops, ops)) ++ { ++ error ("invalid argument to built-in function"); ++ return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx; ++ } + return has_target_p ? ops[0].value : const0_rtx; +} + @@ -2311,7 +2319,7 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + +static rtx +loongarch_expand_builtin_direct (enum insn_code icode, rtx target, tree exp, -+ bool has_target_p) ++ bool has_target_p) +{ + struct expand_operand ops[MAX_RECOG_OPERANDS]; + int opno, argno; @@ -2334,14 +2342,15 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + +rtx +loongarch_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, -+ machine_mode mode, int ignore) ++ machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) +{ + tree fndecl; + unsigned int fcode, avail; + const struct loongarch_builtin_description *d; + + fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); -+ fcode = DECL_FUNCTION_CODE (fndecl); ++ fcode = DECL_MD_FUNCTION_CODE (fndecl); + gcc_assert (fcode < ARRAY_SIZE (loongarch_builtins)); + d = &loongarch_builtins[fcode]; + avail = d->avail (); @@ -2353,7 +2362,6 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + + case LARCH_BUILTIN_DIRECT_NO_TARGET: + return loongarch_expand_builtin_direct (d->icode, target, exp, false); -+ + } + gcc_unreachable (); +} @@ -2372,32 +2380,33 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc + tree get_fcsr = loongarch_builtin_decls[LARCH_MOVFCSR2GR]; + tree set_fcsr = loongarch_builtin_decls[LARCH_MOVGR2FCSR]; + tree get_fcsr_hold_call = build_call_expr (get_fcsr, 1, const0); -+ tree hold_assign_orig = build2 (MODIFY_EXPR, LARCH_ATYPE_USI, -+ fcsr_orig_var, get_fcsr_hold_call); ++ tree hold_assign_orig = build4 (TARGET_EXPR, LARCH_ATYPE_USI, ++ fcsr_orig_var, get_fcsr_hold_call, ++ NULL, NULL); + tree hold_mod_val = build2 (BIT_AND_EXPR, LARCH_ATYPE_USI, fcsr_orig_var, + build_int_cst (LARCH_ATYPE_USI, 0xffe0ffe0)); -+ tree hold_assign_mod = build2 (MODIFY_EXPR, LARCH_ATYPE_USI, -+ fcsr_mod_var, hold_mod_val); -+ tree set_fcsr_hold_call = build_call_expr (set_fcsr, 2, const0, fcsr_mod_var); -+ tree hold_all = build2 (COMPOUND_EXPR, LARCH_ATYPE_USI, -+ hold_assign_orig, hold_assign_mod); -+ *hold = build2 (COMPOUND_EXPR, void_type_node, hold_all, -+ set_fcsr_hold_call); ++ tree hold_assign_mod = build4 (TARGET_EXPR, LARCH_ATYPE_USI, ++ fcsr_mod_var, hold_mod_val, NULL, NULL); ++ tree set_fcsr_hold_call = build_call_expr (set_fcsr, 2, const0, ++ fcsr_mod_var); ++ tree hold_all = build2 (COMPOUND_EXPR, LARCH_ATYPE_USI, hold_assign_orig, ++ hold_assign_mod); ++ *hold = build2 (COMPOUND_EXPR, void_type_node, hold_all, set_fcsr_hold_call); + + *clear = build_call_expr (set_fcsr, 2, const0, fcsr_mod_var); + + tree get_fcsr_update_call = build_call_expr (get_fcsr, 1, const0); -+ *update = build2 (MODIFY_EXPR, LARCH_ATYPE_USI, -+ exceptions_var, get_fcsr_update_call); -+ tree set_fcsr_update_call = build_call_expr (set_fcsr, 2, const0, fcsr_orig_var); ++ *update = build4 (TARGET_EXPR, LARCH_ATYPE_USI, exceptions_var, ++ get_fcsr_update_call, NULL, NULL); ++ tree set_fcsr_update_call = build_call_expr (set_fcsr, 2, const0, ++ fcsr_orig_var); + *update = build2 (COMPOUND_EXPR, void_type_node, *update, + set_fcsr_update_call); + tree atomic_feraiseexcept + = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT); -+ tree int_exceptions_var = fold_convert (integer_type_node, -+ exceptions_var); -+ tree atomic_feraiseexcept_call = build_call_expr (atomic_feraiseexcept, -+ 1, int_exceptions_var); ++ tree int_exceptions_var = fold_convert (integer_type_node, exceptions_var); ++ tree atomic_feraiseexcept_call = build_call_expr (atomic_feraiseexcept, 1, ++ int_exceptions_var); + *update = build2 (COMPOUND_EXPR, void_type_node, *update, + atomic_feraiseexcept_call); +} @@ -2409,17 +2418,15 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch-builtins.c gcc-10.3.0/gc +{ + return ptr_type_node; +} -+ -diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch.c gcc-10.3.0/gcc/config/loongarch/loongarch.c ---- gcc-10.3.0.org/gcc/config/loongarch/loongarch.c 1970-01-01 08:00:00.000000000 +0800 -+++ gcc-10.3.0/gcc/config/loongarch/loongarch.c 2022-03-23 17:40:29.347280120 +0800 -@@ -0,0 +1,9636 @@ -+/* Subroutines used for LARCH code generation. -+ Copyright (C) 1989-2018 Free Software Foundation, Inc. -+ Contributed by A. Lichnewsky, lich@inria.inria.fr. -+ Changes by Michael Meissner, meissner@osf.org. -+ 64-bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and -+ Brendan Eich, brendan@microunity.com. +diff --git a/gcc/config/loongarch/loongarch-c.c b/gcc/config/loongarch/loongarch-c.c +new file mode 100644 +index 000000000..d6e3e19f0 +--- /dev/null ++++ b/gcc/config/loongarch/loongarch-c.c +@@ -0,0 +1,109 @@ ++/* LoongArch-specific code for C family languages. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. ++ Contributed by Loongson Ltd. + +This file is part of GCC. + @@ -2442,8253 +2449,8045 @@ diff -uNr gcc-10.3.0.org/gcc/config/loongarch/loongarch.c gcc-10.3.0/gcc/config/ +#include "config.h" +#include "system.h" +#include "coretypes.h" -+#include "backend.h" -+#include "target.h" -+#include "rtl.h" -+#include "tree.h" -+#include "memmodel.h" -+#include "gimple.h" -+#include "cfghooks.h" -+#include "df.h" -+#include "tm_p.h" -+#include "stringpool.h" -+#include "attribs.h" -+#include "optabs.h" -+#include "regs.h" -+#include "emit-rtl.h" -+#include "recog.h" -+#include "cgraph.h" -+#include "diagnostic.h" -+#include "insn-attr.h" -+#include "output.h" -+#include "alias.h" -+#include "fold-const.h" -+#include "varasm.h" -+#include "stor-layout.h" -+#include "calls.h" -+#include "explow.h" -+#include "expr.h" -+#include "libfuncs.h" -+#include "reload.h" -+#include "common/common-target.h" -+#include "langhooks.h" -+#include "cfgrtl.h" -+#include "cfganal.h" -+#include "sched-int.h" -+#include "gimplify.h" -+#include "target-globals.h" -+#include "tree-pass.h" -+#include "context.h" -+#include "builtins.h" -+#include "rtl-iter.h" ++#include "tm.h" ++#include "c-family/c-common.h" ++#include "cpplib.h" + -+/* This file should be included last. */ -+#include "target-def.h" ++#define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM) ++#define builtin_define(TXT) cpp_define (pfile, TXT) ++#define builtin_assert(TXT) cpp_assert (pfile, TXT) + -+/* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */ -+#define UNSPEC_ADDRESS_P(X) \ -+ (GET_CODE (X) == UNSPEC \ -+ && XINT (X, 1) >= UNSPEC_ADDRESS_FIRST \ -+ && XINT (X, 1) < UNSPEC_ADDRESS_FIRST + NUM_SYMBOL_TYPES) ++/* Define preprocessor macros for the -march and -mtune options. ++ PREFIX is either _LOONGARCH_ARCH or _LOONGARCH_TUNE, INFO is ++ the selected processor. If INFO's canonical name is "foo", ++ define PREFIX to be "foo", and define an additional macro ++ PREFIX_FOO. */ ++#define LARCH_CPP_SET_PROCESSOR(PREFIX, CPU_TYPE) \ ++ do \ ++ { \ ++ char *macro, *p; \ ++ int cpu_type = (CPU_TYPE); \ ++ \ ++ macro = concat ((PREFIX), "_", \ ++ loongarch_cpu_strings[cpu_type], NULL); \ ++ for (p = macro; *p != 0; p++) \ ++ *p = TOUPPER (*p); \ ++ \ ++ builtin_define (macro); \ ++ builtin_define_with_value ((PREFIX), \ ++ loongarch_cpu_strings[cpu_type], 1); \ ++ free (macro); \ ++ } \ ++ while (0) + -+/* Extract the symbol or label from UNSPEC wrapper X. */ -+#define UNSPEC_ADDRESS(X) \ -+ XVECEXP (X, 0, 0) ++void ++loongarch_cpu_cpp_builtins (cpp_reader *pfile) ++{ ++ builtin_assert ("machine=loongarch"); ++ builtin_assert ("cpu=loongarch"); ++ builtin_define ("__loongarch__"); + -+/* Extract the symbol type from UNSPEC wrapper X. */ -+#define UNSPEC_ADDRESS_TYPE(X) \ -+ ((enum loongarch_symbol_type) (XINT (X, 1) - UNSPEC_ADDRESS_FIRST)) ++ LARCH_CPP_SET_PROCESSOR ("_LOONGARCH_ARCH", LARCH_ACTUAL_ARCH); ++ LARCH_CPP_SET_PROCESSOR ("_LOONGARCH_TUNE", LARCH_ACTUAL_TUNE); + -+/* The maximum distance between the top of the stack frame and the -+ value $sp has when we save and restore registers. -+*/ -+#define LARCH_MAX_FIRST_STACK_STEP 0x7f0 ++ /* Base architecture / ABI. */ ++ if (TARGET_64BIT) ++ { ++ builtin_define ("__loongarch_grlen=64"); ++ builtin_define ("__loongarch64"); ++ } + -+/* True if INSN is a loongarch.md pattern or asm statement. */ -+/* ??? This test exists through the compiler, perhaps it should be -+ moved to rtl.h. */ -+#define USEFUL_INSN_P(INSN) \ -+ (NONDEBUG_INSN_P (INSN) \ -+ && GET_CODE (PATTERN (INSN)) != USE \ -+ && GET_CODE (PATTERN (INSN)) != CLOBBER) ++ if (TARGET_ABI_LP64) ++ { ++ builtin_define ("_ABILP64=3"); ++ builtin_define ("_LOONGARCH_SIM=_ABILP64"); ++ builtin_define ("__loongarch_lp64"); ++ } + -+/* If INSN is a delayed branch sequence, return the first instruction -+ in the sequence, otherwise return INSN itself. */ -+#define SEQ_BEGIN(INSN) \ -+ (INSN_P (INSN) && GET_CODE (PATTERN (INSN)) == SEQUENCE \ -+ ? as_a (XVECEXP (PATTERN (INSN), 0, 0)) \ -+ : (INSN)) -+ -+/* Likewise for the last instruction in a delayed branch sequence. */ -+#define SEQ_END(INSN) \ -+ (INSN_P (INSN) && GET_CODE (PATTERN (INSN)) == SEQUENCE \ -+ ? as_a (XVECEXP (PATTERN (INSN), \ -+ 0, \ -+ XVECLEN (PATTERN (INSN), 0) - 1)) \ -+ : (INSN)) -+ -+/* Execute the following loop body with SUBINSN set to each instruction -+ between SEQ_BEGIN (INSN) and SEQ_END (INSN) inclusive. */ -+#define FOR_EACH_SUBINSN(SUBINSN, INSN) \ -+ for ((SUBINSN) = SEQ_BEGIN (INSN); \ -+ (SUBINSN) != NEXT_INSN (SEQ_END (INSN)); \ -+ (SUBINSN) = NEXT_INSN (SUBINSN)) ++ /* These defines reflect the ABI in use, not whether the ++ FPU is directly accessible. */ ++ if (TARGET_DOUBLE_FLOAT_ABI) ++ builtin_define ("__loongarch_double_float=1"); ++ else if (TARGET_SINGLE_FLOAT_ABI) ++ builtin_define ("__loongarch_single_float=1"); + -+/* True if bit BIT is set in VALUE. */ -+#define BITSET_P(VALUE, BIT) (((VALUE) & (1 << (BIT))) != 0) ++ if (TARGET_DOUBLE_FLOAT_ABI || TARGET_SINGLE_FLOAT_ABI) ++ builtin_define ("__loongarch_hard_float=1"); ++ else ++ builtin_define ("__loongarch_soft_float=1"); + -+/* Classifies an address. + -+ ADDRESS_REG -+ A natural register + offset address. The register satisfies -+ loongarch_valid_base_register_p and the offset is a const_arith_operand. ++ /* ISA Extensions. */ ++ if (TARGET_DOUBLE_FLOAT) ++ builtin_define ("__loongarch_frlen=64"); ++ else if (TARGET_SINGLE_FLOAT) ++ builtin_define ("__loongarch_frlen=32"); ++ else ++ builtin_define ("__loongarch_frlen=0"); + -+ ADDRESS_CONST_INT -+ A signed 16-bit constant address. ++ /* Native Data Sizes. */ ++ builtin_define_with_int_value ("_LOONGARCH_SZINT", INT_TYPE_SIZE); ++ builtin_define_with_int_value ("_LOONGARCH_SZLONG", LONG_TYPE_SIZE); ++ builtin_define_with_int_value ("_LOONGARCH_SZPTR", POINTER_SIZE); ++ builtin_define_with_int_value ("_LOONGARCH_FPSET", 32); ++ builtin_define_with_int_value ("_LOONGARCH_SPFPSET", 32); + -+ ADDRESS_SYMBOLIC: -+ A constant symbolic address. */ -+enum loongarch_address_type { -+ ADDRESS_REG, -+ ADDRESS_CONST_INT, -+ ADDRESS_SYMBOLIC -+}; ++} +diff --git a/gcc/config/loongarch/loongarch-cpu.c b/gcc/config/loongarch/loongarch-cpu.c +new file mode 100644 +index 000000000..a886dd932 +--- /dev/null ++++ b/gcc/config/loongarch/loongarch-cpu.c +@@ -0,0 +1,206 @@ ++/* Definitions for LoongArch CPU properties. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. ++ Contributed by Loongson Ltd. + -+/* A class used to control a comdat-style stub that we output in each -+ translation unit that needs it. */ -+class loongarch_one_only_stub { -+public: -+ virtual ~loongarch_one_only_stub () {} ++This file is part of GCC. + -+ /* Return the name of the stub. */ -+ virtual const char *get_name () = 0; ++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. + -+ /* Output the body of the function to asm_out_file. */ -+ virtual void output_body () = 0; -+}; ++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. + -+/* Tuning information that is automatically derived from other sources -+ (such as the scheduler). */ -+static struct { -+ /* The architecture and tuning settings that this structure describes. */ -+ enum processor arch; -+ enum processor tune; ++You should have received a copy of the GNU General Public License ++along with GCC; see the file COPYING3. If not see ++. */ + -+ /* True if the structure has been initialized. */ -+ bool initialized_p; ++#define IN_TARGET_CODE 1 + -+} loongarch_tuning_info; ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "diagnostic-core.h" + -+/* Information about an address described by loongarch_address_type. ++#include "loongarch-opts.h" ++#include "loongarch-cpu.h" ++#include "loongarch-str.h" + -+ ADDRESS_CONST_INT -+ No fields are used. ++/* Native CPU detection with "cpucfg" */ ++#define N_CPUCFG_WORDS 0x15 ++static uint32_t cpucfg_cache[N_CPUCFG_WORDS] = { 0 }; ++static const int cpucfg_useful_idx[] = {0, 1, 2, 16, 17, 18, 19}; + -+ ADDRESS_REG -+ REG is the base register and OFFSET is the constant offset. ++static uint32_t ++read_cpucfg_word (int wordno) ++{ ++ /* To make cross-compiler shut up. */ ++ (void) wordno; ++ uint32_t ret = 0; + -+ ADDRESS_SYMBOLIC -+ SYMBOL_TYPE is the type of symbol that the address references. */ -+struct loongarch_address_info { -+ enum loongarch_address_type type; -+ rtx reg; -+ rtx offset; -+ enum loongarch_symbol_type symbol_type; -+}; ++ #ifdef __loongarch__ ++ __asm__ __volatile__ ("cpucfg %0,%1\n\t" ++ :"=r"(ret) ++ :"r"(wordno) ++ :); ++ #endif + -+/* Method to load immediate number fields. ++ return ret; ++} + -+ METHOD_NORMAL: -+ load immediate number 0-31 bit ++void ++cache_cpucfg (void) ++{ ++ for (unsigned int i = 0; i < sizeof (cpucfg_useful_idx) / sizeof (int); i++) ++ { ++ cpucfg_cache[cpucfg_useful_idx[i]] ++ = read_cpucfg_word (cpucfg_useful_idx[i]); ++ } ++} + -+ METHOD_LU32I: -+ load imm 32-51 bit ++uint32_t ++get_native_prid (void) ++{ ++ /* Fill loongarch_cpu_default_config[CPU_NATIVE] with cpucfg data, ++ see "Loongson Architecture Reference Manual" ++ (Volume 1, Section 2.2.10.5) */ ++ return cpucfg_cache[0]; ++} + -+ METHOD_LU52I: -+ load imm 52-63 bit ++const char* ++get_native_prid_str (void) ++{ ++ static char prid_str[9]; ++ sprintf (prid_str, "%08x", cpucfg_cache[0]); ++ return (const char*) prid_str; ++} + -+ METHOD_INSV: -+ imm 0xfff00000fffffxxx -+ */ -+enum loongarch_load_imm_method { -+ METHOD_NORMAL, -+ METHOD_LU32I, -+ METHOD_LU52I, -+ METHOD_INSV -+}; ++/* Fill property tables for CPU_NATIVE. */ ++unsigned int ++fill_native_cpu_config (int p_arch_native, int p_tune_native) ++{ ++ int ret_cpu_type; + -+/* One stage in a constant building sequence. These sequences have -+ the form: ++ /* Nothing needs to be done unless "-march/tune=native" ++ is given or implied. */ ++ if (!(p_arch_native || p_tune_native)) ++ return CPU_NATIVE; + -+ A = VALUE[0] -+ A = A CODE[1] VALUE[1] -+ A = A CODE[2] VALUE[2] -+ ... ++ /* Fill cpucfg_cache with the "cpucfg" instruction. */ ++ cache_cpucfg (); + -+ where A is an accumulator, each CODE[i] is a binary rtl operation -+ and each VALUE[i] is a constant integer. CODE[0] is undefined. */ -+struct loongarch_integer_op { -+ enum rtx_code code; -+ unsigned HOST_WIDE_INT value; -+ enum loongarch_load_imm_method method; -+}; + -+/* The largest number of operations needed to load an integer constant. -+ The worst accepted case for 64-bit constants is LUI,ORI,SLL,ORI,SLL,ORI. -+ When the lowest bit is clear, we can try, but reject a sequence with -+ an extra SLL at the end. */ -+#define LARCH_MAX_INTEGER_OPS 9 ++ /* Fill: loongarch_cpu_default_isa[CPU_NATIVE].base ++ With: base architecture (ARCH) ++ At: cpucfg_words[1][1:0] */ + -+/* Costs of various operations on the different architectures. */ ++ #define NATIVE_BASE_ISA (loongarch_cpu_default_isa[CPU_NATIVE].base) ++ switch (cpucfg_cache[1] & 0x3) ++ { ++ case 0x02: ++ NATIVE_BASE_ISA = ISA_BASE_LA64V100; ++ break; + -+struct loongarch_rtx_cost_data -+{ -+ unsigned short fp_add; -+ unsigned short fp_mult_sf; -+ unsigned short fp_mult_df; -+ unsigned short fp_div_sf; -+ unsigned short fp_div_df; -+ unsigned short int_mult_si; -+ unsigned short int_mult_di; -+ unsigned short int_div_si; -+ unsigned short int_div_di; -+ unsigned short branch_cost; -+ unsigned short memory_latency; -+}; ++ default: ++ if (p_arch_native) ++ fatal_error (UNKNOWN_LOCATION, ++ "unknown base architecture %<0x%x%>, %qs failed", ++ (unsigned int) (cpucfg_cache[1] & 0x3), ++ "-m" OPTSTR_ARCH "=" STR_CPU_NATIVE); ++ } + -+/* Global variables for machine-dependent things. */ ++ /* Fill: loongarch_cpu_default_isa[CPU_NATIVE].fpu ++ With: FPU type (FP, FP_SP, FP_DP) ++ At: cpucfg_words[2][2:0] */ + -+/* The -G setting, or the configuration's default small-data limit if -+ no -G option is given. */ -+static unsigned int loongarch_small_data_threshold; ++ #define NATIVE_FPU (loongarch_cpu_default_isa[CPU_NATIVE].fpu) ++ switch (cpucfg_cache[2] & 0x7) ++ { ++ case 0x07: ++ NATIVE_FPU = ISA_EXT_FPU64; ++ break; + -+/* The number of file directives written by loongarch_output_filename. */ -+int num_source_filenames; ++ case 0x03: ++ NATIVE_FPU = ISA_EXT_FPU32; ++ break; + -+/* The name that appeared in the last .file directive written by -+ loongarch_output_filename, or "" if loongarch_output_filename hasn't -+ written anything yet. */ -+const char *current_function_file = ""; ++ case 0x00: ++ NATIVE_FPU = ISA_EXT_NOFPU; ++ break; + -+/* Arrays that map GCC register numbers to debugger register numbers. */ -+int loongarch_dbx_regno[FIRST_PSEUDO_REGISTER]; -+int loongarch_dwarf_regno[FIRST_PSEUDO_REGISTER]; ++ default: ++ if (p_arch_native) ++ fatal_error (UNKNOWN_LOCATION, ++ "unknown FPU type %<0x%x%>, %qs failed", ++ (unsigned int) (cpucfg_cache[2] & 0x7), ++ "-m" OPTSTR_ARCH "=" STR_CPU_NATIVE); ++ } + -+/* Information about the current function's epilogue, used only while -+ expanding it. */ -+static struct { -+ /* A list of queued REG_CFA_RESTORE notes. */ -+ rtx cfa_restores; ++ /* Fill: loongarch_cpu_cache[CPU_NATIVE] ++ With: cache size info ++ At: cpucfg_words[16:20][31:0] */ + -+ /* The CFA is currently defined as CFA_REG + CFA_OFFSET. */ -+ rtx cfa_reg; -+ HOST_WIDE_INT cfa_offset; ++ int l1d_present = 0, l1u_present = 0; ++ int l2d_present = 0; ++ uint32_t l1_szword, l2_szword; + -+ /* The offset of the CFA from the stack pointer while restoring -+ registers. */ -+ HOST_WIDE_INT cfa_restore_sp_offset; -+} loongarch_epilogue; ++ l1u_present |= cpucfg_cache[16] & 3; /* bit[1:0]: unified l1 cache */ ++ l1d_present |= cpucfg_cache[16] & 4; /* bit[2:2]: l1 dcache */ ++ l1_szword = l1d_present ? 18 : (l1u_present ? 17 : 0); ++ l1_szword = l1_szword ? cpucfg_cache[l1_szword]: 0; + ++ l2d_present |= cpucfg_cache[16] & 24; /* bit[4:3]: unified l2 cache */ ++ l2d_present |= cpucfg_cache[16] & 128; /* bit[7:7]: l2 dcache */ ++ l2_szword = l2d_present ? cpucfg_cache[19]: 0; + -+/* The current instruction-set architecture. */ -+enum processor loongarch_arch; -+const struct loongarch_cpu_info *loongarch_arch_info; ++ loongarch_cpu_cache[CPU_NATIVE].l1d_line_size ++ = 1 << ((l1_szword & 0x7f000000) >> 24); /* bit[30:24]: log2(linesize) */ + -+/* The processor that we should tune the code for. */ -+enum processor loongarch_tune; -+const struct loongarch_cpu_info *loongarch_tune_info; ++ loongarch_cpu_cache[CPU_NATIVE].l1d_size ++ = (1 << ((l1_szword & 0x00ff0000) >> 16)) /* bit[23:16]: log2(idx) */ ++ * ((l1_szword & 0x0000ffff) + 1) /* bit[15:0]: sets - 1 */ ++ * (1 << ((l1_szword & 0x7f000000) >> 24)) /* bit[30:24]: log2(linesize) */ ++ >> 10; /* in kilobytes */ + -+/* The ISA level associated with loongarch_arch. */ -+int loongarch_isa; ++ loongarch_cpu_cache[CPU_NATIVE].l2d_size ++ = (1 << ((l2_szword & 0x00ff0000) >> 16)) /* bit[23:16]: log2(idx) */ ++ * ((l2_szword & 0x0000ffff) + 1) /* bit[15:0]: sets - 1 */ ++ * (1 << ((l2_szword & 0x7f000000) >> 24)) /* bit[30:24]: log2(linesize) */ ++ >> 10; /* in kilobytes */ + -+/* The ISA revision level. */ -+int loongarch_isa_rev; ++ /* Fill: ret_cpu_type ++ With: processor ID (PRID) ++ At: cpucfg_words[0][31:0] */ + -+/* The architecture selected by -loongarchN, or null if -loongarchN wasn't used. */ -+static const struct loongarch_cpu_info *loongarch_isa_option_info; ++ switch (cpucfg_cache[0] & 0x00ffff00) ++ { ++ case 0x0014c000: /* LA464 */ ++ ret_cpu_type = CPU_LA464; ++ break; + -+/* Which cost information to use. */ -+static const struct loongarch_rtx_cost_data *loongarch_cost; ++ default: ++ /* Unknown PRID. This is generally harmless as long as ++ the properties above can be obtained via "cpucfg". */ ++ if (p_tune_native) ++ inform (UNKNOWN_LOCATION, "unknown processor ID %<0x%x%>, " ++ "some tuning parameters will fall back to default", ++ cpucfg_cache[0]); ++ break; ++ } + -+/* The ambient target flags. */ -+static int loongarch_base_target_flags; ++ /* Properties that cannot be looked up directly using cpucfg. */ ++ loongarch_cpu_issue_rate[CPU_NATIVE] ++ = loongarch_cpu_issue_rate[ret_cpu_type]; + -+/* The default compression mode. */ -+unsigned int loongarch_base_compression_flags; ++ loongarch_cpu_multipass_dfa_lookahead[CPU_NATIVE] ++ = loongarch_cpu_multipass_dfa_lookahead[ret_cpu_type]; + -+/* The ambient values of other global variables. */ -+static int loongarch_base_schedule_insns; /* flag_schedule_insns */ -+static int loongarch_base_reorder_blocks_and_partition; /* flag_reorder... */ -+static int loongarch_base_move_loop_invariants; /* flag_move_loop_invariants */ -+static const char *loongarch_base_align_loops; /* flag_align_loops */ -+static const char *loongarch_base_align_jumps; /* flag_align_jumps */ -+static const char *loongarch_base_align_functions; /* str_align_functions */ ++ loongarch_cpu_rtx_cost_data[CPU_NATIVE] ++ = loongarch_cpu_rtx_cost_data[ret_cpu_type]; + -+/* Index [M][R] is true if register R is allowed to hold a value of mode M. */ -+static bool loongarch_hard_regno_mode_ok_p[MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER]; ++ return ret_cpu_type; ++} +diff --git a/gcc/config/loongarch/loongarch-cpu.h b/gcc/config/loongarch/loongarch-cpu.h +new file mode 100644 +index 000000000..93d656f70 +--- /dev/null ++++ b/gcc/config/loongarch/loongarch-cpu.h +@@ -0,0 +1,30 @@ ++/* Definitions for loongarch native cpu property detection routines. ++ Copyright (C) 2020-2021 Free Software Foundation, Inc. + -+/* Index C is true if character C is a valid PRINT_OPERAND punctation -+ character. */ -+static bool loongarch_print_operand_punct[256]; ++This file is part of GCC. + -+static GTY (()) int loongarch_output_filename_first_time = 1; ++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. + -+/* loongarch_use_pcrel_pool_p[X] is true if symbols of type X should be -+ forced into a PC-relative constant pool. */ -+bool loongarch_use_pcrel_pool_p[NUM_SYMBOL_TYPES]; ++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. + -+/* Cached value of can_issue_more. This is cached in loongarch_variable_issue hook -+ and returned from loongarch_sched_reorder2. */ -+static int cached_can_issue_more; ++You should have received a copy of the GNU General Public License ++along with GCC; see the file COPYING3. If not see ++. */ + -+/* Index R is the smallest register class that contains register R. */ -+const enum reg_class loongarch_regno_to_class[FIRST_PSEUDO_REGISTER] = { -+ GR_REGS, GR_REGS, GR_REGS, GR_REGS, -+ JALR_REGS, JALR_REGS, JALR_REGS, JALR_REGS, -+ JALR_REGS, JALR_REGS, JALR_REGS, JALR_REGS, -+ SIBCALL_REGS, SIBCALL_REGS, SIBCALL_REGS, SIBCALL_REGS, -+ SIBCALL_REGS, SIBCALL_REGS, SIBCALL_REGS, SIBCALL_REGS, -+ SIBCALL_REGS, GR_REGS, GR_REGS, JALR_REGS, -+ JALR_REGS, JALR_REGS, JALR_REGS, JALR_REGS, -+ JALR_REGS, JALR_REGS, JALR_REGS, JALR_REGS, -+ -+ FP_REGS, FP_REGS, FP_REGS, FP_REGS, -+ FP_REGS, FP_REGS, FP_REGS, FP_REGS, -+ FP_REGS, FP_REGS, FP_REGS, FP_REGS, -+ FP_REGS, FP_REGS, FP_REGS, FP_REGS, -+ FP_REGS, FP_REGS, FP_REGS, FP_REGS, -+ FP_REGS, FP_REGS, FP_REGS, FP_REGS, -+ FP_REGS, FP_REGS, FP_REGS, FP_REGS, -+ FP_REGS, FP_REGS, FP_REGS, FP_REGS, -+ ST_REGS, ST_REGS, ST_REGS, ST_REGS, -+ ST_REGS, ST_REGS, ST_REGS, ST_REGS, -+ FRAME_REGS, FRAME_REGS -+}; ++#ifndef LOONGARCH_CPU_H ++#define LOONGARCH_CPU_H + -+static tree loongarch_handle_interrupt_attr (tree *, tree, tree, int, bool *); -+static tree loongarch_handle_use_shadow_register_set_attr (tree *, tree, tree, int, -+ bool *); ++#include "system.h" + -+/* The value of TARGET_ATTRIBUTE_TABLE. */ -+static const struct attribute_spec loongarch_attribute_table[] = { -+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, -+ affects_type_identity, handler, exclude } */ -+ { "long_call", 0, 0, false, true, true, false, NULL, NULL }, -+ { "short_call", 0, 0, false, true, true, false, NULL, NULL }, -+ { "far", 0, 0, false, true, true, false, NULL, NULL }, -+ { "near", 0, 0, false, true, true, false, NULL, NULL }, -+ { "nocompression", 0, 0, true, false, false, false, NULL, NULL }, -+ /* Allow functions to be specified as interrupt handlers */ -+ { "interrupt", 0, 1, false, true, true, false, loongarch_handle_interrupt_attr, -+ NULL }, -+ { "use_shadow_register_set", 0, 1, false, true, true, false, -+ loongarch_handle_use_shadow_register_set_attr, NULL }, -+ { "keep_interrupts_masked", 0, 0, false, true, true, false, NULL, NULL }, -+ { "use_debug_exception_return", 0, 0, false, true, true, false, NULL, NULL }, -+ { NULL, 0, 0, false, false, false, false, NULL, NULL } -+}; -+ -+/* A table describing all the processors GCC knows about; see -+ loongarch-cpus.def for details. */ -+static const struct loongarch_cpu_info loongarch_cpu_info_table[] = { -+#define LARCH_CPU(NAME, CPU, ISA, FLAGS) \ -+ { NAME, CPU, ISA, FLAGS }, -+#include "loongarch-cpus.def" -+#undef LARCH_CPU ++void cache_cpucfg (void); ++unsigned int fill_native_cpu_config (int p_arch_native, int p_tune_native); ++uint32_t get_native_prid (void); ++const char* get_native_prid_str (void); ++ ++#endif /* LOONGARCH_CPU_H */ +diff --git a/gcc/config/loongarch/loongarch-def.c b/gcc/config/loongarch/loongarch-def.c +new file mode 100644 +index 000000000..cbf995d81 +--- /dev/null ++++ b/gcc/config/loongarch/loongarch-def.c +@@ -0,0 +1,180 @@ ++/* LoongArch static properties. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. ++ Contributed by Loongson Ltd. ++ ++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 ++. */ ++ ++#include "loongarch-def.h" ++#include "loongarch-str.h" ++ ++/* Default RTX cost initializer. */ ++#define COSTS_N_INSNS(N) ((N) * 4) ++#define DEFAULT_COSTS \ ++ .fp_add = COSTS_N_INSNS (1), \ ++ .fp_mult_sf = COSTS_N_INSNS (2), \ ++ .fp_mult_df = COSTS_N_INSNS (4), \ ++ .fp_div_sf = COSTS_N_INSNS (6), \ ++ .fp_div_df = COSTS_N_INSNS (8), \ ++ .int_mult_si = COSTS_N_INSNS (1), \ ++ .int_mult_di = COSTS_N_INSNS (1), \ ++ .int_div_si = COSTS_N_INSNS (4), \ ++ .int_div_di = COSTS_N_INSNS (6), \ ++ .branch_cost = 2, \ ++ .memory_latency = 4 ++ ++/* CPU property tables. */ ++const char* ++loongarch_cpu_strings[N_TUNE_TYPES] = { ++ [CPU_NATIVE] = STR_CPU_NATIVE, ++ [CPU_LOONGARCH64] = STR_CPU_LOONGARCH64, ++ [CPU_LA464] = STR_CPU_LA464, +}; + -+/* Default costs. If these are used for a processor we should look -+ up the actual costs. */ -+#define DEFAULT_COSTS COSTS_N_INSNS (6), /* fp_add */ \ -+ COSTS_N_INSNS (7), /* fp_mult_sf */ \ -+ COSTS_N_INSNS (8), /* fp_mult_df */ \ -+ COSTS_N_INSNS (23), /* fp_div_sf */ \ -+ COSTS_N_INSNS (36), /* fp_div_df */ \ -+ COSTS_N_INSNS (10), /* int_mult_si */ \ -+ COSTS_N_INSNS (10), /* int_mult_di */ \ -+ COSTS_N_INSNS (69), /* int_div_si */ \ -+ COSTS_N_INSNS (69), /* int_div_di */ \ -+ 2, /* branch_cost */ \ -+ 4 /* memory_latency */ -+ -+/* Floating-point costs for processors without an FPU. Just assume that -+ all floating-point libcalls are very expensive. */ -+#define SOFT_FP_COSTS COSTS_N_INSNS (256), /* fp_add */ \ -+ COSTS_N_INSNS (256), /* fp_mult_sf */ \ -+ COSTS_N_INSNS (256), /* fp_mult_df */ \ -+ COSTS_N_INSNS (256), /* fp_div_sf */ \ -+ COSTS_N_INSNS (256) /* fp_div_df */ ++struct loongarch_isa ++loongarch_cpu_default_isa[N_ARCH_TYPES] = { ++ [CPU_LOONGARCH64] = { ++ .base = ISA_BASE_LA64V100, ++ .fpu = ISA_EXT_FPU64, ++ }, ++ [CPU_LA464] = { ++ .base = ISA_BASE_LA64V100, ++ .fpu = ISA_EXT_FPU64, ++ }, ++}; + -+/* Costs to use when optimizing for size. */ -+static const struct loongarch_rtx_cost_data loongarch_rtx_cost_optimize_size = { -+ COSTS_N_INSNS (1), /* fp_add */ -+ COSTS_N_INSNS (1), /* fp_mult_sf */ -+ COSTS_N_INSNS (1), /* fp_mult_df */ -+ COSTS_N_INSNS (1), /* fp_div_sf */ -+ COSTS_N_INSNS (1), /* fp_div_df */ -+ COSTS_N_INSNS (1), /* int_mult_si */ -+ COSTS_N_INSNS (1), /* int_mult_di */ -+ COSTS_N_INSNS (1), /* int_div_si */ -+ COSTS_N_INSNS (1), /* int_div_di */ -+ 2, /* branch_cost */ -+ 4 /* memory_latency */ ++struct loongarch_cache ++loongarch_cpu_cache[N_TUNE_TYPES] = { ++ [CPU_LOONGARCH64] = { ++ .l1d_line_size = 64, ++ .l1d_size = 64, ++ .l2d_size = 256, ++ }, ++ [CPU_LA464] = { ++ .l1d_line_size = 64, ++ .l1d_size = 64, ++ .l2d_size = 256, ++ }, +}; + -+/* Costs to use when optimizing for speed, indexed by processor. */ -+static const struct loongarch_rtx_cost_data -+ loongarch_rtx_cost_data[NUM_PROCESSOR_VALUES] = { -+ { /* loongarch */ -+ DEFAULT_COSTS ++/* The following properties cannot be looked up directly using "cpucfg". ++ So it is necessary to provide a default value for "unknown native" ++ tune targets (i.e. -mtune=native while PRID does not correspond to ++ any known "-mtune" type). */ ++ ++struct loongarch_rtx_cost_data ++loongarch_cpu_rtx_cost_data[N_TUNE_TYPES] = { ++ [CPU_NATIVE] = { ++ DEFAULT_COSTS + }, -+ { /* loongarch64 */ -+ DEFAULT_COSTS ++ [CPU_LOONGARCH64] = { ++ DEFAULT_COSTS ++ }, ++ [CPU_LA464] = { ++ DEFAULT_COSTS + }, -+ { /* gs464v */ -+ DEFAULT_COSTS -+ } +}; + -+/* Information about a single argument. */ -+struct n_loongarch_arg_info { -+ /* True if the argument is at least partially passed on the stack. */ -+ bool stack_p; ++/* RTX costs to use when optimizing for size. */ ++extern const struct loongarch_rtx_cost_data ++loongarch_rtx_cost_optimize_size = { ++ .fp_add = 4, ++ .fp_mult_sf = 4, ++ .fp_mult_df = 4, ++ .fp_div_sf = 4, ++ .fp_div_df = 4, ++ .int_mult_si = 4, ++ .int_mult_di = 4, ++ .int_div_si = 4, ++ .int_div_di = 4, ++ .branch_cost = 2, ++ .memory_latency = 4, ++}; + -+ /* The number of integer registers allocated to this argument. */ -+ unsigned int num_gprs; ++int ++loongarch_cpu_issue_rate[N_TUNE_TYPES] = { ++ [CPU_NATIVE] = 4, ++ [CPU_LOONGARCH64] = 4, ++ [CPU_LA464] = 4, ++}; + -+ /* The offset of the first register used, provided num_gprs is nonzero. -+ If passed entirely on the stack, the value is MAX_ARGS_IN_REGISTERS. */ -+ unsigned int gpr_offset; ++int ++loongarch_cpu_multipass_dfa_lookahead[N_TUNE_TYPES] = { ++ [CPU_NATIVE] = 4, ++ [CPU_LOONGARCH64] = 4, ++ [CPU_LA464] = 4, ++}; + -+ /* The number of floating-point registers allocated to this argument. */ -+ unsigned int num_fprs; ++/* Wiring string definitions from loongarch-str.h to global arrays ++ with standard index values from loongarch-opts.h, so we can ++ print config-related messages and do ABI self-spec filtering ++ from the driver in a self-consistent manner. */ + -+ /* The offset of the first register used, provided num_fprs is nonzero. */ -+ unsigned int fpr_offset; ++const char* ++loongarch_isa_base_strings[N_ISA_BASE_TYPES] = { ++ [ISA_BASE_LA64V100] = STR_ISA_BASE_LA64V100, +}; + -+ -+/* Emit a move from SRC to DEST. Assume that the move expanders can -+ handle all moves if !can_create_pseudo_p (). The distinction is -+ important because, unlike emit_move_insn, the move expanders know -+ how to force Pmode objects into the constant pool even when the -+ constant pool address is not itself legitimate. */ ++const char* ++loongarch_isa_ext_strings[N_ISA_EXT_TYPES] = { ++ [ISA_EXT_FPU64] = STR_ISA_EXT_FPU64, ++ [ISA_EXT_FPU32] = STR_ISA_EXT_FPU32, ++ [ISA_EXT_NOFPU] = STR_ISA_EXT_NOFPU, ++}; + -+rtx -+n_loongarch_emit_move (rtx dest, rtx src) -+{ -+ return (can_create_pseudo_p () -+ ? emit_move_insn (dest, src) -+ : emit_move_insn_1 (dest, src)); -+} ++const char* ++loongarch_abi_base_strings[N_ABI_BASE_TYPES] = { ++ [ABI_BASE_LP64D] = STR_ABI_BASE_LP64D, ++ [ABI_BASE_LP64F] = STR_ABI_BASE_LP64F, ++ [ABI_BASE_LP64S] = STR_ABI_BASE_LP64S, ++}; + -+/* Implement TARGET_FUNCTION_ARG_BOUNDARY. Every parameter gets at -+ least PARM_BOUNDARY bits of alignment, but will be given anything up -+ to PREFERRED_STACK_BOUNDARY bits if the type requires it. */ ++const char* ++loongarch_abi_ext_strings[N_ABI_EXT_TYPES] = { ++ [ABI_EXT_BASE] = STR_ABI_EXT_BASE, ++}; + -+static unsigned int -+n_loongarch_function_arg_boundary (machine_mode mode, const_tree type) -+{ -+ unsigned int alignment; ++const char* ++loongarch_cmodel_strings[] = { ++ [CMODEL_NORMAL] = STR_CMODEL_NORMAL, ++ [CMODEL_TINY] = STR_CMODEL_TINY, ++ [CMODEL_TINY_STATIC] = STR_CMODEL_TS, ++ [CMODEL_MEDIUM] = STR_CMODEL_MEDIUM, ++ [CMODEL_LARGE] = STR_CMODEL_LARGE, ++ [CMODEL_EXTREME] = STR_CMODEL_EXTREME, ++}; + -+ /* Use natural alignment if the type is not aggregate data. */ -+ if (type && !AGGREGATE_TYPE_P (type)) -+ alignment = TYPE_ALIGN (TYPE_MAIN_VARIANT (type)); -+ else -+ alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode); ++const char* ++loongarch_switch_strings[] = { ++ [SW_SOFT_FLOAT] = OPTSTR_SOFT_FLOAT, ++ [SW_SINGLE_FLOAT] = OPTSTR_SINGLE_FLOAT, ++ [SW_DOUBLE_FLOAT] = OPTSTR_DOUBLE_FLOAT, ++}; + -+ return MIN (PREFERRED_STACK_BOUNDARY, MAX (PARM_BOUNDARY, alignment)); -+} + -+/* If MODE represents an argument that can be passed or returned in -+ floating-point registers, return the number of registers, else 0. */ ++/* ABI-related definitions. */ ++const struct loongarch_isa ++abi_minimal_isa[N_ABI_BASE_TYPES][N_ABI_EXT_TYPES] = { ++ [ABI_BASE_LP64D] = { ++ [ABI_EXT_BASE] = {.base = ISA_BASE_LA64V100, .fpu = ISA_EXT_FPU64}, ++ }, ++ [ABI_BASE_LP64F] = { ++ [ABI_EXT_BASE] = {.base = ISA_BASE_LA64V100, .fpu = ISA_EXT_FPU32}, ++ }, ++ [ABI_BASE_LP64S] = { ++ [ABI_EXT_BASE] = {.base = ISA_BASE_LA64V100, .fpu = ISA_EXT_NOFPU}, ++ }, ++}; +diff --git a/gcc/config/loongarch/loongarch-def.h b/gcc/config/loongarch/loongarch-def.h +new file mode 100644 +index 000000000..b5985f070 +--- /dev/null ++++ b/gcc/config/loongarch/loongarch-def.h +@@ -0,0 +1,152 @@ ++/* LoongArch definitions. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. ++ Contributed by Loongson Ltd. + -+static unsigned -+n_loongarch_pass_mode_in_fpr_p (machine_mode mode) -+{ -+ if (GET_MODE_UNIT_SIZE (mode) <= UNITS_PER_FP_ARG) -+ { -+ if (GET_MODE_CLASS (mode) == MODE_FLOAT) -+ return 1; ++This file is part of GCC. + -+ if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) -+ return 2; -+ } ++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. + -+ return 0; -+} ++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. + -+typedef struct { -+ const_tree type; -+ HOST_WIDE_INT offset; -+} n_loongarch_aggregate_field; ++You should have received a copy of the GNU General Public License ++along with GCC; see the file COPYING3. If not see ++. */ + -+/* Identify subfields of aggregates that are candidates for passing in -+ floating-point registers. */ ++/* Definition of standard codes for: ++ - base architecture types (isa_base), ++ - ISA extensions (isa_ext), ++ - base ABI types (abi_base), ++ - ABI extension types (abi_ext). + -+static int -+n_loongarch_flatten_aggregate_field (const_tree type, -+ n_loongarch_aggregate_field fields[2], -+ int n, HOST_WIDE_INT offset) -+{ -+ switch (TREE_CODE (type)) -+ { -+ case RECORD_TYPE: -+ /* Can't handle incomplete types nor sizes that are not fixed. */ -+ if (!COMPLETE_TYPE_P (type) -+ || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST -+ || !tree_fits_uhwi_p (TYPE_SIZE (type))) -+ return -1; ++ - code models (cmodel) ++ - other command-line switches (switch) + -+ for (tree f = TYPE_FIELDS (type); f; f = DECL_CHAIN (f)) -+ if (TREE_CODE (f) == FIELD_DECL) -+ { -+ if (!TYPE_P (TREE_TYPE (f))) -+ return -1; ++ These values are primarily used for implementing option handling ++ logic in "loongarch.opt", "loongarch-driver.c" and "loongarch-opt.c". + -+ HOST_WIDE_INT pos = offset + int_byte_position (f); -+ n = n_loongarch_flatten_aggregate_field (TREE_TYPE (f), fields, n, pos); -+ if (n < 0) -+ return -1; -+ } -+ return n; ++ As for the result of this option handling process, the following ++ scheme is adopted to represent the final configuration: + -+ case ARRAY_TYPE: -+ { -+ HOST_WIDE_INT n_elts; -+ n_loongarch_aggregate_field subfields[2]; -+ tree index = TYPE_DOMAIN (type); -+ tree elt_size = TYPE_SIZE_UNIT (TREE_TYPE (type)); -+ int n_subfields = n_loongarch_flatten_aggregate_field (TREE_TYPE (type), -+ subfields, 0, offset); ++ - The target ABI is encoded with a tuple (abi_base, abi_ext) ++ using the code defined below. + -+ /* Can't handle incomplete types nor sizes that are not fixed. */ -+ if (n_subfields <= 0 -+ || !COMPLETE_TYPE_P (type) -+ || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST -+ || !index -+ || !TYPE_MAX_VALUE (index) -+ || !tree_fits_uhwi_p (TYPE_MAX_VALUE (index)) -+ || !TYPE_MIN_VALUE (index) -+ || !tree_fits_uhwi_p (TYPE_MIN_VALUE (index)) -+ || !tree_fits_uhwi_p (elt_size)) -+ return -1; ++ - The target ISA is encoded with a "struct loongarch_isa" defined ++ in loongarch-cpu.h. + -+ n_elts = 1 + tree_to_uhwi (TYPE_MAX_VALUE (index)) -+ - tree_to_uhwi (TYPE_MIN_VALUE (index)); -+ gcc_assert (n_elts >= 0); ++ - The target microarchitecture is represented with a cpu model ++ index defined in loongarch-cpu.h. ++*/ + -+ for (HOST_WIDE_INT i = 0; i < n_elts; i++) -+ for (int j = 0; j < n_subfields; j++) -+ { -+ if (n >= 2) -+ return -1; ++#ifndef LOONGARCH_DEF_H ++#define LOONGARCH_DEF_H + -+ fields[n] = subfields[j]; -+ fields[n++].offset += i * tree_to_uhwi (elt_size); -+ } ++#include "loongarch-tune.h" + -+ return n; -+ } ++#ifdef __cplusplus ++extern "C" { ++#endif + -+ case COMPLEX_TYPE: -+ { -+ /* Complex type need consume 2 field, so n must be 0. */ -+ if (n != 0) -+ return -1; ++/* enum isa_base */ ++extern const char* loongarch_isa_base_strings[]; ++#define ISA_BASE_LA64V100 0 ++#define N_ISA_BASE_TYPES 1 ++ ++/* enum isa_ext_* */ ++extern const char* loongarch_isa_ext_strings[]; ++#define ISA_EXT_NOFPU 0 ++#define ISA_EXT_FPU32 1 ++#define ISA_EXT_FPU64 2 ++#define N_ISA_EXT_FPU_TYPES 3 ++#define N_ISA_EXT_TYPES 3 ++ ++/* enum abi_base */ ++extern const char* loongarch_abi_base_strings[]; ++#define ABI_BASE_LP64D 0 ++#define ABI_BASE_LP64F 1 ++#define ABI_BASE_LP64S 2 ++#define N_ABI_BASE_TYPES 3 ++ ++/* enum abi_ext */ ++extern const char* loongarch_abi_ext_strings[]; ++#define ABI_EXT_BASE 0 ++#define N_ABI_EXT_TYPES 1 ++ ++/* enum cmodel */ ++extern const char* loongarch_cmodel_strings[]; ++#define CMODEL_NORMAL 0 ++#define CMODEL_TINY 1 ++#define CMODEL_TINY_STATIC 2 ++#define CMODEL_MEDIUM 3 ++#define CMODEL_LARGE 4 ++#define CMODEL_EXTREME 5 ++#define N_CMODEL_TYPES 6 ++ ++/* enum switches */ ++/* The "SW_" codes represent command-line switches (options that ++ accept no parameters). Definition for other switches that affects ++ the target ISA / ABI configuration will also be appended here ++ in the future. */ ++ ++extern const char* loongarch_switch_strings[]; ++#define SW_SOFT_FLOAT 0 ++#define SW_SINGLE_FLOAT 1 ++#define SW_DOUBLE_FLOAT 2 ++#define N_SWITCH_TYPES 3 ++ ++/* The common default value for variables whose assignments ++ are triggered by command-line options. */ ++ ++#define M_OPTION_NOT_SEEN -1 ++#define M_OPT_ABSENT(opt_enum) ((opt_enum) == M_OPTION_NOT_SEEN) ++ ++ ++/* Internal representation of the target. */ ++struct loongarch_isa ++{ ++ unsigned char base; /* ISA_BASE_ */ ++ unsigned char fpu; /* ISA_EXT_FPU_ */ ++}; + -+ HOST_WIDE_INT elt_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type))); ++struct loongarch_abi ++{ ++ unsigned char base; /* ABI_BASE_ */ ++ unsigned char ext; /* ABI_EXT_ */ ++}; + -+ if (elt_size <= UNITS_PER_FP_ARG) -+ { -+ fields[0].type = TREE_TYPE (type); -+ fields[0].offset = offset; -+ fields[1].type = TREE_TYPE (type); -+ fields[1].offset = offset + elt_size; ++struct loongarch_target ++{ ++ struct loongarch_isa isa; ++ struct loongarch_abi abi; ++ unsigned char cpu_arch; /* CPU_ */ ++ unsigned char cpu_tune; /* same */ ++ unsigned char cpu_native; /* same */ ++ unsigned char cmodel; /* CMODEL_ */ ++}; + -+ return 2; -+ } ++/* CPU properties. */ ++/* index */ ++#define CPU_NATIVE 0 ++#define CPU_LOONGARCH64 1 ++#define CPU_LA464 2 ++#define N_ARCH_TYPES 3 ++#define N_TUNE_TYPES 3 + -+ return -1; -+ } ++/* parallel tables. */ ++extern const char* loongarch_cpu_strings[]; ++extern struct loongarch_isa loongarch_cpu_default_isa[]; ++extern int loongarch_cpu_issue_rate[]; ++extern int loongarch_cpu_multipass_dfa_lookahead[]; + -+ default: -+ if (n < 2 -+ && ((SCALAR_FLOAT_TYPE_P (type) -+ && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FP_ARG) -+ || (INTEGRAL_TYPE_P (type) -+ && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD))) -+ { -+ fields[n].type = type; -+ fields[n].offset = offset; -+ return n + 1; -+ } -+ else -+ return -1; -+ } ++extern struct loongarch_cache loongarch_cpu_cache[]; ++extern struct loongarch_rtx_cost_data loongarch_cpu_rtx_cost_data[]; ++ ++#ifdef __cplusplus +} ++#endif ++#endif /* LOONGARCH_DEF_H */ +diff --git a/gcc/config/loongarch/loongarch-driver.c b/gcc/config/loongarch/loongarch-driver.c +new file mode 100644 +index 000000000..0adcc923b +--- /dev/null ++++ b/gcc/config/loongarch/loongarch-driver.c +@@ -0,0 +1,187 @@ ++/* Subroutines for the gcc driver. ++ Copyright (C) 2021-2022 Free Software Foundation, Inc. ++ Contributed by Loongson Ltd. + -+/* Identify candidate aggregates for passing in floating-point registers. -+ Candidates have at most two fields after flattening. */ ++This file is part of GCC. + -+static int -+n_loongarch_flatten_aggregate_argument (const_tree type, -+ n_loongarch_aggregate_field fields[2]) -+{ -+ if (!type || TREE_CODE (type) != RECORD_TYPE) -+ return -1; ++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. + -+ return n_loongarch_flatten_aggregate_field (type, fields, 0, 0); -+} ++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. + -+/* See whether TYPE is a record whose fields should be returned in one or -+ two floating-point registers. If so, populate FIELDS accordingly. */ ++You should have received a copy of the GNU General Public License ++along with GCC; see the file COPYING3. If not see ++. */ + -+static unsigned -+n_loongarch_pass_aggregate_in_fpr_pair_p (const_tree type, -+ n_loongarch_aggregate_field fields[2]) -+{ -+ int n = n_loongarch_flatten_aggregate_argument (type, fields); ++#define IN_TARGET_CODE 1 + -+ for (int i = 0; i < n; i++) -+ if (!SCALAR_FLOAT_TYPE_P (fields[i].type)) -+ return 0; ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "obstack.h" ++#include "diagnostic-core.h" + -+ return n > 0 ? n : 0; -+} ++#include "loongarch-opts.h" ++#include "loongarch-driver.h" + -+/* See whether TYPE is a record whose fields should be returned in one or -+ floating-point register and one integer register. If so, populate -+ FIELDS accordingly. */ ++static int ++ opt_arch_driver = M_OPTION_NOT_SEEN, ++ opt_tune_driver = M_OPTION_NOT_SEEN, ++ opt_fpu_driver = M_OPTION_NOT_SEEN, ++ opt_abi_base_driver = M_OPTION_NOT_SEEN, ++ opt_abi_ext_driver = M_OPTION_NOT_SEEN, ++ opt_cmodel_driver = M_OPTION_NOT_SEEN; ++ ++int opt_switches = 0; ++ ++/* This flag is set to 1 if we believe that the user might be avoiding ++ linking (implicitly) against something from the startfile search paths. */ ++static int no_link = 0; ++ ++#define LARCH_DRIVER_SET_M_FLAG(OPTS_ARRAY, N_OPTS, FLAG, STR) \ ++ for (int i = 0; i < (N_OPTS); i++) \ ++ { \ ++ if ((OPTS_ARRAY)[i] != 0) \ ++ if (strcmp ((STR), (OPTS_ARRAY)[i]) == 0) \ ++ (FLAG) = i; \ ++ } + -+static bool -+n_loongarch_pass_aggregate_in_fpr_and_gpr_p (const_tree type, -+ n_loongarch_aggregate_field fields[2]) -+{ -+ unsigned num_int = 0, num_float = 0; -+ int n = n_loongarch_flatten_aggregate_argument (type, fields); ++/* Use the public obstack from the gcc driver (defined in gcc.c). ++ This is for allocating space for the returned string. */ ++extern struct obstack opts_obstack; + -+ for (int i = 0; i < n; i++) -+ { -+ num_float += SCALAR_FLOAT_TYPE_P (fields[i].type); -+ num_int += INTEGRAL_TYPE_P (fields[i].type); -+ } ++#define APPEND_LTR(S) \ ++ obstack_grow (&opts_obstack, (const void*) (S), \ ++ sizeof ((S)) / sizeof (char) -1) + -+ return num_int == 1 && num_float == 1; -+} ++#define APPEND_VAL(S) \ ++ obstack_grow (&opts_obstack, (const void*) (S), strlen ((S))) + -+/* Return the representation of an argument passed or returned in an FPR -+ when the value has mode VALUE_MODE and the type has TYPE_MODE. The -+ two modes may be different for structures like: + -+ struct __attribute__((packed)) foo { float f; } ++const char* ++driver_set_m_flag (int argc, const char **argv) ++{ ++ int parm_off = 0; + -+ where the SFmode value "f" is passed in REGNO but the struct itself -+ has mode BLKmode. */ ++ if (argc != 1) ++ return "%eset_m_flag requires exactly 1 argument."; + -+static rtx -+n_loongarch_pass_fpr_single (machine_mode type_mode, unsigned regno, -+ machine_mode value_mode) -+{ -+ rtx x = gen_rtx_REG (value_mode, regno); ++#undef PARM ++#define PARM (argv[0] + parm_off) + -+ if (type_mode != value_mode) ++/* Note: sizeof (OPTSTR_##NAME) equals the length of "