[v5,02/12] LoongArch Port: gcc build

Message ID 20220122075607.1808354-3-xuchenghua@loongson.cn
State New
Headers
Series Add LoongArch support |

Commit Message

Chenghua Xu Jan. 22, 2022, 7:55 a.m. UTC
  From: chenglulu <chenglulu@loongson.cn>

gcc/

        * common/config/loongarch/loongarch-common.cc: New file.
        * config/loongarch/genopts/genstr.sh: New file.
        * config/loongarch/genopts/loongarch-strings: New file.
        * config/loongarch/genopts/loongarch.opt.in: New file.
	* config/loongarch/loongarch-str.h: New file.
        * config/loongarch/gnu-user.h: New file.
        * config/loongarch/linux.h: New file.
        * config/loongarch/loongarch-cpu.cc: New file.
        * config/loongarch/loongarch-cpu.h: New file.
	* config/loongarch/loongarch-def.c: New file.
	* config/loongarch/loongarch-def.h: New file.
        * config/loongarch/loongarch-driver.cc: New file.
        * config/loongarch/loongarch-driver.h: New file.
        * config/loongarch/loongarch-opts.cc: New file.
        * config/loongarch/loongarch-opts.h: New file.
        * config/loongarch/loongarch.opt: New file.
        * config/loongarch/t-linux: New file.
        * config/loongarch/t-loongarch: New file.
        * config.gcc: Add LoongArch support.
        * configure.ac: Add LoongArch support.
---
 .../config/loongarch/loongarch-common.cc      |  73 +++
 gcc/config.gcc                                | 410 ++++++++++++-
 gcc/config/loongarch/genopts/genstr.sh        |  91 +++
 .../loongarch/genopts/loongarch-strings       |  58 ++
 gcc/config/loongarch/genopts/loongarch.opt.in | 189 ++++++
 gcc/config/loongarch/gnu-user.h               |  84 +++
 gcc/config/loongarch/linux.h                  |  50 ++
 gcc/config/loongarch/loongarch-cpu.cc         | 206 +++++++
 gcc/config/loongarch/loongarch-cpu.h          |  30 +
 gcc/config/loongarch/loongarch-def.c          | 164 +++++
 gcc/config/loongarch/loongarch-def.h          | 151 +++++
 gcc/config/loongarch/loongarch-driver.cc      | 187 ++++++
 gcc/config/loongarch/loongarch-driver.h       |  69 +++
 gcc/config/loongarch/loongarch-opts.cc        | 580 ++++++++++++++++++
 gcc/config/loongarch/loongarch-opts.h         |  86 +++
 gcc/config/loongarch/loongarch-str.h          |  57 ++
 gcc/config/loongarch/loongarch.opt            | 189 ++++++
 gcc/config/loongarch/t-linux                  |  53 ++
 gcc/config/loongarch/t-loongarch              |  59 ++
 gcc/configure.ac                              |  33 +-
 20 files changed, 2814 insertions(+), 5 deletions(-)
 create mode 100644 gcc/common/config/loongarch/loongarch-common.cc
 create mode 100755 gcc/config/loongarch/genopts/genstr.sh
 create mode 100644 gcc/config/loongarch/genopts/loongarch-strings
 create mode 100644 gcc/config/loongarch/genopts/loongarch.opt.in
 create mode 100644 gcc/config/loongarch/gnu-user.h
 create mode 100644 gcc/config/loongarch/linux.h
 create mode 100644 gcc/config/loongarch/loongarch-cpu.cc
 create mode 100644 gcc/config/loongarch/loongarch-cpu.h
 create mode 100644 gcc/config/loongarch/loongarch-def.c
 create mode 100644 gcc/config/loongarch/loongarch-def.h
 create mode 100644 gcc/config/loongarch/loongarch-driver.cc
 create mode 100644 gcc/config/loongarch/loongarch-driver.h
 create mode 100644 gcc/config/loongarch/loongarch-opts.cc
 create mode 100644 gcc/config/loongarch/loongarch-opts.h
 create mode 100644 gcc/config/loongarch/loongarch-str.h
 create mode 100644 gcc/config/loongarch/loongarch.opt
 create mode 100644 gcc/config/loongarch/t-linux
 create mode 100644 gcc/config/loongarch/t-loongarch
  

Comments

Xi Ruoyao Jan. 22, 2022, 8:33 a.m. UTC | #1
On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
> +$(srcdir)/config/loongarch/loongarch.opt: \
> +       $(srcdir)/config/loongarch/genopts/genstr.sh \
> +       $(srcdir)/config/loongarch/genopts/loongarch.opt.in
> +       $(SHELL) $< opt > $@
> +
> +$(LA_STR_H): \
> +       $(srcdir)/config/loongarch/genopts/genstr.sh \
> +       $(srcdir)/config/loongarch/genopts/loongarch-strings
> +       $(SHELL) $< header > $@

I'm not sure about these two rules: is it allowed to modify files in
$(srcdir) running "make"?
  
Xi Ruoyao Jan. 22, 2022, 8:34 a.m. UTC | #2
On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
> +   Copyright (C) 2021 Free Software Foundation, Inc.

All of those should be 2021 - 2022 (or just 2022?) now.
  
Jakub Jelinek Jan. 22, 2022, 8:41 a.m. UTC | #3
On Sat, Jan 22, 2022 at 04:33:08PM +0800, Xi Ruoyao via Gcc-patches wrote:
> On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
> > +$(srcdir)/config/loongarch/loongarch.opt: \
> > +       $(srcdir)/config/loongarch/genopts/genstr.sh \
> > +       $(srcdir)/config/loongarch/genopts/loongarch.opt.in
> > +       $(SHELL) $< opt > $@
> > +
> > +$(LA_STR_H): \
> > +       $(srcdir)/config/loongarch/genopts/genstr.sh \
> > +       $(srcdir)/config/loongarch/genopts/loongarch-strings
> > +       $(SHELL) $< header > $@
> 
> I'm not sure about these two rules: is it allowed to modify files in
> $(srcdir) running "make"?

No (except in --enable-maintainer-mode), but the above certainly
looks wrong, both should be in the objdir instead.

	Jakub
  
Xi Ruoyao Jan. 22, 2022, 8:42 a.m. UTC | #4
On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
> +mstrict-align
> +Target Var(TARGET_STRICT_ALIGN) Init(0)
> +Do not generate unaligned memory accesses.

Section 2.1.8 of LoongArch spec says "load/store instruction *may* be
implemented to allow unaligned memory access".  As it's not a "must",
should we really enable this by default?
  
Xi Ruoyao Jan. 22, 2022, 8:46 a.m. UTC | #5
On Sat, 2022-01-22 at 09:41 +0100, Jakub Jelinek wrote:
> On Sat, Jan 22, 2022 at 04:33:08PM +0800, Xi Ruoyao via Gcc-patches
> wrote:
> > On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
> > > +$(srcdir)/config/loongarch/loongarch.opt: \
> > > +       $(srcdir)/config/loongarch/genopts/genstr.sh \
> > > +       $(srcdir)/config/loongarch/genopts/loongarch.opt.in
> > > +       $(SHELL) $< opt > $@
> > > +
> > > +$(LA_STR_H): \
> > > +       $(srcdir)/config/loongarch/genopts/genstr.sh \
> > > +       $(srcdir)/config/loongarch/genopts/loongarch-strings
> > > +       $(SHELL) $< header > $@
> > 
> > I'm not sure about these two rules: is it allowed to modify files in
> > $(srcdir) running "make"?
> 
> No (except in --enable-maintainer-mode), but the above certainly
> looks wrong, both should be in the objdir instead.

Does the building system support a .opt file in $(objdir)?  And how to
handle the translations (.po) for loongarch.opt if it's in $(objdir)?
  
Lulu Cheng Jan. 22, 2022, 8:56 a.m. UTC | #6
在 2022/1/22 下午4:46, Xi Ruoyao 写道:
> On Sat, 2022-01-22 at 09:41 +0100, Jakub Jelinek wrote:
>> On Sat, Jan 22, 2022 at 04:33:08PM +0800, Xi Ruoyao via Gcc-patches
>> wrote:
>>> On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
>>>> +$(srcdir)/config/loongarch/loongarch.opt: \
>>>> +       $(srcdir)/config/loongarch/genopts/genstr.sh \
>>>> +       $(srcdir)/config/loongarch/genopts/loongarch.opt.in
>>>> +       $(SHELL) $< opt > $@
>>>> +
>>>> +$(LA_STR_H): \
>>>> +       $(srcdir)/config/loongarch/genopts/genstr.sh \
>>>> +       $(srcdir)/config/loongarch/genopts/loongarch-strings
>>>> +       $(SHELL) $< header > $@
>>> I'm not sure about these two rules: is it allowed to modify files in
>>> $(srcdir) running "make"?
>> No (except in --enable-maintainer-mode), but the above certainly
>> looks wrong, both should be in the objdir instead.
> Does the building system support a .opt file in $(objdir)?  And how to
> handle the translations (.po) for loongarch.opt if it's in $(objdir)?

Under the MIPS architecture, *.opt files are also generated in $(srcdir).
  
Xi Ruoyao Jan. 22, 2022, 9:05 a.m. UTC | #7
On Sat, 2022-01-22 at 16:56 +0800, 程璐璐 wrote:

> Under the MIPS architecture, *.opt files are also generated in
> $(srcdir).

Well, but then you should put the commands for generating those files
into contrib/gcc_update instead of Makefile.in, just like MIPS.
  
Lulu Cheng Jan. 22, 2022, 9:16 a.m. UTC | #8
在 2022/1/22 下午5:05, Xi Ruoyao 写道:
> On Sat, 2022-01-22 at 16:56 +0800, 程璐璐 wrote:
>
>> Under the MIPS architecture, *.opt files are also generated in
>> $(srcdir).
> Well, but then you should put the commands for generating those files
> into contrib/gcc_update instead of Makefile.in, just like MIPS.
Sorry, I will move this commands to contrib/gcc_update.
  
Andreas Schwab Jan. 22, 2022, 9:24 a.m. UTC | #9
On Jan 22 2022, Xi Ruoyao via Gcc-patches wrote:

> Well, but then you should put the commands for generating those files
> into contrib/gcc_update instead of Makefile.in, just like MIPS.

contrib/gcc_update doesn't regenerate any files, it only updates
timestamps.
  
Jakub Jelinek Jan. 22, 2022, 9:31 a.m. UTC | #10
On Sat, Jan 22, 2022 at 05:05:00PM +0800, Xi Ruoyao wrote:
> On Sat, 2022-01-22 at 16:56 +0800, 程璐璐 wrote:
> 
> > Under the MIPS architecture, *.opt files are also generated in
> > $(srcdir).
> 
> Well, but then you should put the commands for generating those files
> into contrib/gcc_update instead of Makefile.in, just like MIPS.

The MIPS does it wrong too.  If the generated file is checked into the
tree as in the mips case, such a make rule can be there, but it
should be wrapped with
ifeq($(ENABLE_MAINTAINER_RULES),true)
...
endif
or so.
The point is, when not --enable-maintainer-mode, the gcc tree can be stored
on read-only filesystem.
When adding new CPUs, one just uses --enable-maintainer-mode and regenates
the generated but committed files and commits them together with the
changes.
There are many other examples of such generated files, configure,
Makefile.in from Makefile.am, etc.

	Jakub
  
Lulu Cheng Jan. 22, 2022, 10:35 a.m. UTC | #11
&gt; -----原始邮件-----
&gt; 发件人: "Jakub Jelinek" <jakub@redhat.com>
&gt; 发送时间: 2022-01-22 17:31:40 (星期六)
&gt; 收件人: "Xi Ruoyao" <xry111@mengyan1223.wang>
&gt; 抄送: "程璐璐" <chenglulu@loongson.cn>, "Chenghua Xu" <xuchenghua@loongson.cn>, gcc-patches@gcc.gnu.org, joseph@codesourcery.com
&gt; 主题: Re: [PATCH v5 02/12] LoongArch Port: gcc build
&gt; 
&gt; On Sat, Jan 22, 2022 at 05:05:00PM +0800, Xi Ruoyao wrote:
&gt; &gt; On Sat, 2022-01-22 at 16:56 +0800, 程璐璐 wrote:
&gt; &gt; 
&gt; &gt; &gt; Under the MIPS architecture, *.opt files are also generated in
&gt; &gt; &gt; $(srcdir).
&gt; &gt; 
&gt; &gt; Well, but then you should put the commands for generating those files
&gt; &gt; into contrib/gcc_update instead of Makefile.in, just like MIPS.
&gt; 
&gt; The MIPS does it wrong too.  If the generated file is checked into the
&gt; tree as in the mips case, such a make rule can be there, but it
&gt; should be wrapped with
&gt; ifeq($(ENABLE_MAINTAINER_RULES),true)
&gt; ...
&gt; endif
&gt; or so.
&gt; The point is, when not --enable-maintainer-mode, the gcc tree can be stored
&gt; on read-only filesystem.
&gt; When adding new CPUs, one just uses --enable-maintainer-mode and regenates
&gt; the generated but committed files and commits them together with the
&gt; changes.
&gt; There are many other examples of such generated files, configure,
&gt; Makefile.in from Makefile.am, etc.
&gt; 
&gt; 	Jakub

Ok,thanks! We will modify as soon as possible!

------------------------------
程璐璐

芯片研发部 

---------------------------------------------------------------------------------------------------------------------
龙芯中科技术有限公司
Loongson Technology Corporation Limited
北京市海淀区北清路中关村环保科技示范园 龙芯产业园 2号楼
Loongson Industrial Park, building 2 , Zhongguancun Environmental 
protection park, Haidian District, Beijing, China
邮编: 100095
电话(Tel):  +86 (10) 62546668-5049
邮箱(Email):  chenglulu@loongson.cn
----------------------------------------------------------------------------------------------------------------------


北京市海淀区中关村环保科技示范园龙芯产业园2号楼100095
电话: +86 (10) 62546668
传真: +86 (10) 62600826
www.loongson.cn
</xuchenghua@loongson.cn></chenglulu@loongson.cn></xry111@mengyan1223.wang></jakub@redhat.com>

本邮件及其附件含有龙芯中科的商业秘密信息,仅限于发送给上面地址中列出的个人或群组。禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制或散发)本邮件及其附件中的信息。如果您错收本邮件,请您立即电话或邮件通知发件人并删除本邮件。 
This email and its attachments contain confidential information from Loongson Technology , which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this email in error, please notify the sender by phone or email immediately and delete it.
  
Lulu Cheng Jan. 23, 2022, 8:16 a.m. UTC | #12
在 2022/1/22 下午5:31, Jakub Jelinek 写道:
> On Sat, Jan 22, 2022 at 05:05:00PM +0800, Xi Ruoyao wrote:
>> On Sat, 2022-01-22 at 16:56 +0800, 程璐璐 wrote:
>>
>>> Under the MIPS architecture, *.opt files are also generated in
>>> $(srcdir).
>> Well, but then you should put the commands for generating those files
>> into contrib/gcc_update instead of Makefile.in, just like MIPS.
> The MIPS does it wrong too.  If the generated file is checked into the
> tree as in the mips case, such a make rule can be there, but it
> should be wrapped with
> ifeq($(ENABLE_MAINTAINER_RULES),true)
> ...
> endif
> or so.
> The point is, when not --enable-maintainer-mode, the gcc tree can be stored
> on read-only filesystem.
> When adding new CPUs, one just uses --enable-maintainer-mode and regenates
> the generated but committed files and commits them together with the
> changes.
> There are many other examples of such generated files, configure,
> Makefile.in from Makefile.am, etc.
>
> 	Jakub

Hi, Mr Jakub:

I have fixed it, could you please take a look.


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/config/loongarch/t-loongarch 
b/gcc/config/loongarch/t-loongarch
index 6ed1a3ab56a..c106be1ec45 100644
--- a/gcc/config/loongarch/t-loongarch
+++ b/gcc/config/loongarch/t-loongarch
@@ -21,7 +21,15 @@ LA_MULTIARCH_TRIPLET = $(patsubst 
LA_MULTIARCH_TRIPLET=%,%,$\
  $(filter LA_MULTIARCH_TRIPLET=%,$(tm_defines)))

  # String definition header
-LA_STR_H = $(srcdir)/config/loongarch/loongarch-str.h
+$(srcdir)/config/loongarch/loongarch-str.h: s-loongarch-str ; @true
+s-loongarch-str: $(srcdir)/config/loongarch/genopts/genstr.sh \
+       $(srcdir)/config/loongarch/genopts/loongarch-strings
+       $(SHELL) $(srcdir)/config/loongarch/genopts/genstr.sh header \
+    $(srcdir)/config/loongarch/genopts/loongarch-strings > \
+    tmp-loongarch-str.h
+       $(SHELL) $(srcdir)/../move-if-change tmp-loongarch-str.h \
+               $(srcdir)/config/loongarch/loongarch-str.h
+       $(STAMP) s-loongarch-str

  loongarch-c.o: $(srcdir)/config/loongarch/loongarch-c.cc $(CONFIG_H) 
$(SYSTEM_H) \
         coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) $(TARGET_H)
@@ -48,12 +56,13 @@ loongarch-cpu.o: 
$(srcdir)/config/loongarch/loongarch-cpu.cc $(LA_STR_H)
  loongarch-def.o: $(srcdir)/config/loongarch/loongarch-def.c $(LA_STR_H)
         $(CC) -c $(ALL_CFLAGS) $(INCLUDES) $<

-$(srcdir)/config/loongarch/loongarch.opt: \
-       $(srcdir)/config/loongarch/genopts/genstr.sh \
+$(srcdir)/config/loongarch/loongarch.opt: s-loongarch-opt ; @true
+s-loongarch-opt: $(srcdir)/config/loongarch/genopts/genstr.sh \
         $(srcdir)/config/loongarch/genopts/loongarch.opt.in
-       $(SHELL) $< opt > $@
+       $(SHELL) $(srcdir)/config/loongarch/genopts/genstr.sh opt \
+    $(srcdir)/config/loongarch/genopts/loongarch.opt.in \
+    > tmp-loongarch.opt
+       $(SHELL) $(srcdir)/../move-if-change tmp-loongarch.opt \
+    $(srcdir)/config/loongarch/loongarch.opt
+       $(STAMP) s-loongarch-opt

-$(LA_STR_H): \
-       $(srcdir)/config/loongarch/genopts/genstr.sh \
-       $(srcdir)/config/loongarch/genopts/loongarch-strings
-       $(SHELL) $< header > $@
  
Lulu Cheng Jan. 23, 2022, 8:39 a.m. UTC | #13
在 2022/1/22 下午4:42, Xi Ruoyao 写道:
> On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
>> +mstrict-align
>> +Target Var(TARGET_STRICT_ALIGN) Init(0)
>> +Do not generate unaligned memory accesses.
> Section 2.1.8 of LoongArch spec says "load/store instruction *may* be
> implemented to allow unaligned memory access".  As it's not a "must",
> should we really enable this by default?

Currently, our main architecture supports this feature. Later, in the 
compiler the value of this macro will be set according to the architecture.
  
Xi Ruoyao Jan. 23, 2022, 9 a.m. UTC | #14
On Sun, 2022-01-23 at 16:39 +0800, 程璐璐 wrote:
> 
> 在 2022/1/22 下午4:42, Xi Ruoyao 写道:
>  
> 
> > On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
> >  
> > 
> > > +mstrict-align
> > > +Target Var(TARGET_STRICT_ALIGN) Init(0)
> > > +Do not generate unaligned memory accesses.
> > Section 2.1.8 of LoongArch spec says "load/store instruction *may* be
> > implemented to allow unaligned memory access".  As it's not a "must",
> > should we really enable this by default?
> Currently, our main architecture supports this feature. Later, in the compiler
> the value of this macro will be set according to the architecture.

My suggestion is to make -mstrict-align default for the default
('-march=loongarch64'), as it should generate code working on every
architecture following the spec.  And, -mno-strict-align should be the
default of -march=la464, which is the current main architecture
supporting unaligned access.
  
Lulu Cheng Jan. 23, 2022, 9:28 a.m. UTC | #15
在 2022/1/23 下午5:00, Xi Ruoyao 写道:
> On Sun, 2022-01-23 at 16:39 +0800, 程璐璐 wrote:
>> 在 2022/1/22 下午4:42, Xi Ruoyao 写道:
>>   
>>
>>> On Sat, 2022-01-22 at 15:55 +0800, Chenghua Xu wrote:
>>>   
>>>
>>>> +mstrict-align
>>>> +Target Var(TARGET_STRICT_ALIGN) Init(0)
>>>> +Do not generate unaligned memory accesses.
>>> Section 2.1.8 of LoongArch spec says "load/store instruction *may* be
>>> implemented to allow unaligned memory access".  As it's not a "must",
>>> should we really enable this by default?
>> Currently, our main architecture supports this feature. Later, in the compiler
>> the value of this macro will be set according to the architecture.
> My suggestion is to make -mstrict-align default for the default
> ('-march=loongarch64'), as it should generate code working on every
> architecture following the spec.  And, -mno-strict-align should be the
> default of -march=la464, which is the current main architecture
> supporting unaligned access.

Ok we will consider your suggestion!
  

Patch

diff --git a/gcc/common/config/loongarch/loongarch-common.cc b/gcc/common/config/loongarch/loongarch-common.cc
new file mode 100644
index 00000000000..1d6f370a013
--- /dev/null
+++ b/gcc/common/config/loongarch/loongarch-common.cc
@@ -0,0 +1,73 @@ 
+/* Common hooks for LoongArch.
+   Copyright (C) 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
+<http://www.gnu.org/licenses/>.  */
+
+#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 }
+};
+
+/* Implement TARGET_HANDLE_OPTION.  */
+
+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)
+{
+  size_t code = decoded->opt_index;
+  int value = decoded->value;
+
+  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;
+
+    default:
+      return true;
+    }
+}
+
+#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
+
+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 2c4266ce7b0..ab1f97ce487 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"
@@ -2494,6 +2501,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"
@@ -3600,7 +3621,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
@@ -4930,6 +4951,348 @@  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
+
+		# Inferring 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"
+		triplet_abi+=""
+
+		# Getting 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}"
+
+		## 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"
 
@@ -5367,6 +5730,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.
diff --git a/gcc/config/loongarch/genopts/genstr.sh b/gcc/config/loongarch/genopts/genstr.sh
new file mode 100755
index 00000000000..62a0a0770a2
--- /dev/null
+++ b/gcc/config/loongarch/genopts/genstr.sh
@@ -0,0 +1,91 @@ 
+#!/bin/sh
+# A simple script that generates loongarch-str.h and loongarch.opt
+# from genopt/loongarch-optstr.
+#
+# Copyright (C) 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
+# <http://www.gnu.org/licenses/>.
+
+cd "$(dirname "$0")"
+
+# Generate a header containing definitions from the string table.
+gen_defines() {
+    cat <<EOF
+/* Generated automatically by "genstr" from "loongarch-strings".
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+#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 "@@<KEY>@@" to "<VALUE>" 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
+
+	# 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..553304f9b83
--- /dev/null
+++ b/gcc/config/loongarch/genopts/loongarch-strings
@@ -0,0 +1,58 @@ 
+# Defines the key strings for LoongArch compiler options.
+#
+# Copyright (C) 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
+# <http://www.gnu.org/licenses/>.
+
+# -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..08950a32179
--- /dev/null
+++ b/gcc/config/loongarch/genopts/loongarch.opt.in
@@ -0,0 +1,189 @@ 
+; Generated by "genstr" from the template "loongarch.opt.in"
+; and definitions from "loongarch-strings".
+;
+; Copyright (C) 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
+; <http://www.gnu.org/licenses/>.
+;
+
+; 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)
+Don't optimize block moves.
+
+mlra
+Target Var(loongarch_lra_flag) Init(1) Save
+Use LRA instead of reload.
+
+noasmopt
+Driver
+
+mstrict-align
+Target Mask(STRICT_ALIGN) Save
+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..22c3b3cbdbc
--- /dev/null
+++ b/gcc/config/loongarch/gnu-user.h
@@ -0,0 +1,84 @@ 
+/* Definitions for LoongArch systems using GNU (glibc-based) userspace,
+   or other userspace with libc derived from glibc.
+   Copyright (C) 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
+<http://www.gnu.org/licenses/>.  */
+
+/* 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)
+
+
+#undef ASM_DECLARE_OBJECT_NAME
+#define ASM_DECLARE_OBJECT_NAME loongarch_declare_object_name
diff --git a/gcc/config/loongarch/linux.h b/gcc/config/loongarch/linux.h
new file mode 100644
index 00000000000..a6206de2681
--- /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 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
+<http://www.gnu.org/licenses/>.  */
+
+/* Default system library search paths.
+ * This ensures that a compiler configured with --disable-multilib
+ * can work in a multilib environment.  */
+
+#if defined(__DISABLE_MULTILIB) && defined(__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..384fb54392c
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-cpu.cc
@@ -0,0 +1,206 @@ 
+/* Definitions for LoongArch CPU properties.
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+#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
+<http://www.gnu.org/licenses/>.  */
+
+#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..bc22a55edb0
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-def.c
@@ -0,0 +1,164 @@ 
+/* LoongArch static properties.
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+#include "loongarch-def.h"
+#include "loongarch-str.h"
+
+/* 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..84c27271a69
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-def.h
@@ -0,0 +1,151 @@ 
+/* LoongArch definitions.
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+/* 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..79ab0b9138a
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-driver.cc
@@ -0,0 +1,187 @@ 
+/* Subroutines for the gcc driver.
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+#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 "<option>=".  */
+#undef MATCH_OPT
+#define MATCH_OPT(NAME) \
+  (strncmp (argv[0], OPTSTR_##NAME "=", \
+	    (parm_off = sizeof (OPTSTR_##NAME))) == 0)
+
+  if (strcmp (argv[0], "no_link") == 0)
+    {
+      no_link = 1;
+    }
+  else if (MATCH_OPT (ABI_BASE))
+    {
+      LARCH_DRIVER_SET_M_FLAG (
+	loongarch_abi_base_strings, N_ABI_BASE_TYPES,
+	opt_abi_base_driver, PARM)
+    }
+  else if (MATCH_OPT (ISA_EXT_FPU))
+    {
+      LARCH_DRIVER_SET_M_FLAG (loongarch_isa_ext_strings, N_ISA_EXT_FPU_TYPES,
+			       opt_fpu_driver, PARM)
+    }
+  else if (MATCH_OPT (ARCH))
+    {
+      LARCH_DRIVER_SET_M_FLAG (loongarch_cpu_strings, N_ARCH_TYPES,
+			       opt_arch_driver, PARM)
+    }
+  else if (MATCH_OPT (TUNE))
+    {
+      LARCH_DRIVER_SET_M_FLAG (loongarch_cpu_strings, N_TUNE_TYPES,
+			       opt_tune_driver, PARM)
+    }
+  else if (MATCH_OPT (CMODEL))
+    {
+      LARCH_DRIVER_SET_M_FLAG (loongarch_cmodel_strings, N_CMODEL_TYPES,
+			       opt_cmodel_driver, PARM)
+    }
+  else /* switches */
+    {
+      int switch_idx = M_OPTION_NOT_SEEN;
+
+      LARCH_DRIVER_SET_M_FLAG (loongarch_switch_strings, N_SWITCH_TYPES,
+			       switch_idx, argv[0])
+
+      if (switch_idx != M_OPTION_NOT_SEEN)
+	opt_switches |= loongarch_switch_mask[switch_idx];
+    }
+  return "";
+}
+
+const char*
+driver_get_normalized_m_opts (int argc, const char **argv)
+{
+  if (argc != 0)
+    {
+      (void) argv;  /* To make compiler shut up about unused argument.  */
+      return " %eget_normalized_m_opts requires no argument.\n";
+    }
+
+  loongarch_config_target (& la_target,
+			   opt_switches,
+			   opt_arch_driver,
+			   opt_tune_driver,
+			   opt_fpu_driver,
+			   opt_abi_base_driver,
+			   opt_abi_ext_driver,
+			   opt_cmodel_driver,
+			   !no_link /* follow_multilib_list */);
+
+  /* Output normalized option strings.  */
+  obstack_blank (&opts_obstack, 0);
+
+#undef APPEND_LTR
+#define APPEND_LTR(S) \
+  obstack_grow (&opts_obstack, (const void*) (S), \
+		sizeof ((S)) / sizeof (char) -1)
+
+#undef APPEND_VAL
+#define APPEND_VAL(S) \
+  obstack_grow (&opts_obstack, (const void*) (S), strlen ((S)))
+
+#undef APPEND_OPT
+#define APPEND_OPT(NAME) \
+   APPEND_LTR (" %<m" OPTSTR_##NAME "=* " \
+	       " -m" OPTSTR_##NAME "=")
+
+  for (int i = 0; i < N_SWITCH_TYPES; i++)
+    {
+      APPEND_LTR (" %<m");
+      APPEND_VAL (loongarch_switch_strings[i]);
+    }
+
+  APPEND_OPT (ABI_BASE);
+  APPEND_VAL (loongarch_abi_base_strings[la_target.abi.base]);
+
+  APPEND_OPT (ARCH);
+  APPEND_VAL (loongarch_cpu_strings[la_target.cpu_arch]);
+
+  APPEND_OPT (ISA_EXT_FPU);
+  APPEND_VAL (loongarch_isa_ext_strings[la_target.isa.fpu]);
+
+  APPEND_OPT (CMODEL);
+  APPEND_VAL (loongarch_cmodel_strings[la_target.cmodel]);
+
+  APPEND_OPT (TUNE);
+  APPEND_VAL (loongarch_cpu_strings[la_target.cpu_tune]);
+
+  obstack_1grow (&opts_obstack, '\0');
+
+  return XOBFINISH (&opts_obstack, const char *);
+}
diff --git a/gcc/config/loongarch/loongarch-driver.h b/gcc/config/loongarch/loongarch-driver.h
new file mode 100644
index 00000000000..ce0222748dd
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-driver.h
@@ -0,0 +1,69 @@ 
+/* Subroutine headers for the gcc driver.
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef LOONGARCH_DRIVER_H
+#define LOONGARCH_DRIVER_H
+
+#include "loongarch-str.h"
+
+extern const char*
+driver_set_m_flag (int argc, const char **argv);
+
+extern const char*
+driver_get_normalized_m_opts (int argc, const char **argv);
+
+#define EXTRA_SPEC_FUNCTIONS \
+  { "set_m_flag", driver_set_m_flag  }, \
+  { "get_normalized_m_opts", driver_get_normalized_m_opts  },
+
+/* Pre-process ABI-related options.  */
+#define LA_SET_PARM_SPEC(NAME) \
+  " %{m" OPTSTR_##NAME  "=*: %:set_m_flag(" OPTSTR_##NAME "=%*)}" \
+
+#define LA_SET_FLAG_SPEC(NAME) \
+  " %{m" OPTSTR_##NAME  ": %:set_m_flag(" OPTSTR_##NAME ")}" \
+
+#define DRIVER_HANDLE_MACHINE_OPTIONS			      \
+  " %{c|S|E|nostdlib: %:set_m_flag(no_link)}"		      \
+  " %{nostartfiles: %{nodefaultlibs: %:set_m_flag(no_link)}}" \
+  LA_SET_PARM_SPEC (ABI_BASE)				      \
+  LA_SET_PARM_SPEC (ARCH)				      \
+  LA_SET_PARM_SPEC (TUNE)				      \
+  LA_SET_PARM_SPEC (ISA_EXT_FPU)			      \
+  LA_SET_PARM_SPEC (CMODEL)				      \
+  LA_SET_FLAG_SPEC (SOFT_FLOAT)				      \
+  LA_SET_FLAG_SPEC (SINGLE_FLOAT)			      \
+  LA_SET_FLAG_SPEC (DOUBLE_FLOAT)			      \
+  " %:get_normalized_m_opts()"
+
+#define DRIVER_SELF_SPECS \
+  DRIVER_HANDLE_MACHINE_OPTIONS
+
+/* ABI spec strings.  */
+#define ABI_GRLEN_SPEC \
+  "%{mabi=lp64*:64}"   \
+
+#define ABI_SPEC \
+  "%{mabi=lp64d:lp64d}" \
+  "%{mabi=lp64f:lp64f}" \
+  "%{mabi=lp64s:lp64s}" \
+
+#endif /* LOONGARCH_DRIVER_H */
+
diff --git a/gcc/config/loongarch/loongarch-opts.cc b/gcc/config/loongarch/loongarch-opts.cc
new file mode 100644
index 00000000000..4bd498fd62b
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-opts.cc
@@ -0,0 +1,580 @@ 
+/* Subroutines for loongarch-specific option handling.
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+#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-cpu.h"
+#include "loongarch-opts.h"
+#include "loongarch-str.h"
+
+struct loongarch_target la_target;
+
+/* ABI-related configuration.  */
+#define ABI_COUNT (sizeof(abi_priority_list)/sizeof(struct loongarch_abi))
+static const struct loongarch_abi
+abi_priority_list[] = {
+    {ABI_BASE_LP64D, ABI_EXT_BASE},
+    {ABI_BASE_LP64F, ABI_EXT_BASE},
+    {ABI_BASE_LP64S, ABI_EXT_BASE},
+};
+
+/* Initialize enabled_abi_types from TM_MULTILIB_LIST.  */
+#ifdef __DISABLE_MULTILIB
+#define MULTILIB_LIST_LEN 1
+#else
+#define MULTILIB_LIST_LEN (sizeof (tm_multilib_list) / sizeof (int) / 2)
+static const int tm_multilib_list[] = { TM_MULTILIB_LIST };
+#endif
+static int enabled_abi_types[N_ABI_BASE_TYPES][N_ABI_EXT_TYPES] = { 0 };
+
+#define isa_required(ABI) (abi_minimal_isa[(ABI).base][(ABI).ext])
+extern "C" const struct loongarch_isa
+abi_minimal_isa[N_ABI_BASE_TYPES][N_ABI_EXT_TYPES];
+
+static inline int
+is_multilib_enabled (struct loongarch_abi abi)
+{
+  return enabled_abi_types[abi.base][abi.ext];
+}
+
+static void
+init_enabled_abi_types ()
+{
+#ifdef __DISABLE_MULTILIB
+  enabled_abi_types[DEFAULT_ABI_BASE][DEFAULT_ABI_EXT] = 1;
+#else
+  int abi_base, abi_ext;
+  for (unsigned int i = 0; i < MULTILIB_LIST_LEN; i++)
+    {
+      abi_base = tm_multilib_list[i << 1];
+      abi_ext = tm_multilib_list[(i << 1) + 1];
+      enabled_abi_types[abi_base][abi_ext] = 1;
+    }
+#endif
+}
+
+/* Switch masks.  */
+#undef M
+#define M(NAME) OPTION_MASK_##NAME
+const int loongarch_switch_mask[N_SWITCH_TYPES] = {
+  /* SW_SOFT_FLOAT */    M(FORCE_SOFTF),
+  /* SW_SINGLE_FLOAT */  M(FORCE_F32),
+  /* SW_DOUBLE_FLOAT */  M(FORCE_F64),
+};
+#undef M
+
+/* String processing.  */
+static struct obstack msg_obstack;
+#define APPEND_STRING(STR) obstack_grow (&msg_obstack, STR, strlen(STR));
+#define APPEND1(CH) obstack_1grow(&msg_obstack, CH);
+
+static const char* abi_str (struct loongarch_abi abi);
+static const char* isa_str (const struct loongarch_isa *isa, char separator);
+static const char* arch_str (const struct loongarch_target *target);
+static const char* multilib_enabled_abi_list ();
+
+/* Misc */
+static struct loongarch_abi isa_default_abi (const struct loongarch_isa *isa);
+static int isa_base_compat_p (const struct loongarch_isa *set1,
+			      const struct loongarch_isa *set2);
+static int isa_fpu_compat_p (const struct loongarch_isa *set1,
+			     const struct loongarch_isa *set2);
+static int abi_compat_p (const struct loongarch_isa *isa,
+			 struct loongarch_abi abi);
+static int abi_default_cpu_arch (struct loongarch_abi abi);
+
+/* Checking configure-time defaults.  */
+#ifndef DEFAULT_ABI_BASE
+#error missing definition of DEFAULT_ABI_BASE in ${tm_defines}.
+#endif
+
+#ifndef DEFAULT_ABI_EXT
+#error missing definition of DEFAULT_ABI_EXT in ${tm_defines}.
+#endif
+
+#ifndef DEFAULT_CPU_ARCH
+#error missing definition of DEFAULT_CPU_ARCH in ${tm_defines}.
+#endif
+
+#ifndef DEFAULT_ISA_EXT_FPU
+#error missing definition of DEFAULT_ISA_EXT_FPU in ${tm_defines}.
+#endif
+
+/* Handle combinations of -m machine option values
+   (see loongarch.opt and loongarch-opts.h).  */
+void
+loongarch_config_target (struct loongarch_target *target,
+			 HOST_WIDE_INT opt_switches,
+			 int opt_arch, int opt_tune, int opt_fpu,
+			 int opt_abi_base, int opt_abi_ext,
+			 int opt_cmodel, int follow_multilib_list)
+{
+  struct loongarch_target t;
+
+  if (!target)
+    return;
+
+  /* Initialization */
+  init_enabled_abi_types ();
+  obstack_init (&msg_obstack);
+
+  struct {
+    int arch, tune, fpu, abi_base, abi_ext, cmodel;
+  } constrained = {
+      M_OPT_ABSENT(opt_arch)     ? 0 : 1,
+      M_OPT_ABSENT(opt_tune)     ? 0 : 1,
+      M_OPT_ABSENT(opt_fpu)      ? 0 : 1,
+      M_OPT_ABSENT(opt_abi_base) ? 0 : 1,
+      M_OPT_ABSENT(opt_abi_ext)  ? 0 : 1,
+      M_OPT_ABSENT(opt_cmodel)   ? 0 : 1,
+  };
+
+#define on(NAME) ((loongarch_switch_mask[(SW_##NAME)] & opt_switches) \
+		  && (on_switch = (SW_##NAME), 1))
+  int on_switch;
+
+  /* 1.  Target ABI */
+  t.abi.base = constrained.abi_base ? opt_abi_base : DEFAULT_ABI_BASE;
+
+  t.abi.ext = constrained.abi_ext ? opt_abi_ext : DEFAULT_ABI_EXT;
+
+  /* Extra switch handling.  */
+  if (on (SOFT_FLOAT) || on (SINGLE_FLOAT) || on (DOUBLE_FLOAT))
+    {
+      switch (on_switch)
+	{
+	  case SW_SOFT_FLOAT:
+	    opt_fpu = ISA_EXT_NOFPU;
+	    break;
+
+	  case SW_SINGLE_FLOAT:
+	    opt_fpu = ISA_EXT_FPU32;
+	    break;
+
+	  case SW_DOUBLE_FLOAT:
+	    opt_fpu = ISA_EXT_FPU64;
+	    break;
+
+	  default:
+	    gcc_unreachable();
+	}
+      constrained.fpu = 1;
+
+      /* The target ISA is not ready yet, but (isa_required (t.abi)
+	 + forced fpu) is enough for computing the forced base ABI.  */
+      struct loongarch_isa default_isa = isa_required (t.abi);
+      struct loongarch_isa force_isa = default_isa;
+      struct loongarch_abi force_abi = t.abi;
+      force_isa.fpu = opt_fpu;
+      force_abi.base = isa_default_abi (&force_isa).base;
+
+      if (isa_fpu_compat_p (&default_isa, &force_isa));
+	/* Keep quiet if -m*-float does not promote the FP ABI.  */
+      else if (constrained.abi_base && (t.abi.base != force_abi.base))
+	inform (UNKNOWN_LOCATION,
+		"%<-m%s%> overrides %<-m%s=%s%>, promoting ABI to %qs",
+		loongarch_switch_strings[on_switch],
+		OPTSTR_ABI_BASE, loongarch_abi_base_strings[t.abi.base],
+		abi_str (force_abi));
+
+      t.abi.base = force_abi.base;
+    }
+
+#ifdef __DISABLE_MULTILIB
+  if (follow_multilib_list)
+    if (t.abi.base != DEFAULT_ABI_BASE || t.abi.ext != DEFAULT_ABI_EXT)
+      {
+	static const struct loongarch_abi default_abi
+	  = {DEFAULT_ABI_BASE, DEFAULT_ABI_EXT};
+
+	warning (0, "ABI changed (%qs to %qs) while multilib is disabled",
+		 abi_str (default_abi), abi_str (t.abi));
+      }
+#endif
+
+  /* 2.  Target CPU */
+  t.cpu_arch = constrained.arch ? opt_arch : DEFAULT_CPU_ARCH;
+
+  t.cpu_tune = constrained.tune ? opt_tune
+    : (constrained.arch ? DEFAULT_CPU_ARCH : DEFAULT_CPU_TUNE);
+
+#ifdef __loongarch__
+  /* For native compilers, gather local CPU information
+     and fill the "CPU_NATIVE" index of arrays defined in
+     loongarch-cpu.c.  */
+
+  t.cpu_native = fill_native_cpu_config (t.cpu_arch == CPU_NATIVE,
+					 t.cpu_tune == CPU_NATIVE);
+
+#else
+  if (t.cpu_arch == CPU_NATIVE)
+    fatal_error (UNKNOWN_LOCATION,
+		 "%qs does not work on a cross compiler",
+		 "-m" OPTSTR_ARCH "=" STR_CPU_NATIVE);
+
+  else if (t.cpu_tune == CPU_NATIVE)
+    fatal_error (UNKNOWN_LOCATION,
+		 "%qs does not work on a cross compiler",
+		 "-m" OPTSTR_TUNE "=" STR_CPU_NATIVE);
+#endif
+
+  /* 3.  Target ISA */
+config_target_isa:
+
+  /* Get default ISA from "-march" or its default value.  */
+  t.isa = loongarch_cpu_default_isa[__ACTUAL_ARCH];
+
+  /* Apply incremental changes.  */
+  /* "-march=native" overrides the default FPU type.  */
+  t.isa.fpu = constrained.fpu ? opt_fpu :
+    ((t.cpu_arch == CPU_NATIVE && constrained.arch) ?
+     t.isa.fpu : DEFAULT_ISA_EXT_FPU);
+
+
+  /* 4.  ABI-ISA compatibility */
+  /* Note:
+     - There IS a unique default -march value for each ABI type
+       (config.gcc: triplet -> abi -> default arch).
+
+     - If the base ABI is incompatible with the default arch,
+       try using the default -march it implies (and mark it
+       as "constrained" this time), then re-apply step 3.
+  */
+  struct loongarch_abi abi_tmp;
+  const struct loongarch_isa* isa_min;
+
+  abi_tmp = t.abi;
+  isa_min = &isa_required (abi_tmp);
+
+  if (isa_base_compat_p (&t.isa, isa_min)); /* OK.  */
+  else if (!constrained.arch)
+    {
+      /* Base architecture can only be implied by -march,
+	 so we adjust that first if it is not constrained.  */
+      int fallback_arch = abi_default_cpu_arch (t.abi);
+
+      if (t.cpu_arch == CPU_NATIVE)
+	warning (0, "your native CPU architecture (%qs) "
+		 "does not support %qs ABI, falling back to %<-m%s=%s%>",
+		 arch_str (&t), abi_str (t.abi), OPTSTR_ARCH,
+		 loongarch_cpu_strings[fallback_arch]);
+      else
+	warning (0, "default CPU architecture (%qs) "
+		 "does not support %qs ABI, falling back to %<-m%s=%s%>",
+		 arch_str (&t), abi_str (t.abi), OPTSTR_ARCH,
+		 loongarch_cpu_strings[fallback_arch]);
+
+      t.cpu_arch = fallback_arch;
+      constrained.arch = 1;
+      goto config_target_isa;
+    }
+  else if (!constrained.abi_base)
+    {
+      /* If -march is given while -mabi is not,
+	 try selecting another base ABI type.  */
+      abi_tmp.base = isa_default_abi (&t.isa).base;
+    }
+  else
+    goto fatal;
+
+  if (isa_fpu_compat_p (&t.isa, isa_min)); /* OK.  */
+  else if (!constrained.fpu)
+    t.isa.fpu = isa_min->fpu;
+  else if (!constrained.abi_base)
+      /* If -march is compatible with the default ABI
+	 while -mfpu is not.  */
+    abi_tmp.base = isa_default_abi (&t.isa).base;
+  else
+    goto fatal;
+
+  if (0)
+fatal:
+    fatal_error (UNKNOWN_LOCATION,
+		 "unable to implement ABI %qs with instruction set %qs",
+		 abi_str (t.abi), isa_str (&t.isa, '/'));
+
+
+  /* Using the fallback ABI.  */
+  if (abi_tmp.base != t.abi.base || abi_tmp.ext != t.abi.ext)
+    {
+      /* This flag is only set in the GCC driver.  */
+      if (follow_multilib_list)
+	{
+
+	  /* Continue falling back until we find a feasible ABI type
+	     enabled by TM_MULTILIB_LIST.  */
+	  if (!is_multilib_enabled (abi_tmp))
+	    {
+	      for (unsigned int i = 0; i < ABI_COUNT; i++)
+		{
+		  if (is_multilib_enabled (abi_priority_list[i])
+		      && abi_compat_p (&t.isa, abi_priority_list[i]))
+		    {
+		      abi_tmp = abi_priority_list[i];
+
+		      warning (0, "ABI %qs cannot be implemented due to "
+			       "limited instruction set %qs, "
+			       "falling back to %qs", abi_str (t.abi),
+			       isa_str (&t.isa, '/'), abi_str (abi_tmp));
+
+		      goto fallback;
+		    }
+		}
+
+	      /* Otherwise, keep using abi_tmp with a warning.  */
+#ifdef __DISABLE_MULTILIB
+	      warning (0, "instruction set %qs cannot implement "
+		       "default ABI %qs, falling back to %qs",
+		       isa_str (&t.isa, '/'), abi_str (t.abi),
+		       abi_str (abi_tmp));
+#else
+	      warning (0, "no multilib-enabled ABI (%qs) can be implemented "
+		       "with instruction set %qs, falling back to %qs",
+		       multilib_enabled_abi_list (),
+		       isa_str (&t.isa, '/'), abi_str (abi_tmp));
+#endif
+	    }
+	}
+
+fallback:
+      t.abi = abi_tmp;
+    }
+  else if (follow_multilib_list)
+    {
+      if (!is_multilib_enabled (t.abi))
+	{
+	  inform (UNKNOWN_LOCATION,
+		  "ABI %qs is not enabled at configure-time, "
+		  "the linker might report an error", abi_str (t.abi));
+
+	  inform (UNKNOWN_LOCATION, "ABI with startfiles: %s",
+		  multilib_enabled_abi_list ());
+	}
+    }
+
+
+  /* 5.  Target code model */
+  t.cmodel = constrained.cmodel ? opt_cmodel : CMODEL_NORMAL;
+
+  /* cleanup and return */
+  obstack_free (&msg_obstack, NULL);
+  *target = t;
+}
+
+/* Returns the default ABI for the given instruction set.  */
+static inline struct loongarch_abi
+isa_default_abi (const struct loongarch_isa *isa)
+{
+  struct loongarch_abi abi;
+
+  switch (isa->fpu)
+    {
+      case ISA_EXT_FPU64:
+	if (isa->base == ISA_BASE_LA64V100)
+	  abi.base = ABI_BASE_LP64D;
+	break;
+
+      case ISA_EXT_FPU32:
+	if (isa->base == ISA_BASE_LA64V100)
+	  abi.base = ABI_BASE_LP64F;
+	break;
+
+      case ISA_EXT_NOFPU:
+	if (isa->base == ISA_BASE_LA64V100)
+	  abi.base = ABI_BASE_LP64S;
+	break;
+
+      default:
+	gcc_unreachable ();
+    }
+
+  abi.ext = ABI_EXT_BASE;
+  return abi;
+}
+
+/* Check if set2 is a subset of set1.  */
+static inline int
+isa_base_compat_p (const struct loongarch_isa *set1,
+		   const struct loongarch_isa *set2)
+{
+  switch (set2->base)
+    {
+      case ISA_BASE_LA64V100:
+	return (set1->base == ISA_BASE_LA64V100);
+
+      default:
+	gcc_unreachable ();
+    }
+}
+
+static inline int
+isa_fpu_compat_p (const struct loongarch_isa *set1,
+		  const struct loongarch_isa *set2)
+{
+  switch (set2->fpu)
+    {
+      case ISA_EXT_FPU64:
+	return set1->fpu == ISA_EXT_FPU64;
+
+      case ISA_EXT_FPU32:
+	return set1->fpu == ISA_EXT_FPU32 || set1->fpu == ISA_EXT_FPU64;
+
+      case ISA_EXT_NOFPU:
+	return 1;
+
+      default:
+	gcc_unreachable ();
+    }
+
+}
+
+static inline int
+abi_compat_p (const struct loongarch_isa *isa, struct loongarch_abi abi)
+{
+  int compatible = 1;
+  const struct loongarch_isa *isa2 = &isa_required (abi);
+
+  /* Append conditionals for new ISA components below.  */
+  compatible = compatible && isa_base_compat_p (isa, isa2);
+  compatible = compatible && isa_fpu_compat_p (isa, isa2);
+  return compatible;
+}
+
+/* The behavior of this function should be consistent
+   with config.gcc.  */
+static inline int
+abi_default_cpu_arch (struct loongarch_abi abi)
+{
+  switch (abi.base)
+    {
+      case ABI_BASE_LP64D:
+      case ABI_BASE_LP64F:
+      case ABI_BASE_LP64S:
+	if (abi.ext == ABI_EXT_BASE)
+	  return CPU_LOONGARCH64;
+    }
+  gcc_unreachable ();
+}
+
+static const char*
+abi_str (struct loongarch_abi abi)
+{
+  /* "/base" can be omitted */
+  if (abi.ext == ABI_EXT_BASE)
+    return (const char*)
+      obstack_copy0 (&msg_obstack, loongarch_abi_base_strings[abi.base],
+		     strlen (loongarch_abi_base_strings[abi.base]));
+  else
+    {
+      APPEND_STRING (loongarch_abi_base_strings[abi.base])
+      APPEND1 ('/')
+      APPEND_STRING (loongarch_abi_ext_strings[abi.ext])
+      APPEND1 ('\0')
+
+      return XOBFINISH (&msg_obstack, const char *);
+    }
+}
+
+static const char*
+isa_str (const struct loongarch_isa *isa, char separator)
+{
+  APPEND_STRING (loongarch_isa_base_strings[isa->base])
+  APPEND1 (separator)
+
+  if (isa->fpu == ISA_EXT_NOFPU)
+    {
+      APPEND_STRING ("no" OPTSTR_ISA_EXT_FPU)
+    }
+  else
+    {
+      APPEND_STRING (OPTSTR_ISA_EXT_FPU)
+      APPEND_STRING (loongarch_isa_ext_strings[isa->fpu])
+    }
+  APPEND1 ('\0')
+
+  /* Add more here.  */
+
+  return XOBFINISH (&msg_obstack, const char *);
+}
+
+static const char*
+arch_str (const struct loongarch_target *target)
+{
+  if (target->cpu_arch == CPU_NATIVE)
+    {
+      if (target->cpu_native == CPU_NATIVE)
+	{
+	  /* Describe a native CPU with unknown PRID.  */
+	  const char* isa_string = isa_str (&target->isa, ',');
+	  APPEND_STRING ("PRID: 0x")
+	  APPEND_STRING (get_native_prid_str ())
+	  APPEND_STRING (", ISA features: ")
+	  APPEND_STRING (isa_string)
+	  APPEND1 ('\0')
+	}
+      else
+	APPEND_STRING (loongarch_cpu_strings[target->cpu_native]);
+    }
+  else
+    APPEND_STRING (loongarch_cpu_strings[target->cpu_arch]);
+
+  APPEND1 ('\0')
+  return XOBFINISH (&msg_obstack, const char *);
+}
+
+static const char*
+multilib_enabled_abi_list ()
+{
+  int enabled_abi_idx[MULTILIB_LIST_LEN] = { 0 };
+  const char* enabled_abi_str[MULTILIB_LIST_LEN] = { NULL };
+  unsigned int j = 0;
+
+  for (unsigned int i = 0; i < ABI_COUNT && j < MULTILIB_LIST_LEN; i++)
+    {
+      if (enabled_abi_types[abi_priority_list[i].base]
+	  [abi_priority_list[i].ext])
+	{
+	  enabled_abi_idx[j++] = i;
+	}
+    }
+
+  for (unsigned int k = 0; k < j; k++)
+    {
+      enabled_abi_str[k] = abi_str (abi_priority_list[enabled_abi_idx[k]]);
+    }
+
+  for (unsigned int k = 0; k < j - 1; k++)
+    {
+      APPEND_STRING (enabled_abi_str[k])
+      APPEND1 (',')
+      APPEND1 (' ')
+    }
+  APPEND_STRING (enabled_abi_str[j - 1])
+  APPEND1 ('\0')
+
+  return XOBFINISH (&msg_obstack, const char *);
+}
diff --git a/gcc/config/loongarch/loongarch-opts.h b/gcc/config/loongarch/loongarch-opts.h
new file mode 100644
index 00000000000..9c205e01980
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-opts.h
@@ -0,0 +1,86 @@ 
+/* Definitions for loongarch-specific option handling.
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef LOONGARCH_OPTS_H
+#define LOONGARCH_OPTS_H
+
+
+/* Target configuration */
+extern struct loongarch_target la_target;
+
+/* Switch masks */
+extern const int loongarch_switch_mask[];
+
+#include "loongarch-def.h"
+
+#if !defined(IN_LIBGCC2) && !defined(IN_TARGET_LIBS) && !defined(IN_RTS)
+/* Handler for "-m" option combinations,
+   shared by the driver and the compiler proper.  */
+void
+loongarch_config_target (struct loongarch_target *target,
+  HOST_WIDE_INT opt_switches,
+  int opt_arch, int opt_tune, int opt_fpu,
+  int opt_abi_base, int opt_abi_ext,
+  int opt_cmodel, int follow_multilib_list);
+#endif
+
+
+/* Macros for common conditional expressions used in loongarch.{c,h,md} */
+#define TARGET_CMODEL_NORMAL	    (la_target.cmodel == CMODEL_NORMAL)
+#define TARGET_CMODEL_TINY	    (la_target.cmodel == CMODEL_TINY)
+#define TARGET_CMODEL_TINY_STATIC   (la_target.cmodel == CMODEL_TINY_STATIC)
+#define TARGET_CMODEL_LARGE	    (la_target.cmodel == CMODEL_LARGE)
+#define TARGET_CMODEL_EXTREME	    (la_target.cmodel == CMODEL_EXTREME)
+
+#define TARGET_HARD_FLOAT	    (la_target.isa.fpu != ISA_EXT_NOFPU)
+#define TARGET_HARD_FLOAT_ABI	    (la_target.abi.base == ABI_BASE_LP64D \
+				     || la_target.abi.base == ABI_BASE_LP64F)
+
+#define TARGET_SOFT_FLOAT	  (la_target.isa.fpu == ISA_EXT_NOFPU)
+#define TARGET_SOFT_FLOAT_ABI	  (la_target.abi.base == ABI_BASE_LP64S)
+#define TARGET_SINGLE_FLOAT	  (la_target.isa.fpu == ISA_EXT_FPU32)
+#define TARGET_SINGLE_FLOAT_ABI	  (la_target.abi.base == ABI_BASE_LP64F)
+#define TARGET_DOUBLE_FLOAT	  (la_target.isa.fpu == ISA_EXT_FPU64)
+#define TARGET_DOUBLE_FLOAT_ABI	  (la_target.abi.base == ABI_BASE_LP64D)
+
+#define TARGET_64BIT		  (la_target.isa.base == ISA_BASE_LA64V100)
+#define TARGET_ABI_LP64	  (la_target.abi.base == ABI_BASE_LP64D \
+				   || la_target.abi.base == ABI_BASE_LP64F \
+				   || la_target.abi.base == ABI_BASE_LP64S)
+
+#define TARGET_ARCH_NATIVE	  (la_target.cpu_arch == CPU_NATIVE)
+#define __ACTUAL_ARCH		  (TARGET_ARCH_NATIVE \
+				   ? (la_target.cpu_native < N_ARCH_TYPES \
+				      ? (la_target.cpu_native) : (CPU_NATIVE)) \
+				      : (la_target.cpu_arch))
+
+#define TARGET_TUNE_NATIVE	(la_target.cpu_tune == CPU_NATIVE)
+#define __ACTUAL_TUNE		(TARGET_TUNE_NATIVE \
+				 ? (la_target.cpu_native < N_TUNE_TYPES \
+				    ? (la_target.cpu_native) : (CPU_NATIVE)) \
+				    : (la_target.cpu_tune))
+
+#define TARGET_ARCH_LOONGARCH64	  (__ACTUAL_ARCH == CPU_LOONGARCH64)
+#define TARGET_ARCH_LA464	  (__ACTUAL_ARCH == CPU_LA464)
+
+#define TARGET_TUNE_LOONGARCH64	  (__ACTUAL_TUNE == CPU_LOONGARCH64)
+#define TARGET_TUNE_LA464	  (__ACTUAL_TUNE == CPU_LA464)
+
+#endif /* LOONGARCH_OPTS_H */
diff --git a/gcc/config/loongarch/loongarch-str.h b/gcc/config/loongarch/loongarch-str.h
new file mode 100644
index 00000000000..4f0a76cdc28
--- /dev/null
+++ b/gcc/config/loongarch/loongarch-str.h
@@ -0,0 +1,57 @@ 
+/* Generated automatically by "genstr" from "loongarch-strings".
+   Copyright (C) 2021 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
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef LOONGARCH_STR_H
+#define LOONGARCH_STR_H
+
+#define OPTSTR_ARCH "arch"
+#define OPTSTR_TUNE "tune"
+
+#define STR_CPU_NATIVE "native"
+#define STR_CPU_LOONGARCH64 "loongarch64"
+#define STR_CPU_LA464 "la464"
+
+#define STR_ISA_BASE_LA64V100 "la64"
+
+#define OPTSTR_ISA_EXT_FPU "fpu"
+#define STR_ISA_EXT_NOFPU "none"
+#define STR_ISA_EXT_FPU0 "0"
+#define STR_ISA_EXT_FPU32 "32"
+#define STR_ISA_EXT_FPU64 "64"
+
+#define OPTSTR_SOFT_FLOAT "soft-float"
+#define OPTSTR_SINGLE_FLOAT "single-float"
+#define OPTSTR_DOUBLE_FLOAT "double-float"
+
+#define OPTSTR_ABI_BASE "abi"
+#define STR_ABI_BASE_LP64D "lp64d"
+#define STR_ABI_BASE_LP64F "lp64f"
+#define STR_ABI_BASE_LP64S "lp64s"
+
+#define STR_ABI_EXT_BASE "base"
+
+#define OPTSTR_CMODEL "cmodel"
+#define STR_CMODEL_NORMAL "normal"
+#define STR_CMODEL_TINY "tiny"
+#define STR_CMODEL_TS "tiny-static"
+#define STR_CMODEL_LARGE "large"
+#define STR_CMODEL_EXTREME "extreme"
+
+#endif /* LOONGARCH_STR_H */
diff --git a/gcc/config/loongarch/loongarch.opt b/gcc/config/loongarch/loongarch.opt
new file mode 100644
index 00000000000..0511d08c261
--- /dev/null
+++ b/gcc/config/loongarch/loongarch.opt
@@ -0,0 +1,189 @@ 
+; Generated by "genstr" from the template "loongarch.opt.in"
+; and definitions from "loongarch-strings".
+;
+; Copyright (C) 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
+; <http://www.gnu.org/licenses/>.
+;
+
+; 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(la64) Value(ISA_BASE_LA64V100)
+
+
+;; ISA extensions / adjustments
+Enum
+Name(isa_ext_fpu) Type(int)
+FPU types of LoongArch:
+
+EnumValue
+Enum(isa_ext_fpu) String(none) Value(ISA_EXT_NOFPU)
+
+EnumValue
+Enum(isa_ext_fpu) String(32) Value(ISA_EXT_FPU32)
+
+EnumValue
+Enum(isa_ext_fpu) String(64) Value(ISA_EXT_FPU64)
+
+mfpu=
+Target RejectNegative Joined ToLower Enum(isa_ext_fpu) Var(la_opt_fpu) Init(M_OPTION_NOT_SEEN)
+-mfpu=FPU	Generate code for the given FPU.
+
+mfpu=0
+Target RejectNegative Alias(mfpu=,none)
+
+msoft-float
+Target Driver RejectNegative Var(la_opt_switches) Mask(FORCE_SOFTF) Negative(msingle-float)
+Prevent the use of all hardware floating-point instructions.
+
+msingle-float
+Target Driver RejectNegative Var(la_opt_switches) Mask(FORCE_F32) Negative(mdouble-float)
+Restrict the use of hardware floating-point instructions to 32-bit operations.
+
+mdouble-float
+Target Driver RejectNegative Var(la_opt_switches) Mask(FORCE_F64) Negative(msoft-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(native) Value(CPU_NATIVE)
+
+EnumValue
+Enum(cpu_type) String(loongarch64) Value(CPU_LOONGARCH64)
+
+EnumValue
+Enum(cpu_type) String(la464) Value(CPU_LA464)
+
+march=
+Target RejectNegative Joined Enum(cpu_type) Var(la_opt_cpu_arch) Init(M_OPTION_NOT_SEEN)
+-march=PROCESSOR	Generate code for the given PROCESSOR ISA.
+
+mtune=
+Target RejectNegative Joined Enum(cpu_type) Var(la_opt_cpu_tune) Init(M_OPTION_NOT_SEEN)
+-mtune=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(lp64d) Value(ABI_BASE_LP64D)
+
+EnumValue
+Enum(abi_base) String(lp64f) Value(ABI_BASE_LP64F)
+
+EnumValue
+Enum(abi_base) String(lp64s) Value(ABI_BASE_LP64S)
+
+mabi=
+Target RejectNegative Joined ToLower Enum(abi_base) Var(la_opt_abi_base) Init(M_OPTION_NOT_SEEN)
+-mabi=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)
+Don't optimize block moves.
+
+mlra
+Target Var(loongarch_lra_flag) Init(1) Save
+Use LRA instead of reload.
+
+noasmopt
+Driver
+
+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(normal) Value(CMODEL_NORMAL)
+
+EnumValue
+Enum(cmodel) String(tiny) Value(CMODEL_TINY)
+
+EnumValue
+Enum(cmodel) String(tiny-static) Value(CMODEL_TINY_STATIC)
+
+EnumValue
+Enum(cmodel) String(large) Value(CMODEL_LARGE)
+
+EnumValue
+Enum(cmodel) String(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/t-linux b/gcc/config/loongarch/t-linux
new file mode 100644
index 00000000000..7be867d2351
--- /dev/null
+++ b/gcc/config/loongarch/t-linux
@@ -0,0 +1,53 @@ 
+# Copyright (C) 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
+# <http://www.gnu.org/licenses/>.
+
+# Multilib
+MULTILIB_OPTIONS = mabi=lp64d/mabi=lp64f/mabi=lp64s
+MULTILIB_DIRNAMES = base/lp64d base/lp64f base/lp64s
+
+# The GCC driver always gets all abi-related options on the command line.
+# (see loongarch-driver.c:driver_get_normalized_m_opts)
+comma=,
+MULTILIB_REQUIRED = $(subst $(comma), ,$(TM_MULTILIB_CONFIG))
+
+# Multiarch
+ifneq ($(call if_multiarch,yes),yes)
+    # Define __DISABLE_MULTIARCH if multiarch is disabled.
+    tm_defines += __DISABLE_MULTIARCH
+else
+    # Only define MULTIARCH_DIRNAME when multiarch is enabled,
+    # or it would always introduce ${target} into the search path.
+    MULTIARCH_DIRNAME = $(LA_MULTIARCH_TRIPLET)
+endif
+
+# Don't define MULTILIB_OSDIRNAMES if multilib is disabled.
+ifeq ($(filter __DISABLE_MULTILIB,$(tm_defines)),)
+
+    MULTILIB_OSDIRNAMES = \
+      mabi.lp64d=../lib64$\
+      $(call if_multiarch,:loongarch64-linux-gnuf64)
+
+    MULTILIB_OSDIRNAMES += \
+      mabi.lp64f=../lib64/f32$\
+      $(call if_multiarch,:loongarch64-linux-gnuf32)
+
+    MULTILIB_OSDIRNAMES += \
+      mabi.lp64s=../lib64/sf$\
+      $(call if_multiarch,:loongarch64-linux-gnusf)
+
+endif
diff --git a/gcc/config/loongarch/t-loongarch b/gcc/config/loongarch/t-loongarch
new file mode 100644
index 00000000000..7708449827a
--- /dev/null
+++ b/gcc/config/loongarch/t-loongarch
@@ -0,0 +1,59 @@ 
+# Copyright (C) 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
+# <http://www.gnu.org/licenses/>.
+
+# Canonical target triplet from config.gcc
+LA_MULTIARCH_TRIPLET = $(patsubst LA_MULTIARCH_TRIPLET=%,%,$\
+$(filter LA_MULTIARCH_TRIPLET=%,$(tm_defines)))
+
+# String definition header
+LA_STR_H = $(srcdir)/config/loongarch/loongarch-str.h
+
+loongarch-c.o: $(srcdir)/config/loongarch/loongarch-c.cc $(CONFIG_H) $(SYSTEM_H) \
+	coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) $(TARGET_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/loongarch/loongarch-c.cc
+
+loongarch-builtins.o: $(srcdir)/config/loongarch/loongarch-builtins.cc $(CONFIG_H) \
+	$(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) $(RECOG_H) langhooks.h \
+	$(DIAGNOSTIC_CORE_H) $(OPTABS_H) $(srcdir)/config/loongarch/loongarch-ftypes.def \
+	$(srcdir)/config/loongarch/loongarch-modes.def
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/loongarch/loongarch-builtins.cc
+
+loongarch-driver.o : $(srcdir)/config/loongarch/loongarch-driver.cc $(LA_STR_H) \
+	$(CONFIG_H) $(SYSTEM_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
+loongarch-opts.o: $(srcdir)/config/loongarch/loongarch-opts.cc $(LA_STR_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
+loongarch-cpu.o: $(srcdir)/config/loongarch/loongarch-cpu.cc $(LA_STR_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
+loongarch-def.o: $(srcdir)/config/loongarch/loongarch-def.c $(LA_STR_H)
+	$(CC) -c $(ALL_CFLAGS) $(INCLUDES) $<
+
+$(srcdir)/config/loongarch/loongarch.opt: \
+	$(srcdir)/config/loongarch/genopts/genstr.sh \
+	$(srcdir)/config/loongarch/genopts/loongarch.opt.in
+	$(SHELL) $< opt > $@
+
+$(LA_STR_H): \
+	$(srcdir)/config/loongarch/genopts/genstr.sh \
+	$(srcdir)/config/loongarch/genopts/loongarch-strings
+	$(SHELL) $< header > $@
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 1171c946e6e..3129bca6496 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -951,6 +951,9 @@  AC_ARG_ENABLE(fixed-point,
     mips*-*-*)
       enable_fixed_point=yes
       ;;
+    loongarch*-*-*)
+      enable_fixed_point=yes
+      ;;
     *)
       AC_MSG_WARN([fixed-point is not supported for this target, ignored])
       enable_fixed_point=no
@@ -3830,6 +3833,17 @@  foo:	data8	25
 	movl	r24 = @tprel(foo#)'
 	tls_as_opt=--fatal-warnings
 	;;
+  loongarch*-*-*)
+    conftest_s='
+	.section .tdata,"awT",@progbits
+x:	.word 2
+	.text
+	la.tls.gd $a0,x
+	bl __tls_get_addr'
+	tls_first_major=0
+	tls_first_minor=0
+	tls_as_opt='--fatal-warnings'
+	;;
   microblaze*-*-*)
     conftest_s='
 	.section .tdata,"awT",@progbits
@@ -5290,6 +5304,17 @@  configured with --enable-newlib-nano-formatted-io.])
       [AC_DEFINE(HAVE_AS_MARCH_ZIFENCEI, 1,
 		 [Define if the assembler understands -march=rv*_zifencei.])])
     ;;
+  loongarch*-*-*)
+    gcc_GAS_CHECK_FEATURE([.dtprelword support],
+      gcc_cv_as_loongarch_dtprelword, [2,18,0],,
+      [.section .tdata,"awT",@progbits
+x:
+	.word 2
+	.text
+	.dtprelword x+0x8000],,
+      [AC_DEFINE(HAVE_AS_DTPRELWORD, 1,
+	  [Define if your assembler supports .dtprelword.])])
+    ;;
     s390*-*-*)
     gcc_GAS_CHECK_FEATURE([.gnu_attribute support],
       gcc_cv_as_s390_gnu_attribute,,
@@ -5323,11 +5348,11 @@  configured with --enable-newlib-nano-formatted-io.])
     ;;
 esac
 
-# Mips and HP-UX need the GNU assembler.
+# Mips, LoongArch and HP-UX need the GNU assembler.
 # Linux on IA64 might be able to use the Intel assembler.
 
 case "$target" in
-  mips*-*-* | *-*-hpux* )
+  mips*-*-* | loongarch*-*-* | *-*-hpux* )
     if test x$gas_flag = xyes \
        || test x"$host" != x"$build" \
        || test ! -x "$gcc_cv_as" \
@@ -5484,8 +5509,8 @@  esac
 # ??? Once 2.11 is released, probably need to add first known working
 # version to the per-target configury.
 case "$cpu_type" in
-  aarch64 | alpha | arc | arm | avr | bfin | cris | csky | i386 | m32c | m68k \
-  | microblaze | mips | nds32 | nios2 | pa | riscv | rs6000 | score | sparc \
+  aarch64 | alpha | arc | arm | avr | bfin | cris | csky | i386 | loongarch | m32c \
+  | m68k | microblaze | mips | nds32 | nios2 | pa | riscv | rs6000 | score | sparc \
   | tilegx | tilepro | visium | xstormy16 | xtensa)
     insn="nop"
     ;;