diff --git a/contrib/gcc_update b/contrib/gcc_update
index 1cf15f9b3c2..641ce164775 100755
--- a/contrib/gcc_update
+++ b/contrib/gcc_update
@@ -86,6 +86,8 @@ gcc/config/arm/arm-tables.opt: gcc/config/arm/arm-cpus.in gcc/config/arm/parsecp
gcc/config/c6x/c6x-tables.opt: gcc/config/c6x/c6x-isas.def gcc/config/c6x/genopt.sh
gcc/config/c6x/c6x-sched.md: gcc/config/c6x/c6x-sched.md.in gcc/config/c6x/gensched.sh
gcc/config/c6x/c6x-mult.md: gcc/config/c6x/c6x-mult.md.in gcc/config/c6x/genmult.sh
+gcc/config/loongarch/loongarch-str.h: gcc/config/loongarch/genopts/genstr.sh gcc/config/loongarch/genopts/loongarch-string
+gcc/config/loongarch/loongarch.opt: gcc/config/loongarch/genopts/genstr.sh gcc/config/loongarch/genopts/loongarch.opt.in
gcc/config/m68k/m68k-tables.opt: gcc/config/m68k/m68k-devices.def gcc/config/m68k/m68k-isas.def gcc/config/m68k/m68k-microarchs.def gcc/config/m68k/genopt.sh
gcc/config/mips/mips-tables.opt: gcc/config/mips/mips-cpus.def gcc/config/mips/genopt.sh
gcc/config/rs6000/rs6000-tables.opt: gcc/config/rs6000/rs6000-cpus.def gcc/config/rs6000/genopt.sh
diff --git a/gcc/common/config/loongarch/loongarch-common.cc b/gcc/common/config/loongarch/loongarch-common.cc
new file mode 100644
index 00000000000..085d3d98f1c
--- /dev/null
+++ b/gcc/common/config/loongarch/loongarch-common.cc
@@ -0,0 +1,43 @@
+/* Common hooks for LoongArch.
+ 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
+. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "common/common-target.h"
+#include "common/common-target-def.h"
+#include "opts.h"
+#include "flags.h"
+#include "diagnostic-core.h"
+
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE loongarch_option_optimization_table
+
+/* Set default optimization options. */
+static const struct default_options loongarch_option_optimization_table[] =
+{
+ { OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 },
+ { OPT_LEVELS_NONE, 0, NULL, 0 }
+};
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS MASK_CHECK_ZERO_DIV
+
+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 3833bfa16a9..7b58e1314ff 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -454,6 +454,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"
@@ -2495,6 +2502,20 @@ riscv*-*-freebsd*)
# automatically detect that GAS supports it, yet we require it.
gcc_cv_initfini_array=yes
;;
+
+loongarch*-*-linux*)
+ 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
+
+ # Force .init_array support. The configure script cannot always
+ # automatically detect that GAS supports it, yet we require it.
+ gcc_cv_initfini_array=yes
+ ;;
+
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"
@@ -3601,7 +3622,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
@@ -4933,6 +4954,373 @@ 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 \
+ triplet_os triplet_abi
+
+ # Infer ABI from the triplet.
+ case ${target} in
+ loongarch64-*-*-*f64)
+ abi_pattern="lp64d"
+ triplet_abi="f64"
+ ;;
+ loongarch64-*-*-*f32)
+ abi_pattern="lp64f"
+ triplet_abi="f32"
+ ;;
+ loongarch64-*-*-*sf)
+ abi_pattern="lp64s"
+ triplet_abi="sf"
+ ;;
+ loongarch64-*-*-*)
+ abi_pattern="lp64[dfs]"
+ abi_default="lp64d"
+ triplet_abi=""
+ ;;
+ *)
+ echo "Unsupported target ${target}." 1>&2
+ exit 1
+ ;;
+ esac
+
+ abiext_pattern="*"
+ abiext_default="base"
+
+ # Get the canonical triplet (multiarch specifier).
+ case ${target} in
+ *-linux-gnu*) triplet_os="linux-gnu";;
+ *-linux-musl*) triplet_os="linux-musl";;
+ *)
+ echo "Unsupported target ${target}." 1>&2
+ exit 1
+ ;;
+ esac
+
+ la_canonical_triplet="loongarch64-${triplet_os}${triplet_abi}"
+
+
+ # Perform initial sanity checks on --with-* options.
+ 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.
+ 0)
+ # Convert "0" to "none" for upcoming checks.
+ with_fpu="none"
+ ;;
+ *)
+ echo "Unknown fpu type in --with-fpu=$with_fpu" 1>&2
+ exit 1
+ ;;
+ esac
+
+
+ # Set 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}$" > /dev/null; then
+ : # OK
+ else
+ echo "Incompatible options:" \
+ "--with-abi=${with_abi} and --target=${target}." 1>&2
+ exit 1
+ fi
+ ;;
+ esac
+
+ # Set 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}$" > /dev/null; then
+ : # OK
+ else
+ echo "The ABI extension type \"${with_abiext}\"" \
+ "is incompatible with --target=${target}." 1>&2
+ exit 1
+ fi
+
+ ;;
+ esac
+
+ # Infer 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
+
+ # Infer 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
+
+ ## Set 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}$" > /dev/null; then
+ : # OK
+ else
+ echo "${with_abi}/${with_abiext} ABI cannot be implemented with" \
+ "--with-arch=${with_arch}." 1>&2
+ exit 1
+ fi
+ ;;
+ esac
+
+ ## Set default value for with_fpu.
+ 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}$" > /dev/null; then
+ : # OK
+ else
+ echo "${with_abi}/${with_abiext} ABI cannot be implemented with" \
+ "--with-fpu=${with_fpu}." 1>&2
+ exit 1
+ fi
+ ;;
+ esac
+
+
+ # Infer 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
+
+ ## Set 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}$" > /dev/null; then
+ : # OK
+ else
+ echo "Incompatible options: --with-tune=${with_tune}" \
+ "and --with-arch=${with_arch}." 1>&2
+ exit 1
+ fi
+ ;;
+ 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=""
+
+ # ${with_multilib_list} should not contain whitespaces,
+ # consecutive commas or slashes.
+ if echo "${with_multilib_list}" \
+ | grep -E -e "[[:space:]]" -e '[,/][,/]' -e '[,/]$' -e '^[,/]' > /dev/null; then
+ echo "Invalid argument to --with-multilib-list." 1>&2
+ exit 1
+ fi
+
+ unset component idx elem_abi_base elem_abi_ext elem_tmp
+ for elem in $(echo "${with_multilib_list}" | tr ',' ' '); do
+ idx=0
+ while true; do
+ idx=$((idx + 1))
+ component=$(echo "${elem}" | awk -F'/' '{print $'"${idx}"'}')
+
+ case ${idx} in
+ 1)
+ # Component 1: Base ABI type
+ case ${component} in
+ lp64d) elem_tmp="ABI_BASE_LP64D,";;
+ lp64f) elem_tmp="ABI_BASE_LP64F,";;
+ lp64s) elem_tmp="ABI_BASE_LP64S,";;
+ *)
+ echo "Unknown base ABI \"${component}\" in --with-multilib-list." 1>&2
+ exit 1
+ ;;
+ esac
+ loongarch_multilib_list_c="${loongarch_multilib_list_c}${elem_tmp}"
+ loongarch_multilib_list_make="${loongarch_multilib_list_make}mabi=${component}"
+ elem_abi_base="${component}"
+ ;;
+
+ 2)
+ # Component 2: ABI extension type
+ case ${component} in
+ "" | base)
+ component="base"
+ elem_tmp="ABI_EXT_BASE,"
+ ;;
+ *)
+ echo "Unknown ABI extension \"${component}\" in --with-multilib-list." 1>&2
+ exit 1
+ ;;
+ esac
+ loongarch_multilib_list_c="${loongarch_multilib_list_c}${elem_tmp}"
+ loongarch_multilib_list_make="${loongarch_multilib_list_make}" # Add nothing for now.
+ elem_abi_ext="${component}"
+ ;;
+
+ *)
+ # Component 3 and on: optional stuff
+ case ${component} in
+ "")
+ # End of component list.
+ break
+ ;;
+ *)
+ echo "Unknown ABI \"${elem}\" in --with-multilib-list." 1>&2
+ exit 1
+ ;;
+ esac
+ ;;
+ esac
+ done
+
+ if test x${elem_abi_base} = x${with_abi} \
+ && test x${elem_abi_ext} = x${with_abiext}; then
+ loongarch_multilib_list_sane=yes
+ fi
+ loongarch_multilib_list_make="${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%,}
+ loongarch_multilib_list_make=${loongarch_multilib_list_make%,}
+ ;;
+
nds32*-*-*)
supported_defaults="arch cpu nds32_lib float fpu_config"
@@ -5370,6 +5758,51 @@ case ${target} in
tmake_file="mips/t-mips $tmake_file"
;;
+ loongarch*-*-*)
+ # Export canonical triplet.
+ tm_defines="${tm_defines} LA_MULTIARCH_TRIPLET=${la_canonical_triplet}"
+
+ # Define macro LA_DISABLE_MULTILIB if --disable-multilib
+ tm_defines="${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="${tm_defines} LA_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="${tm_defines} DEFAULT_CPU_ARCH=CPU_NATIVE" ;;
+ la464) tm_defines="${tm_defines} DEFAULT_CPU_ARCH=CPU_LA464" ;;
+ loongarch64) tm_defines="${tm_defines} DEFAULT_CPU_ARCH=CPU_LOONGARCH64" ;;
+ esac
+
+ case ${with_tune} in
+ native) tm_defines="${tm_defines} DEFAULT_CPU_TUNE=CPU_NATIVE" ;;
+ la464) tm_defines="${tm_defines} DEFAULT_CPU_TUNE=CPU_LA464" ;;
+ loongarch64) tm_defines="${tm_defines} DEFAULT_CPU_TUNE=CPU_LOONGARCH64" ;;
+ esac
+
+ case ${with_abi} in
+ lp64d) tm_defines="${tm_defines} DEFAULT_ABI_BASE=ABI_BASE_LP64D" ;;
+ lp64f) tm_defines="${tm_defines} DEFAULT_ABI_BASE=ABI_BASE_LP64F" ;;
+ lp64s) tm_defines="${tm_defines} DEFAULT_ABI_BASE=ABI_BASE_LP64S" ;;
+ esac
+
+ case ${with_abiext} in
+ base) tm_defines="${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.
diff --git a/gcc/config/loongarch/genopts/genstr.sh b/gcc/config/loongarch/genopts/genstr.sh
new file mode 100755
index 00000000000..972ef125ff9
--- /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 <. */
+
+#ifndef LOONGARCH_STR_H
+#define LOONGARCH_STR_H
+EOF
+
+ sed -e '/^$/n' -e 's@#.*$@@' -e '/^$/d' \
+ -e 's@^\([^ \t]\+\)[ \t]*\([^ \t]*\)@#define \1 "\2"@' \
+ loongarch-strings
+
+ echo
+ echo "#endif /* LOONGARCH_STR_H */"
+}
+
+
+# Substitute all "@@@@" to "" in loongarch.opt.in
+# according to the key-value pairs defined in loongarch-strings.
+
+gen_options() {
+
+ 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
+
+ # 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
+
+ # make the substitutions
+ sed -e 's@"@\\"@g' -e 's/@@\([^@]\+\)@@/${\1}/g' loongarch.opt.in | \
+ while read -r line; do
+ eval "echo \"$line\""
+ done
+ }
+}
+
+main() {
+ case "$1" in
+ header) gen_defines;;
+ opt) gen_options;;
+ *) echo "Unknown Command: \"$1\". Available: header, opt"; exit 1;;
+ esac
+}
+
+main "$@"
diff --git a/gcc/config/loongarch/genopts/loongarch-strings b/gcc/config/loongarch/genopts/loongarch-strings
new file mode 100644
index 00000000000..cb88ed56b68
--- /dev/null
+++ b/gcc/config/loongarch/genopts/loongarch-strings
@@ -0,0 +1,58 @@
+# 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
+# .
+
+# -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_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 00000000000..61e7d72a0a1
--- /dev/null
+++ b/gcc/config/loongarch/genopts/loongarch.opt.in
@@ -0,0 +1,179 @@
+; 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.
+
+HeaderInclude
+config/loongarch/loongarch-opts.h
+
+HeaderInclude
+config/loongarch/loongarch-str.h
+
+Variable
+HOST_WIDE_INT la_opt_switches = 0
+
+; ISA related options
+;; Base ISA
+Enum
+Name(isa_base) Type(int)
+Basic ISAs of LoongArch:
+
+EnumValue
+Enum(isa_base) String(@@STR_ISA_BASE_LA64V100@@) Value(ISA_BASE_LA64V100)
+
+
+;; ISA extensions / adjustments
+Enum
+Name(isa_ext_fpu) Type(int)
+FPU types of LoongArch:
+
+EnumValue
+Enum(isa_ext_fpu) String(@@STR_ISA_EXT_NOFPU@@) Value(ISA_EXT_NOFPU)
+
+EnumValue
+Enum(isa_ext_fpu) String(@@STR_ISA_EXT_FPU32@@) Value(ISA_EXT_FPU32)
+
+EnumValue
+Enum(isa_ext_fpu) String(@@STR_ISA_EXT_FPU64@@) Value(ISA_EXT_FPU64)
+
+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.
+
+m@@OPTSTR_ISA_EXT_FPU@@=@@STR_ISA_EXT_FPU0@@
+Target RejectNegative Alias(m@@OPTSTR_ISA_EXT_FPU@@=,@@STR_ISA_EXT_NOFPU@@)
+
+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.
+
+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.
+
+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.
+
+
+;; Base target models (implies ISA & tune parameters)
+Enum
+Name(cpu_type) Type(int)
+LoongArch CPU types:
+
+EnumValue
+Enum(cpu_type) String(@@STR_CPU_NATIVE@@) Value(CPU_NATIVE)
+
+EnumValue
+Enum(cpu_type) String(@@STR_CPU_LOONGARCH64@@) Value(CPU_LOONGARCH64)
+
+EnumValue
+Enum(cpu_type) String(@@STR_CPU_LA464@@) Value(CPU_LA464)
+
+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.
+
+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.
+
+
+; ABI related options
+; (ISA constraints on ABI are handled dynamically)
+
+;; Base ABI
+Enum
+Name(abi_base) Type(int)
+Base ABI types for LoongArch:
+
+EnumValue
+Enum(abi_base) String(@@STR_ABI_BASE_LP64D@@) Value(ABI_BASE_LP64D)
+
+EnumValue
+Enum(abi_base) String(@@STR_ABI_BASE_LP64F@@) Value(ABI_BASE_LP64F)
+
+EnumValue
+Enum(abi_base) String(@@STR_ABI_BASE_LP64S@@) Value(ABI_BASE_LP64S)
+
+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.
+
+;; ABI Extension
+Variable
+int la_opt_abi_ext = M_OPTION_NOT_SEEN
+
+
+mbranch-cost=
+Target RejectNegative Joined UInteger Var(loongarch_branch_cost)
+-mbranch-cost=COST Set the cost of branches to roughly COST instructions.
+
+mcheck-zero-division
+Target Mask(CHECK_ZERO_DIV)
+Trap on integer divide by zero.
+
+mcond-move-int
+Target Var(TARGET_COND_MOVE_INT) Init(1)
+Conditional moves for integral are enabled.
+
+mcond-move-float
+Target Var(TARGET_COND_MOVE_FLOAT) Init(1)
+Conditional moves for float are enabled.
+
+mmemcpy
+Target Mask(MEMCPY)
+Prevent optimizing block moves, which is also the default behavior of -Os.
+
+mstrict-align
+Target Var(TARGET_STRICT_ALIGN) Init(0)
+Do not generate unaligned memory accesses.
+
+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.
+
+; The code model option names for -mcmodel.
+Enum
+Name(cmodel) Type(int)
+The code model option names for -mcmodel:
+
+EnumValue
+Enum(cmodel) String(@@STR_CMODEL_NORMAL@@) Value(CMODEL_NORMAL)
+
+EnumValue
+Enum(cmodel) String(@@STR_CMODEL_TINY@@) Value(CMODEL_TINY)
+
+EnumValue
+Enum(cmodel) String(@@STR_CMODEL_TS@@) Value(CMODEL_TINY_STATIC)
+
+EnumValue
+Enum(cmodel) String(@@STR_CMODEL_LARGE@@) Value(CMODEL_LARGE)
+
+EnumValue
+Enum(cmodel) String(@@STR_CMODEL_EXTREME@@) Value(CMODEL_EXTREME)
+
+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 00000000000..664dc9206ad
--- /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.
+
+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
+. */
+
+/* Define the size of the wide character type. */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+
+/* GNU-specific SPEC definitions. */
+#define GNU_USER_LINK_EMULATION "elf" ABI_GRLEN_SPEC "loongarch"
+
+#undef GLIBC_DYNAMIC_LINKER
+#define GLIBC_DYNAMIC_LINKER \
+ "/lib" ABI_GRLEN_SPEC "/ld-linux-loongarch-" ABI_SPEC ".so.1"
+
+#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*} %{shared} -m " GNU_USER_LINK_EMULATION \
+ "%{!shared: %{static} %{!static: %{rdynamic:-export-dynamic} " \
+ "-dynamic-linker " GNU_USER_DYNAMIC_LINKER "}}"
+
+
+/* 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
+
+#undef LINK_SPEC
+#define LINK_SPEC GNU_USER_TARGET_LINK_SPEC
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ GNU_USER_TARGET_MATHFILE_SPEC " " \
+ GNU_USER_TARGET_ENDFILE_SPEC
+
+#undef SUBTARGET_CPP_SPEC
+#define SUBTARGET_CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
+
+/* 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
+
+#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)
diff --git a/gcc/config/loongarch/linux.h b/gcc/config/loongarch/linux.h
new file mode 100644
index 00000000000..110d0fab93d
--- /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.
+
+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
+. */
+
+/* Default system library search paths.
+ * This ensures that a compiler configured with --disable-multilib
+ * can work in a multilib environment. */
+
+#if defined(LA_DISABLE_MULTILIB) && defined(LA_DISABLE_MULTIARCH)
+
+ #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
+
+#endif
+
+#ifndef ABI_LIBDIR
+#define ABI_LIBDIR "lib"
+#endif
+
+#define STANDARD_STARTFILE_PREFIX_1 "/" ABI_LIBDIR "/"
+#define STANDARD_STARTFILE_PREFIX_2 "/usr/" ABI_LIBDIR "/"
+
+
+/* Define this to be nonzero if static stack checking is supported. */
+#define STACK_CHECK_STATIC_BUILTIN 1
+
+/* The default value isn't sufficient in 64-bit mode. */
+#define STACK_CHECK_PROTECT (TARGET_64BIT ? 16 * 1024 : 12 * 1024)
+
+#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
diff --git a/gcc/config/loongarch/loongarch-cpu.cc b/gcc/config/loongarch/loongarch-cpu.cc
new file mode 100644
index 00000000000..a886dd9323b
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-cpu.cc
@@ -0,0 +1,206 @@
+/* Definitions for LoongArch CPU 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
+. */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "diagnostic-core.h"
+
+#include "loongarch-opts.h"
+#include "loongarch-cpu.h"
+#include "loongarch-str.h"
+
+/* 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};
+
+static uint32_t
+read_cpucfg_word (int wordno)
+{
+ /* To make cross-compiler shut up. */
+ (void) wordno;
+ uint32_t ret = 0;
+
+ #ifdef __loongarch__
+ __asm__ __volatile__ ("cpucfg %0,%1\n\t"
+ :"=r"(ret)
+ :"r"(wordno)
+ :);
+ #endif
+
+ return ret;
+}
+
+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]);
+ }
+}
+
+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];
+}
+
+const char*
+get_native_prid_str (void)
+{
+ static char prid_str[9];
+ sprintf (prid_str, "%08x", cpucfg_cache[0]);
+ return (const char*) prid_str;
+}
+
+/* Fill property tables for CPU_NATIVE. */
+unsigned int
+fill_native_cpu_config (int p_arch_native, int p_tune_native)
+{
+ int ret_cpu_type;
+
+ /* Nothing needs to be done unless "-march/tune=native"
+ is given or implied. */
+ if (!(p_arch_native || p_tune_native))
+ return CPU_NATIVE;
+
+ /* Fill cpucfg_cache with the "cpucfg" instruction. */
+ cache_cpucfg ();
+
+
+ /* Fill: loongarch_cpu_default_isa[CPU_NATIVE].base
+ With: base architecture (ARCH)
+ At: cpucfg_words[1][1:0] */
+
+ #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;
+
+ 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);
+ }
+
+ /* Fill: loongarch_cpu_default_isa[CPU_NATIVE].fpu
+ With: FPU type (FP, FP_SP, FP_DP)
+ At: cpucfg_words[2][2:0] */
+
+ #define NATIVE_FPU (loongarch_cpu_default_isa[CPU_NATIVE].fpu)
+ switch (cpucfg_cache[2] & 0x7)
+ {
+ case 0x07:
+ NATIVE_FPU = ISA_EXT_FPU64;
+ break;
+
+ case 0x03:
+ NATIVE_FPU = ISA_EXT_FPU32;
+ break;
+
+ case 0x00:
+ NATIVE_FPU = ISA_EXT_NOFPU;
+ break;
+
+ 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);
+ }
+
+ /* Fill: loongarch_cpu_cache[CPU_NATIVE]
+ With: cache size info
+ At: cpucfg_words[16:20][31:0] */
+
+ int l1d_present = 0, l1u_present = 0;
+ int l2d_present = 0;
+ uint32_t l1_szword, l2_szword;
+
+ 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;
+
+ loongarch_cpu_cache[CPU_NATIVE].l1d_line_size
+ = 1 << ((l1_szword & 0x7f000000) >> 24); /* bit[30:24]: log2(linesize) */
+
+ 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 */
+
+ 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 */
+
+ /* Fill: ret_cpu_type
+ With: processor ID (PRID)
+ At: cpucfg_words[0][31:0] */
+
+ switch (cpucfg_cache[0] & 0x00ffff00)
+ {
+ case 0x0014c000: /* LA464 */
+ ret_cpu_type = CPU_LA464;
+ break;
+
+ 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;
+ }
+
+ /* Properties that cannot be looked up directly using cpucfg. */
+ loongarch_cpu_issue_rate[CPU_NATIVE]
+ = loongarch_cpu_issue_rate[ret_cpu_type];
+
+ loongarch_cpu_multipass_dfa_lookahead[CPU_NATIVE]
+ = loongarch_cpu_multipass_dfa_lookahead[ret_cpu_type];
+
+ loongarch_cpu_rtx_cost_data[CPU_NATIVE]
+ = loongarch_cpu_rtx_cost_data[ret_cpu_type];
+
+ 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 00000000000..93d656f70f5
--- /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.
+
+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
+. */
+
+#ifndef LOONGARCH_CPU_H
+#define LOONGARCH_CPU_H
+
+#include "system.h"
+
+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 00000000000..c8769b7d65e
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-def.c
@@ -0,0 +1,179 @@
+/* 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,
+};
+
+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,
+ },
+};
+
+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,
+ },
+};
+
+/* 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
+ },
+ [CPU_LOONGARCH64] = {
+ DEFAULT_COSTS
+ },
+ [CPU_LA464] = {
+ DEFAULT_COSTS
+ },
+};
+
+/* 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,
+};
+
+int
+loongarch_cpu_issue_rate[N_TUNE_TYPES] = {
+ [CPU_NATIVE] = 4,
+ [CPU_LOONGARCH64] = 4,
+ [CPU_LA464] = 4,
+};
+
+int
+loongarch_cpu_multipass_dfa_lookahead[N_TUNE_TYPES] = {
+ [CPU_NATIVE] = 4,
+ [CPU_LOONGARCH64] = 4,
+ [CPU_LA464] = 4,
+};
+
+/* 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. */
+
+const char*
+loongarch_isa_base_strings[N_ISA_BASE_TYPES] = {
+ [ISA_BASE_LA64V100] = STR_ISA_BASE_LA64V100,
+};
+
+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,
+};
+
+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,
+};
+
+const char*
+loongarch_abi_ext_strings[N_ABI_EXT_TYPES] = {
+ [ABI_EXT_BASE] = STR_ABI_EXT_BASE,
+};
+
+const char*
+loongarch_cmodel_strings[] = {
+ [CMODEL_NORMAL] = STR_CMODEL_NORMAL,
+ [CMODEL_TINY] = STR_CMODEL_TINY,
+ [CMODEL_TINY_STATIC] = STR_CMODEL_TS,
+ [CMODEL_LARGE] = STR_CMODEL_LARGE,
+ [CMODEL_EXTREME] = STR_CMODEL_EXTREME,
+};
+
+const char*
+loongarch_switch_strings[] = {
+ [SW_SOFT_FLOAT] = OPTSTR_SOFT_FLOAT,
+ [SW_SINGLE_FLOAT] = OPTSTR_SINGLE_FLOAT,
+ [SW_DOUBLE_FLOAT] = OPTSTR_DOUBLE_FLOAT,
+};
+
+
+/* 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 00000000000..c2c35b6ba5c
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-def.h
@@ -0,0 +1,151 @@
+/* LoongArch definitions.
+ 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
+. */
+
+/* Definition of standard codes for:
+ - base architecture types (isa_base),
+ - ISA extensions (isa_ext),
+ - base ABI types (abi_base),
+ - ABI extension types (abi_ext).
+
+ - code models (cmodel)
+ - other command-line switches (switch)
+
+ These values are primarily used for implementing option handling
+ logic in "loongarch.opt", "loongarch-driver.c" and "loongarch-opt.c".
+
+ As for the result of this option handling process, the following
+ scheme is adopted to represent the final configuration:
+
+ - The target ABI is encoded with a tuple (abi_base, abi_ext)
+ using the code defined below.
+
+ - The target ISA is encoded with a "struct loongarch_isa" defined
+ in loongarch-cpu.h.
+
+ - The target microarchitecture is represented with a cpu model
+ index defined in loongarch-cpu.h.
+*/
+
+#ifndef LOONGARCH_DEF_H
+#define LOONGARCH_DEF_H
+
+#include "loongarch-tune.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 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_LARGE 3
+#define CMODEL_EXTREME 4
+#define N_CMODEL_TYPES 5
+
+/* 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_ */
+};
+
+struct loongarch_abi
+{
+ unsigned char base; /* ABI_BASE_ */
+ unsigned char ext; /* ABI_EXT_ */
+};
+
+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_ */
+};
+
+/* 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
+
+/* 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[];
+
+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.cc b/gcc/config/loongarch/loongarch-driver.cc
new file mode 100644
index 00000000000..0adcc923b7d
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-driver.cc
@@ -0,0 +1,187 @@
+/* Subroutines for the gcc driver.
+ 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
+. */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "obstack.h"
+#include "diagnostic-core.h"
+
+#include "loongarch-opts.h"
+#include "loongarch-driver.h"
+
+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; \
+ }
+
+/* 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;
+
+#define APPEND_LTR(S) \
+ obstack_grow (&opts_obstack, (const void*) (S), \
+ sizeof ((S)) / sizeof (char) -1)
+
+#define APPEND_VAL(S) \
+ obstack_grow (&opts_obstack, (const void*) (S), strlen ((S)))
+
+
+const char*
+driver_set_m_flag (int argc, const char **argv)
+{
+ int parm_off = 0;
+
+ if (argc != 1)
+ return "%eset_m_flag requires exactly 1 argument.";
+
+#undef PARM
+#define PARM (argv[0] + parm_off)
+
+/* Note: sizeof (OPTSTR_##NAME) equals the length of "