Browse Source

Add loongarch64 architecture support to compiler

Jinyang He 2 years ago
parent
commit
12c4290ffe
61 changed files with 9247 additions and 31 deletions
  1. 25 6
      compiler/Makefile.fpc
  2. 3 3
      compiler/aggas.pas
  3. 9 9
      compiler/aoptobj.pas
  4. 7 0
      compiler/cfidwarf.pas
  5. 22 0
      compiler/cgbase.pas
  6. 4 2
      compiler/entfile.pas
  7. 10 0
      compiler/fpcdefs.inc
  8. 6 0
      compiler/globals.pas
  9. 362 0
      compiler/loongarch64/aasmcpu.pas
  10. 216 0
      compiler/loongarch64/agcpugas.pas
  11. 152 0
      compiler/loongarch64/aoptcpu.pas
  12. 106 0
      compiler/loongarch64/aoptcpub.pas
  13. 39 0
      compiler/loongarch64/aoptcpuc.pas
  14. 40 0
      compiler/loongarch64/aoptcpud.pas
  15. 1604 0
      compiler/loongarch64/cgcpu.pas
  16. 448 0
      compiler/loongarch64/cpubase.pas
  17. 122 0
      compiler/loongarch64/cpuinfo.pas
  18. 52 0
      compiler/loongarch64/cpunode.pas
  19. 617 0
      compiler/loongarch64/cpupara.pas
  20. 122 0
      compiler/loongarch64/cpupi.pas
  21. 82 0
      compiler/loongarch64/cputarg.pas
  22. 185 0
      compiler/loongarch64/hlcgcpu.pas
  23. 101 0
      compiler/loongarch64/itcpugas.pas
  24. 409 0
      compiler/loongarch64/loongarch64att.inc
  25. 2 0
      compiler/loongarch64/loongarch64nop.inc
  26. 409 0
      compiler/loongarch64/loongarch64op.inc
  27. 404 0
      compiler/loongarch64/loongarchins.dat
  28. 83 0
      compiler/loongarch64/loongarchreg.dat
  29. 401 0
      compiler/loongarch64/ncpuadd.pas
  30. 236 0
      compiler/loongarch64/ncpucnv.pas
  31. 203 0
      compiler/loongarch64/ncpuinl.pas
  32. 152 0
      compiler/loongarch64/ncpumat.pas
  33. 144 0
      compiler/loongarch64/ncpuset.pas
  34. 48 0
      compiler/loongarch64/racpu.pas
  35. 811 0
      compiler/loongarch64/racpugas.pas
  36. 114 0
      compiler/loongarch64/rgcpu.pas
  37. 74 0
      compiler/loongarch64/rloongarch64abi.inc
  38. 74 0
      compiler/loongarch64/rloongarch64con.inc
  39. 74 0
      compiler/loongarch64/rloongarch64dwa.inc
  40. 2 0
      compiler/loongarch64/rloongarch64nor.inc
  41. 74 0
      compiler/loongarch64/rloongarch64num.inc
  42. 74 0
      compiler/loongarch64/rloongarch64rni.inc
  43. 74 0
      compiler/loongarch64/rloongarch64sri.inc
  44. 74 0
      compiler/loongarch64/rloongarch64sta.inc
  45. 74 0
      compiler/loongarch64/rloongarch64std.inc
  46. 74 0
      compiler/loongarch64/rloongarch64sup.inc
  47. 220 0
      compiler/loongarch64/symcpu.pas
  48. 45 0
      compiler/loongarch64/tripletcpu.pas
  49. 4 0
      compiler/ncgcnv.pas
  50. 22 0
      compiler/options.pas
  51. 7 0
      compiler/pp.pas
  52. 4 0
      compiler/psystem.pas
  53. 46 5
      compiler/raatt.pas
  54. 2 1
      compiler/systems.inc
  55. 2 2
      compiler/systems.pas
  56. 1 1
      compiler/tgobj.pas
  57. 4 0
      compiler/utils/fpc.pp
  58. 198 0
      compiler/utils/mkloongarch64ins.pp
  59. 267 0
      compiler/utils/mkloongarch64reg.pp
  60. 4 2
      compiler/utils/ppuutils/ppudump.pp
  61. 3 0
      compiler/version.pas

+ 25 - 6
compiler/Makefile.fpc

@@ -32,7 +32,7 @@ fpcdir=..
 unexport FPC_VERSION FPC_COMPILERINFO
 unexport FPC_VERSION FPC_COMPILERINFO
 
 
 # Which platforms are ready for inclusion in the cycle
 # Which platforms are ready for inclusion in the cycle
-CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80 wasm32
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80 wasm32 loongarch64
 
 
 # All supported targets used for clean
 # All supported targets used for clean
 ALLTARGETS=$(CYCLETARGETS)
 ALLTARGETS=$(CYCLETARGETS)
@@ -128,6 +128,9 @@ endif
 ifdef Z80
 ifdef Z80
 PPC_TARGET=z80
 PPC_TARGET=z80
 endif
 endif
+ifdef LOONGARCH64
+PPC_TARGET=loongarch64
+endif
 
 
 # Default is to generate a compiler for the same
 # Default is to generate a compiler for the same
 # platform as CPU_TARGET (a native compiler)
 # platform as CPU_TARGET (a native compiler)
@@ -302,6 +305,9 @@ endif
 ifeq ($(CPC_TARGET),wasm32)
 ifeq ($(CPC_TARGET),wasm32)
 CPUSUF=wasm32
 CPUSUF=wasm32
 endif
 endif
+ifeq ($(CPC_TARGET),loongarch64)
+CPUSUF=loongarch64
+endif
 
 
 # Do not define the default -d$(CPU_TARGET) because that
 # Do not define the default -d$(CPU_TARGET) because that
 # will conflict with our -d$(CPC_TARGET)
 # will conflict with our -d$(CPC_TARGET)
@@ -468,6 +474,11 @@ ifeq ($(PPC_TARGET),wasm32)
 override LOCALOPT+=-dNOOPT
 override LOCALOPT+=-dNOOPT
 endif
 endif
 
 
+# LoongArch64 specific
+ifeq ($(PPC_TARGET),loongarch64)
+override LOCALOPT+=-Fuloongarch64
+endif
+
 OPTWPOCOLLECT=-OWdevirtcalls,optvmts -FW$(BASEDIR)/pp1.wpo
 OPTWPOCOLLECT=-OWdevirtcalls,optvmts -FW$(BASEDIR)/pp1.wpo
 OPTWPOPERFORM=-Owdevirtcalls,optvmts -Fw$(BASEDIR)/pp1.wpo
 OPTWPOPERFORM=-Owdevirtcalls,optvmts -Fw$(BASEDIR)/pp1.wpo
 # symbol liveness WPO requires nm, smart linking and no stripping (the latter
 # symbol liveness WPO requires nm, smart linking and no stripping (the latter
@@ -671,8 +682,8 @@ endif
 # cpu targets
 # cpu targets
 #####################################################################
 #####################################################################
 
 
-PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel mips64 mips64el avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80 wasm32
-PPC_SUFFIXES=386 68k ppc sparc arm armeb x64 ppc64 mips mipsel mips64 mips64el avr jvm 8086 a64 sparc64 rv32 rv64 xtensa z80 wasm32
+PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel mips64 mips64el avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80 wasm32 loongarch64
+PPC_SUFFIXES=386 68k ppc sparc arm armeb x64 ppc64 mips mipsel mips64 mips64el avr jvm 8086 a64 sparc64 rv32 rv64 xtensa z80 wasm32 loongarch64
 INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 CLEAN_TARGETS=$(addsuffix _clean,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 CLEAN_TARGETS=$(addsuffix _clean,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 SYMLINKINSTALL_TARGETS=$(addsuffix _symlink_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 SYMLINKINSTALL_TARGETS=$(addsuffix _symlink_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
@@ -784,7 +795,11 @@ insdatz80 : z80/z80ins.dat
 	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80ins.pp
 	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80ins.pp
         cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80ins$(SRCEXEEXT)
         cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80ins$(SRCEXEEXT)
 
 
-insdat: insdatx86 insdatarm insdataarch64 insdatz80
+insdatloongarch64 : loongarch64/loongarchins.dat
+	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkloongarch64ins.pp
+        cd loongarch64 && ..$(PATHSEP)utils$(PATHSEP)mkloongarch64ins$(SRCEXEEXT)
+
+insdat: insdatx86 insdatarm insdataarch64 insdatz80 insdatloongarch64
 
 
 regdatx86 : x86/x86reg.dat
 regdatx86 : x86/x86reg.dat
 	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86reg.pp
 	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86reg.pp
@@ -839,7 +854,11 @@ regdatrv64 : riscv/rvreg.dat
         cd riscv && ..$(PATHSEP)utils$(PATHSEP)mkrvreg$(SRCEXEEXT) riscv64
         cd riscv && ..$(PATHSEP)utils$(PATHSEP)mkrvreg$(SRCEXEEXT) riscv64
 		mv -f riscv/rrv64*.inc riscv64
 		mv -f riscv/rrv64*.inc riscv64
 
 
-regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatsp64 regdatz80 regdatwasm regdatrv32 regdatrv64
+regdatloongarch64 : loongarch64/loongarchreg.dat
+            $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkloongarch64reg.pp
+        cd loongarch64 && ..$(PATHSEP)utils$(PATHSEP)mkloongarch64reg$(SRCEXEEXT)
+
+regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatsp64 regdatz80 regdatwasm regdatrv32 regdatrv64 regdatloongarch64
 
 
 intrdatx86 : x86/x86intr.dat
 intrdatx86 : x86/x86intr.dat
 		$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86inl.pp
 		$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86inl.pp
@@ -1122,7 +1141,7 @@ ifeq ($(OS_SOURCE),win64)
   EXCLUDE_80BIT_TARGETS=1
   EXCLUDE_80BIT_TARGETS=1
 endif
 endif
 
 
-ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel mips64 mips64el powerpc powerpc64 sparc sparc64 riscv32 riscv64 xtensa),)
+ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel mips64 mips64el powerpc powerpc64 sparc sparc64 riscv32 riscv64 xtensa loongarch64),)
   EXCLUDE_80BIT_TARGETS=1
   EXCLUDE_80BIT_TARGETS=1
 endif
 endif
 endif
 endif

+ 3 - 3
compiler/aggas.pas

@@ -221,11 +221,11 @@ implementation
 { vtable for a class called Window:                                       }
 { vtable for a class called Window:                                       }
 { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat    }
 { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat    }
 { TODO: .data.ro not yet working}
 { TODO: .data.ro not yet working}
-{$if defined(arm) or defined(aarch64) or defined(riscv64) or defined(powerpc) or defined(x86_64)}
+{$if defined(arm) or defined(aarch64) or defined(riscv64) or defined(powerpc) or defined(x86_64) or defined(loongarch64)}
           '.rodata',
           '.rodata',
-{$else defined(arm) or defined(aarch64) or defined(riscv64) or defined(powerpc) or defined(x86_64)}
+{$else defined(arm) or defined(aarch64) or defined(riscv64) or defined(powerpc) or defined(x86_64) or defined(loongarch64)}
           '.data',
           '.data',
-{$endif defined(arm) or defined(aarch64) or defined(riscv64) or defined(powerpc) or defined(x86_64)}
+{$endif defined(arm) or defined(aarch64) or defined(riscv64) or defined(powerpc) or defined(x86_64) or defined(loongarch64)}
           '.rodata',
           '.rodata',
           '.bss',
           '.bss',
           '.threadvar',
           '.threadvar',

+ 9 - 9
compiler/aoptobj.pas

@@ -473,8 +473,8 @@ Unit AoptObj;
 
 
     function JumpTargetOp(ai: taicpu): poper; inline;
     function JumpTargetOp(ai: taicpu): poper; inline;
       begin
       begin
-{$if defined(MIPS) or defined(riscv64) or defined(riscv32) or defined(xtensa)}
-        { MIPS, Xtensa or RiscV branches can have 1,2 or 3 operands, target label is the last one. }
+{$if defined(MIPS) or defined(riscv64) or defined(riscv32) or defined(xtensa) or defined(loongarch64)}
+        { Branches of above archs can have 1,2 or 3 operands, target label is the last one. }
         result:=ai.oper[ai.ops-1];
         result:=ai.oper[ai.ops-1];
 {$elseif defined(SPARC64)}
 {$elseif defined(SPARC64)}
         if ai.ops=2 then
         if ai.ops=2 then
@@ -2330,7 +2330,7 @@ Unit AoptObj;
 
 
       var p1: tai;
       var p1: tai;
           p2: tai;
           p2: tai;
-{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
+{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM) and not defined(loongarch64)}
           p3: tai;
           p3: tai;
 {$endif}
 {$endif}
           ThisLabel, l: tasmlabel;
           ThisLabel, l: tasmlabel;
@@ -2377,9 +2377,9 @@ Unit AoptObj;
                       Exit;
                       Exit;
                   end;
                   end;
 
 
-{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
+{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM) and not defined(loongarch64)}
                 p3 := p2;
                 p3 := p2;
-{$endif not MIPS and not RV64 and not RV32 and not JVM}
+{$endif not MIPS and not RV64 and not RV32 and not JVM and not loongarch64}
 
 
                 if { the next instruction after the label where the jump hp arrives}
                 if { the next instruction after the label where the jump hp arrives}
                    { is unconditional or of the same type as hp, so continue       }
                    { is unconditional or of the same type as hp, so continue       }
@@ -2388,7 +2388,7 @@ Unit AoptObj;
                    { TODO: For anyone with experience with MIPS or RISC-V, please add support for tracing
                    { TODO: For anyone with experience with MIPS or RISC-V, please add support for tracing
                      conditional jumps. [Kit] }
                      conditional jumps. [Kit] }
 
 
-{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
+{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM) and not defined(loongarch64)}
   { for MIPS, it isn't enough to check the condition; first operands must be same, too. }
   { for MIPS, it isn't enough to check the condition; first operands must be same, too. }
                    or
                    or
                    condition_in(hp.condition, taicpu(p1).condition) or
                    condition_in(hp.condition, taicpu(p1).condition) or
@@ -2406,7 +2406,7 @@ Unit AoptObj;
                      ) and
                      ) and
                      SetAndTest(p2,p1)
                      SetAndTest(p2,p1)
                    )
                    )
-{$endif not MIPS and not RV64 and not RV32 and not JVM}
+{$endif not MIPS and not RV64 and not RV32 and not JVM and not loongarch64}
                    then
                    then
                   begin
                   begin
                     { quick check for loops of the form "l5: ; jmp l5" }
                     { quick check for loops of the form "l5: ; jmp l5" }
@@ -2435,7 +2435,7 @@ Unit AoptObj;
                     GetFinalDestination := True;
                     GetFinalDestination := True;
                     Exit;
                     Exit;
                   end
                   end
-{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
+{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM) and not defined(loongarch64)}
                 else
                 else
                   if condition_in(inverse_cond(hp.condition), taicpu(p1).condition) then
                   if condition_in(inverse_cond(hp.condition), taicpu(p1).condition) then
                     begin
                     begin
@@ -2472,7 +2472,7 @@ Unit AoptObj;
                       GetFinalDestination := True;
                       GetFinalDestination := True;
                       Exit;
                       Exit;
                     end;
                     end;
-{$endif not MIPS and not RV64 and not RV32 and not JVM}
+{$endif not MIPS and not RV64 and not RV32 and not JVM and not loongarch64}
               end;
               end;
           end;
           end;
 
 

+ 7 - 0
compiler/cfidwarf.pas

@@ -315,6 +315,13 @@ implementation
         list.concat(tai_const.create_uleb128bit(dwarf_reg(NR_STACK_POINTER_REG)));
         list.concat(tai_const.create_uleb128bit(dwarf_reg(NR_STACK_POINTER_REG)));
         list.concat(tai_const.create_uleb128bit(0));
         list.concat(tai_const.create_uleb128bit(0));
       end;
       end;
+{$elseif defined(loongarch64)}
+    procedure TDwarfAsmCFILowLevel.generate_initial_instructions(list:TAsmList);
+      begin
+        list.concat(tai_const.create_8bit(DW_CFA_def_cfa));
+        list.concat(tai_const.create_uleb128bit(dwarf_reg(NR_STACK_POINTER_REG)));
+        list.concat(tai_const.create_uleb128bit(0));
+      end;
 {$else}
 {$else}
     { if more cpu dependend stuff is implemented, this needs more refactoring }
     { if more cpu dependend stuff is implemented, this needs more refactoring }
     procedure TDwarfAsmCFILowLevel.generate_initial_instructions(list:TAsmList);
     procedure TDwarfAsmCFILowLevel.generate_initial_instructions(list:TAsmList);

+ 22 - 0
compiler/cgbase.pas

@@ -103,6 +103,28 @@ interface
          addr_got_pcrel_hi,
          addr_got_pcrel_hi,
          addr_plt
          addr_plt
          {$endif RISCV}
          {$endif RISCV}
+         {$if defined(LOONGARCH64)}
+         ,
+         addr_b16, { %b16(sym) }
+         addr_b21, { %b21(sym) }
+         addr_b26, { %b26(sym) }
+         addr_pcrel, { Some times we only use sym like 'bxx rd,rj,sym'. And la.pcrel..sym }
+         addr_plt, { %plt(sym) }
+         addr_abs_hi20, { %abs_hi20(sym) }
+         addr_abs_lo12, { %abs_lo12(sym) }
+         addr_abs64_lo20, { %abs_lo20(sym) }
+         addr_abs64_hi12, { %abs_hi12(sym) }
+         addr_pc_hi20, { %pc_hi20(sym) }
+         addr_got_pc_hi20, { %got_pc_hi20(sym) }
+         addr_got_pc_lo12, { %got_pc_lo12(sym) }
+         addr_pc_lo12, { %pc_lo12(sym) }
+         addr_got, { la.got..sym }
+         addr_abs, { la.abs..sym }
+         addr_reg_reg, { use by [ld/st]x }
+         addr_reg_12i, { use by [ld/st] }
+         addr_reg_14i, { use by [ldptr/stptr] }
+         addr_reg { use by jr.. }
+         {$endif LOONGARCH64}
          {$IFDEF AVR}
          {$IFDEF AVR}
          ,addr_lo8
          ,addr_lo8
          ,addr_lo8_gs
          ,addr_lo8_gs

+ 4 - 2
compiler/entfile.pas

@@ -163,7 +163,8 @@ const
     { 21 } 32 {'xtensa'},
     { 21 } 32 {'xtensa'},
     { 22 } 16 {'z80'},
     { 22 } 16 {'z80'},
     { 23 } 64 {'mips64'},
     { 23 } 64 {'mips64'},
-    { 24 } 64 {'mips64el'}
+    { 24 } 64 {'mips64el'},
+    { 25 } 64 {'loongarch64'}
     );
     );
   CpuAluBitSize : array[tsystemcpu] of longint =
   CpuAluBitSize : array[tsystemcpu] of longint =
     (
     (
@@ -191,7 +192,8 @@ const
     { 21 } 32 {'xtensa'},
     { 21 } 32 {'xtensa'},
     { 22 }  8 {'z80'},
     { 22 }  8 {'z80'},
     { 23 } 64 {'mips64'},
     { 23 } 64 {'mips64'},
-    { 24 } 64 {'mips64el'}
+    { 24 } 64 {'mips64el'},
+    { 25 } 64 {'loongarch64'}
     );
     );
 {$endif generic_cpu}
 {$endif generic_cpu}
 
 

+ 10 - 0
compiler/fpcdefs.inc

@@ -391,6 +391,16 @@
   {$define cpufloatintregmov}
   {$define cpufloatintregmov}
 {$endif xtensa}
 {$endif xtensa}
 
 
+{$ifdef loongarch64}
+  {$define loongarch}
+  {$define cpu64bit}
+  {$define cpu64bitaddr}
+  {$define cpu64bitalu}
+  {$define cputargethasfixedstack}
+  {$define cpucapabilities}
+  {$define SUPPORT_SAFECALL}
+{$endif loongarch64}
+
 { Stabs is not officially supported on 64 bit targets by gdb, except on Mac OS X
 { Stabs is not officially supported on 64 bit targets by gdb, except on Mac OS X
   (but there we don't support it)
   (but there we don't support it)
 }
 }

+ 6 - 0
compiler/globals.pas

@@ -610,6 +610,12 @@ interface
         asmcputype : cpu_none;
         asmcputype : cpu_none;
         fputype : fpu_standard;
         fputype : fpu_standard;
   {$endif wasm}
   {$endif wasm}
+  {$ifdef loongarch64}
+        cputype : cpu_3a;
+        optimizecputype : cpu_3a;
+        asmcputype : cpu_none;
+        fputype : fpu_fd;
+  {$endif loongarch64}
 {$endif not GENERIC_CPU}
 {$endif not GENERIC_CPU}
         asmmode : asmmode_standard;
         asmmode : asmmode_standard;
 {$ifndef jvm}
 {$ifndef jvm}

+ 362 - 0
compiler/loongarch64/aasmcpu.pas

@@ -0,0 +1,362 @@
+{
+    Copyright (C) 2022 Loongson Technology Corporation Limited.
+
+    Contains the assembler object for the LoongArch64
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit aasmcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype,verbose,
+  aasmbase,aasmtai,aasmdata,aasmsym,
+  cpubase,cgbase,cgutils;
+
+    const
+      { "move reg,reg" source operand number }
+      O_MOV_SOURCE = 1;
+      { "move reg,reg" source operand number }
+      O_MOV_DEST = 0;
+
+
+    type
+      { TODO: Branch condition? TRefernece and Symbol? }
+      { taicpu }
+
+      taicpu = class(tai_cpu_abstract_sym)
+         { NOP,TLBSRCH,TLBRD,TLBWR,TLBFILL,TLBCLR,TLBFLUSH,ERTN, }
+         constructor op_none(op : tasmop);
+
+         { DBAR,IBAR,SYSCALL,BREAK,DBCL,IDLE, }
+         constructor op_const(op : tasmop;_op1 : aint);
+
+         { B,BL,JR, }
+         constructor op_ref(op : tasmop; const _op1 : treference);
+
+         { EXT,CLO,CLZ,CTO,CTZ,REVB,REVH,BITREV,ASRTLE,ASRTGT,RDTIMEL,RDTIMEH,
+           RDTIME,CPUCFG,FABS,FNEG,FSQRT,FRECIP,FRSQRT,FLOGB,FCLASS,FCVT,FFINT,
+           FTINT,FTINTRM,FTINTRP,FTINTRZ,FTINTRNE,FRINT,FMOV,MOVGR2FR,MOVGR2FRH,
+           MOVFR2GR,MOVFRH2GR,MOVGR2FCSR,MOVFCSR2GR,MOVFR2CF,MOVCF2FR,MOVGR2CF,
+           MOVCF2GR,IOCSRRD,IOCSRWR,MOVE,}
+         constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister);
+
+         { BEQZ,BNEZ,BCEQZ,BCNEZ,LA,BLTZ,BGTZ,BGEZ,BLEZ,LD,ST,LDX,STX,LDPTR,
+           STPTR,FLD,FST,FLDX,FSTX, }
+         constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
+
+         { LU12I,LU32I,PCADDI,PCADDU12I,PCADDU18I,PCALAU12I,CSRRD,CSRWR,LDPTE,LI, }
+         constructor op_reg_const(op:tasmop; _op1: tregister; _op2: aint);
+
+         { BSTRINS,BSTRPICK, }
+         constructor op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister; _op3, _op4: aint);
+
+         { ADD,SUB,SLT,AND,OR,NOR,XOR,ANDN,ORN,MUL,MULH,MULW,DIV,MOD,SLL,SRL,SRA,
+           RTOR,MASKEQZ,MASKNEZ,LDGT,LDLE,STGT,STLE,AMSWAP,AMSWAP_DB,AMADD,AMADD_DB,
+           AMAND,AMAND_DB,AMOR,AMOR_DB,AMXOR,AMXOR_DB,AMMAX,AMMAX_DB,AMMIN,AMMIN_DB,
+           CRC,CRCC,FADD,FSUB,FMUL,FDIV,FMAX,FMIN,FMAXA,FMINA,FCALEB,FCOPYSIGN,FCMP,
+           FLDGT,FLDLE,FSTGT,FSTLE,}
+         constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
+
+         { ADDI,ADDU16I,LU52I,SLTI,ANDI,ORI,XORI,SLLI,SRLI,SRAI,ROTRI,JIRL,LL,SC,
+           CSRXCHG,LDDIR,}
+         constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint);
+
+         { BEQ,BNE,BLT,BGE,BLTU,BGEU,BGT,BLE,BGTU,BLEU, }
+         constructor op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
+
+         { PRELD,CACOP, }
+         constructor op_const_reg_const(op : tasmop;_op1 : aint;_op2 : tregister;_op3 : aint);
+
+         { PRELDX,INVTLB }
+         constructor op_const_reg_reg(op : tasmop; _op1 : aint; _op2,_op3 : tregister);
+
+         { FMADD,FMSUB,FNMADD,FNMSUB,FSEL,}
+         constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
+
+         { ALSL,BYTEPICK, }
+         constructor op_reg_reg_reg_const(op : tasmop; _op1, _op2, _op3 : tregister; _op4 : aint);
+
+         function is_same_reg_move(regtype: Tregistertype):boolean; override;
+
+         { register spilling code }
+         function spilling_get_operation_type(opnr: longint): topertype;override;
+         function spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;override;
+      end;
+
+      tai_align = class(tai_align_abstract)
+        { nothing to add }
+      end;
+
+    procedure InitAsm;
+    procedure DoneAsm;
+
+
+    function spilling_create_load(const ref:treference;r:tregister):Taicpu;
+    function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+
+implementation
+
+uses cutils, cclasses;
+
+{*****************************************************************************
+                                 taicpu Constructors
+*****************************************************************************}
+
+    constructor taicpu.op_none(op : tasmop);
+      begin
+         inherited create(op);
+      end;
+
+
+    constructor taicpu.op_const(op : tasmop;_op1 : aint);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadconst(0,_op1);
+      end;
+
+
+    constructor taicpu.op_ref(op : tasmop;const _op1 : treference);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadref(0,_op1);
+      end;
+
+
+    constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadref(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: aint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadconst(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister; _op3, _op4: aint);
+      begin
+        inherited create(op);
+        ops := 4;
+        loadreg(0, _op1);
+        loadreg(1, _op2);
+        loadconst(2, _op3);
+        loadconst(3, _op4);
+      end;
+
+
+    constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+
+     constructor taicpu.op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint);
+       begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,_op3);
+      end;
+
+
+     constructor taicpu.op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
+       begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadref(2,_op3);
+      end;
+
+
+    constructor taicpu.op_const_reg_reg(op : tasmop;_op1 : aint;_op2, _op3 : tregister);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+
+     constructor taicpu.op_const_reg_const(op : tasmop;_op1 : aint;_op2 : tregister;_op3 : aint);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,_op3);
+      end;
+
+
+     constructor taicpu.op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
+      begin
+         inherited create(op);
+         ops:=4;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+         loadreg(3,_op4);
+      end;
+
+     constructor taicpu.op_reg_reg_reg_const(op : tasmop; _op1, _op2, _op3 : tregister; _op4 : aint);
+      begin
+        inherited create(op);
+        ops := 4;
+        loadreg(0, _op1);
+        loadreg(1, _op2);
+        loadreg(2, _op3);
+        loadconst(3, cardinal(_op4));
+      end;
+
+
+{ ****************************** newra stuff *************************** }
+
+    function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
+      begin
+        case regtype of
+          R_INTREGISTER:
+            result:=
+               (opcode=A_MOVE) and (oper[0]^.reg=oper[1]^.reg);
+          R_FPUREGISTER:
+            result:=
+               ((opcode=A_FMOV_S) or (opcode=A_FMOV_D)) and
+               (oper[0]^.reg=oper[1]^.reg);
+         else
+           result:=false;
+        end;
+      end;
+
+    { Mant of case is set opnr0 and read from opnr(others). }
+    function normal_oper_type(opnr: longint): topertype;
+      begin
+        if opnr=0 then
+          result:=operand_write
+        else
+          result:=operand_read;
+      end;
+
+
+    function taicpu.spilling_get_operation_type(opnr: longint): topertype;
+      begin
+        case opcode of
+          A_ST_B,A_ST_D,A_ST_W,A_ST_H,A_STX_B,A_STX_D,A_STX_W,A_STX_H,
+          A_STPTR_W,A_STPTR_D,A_STGT_B,A_STGT_D,A_STGT_W,A_STGT_H,
+          A_STLE_B,A_STLE_D,A_STLE_W,A_STLE_H,A_FST_S,A_FST_D,A_FSTX_S,
+          A_FSTX_D,A_FSTGT_S,A_FSTGT_D,A_FSTLE_S,A_FSTLE_D,A_CSRWR,
+          A_IOCSRWR_B,A_IOCSRWR_D,A_IOCSRWR_W,A_IOCSRWR_H:
+            result:=operand_read;
+          A_RDTIME_D,A_RDTIMEL_W,A_RDTIMEH_W:
+            result:=operand_write;
+          A_PRELD,A_PRELDX,A_DBAR,A_IBAR,A_SYSCALL,A_BREAK,A_ASRTLE_D,
+          A_ASRTGT_D,A_CACOP,A_INVTLB,A_DBCL,A_IDLE,A_BEQ,A_BNE,A_BLT,
+          A_BLTU,A_BGE,A_BGEU,A_BEQZ,A_BNEZ,A_B,A_BL,A_BCEQZ,A_BCNEZ,
+          A_BLTZ,A_BGTZ,A_BGEZ,A_BLEZ,A_BGT,A_BLE,A_BGTU,A_BLEU,A_JR,
+          A_NOP,A_BXX:
+            result:=operand_read;
+          A_AMSWAP_W,A_AMSWAP_D,A_AMSWAP_DB_W,A_AMSWAP_DB_D,A_AMADD_W,
+          A_AMADD_D,A_AMADD_DB_W,A_AMADD_DB_D,A_AMAND_W,A_AMAND_D,
+          A_AMAND_DB_W,A_AMAND_DB_D,A_AMOR_W,A_AMOR_D,A_AMOR_DB_W,
+          A_AMOR_DB_D,A_AMXOR_W,A_AMXOR_D,A_AMXOR_DB_W,A_AMXOR_DB_D,
+          A_AMMAX_W,A_AMMAX_DU,A_AMMAX_D,A_AMMAX_WU,A_AMMAX_DB_W,
+          A_AMMAX_DB_DU,A_AMMAX_DB_D,A_AMMAX_DB_WU,A_AMMIN_W,A_AMMIN_DU,
+          A_AMMIN_D,A_AMMIN_WU,A_AMMIN_DB_W,A_AMMIN_DB_DU,A_AMMIN_DB_D,
+          A_AMMIN_DB_WU,A_SC_W,A_SC_D:
+            result:=operand_readwrite;
+        else
+          result:=normal_oper_type(opnr);
+        end;
+      end;
+
+
+    function taicpu.spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;
+      begin
+        result := operand_read;
+      end;
+
+
+    function spilling_create_load(const ref:treference;r:tregister):Taicpu;
+      var
+        href : treference;
+      begin
+        href:=ref;
+        href.refaddr:=addr_reg_12i;
+        case getregtype(r) of
+           R_INTREGISTER: result:=taicpu.op_reg_ref(A_LD_D,r,href);
+           R_FPUREGISTER: result:=taicpu.op_reg_ref(A_FLD_D,r,href);
+        else
+           internalerror(2022111904);
+        end;
+      end;
+
+
+    function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+      var
+        href : treference;
+      begin
+        href:=ref;
+        href.refaddr:=addr_reg_12i;
+        case getregtype(r) of
+           R_INTREGISTER: result:=taicpu.op_reg_ref(A_ST_D,r,href);
+           R_FPUREGISTER: result:=taicpu.op_reg_ref(A_FST_D,r,href);
+        else
+           internalerror(2022111905);
+        end;
+      end;
+
+
+    procedure InitAsm;
+      begin
+      end;
+
+
+    procedure DoneAsm;
+      begin
+      end;
+
+
+begin
+  cai_align:=tai_align;
+  cai_cpu:=taicpu;
+end.

+ 216 - 0
compiler/loongarch64/agcpugas.pas

@@ -0,0 +1,216 @@
+{
+    Copyright (C) 2022 Loongson Technology Corporation Limited.
+
+    This unit the GAS asm writers for LoongArch64
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+{****************************************************************************}
+{                  Helper routines for Instruction Writer                    }
+{****************************************************************************}
+
+unit agcpugas;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       systems,aasmbase,
+       aasmtai,aasmdata,
+       aggas,
+       assemble,
+       cpubase,cgutils,
+       globtype;
+
+  type
+    TLoongArch64InstrWriter=class(TCPUInstrWriter)
+       procedure WriteInstruction(hp : tai);override;
+    end;
+
+    TLoongArch64GNUAssembler=class(TGNUassembler)
+      constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+    end;
+
+  var
+    curop: TAsmOp;
+
+  implementation
+
+    uses
+       cutils,globals,verbose,
+       cgbase,
+       itcpugas,cpuinfo,
+       aasmcpu;
+
+
+    function getreferencestring(asminfo: pasminfo; var ref : treference) : string;
+    var
+      s : string;
+    begin
+      { For LoongArch, we support only 4 cases
+        1. Symbol, symbol + addend (cannot used by got).
+        2. Reg + offset.
+        3. Reg + reg.
+        4. Reg
+      }
+      with ref do
+        begin
+          if assigned(relsymbol) then
+            internalerror(2022081001);
+          case refaddr of
+            addr_b16, addr_b21, addr_b26, addr_pcrel,
+            addr_plt, addr_abs_hi20, addr_abs_lo12,
+            addr_abs64_lo20, addr_abs64_hi12,
+            addr_pc_hi20, addr_got_pc_hi20,
+            addr_pc_lo12, addr_got_pc_lo12,
+            addr_got, addr_abs:
+              begin
+                if (base<>NR_NO) or (index<>NR_NO) then
+                  internalerror(2022081002)
+                else if (refaddr in [addr_got_pc_hi20,addr_got_pc_lo12,addr_got]) and (offset<>0) then
+                  internalerror(2022081003)
+                else if not assigned(symbol) then
+                  internalerror(2022081004);
+                s:=ApplyAsmSymbolRestrictions(symbol.name);
+                if offset<0 then
+                  s:=s+tostr(offset)
+                else if offset>0 then
+                  s:=s+'+'+tostr(offset);
+                case refaddr of
+                  addr_b16: s:='%b16('+s+')';
+                  addr_b21: s:='%b21('+s+')';
+                  addr_b26: s:='%b26('+s+')';
+                  addr_plt: s:='%plt('+s+')';
+                  addr_abs_hi20: s:='%abs_hi20('+s+')';
+                  addr_abs_lo12: s:='%abs_lo12('+s+')';
+                  addr_abs64_lo20: s:='%abs64_lo20('+s+')';
+                  addr_abs64_hi12: s:='%abs64_hi12('+s+')';
+                  addr_pc_hi20: s:='%pc_hi20('+s+')';
+                  addr_got_pc_hi20: s:='%got_pc_hi20('+s+')';
+                  addr_got_pc_lo12: s:='%got_pc_lo12('+s+')';
+                  addr_pc_lo12: s:='%pc_lo12('+s+')';
+                else
+                  ;
+                end;
+              end;
+            addr_reg_reg:
+              begin
+                if assigned(symbol) or (offset<>0) then
+                  internalerror(2022081005)
+                else if (base=NR_NO) or (index=NR_NO) then
+                  internalerror(2022081006);
+                s:=gas_regname(base)+','+gas_regname(index);
+              end;
+            addr_reg_12i, addr_reg_14i:
+              begin
+                if assigned(symbol) or (index<>NR_NO) then
+                  internalerror(2022081007)
+                else if (refaddr=addr_reg_12i) and (not is_simm12(offset)) then
+                  internalerror(2022081008)
+                else if (refaddr=addr_reg_14i) and (not is_simm16_and_quadruple(offset)) then
+                  internalerror(2022081009);
+                s:=gas_regname(base)+','+tostr(offset);
+              end;
+            addr_reg:
+              begin
+                if assigned(symbol) or (index<>NR_NO) or (offset<>0) then
+                  internalerror(2022081010)
+                else if (base=NR_NO) then
+                  internalerror(2022081011);
+                s:=gas_regname(base);
+              end;
+          else
+            internalerror(2022081012);
+          end;
+        end; { with ref do }
+      getreferencestring:=s;
+    end;
+
+
+    function getopstr(asminfo: pasminfo; const o:toper) : string;
+    var
+      hs : string;
+    begin
+      case o.typ of
+        top_reg:
+          getopstr:=gas_regname(o.reg);
+        top_const:
+          getopstr:=tostr(o.val);
+        top_ref:
+          getopstr:=getreferencestring(asminfo,o.ref^);
+      else
+        internalerror(2022111901);
+      end;
+    end;
+
+
+    Procedure TLoongArch64InstrWriter.WriteInstruction(hp : tai);
+    var op: TAsmOp;
+        s: string;
+        i: byte;
+        sep: string[3];
+    begin
+      s:=#9+gas_op2str[taicpu(hp).opcode];
+      if taicpu(hp).condition<>C_None then
+        s:=s+cond2str[taicpu(hp).condition];
+
+      curop:=taicpu(hp).opcode;
+      if taicpu(hp).ops<>0 then
+        begin
+          sep:=#9;
+          for i:=0 to taicpu(hp).ops-1 do
+            begin
+               s:=s+sep+getopstr(owner.asminfo,taicpu(hp).oper[i]^);
+               sep:=',';
+            end;
+        end;
+
+      owner.writer.AsmWriteLn(s);
+    end;
+
+
+{****************************************************************************}
+{                     GNU LoongArch Assembler writer                         }
+{****************************************************************************}
+
+    constructor TLoongArch64GNUAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+      begin
+        inherited;
+        InstrWriter := TLoongArch64InstrWriter.create(self);
+      end;
+
+
+  const
+    as_loongarch64_gas_info : tasminfo =
+       (
+         id     : as_gas;
+         idtxt  : 'AS';
+         asmbin : 'as';
+         asmcmd : '-o $OBJ $EXTRAOPT -mabi=lp64d $ASM';
+         supported_targets : [];
+         flags : [af_needar,af_smartlink_sections];
+         labelprefix : '.L';
+         labelmaxlen : -1;
+         comment : '# ';
+         dollarsign: '$';
+       );
+
+begin
+  RegisterAssembler(as_loongarch64_gas_info,TLoongArch64GNUAssembler);
+end.

+ 152 - 0
compiler/loongarch64/aoptcpu.pas

@@ -0,0 +1,152 @@
+{
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit implements the LoongArch64 optimizer object
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit aoptcpu;
+
+interface
+
+{$I fpcdefs.inc}
+
+{$define DEBUG_AOPTCPU}
+
+uses
+  cpubase,
+  globals, globtype,
+  cgbase, cutils,
+  aoptobj, aoptcpub, aopt,
+  aasmtai, aasmcpu;
+
+type
+
+  TCpuAsmOptimizer = class(TAsmOptimizer)
+    function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
+    function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean; override;
+    function GetNextInstructionUsingReg(Current: tai; Out Next: tai; reg: TRegister): Boolean;
+    function OptPass1Mov(var p: tai): Boolean;
+  end;
+
+implementation
+
+  function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
+    var
+      p: taicpu;
+    begin
+      result:=false;
+      if not ((assigned(hp)) and (hp.typ = ait_instruction)) then
+        exit;
+      p := taicpu(hp);
+      if p.ops=0 then
+        exit;
+      case p.oper[0]^.typ of
+        top_reg:
+          result:=(SuperRegistersEqual(p.oper[0]^.reg,reg)) and
+                  (p.spilling_get_operation_type(0)<>operand_read);
+      else
+          ;
+      end;
+    end;
+
+  function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai; out Next: tai; reg: TRegister): Boolean;
+    begin
+      Next:=Current;
+      repeat
+        Result:=GetNextInstruction(Next,Next);
+      until not (Result) or
+            not(cs_opt_level3 in current_settings.optimizerswitches) or
+            (Next.typ<>ait_instruction) or
+            RegInInstruction(reg,Next) or
+            is_calljmp(taicpu(Next).opcode);
+    end;
+
+  function MatchInstruction(const instr: tai; const op: TAsmOp; const AConditions: TAsmConds = []): boolean;
+    begin
+      result :=
+        (instr.typ = ait_instruction) and
+        (taicpu(instr).opcode = op) and
+        ((AConditions=[]) or (taicpu(instr).condition in AConditions));
+    end;
+
+
+  function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
+    begin
+      result := oper1.typ = oper2.typ;
+
+      if result then
+        case oper1.typ of
+          top_const:
+            Result:=oper1.val = oper2.val;
+          top_reg:
+            Result:=oper1.reg = oper2.reg;
+          {top_ref:
+            Result:=RefsEqual(oper1.ref^, oper2.ref^);}
+          else Result:=false;
+        end
+    end;
+
+
+  function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
+    begin
+      result := (oper.typ = top_reg) and (oper.reg = reg);
+    end;
+
+  function TCpuAsmOptimizer.OptPass1Mov(var p: tai): Boolean;
+    var
+      hp1: tai;
+      alloc, dealloc: tai_regalloc;
+    begin
+      {
+        change
+        mov reg0,reg1
+        mov reg1,reg0
+        into
+        mov reg0,reg1
+      }
+      Result := False;
+      while GetNextInstruction(p, hp1) and
+        MatchInstruction(hp1, A_MOVE, [taicpu(p).condition]) and
+        MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[1]^) and
+        MatchOperand(taicpu(p).oper[1]^, taicpu(hp1).oper[0]^) do
+        begin
+          asml.Remove(hp1);
+          hp1.free;
+          Result:=true;
+        end;
+    end;
+
+  function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
+    begin
+      result := false;
+      if p.typ=ait_instruction then
+          begin
+            case taicpu(p).opcode of
+            A_MOVE:
+                Result:=OptPass1Mov(p);
+            else
+                ;
+            end;
+          end;
+    end;
+
+begin
+  casmoptimizer := TCpuAsmOptimizer;
+end.

+ 106 - 0
compiler/loongarch64/aoptcpub.pas

@@ -0,0 +1,106 @@
+{
+   Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+   Development Team
+
+   This unit contains several types and constants necessary for the
+   optimizer to work on the LoongArch64 architecture
+
+   This program 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 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+****************************************************************************
+}
+unit aoptcpub; { Assembler OPTimizer CPU specific Base }
+
+{$I fpcdefs.inc}
+
+interface
+
+{ TODO }
+
+uses
+  aasmcpu, AOptBase, cpubase;
+
+type
+
+  { type of a normal instruction }
+  TInstr = Taicpu;
+  PInstr = ^TInstr;
+
+  { ************************************************************************* }
+  { **************************** TCondRegs ********************************** }
+  { ************************************************************************* }
+  { Info about the conditional registers                                      }
+  TCondRegs = object
+    constructor Init;
+    destructor Done;
+  end;
+
+  { ************************************************************************* }
+  { **************************** TAoptBaseCpu ******************************* }
+  { ************************************************************************* }
+
+  TAoptBaseCpu = class(TAoptBase)
+  end;
+
+  { ************************************************************************* }
+  { ******************************* Constants ******************************* }
+  { ************************************************************************* }
+const
+
+  { the maximum number of things (registers, memory, ...) a single instruction }
+  { changes                                                                    }
+
+  MaxCh = 3;
+
+  {Oper index of operand that contains the source (reference) with a load }
+  {instruction                                                            }
+
+  LoadSrc = 1;
+
+  {Oper index of operand that contains the destination (register) with a load }
+  {instruction                                                                }
+
+  LoadDst = 0;
+
+  {Oper index of operand that contains the source (register) with a store }
+  {instruction                                                            }
+
+  StoreSrc = 0;
+
+  {Oper index of operand that contains the destination (reference) with a load }
+  {instruction                                                                 }
+
+  StoreDst = 1;
+
+  aopt_uncondjmp = A_B;
+  aopt_condjmp = A_BXX;
+
+implementation
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+
+constructor TCondRegs.init;
+begin
+end;
+
+destructor TCondRegs.Done;
+{$IFDEF inl}inline;
+{$ENDIF inl}
+begin
+end;
+
+end.

+ 39 - 0
compiler/loongarch64/aoptcpuc.pas

@@ -0,0 +1,39 @@
+{
+   Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+   Development Team
+
+   This unit contains the processor specific implementation of the
+   assembler optimizer common subexpression elimination object.
+
+   This program 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 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+****************************************************************************
+}
+unit aoptcpuc;
+
+interface
+
+{$I fpcdefs.inc}
+
+uses
+  AOptCs;
+
+type
+  TRegInfoCpu = object(TRegInfo)
+  end;
+
+implementation
+
+end.

+ 40 - 0
compiler/loongarch64/aoptcpud.pas

@@ -0,0 +1,40 @@
+{
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the processor specific implementation of the
+    assembler optimizer data flow analyzer.
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+Unit aoptcpud;
+
+{$i fpcdefs.inc}
+
+Interface
+
+uses
+  AOptDA;
+
+Type
+  TAOptDFACpu = class(TAOptDFA)
+  End;
+
+Implementation
+
+
+End.

+ 1604 - 0
compiler/loongarch64/cgcpu.pas

@@ -0,0 +1,1604 @@
+{
+    Copyright (C) 2022 Loongson Technology Corporation Limited.
+
+    This unit implements the code generator for the LoongArch64
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cgcpu;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      globtype, symtype, symdef, symsym,
+      cgbase, cgobj,
+      aasmbase, aasmcpu, aasmtai,aasmdata,
+      cpubase, cpuinfo, cgutils, rgcpu,
+      parabase;
+
+    type
+      tfixref = (
+        fr_normal, { Normal type, reg + 12i }
+        fr_big, { Reg + 14i }
+        fr_reg { Reg + reg }
+      );
+      tcgloongarch64 = class(tcg)
+      public
+        procedure init_register_allocators; override;
+        procedure done_register_allocators; override;
+
+        procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);override;
+        { call instructions }
+        procedure a_call_name(list : TAsmList;const s : string; weak: boolean); override;
+        procedure a_call_reg(list : TAsmList;reg: tregister); override;
+
+        { move instructions }
+        procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister); override;
+        procedure a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference); override;
+        procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize; reg: tregister; const ref: treference); override;
+        procedure a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
+        procedure a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
+        procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
+
+        { bit scan instructions }
+        procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override;
+
+        { fpu move instructions }
+        procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
+        procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
+        procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
+
+        { basic arithmetic operations }
+        procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
+        procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
+        procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
+        procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
+
+        { comparison operations }
+        procedure a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
+        procedure a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
+
+        { jump instructions }
+        procedure a_jmp_name(list: TAsmList;const s : string); override;
+        procedure a_jmp_always(list: TAsmList;l: tasmlabel); override;
+
+        procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
+        procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
+
+
+        { mem operations }
+        procedure g_concatcopy(list: TAsmList; const source, dest: treference; len: aint); override;
+
+        { overflow check }
+        procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
+
+        { proc entry and exit }
+        procedure g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean); override;
+        procedure g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean); override;
+
+      protected
+        function fixref(list: TAsmList; var ref: treference; mode : tfixref): boolean;
+        procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
+      end;
+
+    procedure create_codegen;
+
+  { OP_NONE,OP_MOVE,OP_ADD,OP_AND,OP_DIV,OP_IDIV,OP_IMUL,OP_MUL,OP_NEG,
+    OP_NOT,OP_OR,OP_SAR,OP_SHL,OP_SHR,OP_SUB,OP_XOR,OP_ROL,OP_ROR }
+  const
+    TOpCG2AsmConstOp32: Array[topcg] of TAsmOp = (A_NONE,
+          A_NONE,A_ADDI_W,A_ANDI,A_NONE,A_NONE,A_NONE,A_NONE,
+          A_NONE,A_NONE,A_ORI,A_SRAI_W,A_SLLI_W,A_SRLI_W,
+          A_NONE,A_XORI,A_NONE,A_ROTRI_W);
+    TOpCG2AsmOp32: Array[topcg] of TAsmOp = (A_NONE,
+          A_NONE,A_ADD_W,A_AND,A_DIV_WU,A_DIV_W,A_MUL_W,
+          A_MULW_D_WU,A_NONE,A_NONE,A_OR,A_SRA_W,A_SLL_W,A_SRL_W,
+          A_SUB_W,A_XOR,A_NONE,A_ROTR_W);
+    TOpCG2AsmConstOp: Array[topcg] of TAsmOp = (A_NONE,
+          A_NONE,A_ADDI_D,A_ANDI,A_NONE,A_NONE,A_NONE,A_NONE,
+          A_NONE,A_NONE,A_ORI,A_SRAI_D,A_SLLI_D,A_SRLI_D,
+          A_NONE,A_XORI,A_NONE,A_ROTRI_D);
+    TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,
+          A_NONE,A_ADD_D,A_AND,A_DIV_DU,A_DIV_D,A_MUL_D,
+          A_MUL_D,A_NONE,A_NONE,A_OR,A_SRA_D,A_SLL_D,A_SRL_D,
+          A_SUB_D,A_XOR,A_NONE,A_ROTR_D);
+
+
+implementation
+
+    uses
+      sysutils, cclasses,
+      globals, verbose, systems, cutils,
+      symconst, fmodule, symtable,
+      rgobj, tgobj, cpupi, procinfo, paramgr, cpupara;
+
+
+    procedure tcgloongarch64.init_register_allocators;
+      begin
+        inherited init_register_allocators;
+        { From GCC REG_ALLOC_ORDER }
+        rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
+          [RS_R12,RS_R13,RS_R14,RS_R16,RS_R16,RS_R17,RS_R18,RS_R19,RS_R20,
+           RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10,RS_R11,
+           RS_R1,
+           RS_R23,RS_R24,RS_R25,RS_R26,RS_R27,RS_R28,RS_R29,RS_R30,RS_R31],first_int_imreg,[]);
+        rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
+          [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,RS_F8,
+           RS_F9,RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,RS_F16,
+           RS_F17,RS_F18,RS_F19,RS_F20,RS_F21,RS_F22,RS_F23,RS_F24,
+           RS_F25,RS_F26,RS_F27,RS_F28,RS_F29,RS_F30,RS_F31],first_fpu_imreg,[]);
+      end;
+
+
+    procedure tcgloongarch64.done_register_allocators;
+      begin
+        rg[R_INTREGISTER].free;
+        rg[R_FPUREGISTER].free;
+        inherited done_register_allocators;
+      end;
+
+
+    procedure tcgloongarch64.a_call_reg(list : TAsmList;reg: tregister);
+      begin
+        list.concat(taicpu.op_reg_reg_const(A_JIRL,NR_RETURN_ADDRESS_REG,reg,0));
+        include(current_procinfo.flags,pi_do_call);
+      end;
+
+
+    procedure tcgloongarch64.a_call_name(list : TAsmList;const s : string; weak: boolean);
+      var
+        href: treference;
+      begin
+        if not(weak) then
+          reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[])
+        else
+          reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION),0,0,[]);
+        if cs_create_pic in current_settings.moduleswitches then
+          { PIC need using global symbol through GOT.  }
+          begin
+            href.refaddr:=addr_plt;
+            list.concat(taicpu.op_ref(A_BL,href));
+          end
+        else
+          begin
+            if not(weak) then
+              href.refaddr:=addr_pcrel
+            else
+              href.refaddr:=addr_plt;
+            list.concat(taicpu.op_ref(A_BL,href));
+          end;
+        { not assigned while generating external wrappers }
+        if assigned(current_procinfo) then
+          include(current_procinfo.flags,pi_do_call);
+      end;
+
+
+    procedure tcgloongarch64.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);
+      var
+        tmpref, ref: treference;
+        tmpreg: tregister;
+        location: pcgparalocation;
+        orgsizeleft,
+        sizeleft: tcgint;
+        usesize: tcgsize;
+        reghasvalue: boolean;
+      begin
+        location:=cgpara.location;
+        tmpref:=r;
+        sizeleft:=cgpara.intsize;
+        repeat
+          paramanager.allocparaloc(list,location);
+          case location^.loc of
+            LOC_REGISTER,LOC_CREGISTER:
+              begin
+                 if (size<>OS_NO) and
+                    (tcgsize2size[size]<=sizeof(aint)) then
+                   begin
+                     a_load_ref_reg(list,size,location^.size,tmpref,location^.register);
+                     if location^.shiftval<0 then
+                       a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
+                   end
+                 { there's a lot more data left, and the current paraloc's
+                   register is entirely filled with part of that data }
+                 else if (sizeleft>sizeof(aint)) then
+                   begin
+                     a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
+                   end
+                 { we're at the end of the data, and it can be loaded into
+                   the current location's register with a single regular
+                   load }
+                 else if sizeleft in [1,2,4,8] then
+                   begin
+                     a_load_ref_reg(list,int_cgsize(sizeleft),location^.size,tmpref,location^.register);
+                     if location^.shiftval<0 then
+                       a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
+                   end
+                 { we're at the end of the data, and we need multiple loads
+                   to get it in the register because it's an irregular size }
+                 else
+                   begin
+                     { should be the last part }
+                     if assigned(location^.next) then
+                       internalerror(2022111934);
+                     { load the value piecewise to get it into the register }
+                     orgsizeleft:=sizeleft;
+                     reghasvalue:=false;
+{$ifdef cpu64bitalu}
+                     if sizeleft>=4 then
+                       begin
+                         a_load_ref_reg(list,OS_32,location^.size,tmpref,location^.register);
+                         dec(sizeleft,4);
+                         inc(tmpref.offset,4);
+                         reghasvalue:=true;
+                       end;
+{$endif cpu64bitalu}
+                     if sizeleft>=2 then
+                       begin
+                         tmpreg:=getintregister(list,location^.size);
+                         a_load_ref_reg(list,OS_16,location^.size,tmpref,tmpreg);
+                         dec(sizeleft,2);
+                         if reghasvalue then
+                           begin
+                             a_op_const_reg(list,OP_SHL,location^.size,(orgsizeleft-(sizeleft+2))*8,tmpreg);
+                             a_op_reg_reg(list,OP_OR,location^.size,tmpreg,location^.register);
+                           end
+                         else
+                           begin
+                             a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
+                           end;
+                         inc(tmpref.offset,2);
+                         reghasvalue:=true;
+                       end;
+                     if sizeleft=1 then
+                       begin
+                         tmpreg:=getintregister(list,location^.size);
+                         a_load_ref_reg(list,OS_8,location^.size,tmpref,tmpreg);
+                         dec(sizeleft,1);
+                         if reghasvalue then
+                           begin
+                             a_op_const_reg(list,OP_SHL,location^.size,(orgsizeleft-(sizeleft+1))*8,tmpreg);
+                             a_op_reg_reg(list,OP_OR,location^.size,tmpreg,location^.register)
+                           end
+                         else
+                           a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
+                         inc(tmpref.offset);
+                       end;
+                     if location^.shiftval<0 then
+                       a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
+                     { the loop will already adjust the offset and sizeleft }
+                     dec(tmpref.offset,orgsizeleft);
+                     sizeleft:=orgsizeleft;
+                   end;
+              end;
+            LOC_REFERENCE,LOC_CREFERENCE:
+              begin
+                reference_reset_base(ref,location^.reference.index,location^.reference.offset,ctempposinvalid,newalignment(cgpara.alignment,cgpara.intsize-sizeleft),[]);
+                a_load_ref_cgparalocref(list,size,sizeleft,tmpref,ref,cgpara,location);
+              end;
+            LOC_FPUREGISTER,LOC_CFPUREGISTER:
+              begin
+                { can be not a float size in case of a record passed in fpu registers }
+                { the size comparison is to catch F128 passed in two 64 bit floating point registers }
+                if is_float_cgsize(size) and
+                   (tcgsize2size[location^.size]>=tcgsize2size[size]) then
+                  usesize:=size
+                else
+                  usesize:=location^.size;
+                a_loadfpu_ref_reg(list,usesize,location^.size,tmpref,location^.register);
+              end
+            else
+              internalerror(2022111935);
+          end;
+          inc(tmpref.offset,tcgsize2size[location^.size]);
+          dec(sizeleft,tcgsize2size[location^.size]);
+          location:=location^.next;
+        until not assigned(location);
+      end;
+
+    procedure tcgloongarch64.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
+      begin
+        if a=0 then
+          a_load_reg_ref(list,size,size,NR_R0,ref)
+        else
+          inherited a_load_const_ref(list,size,a,ref);
+      end;
+
+
+    procedure tcgloongarch64.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
+        reg: tregister; const ref: treference);
+      var
+        href: treference;
+        op: TAsmOp;
+        hlist: TAsmList;
+      const
+        st_ops: array[boolean,OS_8..OS_INT] of TAsmOp = (
+          (A_ST_B,A_ST_H,A_ST_W,A_ST_D),
+          (A_STX_B,A_STX_H,A_STX_W,A_STX_D)
+        );
+        stptr_ops: array[OS_8..OS_INT] of TAsmOp = (A_NONE,A_NONE,A_STPTR_W,A_STPTR_D);
+      begin
+        if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+          internalerror(2022111936);
+        if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+          internalerror(2022111937);
+
+        hlist:=TAsmList.create;
+        tosize:=tcgsize2unsigned[tosize];
+        if stptr_ops[tosize]<>A_NONE then
+          begin
+            href:=ref;
+            if fixref(hlist,href,fr_big) then
+              begin
+                list.concatList(hlist);
+                hlist.free;
+                list.concat(taicpu.op_reg_ref(stptr_ops[tosize],reg,href));
+                exit;
+              end;
+          end;
+        hlist.Clear;
+        hlist.free;
+        href:=ref;
+        op:=st_ops[fixref(list,href,fr_reg),tosize];
+        list.concat(taicpu.op_reg_ref(op,reg,href));
+      end;
+
+
+    procedure tcgloongarch64.a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
+      var
+        href: treference;
+        op: TAsmOp;
+        usizef,usizet: tcgsize;
+        have_done: boolean;
+        hlist: TAsmList;
+        samesign: boolean;
+      const
+        ld_ops: array[boolean,boolean,OS_8..OS_INT] of TAsmOp = (
+          ((A_LD_B,A_LD_H,A_LD_W,A_LD_D),
+           (A_LD_BU,A_LD_HU,A_LD_WU,A_LD_D)),
+          ((A_LDX_B,A_LDX_H,A_LDX_W,A_LDX_D),
+           (A_LDX_BU,A_LDX_HU,A_LDX_WU,A_LDX_D))
+        );
+      begin
+        if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+          internalerror(2022111938);
+        if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+          internalerror(2022111939);
+
+        hlist:=TAsmList.create;
+        have_done:=false;
+        usizef:=tcgsize2unsigned[fromsize];
+        usizet:=tcgsize2unsigned[tosize];
+        samesign:=((fromsize=usizef) and (tosize=usizet)) or ((fromsize<>usizef) and (tosize<>usizet));
+        if (fromsize=OS_S32) then
+          begin
+            href:=ref;
+            if fixref(hlist,href,fr_big) then
+              begin
+                hlist.concat(taicpu.op_reg_ref(A_LDPTR_W,reg,href));
+                have_done:=true;
+              end;
+          end
+        else if (fromsize=OS_S64) or (fromsize=OS_64) then
+          begin
+            href:=ref;
+            if fixref(hlist,href,fr_big) then
+              begin
+                hlist.concat(taicpu.op_reg_ref(A_LDPTR_D,reg,href));
+                have_done:=true;
+              end;
+          end;
+
+        if not(have_done) then
+          begin
+            hlist.Clear;
+            href:=ref;
+            op:=ld_ops[fixref(list,href,fr_reg),fromsize=usizef,usizef];
+            list.concat(taicpu.op_reg_ref(op,reg,href));
+          end
+        else
+          list.concatList(hlist);
+
+        hlist.free;
+        { First, when load a reg to OS_(S)INT, we use signed load operations.
+          Then, when fromsize is less or equal than tosize, we can not do
+          a_load_reg_reg because of signed load operations. }
+        if (fromsize<>tosize) and (not (tosize in [OS_SINT,OS_INT])) and (not((usizef<=usizet) and samesign)) then
+          a_load_reg_reg(list,fromsize,tosize,reg,reg);
+      end;
+
+
+    procedure tcgloongarch64.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister);
+      begin
+        case size of
+          OS_S8: a:= tcgint(shortint(a));
+          OS_S16: a:= tcgint(smallint(a));
+          OS_S32: a:= tcgint(longint(a));
+        else
+          ;
+        end;
+        list.concat(taicpu.op_reg_const(A_LI_D,register,a));
+      end;
+
+
+    procedure tcgloongarch64.a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
+      const
+        zeroextbits: array[OS_8..OS_INT] of longint=(7,15,31,63);
+        signextop: array[OS_8..OS_INT] of TAsmOp=(A_EXT_W_B,A_EXT_W_H,A_ADDI_W,A_MOVE);
+      var
+        ai: taicpu;
+        ufromsize,utosize: tcgsize;
+        ufrom,uto : boolean;
+      begin
+        if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+          internalerror(2022111940);
+        if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+          internalerror(2022111941);
+        ufromsize:=tcgsize2unsigned[fromsize];
+        utosize:=tcgsize2unsigned[tosize];
+        ufrom:=ufromsize=fromsize;
+        uto:=utosize=tosize;
+        if (fromsize=tosize) or ((ufromsize=OS_INT) and (utosize=OS_INT)) then
+          begin
+            ai:=taicpu.op_reg_reg(A_MOVE,reg2,reg1);
+            list.concat(ai);
+            rg[R_INTREGISTER].add_move_instruction(ai);
+          end
+        else if ufromsize>=utosize then
+          begin
+            if uto then
+              list.concat(taicpu.op_reg_reg_const_const(A_BSTRPICK_D,reg2,reg1,zeroextbits[utosize],0))
+            else if utosize=OS_32 then
+              list.concat(taicpu.op_reg_reg_const(signextop[utosize],reg2,reg1,0))
+            else
+              list.concat(taicpu.op_reg_reg(signextop[utosize],reg2,reg1));
+          end
+        else { ufromsize<utosize }
+          begin
+            if ufrom then
+              list.concat(taicpu.op_reg_reg_const_const(A_BSTRPICK_D,reg2,reg1,zeroextbits[ufromsize],0))
+            else
+              begin
+                if ufromsize=OS_32 then
+                  list.concat(taicpu.op_reg_reg_const(signextop[ufromsize],reg2,reg1,0))
+                else
+                  list.concat(taicpu.op_reg_reg(signextop[ufromsize],reg2,reg1));
+                if uto then
+                  list.concat(taicpu.op_reg_reg_const_const(A_BSTRPICK_D,reg2,reg2,zeroextbits[utosize],0));
+              end;
+          end;
+      end;
+
+
+    procedure tcgloongarch64.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
+      var
+        href: treference;
+        l: TAsmLabel;
+      begin
+        href:=ref;
+        fixref(list,href,fr_normal);
+        { Fixref, so simplely work here. }
+        if href.offset=0 then
+          a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r)
+        else if is_simm12(href.offset) and (href.base<>NR_NO) then
+          list.concat(taicpu.op_reg_reg_const(A_ADDI_D,r,href.base,href.offset))
+        else
+          internalerror(2022111942);
+      end;
+
+
+    procedure tcgloongarch64.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister);
+      begin
+        internalerror(2022111943);
+      end;
+
+
+    { dstreg = dstreg op imm }
+    procedure tcgloongarch64.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
+      begin
+        a_op_const_reg_reg(list,op,size,a,reg,reg);
+      end;
+
+
+    { dstreg = dstreg op srcreg }
+    procedure tcgloongarch64.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
+      begin
+        a_op_reg_reg_reg(list,op,size,src,dst,dst);
+      end;
+
+
+    procedure tcgloongarch64.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
+      var
+        tmpreg: TRegister;
+        usetmp: boolean;
+      begin
+        optimize_op_const(size,op,a);
+
+        if op=OP_NONE then
+          begin
+            a_load_reg_reg(list,size,size,src,dst);
+            exit;
+          end;
+
+        { Sub const to add -const }
+        if op=OP_SUB then
+          begin
+            op:=OP_ADD;
+            a:=-a;
+          end;
+
+        { Make sure shift operation const not overflow. }
+        if op in [OP_SAR,OP_SHL,OP_SHR] then
+          if (size in [OS_32,OS_S32]) and (a>31) then
+            a:=31
+          else if (size in [OS_16,OS_S16]) and (a>15) then
+            a:=15
+          else if (size in [OS_8,OS_S8]) and (a>7) then
+            a:=7
+          else if (size in [OS_64,OS_S64]) and (a>63) then
+            a:=63;
+
+        { Rotate imm bits left to rotate (size - imm) bits right. }
+        if op=OP_ROL then
+          begin
+            op:=OP_ROR;
+            if size in [OS_32,OS_S32] then
+              a:=32-a
+            else if size in [OS_16,OS_S16] then
+              a:=16-a
+            else if size in [OS_8,OS_S8] then
+              a:=8-a
+            else
+              a:=64-a;
+          end;
+
+        { Only effective imm can be used by insn operation. }
+        if ((is_simm12(a) and (op=OP_ADD)) or
+            (is_uimm12(a) and (op<>OP_ADD))) and
+            (TOpCG2AsmConstOp32[op]<>A_NONE)
+            { or (TOpCG2AsmConstOp[op]<>A_NONE)} then
+          begin
+            usetmp:=false;
+            { Size = 16bits or 8bits do special if rotate. }
+            if (size in [OS_16,OS_S16]) and (op=OP_ROR) then
+              begin
+                tmpreg:=getintregister(list,OS_INT);
+                list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg,src,31,16));
+                usetmp:=true;
+              end
+            else if (size in [OS_8,OS_S8]) and (op=OP_ROR) then
+              begin
+                tmpreg:=getintregister(list,OS_INT);
+                list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg,src,15,8));
+                usetmp:=true;
+              end
+            { Signext to 32bits if sra 16bits or 8bits}
+            else if (size in [OS_S16,OS_S8]) and (op=OP_SAR) then
+              begin
+                tmpreg:=getintregister(list,OS_INT);
+                a_load_reg_reg(list,size,OS_S32,tmpreg,src);
+                usetmp:=true;
+              end;
+
+            if size in [OS_64,OS_S64] then
+              begin
+                { Use tmp cannot be true here. }
+                list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp[op],dst,src,a));
+                maybeadjustresult(list,op,size,dst);
+              end
+            else { OS_32/S32, OS_16/S16, OS_8/S8 }
+              begin
+                if usetmp then
+                  list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp32[op],dst,tmpreg,a))
+                else
+                  list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp32[op],dst,src,a));
+                maybeadjustresult(list,op,size,dst);
+              end;
+          end
+        else
+          begin
+            tmpreg:=getintregister(list,OS_INT);
+            a_load_const_reg(list,size,a,tmpreg);
+            a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
+          end;
+      end;
+
+
+    procedure tcgloongarch64.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
+      var
+        tmpreg1, tmpreg2: TRegister;
+        usetmp1, usetmp2: boolean;
+      begin
+        usetmp1:=false;
+        usetmp2:=false;
+        if op=OP_NOT then
+          begin
+            list.concat(taicpu.op_reg_reg_reg(A_NOR,dst,NR_R0,src1));
+            maybeadjustresult(list,op,size,dst);
+            exit;
+          end
+        else if op=OP_NEG then
+          begin
+            list.concat(taicpu.op_reg_reg_reg(A_SUB_D,dst,NR_R0,src1));
+            maybeadjustresult(list,op,size,dst);
+            exit;
+          end
+        else if op=OP_MOVE then
+          begin
+            a_load_reg_reg(list,size,size,src1,dst);
+            exit;
+          end
+        else if op=OP_ROL then
+          begin
+            tmpreg1:=getintregister(list,OS_INT);
+            list.concat(taicpu.op_reg_reg_reg(A_SUB_D,tmpreg1,NR_R0,src1));
+            usetmp1:=true;
+            op:=OP_ROR;
+          end;
+
+        if (TOpCG2AsmOp32[op]<>A_NONE) {or (TOpCG2AsmConstOp[op]<>A_NONE)} then
+          begin
+            { Size = 16bits or 8bits do special if rotate. }
+            if (size in [OS_16,OS_S16]) and (op=OP_ROR) then
+              begin
+                tmpreg2:=getintregister(list,OS_INT);
+                list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,src2,31,16));
+                usetmp2:=true;
+              end
+            else if (size in [OS_8,OS_S8]) and (op=OP_ROR) then
+              begin
+                tmpreg2:=getintregister(list,OS_INT);
+                list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,src2,15,8));
+                list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,tmpreg2,31,16));
+                usetmp2:=true;
+              end
+            { Signext to 32bits if sra 16bits or 8bits}
+            else if (size in [OS_S16,OS_S8]) and (op=OP_SAR) then
+              begin
+                tmpreg2:=getintregister(list,OS_INT);
+                a_load_reg_reg(list,size,OS_S32,src2,tmpreg2);
+                usetmp2:=true;
+              end;
+
+            if size in [OS_64,OS_S64] then
+              begin
+                { usetmp2 cannot be true here. }
+                if usetmp1 then
+                  list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,tmpreg1))
+                else
+                  list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,src1));
+                maybeadjustresult(list,op,size,dst);
+              end
+            else
+              begin
+                if usetmp1 and usetmp2 then
+                  list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,tmpreg2,tmpreg1))
+                else if usetmp1 then
+                  list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,src2,tmpreg1))
+                else if usetmp2 then
+                  list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,tmpreg2,src1))
+                else
+                  list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,src2,src1));
+                maybeadjustresult(list,op,size,dst);
+              end;
+          end;
+      end;
+
+
+    procedure tcgloongarch64.a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
+      var
+        tmpreg: tregister;
+      begin
+        if a = 0 then
+          a_cmp_reg_reg_label(list,size,cmp_op,NR_R0,reg,l)
+        else
+          begin
+            tmpreg := GetIntRegister(list,OS_INT);
+            a_load_const_reg(list,OS_INT,a,tmpreg);
+            a_cmp_reg_reg_label(list, size, cmp_op, tmpreg, reg, l);
+          end;
+      end;
+
+
+    procedure tcgloongarch64.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg1,reg2 : tregister;l : tasmlabel);
+      const
+        { OC_NONE,OC_EQ,OC_GT,OC_LT,OC_GTE,OC_LTE,OC_NE,OC_BE,OC_B,OC_AE,OC_A }
+        TOpCmp2AsmCond: Array[TOpCmp] of TAsmCond = (C_NONE,
+          C_EQ,C_GT,C_LT,C_GE,C_LE,C_NE,C_LEU,C_LTU,C_GEU,C_GTU);
+        TOpCmp2AsmCondZ: Array[TOpCmp] of TAsmCond = (C_NONE,
+          C_EQZ,C_GTZ,C_LTZ,C_GEZ,C_LEZ,C_NEZ,C_NONE,C_NONE,C_NONE,C_NONE);
+      var
+        href: treference;
+        ai: taicpu;
+      begin
+        reference_reset_symbol(href,l,0,0,[]);
+        { It is better to use pcrel instead addr_b16 or addr_b21,
+          because we hardly know the real op after optimizing. }
+        href.refaddr:=addr_pcrel;
+        if (reg1=NR_R0) or (reg2=NR_R0) then
+          begin
+            if (reg1=NR_R0) and (reg2=NR_R0) then
+              begin
+                a_jmp_always(list,l);
+                exit;
+              end
+            else if reg2=NR_R0 then
+              begin
+                reg2:=reg1;
+                reg1:=NR_R0;
+                cmp_op:=swap_opcmp(cmp_op);
+              end;
+            if TOpCmp2AsmCondZ[cmp_op]<>C_NONE then
+              begin
+                ai:=taicpu.op_reg_ref(A_BXX,reg2,href);
+                ai.is_jmp:=true;
+                ai.condition:=TOpCmp2AsmCondZ[cmp_op];
+                list.concat(ai);
+                exit;
+              end;
+          end;
+        ai:=taicpu.op_reg_reg_ref(A_BXX,reg2,reg1,href);
+        ai.is_jmp:=true;
+        ai.condition:=TOpCmp2AsmCond[cmp_op];
+        list.concat(ai);
+      end;
+
+
+    procedure tcgloongarch64.a_jmp_name(list : TAsmList;const s : string);
+      var
+        ai: taicpu;
+        href: treference;
+      begin
+        reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[]);
+        href.refaddr:=addr_b26;
+        ai:=taicpu.op_ref(A_B,href);
+        ai.is_jmp:=true;
+        list.concat(ai);
+      end;
+
+
+    procedure tcgloongarch64.a_jmp_always(list : TAsmList;l: tasmlabel);
+      var
+        ai: taicpu;
+        href: treference;
+      begin
+        reference_reset_symbol(href,l,0,0,[]);
+        href.refaddr:=addr_b26;
+        ai:=taicpu.op_ref(A_B,href);
+        ai.is_jmp:=true;
+        list.concat(ai);
+       end;
+
+
+    procedure tcgloongarch64.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
+      var
+        op: TAsmOp;
+        ai: taicpu;
+      const
+        FpuConvOp: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
+                   ((A_FMOV_S,A_FCVT_D_S),(A_FCVT_S_D,A_FMOV_D));
+      begin
+        if (reg1<>reg2) or (fromsize<>tosize) then
+          begin
+            ai:= taicpu.op_reg_reg(fpuconvop[fromsize,tosize],reg2,reg1);
+            list.concat(ai);
+            if (fromsize=tosize) then
+              rg[R_FPUREGISTER].add_move_instruction(ai);
+          end;
+      end;
+
+
+    procedure tcgloongarch64.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
+      var
+        op: TAsmOp;
+        href: treference;
+      const
+        fld_ops: array[boolean,boolean] of TAsmOp = (
+          (A_FLD_D, A_FLD_S),
+          (A_FLDX_D, A_FLDX_S)
+        );
+      begin
+        href:=ref;
+        op:=fld_ops[fixref(list,href,fr_reg),fromsize=OS_F32];
+        list.concat(taicpu.op_reg_ref(op,reg,href));
+        if fromsize<>tosize then
+          a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
+      end;
+
+    procedure tcgloongarch64.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
+      var
+        op: TAsmOp;
+        tmpfreg: TRegister;
+        href: treference;
+        fst_ops: array[boolean,boolean] of TAsmOp = (
+          (A_FST_D, A_FST_S),
+          (A_FSTX_D, A_FSTX_S)
+        );
+      begin
+        if fromsize<>tosize then
+          begin
+            tmpfreg:=getfpuregister(list,tosize);
+            a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpfreg);
+            reg:=tmpfreg;
+          end;
+
+        href:=ref;
+        op:=fst_ops[fixref(list,href,fr_reg),tosize=OS_F32];
+        list.concat(taicpu.op_reg_ref(op,reg,href));
+      end;
+
+
+    procedure tcgloongarch64.g_concatcopy(list: TAsmList; const source, dest: treference; len: aint);
+      var
+        tmpreg,countreg: TRegister;
+        src,dst: TReference;
+        lab: tasmlabel;
+        len_8,tmplen: longint;
+        len_1,len_2,len_4: boolean;
+      begin
+        { Size is zero }
+        if len=0 then
+          exit;
+        { It's too large or illegal. }
+        if len>high(longint) then
+          internalerror(2022111944);
+        { len = d*8(+4?)(+2?)(+1?). }
+        len_8:=len div 8;
+        tmplen:=len-len_8*8;
+        len_1:=(tmplen and 1)<>0;
+        len_2:=(tmplen and 2)<>0;
+        len_4:=(tmplen and 4)<>0;
+
+        { Set the reference. }
+        reference_reset(src,sizeof(aint),[]);
+        reference_reset(dst,sizeof(aint),[]);
+        src.base:=GetAddressRegister(list);
+        dst.base:=GetAddressRegister(list);
+        src.refaddr:=addr_reg_12i;
+        dst.refaddr:=addr_reg_12i;
+        a_loadaddr_ref_reg(list,source,src.base);
+        a_loadaddr_ref_reg(list,dest,dst.base);
+        tmpreg:= GetIntRegister(list, OS_INT);
+        { TODO Some optimization. }
+        if len_8>0 then
+          begin
+            if len_8>1 then
+              begin
+                countreg := GetIntRegister(list,OS_INT);
+                a_load_const_reg(list,OS_INT,len_8,countreg);
+                current_asmdata.getjumplabel(lab);
+                a_label(list, lab);
+              end;
+            list.concat(taicpu.op_reg_ref(A_LD_D,tmpreg,src));
+            list.concat(taicpu.op_reg_ref(A_ST_D,tmpreg,dst));
+            if len_1 or len_2 or len_4 or (len_8>1) then
+              begin
+                list.concat(taicpu.op_reg_reg_const(A_ADDI_D,src.base,src.base,8));
+                list.concat(taicpu.op_reg_reg_const(A_ADDI_D,dst.base,dst.base,8));
+              end;
+            if len_8>1 then
+              begin
+                list.concat(taicpu.op_reg_reg_const(A_ADDI_D,countreg,countreg,-1));
+                a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
+              end;
+          end; { len_8>0 }
+        if len_4 then
+          begin
+            list.concat(taicpu.op_reg_ref(A_LD_W,tmpreg,src));
+            list.concat(taicpu.op_reg_ref(A_ST_W,tmpreg,dst));
+            inc(src.offset,4);
+            inc(dst.offset,4);
+          end;
+        if len_2 then
+          begin
+            list.concat(taicpu.op_reg_ref(A_LD_H,tmpreg,src));
+            list.concat(taicpu.op_reg_ref(A_ST_H,tmpreg,dst));
+            inc(src.offset,2);
+            inc(dst.offset,2);
+          end;
+        if len_1 then
+          begin
+            list.concat(taicpu.op_reg_ref(A_LD_B,tmpreg,src));
+            list.concat(taicpu.op_reg_ref(A_ST_B,tmpreg,dst));
+          end;
+      end;
+
+
+    procedure tcgloongarch64.g_overflowcheck(list: TAsmList; const loc: tlocation; def: tdef);
+      begin
+        { TODO }
+        { internalerror(2022111945); }
+      end;
+
+
+    procedure tcgloongarch64.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
+      var
+        regs, fregs: tcpuregisterset;
+        r: TSuperRegister;
+        href: treference;
+        stackcount, stackAdjust: longint;
+      begin
+        if not(nostackframe) then
+          begin
+            a_reg_alloc(list,NR_STACK_POINTER_REG);
+            { Always use $fp. }
+            a_reg_alloc(list,NR_FRAME_POINTER_REG);
+            { Int registers }
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+            regs:=regs+[RS_FRAME_POINTER_REG];
+            { Does it call another function? }
+            if (pi_do_call in current_procinfo.flags) or
+               (RS_R1 in rg[R_INTREGISTER].used_in_proc) then
+              regs:=regs+[RS_RETURN_ADDRESS_REG];
+            { Float registers }
+            fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+            { Calculate the stackcount of all regesters. }
+            stackcount:=16;
+            for r:=RS_R1 to RS_R31 do
+              if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
+                inc(stackcount,8);
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                inc(stackcount,8);
+            { Calculate the frame total size. }
+            inc(localsize,stackcount);
+            if localsize=0 then
+              exit;
+            { ADDI instructions only has 12bits-sign-imm range, [-2048,2047]. Once we
+              use -2048 in the prologue, we cannot get back in epilogue use one ADDI.
+              Due to LoongArch psABI, we should save the $ra and then use it as free.
+              We should make $fp as $fp on entry, so ADDI cannot do 2048 size. It
+              seems use -2032 may a good choice without care of many of cases. }
+            if (-localsize<-2032) and (not (RS_RETURN_ADDRESS_REG in regs)) then
+              begin
+                regs:=regs+[RS_RETURN_ADDRESS_REG];
+                inc(localsize,8);
+                inc(stackcount,8);
+              end;
+            if (localsize mod 16)<>0 then
+              inc(localsize,16-(localsize mod 16));
+            { Do first decrease the stack, and record the stackadjust. }
+            stackadjust:=0;
+            if (-localsize<-2032) then
+              begin
+                list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-2032));
+                reference_reset_base(href,NR_STACK_POINTER_REG,2032-8,ctempposinvalid,0,[]);
+                href.refaddr:=addr_reg_12i;
+                stackadjust:=2032;
+                current_asmdata.asmcfi.cfa_def_cfa_offset(list,2032);
+              end
+            else
+              begin
+                list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize));
+                reference_reset_base(href,NR_STACK_POINTER_REG,localsize-8,ctempposinvalid,0,[]);
+                href.refaddr:=addr_reg_12i;
+                stackadjust:=localsize;
+                current_asmdata.asmcfi.cfa_def_cfa_offset(list,localsize);
+              end;
+            { $ra in cfa -8. }
+            if RS_RETURN_ADDRESS_REG in regs then
+              begin
+                list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,RS_RETURN_ADDRESS_REG,R_SUBWHOLE),href));
+                current_asmdata.asmcfi.cfa_offset(list,NR_RETURN_ADDRESS_REG,-8);
+              end;
+            { $fp in cfa -16. }
+            dec(href.offset,8);
+            list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,RS_FRAME_POINTER_REG,R_SUBWHOLE),href));
+            current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-16);
+            { $fp = cfa. }
+            list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackadjust));
+            current_asmdata.asmcfi.cfa_def_cfa(list,NR_FRAME_POINTER_REG,0);
+            { Int registers }
+            for r:=RS_R1 to RS_R31 do
+              if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
+                begin
+                  dec(href.offset,8);
+                  list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+                  current_asmdata.asmcfi.cfa_offset(list,newreg(R_INTREGISTER,r,R_SUBWHOLE),href.offset-stackadjust);
+                end;
+            { Float registers }
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                begin
+                  dec(href.offset,8);
+                  list.concat(taicpu.op_reg_ref(A_FST_D,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+                  current_asmdata.asmcfi.cfa_offset(list,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href.offset);
+                end;
+            { Decrese the remaining stack size. }
+            if (localsize-stackadjust)>2048 then
+              begin
+                a_load_const_reg(list,OS_INT,localsize-stackadjust,NR_RETURN_ADDRESS_REG);
+                list.concat(taicpu.op_reg_reg_reg(A_SUB_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+              end
+            else if (localsize-stackadjust)>0 then
+              begin
+                { TODO It seems to no need $ra. }
+                list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,stackadjust-localsize));
+              end;
+          end;
+      end; { g_proc_entry }
+
+    procedure tcgloongarch64.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
+      var
+        r: tsuperregister;
+        regs, fregs: tcpuregisterset;
+        stackcount, localsize, stackleft: longint;
+        href: treference;
+      begin
+        if not(nostackframe) then
+          begin
+            localsize:=current_procinfo.calc_stackframe_size;
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+            fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+            regs:=regs+[RS_FRAME_POINTER_REG];
+            if (pi_do_call in current_procinfo.flags) or
+               (RS_R1 in rg[R_INTREGISTER].used_in_proc) then
+              regs:=regs+[RS_RETURN_ADDRESS_REG];
+            stackcount:=16;
+            for r:=RS_R1 to RS_R31 do
+              if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
+                inc(stackcount,8);
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                inc(stackcount,8);
+            inc(localsize,stackcount);
+            if (-localsize<-2032) and (not (RS_RETURN_ADDRESS_REG in regs)) then
+              begin
+                regs:=regs+[RS_RETURN_ADDRESS_REG];
+                inc(localsize,8);
+                inc(stackcount,8);
+              end;
+            if (localsize mod 16)<>0 then
+              inc(localsize,16-(localsize mod 16));
+
+            stackleft:=0;
+            if (-localsize<-2032) then
+              stackleft:=2032
+            else
+              stackleft:=localsize;
+            list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,-stackleft));
+            reference_reset_base(href,NR_STACK_POINTER_REG,stackleft-8,ctempposinvalid,0,[]);
+            href.refaddr:=addr_reg_12i;
+            { Restore registers. }
+            if RS_RETURN_ADDRESS_REG in regs then
+              begin
+                list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,RS_RETURN_ADDRESS_REG,R_SUBWHOLE),href));
+                current_asmdata.asmcfi.cfa_restore(list,NR_RETURN_ADDRESS_REG);
+              end;
+            dec(href.offset,8);
+            list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,RS_FRAME_POINTER_REG,R_SUBWHOLE),href));
+            current_asmdata.asmcfi.cfa_restore(list,NR_FRAME_POINTER_REG);
+            current_asmdata.asmcfi.cfa_def_cfa(list,NR_STACK_POINTER_REG,stackleft);
+            for r:=RS_R1 to RS_R31 do
+              if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
+                begin
+                  dec(href.offset,8);
+                  list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+                  current_asmdata.asmcfi.cfa_restore(list,newreg(R_INTREGISTER,r,R_SUBWHOLE));
+                end;
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                begin
+                  dec(href.offset,8);
+                  list.concat(taicpu.op_reg_ref(A_FLD_D,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+                  current_asmdata.asmcfi.cfa_restore(list,newreg(R_FPUREGISTER,r,R_SUBWHOLE));
+                end;
+            { Restore $sp. }
+            list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,stackleft));
+          end;
+        { jr $ra. }
+        reference_reset_base(href,NR_RETURN_ADDRESS_REG,0,ctempposinvalid,0,[]);
+        href.refaddr:=addr_reg;
+        list.concat(taicpu.op_ref(A_JR,href));
+      end; { g_proc_exit }
+
+
+    procedure tcgloongarch64.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
+    var
+      signed: Boolean;
+      l: TAsmLabel;
+      tmpreg: tregister;
+      ai: taicpu;
+      href: treference;
+      tmpreg0,tmpreg1: tregister;
+    begin
+      if setflags then
+        begin
+          if is_simm12(a) and (op=OP_ADD) then
+            begin
+              current_asmdata.getjumplabel(l);
+              reference_reset_symbol(href,l,0,0,[]);
+              href.refaddr:=addr_pcrel;
+              if size in [OS_64,OS_S64,OS_32,OS_S32] then
+                begin
+                  { Backup src so we can compare with it. }
+                  tmpreg1:=getintregister(list,OS_INT);
+                  a_load_reg_reg(list,OS_INT,OS_INT,src,tmpreg1);
+                end;
+              if size in [OS_64,OS_S64] then
+                list.concat(taicpu.op_reg_reg_const(A_ADDI_D,dst,src,a))
+              else
+                list.concat(taicpu.op_reg_reg_const(A_ADDI_W,dst,src,a));
+              case size of
+                OS_S64,OS_S32:
+                  begin
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg1,href);
+                    if a<0 then
+                      ai.condition:=C_LT
+                    else
+                      ai.condition:=C_GE;
+                  end;
+                OS_S16,OS_S8:
+                  begin
+                    tmpreg0:=getintregister(list,OS_INT);
+                    a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
+                    ai.condition:=C_EQ;
+                  end;
+                OS_64,OS_32:
+                  begin
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg1,href);
+                    ai.condition:=C_GEU;
+                  end;
+                OS_16,OS_8:
+                  begin
+                    tmpreg0:=getintregister(list,OS_INT);
+                    if size=OS_16 then
+                      a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
+                    else
+                      a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
+                    ai.condition:=C_GTU;
+                  end;
+                else
+                  internalerror(2022082303);
+                end;
+                ai.is_jmp:=true;
+                list.concat(ai);
+              a_call_name(list,'FPC_OVERFLOW',false);
+              a_label(list,l);
+            end
+          else if op in [OP_ADD,OP_SUB,OP_MUL,OP_IMUL,OP_IDIV] then
+            begin
+              tmpreg:=getintregister(list,size);
+              a_load_const_reg(list,size,a,tmpreg);
+              a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
+            end
+          else
+            internalerror(2022082302);
+        end
+      else
+        a_op_const_reg_reg(list,op,size,a,src,dst);
+    end;
+
+
+    procedure tcgloongarch64.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
+      var
+      signed: Boolean;
+      l: TAsmLabel;
+      tmpreg0,tmpreg1,tmpreg2,tmpreg3: tregister;
+      ai: taicpu;
+      href: treference;
+    begin
+      signed:=tcgsize2unsigned[size]<>size;
+
+      if setflags then
+        case op of
+          OP_ADD:
+            begin
+              current_asmdata.getjumplabel(l);
+              reference_reset_symbol(href,l,0,0,[]);
+              href.refaddr:=addr_pcrel;
+              if size in [OS_64,OS_S64,OS_32,OS_S32] then
+                begin
+                  { Backup src so we can compare with it. }
+                  tmpreg2:=getintregister(list,OS_INT);
+                  tmpreg3:=getintregister(list,OS_INT);
+                  a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
+                  a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
+                end;
+              if size in [OS_S64,OS_64] then
+                list.Concat(taicpu.op_reg_reg_reg(A_ADD_D,dst,src2,src1))
+              else
+                list.Concat(taicpu.op_reg_reg_reg(A_ADD_W,dst,src2,src1));
+              case size of
+                OS_S64,OS_S32:
+                  begin
+                    { if (src1<0)<>(dst<src2) overflow; }
+                    tmpreg0:=getintregister(list,OS_INT);
+                    tmpreg1:=getintregister(list,OS_INT);
+                    list.Concat(taicpu.op_reg_reg_const(A_SLTI,tmpreg0,tmpreg2,0));
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg1,dst,tmpreg3));
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
+                    ai.condition:=C_EQ;
+                  end;
+                OS_S16,OS_S8:
+                  begin
+                    tmpreg0:=getintregister(list,OS_INT);
+                    a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
+                    ai.condition:=C_EQ;
+                  end;
+                OS_64,OS_32:
+                  begin
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg3,href);
+                    ai.condition:=C_GEU;
+                  end;
+                OS_16,OS_8:
+                  begin
+                    tmpreg0:=getintregister(list,OS_INT);
+                    if size=OS_16 then
+                      a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
+                    else
+                      a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
+                    ai.condition:=C_GTU;
+                  end;
+              else
+                internalerror(2022082304);
+              end;
+              ai.is_jmp:=true;
+              list.concat(ai);
+              a_call_name(list,'FPC_OVERFLOW',false);
+              a_label(list,l);
+            end;
+          OP_SUB:
+            begin
+              current_asmdata.getjumplabel(l);
+              reference_reset_symbol(href,l,0,0,[]);
+              href.refaddr:=addr_pcrel;
+              if size in [OS_64,OS_S64,OS_32,OS_S32] then
+                begin
+                  { Backup src so we can compare with it. }
+                  tmpreg2:=getintregister(list,OS_INT);
+                  tmpreg3:=getintregister(list,OS_INT);
+                  a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
+                  a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
+                end;
+              if size in [OS_S64,OS_64] then
+                list.Concat(taicpu.op_reg_reg_reg(A_SUB_D,dst,src2,src1))
+              else
+                list.Concat(taicpu.op_reg_reg_reg(A_SUB_W,dst,src2,src1));
+              case size of
+                OS_S64,OS_S32:
+                  begin
+                    { if (src1<0)<>(dst<src2) overflow; }
+                    tmpreg0:=getintregister(list,OS_INT);
+                    tmpreg1:=getintregister(list,OS_INT);
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,NR_R0,tmpreg2));
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg1,dst,tmpreg3));
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
+                    ai.condition:=C_EQ;
+                  end;
+                OS_S16,OS_S8:
+                  begin
+                    tmpreg0:=getintregister(list,OS_INT);
+                    a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
+                    ai.condition:=C_EQ;
+                  end;
+                OS_64,OS_32:
+                  begin
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg3,dst,href);
+                    ai.condition:=C_GEU;
+                  end;
+                OS_16,OS_8:
+                  begin
+                    tmpreg0:=getintregister(list,OS_INT);
+                    if size=OS_16 then
+                      a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
+                    else
+                      a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
+                    ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
+                    ai.condition:=C_GTU;
+                  end;
+              else
+                internalerror(2022082305);
+              end;
+              ai.is_jmp:=true;
+              list.concat(ai);
+              a_call_name(list,'FPC_OVERFLOW',false);
+              a_label(list,l);
+            end;
+          OP_IMUL:
+            begin
+              { No overflow if upper result is same as sign of result }
+              current_asmdata.getjumplabel(l);
+              reference_reset_symbol(href,l,0,0,[]);
+              href.refaddr:=addr_pcrel;
+              tmpreg0:=getintregister(list,OS_INT);
+              tmpreg1:=getintregister(list,OS_INT);
+              if size in [OS_S64,OS_64] then
+                begin
+                  a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg0);
+                  a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg1);
+                  list.Concat(taicpu.op_reg_reg_reg(A_MUL_D,dst,src1,src2));
+                  list.Concat(taicpu.op_reg_reg_reg(A_MULH_D,tmpreg0,tmpreg0,tmpreg1));
+                  list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg1,dst,63));
+                  ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
+                  ai.condition:=C_EQ;
+                end
+              else
+                begin
+                  list.Concat(taicpu.op_reg_reg_reg(A_MULW_D_W,dst,src1,src2));
+                  case size of
+                    OS_S32,OS_32:
+                      list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,31));
+                    OS_S16,OS_16:
+                      list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,15));
+                    OS_S8,OS_8:
+                      list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,7));
+                  else
+                    internalerror(2022082306);
+                  end;
+                  list.concat(taicpu.op_reg_reg_const(A_ADDI_D,tmpreg0,tmpreg0,1));
+                  list.Concat(taicpu.op_reg_reg_const(A_SLTI,tmpreg1,tmpreg0,2));
+                  ai:=taicpu.op_reg_ref(A_BXX,tmpreg1,href);
+                  ai.condition:=C_NEZ;
+                end;
+              ai.is_jmp:=true;
+              list.concat(ai);
+              a_call_name(list,'FPC_OVERFLOW',false);
+              a_label(list,l);
+            end;
+          OP_MUL:
+            begin
+              { No overflow if upper result is 0 }
+              current_asmdata.getjumplabel(l);
+              reference_reset_symbol(href,l,0,0,[]);
+              href.refaddr:=addr_pcrel;
+              tmpreg0:=getintregister(list,OS_INT);
+              if size in [OS_S64,OS_64] then
+                begin
+                  tmpreg1:=getintregister(list,OS_INT);
+                  a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg0);
+                  a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg1);
+                  list.Concat(taicpu.op_reg_reg_reg(A_MUL_D,dst,src1,src2));
+                  list.Concat(taicpu.op_reg_reg_reg(A_MULH_DU,tmpreg0,tmpreg0,tmpreg1));
+                  ai:=taicpu.op_reg_ref(A_BXX,tmpreg0,href);
+                  ai.condition:=C_EQZ;
+                end
+              else
+                begin
+                  list.Concat(taicpu.op_reg_reg_reg(A_MULW_D_WU,dst,src1,src2));
+                  case size of
+                    OS_S32,OS_32:
+                      list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,31));
+                    OS_S16,OS_16:
+                      list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,15));
+                    OS_S8,OS_8:
+                      list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,7));
+                  else
+                    internalerror(2022082307);
+                  end;
+                  ai:=taicpu.op_reg_ref(A_BXX,tmpreg0,href);
+                  ai.condition:=C_EQZ;
+                end;
+              ai.is_jmp:=true;
+              list.concat(ai);
+              a_call_name(list,'FPC_OVERFLOW',false);
+              a_label(list,l);
+            end;
+          OP_IDIV:
+            begin
+              { Only overflow if -2^(N-1)/(-1)  }
+              current_asmdata.getjumplabel(l);
+              reference_reset_symbol(href,l,0,0,[]);
+              href.refaddr:=addr_pcrel;
+              tmpreg2:=getintregister(list,OS_INT);
+              tmpreg3:=getintregister(list,OS_INT);
+              a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
+              a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
+              if size in [OS_S64,OS_64] then
+                list.Concat(taicpu.op_reg_reg_reg(A_DIV_D,dst,src1,src2))
+              else
+                list.Concat(taicpu.op_reg_reg_reg(A_DIV_W,dst,src1,src2));
+              if size in [OS_S64,OS_64,OS_S32,OS_32] then
+                begin
+                  ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg3,href);
+                  ai.condition:=C_NE;
+                  ai.is_jmp:=true;
+                  list.concat(ai);
+                  ai:=taicpu.op_reg_ref(A_BXX,tmpreg2,href);
+                  ai.condition:=C_GEZ;
+                  ai.is_jmp:=true;
+                  list.concat(ai);
+                end
+              else
+                begin
+                  ai:=taicpu.op_reg_ref(A_BXX,tmpreg2,href);
+                  ai.condition:=C_GEZ;
+                  ai.is_jmp:=true;
+                  list.concat(ai);
+                  tmpreg0:=getintregister(list,OS_INT);
+                  a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
+                  ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg3,href);
+                  ai.condition:=C_NE;
+                  ai.is_jmp:=true;
+                  list.concat(ai);
+                end;
+
+              a_call_name(list,'FPC_OVERFLOW',false);
+              a_label(list,l);
+            end;
+        else
+          internalerror(2022082301);
+        end
+      else
+        a_op_reg_reg_reg(list,op,size,src1,src2,dst);
+    end;
+
+    function tcgloongarch64.fixref(list: TAsmList; var ref: treference; mode : tfixref): boolean;
+      var
+        tmpreg: TRegister;
+        href: treference;
+      begin
+        if ref.refaddr=addr_reg_12i then
+          begin
+            result:=mode=fr_normal;
+            exit;
+          end
+        else if ref.refaddr=addr_reg_reg then
+          begin
+            result:=mode=fr_reg;
+            exit;
+          end
+        else if ref.refaddr=addr_reg_reg then
+          begin
+            result:=mode=fr_big;
+            exit;
+          end;
+
+        { Reference with symbol, load symbol address first. }
+        if assigned(ref.symbol) then
+          begin
+            tmpreg:=getintregister(list,OS_INT);
+            if ((cs_create_pic in current_settings.moduleswitches) and
+                (ref.symbol.bind in [AB_LOCAL,AB_TEMP])) or
+               ((not(cs_create_pic in current_settings.moduleswitches)) and
+                (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL,AB_TEMP])) then
+              begin
+                { Load symbol address as local. }
+                reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,ref.volatility);
+                ref.symbol:=nil;
+                ref.offset:=0;
+                href.refaddr:=addr_pc_hi20;
+                list.concat(taicpu.op_reg_ref(A_PCALAU12I,tmpreg,href));
+                href.refaddr:=addr_pc_lo12;
+                list.concat(taicpu.op_reg_reg_ref(A_ADDI_D,tmpreg,tmpreg,href));
+              end
+            else
+              begin
+                { Load symbol address as global. }
+                reference_reset_symbol(href,ref.symbol,0,0,[]);
+                ref.symbol:=nil;
+                href.refaddr:=addr_got_pc_hi20;
+                list.concat(taicpu.op_reg_ref(A_PCALAU12I,tmpreg,href));
+                href.refaddr:=addr_got_pc_lo12;
+                list.concat(taicpu.op_reg_reg_ref(A_LD_D,tmpreg,tmpreg,href));
+              end;
+            { Make address format become basereg (+indexreg). }
+            if (ref.index<>NR_NO) and (ref.base<>NR_NO) then
+              begin
+                a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
+                ref.base:=tmpreg;
+              end
+            else if (ref.base=NR_NO) then
+              ref.base:=tmpreg
+            else { ref.index=NR_NO }
+              ref.index:=tmpreg;
+          end
+        { Refernce only offset, make offset become a reg. }
+        else if (ref.index=NR_NO) and (ref.base=NR_NO) then
+          begin
+            tmpreg:=getintregister(list,OS_INT);
+            a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
+            reference_reset_base(ref,tmpreg,0,ctempposinvalid,ref.alignment,ref.volatility);
+            ref.index:=NR_R0;
+          end;
+
+        if (ref.index<>NR_NO) and (ref.base=NR_NO) then
+          begin
+            ref.base:=ref.index;
+            ref.index:=NR_R0;
+          end;
+        if (ref.index=NR_NO) then
+          ref.index:=NR_R0;
+
+        { The normal type is widely applicable. When we find it is better to
+          use the normal type, we prevent other types. Or add strong types and
+          adjust it in the future. }
+        if is_simm12(ref.offset) then
+          begin
+            if ref.index<>NR_R0 then
+              begin
+                tmpreg:=getintregister(list,OS_INT);
+                a_op_reg_reg_reg(list,OP_ADD,OS_INT,ref.base,ref.index,tmpreg);
+                ref.base:=tmpreg;
+              end;
+            ref.index:=NR_NO;
+            ref.refaddr:=addr_reg_12i;
+            result:=mode=fr_normal;
+            exit;
+          end;
+
+        if (mode=fr_big) and (is_simm16_and_quadruple(ref.offset)) then
+          begin
+            if ref.index<>NR_NO then
+              begin
+                tmpreg:=getintregister(list,OS_INT);
+                a_op_reg_reg_reg(list,OP_ADD,OS_INT,ref.base,ref.index,tmpreg);
+                ref.base:=tmpreg;
+              end;
+            ref.index:=NR_NO;
+            ref.refaddr:=addr_reg_14i;
+            result:=true;
+            exit;
+          end;
+
+        if mode=fr_reg then
+          begin
+            if ref.offset<>0 then
+              begin
+                tmpreg:=getintregister(list,OS_INT);
+                a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
+                if ref.index<>NR_R0 then
+                  begin
+                    a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
+                    ref.index:=tmpreg;
+                  end
+                else
+                  ref.index:=tmpreg;
+              end;
+            ref.refaddr:=addr_reg_reg;
+            ref.offset:=0;
+            result:=true;
+            exit;
+          end;
+
+        tmpreg:=getintregister(list,OS_INT);
+        a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
+        if ref.index<>NR_R0 then
+          a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
+        a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
+        ref.base:=tmpreg;
+        ref.index:=NR_NO;
+        ref.offset:=0;
+        result:=mode=fr_normal;
+      end;
+
+
+    procedure tcgloongarch64.maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
+      const
+        overflowops = [OP_MUL,OP_IMUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
+      begin
+        if (op in overflowops) and
+           (size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
+          a_load_reg_reg(list,OS_INT,size,dst,dst)
+        else if (op in [OP_ROL,OP_ROR]) and (size in [OS_8,OS_S8,OS_16,OS_S16]) then
+          a_load_reg_reg(list,OS_INT,size,dst,dst);
+      end;
+
+
+    procedure create_codegen;
+      begin
+        cg := tcgloongarch64.create;
+        cg128:=tcg128.create;
+      end;
+
+end.

+ 448 - 0
compiler/loongarch64/cpubase.pas

@@ -0,0 +1,448 @@
+{
+    Copyright (C) 2022 Loongson Technology Corporation Limited.
+
+    Contains the base types for the LoongArch64.
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cpubase;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  strings,globtype,
+  cutils,cclasses,aasmbase,cpuinfo,cgbase;
+
+{*****************************************************************************
+                                Assembler Opcodes
+*****************************************************************************}
+
+    type
+      TAsmOp= {$i loongarch64op.inc}
+
+      {# This should define the array of instructions as string }
+      op2strtable=array[tasmop] of string[16];
+
+    Const
+      {# First value of opcode enumeration }
+      firstop = low(tasmop);
+      {# Last value of opcode enumeration  }
+      lastop  = high(tasmop);
+
+
+{*****************************************************************************
+                                  Registers
+*****************************************************************************}
+
+    type
+      { Number of registers used for indexing in tables }
+      tregisterindex=0..{$i rloongarch64nor.inc}-1;
+
+    const
+      maxvarregs = 32-6; { 32 int registers - r0 - stackpointer - r2 - 3 scratch registers }
+      maxfpuvarregs = 28; { 32 fpuregisters - some scratch registers (minimally 2) }
+
+      { Available Superregisters }
+      {$i rloongarch64sup.inc}
+
+      { No Subregisters }
+      R_SUBWHOLE=R_SUBNONE;
+
+      { Available Registers }
+      {$i rloongarch64con.inc}
+
+      { Integer Super registers first and last }
+      first_int_supreg = RS_R0;
+      first_int_imreg = $20;
+
+      { Float Super register first and last }
+      first_fpu_supreg    = RS_F0;
+      first_fpu_imreg     = $20;
+
+      { MM Super register first and last }
+      first_mm_supreg    = 0;
+      first_mm_imreg     = 1;
+
+{ TODO: Calculate bsstart}
+      regnumber_count_bsstart = 64;
+
+      regnumber_table : array[tregisterindex] of tregister = (
+        {$i rloongarch64num.inc}
+      );
+
+      regstabs_table : array[tregisterindex] of shortint = (
+        {$i rloongarch64sta.inc}
+      );
+
+      regdwarf_table : array[tregisterindex] of shortint = (
+        {$i rloongarch64dwa.inc}
+      );
+
+{*****************************************************************************
+                                Conditions
+*****************************************************************************}
+
+    type
+      TAsmCond = (C_NONE,C_EQ,C_GT,C_LT,C_GE,C_LE,C_NE,C_LEU,C_LTU,C_GEU,C_GTU,
+                  C_EQZ,C_GTZ,C_LTZ,C_GEZ,C_LEZ,C_NEZ);
+      TAsmConds = set of TAsmCond;
+    const
+      cond2str: Array[TAsmCond] of string[4] = ('',
+                'eq','gt','lt','ge','le','ne','leu','ltu','geu','gtu',
+                'eqz','gtz','ltz','gez','lez','nez');
+
+
+{*****************************************************************************
+                                   Flags
+*****************************************************************************}
+
+    type
+      TResFlagsEnum = (F_EQ,F_NE,F_LT,F_LTU,F_GE,F_GEU);
+
+{*****************************************************************************
+                                Reference
+*****************************************************************************}
+
+{*****************************************************************************
+                                Operands
+*****************************************************************************}
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+    const
+      max_operands = 5;
+
+{*****************************************************************************
+                          Default generic sizes
+*****************************************************************************}
+
+  {# Defines the default address size for a processor, }
+  OS_ADDR = OS_64;
+  {# the natural int size for a processor,
+     has to match osuinttype/ossinttype as initialized in psystem }
+  OS_INT = OS_64;
+  OS_SINT = OS_S64;
+  {# the maximum float size for a processor,           }
+  OS_FLOAT = OS_F64;
+  {# the size of a vector register for a processor     }
+  OS_VECTOR = OS_M128;
+
+{*****************************************************************************
+                               GDB Information
+*****************************************************************************}
+
+      stab_regindex : array[tregisterindex] of shortint = (
+        {$i rloongarch64sta.inc}
+      );
+
+{*****************************************************************************
+                          Generic Register names
+*****************************************************************************}
+
+      {# Stack pointer register }
+      NR_STACK_POINTER_REG = NR_R3;
+      RS_STACK_POINTER_REG = RS_R3;
+      {# Frame pointer register }
+      NR_FRAME_POINTER_REG = NR_R22;
+      RS_FRAME_POINTER_REG = RS_R22;
+
+      { Return address of a function }
+      NR_RETURN_ADDRESS_REG = NR_R1;
+      RS_RETURN_ADDRESS_REG = RS_R1;
+      { Results are returned in this register (32-bit values) }
+      NR_FUNCTION_RETURN_REG = NR_R4;
+      RS_FUNCTION_RETURN_REG = RS_R4;
+      { Low part of 64bit return value }
+      NR_FUNCTION_RETURN64_LOW_REG = NR_R4;
+      RS_FUNCTION_RETURN64_LOW_REG = RS_R4;
+      { High part of 64bit return value }
+      NR_FUNCTION_RETURN64_HIGH_REG = NR_R4;
+      RS_FUNCTION_RETURN64_HIGH_REG = RS_R4;
+      { The value returned from a function is available in this register }
+      NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
+      RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
+      { The lowh part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
+      RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
+      { The high part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
+      RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
+
+      NR_FPU_RESULT_REG = NR_F0;
+      NR_MM_RESULT_REG = NR_NO;
+
+      NR_DEFAULTFLAGS = NR_NO;
+      RS_DEFAULTFLAGS = RS_NO;
+
+      RS_FIRST_INT_PARAM_SUPREG = RS_R4;
+      RS_FIRST_FLOAT_PARAM_SUPREG = RS_F0;
+      RS_FIRST_MM_PARAM_SUPREG = RS_NO;
+
+
+{*****************************************************************************
+                       GCC /ABI linking information
+*****************************************************************************}
+
+      {# Registers which must be saved when calling a routine declared as
+         cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
+         saved should be the ones as defined in the target ABI and / or GCC.
+
+         This value can be deduced from CALLED_USED_REGISTERS array in the
+         GCC source.
+      }
+      saved_standard_registers : array[0..10] of tsuperregister = (
+        RS_R3, RS_R22,
+        RS_R23, RS_R24, RS_R25, RS_R26, RS_R27, RS_R28, RS_R29, RS_R30, RS_R31
+      );
+
+      { this is only for the generic code which is not used for this architecture }
+      saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID);
+      saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID);
+
+      {# Required parameter alignment when calling a routine declared as
+         stdcall and cdecl. The alignment value should be the one defined
+         by GCC or the target ABI.
+
+         The value of this constant is equal to the constant
+         PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
+      }
+      std_param_align = 8;
+
+{*****************************************************************************
+                            CPU Dependent Constants
+*****************************************************************************}
+
+      maxfpuregs = 8;
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    function is_simm12(value: tcgint): boolean;
+    function is_uimm12(value: tcgint): boolean;
+    function is_simm16_and_quadruple(value: tcgint): boolean;
+
+    function is_calljmp(o:tasmop):boolean;
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+    { Returns the tcgsize corresponding with the size of reg.}
+    function reg_cgsize(const reg: tregister) : tcgsize;
+
+    function findreg_by_number(r:Tregister):tregisterindex;
+    function std_regnum_search(const s:string):Tregister;
+    function std_regname(r:Tregister):string;
+
+    function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+    function dwarf_reg(r:tregister):shortint;
+    function dwarf_reg_no_error(r:tregister):shortint;
+    function eh_return_data_regno(nr: longint): longint;
+
+    function conditions_equal(const c1,c2: TAsmCond): boolean;
+
+    { Checks if Subset is a subset of c (e.g. "less than" is a subset of "less than or equal" }
+    function condition_in(const Subset, c: TAsmCond): Boolean;
+
+    function is_extra_reg(const s : string) : tregister;
+
+implementation
+
+    uses
+      rgbase,verbose;
+
+    const
+      std_regname_table : TRegNameTable = (
+        {$i rloongarch64std.inc}
+      );
+
+      abi_regname_table : TRegNameTable = (
+        {$i rloongarch64abi.inc}
+      );
+
+      regnumber_index : array[tregisterindex] of tregisterindex = (
+        {$i rloongarch64rni.inc}
+      );
+
+      std_regname_index : array[tregisterindex] of tregisterindex = (
+        {$i rloongarch64sri.inc}
+      );
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    function is_simm12(value: tcgint): boolean;
+      begin
+        result:=(value >= -2048) and (value <= 2047);
+      end;
+
+    function is_uimm12(value: tcgint): boolean;
+      begin
+        result:=(value >= 0) and (value <= 4095);
+      end;
+
+    function is_simm16_and_quadruple(value: tcgint): boolean;
+      begin
+        result:=(value >= -32768) and (value <= 32767) and ((value mod 4) = 0);
+      end;
+
+    function is_calljmp(o:tasmop):boolean;
+      begin
+        case o of
+          { Most of time is call. }
+          A_JIRL,A_BL: result:=true;
+          { Most of time is jump. }
+          A_JR,A_B,A_BEQ,A_BNE,A_BLT,A_BLTU,A_BGE,
+          A_BGEU,A_BEQZ,A_BNEZ,A_BCEQZ,A_BCNEZ,
+          A_BLTZ,A_BGTZ,A_BGEZ,A_BLEZ,A_BGT,A_BLE,
+          A_BGTU,A_BLEU,A_BXX: result:=true;
+        else
+          result:=false;
+        end;
+      end;
+
+    function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+      const
+        inv_condflags:array[TAsmCond] of TAsmCond=(C_NONE,
+          C_NE,C_LE,C_GE,C_LT,C_GT,C_EQ,C_GTU,C_GEU,C_LTU,C_LEU,
+          C_NEZ,C_LEZ,C_GEZ,C_LTZ,C_GTZ,C_EQZ);
+      begin
+        result := inv_condflags[c];
+      end;
+
+
+    function reg_cgsize(const reg: tregister): tcgsize;
+      begin
+        case getregtype(reg) of
+          R_INTREGISTER :
+            result:=OS_INT;
+          R_MMREGISTER:
+            result:=OS_M128;
+          R_FPUREGISTER:
+            result:=OS_F64;
+          else
+            internalerror(2022111902);
+        end;
+      end;
+
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+      begin
+        cgsize2subreg:=R_SUBWHOLE;
+      end;
+
+
+    function findreg_by_number(r:Tregister):tregisterindex;
+      begin
+        result:=rgBase.findreg_by_number_table(r,regnumber_index);
+      end;
+
+
+    function std_regnum_search(const s:string):Tregister;
+      begin
+        result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
+      end;
+
+
+    function std_regname(r:Tregister):string;
+      var
+        p : tregisterindex;
+      begin
+        p:=findreg_by_number_table(r,regnumber_index);
+        if p<>0 then
+          result:=std_regname_table[p]
+        else
+          result:=generic_regname(r);
+      end;
+
+
+    function dwarf_reg(r:tregister):shortint;
+      begin
+        result:=regdwarf_table[findreg_by_number(r)];
+        if result=-1 then
+          internalerror(2022111903);
+      end;
+
+    function dwarf_reg_no_error(r:tregister):shortint;
+      begin
+        result:=regdwarf_table[findreg_by_number(r)];
+      end;
+
+    function eh_return_data_regno(nr: longint): longint;
+      begin
+        if (nr>=0) and (nr<4) then
+          result:=nr+10
+        else
+          result:=-1;
+      end;
+
+    function conditions_equal(const c1, c2: TAsmCond): boolean;
+      begin
+        result:=c1=c2;
+      end;
+
+
+    { Checks if Subset is a subset of c (e.g. "less than" is a subset of "less than or equal" }
+    function condition_in(const Subset, c: TAsmCond): Boolean;
+      begin
+        Result := (c = C_None) or conditions_equal(Subset, c);
+
+        if not Result then
+          case Subset of
+            C_EQ:
+              Result := (c in [C_GE,C_GEU,C_LE,C_LEU]);
+            C_EQZ:
+              Result := (c in [C_GEZ,C_LEZ]);
+            else
+              Result := False;
+          end;
+      end;
+
+
+    function is_extra_reg(const s: string): tregister;
+      const abiname2reg : array[tregisterindex] of tregister = (NR_NO,
+            NR_R0,NR_R1,NR_R2,NR_R3,NR_R4,NR_R5,NR_R6,NR_R7,
+            NR_R8,NR_R9,NR_R10,NR_R11,NR_R12,NR_R13,NR_R14,NR_R15,
+            NR_R16,NR_R17,NR_R18,NR_R19,NR_R20,NR_R21,NR_R22,NR_R23,
+            NR_R24,NR_R25,NR_R26,NR_R27,NR_R28,NR_R29,NR_R30,NR_R31,
+            NR_F0,NR_F1,NR_F2,NR_F3,NR_F4,NR_F5,NR_F6,NR_F7,
+            NR_F8,NR_F9,NR_F10,NR_F11,NR_F12,NR_F13,NR_F14,NR_F15,
+            NR_F16,NR_F17,NR_F18,NR_F19,NR_F20,NR_F21,NR_F22,NR_F23,
+            NR_F24,NR_F25,NR_F26,NR_F27,NR_F28,NR_F29,NR_F30,NR_F31,
+            NR_FCC0,NR_FCC1,NR_FCC2,NR_FCC3,NR_FCC4,NR_FCC5,NR_FCC6,NR_FCC7);
+      var
+        i : longint;
+      begin
+        result:=NR_NO;
+        { LoongArch registers start by '$' and abiname length <= 5 }
+        if not(length(s) in [2..5]) and (s[1]<>'$') then
+          exit;
+        for i:=low(abi_regname_table) to high(abi_regname_table) do
+          begin
+            if s=abi_regname_table[i] then
+              begin
+                result:=abiname2reg[i];
+                exit;
+              end;
+          end;
+      end;
+
+begin
+end.

+ 122 - 0
compiler/loongarch64/cpuinfo.pas

@@ -0,0 +1,122 @@
+{
+    Copyright (c) 1998-2002 by the Free Pascal development team
+
+    Basic Processor information for the LoongArch64
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program 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.
+
+ **********************************************************************}
+
+unit CPUInfo;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype;
+
+type
+  bestreal = double;
+  bestrealrec = TDoubleRec;
+  ts32real = single;
+  ts64real = double;
+  ts80real = extended;
+  ts128real = extended;
+  ts64comp = comp;
+
+  pbestreal = ^bestreal;
+
+  { possible supported processors for this target }
+  tcputype = (cpu_none,
+    cpu_3a
+  );
+
+  tfputype =
+    (fpu_none,
+    fpu_fd
+    );
+
+   tcontrollertype =
+     (ct_none
+     );
+
+   tcontrollerdatatype = record
+      controllertypestr, controllerunitstr: string[20];
+      cputype: tcputype; fputype: tfputype;
+      flashbase, flashsize, srambase, sramsize, eeprombase, eepromsize, bootbase, bootsize: dword;
+   end;
+
+
+Const
+  { Is there support for dealing with multiple microcontrollers available }
+  { for this platform? }
+  ControllerSupport = false;
+
+  { We know that there are fields after sramsize
+    but we don't care about this warning }
+  {$PUSH}
+   {$WARN 3177 OFF}
+  embedded_controllers : array [tcontrollertype] of tcontrollerdatatype =
+  (
+      (controllertypestr:''; controllerunitstr:''; cputype:cpu_none; fputype:fpu_none; flashbase:0; flashsize:0; srambase:0; sramsize:0));
+  {$POP}
+
+  { calling conventions supported by the code generator }
+  supported_calling_conventions: tproccalloptions = [
+    pocall_internproc,
+    pocall_safecall,
+    pocall_stdcall,
+    { the difference to stdcall is only the name mangling }
+    pocall_cdecl,
+    { the difference to stdcall is only the name mangling }
+    pocall_cppdecl,
+    { the difference with stdcall is that all const record
+      parameters are passed by reference }
+    pocall_mwpascal
+    ];
+
+  cputypestr: array[tcputype] of string[11] = ('',
+    'LOONGARCH64'
+    );
+
+  fputypestr: array[tfputype] of string[8] = ('',
+    'FD'
+    );
+
+   { Supported optimizations, only used for information }
+   supported_optimizerswitches = genericlevel1optimizerswitches+
+                                 genericlevel2optimizerswitches+
+                                 genericlevel3optimizerswitches-
+                                 { no need to write info about those }
+                                 [cs_opt_level1,cs_opt_level2,cs_opt_level3]+
+                                 [{$ifndef llvm}cs_opt_regvar,{$endif}cs_opt_loopunroll,cs_opt_nodecse,
+                                  cs_opt_tailrecursion,cs_opt_reorder_fields,cs_opt_fastmath,
+                                  cs_opt_stackframe];
+
+   level1optimizerswitches = genericlevel1optimizerswitches;
+   level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
+     [{$ifndef llvm}cs_opt_regvar,{$endif}cs_opt_stackframe,cs_opt_nodecse,cs_opt_tailrecursion];
+   level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches;
+   level4optimizerswitches = genericlevel4optimizerswitches + level3optimizerswitches + [cs_opt_stackframe];
+
+ { TODO Unaligned accesses, hard float. }
+ type
+   tcpuflags =
+      (CPULOONGARCH_HAS_ATOMIC
+      );
+
+ const
+   cpu_capabilities : array[tcputype] of set of tcpuflags =
+     ( { cpu_none       } [],
+       { cpu_loongarch3a    } [CPULOONGARCH_HAS_ATOMIC]
+     );
+
+implementation
+
+end.

+ 52 - 0
compiler/loongarch64/cpunode.pas

@@ -0,0 +1,52 @@
+{
+    Copyright (c) 2000-2002 by Florian Klaempfl
+
+    Includes the LoongArch64 code generator
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cpunode;
+
+{$I fpcdefs.inc}
+
+interface
+
+implementation
+
+uses
+  { generic nodes }
+  ncgbas, ncgld, ncgflw, ncgcnv, ncgmem, ncgcon, ncgcal, ncgset, ncginl, ncgopt,
+  ncgobjc,
+  { symtable }
+  symcpu,
+  aasmdef,
+  { to be able to only parts of the generic code,
+    the processor specific nodes must be included
+    after the generic one (FK)
+  }
+{$ifndef llvm}
+  ncpuadd,
+  ncpucnv,
+  ncpuinl,
+  ncpumat,
+  ncpuset
+{$else not llvm}
+  llvmnode
+{$endif not llvm}
+  ;
+
+end.

+ 617 - 0
compiler/loongarch64/cpupara.pas

@@ -0,0 +1,617 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    LoongArch64 specific calling conventions
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ****************************************************************************
+}
+unit cpupara;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      globtype,
+      aasmtai,aasmdata,
+      cpubase,
+      symconst, symtype, symdef, symsym,
+      paramgr, parabase, cgbase, cgutils;
+
+    type
+      tcpuparamanager = class(tparamanager)
+        function get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset; override;
+        function get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset; override;
+        function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
+        function ret_in_param(def: tdef; pd: tabstractprocdef): boolean; override;
+
+        procedure getcgtempparaloc(list: TAsmList; pd : tabstractprocdef; nr: longint; var cgpara: tcgpara); override;
+        function create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint; override;
+        function create_varargs_paraloc_info(p: tabstractprocdef; side: tcallercallee; varargspara: tvarargsparalist): longint; override;
+        function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
+
+      private
+        procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
+        function create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; isVararg : boolean): longint;
+        function parseparaloc(p: tparavarsym; const s: string): boolean; override;
+        procedure create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: aword; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
+      end;
+
+implementation
+
+    uses
+      verbose, systems,
+      globals, cpuinfo,
+      defutil,symtable,symcpu,
+      procinfo, cpupi;
+
+    function tcpuparamanager.get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset;
+      begin
+        result:=[RS_R0..RS_R31]-[RS_R3,RS_R22..RS_R31];
+      end;
+
+    function tcpuparamanager.get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset;
+      begin
+        result:=[RS_F0..RS_F31]-[RS_F24..RS_F31];
+      end;
+
+    procedure tcpuparamanager.getcgtempparaloc(list: TAsmList; pd : tabstractprocdef; nr: longint; var cgpara: tcgpara);
+      var
+        paraloc: pcgparalocation;
+        psym: tparavarsym;
+        pdef: tdef;
+      begin
+        psym:=tparavarsym(pd.paras[nr-1]);
+        pdef:=psym.vardef;
+        if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
+          pdef:=cpointerdef.getreusable_no_free(pdef);
+        cgpara.reset;
+        cgpara.size := def_cgsize(pdef);
+        cgpara.intsize := tcgsize2size[cgpara.size];
+        cgpara.alignment := get_para_align(pd.proccalloption);
+        cgpara.def:=pdef;
+        paraloc := cgpara.add_location;
+        with paraloc^ do
+          begin
+            size := def_cgsize(pdef);
+            def := pdef;
+            if (nr <= 8) then
+              begin
+                if (nr = 0) then
+                  internalerror(2022111916);
+                loc := LOC_REGISTER;
+                register := newreg(R_INTREGISTER, RS_R4 + nr-1, R_SUBWHOLE);
+              end
+            else
+              begin
+                loc := LOC_REFERENCE;
+                paraloc^.reference.index := NR_STACK_POINTER_REG;
+                reference.offset := sizeof(aint) * (nr - 9);
+              end;
+          end;
+      end;
+
+    function getparaloc(p: tdef): tcgloc;
+      var
+        hfabasedef: tdef;
+      begin
+        { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
+          if push_addr_param for the def is true
+        }
+        case p.typ of
+          orddef:
+            result := LOC_REGISTER;
+          floatdef:
+            result := LOC_FPUREGISTER;
+          enumdef:
+            result := LOC_REGISTER;
+          pointerdef:
+            result := LOC_REGISTER;
+          formaldef:
+            result := LOC_REGISTER;
+          classrefdef:
+            result := LOC_REGISTER;
+          procvardef:
+            result := LOC_REGISTER;
+          recorddef:
+            result := LOC_REGISTER;
+            { result := LOC_FPUREGISTER; }
+          objectdef:
+            if is_object(p) then
+              result := LOC_REFERENCE
+            else
+              result := LOC_REGISTER;
+          stringdef:
+            if is_shortstring(p) or is_longstring(p) then
+              result := LOC_REFERENCE
+            else
+              result := LOC_REGISTER;
+          filedef:
+            result := LOC_REGISTER;
+          arraydef:
+            if is_dynamic_array(p) then
+              getparaloc:=LOC_REGISTER
+            else
+              result := LOC_REFERENCE;
+          setdef:
+            if is_smallset(p) then
+              result := LOC_REGISTER
+            else
+              result := LOC_REFERENCE;
+          variantdef:
+            result := LOC_REFERENCE;
+          { avoid problems with errornous definitions }
+          errordef:
+            result := LOC_REGISTER;
+        else
+          internalerror(2022111917);
+        end;
+      end;
+
+    function tcpuparamanager.push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean;
+      begin
+        result := false;
+        { var,out,constref always require address }
+        if varspez in [vs_var, vs_out, vs_constref] then
+        begin
+          result := true;
+          exit;
+        end;
+        case def.typ of
+          variantdef,
+          formaldef:
+            result := true;
+          procvardef,
+          recorddef:
+            result := (def.size > 16);
+          arraydef:
+            result := (tarraydef(def).highrange >= tarraydef(def).lowrange) or
+              is_open_array(def) or
+              is_array_of_const(def) or
+              is_array_constructor(def);
+          objectdef:
+            result := is_object(def);
+          setdef:
+            result := not is_smallset(def);
+          stringdef:
+            result := tstringdef(def).stringtype in [st_shortstring, st_longstring];
+          else
+            ;
+        end;
+      end;
+
+    function tcpuparamanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean;
+      var
+        tmpdef: tdef;
+      begin
+        if handle_common_ret_in_param(def,pd,result) then
+          exit;
+
+        { general rule: passed in registers -> returned in registers }
+        result:=push_addr_param(vs_value,def,pd.proccalloption);
+      end;
+
+    procedure tcpuparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
+      begin
+        cur_stack_offset := 0;
+        curintreg := RS_R4;
+        curfloatreg := RS_F0;
+        curmmreg := RS_NO;
+      end;
+
+    function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
+      var
+        paraloc: pcgparalocation;
+        retcgsize: tcgsize;
+        nextfloatreg, nextintreg, nextmmreg: tsuperregister;
+        stack_offset: aword;
+      begin
+        if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
+          exit;
+
+         { in this case, it must be returned in registers as if it were passed
+           as the first parameter }
+         init_values(nextintreg,nextfloatreg,nextmmreg,stack_offset);
+         create_paraloc_for_def(result,vs_value,result.def,nextfloatreg,nextintreg,stack_offset,false,false,side,p);
+         { sanity check (LOC_VOID for empty records) }
+         if not assigned(result.location) or
+            not(result.location^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_VOID]) then
+           internalerror(2022111918);
+      end;
+
+    function tcpuparamanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint;
+      var
+        cur_stack_offset: aword;
+        curintreg, curfloatreg, curmmreg : tsuperregister;
+      begin
+        init_values(curintreg, curfloatreg, curmmreg, cur_stack_offset);
+
+        result := create_paraloc_info_intern(p, side, p.paras, curintreg, curfloatreg, curmmreg, cur_stack_offset, false);
+
+        create_funcretloc_info(p, side);
+      end;
+
+    function tcpuparamanager.create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; isVararg : boolean): longint;
+      var
+        nextintreg, nextfloatreg, nextmmreg : tsuperregister;
+        i: integer;
+        hp: tparavarsym;
+        paraloc: pcgparalocation;
+        delphi_nestedfp: boolean;
+
+      begin
+{$IFDEF extdebug}
+        if po_explicitparaloc in p.procoptions then
+          internalerror(2022111919);
+{$ENDIF extdebug}
+
+        result := 0;
+        nextintreg := curintreg;
+        nextfloatreg := curfloatreg;
+        nextmmreg := curmmreg;
+
+        for i := 0 to paras.count - 1 do begin
+          hp := tparavarsym(paras[i]);
+
+          if (vo_has_explicit_paraloc in hp.varoptions) then begin
+            internalerror(2022111920);
+          end;
+
+          { currently only support C-style array of const }
+          if (p.proccalloption in [pocall_cdecl, pocall_cppdecl]) and
+            is_array_of_const(hp.vardef) then begin
+            paraloc := hp.paraloc[side].add_location;
+            { hack: the paraloc must be valid, but is not actually used }
+            paraloc^.loc := LOC_REGISTER;
+            paraloc^.register := NR_R0;
+            paraloc^.size := OS_ADDR;
+            paraloc^.def := voidpointertype;
+            break;
+          end;
+          delphi_nestedfp:=(vo_is_parentfp in hp.varoptions) and (po_delphi_nested_cc in p.procoptions);
+          create_paraloc_for_def(hp.paraloc[side], hp.varspez, hp.vardef,
+            nextfloatreg, nextintreg, cur_stack_offset, isVararg, delphi_nestedfp, side, p);
+        end;
+
+        curintreg := nextintreg;
+        curfloatreg := nextfloatreg;
+        curmmreg := nextmmreg;
+        result := cur_stack_offset;
+      end;
+
+    procedure tcpuparamanager.create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: aword; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
+      var
+        paracgsize: tcgsize;
+        loc: tcgloc;
+        paraloc: pcgparalocation;
+        { def to use for all paralocs if <> nil }
+        alllocdef,
+        { def to use for the current paraloc }
+        locdef,
+        tmpdef,tmpdef1,tmpdef2: tdef;
+        tmpdep1_size,tmpdep2_size,record_offset,para_same_num: integer;
+        paralen: aint;
+        firstparaloc,
+        paraaligned: boolean;
+      begin
+        alllocdef:=nil;
+        locdef:=nil;
+        para.reset;
+        para_same_num := 0;
+        { have we ensured that the next parameter location will be aligned to the
+          next 8 byte boundary? }
+        paraaligned:=false;
+        if push_addr_param(varspez, paradef, p.proccalloption) then
+          begin
+            paradef := cpointerdef.getreusable_no_free(paradef);
+            loc := LOC_REGISTER;
+            paracgsize := OS_ADDR;
+            paralen := tcgsize2size[OS_ADDR];
+          end
+        else
+          begin
+            if not is_special_array(paradef) then
+              paralen := paradef.size
+            else
+              paralen := tcgsize2size[def_cgsize(paradef)];
+
+            if (paradef.typ=recorddef) and
+               tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(tmpdef) and
+               (tmpdef.typ=floatdef) then
+              begin
+                paradef:=tmpdef;
+                loc:=getparaloc(paradef);
+                paracgsize:=def_cgsize(paradef)
+              end
+            else if (((paradef.typ=arraydef) and not
+                    is_special_array(paradef)) or
+                    (paradef.typ=recorddef) and (varspez in [vs_value,vs_const]) ) then
+              begin
+                { general fallback rule: pass aggregate types in integer registers
+                  without special adjustments (incl. Darwin h) }
+                loc:=LOC_REGISTER;
+                paracgsize:=int_cgsize(paralen);
+                { Check if the element types in the record are the same}
+                if paralen <= 16 then
+                  para_same_num := tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_double_field(tmpdef1, tmpdef2, record_offset);
+                if para_same_num <> 0 then
+                  begin
+                    if (((tmpdef1.typ = floatdef) or (tmpdef2.typ = floatdef)) and (nextfloatreg > RS_F7)) then
+                      para_same_num := 0;
+                  end;
+                if ((para_same_num <> 0) and (record_offset <= 8))then
+                  begin
+                    { Floating point elements less than two will be passed through the floating point register}
+                    if tmpdef1.typ = floatdef then
+                      begin
+                        loc:=LOC_FPUREGISTER;
+                        paracgsize:=int_float_cgsize(paralen);
+                      end;
+                    if ((tmpdef1.typ<>floatdef) and (tmpdef2.typ<>floatdef) and (para_same_num=1))then
+                      para_same_num := 2;
+                  end;
+              end
+            else
+              begin
+                loc:=getparaloc(paradef);
+                paracgsize:=def_cgsize(paradef);
+                { for things like formaldef }
+                if (paracgsize=OS_NO) then
+                  begin
+                    paracgsize:=OS_ADDR;
+                    paralen:=tcgsize2size[OS_ADDR];
+                  end;
+              end
+          end;
+
+        { patch FPU values into integer registers if we are processing varargs }
+        if (isVararg) and (paradef.typ = floatdef) then
+          begin
+            loc := LOC_REGISTER;
+            if paracgsize = OS_F64 then
+              paracgsize := OS_64
+            else
+              paracgsize := OS_32;
+          end;
+
+        para.alignment := std_param_align;
+        para.size := paracgsize;
+        para.intsize := paralen;
+        para.def := paradef;
+        if (paralen = 0) then
+          if (paradef.typ = recorddef) then
+            begin
+              paraloc := para.add_location;
+              paraloc^.loc := LOC_VOID;
+            end
+          else
+            internalerror(2022111921);
+
+        if not assigned(alllocdef) then
+          locdef:=paradef
+        else
+          begin
+            locdef:=alllocdef;
+            paracgsize:=def_cgsize(locdef);
+          end;
+        firstparaloc:=true;
+
+        // Parameters passed in 2 registers are passed in a register starting with an even number.
+        if isVararg and
+           (paralen > 8) and
+           (loc = LOC_REGISTER) and
+           (nextintreg <= RS_R11) and
+           odd(nextintreg) then
+          inc(nextintreg);
+
+        { can become < 0 for e.g. 3-byte records }
+        while paralen > 0 do
+          begin
+            paraloc := para.add_location;
+            { In case of po_delphi_nested_cc, the parent frame pointer
+              is always passed on the stack. }
+            if (loc = LOC_REGISTER) and
+               (nextintreg <= RS_R11) and
+               not forceintmem then
+              begin
+                paraloc^.loc := loc;
+
+                { make sure we don't lose whether or not the type is signed }
+                if (paracgsize <> OS_NO) and
+                   (paradef.typ <> orddef) and
+                   not assigned(alllocdef) then
+                  begin
+                    paracgsize := int_cgsize(paralen);
+                    locdef:=get_paraloc_def(paradef, paralen, firstparaloc);
+                  end;
+                if para_same_num = 1 then
+                  begin
+                    paraloc^.size := int_cgsize(record_offset);
+                    paraloc^.def := locdef;
+                    para_same_num := 0;
+                    {set for next element}
+                    if tmpdef2.typ = floatdef then
+                      begin
+                        loc := LOC_FPUREGISTER;
+                        paracgsize := int_float_cgsize(paralen - record_offset);
+                      end
+                    else
+                      internalerror(2022082601);
+                  end
+                else if (paracgsize in [OS_NO, OS_128, OS_S128]) then
+                  begin
+                    if (paralen>4) then
+                      begin
+                        paraloc^.size := OS_INT;
+                        paraloc^.def := osuinttype;
+                      end
+                    else
+                      begin
+                        { for 3-byte records aligned in the lower bits of register }
+                        paraloc^.size := OS_32;
+                        paraloc^.def := u32inttype;
+                      end;
+                  end
+                else
+                  begin
+                    paraloc^.size := paracgsize;
+                    paraloc^.def := locdef;
+                  end;
+
+                paraloc^.register := newreg(R_INTREGISTER, nextintreg, R_SUBNONE);
+                inc(nextintreg);
+                dec(paralen, tcgsize2size[paraloc^.size]);
+              end
+            else if (loc = LOC_FPUREGISTER) and
+                    (nextfloatreg <= RS_F7) then
+              begin
+                paraloc^.loc := loc;
+                if para_same_num = 1 then
+                  begin
+                    paraloc^.size := int_float_cgsize(record_offset);
+                    if record_offset = 8 then
+                      paraloc^.def := s64floattype
+                    else
+                      paraloc^.def := s32floattype;
+                    para_same_num := 0;
+                    {set for next element}
+                    if tmpdef2.typ <> floatdef then
+                      begin
+                        loc := LOC_REGISTER;
+                        paracgsize:=int_cgsize(paralen - record_offset);
+                      end
+                    else
+                      internalerror(2022082602);
+                  end
+                else if((paracgsize = OS_F128) and (para_same_num = 2)) then
+                  begin
+                    paraloc^.size := OS_FLOAT;
+                    paraloc^.def := s64floattype;
+                  end
+                else if((paracgsize = OS_F64) and (para_same_num = 2)) then
+                  begin
+                    paraloc^.size := OS_F32;
+                    paraloc^.def := s32floattype;
+                  end
+                else
+                  begin
+                    paraloc^.size := paracgsize;
+                    paraloc^.def := locdef;
+                  end;
+                paraloc^.register := newreg(R_FPUREGISTER, nextfloatreg, R_SUBWHOLE);
+                inc(nextfloatreg);
+                dec(paralen, tcgsize2size[paraloc^.size]);
+              end
+            else if (loc = LOC_MMREGISTER) then
+              begin
+                { no mm registers }
+                internalerror(2022111922);
+              end
+            else
+              begin
+                { either LOC_REFERENCE, or one of the above which must be passed on the
+                  stack because of insufficient registers }
+                paraloc^.loc := LOC_REFERENCE;
+                case loc of
+                  LOC_FPUREGISTER:
+                    begin
+                      paraloc^.size:=int_float_cgsize(paralen);
+                      case paraloc^.size of
+                        OS_F32: paraloc^.def:=s32floattype;
+                        OS_F64: paraloc^.def:=s64floattype;
+                      else
+                        internalerror(2022111923);
+                      end;
+                    end;
+                  LOC_REGISTER,
+                  LOC_REFERENCE:
+                    begin
+                      paraloc^.size:=int_cgsize(paralen);
+                      paraloc^.def:=get_paraloc_def(paradef, paralen, firstparaloc);
+                    end;
+                else
+                  internalerror(2022111924);
+                end;
+                if (side = callerside) then
+                  paraloc^.reference.index := NR_STACK_POINTER_REG
+                else
+                  begin
+                    { during procedure entry, NR_OLD_STACK_POINTER_REG contains the old stack pointer }
+                    paraloc^.reference.index := NR_FRAME_POINTER_REG;
+                    { create_paraloc_info_intern might be also called when being outside of
+                      code generation so current_procinfo might be not set }
+                    if assigned(current_procinfo) then
+                      tloongarch64procinfo(current_procinfo).needs_frame_pointer := true;
+                  end;
+                paraloc^.reference.offset := stack_offset;
+
+                { align temp contents to next register size }
+                if not paraaligned then
+                  inc(stack_offset, align(paralen, 8))
+                else
+                  inc(stack_offset, paralen);
+                paralen := 0;
+              end;
+            firstparaloc:=false;
+          end;
+      end;
+
+    function tcpuparamanager.create_varargs_paraloc_info(p: tabstractprocdef; side: tcallercallee; varargspara: tvarargsparalist): longint;
+      var
+        cur_stack_offset: aword;
+        parasize, l: longint;
+        curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
+        i: integer;
+        hp: tparavarsym;
+        paraloc: pcgparalocation;
+      begin
+        init_values(curintreg, curfloatreg, curmmreg, cur_stack_offset);
+        firstfloatreg := curfloatreg;
+
+        result := create_paraloc_info_intern(p, side, p.paras, curintreg, curfloatreg, curmmreg, cur_stack_offset, false);
+        if (p.proccalloption in [pocall_cdecl, pocall_cppdecl, pocall_mwpascal]) then
+          begin
+            { just continue loading the parameters in the registers }
+            if assigned(varargspara) then
+              begin
+                if side=callerside then
+                  result := create_paraloc_info_intern(p, side, varargspara, curintreg, curfloatreg, curmmreg, cur_stack_offset, true)
+                else
+                  internalerror(2022111925);
+                if curfloatreg <> firstfloatreg then
+                  include(varargspara.varargsinfo, va_uses_float_reg);
+              end;
+            { varargs routines have to reserve at least 64 bytes for the RiscV ABI }
+            if (result < 64) then
+              result := 64;
+          end
+        else
+          internalerror(2022111926);
+
+        create_funcretloc_info(p, side);
+      end;
+
+    function tcpuparamanager.parseparaloc(p: tparavarsym; const s: string): boolean;
+      begin
+        internalerror(2022111927);
+        result := true;
+     end;
+
+
+begin
+  paramanager := tcpuparamanager.create;
+end.
+

+ 122 - 0
compiler/loongarch64/cpupi.pas

@@ -0,0 +1,122 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    This unit contains the CPU specific part of tprocinfo
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+{ This unit contains the CPU specific part of tprocinfo. }
+unit cpupi;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      cutils,aasmdata,
+      globtype, cgutils, cgbase,
+      procinfo, cpuinfo, psub;
+
+    type
+      tloongarch64procinfo = class(tcgprocinfo)
+        stackframesize,
+        floatregstart : aint;
+        stackpaddingreg: TSuperRegister;
+
+        needs_frame_pointer: boolean;
+
+        constructor create(aparent: tprocinfo); override;
+        procedure set_first_temp_offset; override;
+        function calc_stackframe_size: longint; override;
+      end;
+
+implementation
+
+    uses
+      globals, systems,
+      cpubase,
+      aasmtai,
+      tgobj,cgobj,
+      symconst, symsym, paramgr, symutil, symtable,
+      verbose,
+      aasmcpu;
+
+
+    constructor tloongarch64procinfo.create(aparent: tprocinfo);
+      begin
+        inherited create(aparent);
+        maxpushedparasize := 0;
+        { GCC option -fomit-frame-pointer is default. }
+        framepointer:=NR_STACK_POINTER_REG;
+      end;
+
+
+    procedure tloongarch64procinfo.set_first_temp_offset;
+      begin
+        { TODO framepointer:=NR_STACK_POINTER_REG; Need get backtrace updated. }
+        { TODO Profile }
+
+        if (po_nostackframe in procdef.procoptions) then
+          begin
+            tg.setfirsttemp(align(maxpushedparasize,
+              max(current_settings.alignment.localalignmin,8)));
+          end
+        else
+          begin
+            tg.setfirsttemp(align(maxpushedparasize,
+              max(current_settings.alignment.localalignmin,8)));
+          end;
+      end;
+
+
+    function tloongarch64procinfo.calc_stackframe_size: longint;
+      var
+         firstfloatreg,lastfloatreg,
+         r : byte;
+         floatsavesize : aword;
+         regs: tcpuregisterset;
+      begin
+        maxpushedparasize:=align(maxpushedparasize,
+                             max(current_settings.alignment.localalignmin,8));
+        floatsavesize:=0;
+        case current_settings.fputype of
+          fpu_fd:
+            begin
+              floatsavesize:=0;
+              regs:=cg.rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+              for r:=RS_F0 to RS_F31 do
+                if r in regs then
+                  inc(floatsavesize,8);
+            end;
+          else
+            ;
+        end;
+        result:=align(tg.direction*tg.lasttemp,
+                  max(current_settings.alignment.localalignmin,8))
+                  +maxpushedparasize+aint(floatsavesize);
+        if tg.direction=1 then
+          floatregstart:=result-aint(floatsavesize)
+        else
+          floatregstart:=-result+maxpushedparasize;
+      end;
+
+
+begin
+  cprocinfo := tloongarch64procinfo;
+end.
+

+ 82 - 0
compiler/loongarch64/cputarg.pas

@@ -0,0 +1,82 @@
+{
+    Copyright (c) 2001-2002 by Peter Vreman
+
+    Includes the LoongArch64 dependent target units
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cputarg;
+
+{$i fpcdefs.inc}
+
+interface
+
+
+implementation
+
+    uses
+      systems { prevent a syntax error when nothing is included }
+
+{**************************************
+             Targets
+**************************************}
+
+    {$ifndef NOTARGETLINUX}
+      ,t_linux
+    {$endif}
+
+{**************************************
+             Assemblers
+**************************************}
+
+    {$ifndef NOAGRVGAS}
+      ,agcpugas
+    {$endif}
+
+{**************************************
+        Assembler Readers
+**************************************}
+
+  {$ifndef NoRaRVGas}
+       ,racpugas
+  {$endif NoRaRVGas}
+
+{**************************************
+             Debuginfo
+**************************************}
+
+  {$ifndef NoDbgStabs}
+      ,dbgstabs
+  {$endif NoDbgStabs}
+  {$ifndef NoDbgStabx}
+      ,dbgstabx
+  {$endif NoDbgStabx}
+  {$ifndef NoDbgDwarf}
+      ,dbgdwarf
+  {$endif NoDbgDwarf}
+
+
+{**************************************
+             Optimizer
+**************************************}
+
+    {$ifndef NOOPT}
+      , aoptcpu
+    {$endif NOOPT}
+      ;
+
+end.

+ 185 - 0
compiler/loongarch64/hlcgcpu.pas

@@ -0,0 +1,185 @@
+{
+    Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+    Member of the Free Pascal development team
+
+    This unit contains routines high-level cg support LoongArch64
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit hlcgcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globals,
+  aasmdata,
+  symtype,symdef,
+  cgbase,cgutils,hlcgobj,hlcg2ll, parabase;
+
+type
+
+  thlcgloongarch64 = class(thlcg2ll)
+    protected
+    public
+      procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+  end;
+
+implementation
+
+  uses
+    verbose,
+    systems,fmodule,
+    symconst, symsym,
+    aasmbase,aasmtai,aasmcpu,
+    cpubase,globtype,
+    procinfo,cpupi,cgobj,cgcpu,
+    defutil;
+
+
+  procedure thlcgloongarch64.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
+    procedure loadvmttor12;
+      var
+        tmpref,
+        href : treference;
+        l : TAsmLabel;
+      begin
+        reference_reset_base(href,voidpointertype,NR_R4,0,ctempposinvalid,sizeof(pint),[]);
+        href.refaddr:=addr_reg_12i;
+        list.concat(taicpu.op_reg_ref(A_LD_D,NR_R12,href));
+      end;
+    procedure op_onr12methodaddr;
+      var
+        tmpref,
+        href : treference;
+        l : TAsmLabel;
+        offset: longint;
+      begin
+        if (procdef.extnumber=$ffff) then
+          Internalerror(2022111915);
+
+        offset:=tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber);
+        if not is_simm12(offset) then
+          begin
+            list.concat(taicpu.op_reg_const(A_LI_D,NR_R15,offset));
+            list.concat(taicpu.op_reg_reg_reg(A_ADD_D,NR_R12,NR_R12,NR_R15));
+            offset:=0;
+          end;
+        reference_reset_base(href,voidpointertype,NR_R12,offset,ctempposinvalid, sizeof(pint),[]);
+        href.refaddr:=addr_reg_12i;
+        cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
+
+        reference_reset_base(href,voidpointertype,NR_R12,0,ctempposinvalid,0,[]);
+        href.refaddr:=addr_reg;
+        list.concat(taicpu.op_ref(A_JR,href));
+      end;
+    var
+      make_global : boolean;
+      tmpref , href: treference;
+      l : TAsmLabel;
+      hsym: tsym;
+      paraloc: PCGParaLocation;
+      tmpreg: TRegister;
+    begin
+      if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
+        Internalerror(2022111909);
+      if not assigned(procdef.struct) or
+         (procdef.procoptions*[po_classmethod, po_staticmethod,
+           po_methodpointer, po_interrupt, po_iocheck]<>[]) then
+        Internalerror(2022111910);
+      if procdef.owner.symtabletype<>ObjectSymtable then
+        Internalerror(2022111911);
+
+      make_global:=false;
+      if (not current_module.is_unit) or
+         create_smartlink or
+         (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
+        make_global:=true;
+
+      if make_global then
+        list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0,voidcodepointertype))
+      else
+        list.concat(Tai_symbol.Createname_hidden(labelname,AT_FUNCTION,0,voidcodepointertype));
+
+      { the wrapper might need aktlocaldata for the additional data to
+        load the constant }
+      current_procinfo:=cprocinfo.create(nil);
+
+      { set param1 interface to self  }
+      procdef.init_paraloc_info(callerside);
+      hsym:=tsym(procdef.parast.Find('self'));
+      if not(assigned(hsym) and
+        (hsym.typ=paravarsym)) then
+        internalerror(2022111912);
+      paraloc:=tparavarsym(hsym).paraloc[callerside].location;
+      if assigned(paraloc^.next) then
+        InternalError(2022111913);
+      case paraloc^.loc of
+        LOC_REGISTER:
+          begin
+            if is_simm12(ioffset) then
+              cg.a_op_const_reg(list,OP_SUB, paraloc^.size,ioffset,paraloc^.register)
+            else
+              begin
+                cg.a_load_const_reg(list, paraloc^.size, ioffset, NR_R13);
+                cg.a_op_reg_reg(list, OP_SUB, paraloc^.size, NR_R13, paraloc^.register);
+              end;
+          end;
+      else
+        internalerror(2022111914);
+      end;
+
+      { case 4 }
+      if (po_virtualmethod in procdef.procoptions) and
+          not is_objectpascal_helper(procdef.struct) then
+        begin
+          loadvmttor12;
+          op_onr12methodaddr;
+        end
+      else
+        begin
+          tmpreg:=NR_R12;
+          reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname,AT_FUNCTION),0,0,[]);
+          href.refaddr:=addr_pc_hi20;
+          list.concat(taicpu.op_reg_ref(A_PCALAU12I,tmpreg,href));
+          href.refaddr:=addr_pc_lo12;
+          list.concat(taicpu.op_reg_reg_ref(A_ADDI_D,tmpreg,tmpreg,href));
+          reference_reset_base(href,voidpointertype,tmpreg,0,ctempposinvalid,0,[]);
+          href.refaddr:=addr_reg;
+          list.concat(taicpu.op_ref(A_JR,href));
+        end;
+      list.concatlist(current_procinfo.aktlocaldata);
+
+      current_procinfo.Free;
+      current_procinfo:=nil;
+
+      list.concat(Tai_symbol_end.Createname(labelname));
+    end;
+
+
+  procedure create_hlcodegen_cpu;
+    begin
+      hlcg:=thlcgloongarch64.create;
+      create_codegen;
+    end;
+
+begin
+  chlcgobj:=thlcgloongarch64;
+  create_hlcodegen:=@create_hlcodegen_cpu;
+end.
+

+ 101 - 0
compiler/loongarch64/itcpugas.pas

@@ -0,0 +1,101 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit contains the LoongArch64 GAS instruction tables
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit itcpugas;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      cpubase, cgbase;
+
+    const
+      gas_op2str: array[tasmop] of string[16] = {$i loongarch64att.inc}
+
+    function gas_regnum_search(const s: string): Tregister;
+    function gas_regname(r: Tregister): string;
+
+  implementation
+
+    uses
+      globtype,globals,aasmbase,
+      cutils,verbose, systems,
+      rgbase;
+
+    const
+      gas_regname_table : TRegNameTable = (
+        {$i rloongarch64std.inc}
+      );
+
+      gas_abi_regname_table : TRegNameTable = (
+        {$i rloongarch64abi.inc}
+      );
+
+      gas_regname_index : array[tregisterindex] of tregisterindex = (
+        {$i rloongarch64sri.inc}
+      );
+
+    function findreg_by_gasname(const s:string):tregisterindex;
+      var
+        i,p : tregisterindex;
+      begin
+        {Binary search.}
+        p:=0;
+        i:=regnumber_count_bsstart;
+        repeat
+          if (p+i<=high(tregisterindex)) and (gas_regname_table[gas_regname_index[p+i]]<=s) then
+            p:=p+i;
+          i:=i shr 1;
+        until i=0;
+        if gas_regname_table[gas_regname_index[p]]=s then
+          findreg_by_gasname:=gas_regname_index[p]
+        else
+          findreg_by_gasname:=0;
+      end;
+
+
+    function gas_regnum_search(const s:string):Tregister;
+      begin
+        result:=regnumber_table[findreg_by_gasname(s)];
+      end;
+
+const
+ __regnumber_index : array[tregisterindex] of tregisterindex = (
+        {$i rloongarch64rni.inc}
+      );
+
+
+    function gas_regname(r:Tregister):string;
+      var
+        p : tregisterindex;
+      begin
+        p:=findreg_by_number(r);
+        if p<>0 then
+          { result:=gas_regname_table[p] }
+          { Use abi name instead. }
+          result:=gas_abi_regname_table[p]
+        else
+          result:=generic_regname(r);
+      end;
+
+end.
+

+ 409 - 0
compiler/loongarch64/loongarch64att.inc

@@ -0,0 +1,409 @@
+{ don't edit, this file is generated from loongarchins.dat }
+(
+'none',
+'add.w',
+'add.d',
+'sub.w',
+'sub.d',
+'addi.w',
+'addi.d',
+'addu16i.d',
+'alsl.w',
+'alsl.d',
+'alsl.wu',
+'lu12i.w',
+'lu32i.d',
+'lu52i.d',
+'slt',
+'sltu',
+'slti',
+'sltui',
+'pcaddi',
+'pcaddu12i',
+'pcaddu18i',
+'pcalau12i',
+'and',
+'or',
+'nor',
+'xor',
+'andn',
+'orn',
+'andi',
+'ori',
+'xori',
+'mul.w',
+'mul.d',
+'mulh.w',
+'mulh.du',
+'mulh.d',
+'mulh.wu',
+'mulw.d.w',
+'mulw.d.wu',
+'div.w',
+'div.du',
+'div.d',
+'div.wu',
+'mod.w',
+'mod.du',
+'mod.d',
+'mod.wu',
+'sll.w',
+'sll.d',
+'srl.w',
+'srl.d',
+'sra.w',
+'sra.d',
+'rotr.w',
+'rotr.d',
+'slli.w',
+'slli.d',
+'srli.w',
+'srli.d',
+'srai.w',
+'srai.d',
+'rotri.w',
+'rotri.d',
+'ext.w.b',
+'ext.w.h',
+'clo.w',
+'clo.d',
+'clz.w',
+'clz.d',
+'cto.w',
+'cto.d',
+'ctz.w',
+'ctz.d',
+'bytepick.w',
+'bytepick.d',
+'revb.2h',
+'revb.d',
+'revb.2w',
+'revb.4h',
+'revh.2w',
+'revh.d',
+'bitrev.4b',
+'bitrev.d',
+'bitrev.w',
+'bitrev.8b',
+'bstrins.w',
+'bstrins.d',
+'bstrpick.w',
+'bstrpick.d',
+'maskeqz',
+'masknez',
+'beq',
+'bne',
+'blt',
+'bltu',
+'bge',
+'bgeu',
+'beqz',
+'bnez',
+'b',
+'bl',
+'jirl',
+'ld.b',
+'ld.d',
+'ld.w',
+'ld.h',
+'ld.bu',
+'ld.wu',
+'ld.hu',
+'st.b',
+'st.d',
+'st.w',
+'st.h',
+'ldx.b',
+'ldx.d',
+'ldx.w',
+'ldx.h',
+'ldx.bu',
+'ldx.wu',
+'ldx.hu',
+'stx.b',
+'stx.d',
+'stx.w',
+'stx.h',
+'ldptr.w',
+'ldptr.d',
+'stptr.w',
+'stptr.d',
+'preld',
+'preldx',
+'ldgt.b',
+'ldgt.d',
+'ldgt.w',
+'ldgt.h',
+'ldle.b',
+'ldle.d',
+'ldle.w',
+'ldle.h',
+'stgt.b',
+'stgt.d',
+'stgt.w',
+'stgt.h',
+'stle.b',
+'stle.d',
+'stle.w',
+'stle.h',
+'amswap.w',
+'amswap.d',
+'amswap_db.w',
+'amswap_db.d',
+'amadd.w',
+'amadd.d',
+'amadd_db.w',
+'amadd_db.d',
+'amand.w',
+'amand.d',
+'amand_db.w',
+'amand_db.d',
+'amor.w',
+'amor.d',
+'amor_db.w',
+'amor_db.d',
+'amxor.w',
+'amxor.d',
+'amxor_db.w',
+'amxor_db.d',
+'ammax.w',
+'ammax.du',
+'ammax.d',
+'ammax.wu',
+'ammax_db.w',
+'ammax_db.du',
+'ammax_db.d',
+'ammax_db.wu',
+'ammin.w',
+'ammin.du',
+'ammin.d',
+'ammin.wu',
+'ammin_db.w',
+'ammin_db.du',
+'ammin_db.d',
+'ammin_db.wu',
+'ll.w',
+'ll.d',
+'sc.w',
+'sc.d',
+'dbar',
+'ibar',
+'crc.w.b.w',
+'crc.w.d.w',
+'crc.w.w.w',
+'crc.w.h.w',
+'crcc.w.b.w',
+'crcc.w.d.w',
+'crcc.w.w.w',
+'crcc.w.h.w',
+'syscall',
+'break',
+'asrtle.d',
+'asrtgt.d',
+'rdtimel.w',
+'rdtimeh.w',
+'rdtime.d',
+'cpucfg',
+'fadd.s',
+'fadd.d',
+'fsub.s',
+'fsub.d',
+'fmul.s',
+'fmul.d',
+'fdiv.s',
+'fdiv.d',
+'fmadd.s',
+'fmadd.d',
+'fmsub.s',
+'fmsub.d',
+'fnmadd.s',
+'fnmadd.d',
+'fnmsub.s',
+'fnmsub.d',
+'fmax.s',
+'fmax.d',
+'fmin.s',
+'fmin.d',
+'fmaxa.s',
+'fmaxa.d',
+'fmina.s',
+'fmina.d',
+'fabs.s',
+'fabs.d',
+'fneg.s',
+'fneg.d',
+'fsqrt.s',
+'fsqrt.d',
+'frecip.s',
+'frecip.d',
+'frsqrt.s',
+'frsqrt.d',
+'fcaleb.s',
+'fcaleb.d',
+'flogb.s',
+'flogb.d',
+'fcopysign.s',
+'fcopysign.d',
+'fclass.s',
+'fclass.d',
+'fcmp.caf.s',
+'fcmp.sune.s',
+'fcmp.sor.s',
+'fcmp.sne.s',
+'fcmp.sule.s',
+'fcmp.sge.s',
+'fcmp.sle.s',
+'fcmp.sult.s',
+'fcmp.sgt.s',
+'fcmp.slt.s',
+'fcmp.sueq.s',
+'fcmp.seq.s',
+'fcmp.sun.s',
+'fcmp.saf.s',
+'fcmp.cune.s',
+'fcmp.cor.s',
+'fcmp.cne.s',
+'fcmp.cuge.s',
+'fcmp.cule.s',
+'fcmp.cle.s',
+'fcmp.cugt.s',
+'fcmp.cult.s',
+'fcmp.clt.s',
+'fcmp.cueq.s',
+'fcmp.ceq.s',
+'fcmp.cun.s',
+'fcmp.caf.d',
+'fcmp.sune.d',
+'fcmp.sor.d',
+'fcmp.sne.d',
+'fcmp.sule.d',
+'fcmp.sge.d',
+'fcmp.sle.d',
+'fcmp.sult.d',
+'fcmp.sgt.d',
+'fcmp.slt.d',
+'fcmp.sueq.d',
+'fcmp.seq.d',
+'fcmp.sun.d',
+'fcmp.saf.d',
+'fcmp.cune.d',
+'fcmp.cor.d',
+'fcmp.cne.d',
+'fcmp.cuge.d',
+'fcmp.cule.d',
+'fcmp.cle.d',
+'fcmp.cugt.d',
+'fcmp.cult.d',
+'fcmp.clt.d',
+'fcmp.cueq.d',
+'fcmp.ceq.d',
+'fcmp.cun.d',
+'fcvt.s.d',
+'fcvt.d.s',
+'ffint.s.l',
+'ffint.d.l',
+'ffint.s.w',
+'ffint.d.w',
+'ftint.l.s',
+'ftint.w.s',
+'ftint.l.d',
+'ftint.w.d',
+'ftintrm.l.s',
+'ftintrm.w.s',
+'ftintrm.l.d',
+'ftintrm.w.d',
+'ftintrp.l.s',
+'ftintrp.w.s',
+'ftintrp.l.d',
+'ftintrp.w.d',
+'ftintrz.l.s',
+'ftintrz.w.s',
+'ftintrz.l.d',
+'ftintrz.w.d',
+'ftintrne.l.s',
+'ftintrne.w.s',
+'ftintrne.l.d',
+'ftintrne.w.d',
+'frint.s',
+'frint.d',
+'fmov.s',
+'fmov.d',
+'fsel',
+'movgr2fr.w',
+'movgr2fr.d',
+'movgr2frh.w',
+'movfr2gr.s',
+'movfr2gr.d',
+'movfrh2gr.s',
+'movgr2fcsr',
+'movfcsr2gr',
+'movfr2cf',
+'movcf2fr',
+'movgr2cf',
+'movcf2gr',
+'bceqz',
+'bcnez',
+'fld.s',
+'fld.d',
+'fst.s',
+'fst.d',
+'fldx.s',
+'fldx.d',
+'fstx.s',
+'fstx.d',
+'fldgt.s',
+'fldgt.d',
+'fldle.s',
+'fldle.d',
+'fstgt.s',
+'fstgt.d',
+'fstle.s',
+'fstle.d',
+'csrrd',
+'csrwr',
+'csrxchg',
+'iocsrrd.b',
+'iocsrrd.d',
+'iocsrrd.w',
+'iocsrrd.h',
+'iocsrwr.b',
+'iocsrwr.d',
+'iocsrwr.w',
+'iocsrwr.h',
+'cacop',
+'tlbsrch',
+'tlbrd',
+'tlbwr',
+'tlbfill',
+'tlbclr',
+'tlbflush',
+'invtlb',
+'lddir',
+'ldpte',
+'ertn',
+'dbcl',
+'idle',
+'nop',
+'li.w',
+'li.d',
+'la.global',
+'la.tls.gd',
+'la.tls.ld',
+'la.tls.ie',
+'la.tle.le',
+'la.got',
+'la.pcrel',
+'la.abs',
+'la.local',
+'bltz',
+'bgtz',
+'bgez',
+'blez',
+'jr',
+'bgt',
+'ble',
+'bgtu',
+'bleu',
+'move',
+'b'
+);

+ 2 - 0
compiler/loongarch64/loongarch64nop.inc

@@ -0,0 +1,2 @@
+{ don't edit, this file is generated from loongarchins.dat }
+406;

+ 409 - 0
compiler/loongarch64/loongarch64op.inc

@@ -0,0 +1,409 @@
+{ don't edit, this file is generated from loongarchins.dat }
+(
+A_NONE,
+A_ADD_W,
+A_ADD_D,
+A_SUB_W,
+A_SUB_D,
+A_ADDI_W,
+A_ADDI_D,
+A_ADDU16I_D,
+A_ALSL_W,
+A_ALSL_D,
+A_ALSL_WU,
+A_LU12I_W,
+A_LU32I_D,
+A_LU52I_D,
+A_SLT,
+A_SLTU,
+A_SLTI,
+A_SLTUI,
+A_PCADDI,
+A_PCADDU12I,
+A_PCADDU18I,
+A_PCALAU12I,
+A_AND,
+A_OR,
+A_NOR,
+A_XOR,
+A_ANDN,
+A_ORN,
+A_ANDI,
+A_ORI,
+A_XORI,
+A_MUL_W,
+A_MUL_D,
+A_MULH_W,
+A_MULH_DU,
+A_MULH_D,
+A_MULH_WU,
+A_MULW_D_W,
+A_MULW_D_WU,
+A_DIV_W,
+A_DIV_DU,
+A_DIV_D,
+A_DIV_WU,
+A_MOD_W,
+A_MOD_DU,
+A_MOD_D,
+A_MOD_WU,
+A_SLL_W,
+A_SLL_D,
+A_SRL_W,
+A_SRL_D,
+A_SRA_W,
+A_SRA_D,
+A_ROTR_W,
+A_ROTR_D,
+A_SLLI_W,
+A_SLLI_D,
+A_SRLI_W,
+A_SRLI_D,
+A_SRAI_W,
+A_SRAI_D,
+A_ROTRI_W,
+A_ROTRI_D,
+A_EXT_W_B,
+A_EXT_W_H,
+A_CLO_W,
+A_CLO_D,
+A_CLZ_W,
+A_CLZ_D,
+A_CTO_W,
+A_CTO_D,
+A_CTZ_W,
+A_CTZ_D,
+A_BYTEPICK_W,
+A_BYTEPICK_D,
+A_REVB_2H,
+A_REVB_D,
+A_REVB_2W,
+A_REVB_4H,
+A_REVH_2W,
+A_REVH_D,
+A_BITREV_4B,
+A_BITREV_D,
+A_BITREV_W,
+A_BITREV_8B,
+A_BSTRINS_W,
+A_BSTRINS_D,
+A_BSTRPICK_W,
+A_BSTRPICK_D,
+A_MASKEQZ,
+A_MASKNEZ,
+A_BEQ,
+A_BNE,
+A_BLT,
+A_BLTU,
+A_BGE,
+A_BGEU,
+A_BEQZ,
+A_BNEZ,
+A_B,
+A_BL,
+A_JIRL,
+A_LD_B,
+A_LD_D,
+A_LD_W,
+A_LD_H,
+A_LD_BU,
+A_LD_WU,
+A_LD_HU,
+A_ST_B,
+A_ST_D,
+A_ST_W,
+A_ST_H,
+A_LDX_B,
+A_LDX_D,
+A_LDX_W,
+A_LDX_H,
+A_LDX_BU,
+A_LDX_WU,
+A_LDX_HU,
+A_STX_B,
+A_STX_D,
+A_STX_W,
+A_STX_H,
+A_LDPTR_W,
+A_LDPTR_D,
+A_STPTR_W,
+A_STPTR_D,
+A_PRELD,
+A_PRELDX,
+A_LDGT_B,
+A_LDGT_D,
+A_LDGT_W,
+A_LDGT_H,
+A_LDLE_B,
+A_LDLE_D,
+A_LDLE_W,
+A_LDLE_H,
+A_STGT_B,
+A_STGT_D,
+A_STGT_W,
+A_STGT_H,
+A_STLE_B,
+A_STLE_D,
+A_STLE_W,
+A_STLE_H,
+A_AMSWAP_W,
+A_AMSWAP_D,
+A_AMSWAP_DB_W,
+A_AMSWAP_DB_D,
+A_AMADD_W,
+A_AMADD_D,
+A_AMADD_DB_W,
+A_AMADD_DB_D,
+A_AMAND_W,
+A_AMAND_D,
+A_AMAND_DB_W,
+A_AMAND_DB_D,
+A_AMOR_W,
+A_AMOR_D,
+A_AMOR_DB_W,
+A_AMOR_DB_D,
+A_AMXOR_W,
+A_AMXOR_D,
+A_AMXOR_DB_W,
+A_AMXOR_DB_D,
+A_AMMAX_W,
+A_AMMAX_DU,
+A_AMMAX_D,
+A_AMMAX_WU,
+A_AMMAX_DB_W,
+A_AMMAX_DB_DU,
+A_AMMAX_DB_D,
+A_AMMAX_DB_WU,
+A_AMMIN_W,
+A_AMMIN_DU,
+A_AMMIN_D,
+A_AMMIN_WU,
+A_AMMIN_DB_W,
+A_AMMIN_DB_DU,
+A_AMMIN_DB_D,
+A_AMMIN_DB_WU,
+A_LL_W,
+A_LL_D,
+A_SC_W,
+A_SC_D,
+A_DBAR,
+A_IBAR,
+A_CRC_W_B_W,
+A_CRC_W_D_W,
+A_CRC_W_W_W,
+A_CRC_W_H_W,
+A_CRCC_W_B_W,
+A_CRCC_W_D_W,
+A_CRCC_W_W_W,
+A_CRCC_W_H_W,
+A_SYSCALL,
+A_BREAK,
+A_ASRTLE_D,
+A_ASRTGT_D,
+A_RDTIMEL_W,
+A_RDTIMEH_W,
+A_RDTIME_D,
+A_CPUCFG,
+A_FADD_S,
+A_FADD_D,
+A_FSUB_S,
+A_FSUB_D,
+A_FMUL_S,
+A_FMUL_D,
+A_FDIV_S,
+A_FDIV_D,
+A_FMADD_S,
+A_FMADD_D,
+A_FMSUB_S,
+A_FMSUB_D,
+A_FNMADD_S,
+A_FNMADD_D,
+A_FNMSUB_S,
+A_FNMSUB_D,
+A_FMAX_S,
+A_FMAX_D,
+A_FMIN_S,
+A_FMIN_D,
+A_FMAXA_S,
+A_FMAXA_D,
+A_FMINA_S,
+A_FMINA_D,
+A_FABS_S,
+A_FABS_D,
+A_FNEG_S,
+A_FNEG_D,
+A_FSQRT_S,
+A_FSQRT_D,
+A_FRECIP_S,
+A_FRECIP_D,
+A_FRSQRT_S,
+A_FRSQRT_D,
+A_FCALEB_S,
+A_FCALEB_D,
+A_FLOGB_S,
+A_FLOGB_D,
+A_FCOPYSIGN_S,
+A_FCOPYSIGN_D,
+A_FCLASS_S,
+A_FCLASS_D,
+A_FCMP_CAF_S,
+A_FCMP_SUNE_S,
+A_FCMP_SOR_S,
+A_FCMP_SNE_S,
+A_FCMP_SULE_S,
+A_FCMP_SGE_S,
+A_FCMP_SLE_S,
+A_FCMP_SULT_S,
+A_FCMP_SGT_S,
+A_FCMP_SLT_S,
+A_FCMP_SUEQ_S,
+A_FCMP_SEQ_S,
+A_FCMP_SUN_S,
+A_FCMP_SAF_S,
+A_FCMP_CUNE_S,
+A_FCMP_COR_S,
+A_FCMP_CNE_S,
+A_FCMP_CUGE_S,
+A_FCMP_CULE_S,
+A_FCMP_CLE_S,
+A_FCMP_CUGT_S,
+A_FCMP_CULT_S,
+A_FCMP_CLT_S,
+A_FCMP_CUEQ_S,
+A_FCMP_CEQ_S,
+A_FCMP_CUN_S,
+A_FCMP_CAF_D,
+A_FCMP_SUNE_D,
+A_FCMP_SOR_D,
+A_FCMP_SNE_D,
+A_FCMP_SULE_D,
+A_FCMP_SGE_D,
+A_FCMP_SLE_D,
+A_FCMP_SULT_D,
+A_FCMP_SGT_D,
+A_FCMP_SLT_D,
+A_FCMP_SUEQ_D,
+A_FCMP_SEQ_D,
+A_FCMP_SUN_D,
+A_FCMP_SAF_D,
+A_FCMP_CUNE_D,
+A_FCMP_COR_D,
+A_FCMP_CNE_D,
+A_FCMP_CUGE_D,
+A_FCMP_CULE_D,
+A_FCMP_CLE_D,
+A_FCMP_CUGT_D,
+A_FCMP_CULT_D,
+A_FCMP_CLT_D,
+A_FCMP_CUEQ_D,
+A_FCMP_CEQ_D,
+A_FCMP_CUN_D,
+A_FCVT_S_D,
+A_FCVT_D_S,
+A_FFINT_S_L,
+A_FFINT_D_L,
+A_FFINT_S_W,
+A_FFINT_D_W,
+A_FTINT_L_S,
+A_FTINT_W_S,
+A_FTINT_L_D,
+A_FTINT_W_D,
+A_FTINTRM_L_S,
+A_FTINTRM_W_S,
+A_FTINTRM_L_D,
+A_FTINTRM_W_D,
+A_FTINTRP_L_S,
+A_FTINTRP_W_S,
+A_FTINTRP_L_D,
+A_FTINTRP_W_D,
+A_FTINTRZ_L_S,
+A_FTINTRZ_W_S,
+A_FTINTRZ_L_D,
+A_FTINTRZ_W_D,
+A_FTINTRNE_L_S,
+A_FTINTRNE_W_S,
+A_FTINTRNE_L_D,
+A_FTINTRNE_W_D,
+A_FRINT_S,
+A_FRINT_D,
+A_FMOV_S,
+A_FMOV_D,
+A_FSEL,
+A_MOVGR2FR_W,
+A_MOVGR2FR_D,
+A_MOVGR2FRH_W,
+A_MOVFR2GR_S,
+A_MOVFR2GR_D,
+A_MOVFRH2GR_S,
+A_MOVGR2FCSR,
+A_MOVFCSR2GR,
+A_MOVFR2CF,
+A_MOVCF2FR,
+A_MOVGR2CF,
+A_MOVCF2GR,
+A_BCEQZ,
+A_BCNEZ,
+A_FLD_S,
+A_FLD_D,
+A_FST_S,
+A_FST_D,
+A_FLDX_S,
+A_FLDX_D,
+A_FSTX_S,
+A_FSTX_D,
+A_FLDGT_S,
+A_FLDGT_D,
+A_FLDLE_S,
+A_FLDLE_D,
+A_FSTGT_S,
+A_FSTGT_D,
+A_FSTLE_S,
+A_FSTLE_D,
+A_CSRRD,
+A_CSRWR,
+A_CSRXCHG,
+A_IOCSRRD_B,
+A_IOCSRRD_D,
+A_IOCSRRD_W,
+A_IOCSRRD_H,
+A_IOCSRWR_B,
+A_IOCSRWR_D,
+A_IOCSRWR_W,
+A_IOCSRWR_H,
+A_CACOP,
+A_TLBSRCH,
+A_TLBRD,
+A_TLBWR,
+A_TLBFILL,
+A_TLBCLR,
+A_TLBFLUSH,
+A_INVTLB,
+A_LDDIR,
+A_LDPTE,
+A_ERTN,
+A_DBCL,
+A_IDLE,
+A_NOP,
+A_LI_W,
+A_LI_D,
+A_LA_GLOBAL,
+A_LA_TLS_GD,
+A_LA_TLS_LD,
+A_LA_TLS_IE,
+A_LA_TLE_LE,
+A_LA_GOT,
+A_LA_PCREL,
+A_LA_ABS,
+A_LA_LOCAL,
+A_BLTZ,
+A_BGTZ,
+A_BGEZ,
+A_BLEZ,
+A_JR,
+A_BGT,
+A_BLE,
+A_BGTU,
+A_BLEU,
+A_MOVE,
+A_BXX
+);

+ 404 - 0
compiler/loongarch64/loongarchins.dat

@@ -0,0 +1,404 @@
+; [NAME](format0)
+;
+; format
+; a, 'w' or 'd'
+; b, 'w'
+; c, 'd'
+; d, 'w' or 'wu' or 'd'
+; e, 'w' or 'wu' or 'd' or 'du'
+; f, 'w' or 'wu'
+; g, 'b' or 'h'
+; h, '2h' or '4h' or '2w' or 'd'
+; i, '2w' or 'd'
+; j, '4b' or '8b' or 'w' or 'd'
+; k, 'b' or 'h' or 'w' or 'd'
+; l, 'bu' or 'hu' or 'wu'
+; m, 's' or 'd'
+; n, fcmp condtions, caf cun ceq cueq clt     cult cugt cle     cule cuge cne cor cune
+;                    saf sun seq sueq slt sgt sult      sle sge sule      sne sor sune
+; o, 's'
+; p, 'd'
+; q, 'l' or 'w'
+; r, 'global' or 'local' or 'abs/pcrel/got' or 'tls.le/ie/ld/gd'
+
+[NONE](0)
+
+[ADD](a0)
+
+[SUB](a0)
+
+[ADDI](a0)
+
+[ADDU16I](c0)
+
+[ALSL](d0)
+
+[LU12I](b0)
+
+[LU32I](c0)
+
+[LU52I](c0)
+
+[SLT](0)
+
+[SLTU](0)
+
+[SLTI](0)
+
+[SLTUI](0)
+
+[PCADDI](0)
+
+[PCADDU12I](0)
+
+[PCADDU18I](0)
+
+[PCALAU12I](0)
+
+[AND](0)
+
+[OR](0)
+
+[NOR](0)
+
+[XOR](0)
+
+[ANDN](0)
+
+[ORN](0)
+
+[ANDI](0)
+
+[ORI](0)
+
+[XORI](0)
+
+[MUL](a0)
+
+[MULH](e0)
+
+[MULW](cf0)
+
+[DIV](e0)
+
+[MOD](e0)
+
+[SLL](a0)
+
+[SRL](a0)
+
+[SRA](a0)
+
+[ROTR](a0)
+
+[SLLI](a0)
+
+[SRLI](a0)
+
+[SRAI](a0)
+
+[ROTRI](a0)
+
+[EXT](bg0)
+
+[CLO](a0)
+
+[CLZ](a0)
+
+[CTO](a0)
+
+[CTZ](a0)
+
+[BYTEPICK](a0)
+
+[REVB](h0)
+
+[REVH](i0)
+
+[BITREV](j0)
+
+[BSTRINS](a0)
+
+[BSTRPICK](a0)
+
+[MASKEQZ](0)
+
+[MASKNEZ](0)
+
+[BEQ](0)
+
+[BNE](0)
+
+[BLT](0)
+
+[BLTU](0)
+
+[BGE](0)
+
+[BGEU](0)
+
+[BEQZ](0)
+
+[BNEZ](0)
+
+[B](0)
+
+[BL](0)
+
+[JIRL](0)
+
+[LD](k0)
+
+[LD](l0)
+
+[ST](k0)
+
+[LDX](k0)
+
+[LDX](l0)
+
+[STX](k0)
+
+[LDPTR](a0)
+
+[STPTR](a0)
+
+[PRELD](0)
+
+[PRELDX](0)
+
+[LDGT](k0)
+
+[LDLE](k0)
+
+[STGT](k0)
+
+[STLE](k0)
+
+[AMSWAP](a0)
+
+[AMSWAP_DB](a0)
+
+[AMADD](a0)
+
+[AMADD_DB](a0)
+
+[AMAND](a0)
+
+[AMAND_DB](a0)
+
+[AMOR](a0)
+
+[AMOR_DB](a0)
+
+[AMXOR](a0)
+
+[AMXOR_DB](a0)
+
+[AMMAX](e0)
+
+[AMMAX_DB](e0)
+
+[AMMIN](e0)
+
+[AMMIN_DB](e0)
+
+[LL](a0)
+
+[SC](a0)
+
+[DBAR](0)
+
+[IBAR](0)
+
+[CRC](bkb0)
+
+[CRCC](bkb0)
+
+[SYSCALL](0)
+
+[BREAK](0)
+
+[ASRTLE](c0)
+
+[ASRTGT](c0)
+
+[RDTIMEL](b0)
+
+[RDTIMEH](b0)
+
+[RDTIME](c0)
+
+[CPUCFG](0)
+
+[FADD](m0)
+
+[FSUB](m0)
+
+[FMUL](m0)
+
+[FDIV](m0)
+
+[FMADD](m0)
+
+[FMSUB](m0)
+
+[FNMADD](m0)
+
+[FNMSUB](m0)
+
+[FMAX](m0)
+
+[FMIN](m0)
+
+[FMAXA](m0)
+
+[FMINA](m0)
+
+[FABS](m0)
+
+[FNEG](m0)
+
+[FSQRT](m0)
+
+[FRECIP](m0)
+
+[FRSQRT](m0)
+
+[FCALEB](m0)
+
+[FLOGB](m0)
+
+[FCOPYSIGN](m0)
+
+[FCLASS](m0)
+
+[FCMP](nm0)
+
+[FCVT](op0)
+
+[FCVT](po0)
+
+[FFINT](mq0)
+
+[FTINT](qm0)
+
+[FTINTRM](qm0)
+
+[FTINTRP](qm0)
+
+[FTINTRZ](qm0)
+
+[FTINTRNE](qm0)
+
+[FRINT](m0)
+
+[FMOV](m0)
+
+[FSEL](0)
+
+[MOVGR2FR](a0)
+
+[MOVGR2FRH](b0)
+
+[MOVFR2GR](m0)
+
+[MOVFRH2GR](o0)
+
+[MOVGR2FCSR](0)
+
+[MOVFCSR2GR](0)
+
+[MOVFR2CF](0)
+
+[MOVCF2FR](0)
+
+[MOVGR2CF](0)
+
+[MOVCF2GR](0)
+
+[BCEQZ](0)
+
+[BCNEZ](0)
+
+[FLD](m0)
+
+[FST](m0)
+
+[FLDX](m0)
+
+[FSTX](m0)
+
+[FLDGT](m0)
+
+[FLDLE](m0)
+
+[FSTGT](m0)
+
+[FSTLE](m0)
+
+[CSRRD](0)
+
+[CSRWR](0)
+
+[CSRXCHG](0)
+
+[IOCSRRD](k0)
+
+[IOCSRWR](k0)
+
+[CACOP](0)
+
+[TLBSRCH](0)
+
+[TLBRD](0)
+
+[TLBWR](0)
+
+[TLBFILL](0)
+
+[TLBCLR](0)
+
+[TLBFLUSH](0)
+
+[INVTLB](0)
+
+[LDDIR](0)
+
+[LDPTE](0)
+
+[ERTN](0)
+
+[DBCL](0)
+
+[IDLE](0)
+
+; Macro Used by Binutils
+[NOP](0)
+
+[LI](a0)
+
+[LA](r0)
+
+[BLTZ](0)
+
+[BGTZ](0)
+
+[BGEZ](0)
+
+[BLEZ](0)
+
+[JR](0)
+
+[BGT](0)
+
+[BLE](0)
+
+[BGTU](0)
+
+[BLEU](0)
+
+[MOVE](0)
+
+; Macro Used Bt Free Pascal
+[BXX](0)

+ 83 - 0
compiler/loongarch64/loongarchreg.dat

@@ -0,0 +1,83 @@
+;
+; LoongArch registers
+;
+; layout
+; <name>,<type>,<subtype>,<value>,<abiname>,<stdname>,<stab idx>,<dwarf idx>
+;
+; We don't care stabs because STABS dbginfo is obsolete
+
+NO,$00,$00,$00,INVALID,INVALID,-1,-1
+R0,$01,$00,$00,$zero,$r0,0,0
+R1,$01,$00,$01,$ra,$r1,1,1
+R2,$01,$00,$02,$tp,$r2,2,2
+R3,$01,$00,$03,$sp,$r3,3,3
+R4,$01,$00,$04,$a0,$r4,4,4
+R5,$01,$00,$05,$a1,$r5,5,5
+R6,$01,$00,$06,$a2,$r6,6,6
+R7,$01,$00,$07,$a3,$r7,7,7
+R8,$01,$00,$08,$a4,$r8,8,8
+R9,$01,$00,$09,$a5,$r9,9,9
+R10,$01,$00,$0A,$a6,$r10,10,10
+R11,$01,$00,$0B,$a7,$r11,11,11
+R12,$01,$00,$0C,$t0,$r12,12,12
+R13,$01,$00,$0D,$t1,$r13,13,13
+R14,$01,$00,$0E,$t2,$r14,14,14
+R15,$01,$00,$0F,$t3,$r15,15,15
+R16,$01,$00,$10,$t4,$r16,16,16
+R17,$01,$00,$11,$t5,$r17,17,17
+R18,$01,$00,$12,$t6,$r18,18,18
+R19,$01,$00,$13,$t7,$r19,19,19
+R20,$01,$00,$14,$t8,$r20,20,20
+R21,$01,$00,$15,$x,$r21,21,21
+R22,$01,$00,$16,$fp,$r22,22,22
+R23,$01,$00,$17,$s0,$r23,23,23
+R24,$01,$00,$18,$s1,$r24,24,24
+R25,$01,$00,$19,$s2,$r25,25,25
+R26,$01,$00,$1A,$s3,$r26,26,26
+R27,$01,$00,$1B,$s4,$r27,27,27
+R28,$01,$00,$1C,$s5,$r28,28,28
+R29,$01,$00,$1D,$s6,$r29,29,29
+R30,$01,$00,$1E,$s7,$r30,30,30
+R31,$01,$00,$1F,$s8,$r31,31,31
+
+F0,$02,$00,$00,$fa0,$f0,32,32
+F1,$02,$00,$01,$fa1,$f1,33,33
+F2,$02,$00,$02,$fa2,$f2,34,34
+F3,$02,$00,$03,$fa3,$f3,35,35
+F4,$02,$00,$04,$fa4,$f4,36,36
+F5,$02,$00,$05,$fa5,$f5,37,37
+F6,$02,$00,$06,$fa6,$f6,38,38
+F7,$02,$00,$07,$fa7,$f7,39,39
+F8,$02,$00,$08,$ft0,$f8,40,40
+F9,$02,$00,$09,$ft1,$f9,41,41
+F10,$02,$00,$0A,$ft2,$f10,42,42
+F11,$02,$00,$0B,$ft3,$f11,43,43
+F12,$02,$00,$0C,$ft4,$f12,44,44
+F13,$02,$00,$0D,$ft5,$f13,45,45
+F14,$02,$00,$0E,$ft6,$f14,46,46
+F15,$02,$00,$0F,$ft7,$f15,47,47
+F16,$02,$00,$10,$ft8,$f16,48,48
+F17,$02,$00,$11,$ft9,$f17,49,49
+F18,$02,$00,$12,$ft10,$f18,50,50
+F19,$02,$00,$13,$ft11,$f19,51,51
+F20,$02,$00,$14,$ft12,$f20,52,52
+F21,$02,$00,$15,$ft13,$f21,53,53
+F22,$02,$00,$16,$ft14,$f22,54,54
+F23,$02,$00,$17,$ft15,$f23,55,55
+F24,$02,$00,$18,$fs0,$f24,56,56
+F25,$02,$00,$19,$fs1,$f25,57,57
+F26,$02,$00,$1A,$fs2,$f26,58,58
+F27,$02,$00,$1B,$fs3,$f27,59,59
+F28,$02,$00,$1C,$fs4,$f28,60,60
+F29,$02,$00,$1D,$fs5,$f29,61,61
+F30,$02,$00,$1E,$fs6,$f30,62,62
+F31,$02,$00,$1F,$fs7,$f31,63,63
+
+FCC0,$05,$00,$00,$fcc0,$fcc0,64,64
+FCC1,$05,$00,$01,$fcc1,$fcc1,65,65
+FCC2,$05,$00,$02,$fcc2,$fcc2,66,66
+FCC3,$05,$00,$03,$fcc3,$fcc3,67,67
+FCC4,$05,$00,$04,$fcc4,$fcc4,68,68
+FCC5,$05,$00,$05,$fcc5,$fcc5,69,69
+FCC6,$05,$00,$06,$fcc6,$fcc6,70,70
+FCC7,$05,$00,$07,$fcc7,$fcc7,71,71

+ 401 - 0
compiler/loongarch64/ncpuadd.pas

@@ -0,0 +1,401 @@
+{
+    Copyright (c) 2000-2006 by Florian Klaempfl and Jonas Maebe
+
+    Code generation for add nodes on the LoongArch64
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit ncpuadd;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       node,nadd,ncgadd,cpubase;
+
+    type
+      tloongarch64addnode = class(tcgaddnode)
+      private
+        procedure Cmp(signed,is_smallset: boolean);
+      protected
+        procedure second_cmpsmallset;override;
+        procedure second_cmpordinal;override;
+        procedure second_cmp64bit; override;
+
+        procedure second_addordinal; override;
+        procedure second_add64bit; override;
+
+        procedure pass_left_and_right;
+
+        procedure second_addfloat;override;
+        procedure second_cmpfloat;override;
+      public
+        function use_generic_mul32to64: boolean; override;
+      end;
+
+
+implementation
+
+    uses
+      globtype,systems,
+      cutils,verbose,globals,
+      symconst,symdef,paramgr,
+      aasmbase,aasmtai,aasmdata,aasmcpu,defutil,htypechk,
+      cgbase,cpuinfo,pass_1,pass_2,
+      cpupara,cgcpu,cgutils,procinfo,
+      ncon,nset,
+      ncgutil,tgobj,rgobj,rgcpu,cgobj,hlcgobj;
+
+
+    procedure tloongarch64addnode.Cmp(signed,is_smallset: boolean);
+      var
+        flabel,tlabel: tasmlabel;
+        op, opi: TAsmOp;
+        allow_constant : boolean;
+      begin
+        pass_left_right;
+
+        allow_constant:=(not is_smallset) or not (nodetype in [lten,gten]);
+
+        force_reg_left_right(true,allow_constant);
+
+        if nf_swapped in flags then
+          swapleftright;
+
+        location_reset(location,LOC_REGISTER,OS_INT);
+        location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+
+        if signed then op:=A_SLT else op:=A_SLTU;
+        if signed then opi:=A_SLTI else opi:=A_SLTUI;
+
+        case nodetype of
+          equaln:
+            begin
+              if not (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if (right.location.loc=LOC_CONSTANT) and
+                 (not is_uimm12(right.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if right.location.loc=LOC_CONSTANT then
+                if right.location.value = 0 then
+                  cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,left.location.register,location.register)
+                else
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_XORI,location.register,left.location.register,right.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_XOR,location.register,left.location.register,right.location.register));
+              current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTUI,location.register,location.register,1));
+            end;
+          unequaln:
+            begin
+              if not (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if (right.location.loc=LOC_CONSTANT) and
+                 (not is_uimm12(right.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if right.location.loc=LOC_CONSTANT then
+                if right.location.value = 0 then
+                  cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,left.location.register,location.register)
+                else
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_XORI,location.register,left.location.register,right.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_XOR,location.register,left.location.register,right.location.register));
+              current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_SLTU,location.register,NR_R0,location.register));
+            end;
+          ltn:
+            begin
+              if not (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if (right.location.loc=LOC_CONSTANT) and
+                 (not is_simm12(right.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if right.location.loc=LOC_CONSTANT then
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(opi,location.register,left.location.register,right.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+            end;
+          gtn:
+            begin
+              if not (right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if (left.location.loc=LOC_CONSTANT) and
+                 (not is_simm12(left.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if left.location.loc=LOC_CONSTANT then
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(opi,location.register,right.location.register,left.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,location.register,right.location.register,left.location.register));
+            end;
+
+          lten:
+            begin
+              if not (right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if (left.location.loc=LOC_CONSTANT) and
+                 (not is_simm12(left.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+              if is_smallset then
+                begin
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_ANDN,location.register,left.location.register,right.location.register));
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTUI,location.register,location.register,1));
+                end
+              else
+                begin
+                  if left.location.loc=LOC_CONSTANT then
+                    current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(opi,location.register,right.location.register,left.location.value))
+                  else
+                    current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,location.register,right.location.register,left.location.register));
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_XORI,location.register,location.register,1));
+                end;
+            end;
+          gten:
+            begin
+              if not (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if (right.location.loc=LOC_CONSTANT) and
+                 (not is_simm12(right.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+              if is_smallset then
+                begin
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_ANDN,location.register,right.location.register,left.location.register));
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTUI,location.register,location.register,1));
+                end
+              else
+                begin
+                   if right.location.loc=LOC_CONSTANT then
+                    current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(opi,location.register,left.location.register,right.location.value))
+                  else
+                    current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_XORI,location.register,location.register,1));
+                end;
+            end;
+        else
+          Internalerror(2022111946);
+        end;
+      end;
+
+
+    { Smallset means the one all bits in another one. }
+    procedure tloongarch64addnode.second_cmpsmallset;
+      begin
+        Cmp(false,true);
+      end;
+
+
+    procedure tloongarch64addnode.second_cmpordinal;
+      var
+        unsigned: Boolean;
+      begin
+        unsigned:=not(is_signed(left.resultdef)) or
+                  not(is_signed(right.resultdef));
+
+        Cmp(not unsigned,false);
+      end;
+
+
+    procedure tloongarch64addnode.second_cmp64bit;
+      var
+        unsigned: Boolean;
+      begin
+        unsigned:=not(is_signed(left.resultdef)) or
+                  not(is_signed(right.resultdef));
+
+        Cmp(not unsigned,false);
+      end;
+
+
+    procedure tloongarch64addnode.second_addordinal;
+      const
+        multops: array[boolean] of TAsmOp = (A_MULW_D_W,A_MULW_D_WU);
+      var
+        unsigned: boolean;
+      begin
+        { 32x32->64 multiplication }
+        if (nodetype=muln) and
+           is_32bit(left.resultdef) and
+           is_32bit(right.resultdef) and
+           is_64bit(resultdef) then
+          begin
+            unsigned:=not(is_signed(left.resultdef)) or
+                      not(is_signed(right.resultdef));
+            pass_left_right;
+            force_reg_left_right(true,true);
+            { force_reg_left_right can leave right as a LOC_CONSTANT (we can't
+              say "a constant register is okay, but an ordinal constant isn't) }
+            if right.location.loc=LOC_CONSTANT then
+              hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true);
+            location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+            location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
+            current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(multops[unsigned],location.register,left.location.register,right.location.register));
+          end
+        else
+          inherited second_addordinal;
+      end;
+
+
+    procedure tloongarch64addnode.second_add64bit;
+      begin
+        second_addordinal;
+      end;
+
+
+    procedure tloongarch64addnode.pass_left_and_right;
+      begin
+        { calculate the operator which is more difficult }
+        firstcomplex(self);
+
+        { in case of constant put it to the left }
+        if (left.nodetype=ordconstn) then
+         swapleftright;
+
+        secondpass(left);
+        secondpass(right);
+      end;
+
+
+    procedure tloongarch64addnode.second_addfloat;
+      var
+        op    : TAsmOp;
+        cmpop,
+        singleprec: boolean;
+      begin
+        pass_left_and_right;
+        if (nf_swapped in flags) then
+          swapleftright;
+
+        hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+        hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
+
+        cmpop:=false;
+        singleprec:=tfloatdef(left.resultdef).floattype=s32real;
+        case nodetype of
+          addn :
+            if singleprec then
+              op:=A_FADD_S
+            else
+              op:=A_FADD_D;
+          muln :
+            if singleprec then
+              op:=A_FMUL_S
+            else
+            op:=A_FMUL_D;
+          subn :
+            if singleprec then
+              op:=A_FSUB_S
+            else
+              op:=A_FSUB_D;
+          slashn :
+            if singleprec then
+              op:=A_FDIV_S
+            else
+             op:=A_FDIV_D;
+          equaln:
+            begin
+              if singleprec then
+                op:=A_FCMP_CEQ_S
+              else
+                op:=A_FCMP_CEQ_D;
+              cmpop:=true;
+            end;
+          unequaln:
+            begin
+              if singleprec then
+                op:=A_FCMP_CUNE_S
+              else
+                op:=A_FCMP_CUNE_D;
+              cmpop:=true;
+            end;
+          ltn:
+            begin
+              if singleprec then
+                op:=A_FCMP_SLT_S
+              else
+                op:=A_FCMP_SLT_D;
+              cmpop:=true;
+            end;
+          lten:
+            begin
+              if singleprec then
+                op:=A_FCMP_SLE_S
+              else
+                op:=A_FCMP_SLE_D;
+              cmpop:=true;
+            end;
+          gtn:
+            begin
+              if singleprec then
+                op:=A_FCMP_SGT_S
+              else
+                op:=A_FCMP_SGT_D;
+              cmpop:=true;
+            end;
+          gten:
+            begin
+              if singleprec then
+                op:=A_FCMP_SGE_S
+              else
+                op:=A_FCMP_SGE_D;
+              cmpop:=true;
+            end;
+          else
+            internalerror(2022111947);
+        end;
+
+        if cmpop then
+          begin
+            { TODO This should be like mips, but... }
+            { location_reset(location, LOC_FLAGS, OS_NO); }
+            { location.register := cg.getfpuregister(current_asmdata.CurrAsmList,location.size); }
+            location_reset(location,LOC_REGISTER,OS_8);
+            location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,NR_FCC0,left.location.register,right.location.register));
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_MOVCF2GR,location.register,NR_FCC0));
+            cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+          end
+        else
+          begin
+            location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
+            location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+            cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+          end;
+      end;
+
+    procedure tloongarch64addnode.second_cmpfloat;
+      begin
+        second_addfloat;
+      end;
+
+    function tloongarch64addnode.use_generic_mul32to64: boolean;
+      begin
+        result:=false;
+      end;
+
+begin
+  caddnode := tloongarch64addnode;
+end.

+ 236 - 0
compiler/loongarch64/ncpucnv.pas

@@ -0,0 +1,236 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate LoongArch64 assembler for type converting nodes
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit ncpucnv;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,ncnv,ncgcnv;
+
+    type
+       tloongarch64typeconvnode = class(tcgtypeconvnode)
+         protected
+         { procedure second_int_to_int;override; }
+         { procedure second_string_to_string;override; }
+         { procedure second_cstring_to_pchar;override; }
+         { procedure second_string_to_chararray;override; }
+         { procedure second_array_to_pointer;override; }
+           function first_int_to_real: tnode; override;
+         { procedure second_pointer_to_array;override; }
+         { procedure second_chararray_to_string;override; }
+         { procedure second_char_to_string;override; }
+           procedure second_int_to_real;override;
+         { procedure second_real_to_real;override; }
+         { procedure second_cord_to_pointer;override; }
+         { procedure second_proc_to_procvar;override; }
+         { procedure second_bool_to_int;override; }
+           procedure second_int_to_bool;override;
+         { procedure second_load_smallset;override;  }
+         { procedure second_ansistring_to_pchar;override; }
+         { procedure second_pchar_to_string;override; }
+         { procedure second_class_to_intf;override; }
+         { procedure second_char_to_char;override; }
+       end;
+
+
+implementation
+
+   uses
+      verbose,globtype,globals,systems,
+      symconst,symdef,aasmbase,aasmtai,aasmdata,
+      defutil, symcpu,
+      cgbase,cgutils,pass_1,pass_2,
+      ncon, ncal,procinfo,
+      ncgutil,
+      cpubase,aasmcpu,
+      rgobj,tgobj,cgobj,hlcgobj;
+
+
+    {*****************************************************************************
+                                 FirstTypeConv
+    *****************************************************************************}
+
+    function tloongarch64typeconvnode.first_int_to_real: tnode;
+      var
+        fname: string[19];
+      begin
+        { converting a 64bit integer to a float requires a helper }
+        if is_64bitint(left.resultdef) or
+          is_currency(left.resultdef) then
+          begin
+            { hack to avoid double division by 10000, as it's
+              already done by typecheckpass.resultdef_int_to_real }
+            if is_currency(left.resultdef) then
+              left.resultdef := s64inttype
+            else if not is_signed(left.resultdef) then
+              begin
+                fname := 'fpc_qword_to_double';
+                result := ccallnode.createintern(fname,ccallparanode.create(left,nil));
+                left:=nil;
+                if (tfloatdef(resultdef).floattype=s32real) then
+                  inserttypeconv(result,s32floattype);
+                firstpass(result);
+                exit;
+              end;
+          end
+        else
+          begin
+            { Else signed supposed to be 32 bit, or unsigned supposed to be 64 bit }
+            if is_signed(left.resultdef) then
+              inserttypeconv(left,s32inttype)
+            else
+              inserttypeconv(left,s64inttype);
+            firstpass(left);
+          end;
+        result := nil;
+        expectloc:=LOC_FPUREGISTER;
+      end;
+
+
+    {*****************************************************************************
+                                 SecondTypeConv
+    *****************************************************************************}
+
+
+    procedure tloongarch64typeconvnode.second_int_to_real;
+      var
+        op, movop: TAsmOp;
+        restype: tfloattype;
+        hreg: tregister;
+      begin
+        location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
+        restype:=tfloatdef(resultdef).floattype;
+        location.Register := cg.getfpuregister(current_asmdata.CurrAsmList, tfloat2tcgsize[restype]);
+
+        if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
+          hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, true);
+        case left.location.size of
+          OS_32,OS_64: internalerror(2022111928);
+          OS_S32:
+            begin
+              if restype=s32real then
+                op:=A_FFINT_S_W
+              else if restype=s64real then
+                op:=A_FFINT_D_W
+              else
+                internalerror(2022111929);
+              hreg:=cg.getfpuregister(current_asmdata.CurrAsmList, OS_F32);
+              movop:=A_MOVGR2FR_W;
+            end;
+          OS_S64:
+            begin
+              if restype=s32real then
+                op:=A_FFINT_S_L
+              else if restype=s64real then
+                op:=A_FFINT_D_L
+              else
+                internalerror(2022111930);
+              hreg:= cg.getfpuregister(current_asmdata.CurrAsmList, OS_F64);
+              movop:=A_MOVGR2FR_D;
+            end;
+        else
+          internalerror(2022111931);
+        end;
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(movop, hreg, left.location.register));
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, location.register, hreg));
+      end;
+
+
+    procedure tloongarch64typeconvnode.second_int_to_bool;
+      var
+        hreg1, hreg2: tregister;
+        opsize: tcgsize;
+        hlabel: tasmlabel;
+        newsize  : tcgsize;
+        href: treference;
+      begin
+        secondpass(left);
+        if codegenerror then
+          exit;
+
+        { Explicit typecasts from any ordinal type to a boolean type }
+        { must not change the ordinal value                          }
+        if (nf_explicit in flags) and
+           not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) then
+          begin
+             location_copy(location,left.location);
+             newsize:=def_cgsize(resultdef);
+             { change of size? change sign only if location is LOC_(C)REGISTER? Then we have to sign/zero-extend }
+             if (tcgsize2size[newsize]<>tcgsize2size[left.location.size]) or
+                ((newsize<>left.location.size) and (location.loc in [LOC_REGISTER,LOC_CREGISTER])) then
+               hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
+             else
+               location.size:=newsize;
+             exit;
+          end;
+
+        location_reset(location, LOC_REGISTER, def_cgsize(resultdef));
+        opsize := def_cgsize(left.resultdef);
+
+        if (left.location.loc in [LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF]) then
+          hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
+
+        case left.location.loc of
+          LOC_CREFERENCE, LOC_REFERENCE, LOC_REGISTER, LOC_CREGISTER:
+            begin
+              if left.location.loc in [LOC_CREFERENCE, LOC_REFERENCE] then
+                begin
+                  hreg2 := cg.getintregister(current_asmdata.CurrAsmList, opsize);
+                  cg.a_load_ref_reg(current_asmdata.CurrAsmList, opsize, opsize, left.location.reference, hreg2);
+                end
+              else
+                begin
+                  hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+                  cg.a_load_reg_reg(current_asmdata.CurrAsmList,opsize,opsize,left.location.register,hreg2);
+                end;
+              hreg1 := cg.getintregister(current_asmdata.CurrAsmList, opsize);
+              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, hreg1, NR_R0, hreg2));
+            end;
+          LOC_JUMP:
+            begin
+              hreg1 := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
+              current_asmdata.getjumplabel(hlabel);
+              cg.a_label(current_asmdata.CurrAsmList, left.location.truelabel);
+              cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 1, hreg1);
+              cg.a_jmp_always(current_asmdata.CurrAsmList, hlabel);
+              cg.a_label(current_asmdata.CurrAsmList, left.location.falselabel);
+              cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, hreg1);
+              cg.a_label(current_asmdata.CurrAsmList, hlabel);
+            end;
+          LOC_FLAGS:
+            Internalerror(2022111932);
+          else
+            internalerror(2022111933);
+        end;
+        { Now hreg1 is either 0 or 1. For C booleans it must be 0 or -1. }
+        if is_cbool(resultdef) then
+          cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,OS_SINT,hreg1,hreg1);
+
+        location.Register := hreg1;
+      end;
+
+
+begin
+  ctypeconvnode := tloongarch64typeconvnode;
+end.

+ 203 - 0
compiler/loongarch64/ncpuinl.pas

@@ -0,0 +1,203 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate LoongArch64 inline nodes
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit ncpuinl;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       cpubase,
+       node,ninl,ncginl;
+
+    type
+
+       tloongarch64inlinenode = class(tcginlinenode)
+          { first pass override
+            so that the code generator will actually generate
+            these nodes.
+          }
+          function first_sqrt_real: tnode; override;
+          function first_abs_real: tnode; override;
+          function first_sqr_real: tnode; override;
+          function first_round_real: tnode; override;
+          function first_trunc_real: tnode; override;
+
+          procedure second_sqrt_real; override;
+          procedure second_abs_real; override;
+          procedure second_sqr_real; override;
+          procedure second_round_real; override;
+          procedure second_trunc_real; override;
+       protected
+          procedure load_fpu_location;
+       end;
+
+implementation
+
+    uses
+      ncal,
+      cutils,globals,verbose,globtype,
+      aasmtai,aasmdata,aasmcpu,
+      symconst,symdef,
+      defutil,
+      cgbase,pass_2,
+      cpuinfo,ncgutil,
+      hlcgobj,cgutils,cgobj,rgobj,tgobj;
+
+
+{*****************************************************************************
+                              tloongarch64inlinenode
+*****************************************************************************}
+
+     function tloongarch64inlinenode.first_sqrt_real : tnode;
+       begin
+         expectloc:=LOC_FPUREGISTER;
+         first_sqrt_real := nil;
+       end;
+
+
+     function tloongarch64inlinenode.first_abs_real : tnode;
+       begin
+         expectloc:=LOC_FPUREGISTER;
+         first_abs_real := nil;
+       end;
+
+
+     function tloongarch64inlinenode.first_sqr_real : tnode;
+       begin
+         expectloc:=LOC_FPUREGISTER;
+         first_sqr_real := nil;
+       end;
+
+
+     function tloongarch64inlinenode.first_round_real: tnode;
+       begin
+         expectloc:=LOC_FPUREGISTER;
+         first_round_real := nil;
+       end;
+
+
+     function tloongarch64inlinenode.first_trunc_real: tnode;
+       begin
+         expectloc:=LOC_FPUREGISTER;
+         first_trunc_real := nil;
+       end;
+
+
+     { load the FPU into the an fpu register }
+     procedure tloongarch64inlinenode.load_fpu_location;
+       begin
+         location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
+         secondpass(left);
+         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+         location.loc := LOC_FPUREGISTER;
+         location.register := cg.getfpuregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
+       end;
+
+
+     procedure tloongarch64inlinenode.second_sqrt_real;
+       var
+         op: TAsmOp;
+       begin
+         location.loc:=LOC_FPUREGISTER;
+         load_fpu_location;
+         if (left.location.size = OS_F32) then
+           op := A_FSQRT_S
+         else
+           op := A_FSQRT_D;
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register));
+         cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
+     procedure tloongarch64inlinenode.second_abs_real;
+       var
+         op: TAsmOp;
+       begin
+         location.loc:=LOC_FPUREGISTER;
+         load_fpu_location;
+         if (left.location.size = OS_F32) then
+           op := A_FABS_S
+         else
+           op := A_FABS_D;
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register));
+       end;
+
+
+     procedure tloongarch64inlinenode.second_sqr_real;
+       var
+         op: tasmop;
+       begin
+         location.loc:=LOC_FPUREGISTER;
+         load_fpu_location;
+         if (left.location.size = OS_F32) then
+           op := A_FMUL_S
+         else
+           op := A_FMUL_D;
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));
+         cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
+     procedure tloongarch64inlinenode.second_round_real;
+       var
+         op: TAsmOp;
+         hreg: tregister;
+       begin
+         secondpass(left);
+         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+         location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+         hreg:= cg.getfpuregister(current_asmdata.CurrAsmList, OS_F64);
+         if (left.location.size = OS_F32) then
+           op := A_FTINT_L_S
+         else
+           op := A_FTINT_L_D;
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,hreg,left.location.register));
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_MOVFR2GR_D,location.register,hreg));
+         cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
+     procedure tloongarch64inlinenode.second_trunc_real;
+       var
+         op,movop: TAsmOp;
+         hreg: tregister;
+       begin
+         secondpass(left);
+         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+         location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+         hreg:= cg.getfpuregister(current_asmdata.CurrAsmList, OS_F64);
+         if (left.location.size = OS_F32) then
+           op := A_FTINTRZ_L_S
+         else
+           op := A_FTINTRZ_L_D;
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,hreg,left.location.register));
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_MOVFR2GR_D,location.register,hreg));
+         cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
+begin
+   cinlinenode:=tloongarch64inlinenode;
+end.

+ 152 - 0
compiler/loongarch64/ncpumat.pas

@@ -0,0 +1,152 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate LoongArch64 assembler for math nodes
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit ncpumat;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      node,nmat, ncgmat,
+      cgbase;
+
+    type
+      tloongarch64moddivnode = class(tcgmoddivnode)
+        function use_moddiv64bitint_helper: boolean; override;
+        procedure emit_div_reg_reg(signed: boolean; denum, num: tregister); override;
+        procedure emit_mod_reg_reg(signed: boolean; denum, num: tregister); override;
+        function first_moddiv64bitint: tnode; override;
+      end;
+
+      tloongarch64shlshrnode = class(tcgshlshrnode)
+      end;
+
+      tloongarch64unaryminusnode = class(tcgunaryminusnode)
+      end;
+
+      tloongarch64notnode = class(tcgnotnode)
+        procedure second_boolean; override;
+      end;
+
+implementation
+
+    uses
+      nadd,ninl,ncal,ncnv,
+      globtype,systems,constexp,
+      cutils,verbose,globals,
+      cpuinfo,
+      symconst,symdef,
+      aasmbase,aasmcpu,aasmtai,aasmdata,
+      defutil,
+      cgutils,cgobj,hlcgobj,
+      pass_1,pass_2,htypechk,
+      ncon,procinfo,
+      cpubase,
+      ncgutil,cgcpu;
+
+    procedure tloongarch64notnode.second_boolean;
+      var
+        tlabel, flabel: tasmlabel;
+      begin
+        secondpass(left);
+        if not handle_locjump then
+          begin
+            case left.location.loc of
+              LOC_FLAGS :
+                begin
+                  Internalerror(2022111907);
+                end;
+              LOC_REGISTER, LOC_CREGISTER,
+              LOC_REFERENCE, LOC_CREFERENCE,
+              LOC_SUBSETREG, LOC_CSUBSETREG,
+              LOC_SUBSETREF, LOC_CSUBSETREF:
+                begin
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+                  location_reset(location,LOC_REGISTER,OS_INT);
+                  location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,s64inttype);
+
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTUI,location.register,left.location.register,1));
+               end;
+              else
+                internalerror(2022111906);
+            end;
+          end;
+      end;
+
+
+    function tloongarch64moddivnode.use_moddiv64bitint_helper: boolean;
+      begin
+        Result:=true;
+      end;
+
+
+    procedure tloongarch64moddivnode.emit_div_reg_reg(signed: boolean; denum, num: tregister);
+      var
+        op: TAsmOp;
+      begin
+        if signed then
+          op:=A_DIV_D
+        else
+          op:=A_DIV_DU;
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
+      end;
+
+
+    procedure tloongarch64moddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
+      var
+        op: TAsmOp;
+      begin
+        if signed then
+          op:=A_MOD_D
+        else
+          op:=A_MOD_DU;
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
+      end;
+
+
+    function tloongarch64moddivnode.first_moddiv64bitint: tnode;
+      begin
+        {We can handle all cases of constant division}
+        if not(cs_check_overflow in current_settings.localswitches) and
+           (right.nodetype=ordconstn) and
+           (nodetype=divn) then
+          result:=nil
+        else if (nodetype in [divn,modn]) then
+          result:=nil
+        else
+          result:=inherited;
+
+        { we may not change the result type here }
+        if assigned(result) and (torddef(result.resultdef).ordtype<>torddef(resultdef).ordtype) then
+          inserttypeconv(result,resultdef);
+      end;
+
+begin
+  cmoddivnode := tloongarch64moddivnode;
+  cshlshrnode := tloongarch64shlshrnode;
+  cunaryminusnode := tloongarch64unaryminusnode;
+  cnotnode := tloongarch64notnode;
+end.
+

+ 144 - 0
compiler/loongarch64/ncpuset.pas

@@ -0,0 +1,144 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl and Carl Eric Codere
+
+    Generate Risc-V32/64 assembler for in set/case nodes
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit ncpuset;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       node,nset,ncgset,cpubase,cgbase,cgobj,aasmbase,aasmtai,aasmdata,globtype;
+
+    type
+       tloongarch64casenode = class(tcgcasenode)
+         protected
+           procedure optimizevalues(var max_linear_list : int64; var max_dist : qword);override;
+           function  has_jumptable : boolean;override;
+           procedure genjumptable(hp : pcaselabel;min_,max_ : int64);override;
+       end;
+
+
+implementation
+
+    uses
+      systems,
+      verbose,globals,constexp,
+      symconst,symdef,defutil,
+      paramgr,
+      cpuinfo,
+      pass_2,cgcpu,
+      ncon,
+      tgobj,ncgutil,rgobj,aasmcpu,
+      procinfo,
+      cgutils;
+
+{*****************************************************************************
+                            TCGCASENODE
+*****************************************************************************}
+
+
+    procedure tloongarch64casenode.optimizevalues(var max_linear_list : int64; var max_dist : qword);
+      begin
+        max_linear_list := 3;
+      end;
+
+
+    function tloongarch64casenode.has_jumptable : boolean;
+      begin
+        has_jumptable:=true;
+      end;
+
+
+    procedure tloongarch64casenode.genjumptable(hp : pcaselabel;min_,max_ : int64);
+      var
+        table : tasmlabel;
+        last : TConstExprInt;
+        indexreg : tregister;
+        href : treference;
+
+        procedure genitem(list:TAsmList;t : pcaselabel);
+          var
+            i : TConstExprInt;
+          begin
+            if assigned(t^.less) then
+              genitem(list,t^.less);
+            { fill possible hole }
+            i:=last+1;
+            while i<=t^._low-1 do
+              begin
+                list.concat(Tai_const.Create_sym_offset(elselabel,0));
+                i:=i+1;
+              end;
+            i:=t^._low;
+            while i<=t^._high do
+              begin
+                list.concat(Tai_const.Create_sym_offset(blocklabel(t^.blockid),0));
+                i:=i+1;
+              end;
+            last:=t^._high;
+            if assigned(t^.greater) then
+              genitem(list,t^.greater);
+          end;
+
+      begin
+        last:=min_;
+
+        {
+          la.pcrel x,tbl
+          alsl.d y,idx,x,3
+          ld.d z,y,0
+          jr z
+        }
+
+        indexreg:= cg.makeregsize(current_asmdata.CurrAsmList, hregister, OS_INT);
+        { indexreg := hregister; }
+        cg.a_load_reg_reg(current_asmdata.CurrAsmList, def_cgsize(opsize), OS_INT, hregister, indexreg);
+        { a <= x <= b <-> unsigned(x-a) <= (b-a) }
+        cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,aint(min_),indexreg);
+        if not(jumptable_no_range) then
+          cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_A,aint(max_)-aint(min_),indexreg,elselabel);
+        current_asmdata.getjumplabel(table);
+        hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
+        { la.pcrel x,tbl }
+        reference_reset_symbol(href, table, 0, 4,[]);
+        href.refaddr:=addr_pcrel;
+        cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
+        { alsl.d y,idx,x,3 }
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_const(A_ALSL_D,hregister,indexreg,hregister,3));
+        { ld.d z,y,0 }
+        reference_reset_base(href,hregister,0,ctempposinvalid,4,[]);
+        cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,hregister);
+        { jr z }
+        reference_reset_base(href,hregister,0,ctempposinvalid,4,[]);
+        href.refaddr:=addr_reg;
+        current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_JR,href));
+
+        { generate jump table }
+        current_asmdata.CurrAsmList.concat(cai_align.Create(8));
+        current_asmdata.CurrAsmList.concat(Tai_label.Create(table));
+        genitem(current_asmdata.CurrAsmList,hp);
+      end;
+
+
+begin
+   ccasenode:=tloongarch64casenode;
+end.

+ 48 - 0
compiler/loongarch64/racpu.pas

@@ -0,0 +1,48 @@
+{
+    Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman
+
+    Handles the common LoongArch64 assembler reader routines
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit racpu;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+  aasmbase, aasmtai,aasmdata, aasmcpu,
+  cpubase, rautils, cclasses;
+
+type
+  TLoongArch64Operand = class(TOperand)
+  end;
+
+  TLoongArch64Instruction = class(TInstruction)
+    function ConcatInstruction(p: TAsmList): tai; override;
+  end;
+
+implementation
+
+  function TLoongArch64Instruction.ConcatInstruction(p: TAsmList): tai;
+    begin
+      Result:=inherited ConcatInstruction(p);
+    end;
+
+end.
+

+ 811 - 0
compiler/loongarch64/racpugas.pas

@@ -0,0 +1,811 @@
+{
+    Copyright (c) 2019 by Jeppe Johansen
+
+    Does the parsing for the LoongArch64 GNU AS styled inline assembler.
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit racpugas;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      globtype,
+      raatt,racpu,
+      cpubase;
+
+    const
+      NRCalMax=64;
+
+    type
+      TArithOpers = (LLOR,LLAND,LINOR,LEXOR,LAND,LEQU,LUNE,LSLT,
+        LBGT,LSLE,LBGE,LSL,LSR,LADD,LSUB,LMUL,LMOD,LDIV);
+      TArithTreeType = (ATT_NUM,ATT_OP);
+      TArithTree = record
+        left : integer;
+        right : integer;
+        case typ:TArithTreeType of
+          ATT_NUM : (num : tcgint);
+          ATT_OP : (op : TArithOpers);
+      end;
+      TArrCals = array[1..NRCalMax] of TArithTree;
+      TArrNums = array[1..(NRCalMax shr 1)] of tcgint;
+      TArrAOps = array[1..(NRCalMax shr 1)] of TArithOpers;
+
+      tloongarch64gasreader = class(tattreader)
+        function is_register(const s: string):boolean;override;
+        function is_asmopcode(const s: string):boolean;override;
+        procedure handledollar;override;
+        procedure handleopcode;override;
+        procedure BuildOperand(oper : tloongarch64operand);
+        procedure BuildOpCode(instr : tloongarch64instruction);
+        function CalculateExprs(nr,first : tcgint; var nums : TArrNums; var ops : TArrAOps): tcgint;
+        function BuildConstLA(from_question,cond : boolean): tcgint;
+        function BuildSymLA(oper : tloongarch64operand; maybeconst: boolean): boolean;
+      end;
+
+  implementation
+
+    uses
+      { helpers }
+      cutils,
+      { global }
+      globals,verbose,
+      systems,
+      { aasm }
+      aasmbase,aasmtai,aasmdata,aasmcpu,
+      { symtable }
+      symconst,symsym,symdef,
+      { parser }
+      scanner,
+      procinfo,
+      rabase,rautils,
+      cgbase,cgobj
+      ;
+
+
+    procedure tloongarch64gasreader.BuildOperand(oper: tloongarch64operand);
+      var
+        expr : string;
+        typesize,l : TCGInt;
+        tempreg : tregister;
+        hl : tasmlabel;
+        ofs : aint;
+        refaddr: trefaddr;
+        entered_paren: Boolean;
+      Begin
+        expr:='';
+        entered_paren:=false;
+        refaddr:=addr_no;
+        { Although assembler has diverse ways to decode parameters,
+          there are four normal ways to describe them.
+          1. Registers.
+          2. %addrtype(Symbol'addend'), addend means expression.
+          3. Symbol'addend'.
+          4. Else, expression. }
+        case actasmtoken of
+          AS_REGISTER:
+            begin
+              { save the type of register used. }
+              tempreg:=actasmregister;
+              Consume(AS_REGISTER);
+              if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
+                begin
+                  oper.opr.typ:=OPR_REGISTER;
+                  oper.opr.reg:=tempreg;
+                end
+              else
+                Message(asmr_e_syn_operand);
+            end;
+          AS_MOD:
+            begin
+              Consume(AS_MOD);
+              if actasmtoken<>AS_ID then
+                Message(asmr_e_syntax_error);
+              if lower(actasmpattern)='b16' then
+                refaddr:=addr_b16
+              else if lower(actasmpattern)='b21' then
+                refaddr:=addr_b21
+              else if lower(actasmpattern)='b26' then
+                refaddr:=addr_b26
+              else if lower(actasmpattern)='plt' then
+                refaddr:=addr_plt
+              else if lower(actasmpattern)='abs_hi20' then
+                refaddr:=addr_abs_hi20
+              else if lower(actasmpattern)='abs_lo12' then
+                refaddr:=addr_abs_lo12
+              else if lower(actasmpattern)='abs64_lo20' then
+                refaddr:=addr_abs64_lo20
+              else if lower(actasmpattern)='abs64_hi12' then
+                refaddr:=addr_abs64_hi12
+              else if lower(actasmpattern)='pc_hi20' then
+                refaddr:=addr_pc_hi20
+              else if lower(actasmpattern)='pc_lo12' then
+                refaddr:=addr_pc_lo12
+              else if lower(actasmpattern)='got_pc_hi20' then
+                refaddr:=addr_got_pc_hi20
+              else if lower(actasmpattern)='got_pc_lo12' then
+                refaddr:=addr_got_pc_lo12
+              else
+                Message(asmr_e_syntax_error);
+              Consume(AS_ID);
+              if actasmtoken<>AS_LPAREN then
+                Message(asmr_e_syntax_error);
+              Consume(AS_LPAREN);
+              BuildSymLA(oper,false);
+              if actasmtoken<>AS_RPAREN then
+                Message(asmr_e_syntax_error);
+              Consume(AS_RPAREN);
+            end;
+          AS_DOT, AS_ID:
+            begin
+              if actopcode=A_LA_GOT then
+                refaddr:=addr_pcrel
+              else if actopcode=A_LA_ABS then
+                refaddr:=addr_abs
+              else
+                refaddr:=addr_pcrel;
+              if not BuildSymLA(oper,actasmtoken=AS_ID) then
+                refaddr:=addr_no;
+            end;
+          AS_END,
+          AS_SEPARATOR,
+          AS_COMMA: ;
+        else
+          begin
+            oper.opr.typ:=OPR_CONSTANT;
+            oper.opr.val:=BuildConstLA(false,false);
+          end;
+        end; { end case }
+
+      if refaddr<>addr_no then
+        begin
+          { Indirectly use parameter can be local and sym is paravarsym. }
+          if oper.opr.typ=OPR_LOCAL then
+              exit;
+          if oper.opr.typ<>OPR_REFERENCE then
+            oper.InitRef;
+          oper.opr.ref.refaddr:=refaddr;
+        end
+      else if (oper.opr.typ=OPR_REFERENCE) and
+              (oper.opr.ref.refaddr=addr_no) and
+              assigned(oper.opr.ref.symbol) then
+        oper.opr.ref.refaddr:=addr_pcrel;
+
+      end;
+
+
+{*****************************************************************************
+                                tloongarch64gasreader
+*****************************************************************************}
+
+    procedure tloongarch64gasreader.BuildOpCode(instr : tloongarch64instruction);
+      var
+        operandnum : longint;
+      begin
+        { opcode }
+        if (actasmtoken<>AS_OPCODE) then
+         begin
+           Message(asmr_e_invalid_or_missing_opcode);
+           RecoverConsume(true);
+           exit;
+         end;
+        { Fill the instr object with the current state }
+        with instr do
+          begin
+            Opcode:=ActOpcode;
+            condition:=ActCondition;
+          end;
+
+        { We are reading operands, so opcode will be an AS_ID }
+        operandnum:=1;
+        Consume(AS_OPCODE);
+        { Zero operand opcode ?  }
+        if actasmtoken in [AS_SEPARATOR,AS_END] then
+         begin
+           operandnum:=0;
+           exit;
+         end;
+        { Read the operands }
+        repeat
+          case actasmtoken of
+            AS_COMMA: { Operand delimiter }
+              begin
+                if operandnum>Max_Operands then
+                  Message(asmr_e_too_many_operands)
+                else
+                  begin
+                    { condition operands doesn't set the operand but write to the
+                      condition field of the instruction
+                    }
+                    if instr.Operands[operandnum].opr.typ<>OPR_NONE then
+                      Inc(operandnum);
+                  end;
+                Consume(AS_COMMA);
+              end;
+            AS_SEPARATOR,
+            AS_END : { End of asm operands for this opcode  }
+              begin
+                break;
+              end;
+          else
+            BuildOperand(instr.Operands[operandnum] as tloongarch64operand);
+          end; { end case }
+        until false;
+        if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
+          dec(operandnum);
+        instr.Ops:=operandnum;
+      end;
+
+
+    function tloongarch64gasreader.is_register(const s: string): boolean;
+      var
+        reg: TRegister;
+      begin
+        result:=inherited is_register(s);
+        { reg found? search it in abinames?  }
+        if not(result) then
+          begin
+            reg:=is_extra_reg(s);
+            if reg<>NR_NO then
+              begin
+                actasmregister:=reg;
+                result:=true;
+                actasmtoken:=AS_REGISTER;
+              end;
+          end;
+      end;
+
+
+    function tloongarch64gasreader.is_asmopcode(const s: string):boolean;
+      var
+        cond  : tasmcond;
+        hs, postfix : string;
+        l: longint;
+      begin
+        { making s a value parameter would break other assembler readers }
+        hs:=s;
+        is_asmopcode:=false;
+
+        { clear op code }
+        actopcode:=A_None;
+        { clear condition }
+        fillchar(actcondition,sizeof(actcondition),0);
+
+        { check for direction hint }
+        actopcode := tasmop(ptruint(iasmops.find(hs)));
+        if actopcode <> A_NONE then
+          begin
+            actasmtoken:=AS_OPCODE;
+            is_asmopcode:=true;
+            exit;
+          end;
+      end;
+
+
+    procedure tloongarch64gasreader.handledollar;
+      var
+        len: longint;
+      begin
+        len:=1;
+        actasmpattern[len]:='$';
+        c:=current_scanner.asmgetchar;
+        while c in ['A'..'Z','a'..'z','0'..'9'] do
+          begin
+            inc(len);
+            actasmpattern[len]:=c;
+            c:=current_scanner.asmgetchar;
+          end;
+        actasmpattern[0]:=chr(len);
+        actasmpattern:=lower(actasmpattern);
+        { TODO Something else. }
+        if not is_register(actasmpattern) then
+          internalerror(2022062915);
+      end;
+
+
+    procedure tloongarch64gasreader.handleopcode;
+      var
+        instr : tloongarch64instruction;
+      begin
+        instr:=tloongarch64instruction.create(tloongarch64operand);
+        BuildOpCode(instr);
+        { TODO insruction field }
+        instr.ConcatInstruction(curlist);
+        instr.Free;
+      end;
+
+
+    { In LoongArch binutils gas, the expression calculation is complex.
+      The priority is ternary is the lowest and the unary is the highest.
+      Ternary '?:', binary ordered by form low to high is '||', '&&',
+      '|', '^', '&', '==,!=', '<,<=,>,>=', '<<,>>', '+,-' and '*,/,%',
+      Unary is '+,-,~,!'. It is different form CalculateExpression, so
+      we should implement ourselves. Collect integers and binary,
+      calculate parentheses by recursing call, mark ternay and calculate
+      unary in time. }
+    function tloongarch64gasreader.CalculateExprs(nr,first : tcgint; var nums : TArrNums; var ops : TArrAOps): tcgint;
+
+      procedure alloc_num(var idx : integer; var arr : TArrCals; num : int64);
+        begin
+          idx:=idx+1;
+          if idx>NRCalMax then
+            internalerror(2022081601);
+          arr[idx].typ:=ATT_NUM;
+          arr[idx].num:=num;
+        end;
+
+      procedure alloc_op(var idx : integer; var arr : TArrCals; op : TArithOpers);
+        begin
+          idx:=idx+1;
+          if idx>NRCalMax then
+            internalerror(2022081602);
+          arr[idx].typ:=ATT_OP;
+          arr[idx].op:=op;
+        end;
+
+      function priority_less(op1, op2 : TArithOpers): boolean;
+        begin
+          case op1 of
+            LMUL,LMOD,LDIV:
+              priority_less:=false;
+            LADD,LSUB:
+              priority_less:=op2 in [LMUL..LDIV];
+            LSL,LSR:
+              priority_less:=op2 in [LADD..LDIV];
+            LSLT,LBGT,LSLE,LBGE:
+              priority_less:=op2 in [LSL..LDIV];
+            LEQU,LUNE:
+              priority_less:=op2 in [LSLT..LDIV];
+            LAND:
+              priority_less:=op2 in [LEQU..LDIV];
+            LEXOR:
+              priority_less:=op2 in [LAND..LDIV];
+            LINOR:
+              priority_less:=op2 in [LEXOR..LDIV];
+            LLAND:
+              priority_less:=op2 in [LINOR..LDIV];
+            LLOR:
+              priority_less:=op2<>LLOR;
+          end;
+        end;
+
+      function get_where_insert(head,item : integer; var arr : TArrCals) : integer;
+        var
+          last,t : integer;
+        begin
+          last:=0;
+          t:=head;
+          while arr[t].typ=ATT_OP do
+            begin
+              if priority_less(arr[item].op,arr[t].op) then
+                break;
+              last:=t;
+              t:=arr[t].right;
+            end;
+          get_where_insert:=last;
+        end;
+
+      function arith_treecal(var arr : TArrCals; idx : integer): tcgint;
+        var
+          lv,rv : tcgint;
+        begin
+          if arr[idx].typ=ATT_NUM then
+            begin
+              result:=arr[idx].num;
+              exit;
+            end;
+          if (arr[idx].left=0) and (arr[idx].right=0) then
+            internalerror(2022081705);
+          lv:=arith_treecal(arr,arr[idx].left);
+          rv:=arith_treecal(arr,arr[idx].right);
+          case arr[idx].op of
+            LLOR: result:=tcgint((lv<>0) or (rv<>0));
+            LLAND: result:=tcgint((lv<>0) and (rv<>0));
+            LINOR: result:=lv or rv;
+            LEXOR: result:=lv xor rv;
+            LAND: result:=lv and rv;
+            LEQU: result:=tcgint(lv=rv);
+            LUNE: result:=tcgint(lv<>rv);
+            LSLT: result:=tcgint(lv<rv);
+            LBGT: result:=tcgint(lv>rv);
+            LSLE: result:=tcgint(lv<=rv);
+            LBGE: result:=tcgint(lv>=rv);
+            LSL: result:=lv<<rv;
+            LSR: result:=lv>>rv;
+            LADD: result:=lv+rv;
+            LSUB: result:=lv-rv;
+            LMUL: result:=lv*rv;
+            LMOD: result:=lv mod rv;
+            LDIV: result:=lv div rv;
+          end;
+        end;
+
+      procedure debug_treecal(var arr : TArrCals; idx : integer; first : boolean);
+        const
+          strops: Array[LLOR..LDIV] of string[3] =
+            ('||','&&','|','^','&','==','!=','<','>',
+             '<=','>=','<<','>>','+','-','*','%','/');
+        begin
+          if first then
+            writeln('[Debug] ');
+          if arr[idx].typ=ATT_NUM then
+            begin
+              write(arr[idx].num);
+              exit;
+            end;
+          if (arr[idx].left=0) and (arr[idx].right=0) then
+            writeln(#10,'[Debug Error]');
+          debug_treecal(arr,arr[idx].left,false);
+          if arr[idx].typ=ATT_OP then
+            write(strops[arr[idx].op]);
+          debug_treecal(arr,arr[idx].right,false);
+          if first then
+            writeln('=',arith_treecal(arr,idx));
+        end;
+
+      var
+        i,curidx,curhead,curright,cursym,insidx : integer;
+        exprs : TArrCals;
+      begin
+        if nr=0 then
+          internalerror(2022081704);
+        curidx:=0;
+        alloc_num(curidx,exprs,first);
+        curhead:=curidx;
+        cursym:=0;
+        for i := 1  to nr do
+          begin
+            alloc_op(curidx,exprs,ops[i]);
+            cursym:=curidx;
+            alloc_num(curidx,exprs,nums[i]);
+            curright:=curidx;
+            exprs[cursym].right:=curright;
+            insidx:=get_where_insert(curhead,cursym,exprs);
+            if insidx=0 then
+              begin
+                exprs[cursym].left:=curhead;
+                curhead:=cursym;
+              end
+            else
+              begin
+                exprs[cursym].left:=exprs[insidx].right;
+                exprs[insidx].right:=cursym;
+              end;
+          end;
+        { debug_treecal(exprs,curhead,true); }
+        result:=arith_treecal(exprs,curhead);
+      end;
+
+    function tloongarch64gasreader.BuildConstLA(from_question,cond : boolean): tcgint;
+
+      function get_a_int: tcgint;
+        var
+          l : tcgint;
+        begin
+          result:=0;
+          case actasmtoken of
+            AS_PLUS:
+              begin
+                Consume(AS_PLUS);
+                result:=get_a_int();
+              end;
+            AS_MINUS:
+              begin
+                Consume(AS_MINUS);
+                result:=-get_a_int();
+              end;
+            AS_NOT:
+              begin
+                Consume(AS_NOT);
+                result:=tcgint(get_a_int()=0);
+              end;
+            AS_NOR:
+              begin
+                Consume(AS_NOR);
+                result:=not get_a_int();
+              end;
+            AS_ID:
+              begin
+                if SearchIConstant(actasmpattern,l) then
+                  result:=l
+                else
+                  internalerror(2022081101);
+                Consume(AS_ID);
+              end;
+            AS_INTNUM:
+              begin
+                result:=CalculateExpression(actasmpattern);
+                Consume(AS_INTNUM);
+              end;
+            AS_LPAREN:
+              begin
+                Consume(AS_LPAREN);
+                l:=BuildConstLA(false,false);
+                if actasmtoken<>AS_RPAREN then
+                  Message(asmr_e_syntax_error);
+                Consume(AS_RPAREN);
+                result:=l;
+              end;
+          else
+            Message(asmr_e_syntax_error);
+          end;
+        end;
+
+      function get_a_op: TArithOpers;
+        begin
+          case actasmtoken of
+            AS_SHL:
+              begin
+                Consume(AS_SHL);
+                result:=LSL;
+              end;
+            AS_SHR:
+              begin
+                Consume(AS_SHR);
+                result:=LSR;
+              end;
+            AS_LT:
+              begin
+                Consume(AS_LT);
+                if actasmtoken=AS_EQUAL then
+                  begin
+                    Consume(AS_EQUAL);
+                    result:=LSLE;
+                  end
+                else
+                  result:=LSLT;
+              end;
+            AS_GT:
+              begin
+                Consume(AS_GT);
+                if actasmtoken=AS_EQUAL then
+                  begin
+                    Consume(AS_EQUAL);
+                    result:=LBGE;
+                  end
+                else
+                  result:=LBGT;
+              end;
+            AS_OR:
+              begin
+                Consume(AS_OR);
+                if actasmtoken=AS_OR then
+                  begin
+                    Consume(AS_OR);
+                    result:=LLOR;
+                  end
+                else
+                  result:=LINOR;
+              end;
+            AS_AND:
+              begin
+                Consume(AS_AND);
+                if actasmtoken=AS_AND then
+                  begin
+                    Consume(AS_AND);
+                    result:=LLAND;
+                  end
+                else
+                  result:=LAND;
+              end;
+            AS_EQUAL:
+              begin
+                Consume(AS_EQUAL);
+                if actasmtoken<>AS_EQUAL then
+                  internalerror(2022081701);
+                Consume(AS_EQUAL);
+                result:=LEQU;
+              end;
+            AS_NOT:
+              begin
+                Consume(AS_NOT);
+                if actasmtoken<>AS_EQUAL then
+                  internalerror(2022081702);
+                Consume(AS_EQUAL);
+                result:=LUNE;
+              end;
+            AS_XOR:
+              begin
+                Consume(AS_XOR);
+                result:=LEXOR;
+              end;
+            AS_PLUS:
+              begin
+                Consume(AS_PLUS);
+                result:=LADD;
+              end;
+            AS_MINUS:
+              begin
+                Consume(AS_MINUS);
+                result:=LSUB;
+              end;
+            AS_STAR:
+              begin
+                Consume(AS_STAR);
+                result:=LMUL;
+              end;
+            AS_MOD:
+              begin
+                Consume(AS_MOD);
+                result:=LMOD;
+              end;
+            AS_SLASH:
+              begin
+                Consume(AS_SLASH);
+                result:=LDIV;
+              end;
+          else
+            Message(asmr_e_syntax_error);
+          end;
+        end;
+
+      var
+        firstnum,nr,l,l2 : tcgint;
+        IntStack : TArrNums;
+        OpsStack : TArrAOps;
+        op_or_int: boolean;
+      begin
+        result:=0;
+        nr:=0;
+
+        firstnum:=get_a_int;
+        { Most of case will return as they only have an integer. }
+
+        repeat
+          case actasmtoken of
+            AS_END,AS_SEPARATOR,AS_COMMA,AS_RPAREN: break;
+            AS_LPAREN:
+              begin
+                Consume(AS_LPAREN);
+                l:=BuildConstLA(false,false);
+                if actasmtoken<>AS_RPAREN then
+                  Message(asmr_e_syntax_error);
+                Consume(AS_RPAREN);
+              end;
+            AS_QUESTION:
+              begin
+                Consume(AS_QUESTION);
+                if nr=0 then
+                  l:=firstnum
+                else
+                  l:=CalculateExprs(nr,firstnum,IntStack,OpsStack);
+                result:=BuildConstLA(true,l<>0);
+                exit;
+              end;
+            AS_COLON:
+              begin
+                if not from_question then
+                  Message(asmr_e_syntax_error);
+                Consume(AS_COLON);
+                if nr=0 then
+                  l:=firstnum
+                else
+                  l:=CalculateExprs(nr,firstnum,IntStack,OpsStack);
+                l2:=BuildConstLA(false,false);
+                if cond then
+                  result:=l
+                else
+                  result:=l2;
+                exit;
+              end;
+          else
+            begin
+              nr:=nr+1;
+              if nr>(NRCalMax shr 1) then
+                internalerror(2022081703);
+              OpsStack[nr]:=get_a_op;
+              IntStack[nr]:=get_a_int;
+            end;
+          end; { case actasmtoken }
+        until false;
+
+        if nr=0 then
+          result:=firstnum
+        else
+          result:=CalculateExprs(nr,firstnum,IntStack,OpsStack);
+      end;
+
+
+    function tloongarch64gasreader.BuildSymLA(oper : tloongarch64operand; maybeconst : boolean): boolean;
+      var
+        hl : tasmlabel;
+        value : tcgint;
+        toffset, tsize: tcgint;
+        expr,mangledname: string;
+      begin
+        result:=True;
+        if (is_locallabel(actasmpattern)) then
+          begin
+            CreateLocalLabel(actasmpattern,hl,false);
+            Consume(AS_ID);
+            oper.InitRef;
+            oper.opr.ref.symbol:=hl;
+          end
+        else if SearchLabel(actasmpattern,hl,false) then
+          begin
+            Consume(AS_ID);
+            oper.InitRef;
+            oper.opr.ref.symbol:=hl;
+          end
+        else if maybeconst then
+          begin
+            if not SearchIConstant(actasmpattern,value) then
+              begin
+                expr:=actasmpattern;
+                Consume(AS_ID);
+                if actasmtoken = AS_DOT then
+                  begin
+                    mangledname:='';
+                    BuildRecordOffsetSize(expr, toffset, tsize, mangledname, false);
+                    if mangledname <> '' then
+                      Message(asmr_e_wrong_sym_type);
+                    oper.opr.typ:=OPR_CONSTANT;
+                    oper.opr.val:=toffset;
+                    Result:=False;
+                  end
+                else
+                  begin
+                    oper.InitRef;
+                    oper.SetupVar(expr,false);
+                  end;
+              end;
+          end
+        else if actasmtoken=AS_ID then
+          begin
+            oper.InitRef;
+            oper.SetupVar(actasmpattern,false);
+            Consume(AS_ID);
+          end
+        else
+          begin
+            Message(asmr_e_syntax_error);
+            internalerror(2022082501);
+          end;
+
+        if actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA,AS_RPAREN] then
+          exit;
+
+        value:=BuildConstLA(false,false);
+        if assigned(oper.opr.ref.symbol) then
+          oper.opr.ref.offset:=value
+        else
+          begin
+            oper.opr.typ:=OPR_CONSTANT;
+            oper.opr.val:=value;
+            Result:=False;
+          end;
+      end;
+
+
+{*****************************************************************************
+                                     Initialize
+*****************************************************************************}
+
+    const
+      asmmode_loongarch64_standard_info : tasmmodeinfo =
+              (
+                id    : asmmode_standard;
+                idtxt : 'STANDARD';
+                casmreader : tloongarch64gasreader;
+              );
+
+initialization
+  RegisterAsmMode(asmmode_loongarch64_standard_info);
+end.

+ 114 - 0
compiler/loongarch64/rgcpu.pas

@@ -0,0 +1,114 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the LoongArch64 specific class for the register
+    allocator
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit rgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+     uses
+       aasmbase,aasmtai,aasmdata,aasmcpu,
+       cgbase,cgutils,
+       cpubase,
+       rgobj;
+
+     type
+       trgcpu = class(trgobj)
+         procedure do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
+         procedure do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
+       end;
+
+       trgintcpu = class(trgcpu)
+       end;
+
+  implementation
+
+    uses
+      verbose, cutils,globtype,
+      cgobj,
+      procinfo;
+
+
+    procedure trgcpu.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
+      var
+        tmpref : treference;
+        helplist : TAsmList;
+        hreg : tregister;
+        helpins: Taicpu;
+      begin
+        if not is_simm12(spilltemp.offset) then
+          begin
+            helplist:=tasmlist.create;
+
+            if getregtype(tempreg)=R_INTREGISTER then
+              hreg:=tempreg
+            else
+              hreg:=cg.getintregister(helplist,OS_ADDR);
+
+            helplist.concat(taicpu.op_reg_const(A_LI_D,hreg,spilltemp.offset));
+            helplist.concat(taicpu.op_reg_reg_reg(A_ADD_D,hreg,hreg,spilltemp.base));
+
+            reference_reset_base(tmpref,hreg,0,ctempposinvalid,sizeof(aint),[]);
+            helpins:=spilling_create_load(tmpref,tempreg);
+            helplist.concat(helpins);
+            list.insertlistafter(pos,helplist);
+            helplist.free;
+          end
+        else
+          inherited;
+      end;
+
+
+    procedure trgcpu.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
+      var
+        tmpref   : treference;
+        helplist : tasmlist;
+        hreg     : tregister;
+      begin
+        if not is_simm12(spilltemp.offset) then
+          begin
+            helplist:=tasmlist.create;
+
+            if getregtype(tempreg)=R_INTREGISTER then
+              hreg:=getregisterinline(helplist,[R_SUBWHOLE])
+            else
+              hreg:=cg.getintregister(helplist,OS_ADDR);
+
+            helplist.concat(taicpu.op_reg_const(A_LI_D,hreg,spilltemp.offset));
+            helplist.concat(taicpu.op_reg_reg_reg(A_ADD_D,hreg,hreg,spilltemp.base));
+
+            reference_reset_base(tmpref,hreg,0,ctempposinvalid,sizeof(aint),[]);
+            helplist.concat(spilling_create_store(tempreg,tmpref));
+            if getregtype(tempreg)=R_INTREGISTER then
+              ungetregisterinline(helplist,hreg);
+
+            list.insertlistafter(pos,helplist);
+            helplist.free;
+          end
+        else
+          inherited;
+      end;
+
+
+end.

+ 74 - 0
compiler/loongarch64/rloongarch64abi.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+'INVALID',
+'$zero',
+'$ra',
+'$tp',
+'$sp',
+'$a0',
+'$a1',
+'$a2',
+'$a3',
+'$a4',
+'$a5',
+'$a6',
+'$a7',
+'$t0',
+'$t1',
+'$t2',
+'$t3',
+'$t4',
+'$t5',
+'$t6',
+'$t7',
+'$t8',
+'$x',
+'$fp',
+'$s0',
+'$s1',
+'$s2',
+'$s3',
+'$s4',
+'$s5',
+'$s6',
+'$s7',
+'$s8',
+'$fa0',
+'$fa1',
+'$fa2',
+'$fa3',
+'$fa4',
+'$fa5',
+'$fa6',
+'$fa7',
+'$ft0',
+'$ft1',
+'$ft2',
+'$ft3',
+'$ft4',
+'$ft5',
+'$ft6',
+'$ft7',
+'$ft8',
+'$ft9',
+'$ft10',
+'$ft11',
+'$ft12',
+'$ft13',
+'$ft14',
+'$ft15',
+'$fs0',
+'$fs1',
+'$fs2',
+'$fs3',
+'$fs4',
+'$fs5',
+'$fs6',
+'$fs7',
+'$fcc0',
+'$fcc1',
+'$fcc2',
+'$fcc3',
+'$fcc4',
+'$fcc5',
+'$fcc6',
+'$fcc7'

+ 74 - 0
compiler/loongarch64/rloongarch64con.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+NR_NO = tregister(0);
+NR_R0 = tregister(16777216);
+NR_R1 = tregister(16777217);
+NR_R2 = tregister(16777218);
+NR_R3 = tregister(16777219);
+NR_R4 = tregister(16777220);
+NR_R5 = tregister(16777221);
+NR_R6 = tregister(16777222);
+NR_R7 = tregister(16777223);
+NR_R8 = tregister(16777224);
+NR_R9 = tregister(16777225);
+NR_R10 = tregister(16777226);
+NR_R11 = tregister(16777227);
+NR_R12 = tregister(16777228);
+NR_R13 = tregister(16777229);
+NR_R14 = tregister(16777230);
+NR_R15 = tregister(16777231);
+NR_R16 = tregister(16777232);
+NR_R17 = tregister(16777233);
+NR_R18 = tregister(16777234);
+NR_R19 = tregister(16777235);
+NR_R20 = tregister(16777236);
+NR_R21 = tregister(16777237);
+NR_R22 = tregister(16777238);
+NR_R23 = tregister(16777239);
+NR_R24 = tregister(16777240);
+NR_R25 = tregister(16777241);
+NR_R26 = tregister(16777242);
+NR_R27 = tregister(16777243);
+NR_R28 = tregister(16777244);
+NR_R29 = tregister(16777245);
+NR_R30 = tregister(16777246);
+NR_R31 = tregister(16777247);
+NR_F0 = tregister(33554432);
+NR_F1 = tregister(33554433);
+NR_F2 = tregister(33554434);
+NR_F3 = tregister(33554435);
+NR_F4 = tregister(33554436);
+NR_F5 = tregister(33554437);
+NR_F6 = tregister(33554438);
+NR_F7 = tregister(33554439);
+NR_F8 = tregister(33554440);
+NR_F9 = tregister(33554441);
+NR_F10 = tregister(33554442);
+NR_F11 = tregister(33554443);
+NR_F12 = tregister(33554444);
+NR_F13 = tregister(33554445);
+NR_F14 = tregister(33554446);
+NR_F15 = tregister(33554447);
+NR_F16 = tregister(33554448);
+NR_F17 = tregister(33554449);
+NR_F18 = tregister(33554450);
+NR_F19 = tregister(33554451);
+NR_F20 = tregister(33554452);
+NR_F21 = tregister(33554453);
+NR_F22 = tregister(33554454);
+NR_F23 = tregister(33554455);
+NR_F24 = tregister(33554456);
+NR_F25 = tregister(33554457);
+NR_F26 = tregister(33554458);
+NR_F27 = tregister(33554459);
+NR_F28 = tregister(33554460);
+NR_F29 = tregister(33554461);
+NR_F30 = tregister(33554462);
+NR_F31 = tregister(33554463);
+NR_FCC0 = tregister(83886080);
+NR_FCC1 = tregister(83886081);
+NR_FCC2 = tregister(83886082);
+NR_FCC3 = tregister(83886083);
+NR_FCC4 = tregister(83886084);
+NR_FCC5 = tregister(83886085);
+NR_FCC6 = tregister(83886086);
+NR_FCC7 = tregister(83886087);

+ 74 - 0
compiler/loongarch64/rloongarch64dwa.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+63,
+64,
+65,
+66,
+67,
+68,
+69,
+70,
+71

+ 2 - 0
compiler/loongarch64/rloongarch64nor.inc

@@ -0,0 +1,2 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+73

+ 74 - 0
compiler/loongarch64/rloongarch64num.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+tregister(0),
+tregister(16777216),
+tregister(16777217),
+tregister(16777218),
+tregister(16777219),
+tregister(16777220),
+tregister(16777221),
+tregister(16777222),
+tregister(16777223),
+tregister(16777224),
+tregister(16777225),
+tregister(16777226),
+tregister(16777227),
+tregister(16777228),
+tregister(16777229),
+tregister(16777230),
+tregister(16777231),
+tregister(16777232),
+tregister(16777233),
+tregister(16777234),
+tregister(16777235),
+tregister(16777236),
+tregister(16777237),
+tregister(16777238),
+tregister(16777239),
+tregister(16777240),
+tregister(16777241),
+tregister(16777242),
+tregister(16777243),
+tregister(16777244),
+tregister(16777245),
+tregister(16777246),
+tregister(16777247),
+tregister(33554432),
+tregister(33554433),
+tregister(33554434),
+tregister(33554435),
+tregister(33554436),
+tregister(33554437),
+tregister(33554438),
+tregister(33554439),
+tregister(33554440),
+tregister(33554441),
+tregister(33554442),
+tregister(33554443),
+tregister(33554444),
+tregister(33554445),
+tregister(33554446),
+tregister(33554447),
+tregister(33554448),
+tregister(33554449),
+tregister(33554450),
+tregister(33554451),
+tregister(33554452),
+tregister(33554453),
+tregister(33554454),
+tregister(33554455),
+tregister(33554456),
+tregister(33554457),
+tregister(33554458),
+tregister(33554459),
+tregister(33554460),
+tregister(33554461),
+tregister(33554462),
+tregister(33554463),
+tregister(83886080),
+tregister(83886081),
+tregister(83886082),
+tregister(83886083),
+tregister(83886084),
+tregister(83886085),
+tregister(83886086),
+tregister(83886087)

+ 74 - 0
compiler/loongarch64/rloongarch64rni.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+63,
+64,
+65,
+66,
+67,
+68,
+69,
+70,
+71,
+72

+ 74 - 0
compiler/loongarch64/rloongarch64sri.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+33,
+34,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+35,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+36,
+63,
+64,
+37,
+38,
+39,
+40,
+41,
+42,
+65,
+66,
+67,
+68,
+69,
+70,
+71,
+72,
+1,
+2,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+3,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+4,
+31,
+32,
+5,
+6,
+7,
+8,
+9,
+10,
+0

+ 74 - 0
compiler/loongarch64/rloongarch64sta.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+63,
+64,
+65,
+66,
+67,
+68,
+69,
+70,
+71

+ 74 - 0
compiler/loongarch64/rloongarch64std.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+'INVALID',
+'$r0',
+'$r1',
+'$r2',
+'$r3',
+'$r4',
+'$r5',
+'$r6',
+'$r7',
+'$r8',
+'$r9',
+'$r10',
+'$r11',
+'$r12',
+'$r13',
+'$r14',
+'$r15',
+'$r16',
+'$r17',
+'$r18',
+'$r19',
+'$r20',
+'$r21',
+'$r22',
+'$r23',
+'$r24',
+'$r25',
+'$r26',
+'$r27',
+'$r28',
+'$r29',
+'$r30',
+'$r31',
+'$f0',
+'$f1',
+'$f2',
+'$f3',
+'$f4',
+'$f5',
+'$f6',
+'$f7',
+'$f8',
+'$f9',
+'$f10',
+'$f11',
+'$f12',
+'$f13',
+'$f14',
+'$f15',
+'$f16',
+'$f17',
+'$f18',
+'$f19',
+'$f20',
+'$f21',
+'$f22',
+'$f23',
+'$f24',
+'$f25',
+'$f26',
+'$f27',
+'$f28',
+'$f29',
+'$f30',
+'$f31',
+'$fcc0',
+'$fcc1',
+'$fcc2',
+'$fcc3',
+'$fcc4',
+'$fcc5',
+'$fcc6',
+'$fcc7'

+ 74 - 0
compiler/loongarch64/rloongarch64sup.inc

@@ -0,0 +1,74 @@
+{ don't edit, this file is generated from loongarchreg.dat }
+RS_NO = 0;
+RS_R0 = 0;
+RS_R1 = 1;
+RS_R2 = 2;
+RS_R3 = 3;
+RS_R4 = 4;
+RS_R5 = 5;
+RS_R6 = 6;
+RS_R7 = 7;
+RS_R8 = 8;
+RS_R9 = 9;
+RS_R10 = 10;
+RS_R11 = 11;
+RS_R12 = 12;
+RS_R13 = 13;
+RS_R14 = 14;
+RS_R15 = 15;
+RS_R16 = 16;
+RS_R17 = 17;
+RS_R18 = 18;
+RS_R19 = 19;
+RS_R20 = 20;
+RS_R21 = 21;
+RS_R22 = 22;
+RS_R23 = 23;
+RS_R24 = 24;
+RS_R25 = 25;
+RS_R26 = 26;
+RS_R27 = 27;
+RS_R28 = 28;
+RS_R29 = 29;
+RS_R30 = 30;
+RS_R31 = 31;
+RS_F0 = 0;
+RS_F1 = 1;
+RS_F2 = 2;
+RS_F3 = 3;
+RS_F4 = 4;
+RS_F5 = 5;
+RS_F6 = 6;
+RS_F7 = 7;
+RS_F8 = 8;
+RS_F9 = 9;
+RS_F10 = 10;
+RS_F11 = 11;
+RS_F12 = 12;
+RS_F13 = 13;
+RS_F14 = 14;
+RS_F15 = 15;
+RS_F16 = 16;
+RS_F17 = 17;
+RS_F18 = 18;
+RS_F19 = 19;
+RS_F20 = 20;
+RS_F21 = 21;
+RS_F22 = 22;
+RS_F23 = 23;
+RS_F24 = 24;
+RS_F25 = 25;
+RS_F26 = 26;
+RS_F27 = 27;
+RS_F28 = 28;
+RS_F29 = 29;
+RS_F30 = 30;
+RS_F31 = 31;
+RS_FCC0 = 0;
+RS_FCC1 = 1;
+RS_FCC2 = 2;
+RS_FCC3 = 3;
+RS_FCC4 = 4;
+RS_FCC5 = 5;
+RS_FCC6 = 6;
+RS_FCC7 = 7;

+ 220 - 0
compiler/loongarch64/symcpu.pas

@@ -0,0 +1,220 @@
+{
+    Copyright (c) 2014 by Florian Klaempfl
+
+    Symbol table overrides for LoongArch64
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit symcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  symtype,symdef,symsym;
+
+type
+  { defs }
+  tcpufiledef = class(tfiledef)
+  end;
+  tcpufiledefclass = class of tcpufiledef;
+
+  tcpuvariantdef = class(tvariantdef)
+  end;
+  tcpuvariantdefclass = class of tcpuvariantdef;
+
+  tcpuformaldef = class(tformaldef)
+  end;
+  tcpuformaldefclass = class of tcpuformaldef;
+
+  tcpuforwarddef = class(tforwarddef)
+  end;
+  tcpuforwarddefclass = class of tcpuforwarddef;
+
+  tcpuundefineddef = class(tundefineddef)
+  end;
+  tcpuundefineddefclass = class of tcpuundefineddef;
+
+  tcpuerrordef = class(terrordef)
+  end;
+  tcpuerrordefclass = class of tcpuerrordef;
+
+  tcpupointerdef = class(tpointerdef)
+  end;
+  tcpupointerdefclass = class of tcpupointerdef;
+
+  tcpurecorddef = class(trecorddef)
+  end;
+  tcpurecorddefclass = class of tcpurecorddef;
+
+  tcpuimplementedinterface = class(timplementedinterface)
+  end;
+  tcpuimplementedinterfaceclass = class of tcpuimplementedinterface;
+
+  tcpuobjectdef = class(tobjectdef)
+  end;
+  tcpuobjectdefclass = class of tcpuobjectdef;
+
+  tcpuclassrefdef = class(tclassrefdef)
+  end;
+  tcpuclassrefdefclass = class of tcpuclassrefdef;
+
+  tcpuarraydef = class(tarraydef)
+  end;
+  tcpuarraydefclass = class of tcpuarraydef;
+
+  tcpuorddef = class(torddef)
+  end;
+  tcpuorddefclass = class of tcpuorddef;
+
+  tcpufloatdef = class(tfloatdef)
+  end;
+  tcpufloatdefclass = class of tcpufloatdef;
+
+  tcpuprocvardef = class(tprocvardef)
+  end;
+  tcpuprocvardefclass = class of tcpuprocvardef;
+
+  tcpuprocdef = class(tprocdef)
+  end;
+  tcpuprocdefclass = class of tcpuprocdef;
+
+  tcpustringdef = class(tstringdef)
+  end;
+  tcpustringdefclass = class of tcpustringdef;
+
+  tcpuenumdef = class(tenumdef)
+  end;
+  tcpuenumdefclass = class of tcpuenumdef;
+
+  tcpusetdef = class(tsetdef)
+  end;
+  tcpusetdefclass = class of tcpusetdef;
+
+  { syms }
+  tcpulabelsym = class(tlabelsym)
+  end;
+  tcpulabelsymclass = class of tcpulabelsym;
+
+  tcpuunitsym = class(tunitsym)
+  end;
+  tcpuunitsymclass = class of tcpuunitsym;
+
+  tcpuprogramparasym = class(tprogramparasym)
+  end;
+  tcpuprogramparasymclass = class(tprogramparasym);
+
+  tcpunamespacesym = class(tnamespacesym)
+  end;
+  tcpunamespacesymclass = class of tcpunamespacesym;
+
+  tcpuprocsym = class(tprocsym)
+  end;
+  tcpuprocsymclass = class of tcpuprocsym;
+
+  tcputypesym = class(ttypesym)
+  end;
+  tcpuypesymclass = class of tcputypesym;
+
+  tcpufieldvarsym = class(tfieldvarsym)
+  end;
+  tcpufieldvarsymclass = class of tcpufieldvarsym;
+
+  tcpulocalvarsym = class(tlocalvarsym)
+  end;
+  tcpulocalvarsymclass = class of tcpulocalvarsym;
+
+  tcpuparavarsym = class(tparavarsym)
+  end;
+  tcpuparavarsymclass = class of tcpuparavarsym;
+
+  tcpustaticvarsym = class(tstaticvarsym)
+  end;
+  tcpustaticvarsymclass = class of tcpustaticvarsym;
+
+  tcpuabsolutevarsym = class(tabsolutevarsym)
+  end;
+  tcpuabsolutevarsymclass = class of tcpuabsolutevarsym;
+
+  tcpupropertysym = class(tpropertysym)
+  end;
+  tcpupropertysymclass = class of tcpupropertysym;
+
+  tcpuconstsym = class(tconstsym)
+  end;
+  tcpuconstsymclass = class of tcpuconstsym;
+
+  tcpuenumsym = class(tenumsym)
+  end;
+  tcpuenumsymclass = class of tcpuenumsym;
+
+  tcpusyssym = class(tsyssym)
+  end;
+  tcpusyssymclass = class of tcpusyssym;
+
+
+const
+  pbestrealtype : ^tdef = @s64floattype;
+
+
+implementation
+
+  uses
+    symconst, defutil, defcmp;
+
+
+begin
+  { used tdef classes }
+  cfiledef:=tcpufiledef;
+  cvariantdef:=tcpuvariantdef;
+  cformaldef:=tcpuformaldef;
+  cforwarddef:=tcpuforwarddef;
+  cundefineddef:=tcpuundefineddef;
+  cerrordef:=tcpuerrordef;
+  cpointerdef:=tcpupointerdef;
+  crecorddef:=tcpurecorddef;
+  cimplementedinterface:=tcpuimplementedinterface;
+  cobjectdef:=tcpuobjectdef;
+  cclassrefdef:=tcpuclassrefdef;
+  carraydef:=tcpuarraydef;
+  corddef:=tcpuorddef;
+  cfloatdef:=tcpufloatdef;
+  cprocvardef:=tcpuprocvardef;
+  cprocdef:=tcpuprocdef;
+  cstringdef:=tcpustringdef;
+  cenumdef:=tcpuenumdef;
+  csetdef:=tcpusetdef;
+
+  { used tsym classes }
+  clabelsym:=tcpulabelsym;
+  cunitsym:=tcpuunitsym;
+  cprogramparasym:=tcpuprogramparasym;
+  cnamespacesym:=tcpunamespacesym;
+  cprocsym:=tcpuprocsym;
+  ctypesym:=tcputypesym;
+  cfieldvarsym:=tcpufieldvarsym;
+  clocalvarsym:=tcpulocalvarsym;
+  cparavarsym:=tcpuparavarsym;
+  cstaticvarsym:=tcpustaticvarsym;
+  cabsolutevarsym:=tcpuabsolutevarsym;
+  cpropertysym:=tcpupropertysym;
+  cconstsym:=tcpuconstsym;
+  cenumsym:=tcpuenumsym;
+  csyssym:=tcpusyssym;
+end.
+

+ 45 - 0
compiler/loongarch64/tripletcpu.pas

@@ -0,0 +1,45 @@
+{
+    Copyright (c) 2020 by Jonas Maebe
+
+    Construct the cpu part of the triplet
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit tripletcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype;
+
+function tripletcpustr(tripletstyle: ttripletstyle): ansistring;
+
+implementation
+
+uses
+  globals, cpuinfo;
+
+function tripletcpustr(tripletstyle: ttripletstyle): ansistring;
+  begin
+    result:='loongarch';
+  end;
+
+
+end.
+

+ 4 - 0
compiler/ncgcnv.pas

@@ -677,7 +677,11 @@ interface
           the bits that define the true status can be outside the limits
           the bits that define the true status can be outside the limits
           of the new size and truncating the register can result in a 0
           of the new size and truncating the register can result in a 0
           value }
           value }
+{$ifndef loongarch64}
         if (left.expectloc in [LOC_FLAGS,LOC_JUMP]) and
         if (left.expectloc in [LOC_FLAGS,LOC_JUMP]) and
+{$else loongarch64}
+        if (left.expectloc=LOC_JUMP) and
+{$endif loongarch64}
            { a cbool must be converted to -1/0 }
            { a cbool must be converted to -1/0 }
            not is_cbool(resultdef) then
            not is_cbool(resultdef) then
           begin
           begin

+ 22 - 0
compiler/options.pas

@@ -981,6 +981,9 @@ begin
 {$endif}
 {$endif}
 {$ifdef wasm32}
 {$ifdef wasm32}
       'W',
       'W',
+{$endif}
+{$ifdef loongarch64}
+      'l',
 {$endif}
 {$endif}
       '*' : show:=true;
       '*' : show:=true;
      end;
      end;
@@ -4395,6 +4398,16 @@ procedure read_arguments(cmd:TCmdStr);
         def_system_macro('FPC_COMP_IS_INT64');
         def_system_macro('FPC_COMP_IS_INT64');
       {$endif wasm32}
       {$endif wasm32}
 
 
+      {$ifdef loongarch64}
+        def_system_macro('CPULOONGARCH');
+        def_system_macro('CPULOONGARCH64');
+        def_system_macro('CPU64');
+        def_system_macro('FPC_CURRENCY_IS_INT64');
+        def_system_macro('FPC_COMP_IS_INT64');
+        def_system_macro('FPC_REQUIRES_PROPER_ALIGNMENT');
+        def_system_macro('FPC_LOCALS_ARE_STACK_REG_RELATIVE');
+      {$endif loongarch64}
+
       {$if defined(cpu8bitalu)}
       {$if defined(cpu8bitalu)}
         def_system_macro('CPUINT8');
         def_system_macro('CPUINT8');
       {$elseif defined(cpu16bitalu)}
       {$elseif defined(cpu16bitalu)}
@@ -5182,6 +5195,15 @@ begin
     end;
     end;
 {$endif wasm}
 {$endif wasm}
 
 
+{$if defined(loongarch64)}
+  { LoongArch defaults }
+  if (target_info.abi = abi_riscv_hf) then
+    begin
+      init_settings.cputype:=cpu_3a;
+      init_settings.fputype:=fpu_fd;
+    end;
+{$endif defined(loongarch64)}
+
   { now we can define cpu and fpu type }
   { now we can define cpu and fpu type }
   def_cpu_macros;
   def_cpu_macros;
 
 

+ 7 - 0
compiler/pp.pas

@@ -45,6 +45,7 @@ program pp;
   X86_64              generate a compiler for the AMD x86-64 architecture
   X86_64              generate a compiler for the AMD x86-64 architecture
   XTENSA              generate a compiler for XTENSA
   XTENSA              generate a compiler for XTENSA
   Z80                 generate a compiler for Z80
   Z80                 generate a compiler for Z80
+  LOONGARCH64         generate a compiler for the LoongArch64 architecture
 
 
   -----------------------------------------------------------------
   -----------------------------------------------------------------
   Other compiler switches
   Other compiler switches
@@ -201,6 +202,12 @@ program pp;
   {$endif CPUDEFINED}
   {$endif CPUDEFINED}
   {$define CPUDEFINED}
   {$define CPUDEFINED}
 {$endif WASM32}
 {$endif WASM32}
+{$ifdef LOONGARCH64}
+  {$ifdef CPUDEFINED}
+    {$fatal ONLY one of the switches for the CPU type must be defined}
+  {$endif CPUDEFINED}
+  {$define CPUDEFINED}
+{$endif LOONGARCH64}
 
 
 {$ifndef CPUDEFINED}
 {$ifndef CPUDEFINED}
   {$fatal A CPU type switch must be defined}
   {$fatal A CPU type switch must be defined}

+ 4 - 0
compiler/psystem.pas

@@ -394,6 +394,10 @@ implementation
         create_fpu_types;
         create_fpu_types;
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
 {$endif xtensa}
 {$endif xtensa}
+{$ifdef loongarch64}
+        create_fpu_types;
+        s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
+{$endif loongarch64}
         set_default_int_types;
         set_default_int_types;
         { some other definitions }
         { some other definitions }
         charpointertype:=cpointerdef.create(cansichartype);
         charpointertype:=cpointerdef.create(cansichartype);

+ 46 - 5
compiler/raatt.pas

@@ -48,7 +48,7 @@ unit raatt;
         AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR,
         AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR,
         AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH,AS_DOLLAR,
         AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH,AS_DOLLAR,
         AS_HASH,AS_LSBRACKET,AS_RSBRACKET,AS_LBRACKET,AS_RBRACKET,
         AS_HASH,AS_LSBRACKET,AS_RSBRACKET,AS_LBRACKET,AS_RBRACKET,
-        AS_EQUAL,
+        AS_EQUAL,AS_QUESTION,AS_LT,AS_GT,
         {------------------ Assembler directives --------------------}
         {------------------ Assembler directives --------------------}
         AS_DB,AS_DW,AS_DD,AS_DQ,AS_GLOBAL,
         AS_DB,AS_DW,AS_DD,AS_DQ,AS_GLOBAL,
         AS_ALIGN,AS_BALIGN,AS_P2ALIGN,AS_ASCII,
         AS_ALIGN,AS_BALIGN,AS_P2ALIGN,AS_ASCII,
@@ -76,7 +76,7 @@ unit raatt;
         ')',':','.','+','-','*',
         ')',':','.','+','-','*',
         ';','identifier','register','opcode','/','$',
         ';','identifier','register','opcode','/','$',
         '#','{','}','[',']',
         '#','{','}','[',']',
-        '=',
+        '=','?','<','>',
         '.byte','.word','.long','.quad','.globl',
         '.byte','.word','.long','.quad','.globl',
         '.align','.balign','.p2align','.ascii',
         '.align','.balign','.p2align','.ascii',
         '.asciz','.lcomm','.comm','.single','.double','.tfloat','.tcfloat',
         '.asciz','.lcomm','.comm','.single','.double','.tfloat','.tcfloat',
@@ -363,6 +363,18 @@ unit raatt;
                end;
                end;
            end;
            end;
 {$endif xtensa}
 {$endif xtensa}
+{$ifdef loongarch64}
+           { LoongArch have multiple postfixes. So... }
+           case c of
+             '.' :
+               begin
+                 repeat
+                   actasmpattern:=actasmpattern+c;
+                   c:=current_scanner.asmgetchar;
+                 until not(c in ['a'..'z','A'..'Z', '0'..'9', '.']);
+               end;
+           end;
+{$endif loongarch64}
            { Opcode ? }
            { Opcode ? }
            If is_asmopcode(upper(actasmpattern)) then
            If is_asmopcode(upper(actasmpattern)) then
             Begin
             Begin
@@ -718,14 +730,23 @@ unit raatt;
                  exit;
                  exit;
                end;
                end;
 {$endif arm or aarch64}
 {$endif arm or aarch64}
-{$ifdef arm}
+{$if defined(arm) or defined(loongarch64)}
              '=' :
              '=' :
                begin
                begin
                  actasmtoken:=AS_EQUAL;
                  actasmtoken:=AS_EQUAL;
                  c:=current_scanner.asmgetchar;
                  c:=current_scanner.asmgetchar;
                  exit;
                  exit;
                end;
                end;
-{$endif arm}
+{$endif arm or loongarch64}
+
+{$ifdef loongarch64}
+             '?' :
+               begin
+                 actasmtoken:=AS_QUESTION;
+                 c:=current_scanner.asmgetchar;
+                 exit;
+               end;
+{$endif loongarch64}
 
 
              ',' :
              ',' :
                begin
                begin
@@ -736,19 +757,39 @@ unit raatt;
 
 
              '<' :
              '<' :
                begin
                begin
+{$if defined(loongarch64)}
+                 actasmtoken:=AS_LT;
+                 c:=current_scanner.asmgetchar;
+                 if c = '<' then
+                   begin
+                     actasmtoken:=AS_SHL;
+                     c:=current_scanner.asmgetchar;
+                   end;
+{$else}
                  actasmtoken:=AS_SHL;
                  actasmtoken:=AS_SHL;
                  c:=current_scanner.asmgetchar;
                  c:=current_scanner.asmgetchar;
                  if c = '<' then
                  if c = '<' then
                   c:=current_scanner.asmgetchar;
                   c:=current_scanner.asmgetchar;
+{$endif loongarch64}
                  exit;
                  exit;
                end;
                end;
 
 
              '>' :
              '>' :
                begin
                begin
-                 actasmtoken:=AS_SHL;
+{$if defined(loongarch64)}
+                 actasmtoken:=AS_GT;
+                 c:=current_scanner.asmgetchar;
+                 if c = '>' then
+                   begin
+                     actasmtoken:=AS_SHR;
+                     c:=current_scanner.asmgetchar;
+                   end;
+{$else}
+                 actasmtoken:=AS_SHR;
                  c:=current_scanner.asmgetchar;
                  c:=current_scanner.asmgetchar;
                  if c = '>' then
                  if c = '>' then
                   c:=current_scanner.asmgetchar;
                   c:=current_scanner.asmgetchar;
+{$endif loongarch64}
                  exit;
                  exit;
                end;
                end;
 
 

+ 2 - 1
compiler/systems.inc

@@ -58,7 +58,8 @@
              cpu_xtensa,                   { 21 }
              cpu_xtensa,                   { 21 }
              cpu_z80,                      { 22 }
              cpu_z80,                      { 22 }
              cpu_mips64,                   { 23 }
              cpu_mips64,                   { 23 }
-             cpu_mips64el                  { 24 }
+             cpu_mips64el,                 { 24 }
+             cpu_loongarch64               { 25 }
        );
        );
 
 
        tasmmode= (asmmode_none
        tasmmode= (asmmode_none

+ 2 - 2
compiler/systems.pas

@@ -470,11 +470,11 @@ interface
        asms_int_coff = [as_arm_pecoffwince,as_x86_64_pecoff,as_i386_pecoffwince,
        asms_int_coff = [as_arm_pecoffwince,as_x86_64_pecoff,as_i386_pecoffwince,
                         as_i386_pecoffwdosx,as_i386_pecoff,as_i386_coff];
                         as_i386_pecoffwdosx,as_i386_pecoff,as_i386_coff];
 
 
-       cpu2str : array[TSystemCpu] of string[10] =
+       cpu2str : array[TSystemCpu] of string[12] =
             ('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64',
             ('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64',
              'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086',
              'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086',
              'aarch64', 'wasm32', 'sparc64', 'riscv32', 'riscv64', 'xtensa',
              'aarch64', 'wasm32', 'sparc64', 'riscv32', 'riscv64', 'xtensa',
-             'z80', 'mips64', 'mips64el');
+             'z80', 'mips64', 'mips64el', 'loongarch64');
 
 
        abiinfo : array[tabi] of tabiinfo = (
        abiinfo : array[tabi] of tabiinfo = (
          (name: 'DEFAULT'; supported: true),
          (name: 'DEFAULT'; supported: true),

+ 1 - 1
compiler/tgobj.pas

@@ -186,7 +186,7 @@ implementation
        tempfreelist:=nil;
        tempfreelist:=nil;
        templist:=nil;
        templist:=nil;
        { we could create a new child class for this but I don't if it is worth the effort (FK) }
        { we could create a new child class for this but I don't if it is worth the effort (FK) }
-{$if defined(powerpc) or defined(powerpc64) or defined(avr) or defined(jvm) or defined(aarch64) or defined(xtensa) or defined(wasm32)}
+{$if defined(powerpc) or defined(powerpc64) or defined(avr) or defined(jvm) or defined(aarch64) or defined(xtensa) or defined(wasm32) or defined(loongarch64)}
        direction:=1;
        direction:=1;
 {$else}
 {$else}
        direction:=-1;
        direction:=-1;

+ 4 - 0
compiler/utils/fpc.pp

@@ -188,6 +188,10 @@ program fpc;
      ppcbin:='ppcwasm32';
      ppcbin:='ppcwasm32';
      processorname:='wasm32';
      processorname:='wasm32';
 {$endif wasm32}
 {$endif wasm32}
+{$ifdef loongarch64}
+     ppcbin:='ppcloongarch64';
+     processorname:='loongarch64';
+{$endif loongarch64}
      versionstr:='';                      { Default is just the name }
      versionstr:='';                      { Default is just the name }
      if ParamCount = 0 then
      if ParamCount = 0 then
        begin
        begin

+ 198 - 0
compiler/utils/mkloongarch64ins.pp

@@ -0,0 +1,198 @@
+{
+    Copyright (C) 2022 Loongson Technology Corporation Limited.
+
+    Convert loongarchins.dat from Nasm to a .inc file for usage with
+    the Free pascal compiler
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program 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.
+
+ **********************************************************************}
+{$mode objfpc}
+
+program mkloongarch64ins;
+
+const
+  Version = '1.0';
+
+var
+  insfile,opfile,nopfile,attfile : text;
+
+type
+  topcodes = array[1..64] of string;
+
+procedure bug(errormsg : string);
+begin
+  writeln(errormsg);
+  close(insfile);
+  close(opfile);
+  close(nopfile);
+  close(attfile);
+  halt;
+end;
+
+procedure copy_present_opcodes(start,len : longint; var ops : topcodes);
+var
+  i : longint;
+begin
+  for i:=start to start+len-1 do
+    ops[i]:=ops[1+i-start];
+end;
+
+procedure set_suffix(start,len : longint; var ops : topcodes; suffix : string);
+var
+  i : longint;
+begin
+  for i:=start to start+len-1 do
+    ops[i]:=ops[i]+suffix;
+end;
+
+function decode_format(format,prefix : string; var ops : topcodes) : longint;
+var
+  i,j,nr_comma,last_comma,nr_op : longint;
+  suffixs : string;
+begin
+  nr_op:=1;
+  ops[1]:=prefix;
+  i:=1;
+  while (format[i]<>'0') do
+    begin
+      case format[i] of
+        'a': suffixs:='W,D';
+        'b': suffixs:='W';
+        'c': suffixs:='D';
+        'd': suffixs:='W,WU,D';
+        'e': suffixs:='W,WU,D,DU';
+        'f': suffixs:='W,WU';
+        'g': suffixs:='B,H';
+        'h': suffixs:='2H,4H,2W,D';
+        'i': suffixs:='2W,D';
+        'j': suffixs:='4B,8B,W,D';
+        'k': suffixs:='B,H,W,D';
+        'l': suffixs:='BU,HU,WU';
+        'm': suffixs:='S,D';
+        'n': suffixs:='CAF,CUN,CEQ,CUEQ,CLT,CULT,CUGT,CLE,CULE,CUGE,CNE,COR,CUNE,SAF,SUN,SEQ,SUEQ,SLT,SGT,SULT,SLE,SGE,SULE,SNE,SOR,SUNE';
+        'o': suffixs:='S';
+        'p': suffixs:='D';
+        'q': suffixs:='L,W';
+        'r': suffixs:='GLOBAL,LOCAL,ABS,PCREL,GOT,TLE#LE,TLS#IE,TLS#LD,TLS#GD';
+      else
+        bug('Error Format');
+      end;
+      i:=i+1;
+
+      { For each comma, add suffix for present opcodes }
+      nr_comma:=1;
+      last_comma:=length(suffixs)+1;
+      for j:=length(suffixs) downto 0 do
+        begin
+          if (j=0) then
+            set_suffix(1,nr_op,ops,'#'+copy(suffixs,1,last_comma-1));
+          if (suffixs[j]<>',') then
+            continue;
+          copy_present_opcodes(nr_comma*nr_op+1, nr_op, ops);
+          set_suffix(nr_comma*nr_op+1,nr_op,ops,'#'+copy(suffixs,j+1,last_comma-j-1));
+          last_comma:=j;
+          nr_comma:=nr_comma+1;
+        end;
+      nr_op:=nr_comma*nr_op;
+    end;
+    result:=nr_op;
+end;
+
+procedure writeop(op : string);
+var
+  i : longint;
+  s : string;
+begin
+  for i:=1 to length(op) do
+    if op[i]='#' then
+      s[i]:='_'
+    else
+      s[i]:=op[i];
+  s[0]:=op[0];
+  write(opfile, 'A_', s);
+end;
+
+procedure writeatt(op : string);
+var
+  i : longint;
+  s : string;
+begin
+  for i:=1 to length(op) do
+    if op[i] in ['A'..'Z'] then
+      s[i]:=char(byte(op[i])+32)
+    else if op[i]='#' then
+      s[i]:='.'
+    else
+      s[i]:=op[i];
+  s[0]:=op[0];
+  write(attfile, '''', s, '''');
+end;
+
+var
+  i,j,all_op,nr_op : longint;
+  s : string;
+  opcode : string;
+  opcodes : topcodes;
+  is_not_first_op : boolean;
+begin
+  writeln('FPC Instruction Table Converter Version ',Version);
+  assign(insfile,'../loongarch64/loongarchins.dat');
+  reset(insfile);
+  assign(opfile,'../loongarch64/loongarch64op.inc');
+  rewrite(opfile);
+  writeln(opfile,'{ don''t edit, this file is generated from loongarchins.dat }');
+  writeln(opfile,'(');
+  assign(nopfile,'../loongarch64/loongarch64nop.inc');
+  rewrite(nopfile);
+  writeln(nopfile,'{ don''t edit, this file is generated from loongarchins.dat }');
+  assign(attfile,'../loongarch64/loongarch64att.inc');
+  rewrite(attfile);
+  writeln(attfile,'{ don''t edit, this file is generated from loongarchins.dat }');
+  writeln(attfile,'(');
+
+  all_op:=0;
+  is_not_first_op:=false;
+  while not(eof(insfile)) do
+    begin
+      readln(insfile,s);
+      if (s='') or (s[1]=';') then
+        continue;
+      if (s[1]<>'[') then
+        continue;
+      i:=pos(']',s);
+      opcode:=copy(s,2,i-2);
+      i:=pos('(',s);
+      j:=pos(')',s);
+      nr_op:=decode_format(copy(s,i+1,j-i-1),opcode,opcodes);
+      for i:=1 to nr_op do
+        begin
+          if is_not_first_op then
+            begin
+              writeln(opfile,',');
+              writeln(attfile,',');
+            end;
+          writeop(opcodes[i]);
+          if opcodes[i]='BXX' then
+            writeatt('B')
+          else
+            writeatt(opcodes[i]);
+          is_not_first_op:=true;
+        end;
+      all_op:=all_op+nr_op;
+    end;
+  writeln(opfile);
+  write(opfile,');');
+  writeln(attfile);
+  write(attfile,');');
+  write(nopfile, all_op, ';');
+  close(insfile);
+  close(opfile);
+  close(nopfile);
+  close(attfile);
+end.

+ 267 - 0
compiler/utils/mkloongarch64reg.pp

@@ -0,0 +1,267 @@
+{
+    Copyright (C) 2022 Loongson Technology Corporation Limited.
+
+    Convert loongarchreg.dat to a .inc file for usage with
+    the Free pascal compiler
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program 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.
+
+ **********************************************************************}
+{$mode objfpc}
+
+program mkloongarchreg;
+
+const
+  Version = '1.0';
+  max_regcount = 512;
+
+var
+  nr_regs : word;
+  srcfile : text;
+  names,abinames,stdnames : array[0..max_regcount] of string;
+  regtypes,subtypes,values,stabs,dwarf,std_regname_index,regnumber_index : array[0..max_regcount] of word;
+  numbers : array[0..max_regcount] of longint;
+
+procedure bug(errormsg : string);
+begin
+  writeln(errormsg);
+  close(srcfile);
+  halt;
+end;
+
+function str2word(s : string) : word;
+var
+  v,errcode : integer;
+begin
+  val(s,v,errcode);
+  if (errcode<>0) or (v>65535) or (v<0) then
+    str2word:=0
+  else
+    str2word:=word(v);
+end;
+
+procedure readdatfile;
+var
+  i,last,idx : longint;
+  s,subs : string;
+begin
+  assign(srcfile, '../loongarch64/loongarchreg.dat');
+  reset(srcfile);
+  nr_regs:=0;
+  while not(eof(srcfile)) do
+    begin
+      readln(srcfile,s);
+      if (s='') or (s[1]=';') then
+        continue;
+      { <name>,<type>,<subtype>,<value>,<abiname>,<stdname>,<stab idx>,<dwarf idx> }
+      last:=length(s)+1;
+      idx:=1;
+      for i:=length(s) downto 0 do
+        begin
+          if (i=0) then
+            begin
+              if (idx<>8) then
+                bug('Incomplete tables');
+              names[nr_regs]:=copy(s,1,last-1);
+              continue;
+            end;
+          if (s[i]<>',') then
+            continue;
+          subs:=copy(s,i+1,last-i-1);
+          case (idx) of
+            1: dwarf[nr_regs]:=str2word(subs);
+            2: stabs[nr_regs]:=str2word(subs);
+            3: stdnames[nr_regs]:=subs;
+            4: abinames[nr_regs]:=subs;
+            5: values[nr_regs]:=str2word(subs);
+            6: subtypes[nr_regs]:=str2word(subs);
+            7: regtypes[nr_regs]:=str2word(subs);
+            8: bug('Overflow tables');
+          end;
+          idx:=idx+1;
+          last:=i;
+        end;
+      nr_regs:=nr_regs+1;
+    end;
+end;
+
+type
+  SWAP_FUNC=procedure (i,j : longint; p : pointer);
+  CMPR_FUNC=function (i,j : longint; p :pointer) : boolean;
+
+procedure qsort(l,r : longint; p : pointer; s : SWAP_FUNC; c : CMPR_FUNC);
+var
+  i,j : longint;
+begin
+  if l>=r then
+    exit;
+  i:=l;
+  j:=r;
+  while i<j do
+    begin
+      while (i<j) and c(i,j,p) do
+        j:=j-1;
+      if i<j then
+        begin
+          s(i,j,p);
+          i:=i+1;
+        end;
+      while (i<j) and c(i,j,p) do
+        i:=i+1;
+      if i<j then
+        begin
+          s(i,j,p);
+          j:=j-1;
+        end;
+    end;
+  qsort(l,i-1,p,s,c);
+  qsort(i+1,r,p,s,c);
+end;
+
+procedure swap_rni(i,j : longint; p : pointer);
+var
+  t : word;
+begin
+  t:=regnumber_index[i];
+  regnumber_index[i]:=regnumber_index[j];
+  regnumber_index[j]:=t;
+end;
+
+function cmpr_rn(i,j : longint; p :pointer) : boolean;
+begin
+  cmpr_rn:=numbers[regnumber_index[i]]<numbers[regnumber_index[j]];
+end;
+
+procedure swap_sri(i,j : longint; p : pointer);
+var
+  t : word;
+begin
+  t:=std_regname_index[i];
+  std_regname_index[i]:=std_regname_index[j];
+  std_regname_index[j]:=t;
+end;
+
+function cmpr_sr(i,j : longint; p :pointer) : boolean;
+begin
+  cmpr_sr:=stdnames[std_regname_index[i]]<stdnames[std_regname_index[j]];
+end;
+
+procedure build_regnum_index;
+var
+  i :longint;
+  s : SWAP_FUNC;
+  c : CMPR_FUNC;
+begin
+  for i:=0 to nr_regs-1 do
+    regnumber_index[i]:=i;
+  s:=@swap_rni;
+  c:=@cmpr_rn;
+  qsort(0,nr_regs-1,nil,s,c);
+end;
+
+procedure build_std_regname_index;
+var
+  i : longint;
+  s : SWAP_FUNC;
+  c : CMPR_FUNC;
+begin
+  for i:=0 to nr_regs-1 do
+    std_regname_index[i]:=i;
+  s:=@swap_sri;
+  c:=@cmpr_sr;
+  qsort(0,nr_regs-1,nil,s,c);
+end;
+
+procedure setarrays;
+var
+  i : longint;
+begin
+  for i:=0 to nr_regs-1 do
+    numbers[i]:=(regtypes[i] shl 24) or (subtypes[i] shl 16) or values[i];
+  build_regnum_index;
+  build_std_regname_index;
+end;
+
+procedure openinc(out f:text;const fn:string);
+begin
+  writeln('creating ',fn);
+  assign(f,fn);
+  rewrite(f);
+  writeln(f,'{ don''t edit, this file is generated from loongarchreg.dat }');
+end;
+
+procedure closeinc(var f:text);
+begin
+  writeln(f);
+  close(f);
+end;
+
+procedure write_inc_files;
+var
+  first : boolean;
+  numfile,stdfile,stabfile,dwarffile,rnifile,srifile,supfile,norfile,confile,abinamefile : text;
+  i : longint;
+begin
+  { create inc files }
+  openinc(confile,'../loongarch64/rloongarch64con.inc');
+  openinc(supfile,'../loongarch64/rloongarch64sup.inc');
+  openinc(numfile,'../loongarch64/rloongarch64num.inc');
+  openinc(stdfile,'../loongarch64/rloongarch64std.inc');
+  openinc(abinamefile,'../loongarch64/rloongarch64abi.inc');
+  openinc(stabfile,'../loongarch64/rloongarch64sta.inc');
+  openinc(dwarffile,'../loongarch64/rloongarch64dwa.inc');
+  openinc(rnifile,'../loongarch64/rloongarch64rni.inc');
+  openinc(srifile,'../loongarch64/rloongarch64sri.inc');
+  first:=true;
+  for i:=0 to nr_regs-1 do
+    begin
+      if not first then
+        begin
+          writeln(numfile,',');
+          writeln(stdfile,',');
+          writeln(abinamefile,',');
+          writeln(stabfile,',');
+          writeln(dwarffile,',');
+          writeln(rnifile,',');
+          writeln(srifile,',');
+        end
+      else
+        first:=false;
+      writeln(supfile,'RS_',names[i],' = ',values[i],';');
+      writeln(confile,'NR_'+names[i],' = ','tregister(',numbers[i],')',';');
+      write(numfile,'tregister(',numbers[i],')');
+      write(stdfile,'''',stdnames[i],'''');
+      write(abinamefile,'''',abinames[i],'''');
+      write(stabfile,stabs[i]);
+      write(dwarffile,dwarf[i]);
+      write(rnifile,regnumber_index[i]);
+      write(srifile,std_regname_index[i]);
+    end;
+  openinc(norfile,'../loongarch64/rloongarch64nor.inc');
+  write(norfile,nr_regs);
+  closeinc(norfile);
+  close(confile);
+  close(supfile);
+  closeinc(numfile);
+  closeinc(stdfile);
+  closeinc(abinamefile);
+  closeinc(stabfile);
+  closeinc(dwarffile);
+  closeinc(rnifile);
+  closeinc(srifile);
+  writeln('Done!');
+  writeln(nr_regs,' registers processed');
+end;
+
+begin
+   writeln('Register Table Converter Version ',Version);
+   readdatfile;
+   setarrays;
+   write_inc_files;
+end.
+

+ 4 - 2
compiler/utils/ppuutils/ppudump.pp

@@ -89,7 +89,8 @@ const
     { 21 } 'xtensa',
     { 21 } 'xtensa',
     { 22 } 'z80',
     { 22 } 'z80',
     { 23 } 'mips64',
     { 23 } 'mips64',
-    { 24 } 'mips64el'
+    { 24 } 'mips64el',
+    { 25 } 'loongarch64'
     );
     );
 
 
   CpuHasController : array[tsystemcpu] of boolean =
   CpuHasController : array[tsystemcpu] of boolean =
@@ -118,7 +119,8 @@ const
     { 21 } true  {'xtensa'},
     { 21 } true  {'xtensa'},
     { 22 } true  {'z80'},
     { 22 } true  {'z80'},
     { 23 } false {'mips64'},
     { 23 } false {'mips64'},
-    { 24 } false {'mips64el'}
+    { 24 } false {'mips64el'},
+    { 25 } false {'loongarch64'}
     );
     );
 
 
 { List of all supported system-cpu couples }
 { List of all supported system-cpu couples }

+ 3 - 0
compiler/version.pas

@@ -86,6 +86,9 @@ interface
 {$ifdef cpuwasm32}
 {$ifdef cpuwasm32}
         source_cpu_string = 'wasm32';
         source_cpu_string = 'wasm32';
 {$endif cpuwasm32}
 {$endif cpuwasm32}
+{$ifdef cpuloongarch64}
+        source_cpu_string = 'loongarch64';
+{$endif cpuloongarch64}
 
 
 function version_string:string;
 function version_string:string;
 function full_version_string:string;
 function full_version_string:string;