summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorflorian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2>2018-09-26 19:49:08 +0000
committerflorian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2>2018-09-26 19:49:08 +0000
commit844935a6ffbca5d7ae4758de3aa4ef8496543f3a (patch)
tree4cc43a6480f3e1a1702fda012b2da986a015a0b3 /compiler
parentacb2f648fb97fdc281287b6cdb3d0ca2a537ae7a (diff)
downloadfpc-844935a6ffbca5d7ae4758de3aa4ef8496543f3a.tar.gz
Merged riscv_new branch
git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@39813 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'compiler')
-rw-r--r--compiler/Makefile126
-rw-r--r--compiler/Makefile.fpc28
-rw-r--r--compiler/aasmtai.pas8
-rw-r--r--compiler/aggas.pas2
-rw-r--r--compiler/aoptobj.pas19
-rw-r--r--compiler/cgbase.pas8
-rw-r--r--compiler/cgobj.pas10
-rw-r--r--compiler/cgutils.pas5
-rw-r--r--compiler/dbgdwarf.pas10
-rw-r--r--compiler/entfile.pas8
-rw-r--r--compiler/fpcdefs.inc24
-rw-r--r--compiler/globals.pas16
-rw-r--r--compiler/globtype.pas2
-rw-r--r--compiler/msg/errore.msg1
-rw-r--r--compiler/msgidx.inc2
-rw-r--r--compiler/msgtxt.inc333
-rw-r--r--compiler/nadd.pas2
-rw-r--r--compiler/ncal.pas3
-rw-r--r--compiler/ncgcal.pas4
-rw-r--r--compiler/ninl.pas27
-rw-r--r--compiler/nutils.pas33
-rw-r--r--compiler/optcse.pas7
-rw-r--r--compiler/options.pas62
-rw-r--r--compiler/pp.pas13
-rw-r--r--compiler/ppcriscv32.lpi86
-rw-r--r--compiler/ppcriscv64.lpi78
-rw-r--r--compiler/psub.pas2
-rw-r--r--compiler/psystem.pas8
-rw-r--r--compiler/raatt.pas16
-rw-r--r--compiler/rautils.pas9
-rw-r--r--compiler/riscv/aasmcpu.pas624
-rw-r--r--compiler/riscv/agrvgas.pas253
-rw-r--r--compiler/riscv/cgrv.pas758
-rw-r--r--compiler/riscv/hlcgrv.pas260
-rw-r--r--compiler/riscv/nrvadd.pas417
-rw-r--r--compiler/riscv/nrvcnv.pas178
-rw-r--r--compiler/riscv/nrvcon.pas131
-rw-r--r--compiler/riscv/nrvinl.pas341
-rw-r--r--compiler/riscv/nrvset.pas154
-rw-r--r--compiler/riscv/rgcpu.pas126
-rw-r--r--compiler/riscv32/aoptcpu.pas77
-rw-r--r--compiler/riscv32/aoptcpub.pas115
-rw-r--r--compiler/riscv32/aoptcpuc.pas40
-rw-r--r--compiler/riscv32/aoptcpud.pas40
-rw-r--r--compiler/riscv32/cgcpu.pas641
-rw-r--r--compiler/riscv32/cpubase.pas428
-rw-r--r--compiler/riscv32/cpuinfo.pas135
-rw-r--r--compiler/riscv32/cpunode.pas50
-rw-r--r--compiler/riscv32/cpupara.pas550
-rw-r--r--compiler/riscv32/cpupi.pas123
-rw-r--r--compiler/riscv32/cputarg.pas84
-rw-r--r--compiler/riscv32/hlcgcpu.pas61
-rw-r--r--compiler/riscv32/itcpugas.pas141
-rw-r--r--compiler/riscv32/nrv32add.pas56
-rw-r--r--compiler/riscv32/nrv32cal.pas51
-rw-r--r--compiler/riscv32/nrv32cnv.pas151
-rw-r--r--compiler/riscv32/nrv32mat.pas135
-rw-r--r--compiler/riscv32/rarv32.pas41
-rw-r--r--compiler/riscv32/rarv32gas.pas771
-rw-r--r--compiler/riscv32/rrv32con.inc67
-rw-r--r--compiler/riscv32/rrv32dwa.inc67
-rw-r--r--compiler/riscv32/rrv32nor.inc2
-rw-r--r--compiler/riscv32/rrv32num.inc67
-rw-r--r--compiler/riscv32/rrv32rni.inc67
-rw-r--r--compiler/riscv32/rrv32sri.inc67
-rw-r--r--compiler/riscv32/rrv32sta.inc67
-rw-r--r--compiler/riscv32/rrv32std.inc67
-rw-r--r--compiler/riscv32/rrv32sup.inc67
-rw-r--r--compiler/riscv32/rv32reg.dat77
-rw-r--r--compiler/riscv32/symcpu.pas216
-rw-r--r--compiler/riscv64/aoptcpu.pas387
-rw-r--r--compiler/riscv64/aoptcpub.pas116
-rw-r--r--compiler/riscv64/aoptcpuc.pas40
-rw-r--r--compiler/riscv64/aoptcpud.pas40
-rw-r--r--compiler/riscv64/cgcpu.pas642
-rw-r--r--compiler/riscv64/cpubase.pas462
-rw-r--r--compiler/riscv64/cpuinfo.pas139
-rw-r--r--compiler/riscv64/cpunode.pas55
-rw-r--r--compiler/riscv64/cpupara.pas545
-rw-r--r--compiler/riscv64/cpupi.pas116
-rw-r--r--compiler/riscv64/cputarg.pas85
-rw-r--r--compiler/riscv64/hlcgcpu.pas78
-rw-r--r--compiler/riscv64/itcpugas.pas157
-rw-r--r--compiler/riscv64/nrv64add.pas98
-rw-r--r--compiler/riscv64/nrv64cal.pas56
-rw-r--r--compiler/riscv64/nrv64cnv.pas124
-rw-r--r--compiler/riscv64/nrv64ld.pas57
-rw-r--r--compiler/riscv64/nrv64mat.pas163
-rw-r--r--compiler/riscv64/rarv.pas50
-rw-r--r--compiler/riscv64/rarv64gas.pas840
-rw-r--r--compiler/riscv64/rrv32con.inc67
-rw-r--r--compiler/riscv64/rrv32dwa.inc67
-rw-r--r--compiler/riscv64/rrv32nor.inc2
-rw-r--r--compiler/riscv64/rrv32num.inc67
-rw-r--r--compiler/riscv64/rrv32rni.inc67
-rw-r--r--compiler/riscv64/rrv32sri.inc67
-rw-r--r--compiler/riscv64/rrv32sta.inc67
-rw-r--r--compiler/riscv64/rrv32std.inc67
-rw-r--r--compiler/riscv64/rrv32sup.inc67
-rw-r--r--compiler/riscv64/rv32reg.dat77
-rw-r--r--compiler/riscv64/symcpu.pas220
-rw-r--r--compiler/scandir.pas7
-rw-r--r--compiler/systems.inc11
-rw-r--r--compiler/systems.pas18
-rw-r--r--compiler/systems/i_linux.pas142
-rw-r--r--compiler/systems/t_linux.pas25
-rw-r--r--compiler/utils/Makefile64
-rw-r--r--compiler/utils/fpc.pp8
-rw-r--r--compiler/utils/ppuutils/ppudump.pp10
-rw-r--r--compiler/version.pas6
110 files changed, 13866 insertions, 225 deletions
diff --git a/compiler/Makefile b/compiler/Makefile
index ecf8f5d277..0419ce9e23 100644
--- a/compiler/Makefile
+++ b/compiler/Makefile
@@ -1,8 +1,8 @@
#
-# Don't edit, this file is generated by FPCMake Version 2.0.0
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2018/07/20]
#
default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm sparc64-linux
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded
BSDs = freebsd netbsd openbsd darwin dragonfly
UNIXs = linux $(BSDs) solaris qnx haiku aix
LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -332,9 +332,9 @@ FPCFPMAKE=$(FPC)
endif
endif
override PACKAGE_NAME=compiler
-override PACKAGE_VERSION=3.3.1
+override PACKAGE_VERSION=3.1.1
unexport FPC_VERSION FPC_COMPILERINFO
-CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64
ALLTARGETS=$(CYCLETARGETS)
ifdef POWERPC
PPC_TARGET=powerpc
@@ -381,6 +381,12 @@ endif
ifdef AARCH64
PPC_TARGET=aarch64
endif
+ifdef RISCV32
+PPC_TARGET=riscv32
+endif
+ifdef RISCV64
+PPC_TARGET=riscv64
+endif
ifndef PPC_TARGET
PPC_TARGET=$(CPU_TARGET)
endif
@@ -483,6 +489,12 @@ endif
ifeq ($(CPC_TARGET),aarch64)
CPUSUF=a64
endif
+ifeq ($(CPC_TARGET),riscv32)
+CPUSUF=rv32
+endif
+ifeq ($(CPC_TARGET),riscv64)
+CPUSUF=rv64
+endif
NOCPUDEF=1
MSGFILE=msg/error$(FPCLANG).msg
SVNVERSION:=$(firstword $(wildcard $(addsuffix /svnversion$(SRCEXEEXT),$(SEARCHPATH))))
@@ -544,6 +556,12 @@ endif
ifeq ($(PPC_TARGET),i8086)
override LOCALOPT+=-Fux86
endif
+ifeq ($(PPC_TARGET),riscv32)
+override LOCALOPT+=-Furiscv
+endif
+ifeq ($(PPC_TARGET),riscv64)
+override LOCALOPT+=-Furiscv
+endif
OPTWPOCOLLECT=-OWdevirtcalls,optvmts -FW$(BASEDIR)/pp1.wpo
OPTWPOPERFORM=-Owdevirtcalls,optvmts -Fw$(BASEDIR)/pp1.wpo
ifneq ($(findstring $(OS_TARGET),darwin linux dragonfly freebsd solaris),)
@@ -834,6 +852,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override TARGET_DIRS+=utils
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override TARGET_DIRS+=utils
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override TARGET_DIRS+=utils
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override TARGET_DIRS+=utils
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override TARGET_DIRS+=utils
+endif
ifeq ($(FULL_TARGET),i386-linux)
override TARGET_PROGRAMS+=pp
endif
@@ -1089,6 +1119,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override TARGET_PROGRAMS+=pp
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override TARGET_PROGRAMS+=pp
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override TARGET_PROGRAMS+=pp
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override TARGET_PROGRAMS+=pp
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override TARGET_PROGRAMS+=pp
+endif
override INSTALL_FPCPACKAGE=y
ifeq ($(FULL_TARGET),i386-linux)
override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
@@ -1345,6 +1387,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
ifeq ($(FULL_TARGET),i386-linux)
override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
endif
@@ -1600,6 +1654,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
ifeq ($(FULL_TARGET),i386-linux)
override COMPILER_TARGETDIR+=.
endif
@@ -1855,6 +1921,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override COMPILER_TARGETDIR+=.
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_TARGETDIR+=.
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_TARGETDIR+=.
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_TARGETDIR+=.
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_TARGETDIR+=.
+endif
ifeq ($(FULL_TARGET),i386-linux)
override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
endif
@@ -2110,6 +2188,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
ifdef REQUIRE_UNITSDIR
override UNITSDIR+=$(REQUIRE_UNITSDIR)
endif
@@ -3030,6 +3120,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
REQUIRE_PACKAGES_RTL=1
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
ifdef REQUIRE_PACKAGES_RTL
PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
ifneq ($(PACKAGEDIR_RTL),)
@@ -3930,6 +4032,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
TARGET_DIRS_UTILS=1
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+TARGET_DIRS_UTILS=1
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+TARGET_DIRS_UTILS=1
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+TARGET_DIRS_UTILS=1
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+TARGET_DIRS_UTILS=1
+endif
ifdef TARGET_DIRS_UTILS
utils_all:
$(MAKE) -C utils all
@@ -4058,7 +4172,7 @@ INSTALLEXEFILE=$(PPCROSSNAME)
else
INSTALLEXEFILE=$(EXENAME)
endif
-PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64
+PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64 riscv32 riscv64
INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
SYMLINKINSTALL_TARGETS=$(addsuffix _symlink_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
.PHONY: $(PPC_TARGETS) $(INSTALL_TARGETS)$(SYMLINKINSTALL_TARGETS)
@@ -4293,7 +4407,7 @@ cvstest:
ifeq ($(OS_SOURCE),win64)
EXCLUDE_80BIT_TARGETS=1
endif
-ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel powerpc powerpc64 sparc sparc64),)
+ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel powerpc powerpc64 sparc sparc64 riscv32 riscv64),)
EXCLUDE_80BIT_TARGETS=1
endif
full: fullcycle
diff --git a/compiler/Makefile.fpc b/compiler/Makefile.fpc
index 2338ad6896..7f999dcfab 100644
--- a/compiler/Makefile.fpc
+++ b/compiler/Makefile.fpc
@@ -32,7 +32,7 @@ fpcdir=..
unexport FPC_VERSION FPC_COMPILERINFO
# 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
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64
# All supported targets used for clean
ALLTARGETS=$(CYCLETARGETS)
@@ -83,6 +83,12 @@ endif
ifdef AARCH64
PPC_TARGET=aarch64
endif
+ifdef RISCV32
+PPC_TARGET=riscv32
+endif
+ifdef RISCV64
+PPC_TARGET=riscv64
+endif
# Default is to generate a compiler for the same
# platform as CPU_TARGET (a native compiler)
@@ -213,6 +219,12 @@ endif
ifeq ($(CPC_TARGET),aarch64)
CPUSUF=a64
endif
+ifeq ($(CPC_TARGET),riscv32)
+CPUSUF=rv32
+endif
+ifeq ($(CPC_TARGET),riscv64)
+CPUSUF=rv64
+endif
# Do not define the default -d$(CPU_TARGET) because that
# will conflict with our -d$(CPC_TARGET)
@@ -315,6 +327,16 @@ ifeq ($(PPC_TARGET),i8086)
override LOCALOPT+=-Fux86
endif
+# RiscV32 specific
+ifeq ($(PPC_TARGET),riscv32)
+override LOCALOPT+=-Furiscv
+endif
+
+# RiscV64 specific
+ifeq ($(PPC_TARGET),riscv64)
+override LOCALOPT+=-Furiscv
+endif
+
OPTWPOCOLLECT=-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
@@ -432,7 +454,7 @@ endif
# CPU targets
#####################################################################
-PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64
+PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64 riscv32 riscv64
INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
SYMLINKINSTALL_TARGETS=$(addsuffix _symlink_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
@@ -802,7 +824,7 @@ ifeq ($(OS_SOURCE),win64)
EXCLUDE_80BIT_TARGETS=1
endif
-ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel powerpc powerpc64 sparc sparc64),)
+ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel powerpc powerpc64 sparc sparc64 riscv32 riscv64),)
EXCLUDE_80BIT_TARGETS=1
endif
diff --git a/compiler/aasmtai.pas b/compiler/aasmtai.pas
index 6add506545..99057b8696 100644
--- a/compiler/aasmtai.pas
+++ b/compiler/aasmtai.pas
@@ -262,6 +262,10 @@ interface
,top_para
,top_asmlist
{$endif llvm}
+{$if defined(riscv32) or defined(riscv64)}
+ ,top_fenceflags
+ ,top_roundingmode
+{$endif defined(riscv32) or defined(riscv64)}
);
{ kinds of operations that an instruction can perform on an operand }
@@ -463,6 +467,10 @@ interface
top_para : (paras: tfplist);
top_asmlist : (asmlist: tasmlist);
{$endif llvm}
+ {$if defined(riscv32) or defined(riscv64)}
+ top_fenceflags : (fenceflags : TFenceFlags);
+ top_roundingmode : (roundingmode : TRoundingMode);
+ {$endif defined(riscv32) or defined(riscv64)}
end;
poper=^toper;
diff --git a/compiler/aggas.pas b/compiler/aggas.pas
index b84f0d505d..4478bc3dc4 100644
--- a/compiler/aggas.pas
+++ b/compiler/aggas.pas
@@ -211,7 +211,7 @@ implementation
{ vtable for a class called Window: }
{ .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat }
{ TODO: .data.ro not yet working}
-{$if defined(arm) or defined(powerpc)}
+{$if defined(arm) or defined(riscv64) or defined(powerpc)}
'.rodata',
{$else arm}
'.data',
diff --git a/compiler/aoptobj.pas b/compiler/aoptobj.pas
index b9aed768e1..dbf9dac333 100644
--- a/compiler/aoptobj.pas
+++ b/compiler/aoptobj.pas
@@ -383,8 +383,8 @@ Unit AoptObj;
function JumpTargetOp(ai: taicpu): poper; inline;
begin
-{$if defined(MIPS)}
- { MIPS branches can have 1,2 or 3 operands, target label is the last one. }
+{$if defined(MIPS) or defined(riscv64) or defined(riscv32)}
+ { MIPS or RiscV branches can have 1,2 or 3 operands, target label is the last one. }
result:=ai.oper[ai.ops-1];
{$elseif defined(SPARC64)}
if ai.ops=2 then
@@ -1342,7 +1342,12 @@ Unit AoptObj;
{$if defined(arm) or defined(aarch64)}
(hp.condition=c_None) and
{$endif arm or aarch64}
+{$if defined(riscv32) or defined(riscv64)}
(hp.ops>0) and
+ (hp.oper[0]^.reg=NR_X0) and
+{$else riscv}
+ (hp.ops>0) and
+{$endif riscv}
(JumpTargetOp(hp)^.typ = top_ref) and
(JumpTargetOp(hp)^.ref^.symbol is TAsmLabel);
end;
@@ -1390,7 +1395,7 @@ Unit AoptObj;
to avoid endless loops with constructs such as "l5: ; jmp l5" }
var p1: tai;
- {$if not defined(MIPS) and not defined(JVM)}
+ {$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
p2: tai;
l: tasmlabel;
{$endif}
@@ -1408,7 +1413,7 @@ Unit AoptObj;
if { the next instruction after the label where the jump hp arrives}
{ is unconditional or of the same type as hp, so continue }
IsJumpToLabelUncond(taicpu(p1))
-{$if not defined(MIPS) and not defined(JVM)}
+{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
{ for MIPS, it isn't enough to check the condition; first operands must be same, too. }
or
conditions_equal(taicpu(p1).condition,hp.condition) or
@@ -1425,7 +1430,7 @@ Unit AoptObj;
(IsJumpToLabelUncond(taicpu(p2)) or
(conditions_equal(taicpu(p2).condition,hp.condition))) and
SkipLabels(p1,p1))
-{$endif not MIPS and not JVM}
+{$endif not MIPS and not RV64 and not RV32 and not JVM}
then
begin
{ quick check for loops of the form "l5: ; jmp l5 }
@@ -1446,7 +1451,7 @@ Unit AoptObj;
JumpTargetOp(hp)^.ref^.symbol:=JumpTargetOp(taicpu(p1))^.ref^.symbol;
tasmlabel(JumpTargetOp(hp)^.ref^.symbol).increfs;
end
-{$if not defined(MIPS) and not defined(JVM)}
+{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
else
if conditions_equal(taicpu(p1).condition,inverse_cond(hp.condition)) then
if not FindAnyLabel(p1,l) then
@@ -1477,7 +1482,7 @@ Unit AoptObj;
if not GetFinalDestination(hp,succ(level)) then
exit;
end;
-{$endif not MIPS and not JVM}
+{$endif not MIPS and not RV64 and not RV32 and not JVM}
end;
GetFinalDestination := true;
end;
diff --git a/compiler/cgbase.pas b/compiler/cgbase.pas
index 325e8fdfdf..e7abf39926 100644
--- a/compiler/cgbase.pas
+++ b/compiler/cgbase.pas
@@ -93,6 +93,14 @@ interface
addr_low_call, // counterpart of two above, generate call_hi16 and call_lo16 relocs
addr_high_call
{$ENDIF}
+ {$if defined(RISCV32) or defined(RISCV64)}
+ ,
+ addr_hi20,
+ addr_lo12,
+ addr_pcrel_hi20,
+ addr_pcrel_lo12,
+ addr_pcrel
+ {$endif RISCV}
{$IFDEF AVR}
,addr_lo8
,addr_lo8_gs
diff --git a/compiler/cgobj.pas b/compiler/cgobj.pas
index fe839b56b2..316253cef1 100644
--- a/compiler/cgobj.pas
+++ b/compiler/cgobj.pas
@@ -446,6 +446,10 @@ unit cgobj;
generic version is suitable for 3-address CPUs }
procedure g_div_const_reg_reg(list:tasmlist; size: TCgSize; a: tcgint; src,dst: tregister); virtual;
+ { some CPUs do not support hardware fpu exceptions, this procedure is called after instructions which
+ might set FPU exception related flags, so it has to check these flags if needed and throw an exeception }
+ procedure g_check_for_fpu_exception(list: TAsmList); virtual;
+
protected
function g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister;virtual;
end;
@@ -2876,6 +2880,12 @@ implementation
end;
+ procedure tcg.g_check_for_fpu_exception(list: TAsmList);
+ begin
+ { empty by default }
+ end;
+
+
{*****************************************************************************
TCG64
*****************************************************************************}
diff --git a/compiler/cgutils.pas b/compiler/cgutils.pas
index 0c1374b69a..3e2475ced6 100644
--- a/compiler/cgutils.pas
+++ b/compiler/cgutils.pas
@@ -74,7 +74,10 @@ unit cgutils;
base,
index : tregister;
refaddr : trefaddr;
- scalefactor : byte;
+ scalefactor : byte;
+{$if defined(riscv32) or defined(riscv64)}
+ symboldata : tlinkedlistitem;
+{$endif riscv32/64}
{$ifdef arm}
symboldata : tlinkedlistitem;
signindex : shortint;
diff --git a/compiler/dbgdwarf.pas b/compiler/dbgdwarf.pas
index 28ca4ed236..375502dc81 100644
--- a/compiler/dbgdwarf.pas
+++ b/compiler/dbgdwarf.pas
@@ -3774,10 +3774,12 @@ implementation
asmline.concat(tai_comment.Create(strpnew('['+tostr(currfileinfo.line)+':'+tostr(currfileinfo.column)+']')));
if (prevlabel = nil) or
- { darwin's assembler cannot create an uleb128 of the difference }
- { between to symbols }
- { same goes for Solaris native assembler }
- (target_info.system in systems_darwin) or
+ { darwin's assembler cannot create an uleb128 of the difference
+ between to symbols
+ same goes for Solaris native assembler
+ ... and riscv }
+
+ (target_info.system in systems_darwin+[system_riscv32_linux,system_riscv64_linux]) or
(target_asm.id=as_solaris_as) then
begin
asmline.concat(tai_const.create_8bit(DW_LNS_extended_op));
diff --git a/compiler/entfile.pas b/compiler/entfile.pas
index 34b3bc3325..7bbbbca9b1 100644
--- a/compiler/entfile.pas
+++ b/compiler/entfile.pas
@@ -153,7 +153,9 @@ const
{ 15 } 16 {'i8086'},
{ 16 } 64 {'aarch64'},
{ 17 } 32 {'wasm'},
- { 18 } 64 {'sparc64'}
+ { 18 } 64 {'sparc64'},
+ { 19 } 32 {'riscv32'},
+ { 20 } 64 {'riscv64'}
);
CpuAluBitSize : array[tsystemcpu] of longint =
(
@@ -175,7 +177,9 @@ const
{ 15 } 16 {'i8086'},
{ 16 } 64 {'aarch64'},
{ 17 } 64 {'wasm'},
- { 18 } 64 {'sparc64'}
+ { 18 } 64 {'sparc64'},
+ { 19 } 32 {'riscv32'},
+ { 20 } 64 {'riscv64'}
);
{$endif generic_cpu}
diff --git a/compiler/fpcdefs.inc b/compiler/fpcdefs.inc
index ff3add6a38..59f48cd00a 100644
--- a/compiler/fpcdefs.inc
+++ b/compiler/fpcdefs.inc
@@ -273,6 +273,30 @@
{$define SUPPORT_GET_FRAME}
{$endif aarch64}
+{$ifdef riscv32}
+ {$define cpu32bit}
+ {$define cpu32bitaddr}
+ {$define cpu32bitalu}
+ {$define cpufpemu}
+ {$define cputargethasfixedstack}
+ {$define cpuneedsmulhelper}
+ {$define cpuneedsdivhelper}
+ {$define cpucapabilities}
+ {$define cpurequiresproperalignment}
+{$endif riscv32}
+
+{$ifdef riscv64}
+ {$define cpu64bit}
+ {$define cpu64bitaddr}
+ {$define cpu64bitalu}
+ {$define cpufpemu}
+ {$define cputargethasfixedstack}
+ {$define cpuneedsmulhelper}
+ {$define cpuneedsdivhelper}
+ {$define cpucapabilities}
+ {$define cpurequiresproperalignment}
+{$endif riscv64}
+
{$IFDEF MACOS}
{$DEFINE USE_FAKE_SYSUTILS}
{$ENDIF MACOS}
diff --git a/compiler/globals.pas b/compiler/globals.pas
index 121845ae28..d4f9af7be4 100644
--- a/compiler/globals.pas
+++ b/compiler/globals.pas
@@ -54,8 +54,8 @@ interface
[m_delphi,m_class,m_objpas,m_result,m_string_pchar,
m_pointer_2_procedure,m_autoderef,m_tp_procvar,m_initfinal,m_default_ansistring,
m_out,m_default_para,m_duplicate_names,m_hintdirective,
- m_property,m_default_inline,m_except,m_advanced_records,
- m_array_operators];
+ m_property,m_default_inline,m_except,m_advanced_records,
+ m_array_operators];
delphiunicodemodeswitches = delphimodeswitches + [m_systemcodepage,m_default_unicodestring];
fpcmodeswitches =
[m_fpc,m_string_pchar,m_nested_comment,m_repeat_forward,
@@ -529,6 +529,18 @@ interface
asmcputype : cpu_none;
fputype : fpu_x87;
{$endif i8086}
+ {$ifdef riscv32}
+ cputype : cpu_rv32imafd;
+ optimizecputype : cpu_rv32imafd;
+ asmcputype : cpu_none;
+ fputype : fpu_fd;
+ {$endif riscv32}
+ {$ifdef riscv64}
+ cputype : cpu_rv64imafdc;
+ optimizecputype : cpu_rv64imafdc;
+ asmcputype : cpu_none;
+ fputype : fpu_fd;
+ {$endif riscv64}
{$endif not GENERIC_CPU}
asmmode : asmmode_standard;
{$ifndef jvm}
diff --git a/compiler/globtype.pas b/compiler/globtype.pas
index 7d23464d57..d763caa02d 100644
--- a/compiler/globtype.pas
+++ b/compiler/globtype.pas
@@ -148,7 +148,7 @@ interface
cs_full_boolean_eval,cs_typed_const_writable,cs_allow_enum_calc,
cs_do_inline,cs_fpu_fwait,cs_ieee_errors,
cs_check_low_addr_load,cs_imported_data,
- cs_excessprecision,
+ cs_excessprecision,cs_check_fpu_exceptions,
{ mmx }
cs_mmx,cs_mmx_saturation,
{ parser }
diff --git a/compiler/msg/errore.msg b/compiler/msg/errore.msg
index 3776bb3dc6..c32195aab6 100644
--- a/compiler/msg/errore.msg
+++ b/compiler/msg/errore.msg
@@ -3814,6 +3814,7 @@ S*2Aas_Assemble using GNU AS
**2Cc<x>_Set default calling convention to <x>
**2CD_Create also dynamic library (not supported)
**2Ce_Compilation with emulated floating point opcodes
+**2CE_Generate FPU code which can raise exceptions
**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for possible values
**2CF<x>_Minimal floating point constant precision (default, 32, 64)
**2Cg_Generate PIC code
diff --git a/compiler/msgidx.inc b/compiler/msgidx.inc
index 4a3fb12872..411162efc1 100644
--- a/compiler/msgidx.inc
+++ b/compiler/msgidx.inc
@@ -1105,7 +1105,7 @@ const
option_info=11024;
option_help_pages=11025;
- MsgTxtSize = 82541;
+ MsgTxtSize = 82592;
MsgIdxMax : array[1..20] of longint=(
28,106,349,126,98,59,142,34,221,67,
diff --git a/compiler/msgtxt.inc b/compiler/msgtxt.inc
index d78cb82961..95464e6df6 100644
--- a/compiler/msgtxt.inc
+++ b/compiler/msgtxt.inc
@@ -1,8 +1,8 @@
const msgtxt_codepage=20127;
{$ifdef Delphi}
-const msgtxt : array[0..000343] of string[240]=(
+const msgtxt : array[0..000344] of string[240]=(
{$else Delphi}
-const msgtxt : array[0..000343,1..240] of char=(
+const msgtxt : array[0..000344,1..240] of char=(
{$endif Delphi}
'01000_T_Compiler: $1'#000+
'01001_D_Compiler OS: $1'#000+
@@ -1463,222 +1463,223 @@ const msgtxt : array[0..000343,1..240] of char=(
'**2Cc<x>_Set default calling convention to <x>'#010+
'**2CD_Create also dynamic library (not supported)'#010+
'**2','Ce_Compilation with emulated floating point opcodes'#010+
+ '**2CE_Generate FPU code which can raise exceptions'#010+
'**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+
'possible values'#010+
- '**2CF<x>_Minimal floating point constant precision (default, 32, 64)'#010+
+ '**2CF<x>_Minimal floating point constant precision ','(default, 32, 64)'+
+ #010+
'**2Cg_Generate PIC code'#010+
- '**2Ch<n>[',',m]_<n> bytes min heap size (between 1023 and 67107840) and'+
- ' optionally [m] max heap size'#010+
+ '**2Ch<n>[,m]_<n> bytes min heap size (between 1023 and 67107840) and o'+
+ 'ptionally [m] max heap size'#010+
'**2Ci_IO-checking'#010+
'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#010+
'**2Cn_Omit linking stage'#010+
- 'P*2CN_Generate nil-pointer checks (AIX-only)'#010+
- '**2Co_Chec','k overflow of integer operations'#010+
+ 'P*2C','N_Generate nil-pointer checks (AIX-only)'#010+
+ '**2Co_Check overflow of integer operations'#010+
'**2CO_Check for possible overflow of integer operations'#010+
'**2Cp<x>_Select instruction set; see fpc -i or fpc -ic for possible va'+
'lues'#010+
- '**2CP<x>=<y>_ packing settings'#010+
- '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or',' DEFAULT or NORMAL, 2, '+
- '4 and 8'#010+
+ '**2CP<x>=<y>_ packing set','tings'#010+
+ '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
+ 'and 8'#010+
'**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
'L'#010+
'**3CPPACKRECORD=<y>_ <y> record packing: 0 or DEFAULT or NORMAL, 1, 2,'+
- ' 4, 8, 16 and 32'#010+
+ ' 4, 8, 16 and 32',#010+
'**2Cr_Range checking'#010+
- '**2CR_Verify object method ca','ll validity'#010+
+ '**2CR_Verify object method call validity'#010+
'**2Cs<n>_Set stack checking size to <n>'#010+
'**2Ct_Stack checking (for testing only, see manual)'#010+
'8*2CT<x>_Target-specific code generation options'#010+
- '3*2CT<x>_Target-specific code generation options'#010+
- '4*2CT<x>_Target-specific code generati','on options'#010+
+ '3*2CT<x>_Target-specific code genera','tion options'#010+
+ '4*2CT<x>_Target-specific code generation options'#010+
'p*2CT<x>_Target-specific code generation options'#010+
'P*2CT<x>_Target-specific code generation options'#010+
'J*2CT<x>_Target-specific code generation options'#010+
- 'A*2CT<x>_Target-specific code generation options'#010+
- 'p*3CTsmalltoc_ Generate smaller T','OCs at the expense of execution spe'+
- 'ed (AIX)'#010+
+ 'A*2CT<x>_Target-specific code g','eneration options'#010+
+ 'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
+ ' (AIX)'#010+
'P*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
' (AIX)'#010+
- 'J*3CTautogetterprefix=X_ Automatically create getters for properties '+
+ 'J*3CTautogetterprefix=X_ Automatically create getters for propertie','s'+
+ ' with prefix X (empty string disables)'#010+
+ 'J*3CTautosetterprefix=X_ Automatically create setters for properties '+
'with prefix X (empty string disables)'#010+
- 'J*3CTautose','tterprefix=X_ Automatically create setters for propertie'+
- 's with prefix X (empty string disables)'#010+
'8*3CTcld_ Emit a CLD instruction before using the x86 '+
'string instructions'#010+
- '3*3CTcld_ Emit a CLD instruction befo','re using the x8'+
+ '3*','3CTcld_ Emit a CLD instruction before using the x8'+
'6 string instructions'#010+
'4*3CTcld_ Emit a CLD instruction before using the x86 '+
'string instructions'#010+
- '8*3CTfarprocspushoddbp_ Increment BP before pushing it in the pr'+
- 'ologue of far functions'#010+
- 'J*3CTcompactintarra','yinit_ Generate smaller (but potentially slower) '+
- 'code for initializing integer array constants'#010+
+ '8*3CTfarprocspushoddbp_ Increment BP before pushing it i','n the '+
+ 'prologue of far functions'#010+
+ 'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+
+ 'de for initializing integer array constants'#010+
'J*3CTenumfieldinit_ Initialize enumeration fields in constructor'+
- 's to enumtype(0), after calling inherited constructors'#010+
- 'J*3CTinitlocals_ ',' Initialize local variables that trigger a '+
- 'JVM bytecode verification error if used uninitialized (slows down code'+
- ')'#010+
- 'J*3CTlowercaseprocstart_ Lowercase the first character of procedure/f'+
- 'unction/method names'#010+
- 'A*3CTthumbinterworking_ Gener','ate Thumb interworking-safe code if pos'+
- 'sible'#010+
+ 's to enumtype(0), after ','calling inherited constructors'#010+
+ 'J*3CTinitlocals_ Initialize local variables that trigger a JV'+
+ 'M bytecode verification error if used uninitialized (slows down code)'#010+
+ 'J*3CTlowercaseprocstart_ Lowercase the first character of procedure/',
+ 'function/method names'#010+
+ 'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+
+ 'ble'#010+
'J*2Cv_Var/out parameter copy-out checking'#010+
'**2CX_Create also smartlinked library'#010+
'**1d<x>_Defines the symbol <x>'#010+
'**1D_Generate a DEF file'#010+
- '**2Dd<x>_Set description to <x>'#010+
- '**2Dv<x>_Set DLL version to',' <x>'#010+
+ '**2Dd<x>','_Set description to <x>'#010+
+ '**2Dv<x>_Set DLL version to <x>'#010+
'*O2Dw_PM application'#010+
'**1e<x>_Set path to executable'#010+
'**1E_Same as -Cn'#010+
'**1fPIC_Same as -Cg'#010+
'**1F<x>_Set file names and paths:'#010+
- '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
- 'sed'#010+
+ '**2Fa<x>[,y]_(for a program) load units <x> and [y] before us','es is p'+
+ 'arsed'#010+
'**2Fc<x>_Set input codepage to <x>'#010+
- '**2','FC<x>_Set RC compiler binary name to <x>'#010+
+ '**2FC<x>_Set RC compiler binary name to <x>'#010+
'**2Fd_Disable the compiler'#039's internal directory cache'#010+
'**2FD<x>_Set the directory where to search for compiler utilities'#010+
- '**2Fe<x>_Redirect error output to <x>'#010+
- '**2Ff<x>_Add <x> to framework path (Darwi','n only)'#010+
+ '**2Fe<x>_Redirect error outp','ut to <x>'#010+
+ '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
'**2FE<x>_Set exe/unit output path to <x>'#010+
'**2Fi<x>_Add <x> to include path'#010+
'**2Fl<x>_Add <x> to library path'#010+
'**2FL<x>_Use <x> as dynamic linker'#010+
- '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
- 'r'#010+
- '**2FM<x>_Set the d','irectory where to search for unicode binary files'#010+
+ '**2Fm<x>_Load unicode conversion table ','from <x>.txt in the compiler '+
+ 'dir'#010+
+ '**2FM<x>_Set the directory where to search for unicode binary files'#010+
'**2FN<x>_Add <x> to list of default unit scopes (namespaces)'#010+
'**2Fo<x>_Add <x> to object path'#010+
'**2Fr<x>_Load error message file <x>'#010+
- '**2FR<x>_Set resource (.res) linker to <x>'#010+
- '**2Fu<x>_Add <x> ','to unit path'#010+
+ '**2FR<x>_','Set resource (.res) linker to <x>'#010+
+ '**2Fu<x>_Add <x> to unit path'#010+
'**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
'**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+
- '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+
- 'om <x>'#010+
- '*g1g_Generate debug informatio','n (default format for target)'#010+
+ '**2Fw<x>_Load previously stored whole-program optimizati','on feedback '+
+ 'from <x>'#010+
+ '*g1g_Generate debug information (default format for target)'#010+
'*g2gc_Generate checks for pointers (experimental, only available on so'+
'me targets, might generate false positive)'#010+
- '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
- '*g2gl_Use line info unit (show mo','re info with backtraces)'#010+
+ '*g2gh_Use heaptrace unit (for memory leak/corr','uption debugging)'#010+
+ '*g2gl_Use line info unit (show more info with backtraces)'#010+
'*g2gm_Generate Microsoft CodeView debug information (experimental)'#010+
'*g2go<x>_Set debug information options'#010+
- '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+
- 'aks gdb < 6.5)'#010+
- '*g3gostabsabsincludes_ Store abs','olute/full include file paths in Sta'+
- 'bs'#010+
+ '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information ','(b'+
+ 'reaks gdb < 6.5)'#010+
+ '*g3gostabsabsincludes_ Store absolute/full include file paths in Stabs'+
+ #010+
'*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+
'ame'#010+
'*g3godwarfcpp_ Simulate C++ debug information in DWARF'#010+
- '*g3godwarfomflinnum_ Generate line number information in OMF LINNUM re'+
- 'co','rds in MS LINK format in addition to the DWARF debug information ('+
+ '*g3godwarfomflinnum_ ','Generate line number information in OMF LINNUM '+
+ 'records in MS LINK format in addition to the DWARF debug information ('+
'Open Watcom Debugger/Linker compatibility)'#010+
'*g2gp_Preserve case in stabs symbol names'#010+
- '*g2gs_Generate Stabs debug information'#010+
- '*g2gt_Trash local variables (to detect uninitializ','ed uses; multiple '+
- #039't'#039' changes the trashing value)'#010+
+ '*g2gs_Generate Stabs debug information',#010+
+ '*g2gt_Trash local variables (to detect uninitialized uses; multiple '#039+
+ 't'#039' changes the trashing value)'#010+
'*g2gv_Generates programs traceable with Valgrind'#010+
'*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
- '*g2gw2_Generate DWARFv2 debug information'#010+
+ '*g2gw2_Generate DWARFv2 debug info','rmation'#010+
'*g2gw3_Generate DWARFv3 debug information'#010+
- '*','g2gw4_Generate DWARFv4 debug information (experimental)'#010+
+ '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+
'**1i_Information'#010+
'**2iD_Return compiler date'#010+
'**2iSO_Return compiler OS'#010+
'**2iSP_Return compiler host processor'#010+
'**2iTO_Return target OS'#010+
- '**2iTP_Return target processor'#010+
- '**2iV_Return short co','mpiler version'#010+
+ '*','*2iTP_Return target processor'#010+
+ '**2iV_Return short compiler version'#010+
'**2iW_Return full compiler version'#010+
'**2ia_Return list of supported ABI targets'#010+
'**2ic_Return list of supported CPU instruction sets'#010+
- '**2if_Return list of supported FPU instruction sets'#010+
- '**2ii_Return list of supported inline assem','bler modes'#010+
+ '**2if_Return list of supported FPU instructi','on sets'#010+
+ '**2ii_Return list of supported inline assembler modes'#010+
'**2io_Return list of supported optimizations'#010+
'**2ir_Return list of recognized compiler and RTL features'#010+
'**2it_Return list of supported targets'#010+
- '**2iu_Return list of supported microcontroller types'#010+
- '**2iw_Return list of supported who','le program optimizations'#010+
+ '**2iu_Return list of supported micro','controller types'#010+
+ '**2iw_Return list of supported whole program optimizations'#010+
'**1I<x>_Add <x> to include path'#010+
'**1k<x>_Pass <x> to the linker'#010+
'**1l_Write logo'#010+
'**1M<x>_Set language mode to <x>'#010+
'**2Mfpc_Free Pascal dialect (default)'#010+
- '**2Mobjfpc_FPC mode with Object Pascal support'#010+
- '**2Mdelphi_Delphi ','7 compatibility mode'#010+
+ '**2Mobjfpc_FPC',' mode with Object Pascal support'#010+
+ '**2Mdelphi_Delphi 7 compatibility mode'#010+
'**2Mtp_TP/BP 7.0 compatibility mode'#010+
'**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
'**2Miso_ISO 7185 mode'#010+
'**2Mextendedpascal_ISO 10206 mode'#010+
- '**2Mdelphiunicode_Delphi 2009 and later compatibility mode'#010+
- '**1n_Do not ','read the default config files'#010+
+ '**2Mdelphiunicode_De','lphi 2009 and later compatibility mode'#010+
+ '**1n_Do not read the default config files'#010+
'**1o<x>_Change the name of the executable produced to <x>'#010+
'**1O<x>_Optimizations:'#010+
'**2O-_Disable optimizations'#010+
- '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
- '**2O2_Level 2 optimizations (-O1 + quick op','timizations)'#010+
+ '**2O1_Level 1 optimizations (quick and debugger fr','iendly)'#010+
+ '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
'**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
'**2O4_Level 4 optimizations (-O3 + optimizations which might have unex'+
'pected side effects)'#010+
'**2Oa<x>=<y>_Set alignment'#010+
- '**2Oo[NO]<x>_Enable or disable optimizations; see fpc ','-i or fpc -io '+
+ '**2','Oo[NO]<x>_Enable or disable optimizations; see fpc -i or fpc -io '+
'for possible values'#010+
'**2Op<x>_Set target cpu for optimizing; see fpc -i or fpc -ic for poss'+
'ible values'#010+
'**2OW<x>_Generate whole-program optimization feedback for optimization'+
- ' <x>; see fpc -i or fpc -iw for possible values'#010+
- '**2Ow<','x>_Perform whole-program optimization <x>; see fpc -i or fpc -'+
- 'iw for possible values'#010+
+ ' <x','>; see fpc -i or fpc -iw for possible values'#010+
+ '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -iw'+
+ ' for possible values'#010+
'**2Os_Optimize for size rather than speed'#010+
'**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+
- 'F*1P<x>_Target CPU / compiler related options:'#010+
- 'F*2PB_','Show default compiler binary'#010+
+ 'F*','1P<x>_Target CPU / compiler related options:'#010+
+ 'F*2PB_Show default compiler binary'#010+
'F*2PP_Show default target cpu'#010+
'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mipse'+
'l,powerpc,powerpc64,sparc,x86_64)'#010+
- '**1R<x>_Assembler reading style:'#010+
- '**2Rdefault_Use default assembler for target',#010+
+ '**1R<x>_Assembler reading ','style:'#010+
+ '**2Rdefault_Use default assembler for target'#010+
'3*2Ratt_Read AT&T style assembler'#010+
'3*2Rintel_Read Intel style assembler'#010+
'4*2Ratt_Read AT&T style assembler'#010+
'4*2Rintel_Read Intel style assembler'#010+
'8*2Ratt_Read AT&T style assembler'#010+
- '8*2Rintel_Read Intel style assembler'#010+
- '6*2RMOT_Read Motorola styl','e assembler'#010+
+ '8*2Rintel_Re','ad Intel style assembler'#010+
+ '6*2RMOT_Read Motorola style assembler'#010+
'**1S<x>_Syntax options:'#010+
'**2S2_Same as -Mobjfpc'#010+
'**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
'**2Sa_Turn on assertions'#010+
'**2Sd_Same as -Mdelphi'#010+
- '**2Se<x>_Error options. <x> is a combination of the following:'#010+
- '**3*_<n> : Compiler h','alts after the <n> errors (default is 1)'#010+
+ '**2Se<x>_Error options. <x> is a ','combination of the following:'#010+
+ '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
'**3*_w : Compiler also halts after warnings'#010+
'**3*_n : Compiler also halts after notes'#010+
'**3*_h : Compiler also halts after hints'#010+
- '**2Sf_Enable certain features in compiler and RTL; see fpc -i or fpc -'+
- 'ir ','for possible values)'#010+
+ '**2Sf_Enable certain f','eatures in compiler and RTL; see fpc -i or fpc'+
+ ' -ir for possible values)'#010+
'**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
'**2Sh_Use reference counted strings (ansistring by default) instead of'+
' shortstrings'#010+
- '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
- '**2Sj_Al','lows typed constants to be writeable (default in all modes)'#010+
+ '**2Si_Turn on inlining of',' procedures/functions declared as "inline"'#010+
+ '**2Sj_Allows typed constants to be writeable (default in all modes)'#010+
'**2Sk_Load fpcylix unit'#010+
'**2SI<x>_Set interface style to <x>'#010+
'**3SIcom_COM compatible interface (default)'#010+
- '**3SIcorba_CORBA compatible interface'#010+
+ '**3SIcorba_CORBA compatib','le interface'#010+
'**2Sm_Support macros like C (global)'#010+
- '*','*2So_Same as -Mtp'#010+
+ '**2So_Same as -Mtp'#010+
'**2Sr_Transparent file names in ISO mode'#010+
'**2Ss_Constructor name must be init (destructor must be done)'#010+
- '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
- 'e)'#010+
- '**2Sx_Enable exception keywords (default in De','lphi/ObjFPC modes)'#010+
+ '**2Sv_Support vector processing (use CPU vector extensions if availa','b'+
+ 'le)'#010+
+ '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
'**2Sy_@<pointer> returns a typed pointer, same as $T+'#010+
'**1s_Do not call assembler and linker'#010+
'**2sh_Generate script to link on host'#010+
- '**2st_Generate script to link on target'#010+
- '**2sr_Skip register allocation phase (use with -alr',')'#010+
+ '**2st_Generate script to link on target'#010,
+ '**2sr_Skip register allocation phase (use with -alr)'#010+
'**1T<x>_Target operating system:'#010+
'3*2Tandroid_Android'#010+
'3*2Taros_AROS'#010+
@@ -1686,25 +1687,25 @@ const msgtxt : array[0..000343,1..240] of char=(
'3*2Tdarwin_Darwin/Mac OS X'#010+
'3*2Tembedded_Embedded'#010+
'3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
- '3*2Tfreebsd_FreeBSD'#010+
- '3*2Tgo32v2_Version 2 of DJ Delorie DOS',' extender'#010+
+ '3*2Tfre','ebsd_FreeBSD'#010+
+ '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
'3*2Thaiku_Haiku'#010+
'3*2Tiphonesim_iPhoneSimulator from iOS SDK 3.2+ (older versions: -Tdar'+
'win)'#010+
'3*2Tlinux_Linux'#010+
'3*2Tnativent_Native NT API (experimental)'#010+
'3*2Tnetbsd_NetBSD'#010+
- '3*2Tnetware_Novell Netware Module (clib)'#010+
- '3*2Tnetwlibc_Novell Ne','tware Module (libc)'#010+
+ '3*2Tnetware_','Novell Netware Module (clib)'#010+
+ '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
'3*2Topenbsd_OpenBSD'#010+
'3*2Tos2_OS/2 / eComStation'#010+
'3*2Tsymbian_Symbian OS'#010+
'3*2Tsolaris_Solaris'#010+
'3*2Twatcom_Watcom compatible DOS extender'#010+
'3*2Twdosx_WDOSX DOS extender'#010+
- '3*2Twin32_Windows 32 Bit'#010+
+ '3*2Twin3','2_Windows 32 Bit'#010+
'3*2Twince_Windows CE'#010+
- '4*2Taros_AROS',#010+
+ '4*2Taros_AROS'#010+
'4*2Tdarwin_Darwin/Mac OS X'#010+
'4*2Tdragonfly_DragonFly BSD'#010+
'4*2Tembedded_Embedded'#010+
@@ -1713,8 +1714,8 @@ const msgtxt : array[0..000343,1..240] of char=(
'4*2Tlinux_Linux'#010+
'4*2Tnetbsd_NetBSD'#010+
'4*2Topenbsd_OpenBSD'#010+
- '4*2Tsolaris_Solaris'#010+
- '4*2Twin64_Win64 (64 bit Windows system','s)'#010+
+ '4*2Tsol','aris_Solaris'#010+
+ '4*2Twin64_Win64 (64 bit Windows systems)'#010+
'6*2Tamiga_Commodore Amiga'#010+
'6*2Tatari_Atari ST/STe/TT'#010+
'6*2Tembedded_Embedded'#010+
@@ -1723,9 +1724,9 @@ const msgtxt : array[0..000343,1..240] of char=(
'6*2Tmacos_Mac OS'#010+
'6*2Tpalmos_PalmOS'#010+
'8*2Tembedded_Embedded'#010+
- '8*2Tmsdos_MS-DOS (and compatible)'#010+
+ '8*2Tmsdos_MS-DOS (and',' compatible)'#010+
'8*2Twin16_Windows 16 Bit'#010+
- 'A*2Tandroid_A','ndroid'#010+
+ 'A*2Tandroid_Android'#010+
'A*2Taros_AROS'#010+
'A*2Tdarwin_Darwin/iPhoneOS/iOS'#010+
'A*2Tembedded_Embedded'#010+
@@ -1734,10 +1735,10 @@ const msgtxt : array[0..000343,1..240] of char=(
'A*2Tnds_Nintendo DS'#010+
'A*2Tnetbsd_NetBSD'#010+
'A*2Tpalmos_PalmOS'#010+
- 'A*2Tsymbian_Symbian'#010+
+ 'A*2Tsymbian_Symbia','n'#010+
'A*2Twince_Windows CE'#010+
'a*2Tdarwin_Darwin/iOS'#010+
- 'a*2Tli','nux_Linux'#010+
+ 'a*2Tlinux_Linux'#010+
'J*2Tandroid_Android'#010+
'J*2Tjava_Java'#010+
'm*2Tandroid_Android'#010+
@@ -1747,10 +1748,10 @@ const msgtxt : array[0..000343,1..240] of char=(
'M*2Tlinux_Linux'#010+
'P*2Taix_AIX'#010+
'P*2Tamiga_AmigaOS'#010+
- 'P*2Tdarwin_Darwin/Mac OS X'#010+
+ 'P*2Tdarwin_Darwin/M','ac OS X'#010+
'P*2Tembedded_Embedded'#010+
'P*2Tlinux_Linux'#010+
- 'P*2Tm','acos_Mac OS (classic)'#010+
+ 'P*2Tmacos_Mac OS (classic)'#010+
'P*2Tmorphos_MorphOS'#010+
'P*2Tnetbsd_NetBSD'#010+
'P*2Twii_Wii'#010+
@@ -1760,147 +1761,147 @@ const msgtxt : array[0..000343,1..240] of char=(
'p*2Tlinux_Linux'#010+
'S*2Tlinux_Linux'#010+
'S*2Tsolaris_Solaris'#010+
- 's*2Tlinux_Linux'#010+
+ 's*2T','linux_Linux'#010+
'V*2Tembedded_Embedded'#010+
- '**1u<x>_Undefines',' the symbol <x>'#010+
+ '**1u<x>_Undefines the symbol <x>'#010+
'**1U_Unit options:'#010+
'**2Un_Do not check where the unit name matches the file name'#010+
'**2Ur_Generate release unit files (never automatically recompiled)'#010+
- '**2Us_Compile a system unit'#010+
- '**1v<x>_Be verbose. <x> is a combination of the f','ollowing letters:'#010+
+ '**2Us_Compile a system uni','t'#010+
+ '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
'**2*_e : Show errors (default) 0 : Show nothing (except errors)'#010+
'**2*_w : Show warnings u : Show unit info'#010+
- '**2*_n : Show notes t : Show tried/used files'#010+
- '**2*_h : Show hints ',' c : Show conditionals'#010+
+ '**2*_n : Show notes t : Show',' tried/used files'#010+
+ '**2*_h : Show hints c : Show conditionals'#010+
'**2*_i : Show general info d : Show debug info'#010+
'**2*_l : Show linenumbers r : Rhide/GCC compatibility mode'#010+
- '**2*_s : Show time stamps q : Show message numbers'#010+
- '**2*_a : Show everything ',' x : Show info about invoked too'+
- 'ls'#010+
+ '**2*_s : Show time stamps ',' q : Show message numbers'#010+
+ '**2*_a : Show everything x : Show info about invoked tools'+
+ #010+
'**2*_b : Write file names messages p : Write tree.log with parse tre'+
'e'#010+
'**2*_ with full path v : Write fpcdebug.txt with'#010+
- '**2*_z : Write output to stderr lots of debuggin','g info'#010+
+ '**2*_z',' : Write output to stderr lots of debugging info'#010+
'**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+
'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+
'or version)'#010+
'**1W<x>_Target-specific options (targets)'#010+
- '3*2WA_Specify native type application (Windows)'#010+
- '4*2WA_Speci','fy native type application (Windows)'#010+
+ '3*2WA_Sp','ecify native type application (Windows)'#010+
+ '4*2WA_Specify native type application (Windows)'#010+
'A*2WA_Specify native type application (Windows)'#010+
'3*2Wb_Create a bundle instead of a library (Darwin)'#010+
- 'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
- 'p*2Wb_Create a bundle instead of a library (Darwin)',#010+
+ 'P*2Wb_Create a bundle instead of a library (Darwin)'#010,
+ 'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
'a*2Wb_Create a bundle instead of a library (Darwin)'#010+
'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
'4*2Wb_Create a bundle instead of a library (Darwin)'#010+
- '3*2WB_Create a relocatable image (Windows, Symbian)'#010+
- '3*2WB<x>_Set image base to <x> ','(Windows, Symbian)'#010+
+ '3*2WB_Create a relocatable image',' (Windows, Symbian)'#010+
+ '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
'4*2WB_Create a relocatable image (Windows)'#010+
'4*2WB<x>_Set image base to <x> (Windows)'#010+
'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
- 'A*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
- '3*2WC_Specify console type applicat','ion (EMX, OS/2, Windows)'#010+
+ 'A*2WB<x>_Set image base to <x> (Wi','ndows, Symbian)'#010+
+ '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
'4*2WC_Specify console type application (Windows)'#010+
'A*2WC_Specify console type application (Windows)'#010+
'P*2WC_Specify console type application (Classic Mac OS)'#010+
- '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)',#010+
+ '3*2WD_Use ','DEFFILE to export functions of DLL or EXE (Windows)'#010+
'4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
'3*2We_Use external resources (Darwin)'#010+
- '4*2We_Use external resources (Darwin)'#010+
+ '4*2We_Use external resourc','es (Darwin)'#010+
'a*2We_Use external resources (Darwin)'#010+
- 'A','*2We_Use external resources (Darwin)'#010+
+ 'A*2We_Use external resources (Darwin)'#010+
'P*2We_Use external resources (Darwin)'#010+
'p*2We_Use external resources (Darwin)'#010+
'3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
- '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
- '4*2WG_Specif','y graphic type application (Windows)'#010+
+ '3*2WG_Specify graphic',' type application (EMX, OS/2, Windows)'#010+
+ '4*2WG_Specify graphic type application (Windows)'#010+
'A*2WG_Specify graphic type application (Windows)'#010+
'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
'3*2Wi_Use internal resources (Darwin)'#010+
- '4*2Wi_Use internal resources (Darwin)'#010+
- 'a*2Wi_Use internal res','ources (Darwin)'#010+
+ '4*2Wi_Use',' internal resources (Darwin)'#010+
+ 'a*2Wi_Use internal resources (Darwin)'#010+
'A*2Wi_Use internal resources (Darwin)'#010+
'P*2Wi_Use internal resources (Darwin)'#010+
'p*2Wi_Use internal resources (Darwin)'#010+
'3*2WI_Turn on/off the usage of import sections (Windows)'#010+
- '4*2WI_Turn on/off the usage of import sections (Windo','ws)'#010+
+ '4*','2WI_Turn on/off the usage of import sections (Windows)'#010+
'A*2WI_Turn on/off the usage of import sections (Windows)'#010+
'8*2Wh_Use huge code for units (ignored for models with CODE in a uniqu'+
'e segment)'#010+
'8*2Wm<x>_Set memory model'#010+
- '8*3WmTiny_Tiny memory model'#010+
+ '8*3WmTiny_Tiny memory',' model'#010+
'8*3WmSmall_Small memory model (default)'#010+
- '8*3W','mMedium_Medium memory model'#010+
+ '8*3WmMedium_Medium memory model'#010+
'8*3WmCompact_Compact memory model'#010+
'8*3WmLarge_Large memory model'#010+
'8*3WmHuge_Huge memory model'#010+
- '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
+ '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darw',
+ 'in)'#010+
+ '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
'n)'#010+
- '4*2WM<x>_Minimum Mac OS X deployment version: 1','0.4, 10.5.1, ... (Dar'+
- 'win)'#010+
'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
'n)'#010+
'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
'n)'#010+
- '3*2WN_Do not generate relocation code, needed for debugging (Windows',')'+
- #010+
+ '3*2WN_Do not gene','rate relocation code, needed for debugging (Windows'+
+ ')'#010+
'4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
- 'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
- 'le values'#010+
- 'm*2Wp<x>_Specify t','he controller type; see fpc -i or fpc -iu for poss'+
+ 'A*2Wp<x>_Specify the controller type; see fpc -','i or fpc -iu for poss'+
'ible values'#010+
+ 'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
+ 'le values'#010+
'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
'le values'#010+
- '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)'#010+
- '4*2WP<x>_Minimum iOS deployme','nt version: 8.0, 8.0.2, ... (iphonesim)'+
+ '3*2WP<x>_Minimum iOS deployment version: 3.0, 5','.0.1, ... (iphonesim)'+
#010+
+ '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+
'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010+
- '3*2WR_Generate relocation code (Windows)'#010+
- '4*2WR_Generate relocation c','ode (Windows)'#010+
+ '3*2WR_Generate re','location code (Windows)'#010+
+ '4*2WR_Generate relocation code (Windows)'#010+
'A*2WR_Generate relocation code (Windows)'#010+
'8*2Wt<x>_Set the target executable format'#010+
'8*3Wtexe_Create a DOS .EXE file (default)'#010+
- '8*3Wtcom_Create a DOS .COM file (requires tiny memory model)'#010+
- 'P*2WT_Specify MPW tool type application ','(Classic Mac OS)'#010+
+ '8*3Wtcom_Create a DOS .COM file (requires tiny mem','ory model)'#010+
+ 'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
'**2WX_Enable executable stack (Linux)'#010+
'**1X_Executable options:'#010+
'**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
'9.1 (Linux)'#010+
- '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
- 'ux)'#010+
- '**2X','d_Do not search default library path (sometimes required for cro'+
- 'ss-compiling when not using -XR)'#010+
+ '**2Xc_Pass --shared/-dynami','c to the linker (BeOS, Darwin, FreeBSD, L'+
+ 'inux)'#010+
+ '**2Xd_Do not search default library path (sometimes required for cross'+
+ '-compiling when not using -XR)'#010+
'**2Xe_Use external linker'#010+
'**2Xf_Substitute pthread library name for linking (BSD)'#010+
- '**2Xg_Create debuginfo in a separate file and add a debuglink',' sectio'+
+ '**2Xg_Crea','te debuginfo in a separate file and add a debuglink sectio'+
'n to executable'#010+
'**2XD_Try to link units dynamically (defines FPC_LINK_DYNAMIC)'#010+
'**2Xi_Use internal linker'#010+
'**2XLA_Define library substitutions for linking'#010+
- '**2XLO_Define order of library linking'#010+
- '**2XLD_Exclude default order of stan','dard libraries'#010+
+ '**2XLO_Define order of l','ibrary linking'#010+
+ '**2XLD_Exclude default order of standard libraries'#010+
'**2Xm_Generate link map'#010+
'**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
's '#039'main'#039')'#010+
'**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
#010+
- 'F*2Xp<x>_First search for the compiler binary in the direc','tory <x>'#010+
+ 'F*2Xp<x','>_First search for the compiler binary in the directory <x>'#010+
'**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
'**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+
- 'ile, see the ld manual for more information) (BeOS, Linux)'#010+
- '**2XR<x>_Prepend <x> to all linker search paths (B','eOS, Darwin, FreeB'+
- 'SD, Linux, Mac OS, Solaris)'#010+
+ 'ile, see the ld manual for more information) (BeOS, Linux)',#010+
+ '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
+ ', Linux, Mac OS, Solaris)'#010+
'**2Xs_Strip all symbols from executable'#010+
'**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
- '**2Xt_Link with static libraries (-static is passed to linker)'#010+
- '**2Xv_Generate table ','for Virtual Entry calls'#010+
+ '**2Xt_Link with static libraries ','(-static is passed to linker)'#010+
+ '**2Xv_Generate table for Virtual Entry calls'#010+
'**2XV_Use VLink as external linker (default on Amiga, MorphOS)'#010+
'**2XX_Try to smartlink units (defines FPC_LINK_SMART)'#010+
'**1*_'#010+
'**1?_Show this help'#010+
- '**1h_Shows this help without waiting'
+ '**1h','_Shows this help without waiting'
);
diff --git a/compiler/nadd.pas b/compiler/nadd.pas
index 9cf5da39a9..04ad7952d6 100644
--- a/compiler/nadd.pas
+++ b/compiler/nadd.pas
@@ -1095,7 +1095,7 @@ implementation
end;
end
{ short to full boolean evalution possible and useful? }
- else if not(might_have_sideeffects(right)) and not(cs_full_boolean_eval in localswitches) then
+ else if not(might_have_sideeffects(right,[mhs_exceptions])) and not(cs_full_boolean_eval in localswitches) then
begin
case nodetype of
andn,orn:
diff --git a/compiler/ncal.pas b/compiler/ncal.pas
index b93e2eeffd..e87272a467 100644
--- a/compiler/ncal.pas
+++ b/compiler/ncal.pas
@@ -56,7 +56,8 @@ interface
cnf_call_never_returns, { information for the dfa that a subroutine never returns }
cnf_call_self_node_done,{ the call_self_node has been generated if necessary
(to prevent it from potentially happening again in a wrong context in case of constant propagation or so) }
- cnf_ignore_visibility { internally generated call that should ignore visibility checks }
+ cnf_ignore_visibility, { internally generated call that should ignore visibility checks }
+ cnf_check_fpu_exceptions { after the call fpu exceptions shall be checked }
);
tcallnodeflags = set of tcallnodeflag;
diff --git a/compiler/ncgcal.pas b/compiler/ncgcal.pas
index 490f2934ab..be9705da5f 100644
--- a/compiler/ncgcal.pas
+++ b/compiler/ncgcal.pas
@@ -1272,6 +1272,10 @@ implementation
{ release temps of paras }
release_para_temps;
+ { check for fpu exceptions }
+ if cnf_check_fpu_exceptions in callnodeflags then
+ cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+
{ perhaps i/o check ? }
if (cs_check_io in current_settings.localswitches) and
(po_iocheck in procdefinition.procoptions) and
diff --git a/compiler/ninl.pas b/compiler/ninl.pas
index 53beb4e816..ee0c386682 100644
--- a/compiler/ninl.pas
+++ b/compiler/ninl.pas
@@ -4028,7 +4028,7 @@ implementation
begin
{ create the call to the helper }
{ on entry left node contains the parameter }
- first_arctan_real := ccallnode.createintern('fpc_arctan_real',
+ result := ccallnode.createintern('fpc_arctan_real',
ccallparanode.create(left,nil));
left := nil;
end;
@@ -4037,8 +4037,9 @@ implementation
begin
{ create the call to the helper }
{ on entry left node contains the parameter }
- first_abs_real := ctypeconvnode.create(ccallnode.createintern('fpc_abs_real',
+ result := ctypeconvnode.create(ccallnode.createintern('fpc_abs_real',
ccallparanode.create(left,nil)),resultdef);
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4051,8 +4052,9 @@ implementation
{$endif cpufpemu}
{ create the call to the helper }
{ on entry left node contains the parameter }
- first_sqr_real := ctypeconvnode.create(ccallnode.createintern('fpc_sqr_real',
+ result := ctypeconvnode.create(ccallnode.createintern('fpc_sqr_real',
ccallparanode.create(left,nil)),resultdef);
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4084,15 +4086,16 @@ implementation
else
internalerror(2014052101);
end;
- first_sqrt_real:=ctypeconvnode.create_internal(ccallnode.createintern(procname,ccallparanode.create(
+ result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,ccallparanode.create(
ctypeconvnode.create_internal(left,fdef),nil)),resultdef);
end
else
begin
{ create the call to the helper }
{ on entry left node contains the parameter }
- first_sqrt_real := ctypeconvnode.create(ccallnode.createintern('fpc_sqrt_real',
+ result := ctypeconvnode.create(ccallnode.createintern('fpc_sqrt_real',
ccallparanode.create(left,nil)),resultdef);
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
end;
left := nil;
end;
@@ -4101,8 +4104,9 @@ implementation
begin
{ create the call to the helper }
{ on entry left node contains the parameter }
- first_ln_real := ccallnode.createintern('fpc_ln_real',
+ result := ccallnode.createintern('fpc_ln_real',
ccallparanode.create(left,nil));
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4110,8 +4114,9 @@ implementation
begin
{ create the call to the helper }
{ on entry left node contains the parameter }
- first_cos_real := ccallnode.createintern('fpc_cos_real',
+ result := ccallnode.createintern('fpc_cos_real',
ccallparanode.create(left,nil));
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4119,8 +4124,9 @@ implementation
begin
{ create the call to the helper }
{ on entry left node contains the parameter }
- first_sin_real := ccallnode.createintern('fpc_sin_real',
+ result := ccallnode.createintern('fpc_sin_real',
ccallparanode.create(left,nil));
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4129,6 +4135,7 @@ implementation
{ create the call to the helper }
{ on entry left node contains the parameter }
result := ccallnode.createintern('fpc_exp_real',ccallparanode.create(left,nil));
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4137,6 +4144,7 @@ implementation
{ create the call to the helper }
{ on entry left node contains the parameter }
result := ccallnode.createintern('fpc_int_real',ccallparanode.create(left,nil));
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4145,6 +4153,7 @@ implementation
{ create the call to the helper }
{ on entry left node contains the parameter }
result := ccallnode.createintern('fpc_frac_real',ccallparanode.create(left,nil));
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4153,6 +4162,7 @@ implementation
{ create the call to the helper }
{ on entry left node contains the parameter }
result := ccallnode.createintern('fpc_round_real',ccallparanode.create(left,nil));
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
@@ -4161,6 +4171,7 @@ implementation
{ create the call to the helper }
{ on entry left node contains the parameter }
result := ccallnode.createintern('fpc_trunc_real',ccallparanode.create(left,nil));
+ include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
left := nil;
end;
diff --git a/compiler/nutils.pas b/compiler/nutils.pas
index c6d1b1e804..c276217800 100644
--- a/compiler/nutils.pas
+++ b/compiler/nutils.pas
@@ -54,6 +54,14 @@ interface
then the parent node is processed again }
pm_postandagain);
+
+ tmhs_flag = (
+ { exceptions (overflow, sigfault etc.) are considered as side effect }
+ mhs_exceptions
+ );
+ tmhs_flags = set of tmhs_flag;
+ pmhs_flags = ^tmhs_flags;
+
foreachnodefunction = function(var n: tnode; arg: pointer): foreachnoderesult of object;
staticforeachnodefunction = function(var n: tnode; arg: pointer): foreachnoderesult;
@@ -117,7 +125,7 @@ interface
function genloadfield(n: tnode; const fieldname: string): tnode;
{ returns true, if the tree given might have side effects }
- function might_have_sideeffects(n : tnode) : boolean;
+ function might_have_sideeffects(n : tnode;const flags : tmhs_flags = []) : boolean;
{ count the number of nodes in the node tree,
rough estimation how large the tree "node" is }
@@ -153,6 +161,10 @@ interface
{ include or exclude cs from p.localswitches }
procedure node_change_local_switch(p : tnode;cs : tlocalswitch;enable : boolean);
+ { returns true, if p is a node which shall be short boolean evaluated,
+ if it is not an orn/andn with boolean operans, the result is undefined }
+ function doshortbooleval(p : tnode) : Boolean;
+
implementation
uses
@@ -1334,13 +1346,19 @@ implementation
in_finalize_x,in_new_x,in_dispose_x,in_exit,in_copy_x,in_initialize_x,in_leave,in_cycle,
in_and_assign_x_y,in_or_assign_x_y,in_xor_assign_x_y,in_sar_assign_x_y,in_shl_assign_x_y,
in_shr_assign_x_y,in_rol_assign_x_y,in_ror_assign_x_y,in_neg_assign_x,in_not_assign_x])
+ ) or
+ ((mhs_exceptions in pmhs_flags(arg)^) and
+ ((n.nodetype in [derefn,vecn,subscriptn]) or
+ ((n.nodetype in [addn,subn,muln,divn,slashn,unaryminusn]) and (n.localswitches*[cs_check_overflow,cs_check_range]<>[]))
+ )
) then
result:=fen_norecurse_true;
end;
- function might_have_sideeffects(n : tnode) : boolean;
+
+ function might_have_sideeffects(n : tnode; const flags : tmhs_flags) : boolean;
begin
- result:=foreachnodestatic(n,@check_for_sideeffect,nil);
+ result:=foreachnodestatic(n,@check_for_sideeffect,@flags);
end;
var
@@ -1445,7 +1463,8 @@ implementation
exclude(p.localswitches, plocalswitchchange(plsc)^.cs);
result:=fen_true;
end;
-
+
+
procedure node_change_local_switch(p : tnode;cs : tlocalswitch;enable : boolean);
var
lsc : tlocalswitchchange;
@@ -1455,4 +1474,10 @@ implementation
foreachnodestatic(p,@do_change_local_settings,@lsc);
end;
+
+ function doshortbooleval(p : tnode) : Boolean;
+ begin
+ Result:=(p.nodetype in [orn,andn]) and ((nf_short_bool in taddnode(p).flags) or not(cs_full_boolean_eval in p.localswitches));
+ end;
+
end.
diff --git a/compiler/optcse.pas b/compiler/optcse.pas
index f04a65fd94..c34da85563 100644
--- a/compiler/optcse.pas
+++ b/compiler/optcse.pas
@@ -298,9 +298,9 @@ unit optcse;
if not(csedomain) then
begin
{ try to transform the tree to get better cse domains, consider:
- +
+ + (1)
/ \
- + C
+ (2) + C
/ \
A B
@@ -329,6 +329,9 @@ unit optcse;
(is_set(n.resultdef))
) then
while (n.nodetype=tbinarynode(n).left.nodetype) and
+ { if node (1) is fully boolean evaluated and node (2) not, we cannot do the swap as is might result in B being evaluated always,
+ the other way round is no problem, C is still evaluated only if needed }
+ (not(is_boolean(n.resultdef)) or not(n.nodetype in [andn,orn]) or doshortbooleval(n) or not(doshortbooleval(tbinarynode(n).left))) and
{ the resulttypes of the operands we'll swap must be equal,
required in case of a 32x32->64 multiplication, then we
cannot swap out one of the 32 bit operands for a 64 bit one
diff --git a/compiler/options.pas b/compiler/options.pas
index a5844254b5..2ef6f6a6da 100644
--- a/compiler/options.pas
+++ b/compiler/options.pas
@@ -135,7 +135,8 @@ const
+ [system_i386_GO32V2]
+ [system_i386_freebsd]
+ [system_i386_netbsd]
- + [system_i386_wdosx];
+ + [system_i386_wdosx]
+ + [system_riscv32_linux,system_riscv64_linux];
suppported_targets_x_smallr = systems_linux + systems_solaris
+ [system_i386_haiku]
@@ -695,6 +696,12 @@ begin
{$ifdef sparc64}
's',
{$endif}
+{$ifdef riscv32}
+ 'R',
+{$endif}
+{$ifdef riscv64}
+ 'r',
+{$endif}
{$ifdef avr}
'V',
{$endif}
@@ -1186,6 +1193,11 @@ begin
include(init_settings.moduleswitches,cs_fp_emulation);
end;
{$endif cpufpemu}
+ 'E' :
+ If UnsetBool(More, j, opt, false) then
+ exclude(init_settings.localswitches,cs_check_fpu_exceptions)
+ Else
+ include(init_settings.localswitches,cs_check_fpu_exceptions);
'f' :
begin
s:=upper(copy(more,j+1,length(more)-j));
@@ -3581,6 +3593,23 @@ procedure read_arguments(cmd:TCmdStr);
def_system_macro('FPC_COMP_IS_INT64');
{$endif aarch64}
+ {$ifdef riscv32}
+ def_system_macro('CPURISCV');
+ def_system_macro('CPURISCV32');
+ def_system_macro('CPU32');
+ def_system_macro('FPC_CURRENCY_IS_INT64');
+ def_system_macro('FPC_COMP_IS_INT64');
+ def_system_macro('FPC_REQUIRES_PROPER_ALIGNMENT');
+ {$endif riscv32}
+ {$ifdef riscv64}
+ def_system_macro('CPURISCV');
+ def_system_macro('CPURISCV64');
+ 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');
+ {$endif riscv64}
+
{$if defined(cpu8bitalu)}
def_system_macro('CPUINT8');
{$elseif defined(cpu16bitalu)}
@@ -4012,12 +4041,13 @@ begin
if not(option.FPUSetExplicitly) and
((target_info.system in [system_arm_wince,system_arm_gba,
system_m68k_amiga,system_m68k_atari,
- system_arm_nds,system_arm_embedded])
+ system_arm_nds,system_arm_embedded,
+ system_riscv32_embedded,system_riscv64_embedded])
{$ifdef arm}
or (target_info.abi=abi_eabi)
{$endif arm}
)
-{$if defined(arm) or defined (m68k)}
+{$if defined(arm) or defined(riscv32) or defined(riscv64) or defined (m68k)}
or (init_settings.fputype=fpu_soft)
{$endif arm or m68k}
then
@@ -4121,6 +4151,32 @@ begin
def_system_macro('CPUTHUMB2');
{$endif arm}
+{$if defined(riscv32) or defined(riscv64)}
+ { ARMHF defaults }
+ if (target_info.abi = abi_riscv_hf) then
+ { set default cpu type to ARMv7a for ARMHF unless specified otherwise }
+ begin
+ if not option.CPUSetExplicitly then
+ init_settings.cputype:=cpu_rv64imafdc;
+ if not option.OptCPUSetExplicitly then
+ init_settings.optimizecputype:=cpu_rv64imafdc;
+
+ { Set FPU type }
+ if not(option.FPUSetExplicitly) then
+ begin
+ init_settings.fputype:=fpu_fd;
+ end
+ else
+ begin
+ if not (init_settings.fputype in [fpu_fd]) then
+ begin
+ Message(option_illegal_fpu_eabihf);
+ StopOptions(1);
+ end;
+ end;
+ end;
+{$endif defined(riscv32) or defined(riscv64)}
+
{$ifdef jvm}
{ set default CPU type to Dalvik when targeting Android }
if target_info.system=system_jvm_android32 then
diff --git a/compiler/pp.pas b/compiler/pp.pas
index aec3a42891..7dd479d360 100644
--- a/compiler/pp.pas
+++ b/compiler/pp.pas
@@ -37,6 +37,7 @@ program pp;
MIPSEL generate a compiler for the MIPSEL (Littel Endian)
POWERPC generate a compiler for the PowerPC
POWERPC64 generate a compiler for the PowerPC64 architecture
+ RISCV64 generate a compiler for the RiscV64 architecture
SPARC generate a compiler for SPARC
SPARC64 generate a compiler for SPARC64
X86_64 generate a compiler for the AMD x86-64 architecture
@@ -163,6 +164,18 @@ program pp;
{$endif CPUDEFINED}
{$define CPUDEFINED}
{$endif AARCH64}
+{$ifdef RISCV32}
+ {$ifdef CPUDEFINED}
+ {$fatal ONLY one of the switches for the CPU type must be defined}
+ {$endif CPUDEFINED}
+ {$define CPUDEFINED}
+{$endif RISCV32}
+{$ifdef RISCV64}
+ {$ifdef CPUDEFINED}
+ {$fatal ONLY one of the switches for the CPU type must be defined}
+ {$endif CPUDEFINED}
+ {$define CPUDEFINED}
+{$endif RISCV64}
{$ifndef CPUDEFINED}
{$fatal A CPU type switch must be defined}
diff --git a/compiler/ppcriscv32.lpi b/compiler/ppcriscv32.lpi
new file mode 100644
index 0000000000..2f948f5720
--- /dev/null
+++ b/compiler/ppcriscv32.lpi
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+ <ProjectOptions>
+ <Version Value="11"/>
+ <PathDelim Value="\"/>
+ <General>
+ <Flags>
+ <MainUnitHasUsesSectionForAllUnits Value="False"/>
+ <MainUnitHasCreateFormStatements Value="False"/>
+ <MainUnitHasTitleStatement Value="False"/>
+ <LRSInOutputDirectory Value="False"/>
+ </Flags>
+ <SessionStorage Value="InProjectDir"/>
+ <MainUnit Value="0"/>
+ <Title Value="ppcrv32"/>
+ </General>
+ <BuildModes Count="1">
+ <Item1 Name="default" Default="True"/>
+ </BuildModes>
+ <PublishOptions>
+ <Version Value="2"/>
+ <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+ <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+ </PublishOptions>
+ <RunParams>
+ <FormatVersion Value="2"/>
+ <Modes Count="1">
+ <Mode0 Name="default">
+ <local>
+ <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+ </local>
+ </Mode0>
+ </Modes>
+ </RunParams>
+ <Units Count="4">
+ <Unit0>
+ <Filename Value="pp.pas"/>
+ <IsPartOfProject Value="True"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="riscv32\aasmcpu.pas"/>
+ <IsPartOfProject Value="True"/>
+ </Unit1>
+ <Unit2>
+ <Filename Value="riscv32\aoptcpu.pas"/>
+ <IsPartOfProject Value="True"/>
+ </Unit2>
+ <Unit3>
+ <Filename Value="aopt.pas"/>
+ <IsPartOfProject Value="True"/>
+ </Unit3>
+ </Units>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="11"/>
+ <PathDelim Value="\"/>
+ <Target>
+ <Filename Value="riscv32\pp"/>
+ </Target>
+ <SearchPaths>
+ <IncludeFiles Value="riscv32;riscv"/>
+ <OtherUnitFiles Value="riscv32;riscv;systems"/>
+ <UnitOutputDirectory Value="riscv32\lazbuild"/>
+ </SearchPaths>
+ <Parsing>
+ <SyntaxOptions>
+ <CStyleOperator Value="False"/>
+ <AllowLabel Value="False"/>
+ <CPPInline Value="False"/>
+ <UseAnsiStrings Value="False"/>
+ </SyntaxOptions>
+ </Parsing>
+ <Other>
+ <Verbosity>
+ <ShowWarn Value="False"/>
+ <ShowNotes Value="False"/>
+ <ShowHints Value="False"/>
+ </Verbosity>
+ <ConfigFile>
+ <StopAfterErrCount Value="50"/>
+ </ConfigFile>
+ <CustomOptions Value="-driscv32
+-Sew"/>
+ </Other>
+ </CompilerOptions>
+</CONFIG>
diff --git a/compiler/ppcriscv64.lpi b/compiler/ppcriscv64.lpi
new file mode 100644
index 0000000000..04ff31e24d
--- /dev/null
+++ b/compiler/ppcriscv64.lpi
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+ <ProjectOptions>
+ <Version Value="11"/>
+ <PathDelim Value="\"/>
+ <General>
+ <Flags>
+ <MainUnitHasUsesSectionForAllUnits Value="False"/>
+ <MainUnitHasCreateFormStatements Value="False"/>
+ <MainUnitHasTitleStatement Value="False"/>
+ <LRSInOutputDirectory Value="False"/>
+ </Flags>
+ <SessionStorage Value="InProjectDir"/>
+ <MainUnit Value="0"/>
+ <Title Value="ppcriscv64"/>
+ </General>
+ <BuildModes Count="1">
+ <Item1 Name="default" Default="True"/>
+ </BuildModes>
+ <PublishOptions>
+ <Version Value="2"/>
+ <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+ <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+ </PublishOptions>
+ <RunParams>
+ <FormatVersion Value="2"/>
+ <Modes Count="1">
+ <Mode0 Name="default">
+ <local>
+ <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+ </local>
+ </Mode0>
+ </Modes>
+ </RunParams>
+ <Units Count="2">
+ <Unit0>
+ <Filename Value="pp.pas"/>
+ <IsPartOfProject Value="True"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="sparc64\aasmcpu.pas"/>
+ <IsPartOfProject Value="True"/>
+ </Unit1>
+ </Units>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="11"/>
+ <PathDelim Value="\"/>
+ <Target>
+ <Filename Value="riscv64\pp"/>
+ </Target>
+ <SearchPaths>
+ <IncludeFiles Value="riscv;riscv64"/>
+ <OtherUnitFiles Value="riscv;riscv64;systems"/>
+ <UnitOutputDirectory Value="riscv64\lazbuild"/>
+ </SearchPaths>
+ <Parsing>
+ <SyntaxOptions>
+ <CStyleOperator Value="False"/>
+ <AllowLabel Value="False"/>
+ <CPPInline Value="False"/>
+ <UseAnsiStrings Value="False"/>
+ </SyntaxOptions>
+ </Parsing>
+ <Other>
+ <Verbosity>
+ <ShowWarn Value="False"/>
+ <ShowNotes Value="False"/>
+ <ShowHints Value="False"/>
+ </Verbosity>
+ <ConfigFile>
+ <StopAfterErrCount Value="50"/>
+ </ConfigFile>
+ <CustomOptions Value="-driscv64
+-Sew"/>
+ </Other>
+ </CompilerOptions>
+</CONFIG>
diff --git a/compiler/psub.pas b/compiler/psub.pas
index a90fc2f80c..2b7a0563b5 100644
--- a/compiler/psub.pas
+++ b/compiler/psub.pas
@@ -990,7 +990,7 @@ implementation
end;
-{$if defined(i386) or defined(x86_64) or defined(arm)}
+{$if defined(i386) or defined(x86_64) or defined(arm) or defined(riscv32) or defined(riscv64)}
const
exception_flags: array[boolean] of tprocinfoflags = (
[],
diff --git a/compiler/psystem.pas b/compiler/psystem.pas
index 36caae6c8f..ac1b9c86da 100644
--- a/compiler/psystem.pas
+++ b/compiler/psystem.pas
@@ -346,6 +346,14 @@ implementation
create_fpu_types;
s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
{$endif mips}
+{$ifdef riscv32}
+ create_fpu_types;
+ s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
+{$endif riscv32}
+{$ifdef riscv64}
+ create_fpu_types;
+ s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
+{$endif riscv64}
{$ifdef jvm}
create_fpu_types;
s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
diff --git a/compiler/raatt.pas b/compiler/raatt.pas
index f9aa5dd298..a795ce3401 100644
--- a/compiler/raatt.pas
+++ b/compiler/raatt.pas
@@ -330,6 +330,22 @@ unit raatt;
end;
end;
{$endif aarch64}
+{$if defined(riscv32) or defined(riscv64)}
+ {
+ amo* instructions contain a postfix with size, and optionally memory ordering
+ fence* can contain memory type identifier
+ floating point instructions contain size, and optionally rounding mode
+ }
+ case c of
+ '.':
+ begin
+ repeat
+ actasmpattern:=actasmpattern+c;
+ c:=current_scanner.asmgetchar;
+ until not(c in ['a'..'z','A'..'Z','.']);
+ end;
+ end;
+{$endif riscv}
{ Opcode ? }
If is_asmopcode(upper(actasmpattern)) then
Begin
diff --git a/compiler/rautils.pas b/compiler/rautils.pas
index d676c05579..33a63c2f3d 100644
--- a/compiler/rautils.pas
+++ b/compiler/rautils.pas
@@ -45,7 +45,7 @@ type
TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL,
OPR_REFERENCE,OPR_REGISTER,OPR_COND,OPR_REGSET,
OPR_SHIFTEROP,OPR_MODEFLAGS,OPR_SPECIALREG,
- OPR_REGPAIR);
+ OPR_REGPAIR,OPR_FENCEFLAGS);
TOprRec = record
case typ:TOprType of
@@ -82,6 +82,9 @@ type
OPR_SHIFTEROP : (shifterop : tshifterop);
OPR_COND : (cc : tasmcond);
{$endif aarch64}
+{$if defined(riscv32) or defined(riscv64)}
+ OPR_FENCEFLAGS: (fenceflags : TFenceFlags);
+{$endif aarch64}
end;
TOperand = class
@@ -1295,6 +1298,10 @@ end;
OPR_COND:
ai.loadconditioncode(i-1,cc);
{$endif arm or aarch64}
+{$if defined(riscv32) or defined(riscv64)}
+ OPR_FENCEFLAGS:
+ ai.loadfenceflags(i-1,fenceflags);
+{$endif riscv32 or riscv64}
{ ignore wrong operand }
OPR_NONE:
;
diff --git a/compiler/riscv/aasmcpu.pas b/compiler/riscv/aasmcpu.pas
new file mode 100644
index 0000000000..e6937a7cab
--- /dev/null
+++ b/compiler/riscv/aasmcpu.pas
@@ -0,0 +1,624 @@
+{
+ Copyright (c) 1999-2002 by Jonas Maebe and Thomas Schatzl
+
+ Contains the assembler object for the Risc-V 32 and Risc-V 64
+
+ 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
+ { "mov reg,reg" source operand number }
+ O_MOV_SOURCE = 1;
+ { "mov reg,reg" source operand number }
+ O_MOV_DEST = 0;
+
+
+ type
+
+ { taicpu }
+
+ taicpu = class(tai_cpu_abstract_sym)
+ memoryordering: TMemoryOrdering;
+ constructor op_none(op : tasmop);
+
+ constructor op_reg(op : tasmop;_op1 : tregister);
+ constructor op_const(op : tasmop;_op1 : aint);
+
+ constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister);
+ constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
+ constructor op_reg_const(op:tasmop; _op1: tregister; _op2: aint);
+ constructor op_const_reg(op:tasmop; _op1: aint; _op2: tregister);
+
+ constructor op_const_const(op : tasmop;_op1,_op2 : aint);
+
+ constructor op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister; _op3, _op4: aint);
+
+ constructor op_reg_reg_roundingmode(op : tasmop;_op1,_op2 : tregister; _op3: TRoundingMode);
+ constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
+ constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint);
+ constructor op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: aint);
+ constructor op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
+ constructor op_const_reg_reg(op : tasmop;_op1 : aint;_op2, _op3 : tregister);
+ constructor op_const_reg_const(op : tasmop;_op1 : aint;_op2 : tregister;_op3 : aint);
+ constructor op_const_const_const(op : tasmop;_op1 : aint;_op2 : aint;_op3 : aint);
+
+ constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
+ constructor op_reg_bool_reg_reg(op : tasmop;_op1: tregister;_op2:boolean;_op3,_op4:tregister);
+ constructor op_reg_bool_reg_const(op : tasmop;_op1: tregister;_op2:boolean;_op3:tregister;_op4: aint);
+
+ constructor op_reg_reg_reg_const(op : tasmop; _op1, _op2, _op3 : tregister; _op4 : aint);
+ constructor op_reg_reg_reg_const_const(op : tasmop;_op1,_op2,_op3 : tregister;_op4,_op5 : aint);
+ constructor op_reg_reg_const_const_const(op : tasmop;_op1,_op2 : tregister;_op3,_op4,_op5 : aint);
+
+
+ { this is for Jmp instructions }
+ constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+ constructor op_const_const_sym(op : tasmop;_op1,_op2 : aint;_op3: tasmsymbol);
+
+
+ constructor op_sym(op : tasmop;_op1 : tasmsymbol);
+ constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint);
+ constructor op_reg_sym(op : tasmop;_op1 : tregister;_op2:tasmsymbol);
+ constructor op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : aint);
+ constructor op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint;const _op2 : treference);
+
+ procedure loadroundingmode(opidx:aint;_roundmode:TRoundingMode);
+ procedure loadfenceflags(opidx:aint;_flags:TFenceFlags);
+ procedure loadbool(opidx:aint;_b:boolean);
+
+ 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
+*****************************************************************************}
+
+ procedure taicpu.loadbool(opidx:aint;_b:boolean);
+ begin
+ if opidx>=ops then
+ ops:=opidx+1;
+ with oper[opidx]^ do
+ begin
+ if typ=top_ref then
+ dispose(ref);
+ b:=_b;
+ typ:=top_bool;
+ end;
+ end;
+
+
+ constructor taicpu.op_none(op : tasmop);
+ begin
+ inherited create(op);
+ end;
+
+
+ constructor taicpu.op_reg(op : tasmop;_op1 : tregister);
+ begin
+ inherited create(op);
+ ops:=1;
+ loadreg(0,_op1);
+ end;
+
+
+ constructor taicpu.op_const(op : tasmop;_op1 : aint);
+ begin
+ inherited create(op);
+ ops:=1;
+ loadconst(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_const(op:tasmop; _op1: tregister; _op2: aint);
+ begin
+ inherited create(op);
+ ops:=2;
+ loadreg(0,_op1);
+ loadconst(1,_op2);
+ end;
+
+ constructor taicpu.op_const_reg(op:tasmop; _op1: aint; _op2: tregister);
+ begin
+ inherited create(op);
+ ops:=2;
+ loadconst(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_const_const(op : tasmop;_op1,_op2 : aint);
+ begin
+ inherited create(op);
+ ops:=2;
+ loadconst(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_roundingmode(op: tasmop; _op1, _op2: tregister; _op3: TRoundingMode);
+ begin
+ inherited create(op);
+ ops:=3;
+ loadreg(0,_op1);
+ loadreg(1,_op2);
+ loadroundingmode(2,_op3);
+ 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_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: aint);
+ begin
+ inherited create(op);
+ ops:=3;
+ loadreg(0,_op1);
+ loadreg(1,_op2);
+ loadsymbol(2,_op3,_op3ofs);
+ 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_const_const_const(op : tasmop;_op1 : aint;_op2 : aint;_op3 : aint);
+ begin
+ inherited create(op);
+ ops:=3;
+ loadconst(0,_op1);
+ loadconst(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_bool_reg_reg(op : tasmop;_op1: tregister;_op2:boolean;_op3,_op4:tregister);
+ begin
+ inherited create(op);
+ ops:=4;
+ loadreg(0,_op1);
+ loadbool(1,_op2);
+ loadreg(2,_op3);
+ loadreg(3,_op4);
+ end;
+
+ constructor taicpu.op_reg_bool_reg_const(op : tasmop;_op1: tregister;_op2:boolean;_op3:tregister;_op4: aint);
+ begin
+ inherited create(op);
+ ops:=4;
+ loadreg(0,_op1);
+ loadbool(0,_op2);
+ loadreg(0,_op3);
+ loadconst(0,cardinal(_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;
+
+ constructor taicpu.op_reg_reg_reg_const_const(op : tasmop;_op1,_op2,_op3 : tregister;_op4,_op5 : aint);
+ begin
+ inherited create(op);
+ ops:=5;
+ loadreg(0,_op1);
+ loadreg(1,_op2);
+ loadreg(2,_op3);
+ loadconst(3,cardinal(_op4));
+ loadconst(4,cardinal(_op5));
+ end;
+
+ constructor taicpu.op_reg_reg_const_const_const(op : tasmop;_op1,_op2 : tregister;_op3,_op4,_op5 : aint);
+ begin
+ inherited create(op);
+ ops:=5;
+ loadreg(0,_op1);
+ loadreg(1,_op2);
+ loadconst(2,_op3);
+ loadconst(3,_op4);
+ loadconst(4,_op5);
+ end;
+
+ constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+ begin
+ inherited create(op);
+ condition:=cond;
+ ops:=1;
+ loadsymbol(0,_op1,0);
+ end;
+
+ constructor taicpu.op_const_const_sym(op : tasmop;_op1,_op2 : aint; _op3: tasmsymbol);
+ begin
+ inherited create(op);
+ ops:=3;
+ loadconst(0,_op1);
+ loadconst(1,_op2);
+ loadsymbol(2,_op3,0);
+ end;
+
+
+ constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
+ begin
+ inherited create(op);
+ ops:=1;
+ loadsymbol(0,_op1,0);
+ end;
+
+
+ constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint);
+ begin
+ inherited create(op);
+ ops:=1;
+ loadsymbol(0,_op1,_op1ofs);
+ end;
+
+ constructor taicpu.op_reg_sym(op: tasmop; _op1: tregister; _op2: tasmsymbol);
+ begin
+ inherited create(op);
+ ops:=2;
+ loadreg(0,_op1);
+ loadsymbol(1,_op2,0);
+ end;
+
+
+ constructor taicpu.op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : aint);
+ begin
+ inherited create(op);
+ ops:=2;
+ loadreg(0,_op1);
+ loadsymbol(1,_op2,_op2ofs);
+ end;
+
+
+ constructor taicpu.op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint;const _op2 : treference);
+ begin
+ inherited create(op);
+ ops:=2;
+ loadsymbol(0,_op1,_op1ofs);
+ loadref(1,_op2);
+ end;
+
+
+ procedure taicpu.loadroundingmode(opidx: aint; _roundmode: TRoundingMode);
+ begin
+ allocate_oper(opidx+1);
+ with oper[opidx]^ do
+ begin
+ if typ<>top_roundingmode then
+ clearop(opidx);
+ roundingmode:=_roundmode;
+ typ:=top_roundingmode;
+ end;
+ end;
+
+
+ procedure taicpu.loadfenceflags(opidx: aint; _flags: TFenceFlags);
+ begin
+ allocate_oper(opidx+1);
+ with oper[opidx]^ do
+ begin
+ if typ<>top_fenceflags then
+ clearop(opidx);
+ fenceflags:=_flags;
+ typ:=top_fenceflags;
+ end;
+ end;
+
+
+{ ****************************** newra stuff *************************** }
+
+ function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
+ begin
+ case regtype of
+ R_INTREGISTER:
+ result:=
+ (opcode=A_ADDI) and
+ (oper[0]^.reg=oper[1]^.reg) and
+ (oper[2]^.val=0);
+ R_FPUREGISTER:
+ result:=
+ (opcode in [A_FSGNJ_S,A_FSGNJ_D]) and
+ (oper[0]^.reg=oper[1]^.reg) and
+ (oper[0]^.reg=oper[2]^.reg);
+ end;
+ end;
+
+
+ function taicpu.spilling_get_operation_type(opnr: longint): topertype;
+ begin
+ result := operand_read;
+ case opcode of
+ // U type
+ A_LUI,
+ A_AUIPC:
+ if opnr=0 then
+ result:=operand_write
+ else
+ result:=operand_read;
+
+ // UJ type
+ A_JAL:
+ if opnr=0 then
+ result:=operand_write
+ else
+ result:=operand_read;
+
+ // I type
+ A_JALR,
+ A_LB,A_LH,A_LW,A_LBU,A_LHU,
+ A_ADDI,A_SLTI,A_SLTIU,
+ A_XORI,A_ORI,A_ANDI,
+ A_SLLI,A_SRLI,A_SRAI,
+
+ A_FENCE,A_FENCE_I,
+ A_ECALL,A_EBREAK,
+ A_CSRRW,A_CSRRS,A_CSRRC,A_CSRRWI,A_CSRRSI,A_CSRRCI,
+
+ A_FRCSR,A_FRRM,A_FRFLAGS,A_FSCSR,A_FSRM,
+ A_FSFLAGS,A_FSRMI,A_FSFLAGSI:
+ if opnr=0 then
+ result:=operand_write
+ else
+ result:=operand_read;
+
+ A_FLW,
+ A_FLD:
+ if opnr=0 then
+ result:=operand_write
+ else
+ result:=operand_read;
+
+ // SB type
+ A_Bxx:
+ result:=operand_read;
+
+ // S type
+ A_SB,A_SH,A_SW,
+
+ A_FSW,
+ A_FSD:
+ result:=operand_read;
+
+ // R type
+ A_ADD,A_SUB,A_SLL,A_SLT,A_SLTU,
+ A_XOR,A_OR,A_AND,A_SRL,A_SRA,
+
+ A_MUL,A_MULH,A_MULHSU,A_MULHU,
+ A_DIV,A_DIVU,A_REM,A_REMU,
+
+ A_LR_W,A_SC_W,A_AMOSWAP_W,A_AMOADD_W,A_AMOXOR_W,A_AMOAND_W,
+ A_AMOOR_W,A_AMOMIN_W,A_AMOMAX_W,A_AMOMINU_W,A_AMOMAXU_W,
+
+ A_FADD_S,A_FSUB_S,A_FMUL_S,A_FDIV_S,
+ A_FSQRT_S,A_FSGNJ_S,A_FSGNJN_S,A_FSGNJX_S,
+ A_FMIN_S,A_FMAX_S,
+ A_FMV_X_S,A_FEQ_S,A_FLT_S,A_FLE_S,A_FCLASS_S,
+ A_FCVT_W_S,A_FCVT_WU_S,A_FCVT_S_W,A_FCVT_S_WU,
+ A_FMV_S_X,
+
+ A_FADD_D,A_FSUB_D,A_FMUL_D,A_FDIV_D,
+ A_FSQRT_D,A_FSGNJ_D,A_FSGNJN_D,A_FSGNJX_D,
+ A_FMIN_D,A_FMAX_D,
+ A_FEQ_D,A_FLT_D,A_FLE_D,A_FCLASS_D,
+ A_FCVT_D_S,A_FCVT_S_D,
+ A_FCVT_W_D,A_FCVT_WU_D,A_FCVT_D_W,A_FCVT_D_WU:
+ if opnr=0 then
+ result:=operand_write
+ else
+ result:=operand_read;
+
+ // R4 type
+ A_FMADD_S,A_FMSUB_S,A_FNMSUB_S,A_FNMADD_S,
+
+ A_FMADD_D,A_FMSUB_D,A_FNMSUB_D,A_FNMADD_D:
+ if opnr=0 then
+ result:=operand_write
+ else
+ result:=operand_read;
+{$ifdef RISCV64}
+ A_LR_D,A_SC_D,A_AMOSWAP_D,A_AMOADD_D,A_AMOXOR_D,A_AMOAND_D,
+ A_AMOOR_D,A_AMOMIN_D,A_AMOMAX_D,A_AMOMINU_D,A_AMOMAXU_D,
+
+ A_MULW,
+ A_DIVW,A_DIVUW,A_REMW,A_REMUW,
+
+ A_FCVT_L_S,A_FCVT_LU_S,
+ A_FCVT_S_L,A_FCVT_S_LU,
+
+ A_FCVT_L_D,A_FCVT_LU_D,A_FMV_X_D,
+ A_FCVT_D_L,A_FCVT_D_LU,A_FMV_D_X,
+
+ A_ADDIW,A_SLLIW,A_SRLIW,A_SRAIW,
+ A_ADDW,A_SLLW,A_SRLW,A_SUBW,A_SRAW,
+ A_LD,A_LWU:
+ if opnr=0 then
+ result:=operand_write
+ else
+ result:=operand_read;
+
+ A_SD:
+ result:=operand_read;
+{$endif RISCV64}
+ 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;
+ begin
+ case getregtype(r) of
+ R_INTREGISTER:
+{$ifdef cpu64bitalu}
+ result:=taicpu.op_reg_ref(A_LD,r,ref);
+{$else cpu64bitalu}
+ result:=taicpu.op_reg_ref(A_LW,r,ref);
+{$endif cpu64bitalu}
+ R_FPUREGISTER:
+ result:=taicpu.op_reg_ref(A_FLD,r,ref);
+ else
+ internalerror(2005123101);
+ end;
+ end;
+
+
+ function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+ begin
+ case getregtype(r) of
+ R_INTREGISTER:
+{$ifdef cpu64bitalu}
+ result:=taicpu.op_reg_ref(A_SD,r,ref);
+{$else cpu64bitalu}
+ result:=taicpu.op_reg_ref(A_SW,r,ref);
+{$endif cpu64bitalu}
+ R_FPUREGISTER:
+ result:=taicpu.op_reg_ref(A_FSD,r,ref);
+ else
+ internalerror(2005123102);
+ end;
+ end;
+
+
+ procedure InitAsm;
+ begin
+ end;
+
+
+ procedure DoneAsm;
+ begin
+ end;
+
+
+begin
+ cai_align:=tai_align;
+ cai_cpu:=taicpu;
+end.
+
diff --git a/compiler/riscv/agrvgas.pas b/compiler/riscv/agrvgas.pas
new file mode 100644
index 0000000000..a047c7c6a6
--- /dev/null
+++ b/compiler/riscv/agrvgas.pas
@@ -0,0 +1,253 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ This unit the GAS asm writers for Risc-V32/Risc-V64
+
+ 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 agrvgas;
+
+{$i fpcdefs.inc}
+
+ interface
+
+ uses
+ systems,aasmbase,
+ aasmtai,aasmdata,
+ aggas,
+ assemble,
+ cpubase,cgutils,
+ globtype;
+
+ type
+ TRVInstrWriter=class(TCPUInstrWriter)
+ procedure WriteInstruction(hp : tai);override;
+ end;
+
+ TRVGNUAssembler=class(TGNUassembler)
+ constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+ function MakeCmdLine: TCmdStr; override;
+ end;
+
+ implementation
+
+ uses
+ cutils,globals,verbose,
+ cgbase,
+ itcpugas,cpuinfo,
+ aasmcpu;
+
+
+ function getreferencestring(asminfo: pasminfo; var ref : treference) : string;
+ var
+ s : string;
+ begin
+ with ref do
+ begin
+ if ((offset < -2048) or (offset > 2047)) and
+ (refaddr = addr_no) then
+ internalerror(2006052501);
+ case refaddr of
+ addr_no:
+ s := '';
+ addr_pic_no_got:
+ internalerror(2016060501);
+ else
+ begin
+ s :='';
+ s := s+'(';
+ if assigned(symbol) then
+ begin
+ if asminfo^.dollarsign<>'$' then
+ begin
+ s:=s+ReplaceForbiddenAsmSymbolChars(symbol.name);
+ if assigned(relsymbol) then
+ s:=s+'-'+ReplaceForbiddenAsmSymbolChars(relsymbol.name)
+ end
+ else
+ begin
+ s:=s+symbol.name;
+ if assigned(relsymbol) then
+ s:=s+'-'+relsymbol.name;
+ end;
+ end;
+ end;
+ end;
+ if offset<0 then
+ s:=s+tostr(offset)
+ else
+ if (offset>0) then
+ begin
+ if assigned(symbol) then
+ s:=s+'+'+tostr(offset)
+ else
+ s:=s+tostr(offset);
+ end;
+
+ if not(refaddr in [addr_no,addr_pic_no_got]) then
+ begin
+ s := s+')';
+ end;
+{$ifdef cpu64bitaddr}
+ if (refaddr=addr_pic) then
+ s := s + '@got';
+{$endif cpu64bitaddr}
+
+ if (index=NR_NO) then
+ begin
+ if offset=0 then
+ begin
+ if not (assigned(symbol)) then
+ s:=s+'0';
+ end;
+ if (base<>NR_NO) then
+ s:=s+'('+gas_regname(base)+')'
+ else if not assigned(symbol) then
+ s:=s+'(0)';
+ end
+ else if (index<>NR_NO) and (base<>NR_NO) then
+ begin
+ if (offset=0) then
+ s:=s+gas_regname(base)+','+gas_regname(index)
+ else
+ internalerror(2006052502);
+ end;
+
+ case refaddr of
+ addr_lo12: s:='%lo'+s;
+ addr_hi20: s:='%hi'+s;
+ addr_pcrel_lo12: s:='%pcrel_lo'+s;
+ addr_pcrel_hi20: s:='%pcrel_hi'+s;
+ end;
+ end;
+ 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(longint(o.val));
+ top_ref:
+ if o.ref^.refaddr=addr_full then
+ begin
+ hs:=o.ref^.symbol.name;
+ if asminfo^.dollarsign<>'$' then
+ hs:=ReplaceForbiddenAsmSymbolChars(hs);
+ if o.ref^.offset>0 then
+ hs:=hs+'+'+tostr(o.ref^.offset)
+ else
+ if o.ref^.offset<0 then
+ hs:=hs+tostr(o.ref^.offset);
+ getopstr:=hs;
+ end
+ else
+ getopstr:=getreferencestring(asminfo,o.ref^);
+ top_fenceflags:
+ begin
+ getopstr:='';
+ if ffI in o.fenceflags then getopstr:=getopstr+'i';
+ if ffO in o.fenceflags then getopstr:=getopstr+'o';
+ if ffR in o.fenceflags then getopstr:=getopstr+'r';
+ if ffW in o.fenceflags then getopstr:=getopstr+'w';
+ end;
+ top_roundingmode:
+ getopstr:=roundingmode2str[o.roundingmode];
+ else
+ internalerror(2002070604);
+ end;
+ end;
+
+
+ Procedure TRVInstrWriter.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];
+
+ if taicpu(hp).memoryordering<>[] then
+ begin
+ s:=s+'.';
+ if moAq in taicpu(hp).memoryordering then s:=s+'aq';
+ if moRl in taicpu(hp).memoryordering then s:=s+'rl';
+ end;
+
+ 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 RiscV Assembler writer }
+{****************************************************************************}
+
+ constructor TRVGNUAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+ begin
+ inherited;
+ InstrWriter := TRVInstrWriter.create(self);
+ end;
+
+
+ function TRVGNUAssembler.MakeCmdLine: TCmdStr;
+ begin
+ result := inherited MakeCmdLine;
+ Replace(result,'$ARCH',lower(cputypestr[current_settings.cputype]));
+ end;
+
+
+ const
+ as_riscv_gas_info : tasminfo =
+ (
+ id : as_gas;
+
+ idtxt : 'AS';
+ asmbin : 'as';
+ asmcmd : '-o $OBJ $EXTRAOPT -march=$ARCH $ASM';
+ supported_targets : [system_riscv32_linux,system_riscv64_linux];
+ flags : [af_needar,af_smartlink_sections];
+ labelprefix : '.L';
+ comment : '# ';
+ dollarsign: '$';
+ );
+
+begin
+ RegisterAssembler(as_riscv_gas_info,TRVGNUAssembler);
+end.
diff --git a/compiler/riscv/cgrv.pas b/compiler/riscv/cgrv.pas
new file mode 100644
index 0000000000..7105207c67
--- /dev/null
+++ b/compiler/riscv/cgrv.pas
@@ -0,0 +1,758 @@
+{
+ Copyright (c) 2006 by Florian Klaempfl
+
+ This unit implements the common part of the code generator for the Risc-V
+
+ 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 cgrv;
+
+{$i fpcdefs.inc}
+ interface
+
+ uses
+ globtype,symtype,symdef,
+ cgbase,cgobj,
+ aasmbase,aasmcpu,aasmtai,aasmdata,
+ cpubase,cpuinfo,cgutils,rgcpu,
+ parabase;
+
+ type
+
+ { tcgrv }
+
+ tcgrv = class(tcg)
+ procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara); override;
+
+ procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override;
+
+ procedure a_call_reg(list : TAsmList;reg: tregister); override;
+ procedure a_call_name(list : TAsmList;const s : string; weak: boolean); 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_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
+ procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister); override;
+
+ 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;
+
+ procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
+
+ 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;
+
+ procedure a_jmp_name(list : TAsmList;const s : string); override;
+ procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
+
+ procedure g_save_registers(list: TAsmList); override;
+ procedure g_restore_registers(list: TAsmList); override;
+
+ procedure g_profilecode(list: TAsmList); 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;
+
+ procedure g_check_for_fpu_exception(list: TAsmList); override;
+ protected
+ function fixref(list: TAsmList; var ref: treference): boolean;
+ procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
+ end;
+
+ const
+ TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_NONE,
+ C_LT,C_GE,C_None,C_NE,C_NONE,C_LTU,C_GEU,C_NONE);
+
+ const
+ TOpCG2AsmConstOp: Array[topcg] of TAsmOp = (A_NONE,
+ A_NONE,A_ADDI,A_ANDI,A_NONE,A_NONE,A_NONE,A_NONE,
+ A_None,A_None,A_ORI,A_SRAI,A_SLLI,A_SRLI,A_NONE,A_XORI,A_None,A_None);
+ TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,
+ A_NONE,A_ADD,A_AND,A_DIVU,A_DIV,A_MUL,A_MUL,
+ A_None,A_None,A_OR,A_SRA,A_SLL,A_SRL,A_SUB,A_XOR,A_None,A_None);
+
+
+ implementation
+
+ uses
+ {$ifdef extdebug}sysutils,{$endif}
+ globals,verbose,systems,cutils,
+ symconst,symsym,symtable,fmodule,
+ rgobj,tgobj,cpupi,procinfo,paramgr;
+
+
+ procedure tcgrv.a_call_name(list : TAsmList;const s : string; weak: boolean);
+ var
+ href: treference;
+ l: TAsmLabel;
+ 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,[]);
+
+ current_asmdata.getjumplabel(l);
+
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,NR_RETURN_ADDRESS_REG,href));
+
+ reference_reset_symbol(href,l,0,0,[]);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_JALR,NR_RETURN_ADDRESS_REG,NR_RETURN_ADDRESS_REG,href));
+
+ { not assigned while generating external wrappers }
+ if assigned(current_procinfo) then
+ include(current_procinfo.flags,pi_do_call);
+ end;
+
+
+ procedure tcgrv.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_X0,ref)
+ else
+ inherited a_load_const_ref(list, size, a, ref);
+ end;
+
+
+ procedure tcgrv.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
+ var
+ ref: treference;
+ tmpreg: tregister;
+
+ begin
+ paraloc.check_simple_location;
+ paramanager.allocparaloc(list,paraloc.location);
+ case paraloc.location^.loc of
+ LOC_REGISTER,LOC_CREGISTER:
+ a_loadaddr_ref_reg(list,r,paraloc.location^.register);
+ LOC_REFERENCE:
+ begin
+ reference_reset(ref,paraloc.alignment,[]);
+ ref.base := paraloc.location^.reference.index;
+ ref.offset := paraloc.location^.reference.offset;
+ tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
+ a_loadaddr_ref_reg(list,r,tmpreg);
+ a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
+ end;
+ else
+ internalerror(2002080701);
+ end;
+ end;
+
+
+ procedure tcgrv.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister);
+ begin
+ internalerror(2016060401);
+ end;
+
+
+ procedure tcgrv.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;
+
+
+ procedure tcgrv.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 tcgrv.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
+ var
+ tmpreg: TRegister;
+ begin
+ optimize_op_const(size,op,a);
+
+ if op=OP_NONE then
+ begin
+ a_load_reg_reg(list,size,size,src,dst);
+ exit;
+ end;
+
+ if op=OP_SUB then
+ begin
+ op:=OP_ADD;
+ a:=-a;
+ end;
+
+{$ifdef RISCV64}
+ if (op=OP_SHL) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_SLLIW,dst,src,a));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if (op=OP_SHR) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_SRLIW,dst,src,a));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if (op=OP_SAR) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_SRAIW,dst,src,a));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else
+{$endif RISCV64}
+ if (TOpCG2AsmConstOp[op]<>A_None) and
+ is_imm12(a) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp[op],dst,src,a));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else
+ begin
+ tmpreg:=getintregister(list,size);
+ a_load_const_reg(list,size,a,tmpreg);
+ a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
+ end;
+ end;
+
+
+ procedure tcgrv.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
+ begin
+ if op=OP_NOT then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_XORI,dst,src1,-1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if op=OP_NEG then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SUB,dst,NR_X0,src1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else
+ case op of
+ OP_MOVE:
+ a_load_reg_reg(list,size,size,src1,dst);
+ else
+{$ifdef RISCV64}
+ if (op=OP_SHL) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SLLW,dst,src2,src1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if (op=OP_SHR) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SRLW,dst,src2,src1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if (op=OP_SAR) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SRAW,dst,src2,src1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else
+{$endif RISCV64}
+ begin
+ list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,src1));
+ maybeadjustresult(list,op,size,dst);
+ end;
+ end;
+ end;
+
+
+ procedure tcgrv.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
+ var
+ href: treference;
+ b, tmpreg: TRegister;
+ l: TAsmLabel;
+ begin
+ href:=ref;
+ fixref(list,href);
+
+ if (not assigned(href.symbol)) and
+ (href.offset=0) then
+ a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r)
+ else if (assigned(href.symbol) or
+ (not is_imm12(href.offset))) and
+ (href.base<>NR_NO) then
+ begin
+ b:= href.base;
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.base:=NR_NO;
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,r,href));
+
+ reference_reset_symbol(href,l,0,0,ref.volatility);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,href));
+
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,b));
+ end
+ else if is_imm12(href.offset) and
+ (href.base<>NR_NO) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,r,href.base,href.offset));
+ end
+ else if (href.refaddr=addr_pcrel) then
+ begin
+ tmpreg:=getintregister(list,OS_ADDR);
+
+ b:=href.base;
+ href.base:=NR_NO;
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+
+ reference_reset_symbol(href,l,0,0,ref.volatility);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,tmpreg,href));
+
+ if b<>NR_NO then
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,b));
+ end
+ else
+ internalerror(2016060504);
+ end;
+
+
+ procedure tcgrv.a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
+ begin
+ if a=0 then
+ a_cmp_reg_reg_label(list,size,cmp_op,NR_X0,reg,l)
+ else
+ inherited;
+ end;
+
+
+ procedure tcgrv.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg1,reg2 : tregister;l : tasmlabel);
+ var
+ tmpreg: TRegister;
+ ai: taicpu;
+ begin
+ if TOpCmp2AsmCond[cmp_op]=C_None then
+ begin
+ cmp_op:=swap_opcmp(cmp_op);
+ tmpreg:=reg1;
+ reg1:=reg2;
+ reg2:=tmpreg;
+ end;
+
+ ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,reg2,reg1,l,0);
+ ai.is_jmp:=true;
+ ai.condition:=TOpCmp2AsmCond[cmp_op];
+ list.concat(ai);
+ end;
+
+
+ procedure tcgrv.a_jmp_name(list : TAsmList;const s : string);
+ var
+ ai: taicpu;
+ href: treference;
+ tmpreg: TRegister;
+ l: TAsmLabel;
+ begin
+ reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[]);
+
+ tmpreg:=getintregister(list,OS_ADDR);
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+ reference_reset_symbol(href,l,0,0,[]);
+ href.refaddr:=addr_pcrel_lo12;
+ ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
+ ai.is_jmp:=true;
+ list.concat(ai);
+
+ //ai:=taicpu.op_reg_sym(A_JAL,NR_X0,current_asmdata.RefAsmSymbol(s));
+ //ai.is_jmp:=true;
+ end;
+
+
+ procedure tcgrv.a_jmp_always(list : TAsmList;l: tasmlabel);
+ var
+ ai: taicpu;
+ {href: treference;
+ tmpreg: TRegister;}
+ begin
+ {reference_reset_symbol(href,l,0,0);
+
+ tmpreg:=getintregister(list,OS_ADDR);
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+ reference_reset_symbol(href,l,0,0);
+ href.refaddr:=addr_pcrel_lo12;
+ ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
+ ai.is_jmp:=true;
+ list.concat(ai);}
+
+ ai:=taicpu.op_reg_sym(A_JAL,NR_X0,l);
+ ai.is_jmp:=true;
+ list.concat(ai);
+ end;
+
+
+ procedure tcgrv.g_save_registers(list: TAsmList);
+ begin
+ end;
+
+
+ procedure tcgrv.g_restore_registers(list: TAsmList);
+ begin
+ end;
+
+
+ procedure tcgrv.g_profilecode(list: TAsmList);
+ begin
+ if target_info.system in [system_riscv32_linux,system_riscv64_linux] then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_X10,NR_RETURN_ADDRESS_REG,0));
+ a_call_name(list,'_mcount',false);
+ end
+ else
+ internalerror(2018092201);
+ end;
+
+
+ procedure tcgrv.a_call_reg(list : TAsmList;reg: tregister);
+ begin
+ list.concat(taicpu.op_reg_reg(A_JALR,NR_RETURN_ADDRESS_REG,reg));
+ include(current_procinfo.flags,pi_do_call);
+ end;
+
+
+ procedure tcgrv.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
+ reg: tregister; const ref: treference);
+
+ const
+ StoreInstr: array[OS_8..OS_INT] of TAsmOp =
+ (A_SB,A_SH,A_SW
+{$ifdef cpu64bitalu}
+ ,
+ A_SD
+{$endif cpu64bitalu}
+ );
+ var
+ ref2: TReference;
+ tmpreg: tregister;
+ op: TAsmOp;
+ begin
+ if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+ internalerror(2002090904);
+ if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+ internalerror(2002090905);
+
+ tosize:=tcgsize2unsigned[tosize];
+
+ ref2 := ref;
+ fixref(list, ref2);
+
+ op := storeinstr[tcgsize2unsigned[tosize]];
+ list.concat(taicpu.op_reg_ref(op, reg,ref2));
+ end;
+
+
+ procedure tcgrv.a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
+ var
+ href: treference;
+ op: TAsmOp;
+ tmpreg: TRegister;
+ begin
+ href:=ref;
+ fixref(list,href);
+
+ if href.refaddr=addr_pcrel then
+ begin
+ tmpreg:=getintregister(list,OS_ADDR);
+ a_loadaddr_ref_reg(list,href,tmpreg);
+ reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+ end;
+
+ case fromsize of
+ OS_8: op:=A_LBU;
+ OS_16: op:=A_LHU;
+ OS_S8: op:=A_LB;
+ OS_S16: op:=A_LH;
+{$ifdef RISCV64}
+ OS_32: op:=A_LWU;
+ OS_S32: op:=A_LW;
+ OS_64,
+ OS_S64: op:=A_LD;
+{$else}
+ OS_32,
+ OS_S32: op:=A_LW;
+{$endif}
+ else
+ internalerror(2016060502);
+ end;
+
+ list.concat(taicpu.op_reg_ref(op,reg,href));
+ if (fromsize<>tosize) and (not (tosize in [OS_SINT,OS_INT])) then
+ a_load_reg_reg(list,fromsize,tosize,reg,reg);
+ end;
+
+
+ procedure tcgrv.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister);
+ begin
+ if a=0 then
+ a_load_reg_reg(list,size,size,NR_X0,register)
+ else
+ begin
+ if is_imm12(a) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,register,NR_X0,a))
+ else if is_lui_imm(a) then
+ list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF))
+ else
+ begin
+ if (a and $800)<>0 then
+ list.concat(taicpu.op_reg_const(A_LUI,register,((a shr 12)+1) and $FFFFF))
+ else
+ list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF));
+
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,register,register,SarSmallint(a shl 4,4)));
+ end;
+ end;
+ end;
+
+
+ procedure tcgrv.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
+ var
+ op: TAsmOp;
+ ai: taicpu;
+
+ const
+ convOp: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
+ ((A_None,A_FCVT_D_S),
+ (A_FCVT_S_D,A_None));
+
+ begin
+ if fromsize<>tosize then
+ begin
+ list.concat(taicpu.op_reg_reg(convOp[fromsize,tosize],reg2,reg1));
+ g_check_for_fpu_exception(list);
+ end
+ else
+ begin
+ if tosize=OS_F32 then
+ op:=A_FSGNJ_S
+ else
+ op:=A_FSGNJ_D;
+
+ ai:=taicpu.op_reg_reg_reg(op,reg2,reg1,reg1);
+ list.concat(ai);
+ rg[R_FPUREGISTER].add_move_instruction(ai);
+ end;
+ end;
+
+
+ procedure tcgrv.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
+ var
+ href: treference;
+ op: TAsmOp;
+ tmpreg: TRegister;
+ l: TAsmLabel;
+ begin
+ href:=ref;
+ fixref(list,href);
+
+ if href.refaddr=addr_pcrel then
+ begin
+ tmpreg:=getintregister(list,OS_ADDR);
+ a_loadaddr_ref_reg(list,href,tmpreg);
+ reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+ end;
+
+ if fromsize=OS_F32 then
+ op:=A_FLW
+ else
+ op:=A_FLD;
+
+ list.concat(taicpu.op_reg_ref(op,reg,href));
+
+ if fromsize<>tosize then
+ a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
+ end;
+
+
+ procedure tcgrv.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
+ var
+ href: treference;
+ op: TAsmOp;
+ tmpreg: TRegister;
+ begin
+ href:=ref;
+ fixref(list,href);
+
+ if href.refaddr=addr_pcrel then
+ begin
+ tmpreg:=getintregister(list,OS_ADDR);
+ a_loadaddr_ref_reg(list,href,tmpreg);
+ reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+ end;
+
+ if fromsize<>tosize then
+ begin
+ tmpreg:=getfpuregister(list,tosize);
+ a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
+ reg:=tmpreg;
+ end;
+
+ if tosize=OS_F32 then
+ op:=A_FSW
+ else
+ op:=A_FSD;
+
+ list.concat(taicpu.op_reg_ref(op,reg,href));
+ end;
+
+
+ function tcgrv.fixref(list: TAsmList; var ref: treference): boolean;
+ var
+ tmpreg: TRegister;
+ href: treference;
+ l: TAsmLabel;
+ begin
+ result:=true;
+
+ if ref.refaddr=addr_pcrel then
+ exit;
+
+ if assigned(ref.symbol) then
+ begin
+ reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,ref.volatility);
+ ref.symbol:=nil;
+ ref.offset:=0;
+
+ tmpreg:=getintregister(list,OS_INT);
+
+ current_asmdata.getaddrlabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+ reference_reset_symbol(href,l,0,0,ref.volatility);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_ADDI,tmpreg,tmpreg,href));
+
+ 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.index=NR_NO) and
+ (ref.base<>NR_NO) then
+ ref.index:=tmpreg
+ else
+ ref.base:=tmpreg;
+ end
+ 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);
+ end;
+
+ if (ref.index<>NR_NO) and
+ (ref.base=NR_NO) then
+ begin
+ ref.base:=ref.index;
+ ref.index:=NR_NO;
+ end;
+
+ if not is_imm12(ref.offset) then
+ begin
+ tmpreg:=getintregister(list,OS_INT);
+ a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
+
+ ref.offset:=0;
+
+ if (ref.index<>NR_NO) and
+ (ref.base<>NR_NO) then
+ begin
+ a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
+ ref.index:=tmpreg;
+ end
+ else
+ ref.index:=tmpreg;
+ end;
+
+ if (ref.index<>NR_NO) and
+ (ref.base<>NR_NO) then
+ begin
+ tmpreg:=getaddressregister(list);
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
+ ref.base:=tmpreg;
+ ref.index:=NR_NO;
+ end;
+ end;
+
+
+ procedure tcgrv.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{$ifdef RISCV64},OS_32,OS_S32{$endif RISCV64}]) then
+ a_load_reg_reg(list,OS_INT,size,dst,dst)
+ end;
+
+
+ procedure tcgrv.g_check_for_fpu_exception(list: TAsmList);
+ var
+ r : TRegister;
+ ai: taicpu;
+ l: TAsmLabel;
+ begin
+ if cs_check_fpu_exceptions in current_settings.localswitches then
+ begin
+ r:=getintregister(list,OS_INT);
+ list.concat(taicpu.op_reg(A_FRFLAGS,r));
+ current_asmdata.getjumplabel(l);
+ ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,r,NR_X0,l,0);
+ ai.is_jmp:=true;
+ ai.condition:=C_EQ;
+ list.concat(ai);
+ alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+ cg.a_call_name(current_asmdata.CurrAsmList,'FPC_THROWFPUEXCEPTION',false);
+ dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+ a_label(list,l);
+ end;
+ end;
+
+end.
diff --git a/compiler/riscv/hlcgrv.pas b/compiler/riscv/hlcgrv.pas
new file mode 100644
index 0000000000..30a1d66968
--- /dev/null
+++ b/compiler/riscv/hlcgrv.pas
@@ -0,0 +1,260 @@
+{
+ Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+ Member of the Free Pascal development team
+
+ This unit contains routines high-level code generator support shared by
+ riscv32 and riscv64
+
+ 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 hlcgrv;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+ globals,
+ aasmdata,
+ symtype,symdef,
+ cgbase,cgutils,hlcgobj,hlcg2ll, parabase;
+
+type
+
+ { thlcgriscv }
+
+ thlcgriscv = class(thlcg2ll)
+ protected
+ procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tdef; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
+ public
+ procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+ procedure g_external_wrapper(list: TAsmList; procdef: tprocdef; const wrappername, externalname: string; global: boolean); override;
+ end;
+
+implementation
+
+ uses
+ verbose,
+ systems,fmodule,
+ symconst, symsym,
+ aasmbase,aasmtai,aasmcpu,
+ cpubase,globtype,
+ procinfo,cpupi,cgobj,cgrv,
+ defutil;
+
+{ thlcgriscv }
+
+ procedure thlcgriscv.a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tdef; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister);
+ var
+ fromsreg, tosreg: tsubsetregister;
+ restbits: byte;
+ begin
+ { the code below is only valid for big endian }
+ if target_info.endian=endian_little then
+ begin
+ inherited;
+ exit
+ end;
+ restbits:=(sref.bitlen-(loadbitsize-sref.startbit));
+ if is_signed(subsetsize) then
+ begin
+ { sign extend }
+ a_op_const_reg(list,OP_SHL,osuinttype,AIntBits-loadbitsize+sref.startbit,valuereg);
+ a_op_const_reg(list,OP_SAR,osuinttype,AIntBits-sref.bitlen,valuereg);
+ end
+ else
+ begin
+ a_op_const_reg(list,OP_SHL,osuinttype,restbits,valuereg);
+ { mask other bits }
+ if (sref.bitlen<>AIntBits) then
+ a_op_const_reg(list,OP_AND,osuinttype,(aword(1) shl sref.bitlen)-1,valuereg);
+ end;
+ { use subsetreg routine, it may have been overridden with an optimized version }
+ fromsreg.subsetreg:=extra_value_reg;
+ fromsreg.subsetregsize:=OS_INT;
+ { subsetregs always count bits from right to left }
+ fromsreg.startbit:=loadbitsize-restbits;
+ fromsreg.bitlen:=restbits;
+
+ tosreg.subsetreg:=valuereg;
+ tosreg.subsetregsize:=OS_INT;
+ tosreg.startbit:=0;
+ tosreg.bitlen:=restbits;
+
+ a_load_subsetreg_subsetreg(list,subsetsize,subsetsize,fromsreg,tosreg);
+ end;
+
+
+ procedure thlcgriscv.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_X10,0,ctempposinvalid,sizeof(pint),[]);
+ cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_X5);
+ end;
+
+
+ procedure op_onr12methodaddr;
+ var
+ tmpref,
+ href : treference;
+ l : TAsmLabel;
+ begin
+ if (procdef.extnumber=$ffff) then
+ Internalerror(200006139);
+
+ reference_reset_base(href,voidpointertype,NR_X5,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),ctempposinvalid, sizeof(pint),[]);
+ cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_X5);
+
+ list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_X5));
+ 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(200006137);
+ if not assigned(procdef.struct) or
+ (procdef.procoptions*[po_classmethod, po_staticmethod,
+ po_methodpointer, po_interrupt, po_iocheck]<>[]) then
+ Internalerror(200006138);
+ if procdef.owner.symtabletype<>ObjectSymtable then
+ Internalerror(200109191);
+
+ 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(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(2010103101);
+ paraloc:=tparavarsym(hsym).paraloc[callerside].location;
+ if assigned(paraloc^.next) then
+ InternalError(2013020101);
+
+ case paraloc^.loc of
+ LOC_REGISTER:
+ begin
+ if is_imm12(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_X6);
+ cg.a_op_reg_reg(list, OP_SUB, paraloc^.size, NR_X6, paraloc^.register);
+ end;
+ end;
+ else
+ internalerror(2010103102);
+ end;
+
+ { case 4 }
+ if (po_virtualmethod in procdef.procoptions) and
+ not is_objectpascal_helper(procdef.struct) then
+ begin
+ loadvmttor12;
+ op_onr12methodaddr;
+ end
+ else
+ begin
+ reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname,AT_FUNCTION),0,0,[]);
+
+ tmpreg:=NR_X5;
+
+ current_asmdata.getjumplabel(l);
+
+ cg.a_label(list, l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+
+ reference_reset_symbol(href,l,0,0,[]);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href));
+
+ //list.concat(taicpu.op_reg_sym(A_JAL,NR_X0,current_asmdata.RefAsmSymbol(procdef.mangledname)));
+ end;
+ list.concatlist(current_procinfo.aktlocaldata);
+
+ current_procinfo.Free;
+ current_procinfo:=nil;
+
+ list.concat(Tai_symbol_end.Createname(labelname));
+ end;
+
+ procedure thlcgriscv.g_external_wrapper(list: TAsmList; procdef: tprocdef; const wrappername, externalname: string; global: boolean);
+ var
+ sym: tasmsymbol;
+ ai: taicpu;
+ href: treference;
+ tmpreg: TRegister;
+ l: TAsmLabel;
+ begin
+ maybe_new_object_file(list);
+ new_section(list,sec_code,wrappername,target_info.alignment.procalign);
+ if global then
+ begin
+ sym:=current_asmdata.DefineAsmSymbol(wrappername,AB_GLOBAL,AT_FUNCTION,procdef);
+ list.concat(Tai_symbol.Create_global(sym,0));
+ end
+ else
+ begin
+ sym:=current_asmdata.DefineAsmSymbol(wrappername,AB_LOCAL,AT_FUNCTION,procdef);
+ list.concat(Tai_symbol.Create(sym,0));
+ end;
+
+ reference_reset_symbol(href,current_asmdata.RefAsmSymbol(externalname,AT_FUNCTION),0,0,[]);
+
+ tmpreg:=NR_X5;
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+ reference_reset_symbol(href,l,0,0,[]);
+ href.refaddr:=addr_pcrel_lo12;
+ ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
+ ai.is_jmp:=true;
+ list.concat(ai);
+
+ list.concat(Tai_symbol_end.Create(sym));
+ end;
+
+end.
+
diff --git a/compiler/riscv/nrvadd.pas b/compiler/riscv/nrvadd.pas
new file mode 100644
index 0000000000..291fd037c3
--- /dev/null
+++ b/compiler/riscv/nrvadd.pas
@@ -0,0 +1,417 @@
+{
+ Copyright (c) 2000-2006 by Florian Klaempfl and Jonas Maebe
+
+ Code generation for add nodes on the Risc-V (32 and 64 bit generic)
+
+ 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 nrvadd;
+
+
+{$i fpcdefs.inc}
+
+ interface
+
+ uses
+ node,nadd,ncgadd,cpubase;
+
+ type
+ trvaddnode = class(tcgaddnode)
+ function pass_1: tnode; override;
+ protected
+ procedure Cmp(signed: boolean);
+
+ procedure second_cmpsmallset;override;
+ procedure second_cmpordinal;override;
+ procedure second_cmp64bit; override;
+
+ procedure second_addordinal; override;
+
+ procedure pass_left_and_right;
+
+ function use_fma: boolean; override;
+
+ procedure second_addfloat;override;
+ procedure second_cmpfloat;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 trvaddnode.Cmp(signed: boolean);
+ var
+ flabel,tlabel: tasmlabel;
+ op, opi: TAsmOp;
+ begin
+ pass_left_right;
+
+ force_reg_left_right(true,true);
+
+ 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_SLTIU;
+
+ 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_imm12(-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(A_ADDI,location.register,left.location.register,-right.location.value))
+ else
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_SUB,location.register,left.location.register,right.location.register));
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTIU,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_imm12(-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(A_ADDI,location.register,left.location.register,-right.location.value))
+ else
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_SUB,location.register,left.location.register,right.location.register));
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_SLTU,location.register,NR_X0,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_imm12(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_imm12(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_imm12(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));
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTIU,location.register,location.register,1));
+ 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_imm12(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));
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTIU,location.register,location.register,1));
+ end;
+ else
+ Internalerror(2016061101);
+ end;
+ end;
+
+
+ procedure trvaddnode.second_cmpsmallset;
+ begin
+ Cmp(true);
+ end;
+
+
+ procedure trvaddnode.second_cmpordinal;
+ var
+ unsigned: Boolean;
+ begin
+ unsigned:=not(is_signed(left.resultdef)) or
+ not(is_signed(right.resultdef));
+
+ Cmp(not unsigned);
+ end;
+
+
+ procedure trvaddnode.second_cmp64bit;
+ var
+ unsigned: Boolean;
+ begin
+ unsigned:=not(is_signed(left.resultdef)) or
+ not(is_signed(right.resultdef));
+
+ Cmp(not unsigned);
+ end;
+
+
+ procedure trvaddnode.second_addordinal;
+ 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(A_MUL,location.register,left.location.register,right.location.register));
+ end
+ else
+ inherited second_addordinal;
+ end;
+
+
+ function trvaddnode.pass_1: tnode;
+ begin
+ if (nodetype=muln) and
+ (left.resultdef.typ=orddef) and (left.resultdef.typ=orddef) and
+ (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype])
+{$ifdef cpu32bitalu}
+ and (not (is_64bit(left.resultdef) or
+ is_64bit(right.resultdef)))
+{$endif cpu32bitalu}
+ then
+ begin
+ result:=nil;
+
+ firstpass(left);
+ firstpass(right);
+
+ expectloc:=LOC_REGISTER;
+ end
+ else if (nodetype=muln) and
+ (not (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype])) and
+ (is_64bit(left.resultdef) or
+ is_64bit(right.resultdef)) then
+ begin
+ result:=first_add64bitint;
+ end
+ else
+ Result:=inherited pass_1;
+
+ if expectloc=LOC_FLAGS then
+ expectloc:=LOC_REGISTER;
+ end;
+
+
+ procedure trvaddnode.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;
+
+
+ function trvaddnode.use_fma: boolean;
+ begin
+ Result:=current_settings.fputype in [fpu_fd];
+ end;
+
+
+ procedure trvaddnode.second_addfloat;
+ var
+ op : TAsmOp;
+ cmpop,
+ singleprec , inv: 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;
+ inv:=false;
+ 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_FEQ_S
+ else
+ op:=A_FEQ_D;
+ cmpop:=true;
+ end;
+ unequaln:
+ begin
+ if singleprec then
+ op:=A_FEQ_S
+ else
+ op:=A_FEQ_D;
+ inv:=true;
+ cmpop:=true;
+ end;
+ ltn:
+ begin
+ if singleprec then
+ op:=A_FLT_S
+ else
+ op:=A_FLT_D;
+ cmpop:=true;
+ end;
+ lten:
+ begin
+ if singleprec then
+ op:=A_FLE_S
+ else
+ op:=A_FLE_D;
+ cmpop:=true;
+ end;
+ gtn:
+ begin
+ if singleprec then
+ op:=A_FLT_S
+ else
+ op:=A_FLT_D;
+ swapleftright;
+ cmpop:=true;
+ end;
+ gten:
+ begin
+ if singleprec then
+ op:=A_FLE_S
+ else
+ op:=A_FLE_D;
+ swapleftright;
+ cmpop:=true;
+ end;
+ else
+ internalerror(200403182);
+ end;
+
+ // put both operands in a register
+ hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
+ hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+
+ // initialize de result
+ if not cmpop then
+ begin
+ location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
+ location.register := cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
+ end
+ else
+ begin
+ location_reset(location,LOC_REGISTER,OS_8);
+ location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+ end;
+
+ // emit the actual operation
+ if not cmpop then
+ begin
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+ cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+ end
+ else
+ begin
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+ cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+
+ if inv then
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_XORI,location.register,location.register,1));
+ end;
+ end;
+
+ procedure trvaddnode.second_cmpfloat;
+ begin
+ second_addfloat;
+ end;
+
+end.
diff --git a/compiler/riscv/nrvcnv.pas b/compiler/riscv/nrvcnv.pas
new file mode 100644
index 0000000000..54f3e91f29
--- /dev/null
+++ b/compiler/riscv/nrvcnv.pas
@@ -0,0 +1,178 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Generate Risc-V 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 nrvcnv;
+
+{$i fpcdefs.inc}
+
+interface
+
+ uses
+ node,ncnv,ncgcnv;
+
+ type
+ trvtypeconvnode = 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,
+ cgbase,cgutils,pass_1,pass_2,
+ ncgutil,procinfo,
+ cpubase,aasmcpu,
+ rgobj,tgobj,cgobj,hlcgobj;
+
+
+ procedure trvtypeconvnode.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);
+{$ifndef cpu64bitalu}
+ if left.location.size in [OS_64,OS_S64] then
+ begin
+ cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,left.location.reference,hreg2);
+ hreg1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+ href:=left.location.reference;
+ inc(href.offset,4);
+ cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,href,hreg1);
+ cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,hreg1,hreg2,hreg2);
+ end
+ else
+{$endif not cpu64bitalu}
+ 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);
+{$ifndef cpu64bitalu}
+ if left.location.size in [OS_64,OS_S64] then
+ begin
+ hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
+ cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,left.location.register64.reghi,left.location.register64.reglo,hreg2);
+ end
+ else
+{$endif not cpu64bitalu}
+ 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_X0, 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:
+ begin
+ Internalerror(2016060403);
+ end
+ else
+ internalerror(10062);
+ 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);
+
+{$ifndef cpu64bitalu}
+ if (location.size in [OS_64,OS_S64]) then
+ begin
+ location.register64.reglo:=hreg1;
+ location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
+ if (is_cbool(resultdef)) then
+ { reglo is either 0 or -1 -> reghi has to become the same }
+ cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,location.register64.reglo,location.register64.reghi)
+ else
+ { unsigned }
+ cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_32,0,location.register64.reghi);
+ end
+ else
+{$endif not cpu64bitalu}
+ location.Register := hreg1;
+ end;
+
+end.
diff --git a/compiler/riscv/nrvcon.pas b/compiler/riscv/nrvcon.pas
new file mode 100644
index 0000000000..66698527b7
--- /dev/null
+++ b/compiler/riscv/nrvcon.pas
@@ -0,0 +1,131 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Code generation for const nodes on the Risc-V
+
+ 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 nrvcon;
+
+{$i fpcdefs.inc}
+
+interface
+
+ uses
+ ncgcon,cpubase;
+
+ type
+ trvrealconstnode = class(tcgrealconstnode)
+ procedure pass_generate_code;override;
+ end;
+
+
+implementation
+
+ uses
+ verbose,
+ globtype,globals,
+ cpuinfo,
+ aasmbase,aasmtai,aasmdata,symdef,
+ defutil,
+ cgbase,cgutils,
+ procinfo,
+ ncon;
+
+{*****************************************************************************
+ TARMREALCONSTNODE
+*****************************************************************************}
+
+ procedure trvrealconstnode.pass_generate_code;
+ { I suppose the parser/pass_1 must make sure the generated real }
+ { constants are actually supported by the target processor? (JM) }
+ const
+ floattype2ait:array[tfloattype] of tairealconsttype=
+ (aitrealconst_s32bit,aitrealconst_s64bit,aitrealconst_s80bit,aitrealconst_s80bit,aitrealconst_s64comp,aitrealconst_s64comp,aitrealconst_s128bit);
+ var
+ lastlabel : tasmlabel;
+ realait : tairealconsttype;
+
+ begin
+ location_reset_ref(location,LOC_CREFERENCE,def_cgsize(resultdef),4);
+ lastlabel:=nil;
+ realait:=floattype2ait[tfloatdef(resultdef).floattype];
+ { const already used ? }
+ if not assigned(lab_real) then
+ begin
+ current_asmdata.getjumplabel(lastlabel);
+ lab_real:=lastlabel;
+ current_procinfo.aktlocaldata.concat(Tai_label.Create(lastlabel));
+ location.reference.symboldata:=current_procinfo.aktlocaldata.last;
+ case realait of
+ aitrealconst_s32bit :
+ begin
+ current_procinfo.aktlocaldata.concat(tai_realconst.create_s32real(ts32real(value_real)));
+ { range checking? }
+ if floating_point_range_check_error and
+ (tai_realconst(current_procinfo.aktlocaldata.last).value.s32val=MathInf.Value) then
+ Message(parser_e_range_check_error);
+ end;
+
+ aitrealconst_s64bit :
+ begin
+ current_procinfo.aktlocaldata.concat(tai_realconst.create_s64real(ts64real(value_real)));
+
+ { range checking? }
+ if floating_point_range_check_error and
+ (tai_realconst(current_procinfo.aktlocaldata.last).value.s64val=MathInf.Value) then
+ Message(parser_e_range_check_error);
+ end;
+
+ aitrealconst_s80bit :
+ begin
+ current_procinfo.aktlocaldata.concat(tai_realconst.create_s80real(value_real,tfloatdef(resultdef).size));
+
+ { range checking? }
+ if floating_point_range_check_error and
+ (tai_realconst(current_procinfo.aktlocaldata.last).value.s80val=MathInf.Value) then
+ Message(parser_e_range_check_error);
+ end;
+{$ifdef cpufloat128}
+ aitrealconst_s128bit :
+ begin
+ current_procinfo.aktlocaldata.concat(tai_realconst.create_s128real(value_real));
+
+ { range checking? }
+ if floating_point_range_check_error and
+ (tai_realconst(current_procinfo.aktlocaldata.last).value.s128val=MathInf.Value) then
+ Message(parser_e_range_check_error);
+ end;
+{$endif cpufloat128}
+
+ { the round is necessary for native compilers where comp isn't a float }
+ aitrealconst_s64comp :
+ if (value_real>9223372036854775807.0) or (value_real<-9223372036854775808.0) then
+ message(parser_e_range_check_error)
+ else
+ current_procinfo.aktlocaldata.concat(tai_realconst.create_s64compreal(round(value_real)));
+ else
+ internalerror(2005092401);
+ end;
+ end;
+ location.reference.symbol:=lab_real;
+ location.reference.refaddr:=addr_pcrel;
+ end;
+
+begin
+ crealconstnode:=trvrealconstnode;
+end.
diff --git a/compiler/riscv/nrvinl.pas b/compiler/riscv/nrvinl.pas
new file mode 100644
index 0000000000..9da7a05c1d
--- /dev/null
+++ b/compiler/riscv/nrvinl.pas
@@ -0,0 +1,341 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Generate Risc-V32/64 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 nrvinl;
+
+{$i fpcdefs.inc}
+
+interface
+
+ uses
+ cpubase,
+ node,ninl,ncginl;
+
+ type
+
+ { trvinlinenode }
+
+ trvinlinenode = 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;
+
+ function first_fma: 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;
+
+ procedure second_fma; 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;
+
+
+{*****************************************************************************
+ trvinlinenode
+*****************************************************************************}
+
+ function trvinlinenode.first_sqrt_real : tnode;
+ begin
+ if (current_settings.fputype >= fpu_fd) then
+ begin
+ expectloc:=LOC_FPUREGISTER;
+ first_sqrt_real := nil;
+ end
+ else
+ result:=inherited first_sqrt_real;
+ end;
+
+
+ function trvinlinenode.first_abs_real : tnode;
+ begin
+ if (current_settings.fputype >= fpu_fd) then
+ begin
+ expectloc:=LOC_FPUREGISTER;
+ first_abs_real := nil;
+ end
+ else
+ result:=inherited first_abs_real;
+ end;
+
+
+ function trvinlinenode.first_sqr_real : tnode;
+ begin
+ if (current_settings.fputype >= fpu_fd) then
+ begin
+ expectloc:=LOC_FPUREGISTER;
+ first_sqr_real := nil;
+ end
+ else
+ result:=inherited first_sqr_real;
+ end;
+
+
+ function trvinlinenode.first_round_real: tnode;
+ begin
+ if (current_settings.fputype >= fpu_fd) then
+ begin
+ expectloc:=LOC_FPUREGISTER;
+ first_round_real := nil;
+ end
+ else
+ result:=inherited first_round_real;
+ end;
+
+
+ function trvinlinenode.first_trunc_real: tnode;
+ begin
+ if (current_settings.fputype >= fpu_fd) then
+ begin
+ expectloc:=LOC_FPUREGISTER;
+ first_trunc_real := nil;
+ end
+ else
+ result:=inherited first_trunc_real;
+ end;
+
+
+ function trvinlinenode.first_fma: tnode;
+ begin
+ Result:=nil;
+ end;
+
+
+ { load the FPU into the an fpu register }
+ procedure trvinlinenode.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 trvinlinenode.second_sqrt_real;
+ begin
+ location.loc:=LOC_FPUREGISTER;
+ load_fpu_location;
+ case left.location.size of
+ OS_F32:
+ begin
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_S,location.register,
+ left.location.register));
+ cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+ end;
+ OS_F64:
+ begin
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_D,location.register,
+ left.location.register));
+ cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+ end
+ else
+ inherited;
+ end;
+ end;
+
+
+ procedure trvinlinenode.second_abs_real;
+ var
+ op: TAsmOp;
+ begin
+ location.loc:=LOC_FPUREGISTER;
+ load_fpu_location;
+ if (left.location.size = OS_F32) then
+ op := A_FSGNJX_S
+ else
+ op := A_FSGNJX_D;
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));
+ end;
+
+
+ procedure trvinlinenode.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.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+ end;
+
+
+ procedure trvinlinenode.second_round_real;
+ var
+ op: TAsmOp;
+ 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);
+ { convert to signed integer rounding towards zero (there's no "round to
+ integer using current rounding mode") }
+
+{$ifdef RISCV32}
+ if (left.location.size = OS_F32) then
+ op := A_FCVT_W_S
+ else
+ op := A_FCVT_W_D;
+{$else}
+ if (left.location.size = OS_F32) then
+ op := A_FCVT_L_S
+ else
+ op := A_FCVT_L_D;
+{$endif}
+
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register));
+ cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+ end;
+
+
+ procedure trvinlinenode.second_trunc_real;
+ var
+ op: TAsmOp;
+ 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);
+ { convert to signed integer rounding towards zero (there's no "round to
+ integer using current rounding mode") }
+
+{$ifdef RISCV32}
+ if (left.location.size = OS_F32) then
+ op := A_FCVT_W_S
+ else
+ op := A_FCVT_W_D;
+{$else}
+ if (left.location.size = OS_F32) then
+ op := A_FCVT_L_S
+ else
+ op := A_FCVT_L_D;
+{$endif}
+
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_roundingmode(op,location.register,left.location.register,RM_RTZ));
+ cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+ end;
+
+
+ procedure trvinlinenode.second_fma;
+ const
+ op : array[os_f32..os_f64,false..true,false..true] of TAsmOp =
+ (
+ (
+ (A_FMADD_S,A_FMSUB_S),
+ (A_FNMADD_S,A_FNMSUB_S)
+ ),
+ (
+ (A_FMADD_D,A_FMSUB_D),
+ (A_FNMADD_D,A_FNMSUB_D)
+ )
+ );
+ var
+ paraarray : array[1..3] of tnode;
+ i : integer;
+ negop3,
+ negproduct : boolean;
+ begin
+ if current_settings.fputype in [fpu_fd] then
+ begin
+ negop3:=false;
+ negproduct:=false;
+ paraarray[1]:=tcallparanode(tcallparanode(tcallparanode(parameters).nextpara).nextpara).paravalue;
+ paraarray[2]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue;
+ paraarray[3]:=tcallparanode(parameters).paravalue;
+
+ { check if a neg. node can be removed
+ this is possible because changing the sign of
+ a floating point number does not affect its absolute
+ value in any way
+ }
+ if paraarray[1].nodetype=unaryminusn then
+ begin
+ paraarray[1]:=tunarynode(paraarray[1]).left;
+ { do not release the unused unary minus node, it is kept and release together with the other nodes,
+ only no code is generated for it }
+ negproduct:=not(negproduct);
+ end;
+
+ if paraarray[2].nodetype=unaryminusn then
+ begin
+ paraarray[2]:=tunarynode(paraarray[2]).left;
+ { do not release the unused unary minus node, it is kept and release together with the other nodes,
+ only no code is generated for it }
+ negproduct:=not(negproduct);
+ end;
+
+ if paraarray[3].nodetype=unaryminusn then
+ begin
+ paraarray[3]:=tunarynode(paraarray[3]).left;
+ { do not release the unused unary minus node, it is kept and release together with the other nodes,
+ only no code is generated for it }
+ negop3:=true;
+ end;
+
+ for i:=1 to 3 do
+ secondpass(paraarray[i]);
+
+ { no memory operand is allowed }
+ for i:=1 to 3 do
+ begin
+ if not(paraarray[i].location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
+ hlcg.location_force_fpureg(current_asmdata.CurrAsmList,paraarray[i].location,paraarray[i].resultdef,true);
+ end;
+
+ location_reset(location,LOC_FPUREGISTER,paraarray[1].location.size);
+ location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
+
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(op[def_cgsize(resultdef), negproduct,negop3],location.register,paraarray[1].location.register,paraarray[2].location.register,paraarray[2].location.register));
+ cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+ end
+ else
+ internalerror(2014032301);
+ end;
+
+
+begin
+ cinlinenode:=trvinlinenode;
+end.
diff --git a/compiler/riscv/nrvset.pas b/compiler/riscv/nrvset.pas
new file mode 100644
index 0000000000..5a78175480
--- /dev/null
+++ b/compiler/riscv/nrvset.pas
@@ -0,0 +1,154 @@
+{
+ 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 nrvset;
+
+{$i fpcdefs.inc}
+
+interface
+
+ uses
+ node,nset,ncgset,cpubase,cgbase,cgobj,aasmbase,aasmtai,aasmdata,globtype;
+
+ type
+ trvcasenode = class(tcgcasenode)
+ protected
+ procedure optimizevalues(var max_linear_list : aint; var max_dist : aword);override;
+ function has_jumptable : boolean;override;
+ procedure genjumptable(hp : pcaselabel;min_,max_ : aint);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 trvcasenode.optimizevalues(var max_linear_list : aint; var max_dist : aword);
+ begin
+ max_linear_list := 3;
+ end;
+
+
+ function trvcasenode.has_jumptable : boolean;
+ begin
+ has_jumptable:=true;
+ end;
+
+
+ procedure trvcasenode.genjumptable(hp : pcaselabel;min_,max_ : aint);
+ 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_rel_sym(aitconst_32bit,table,elselabel));
+ i:=i+1;
+ end;
+ i:=t^._low;
+ while i<=t^._high do
+ begin
+ list.concat(Tai_const.Create_rel_sym(aitconst_32bit,table,blocklabel(t^.blockid)));
+ i:=i+1;
+ end;
+ last:=t^._high;
+ if assigned(t^.greater) then
+ genitem(list,t^.greater);
+ end;
+
+ begin
+ last:=min_;
+
+ {
+ .l
+ auipc x,hi(tbl-.l)
+ addi x,x,lo(tbl-.l)
+ sll idx,idx,2
+ add idx,idx,x
+ lw idx,idx,lo(tbl-.l)
+ add idx,idx,x
+ jalr x0,idx
+ }
+
+ { make it a 32bit register }
+ // allocate base and index registers register
+ 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
+ begin
+ { case expr greater than max_ => goto elselabel }
+ cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_A,aint(max_)-aint(min_),indexreg,elselabel);
+ end;
+ current_asmdata.getjumplabel(table);
+ { create reference, indexreg := indexreg * sizeof(jtentry) (= 4) }
+ cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, 4, indexreg);
+ reference_reset_symbol(href, table, 0, 4,[]);
+
+ hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
+ cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
+ reference_reset_base(href,hregister,0,ctempposinvalid,4,[]);
+ href.index:=indexreg;
+ indexreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
+ { load table entry }
+ cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,indexreg);
+ { add table base }
+ cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,hregister,indexreg);
+ { jump }
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_JALR,NR_X0, indexreg));
+
+ { generate jump table }
+ current_asmdata.CurrAsmList.concat(cai_align.Create(4));
+ current_asmdata.CurrAsmList.concat(Tai_label.Create(table));
+ genitem(current_asmdata.CurrAsmList,hp);
+ end;
+
+
+begin
+ ccasenode:=trvcasenode;
+end.
diff --git a/compiler/riscv/rgcpu.pas b/compiler/riscv/rgcpu.pas
new file mode 100644
index 0000000000..e24821575a
--- /dev/null
+++ b/compiler/riscv/rgcpu.pas
@@ -0,0 +1,126 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ This unit implements the Risc-V 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_imm12(spilltemp.offset) then
+ begin
+ helplist:=tasmlist.create;
+
+ if getregtype(tempreg)=R_INTREGISTER then
+ hreg:=tempreg
+ else
+ hreg:=cg.getintregister(helplist,OS_ADDR);
+
+ if (spilltemp.offset and $800)<>0 then
+ helplist.concat(taicpu.op_reg_const(A_LUI,hreg,((spilltemp.offset shr 12)+1) and $FFFFF))
+ else
+ helplist.concat(taicpu.op_reg_const(A_LUI,hreg,(spilltemp.offset shr 12) and $FFFFF));
+ helplist.concat(taicpu.op_reg_reg_const(A_ADDI,hreg,hreg,SarSmallint(spilltemp.offset shl 4,4)));
+
+ helplist.concat(taicpu.op_reg_reg_reg(A_ADD,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_imm12(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);
+
+ if (spilltemp.offset and $800)<>0 then
+ helplist.concat(taicpu.op_reg_const(A_LUI,hreg,((spilltemp.offset shr 12)+1) and $FFFFF))
+ else
+ helplist.concat(taicpu.op_reg_const(A_LUI,hreg,(spilltemp.offset shr 12) and $FFFFF));
+ helplist.concat(taicpu.op_reg_reg_const(A_ADDI,hreg,hreg,SarSmallint(spilltemp.offset shl 4,4)));
+
+ helplist.concat(taicpu.op_reg_reg_reg(A_ADD,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.
diff --git a/compiler/riscv32/aoptcpu.pas b/compiler/riscv32/aoptcpu.pas
new file mode 100644
index 0000000000..eb45ee1b9d
--- /dev/null
+++ b/compiler/riscv32/aoptcpu.pas
@@ -0,0 +1,77 @@
+{
+ Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+ Development Team
+
+ This unit implements the Risc-V32 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}
+
+uses cpubase, aoptobj, aoptcpub, aopt, aasmtai,aasmdata, aasmcpu;
+
+Type
+ TCpuAsmOptimizer = class(TAsmOptimizer)
+ { uses the same constructor as TAopObj }
+ function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
+
+ function PostPeepHoleOptsCpu(var p: tai): boolean; override;
+ End;
+
+Implementation
+
+ uses
+ cutils, verbose, cgbase, cgcpu, cgobj;
+
+
+ function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
+ var
+ next1, next2: tai;
+ l1, l2, shlcount: longint;
+ begin
+ result := false;
+ case p.typ of
+ ait_instruction:
+ begin
+ {case taicpu(p).opcode of
+ end;}
+ end;
+ end;
+ end;
+
+
+ function TCpuAsmOptimizer.PostPeepHoleOptsCpu(var p: tai): boolean;
+ var
+ next1: tai;
+ begin
+ result := false;
+ case p.typ of
+ ait_instruction:
+ begin
+ end;
+ end;
+ end;
+
+begin
+ casmoptimizer:=TCpuAsmOptimizer;
+End.
diff --git a/compiler/riscv32/aoptcpub.pas b/compiler/riscv32/aoptcpub.pas
new file mode 100644
index 0000000000..eb60faa451
--- /dev/null
+++ b/compiler/riscv32/aoptcpub.pas
@@ -0,0 +1,115 @@
+ {
+ 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 80x86 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}
+
+
+{ enable the following define if memory references can have a scaled index }
+{ define RefsHaveScale}
+
+{ enable the following define if memory references can have a segment }
+{ override }
+{ define RefsHaveSegment}
+
+Interface
+
+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;
+
+{ the maximum number of operands an instruction has }
+
+ MaxOps = 5;
+
+{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_JAL;
+ aopt_condjmp = A_Bxx;
+
+Implementation
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+Constructor TCondRegs.init;
+Begin
+End;
+
+Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl}
+Begin
+End;
+
+End.
diff --git a/compiler/riscv32/aoptcpuc.pas b/compiler/riscv32/aoptcpuc.pas
new file mode 100644
index 0000000000..4b82e87f4a
--- /dev/null
+++ b/compiler/riscv32/aoptcpuc.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 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.
diff --git a/compiler/riscv32/aoptcpud.pas b/compiler/riscv32/aoptcpud.pas
new file mode 100644
index 0000000000..2df7e2e49e
--- /dev/null
+++ b/compiler/riscv32/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.
diff --git a/compiler/riscv32/cgcpu.pas b/compiler/riscv32/cgcpu.pas
new file mode 100644
index 0000000000..ad2229f0da
--- /dev/null
+++ b/compiler/riscv32/cgcpu.pas
@@ -0,0 +1,641 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ This unit implements the code generator for the Risc-V32
+
+ 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,
+ cgbase,cgobj,cgrv,
+ aasmbase,aasmcpu,aasmtai,aasmdata,
+ cpubase,cpuinfo,cgutils,cg64f32,rgcpu,
+ parabase;
+
+ type
+ tcgrv32 = class(tcgrv)
+ procedure init_register_allocators;override;
+ procedure done_register_allocators;override;
+
+ { move instructions }
+ procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
+
+ { 32x32 to 64 bit multiplication }
+ procedure a_mul_reg_reg_pair(list: TAsmList;size: tcgsize; src1,src2,dstlo,dsthi: tregister); override;
+
+ procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
+ procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
+
+ procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
+ procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
+
+ procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
+ end;
+
+ tcg64frv = class(tcg64f32)
+ procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
+ procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
+ procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
+ procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
+ end;
+
+ procedure create_codegen;
+
+ implementation
+
+ uses
+ symtable,
+ globals,verbose,systems,cutils,
+ symconst,symsym,fmodule,
+ rgobj,tgobj,cpupi,procinfo,paramgr;
+
+
+ procedure tcgrv32.init_register_allocators;
+ begin
+ inherited init_register_allocators;
+ rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
+ [RS_X10,RS_X11,RS_X12,RS_X13,RS_X14,RS_X15,RS_X16,RS_X17,
+ RS_X31,RS_X30,RS_X29,RS_X28,
+ RS_X5,RS_X6,RS_X7,
+ RS_X3,RS_X4,
+ RS_X9,RS_X27,RS_X26,RS_X25,RS_X24,RS_X23,RS_X22,
+ RS_X21,RS_X20,RS_X19,RS_X18],first_int_imreg,[]);
+ rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
+ [RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,RS_F16,RS_F17,
+ RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
+ RS_F28,RS_F29,RS_F30,RS_F31,
+ RS_F8,RS_F9,
+ RS_F27,
+ RS_F26,RS_F25,RS_F24,RS_F23,RS_F22,RS_F21,RS_F20,RS_F19,RS_F18],first_fpu_imreg,[]);
+ end;
+
+
+ procedure tcgrv32.done_register_allocators;
+ begin
+ rg[R_INTREGISTER].free;
+ rg[R_FPUREGISTER].free;
+ inherited done_register_allocators;
+ end;
+
+
+ procedure tcgrv32.a_load_reg_reg(list : TAsmList;fromsize, tosize : tcgsize;reg1,reg2 : tregister);
+ var
+ ai: taicpu;
+ begin
+ if (fromsize=tosize) or
+ ((tcgsize2unsigned[fromsize]=tcgsize2unsigned[tosize]) and
+ (tcgsize2unsigned[fromsize]=OS_32)) then
+ begin
+ ai:=taicpu.op_reg_reg_const(A_ADDI,reg2,reg1,0);
+ list.concat(ai);
+ rg[R_INTREGISTER].add_move_instruction(ai);
+ end
+ else if fromsize=OS_8 then
+ begin
+ list.Concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$FF))
+ end
+ else
+ begin
+ if tcgsize2size[tosize]<tcgsize2size[fromsize] then
+ fromsize:=tosize;
+
+ if tcgsize2unsigned[fromsize]<>OS_32 then
+ list.Concat(taicpu.op_reg_reg_const(A_SLLI,reg2,reg1,8*(4-tcgsize2size[fromsize])))
+ else
+ a_load_reg_reg(list,fromsize,fromsize,reg1,reg2);
+
+ if tcgsize2unsigned[fromsize]=fromsize then
+ list.Concat(taicpu.op_reg_reg_const(A_SRLI,reg2,reg2,8*(4-tcgsize2size[fromsize])))
+ else
+ list.Concat(taicpu.op_reg_reg_const(A_SRAI,reg2,reg2,8*(4-tcgsize2size[fromsize])));
+ end;
+ end;
+
+
+ procedure tcgrv32.a_mul_reg_reg_pair(list: TAsmList;size: tcgsize; src1,src2,dstlo,dsthi: tregister);
+ var
+ op: tasmop;
+ begin
+ case size of
+ OS_INT: op:=A_MULHU;
+ OS_SINT: op:=A_MULH;
+ else
+ InternalError(2014061501);
+ end;
+ if (dsthi<>NR_NO) then
+ list.concat(taicpu.op_reg_reg_reg(op,dsthi,src1,src2));
+ { low word is always unsigned }
+ if (dstlo<>NR_NO) then
+ list.concat(taicpu.op_reg_reg_reg(A_MUL,dstlo,src1,src2));
+ end;
+
+
+ procedure tcgrv32.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
+ var
+ regs, fregs: tcpuregisterset;
+ r: TSuperRegister;
+ href: treference;
+ stackcount: longint;
+ begin
+ if not(nostackframe) then
+ begin
+ a_reg_alloc(list,NR_STACK_POINTER_REG);
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ a_reg_alloc(list,NR_FRAME_POINTER_REG);
+
+ reference_reset_base(href,NR_STACK_POINTER_REG,-4,ctempposinvalid,0,[]);
+
+ { Int registers }
+ regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
+
+ if (pi_do_call in current_procinfo.flags) then
+ regs:=regs+[RS_RETURN_ADDRESS_REG];
+
+ stackcount:=0;
+ for r:=RS_X0 to RS_X31 do
+ if r in regs then
+ inc(stackcount,4);
+
+ { Float registers }
+ fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+ for r:=RS_F0 to RS_F31 do
+ if r in fregs then
+ inc(stackcount,8);
+
+ inc(localsize,stackcount);
+ if not is_imm12(-localsize) then
+ begin
+ if not (RS_RETURN_ADDRESS_REG in regs) then
+ begin
+ include(regs,RS_RETURN_ADDRESS_REG);
+ inc(localsize,4);
+ end;
+ end;
+
+ stackcount:=0;
+ for r:=RS_X0 to RS_X31 do
+ if r in regs then
+ begin
+ list.concat(taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+ dec(href.offset,4);
+ end;
+
+ { Float registers }
+ for r:=RS_F0 to RS_F31 do
+ if r in fregs then
+ begin
+ list.concat(taicpu.op_reg_ref(A_FSD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+ dec(href.offset,8);
+ end;
+
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,0));
+
+ if localsize>0 then
+ begin
+ localsize:=align(localsize,4);
+
+ if is_imm12(-localsize) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize))
+ else
+ begin
+ a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
+ list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+ end;
+ end;
+ end;
+ end;
+
+
+ procedure tcgrv32.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
+ var
+ r: tsuperregister;
+ regs, fregs: tcpuregisterset;
+ stackcount, localsize: longint;
+ href: treference;
+ begin
+ if not(nostackframe) then
+ begin
+ regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
+
+ if (pi_do_call in current_procinfo.flags) then
+ regs:=regs+[RS_RETURN_ADDRESS_REG];
+
+ stackcount:=0;
+ reference_reset_base(href,NR_STACK_POINTER_REG,-4,ctempposinvalid,0,[]);
+ for r:=RS_X31 downto RS_X0 do
+ if r in regs then
+ dec(href.offset,4);
+
+ { Float registers }
+ fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+ for r:=RS_F0 to RS_F31 do
+ if r in fregs then
+ dec(stackcount,8);
+
+ localsize:=current_procinfo.calc_stackframe_size+(-href.offset-4);
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,0))
+ else if localsize>0 then
+ begin
+ localsize:=align(localsize,4);
+
+ if is_imm12(localsize) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
+ else
+ begin
+ if not (RS_RETURN_ADDRESS_REG in regs) then
+ begin
+ include(regs,RS_RETURN_ADDRESS_REG);
+ dec(href.offset,4);
+ inc(localsize,4);
+ end;
+
+ a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+ end;
+ end;
+
+ { Float registers }
+ for r:=RS_F31 downto RS_F0 do
+ if r in fregs then
+ begin
+ inc(href.offset,8);
+ list.concat(taicpu.op_reg_ref(A_FLD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+ end;
+
+ for r:=RS_X31 downto RS_X0 do
+ if r in regs then
+ begin
+ inc(href.offset,4);
+ list.concat(taicpu.op_reg_ref(A_LW,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+ inc(stackcount);
+ end;
+ end;
+
+ list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_RETURN_ADDRESS_REG));
+ end;
+
+
+ procedure tcgrv32.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
+ var
+ paraloc1, paraloc2, paraloc3: TCGPara;
+ pd: tprocdef;
+ begin
+ pd:=search_system_proc('MOVE');
+ paraloc1.init;
+ paraloc2.init;
+ paraloc3.init;
+ paramanager.getintparaloc(list, pd, 1, paraloc1);
+ paramanager.getintparaloc(list, pd, 2, paraloc2);
+ paramanager.getintparaloc(list, pd, 3, paraloc3);
+ a_load_const_cgpara(list, OS_SINT, len, paraloc3);
+ a_loadaddr_ref_cgpara(list, dest, paraloc2);
+ a_loadaddr_ref_cgpara(list, Source, paraloc1);
+ paramanager.freecgpara(list, paraloc3);
+ paramanager.freecgpara(list, paraloc2);
+ paramanager.freecgpara(list, paraloc1);
+ alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
+ alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
+ a_call_name(list, 'FPC_MOVE', false);
+ dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
+ dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
+ paraloc3.done;
+ paraloc2.done;
+ paraloc1.done;
+ end;
+
+
+ procedure tcgrv32.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
+ var
+ tmpreg1, hreg, countreg: TRegister;
+ src, dst, src2, dst2: TReference;
+ lab: tasmlabel;
+ Count, count2: aint;
+
+ function reference_is_reusable(const ref: treference): boolean;
+ begin
+ result:=(ref.base<>NR_NO) and (ref.index=NR_NO) and
+ (ref.symbol=nil) and
+ is_imm12(ref.offset);
+ end;
+
+ begin
+ src2:=source;
+ fixref(list,src2);
+
+ dst2:=dest;
+ fixref(list,dst2);
+
+ if len > high(longint) then
+ internalerror(2002072704);
+ { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
+ allocated on stack. This can only be done before tmipsprocinfo.set_first_temp_offset,
+ i.e. before secondpass. Other internal procedures request correct stack frame
+ by setting pi_do_call during firstpass, but for this particular one it is impossible.
+ Therefore, if the current procedure is a leaf one, we have to leave it that way. }
+
+ { anybody wants to determine a good value here :)? }
+ if (len > 100) and
+ assigned(current_procinfo) and
+ (pi_do_call in current_procinfo.flags) then
+ g_concatcopy_move(list, src2, dst2, len)
+ else
+ begin
+ Count := len div 4;
+ if (count<=4) and reference_is_reusable(src2) then
+ src:=src2
+ else
+ begin
+ reference_reset(src,sizeof(aint),[]);
+ { load the address of src2 into src.base }
+ src.base := GetAddressRegister(list);
+ a_loadaddr_ref_reg(list, src2, src.base);
+ end;
+ if (count<=4) and reference_is_reusable(dst2) then
+ dst:=dst2
+ else
+ begin
+ reference_reset(dst,sizeof(aint),[]);
+ { load the address of dst2 into dst.base }
+ dst.base := GetAddressRegister(list);
+ a_loadaddr_ref_reg(list, dst2, dst.base);
+ end;
+ { generate a loop }
+ if Count > 4 then
+ begin
+ countreg := GetIntRegister(list, OS_INT);
+ tmpreg1 := GetIntRegister(list, OS_INT);
+ a_load_const_reg(list, OS_INT, Count, countreg);
+ current_asmdata.getjumplabel(lab);
+ a_label(list, lab);
+ list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
+ list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
+ list.concat(taicpu.op_reg_reg_const(A_ADDI, src.base, src.base, 4));
+ list.concat(taicpu.op_reg_reg_const(A_ADDI, dst.base, dst.base, 4));
+ list.concat(taicpu.op_reg_reg_const(A_ADDI, countreg, countreg, -1));
+ a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_X0,countreg,lab);
+ len := len mod 4;
+ end;
+ { unrolled loop }
+ Count := len div 4;
+ if Count > 0 then
+ begin
+ tmpreg1 := GetIntRegister(list, OS_INT);
+ for count2 := 1 to Count do
+ begin
+ list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
+ list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
+ Inc(src.offset, 4);
+ Inc(dst.offset, 4);
+ end;
+ len := len mod 4;
+ end;
+ if (len and 4) <> 0 then
+ begin
+ hreg := GetIntRegister(list, OS_INT);
+ a_load_ref_reg(list, OS_32, OS_32, src, hreg);
+ a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
+ Inc(src.offset, 4);
+ Inc(dst.offset, 4);
+ end;
+ { copy the leftovers }
+ if (len and 2) <> 0 then
+ begin
+ hreg := GetIntRegister(list, OS_INT);
+ a_load_ref_reg(list, OS_16, OS_16, src, hreg);
+ a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
+ Inc(src.offset, 2);
+ Inc(dst.offset, 2);
+ end;
+ if (len and 1) <> 0 then
+ begin
+ hreg := GetIntRegister(list, OS_INT);
+ a_load_ref_reg(list, OS_8, OS_8, src, hreg);
+ a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
+ end;
+ end;
+ end;
+
+
+ procedure tcgrv32.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
+ begin
+
+ end;
+
+
+ procedure tcg64frv.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
+ var
+ tmpreg1: TRegister;
+ begin
+ case op of
+ OP_NOT:
+ begin
+ cg.a_op_reg_reg(list,OP_NOT,OS_32,regsrc.reglo,regdst.reglo);
+ cg.a_op_reg_reg(list,OP_NOT,OS_32,regsrc.reghi,regdst.reghi);
+ end;
+ OP_NEG:
+ begin
+ tmpreg1 := cg.GetIntRegister(list, OS_INT);
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reglo, NR_X0, regsrc.reglo));
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, NR_X0, regdst.reglo));
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, NR_X0, regsrc.reghi));
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, regdst.reghi, tmpreg1));
+ end;
+ else
+ a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
+ end;
+ end;
+
+
+ procedure tcg64frv.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
+ begin
+ a_op64_const_reg_reg(list,op,size,value,reg,reg);
+ end;
+
+
+ procedure tcg64frv.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
+ var
+ signed: Boolean;
+ tmplo, carry, tmphi, hreg: TRegister;
+ begin
+ case op of
+ OP_AND,OP_OR,OP_XOR:
+ begin
+ cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
+ cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
+ end;
+ OP_ADD:
+ begin
+ signed:=(size in [OS_S64]);
+ tmplo := cg.GetIntRegister(list,OS_S32);
+ carry := cg.GetIntRegister(list,OS_S32);
+ // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
+ list.concat(taicpu.op_reg_reg_reg(A_ADD, tmplo, regsrc2.reglo, regsrc1.reglo));
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmplo, regsrc2.reglo));
+ cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
+ if signed then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_ADD, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
+ list.concat(taicpu.op_reg_reg_reg(A_ADD, regdst.reghi, regdst.reghi, carry));
+ end
+ else
+ begin
+ tmphi:=cg.GetIntRegister(list,OS_INT);
+ hreg:=cg.GetIntRegister(list,OS_INT);
+ cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
+ // first add carry to one of the addends
+ list.concat(taicpu.op_reg_reg_reg(A_ADD, tmphi, regsrc2.reghi, carry));
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regsrc2.reghi));
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
+ // then add another addend
+ list.concat(taicpu.op_reg_reg_reg(A_ADD, regdst.reghi, tmphi, regsrc1.reghi));
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regdst.reghi, tmphi));
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
+ end;
+ end;
+ OP_SUB:
+ begin
+ signed:=(size in [OS_S64]);
+ tmplo := cg.GetIntRegister(list,OS_S32);
+ carry := cg.GetIntRegister(list,OS_S32);
+ // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, tmplo, regsrc2.reglo, regsrc1.reglo));
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reglo,tmplo));
+ cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
+ if signed then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, regdst.reghi, carry));
+ end
+ else
+ begin
+ tmphi:=cg.GetIntRegister(list,OS_INT);
+ hreg:=cg.GetIntRegister(list,OS_INT);
+ cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
+ // first subtract the carry...
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, tmphi, regsrc2.reghi, carry));
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reghi, tmphi));
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
+ // ...then the subtrahend
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, tmphi, regsrc1.reghi));
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regdst.reghi));
+ list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
+ end;
+ end;
+ else
+ internalerror(2002072801);
+ end;
+ end;
+
+
+ procedure tcg64frv.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
+ var
+ tmplo,carry: TRegister;
+ hisize: tcgsize;
+ begin
+ carry:=NR_NO;
+ if (size in [OS_S64]) then
+ hisize:=OS_S32
+ else
+ hisize:=OS_32;
+
+ case op of
+ OP_AND,OP_OR,OP_XOR:
+ begin
+ cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
+ cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
+ end;
+
+ OP_ADD:
+ begin
+ if lo(value)<>0 then
+ begin
+ tmplo:=cg.GetIntRegister(list,OS_32);
+ carry:=cg.GetIntRegister(list,OS_32);
+
+ if is_imm12(aint(lo(value))) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,tmplo,regsrc.reglo,aint(lo(value))))
+ else
+ begin
+ cg.a_load_const_reg(list,OS_INT,aint(lo(value)),tmplo);
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,tmplo,tmplo,regsrc.reglo))
+ end;
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,tmplo,regsrc.reglo));
+ cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
+ end
+ else
+ cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
+
+ { With overflow checking and unsigned args, this generates slighly suboptimal code
+ ($80000000 constant loaded twice). Other cases are fine. Getting it perfect does not
+ look worth the effort. }
+ cg.a_op_const_reg_reg(list,OP_ADD,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi);
+ if carry<>NR_NO then
+ cg.a_op_reg_reg_reg(list,OP_ADD,hisize,carry,regdst.reghi,regdst.reghi);
+ end;
+
+ OP_SUB:
+ begin
+ carry:=NR_NO;
+ if lo(value)<>0 then
+ begin
+ tmplo:=cg.GetIntRegister(list,OS_32);
+ carry:=cg.GetIntRegister(list,OS_32);
+
+ if is_imm12(-aint(lo(value))) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,tmplo,regsrc.reglo,-aint(lo(value))))
+ else
+ begin
+ cg.a_load_const_reg(list,OS_INT,aint(lo(value)),tmplo);
+ list.concat(taicpu.op_reg_reg_reg(A_SUB,tmplo,tmplo,regsrc.reglo))
+ end;
+ list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,regsrc.reglo,tmplo));
+ cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
+ end
+ else
+ cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
+
+ cg.a_op_const_reg_reg(list,OP_SUB,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi);
+ if carry<>NR_NO then
+ cg.a_op_reg_reg_reg(list,OP_SUB,hisize,carry,regdst.reghi,regdst.reghi);
+ end;
+ else
+ InternalError(2013050301);
+ end;
+ end;
+
+
+ procedure create_codegen;
+ begin
+ cg := tcgrv32.create;
+ cg64 :=tcg64frv.create;
+ end;
+
+end.
diff --git a/compiler/riscv32/cpubase.pas b/compiler/riscv32/cpubase.pas
new file mode 100644
index 0000000000..46ec67c966
--- /dev/null
+++ b/compiler/riscv32/cpubase.pas
@@ -0,0 +1,428 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Contains the base types for the Risc-V32
+
+ 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 base types for the Risc-V32
+}
+unit cpubase;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+ strings,globtype,
+ cutils,cclasses,aasmbase,cpuinfo,cgbase;
+
+
+{*****************************************************************************
+ Assembler Opcodes
+*****************************************************************************}
+
+ type
+ TAsmOp=(A_None,
+ { Pseudo instructions }
+ A_NOP,
+ { normal opcodes }
+ A_LUI,A_AUIPC,A_JAL,A_JALR,
+ A_Bxx,A_LB,A_LH,A_LW,A_LBU,A_LHU,
+ A_SB,A_SH,A_SW,
+ A_ADDI,A_SLTI,A_SLTIU,
+ A_XORI,A_ORI,A_ANDI,
+ A_SLLI,A_SRLI,A_SRAI,
+ A_ADD,A_SUB,A_SLL,A_SLT,A_SLTU,
+ A_XOR,A_SRL,A_SRA,A_OR,A_AND,
+ A_FENCE,A_FENCE_I,
+ A_ECALL,A_EBREAK,
+ A_CSRRW,A_CSRRS,A_CSRRC,A_CSRRWI,A_CSRRSI,A_CSRRCI,
+
+ { M-extension }
+ A_MUL,A_MULH,A_MULHSU,A_MULHU,
+ A_DIV,A_DIVU,A_REM,A_REMU,
+
+ { A-extension }
+ A_LR_W,A_SC_W,A_AMOSWAP_W,A_AMOADD_W,A_AMOXOR_W,A_AMOAND_W,
+ A_AMOOR_W,A_AMOMIN_W,A_AMOMAX_W,A_AMOMINU_W,A_AMOMAXU_W,
+
+ { F-extension }
+ A_FLW,A_FSW,
+ A_FMADD_S,A_FMSUB_S,A_FNMSUB_S,A_FNMADD_S,
+ A_FADD_S,A_FSUB_S,A_FMUL_S,A_FDIV_S,
+ A_FSQRT_S,A_FSGNJ_S,A_FSGNJN_S,A_FSGNJX_S,
+ A_FMIN_S,A_FMAX_S,
+ A_FMV_X_S,A_FEQ_S,A_FLT_S,A_FLE_S,A_FCLASS_S,
+ A_FCVT_W_S,A_FCVT_WU_S,A_FCVT_S_W,A_FCVT_S_WU,
+ A_FMV_S_X,
+ A_FRCSR,A_FRRM,A_FRFLAGS,A_FSCSR,A_FSRM,
+ A_FSFLAGS,A_FSRMI,A_FSFLAGSI,
+
+ { D-extension }
+ A_FLD,A_FSD,
+ A_FMADD_D,A_FMSUB_D,A_FNMSUB_D,A_FNMADD_D,
+ A_FADD_D,A_FSUB_D,A_FMUL_D,A_FDIV_D,
+ A_FSQRT_D,A_FSGNJ_D,A_FSGNJN_D,A_FSGNJX_D,
+ A_FMIN_D,A_FMAX_D,
+ A_FEQ_D,A_FLT_D,A_FLE_D,A_FCLASS_D,
+ A_FCVT_D_S,A_FCVT_S_D,
+ A_FCVT_W_D,A_FCVT_WU_D,A_FCVT_D_W,A_FCVT_D_WU,
+
+ { Machine mode }
+ A_MRET,A_HRET,A_SRET,A_URET,
+ A_WFI,
+
+ { Supervisor }
+ A_SFENCE_VM
+ );
+
+ {# This should define the array of instructions as string }
+ op2strtable=array[tasmop] of string[8];
+
+ 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 rrv32nor.inc}-1;
+ totherregisterset = set of tregisterindex;
+
+ 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 rrv32sup.inc}
+
+ { No Subregisters }
+ R_SUBWHOLE=R_SUBNONE;
+
+ { Available Registers }
+ {$i rrv32con.inc}
+
+ { Integer Super registers first and last }
+ first_int_imreg = $20;
+
+ { Float Super register first and last }
+ first_fpu_imreg = $20;
+
+ { MM Super register first and last }
+ first_mm_imreg = $20;
+
+{ TODO: Calculate bsstart}
+ regnumber_count_bsstart = 64;
+
+ regnumber_table : array[tregisterindex] of tregister = (
+ {$i rrv32num.inc}
+ );
+
+ regstabs_table : array[tregisterindex] of shortint = (
+ {$i rrv32sta.inc}
+ );
+
+ regdwarf_table : array[tregisterindex] of shortint = (
+ {$i rrv32dwa.inc}
+ );
+
+{*****************************************************************************
+ Conditions
+*****************************************************************************}
+
+ type
+ TAsmCond = (C_None { unconditional jumps },
+ C_LT,C_LTU,C_GE,C_GEU,C_NE,C_EQ);
+
+ const
+ cond2str: Array[TAsmCond] of string[4] = ({cf_none}'',
+ { conditions when not using ctr decrement etc}
+ 'lt','ltu','ge','geu','ne','eq');
+
+ uppercond2str: Array[TAsmCond] of string[4] = ({cf_none}'',
+ { conditions when not using ctr decrement etc}
+ 'LT','LTU','GE','GEU','NE','EQ');
+
+
+{*****************************************************************************
+ Flags
+*****************************************************************************}
+
+ type
+ TResFlagsEnum = (F_EQ,F_NE,F_LT,F_LTU,F_GE,F_GEU);
+
+{*****************************************************************************
+ Reference
+*****************************************************************************}
+
+{*****************************************************************************
+ Operand Sizes
+*****************************************************************************}
+
+
+{*****************************************************************************
+ Constants
+*****************************************************************************}
+
+ const
+ max_operands = 5;
+
+
+{*****************************************************************************
+ Default generic sizes
+*****************************************************************************}
+
+ {# Defines the default address size for a processor, }
+ OS_ADDR = OS_32;
+ {# the natural int size for a processor,
+ has to match osuinttype/ossinttype as initialized in psystem }
+ OS_INT = OS_32;
+ OS_SINT = OS_S32;
+ {# 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 rrv32sta.inc}
+ );
+
+
+{*****************************************************************************
+ Generic Register names
+*****************************************************************************}
+
+ {# Stack pointer register }
+ NR_STACK_POINTER_REG = NR_X2;
+ RS_STACK_POINTER_REG = RS_X2;
+ {# Frame pointer register }
+ NR_FRAME_POINTER_REG = NR_X8;
+ RS_FRAME_POINTER_REG = RS_X8;
+
+ NR_PIC_OFFSET_REG = NR_X3;
+ { Return address of a function }
+ NR_RETURN_ADDRESS_REG = NR_X1;
+ RS_RETURN_ADDRESS_REG = RS_X1;
+ { Results are returned in this register (32-bit values) }
+ NR_FUNCTION_RETURN_REG = NR_X10;
+ RS_FUNCTION_RETURN_REG = RS_X10;
+ { Low part of 64bit return value }
+ NR_FUNCTION_RETURN64_LOW_REG = NR_X10;
+ RS_FUNCTION_RETURN64_LOW_REG = RS_X10;
+ { High part of 64bit return value }
+ NR_FUNCTION_RETURN64_HIGH_REG = NR_X11;
+ RS_FUNCTION_RETURN64_HIGH_REG = RS_X11;
+ { 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_F10;
+ NR_MM_RESULT_REG = NR_NO;
+
+ NR_DEFAULTFLAGS = NR_NO;
+ RS_DEFAULTFLAGS = 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..12] of tsuperregister = (
+ RS_X2,
+ RS_X8,RS_X9,
+ RS_X18,RS_X19,
+ RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27
+ );
+
+ { 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 = 4; { for 32-bit version only }
+
+
+{*****************************************************************************
+ CPU Dependent Constants
+*****************************************************************************}
+
+ maxfpuregs = 8;
+
+{*****************************************************************************
+ Helpers
+*****************************************************************************}
+
+ function is_imm12(value: aint): boolean;
+ function is_lui_imm(value: aint): 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 conditions_equal(const c1,c2: TAsmCond): boolean;
+
+implementation
+
+ uses
+ rgbase,verbose;
+
+ const
+ std_regname_table : TRegNameTable = (
+ {$i rrv32std.inc}
+ );
+
+ regnumber_index : array[tregisterindex] of tregisterindex = (
+ {$i rrv32rni.inc}
+ );
+
+ std_regname_index : array[tregisterindex] of tregisterindex = (
+ {$i rrv32sri.inc}
+ );
+
+
+{*****************************************************************************
+ Helpers
+*****************************************************************************}
+
+ function is_imm12(value: aint): boolean;
+ begin
+ result:=(value >= -2048) and (value <= 2047);
+ end;
+
+
+ function is_lui_imm(value: aint): boolean;
+ begin
+ result:=SarInt64((value and $FFFFF000) shl 32, 32) = value;
+ end;
+
+
+ function is_calljmp(o:tasmop):boolean;
+ begin
+ is_calljmp:=false;
+ case o of
+ A_JAL,A_JALR,A_Bxx:
+ is_calljmp:=true;
+ end;
+ end;
+
+
+ function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+ const
+ inv_condflags:array[TAsmCond] of TAsmCond=(C_None,
+ C_GE,C_GEU,C_LT,C_LTU,C_EQ,C_NE);
+ begin
+ result := inv_condflags[c];
+ end;
+
+
+ function reg_cgsize(const reg: tregister): tcgsize;
+ begin
+ case getregtype(reg) of
+ R_INTREGISTER :
+ result:=OS_32;
+ R_MMREGISTER:
+ result:=OS_M128;
+ R_FPUREGISTER:
+ result:=OS_F64;
+ else
+ internalerror(200303181);
+ 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(200603251);
+ end;
+
+ function conditions_equal(const c1, c2: TAsmCond): boolean;
+ begin
+ result:=c1=c2;
+ end;
+
+end.
diff --git a/compiler/riscv32/cpuinfo.pas b/compiler/riscv32/cpuinfo.pas
new file mode 100644
index 0000000000..755da23976
--- /dev/null
+++ b/compiler/riscv32/cpuinfo.pas
@@ -0,0 +1,135 @@
+{
+ Copyright (c) 1998-2002 by the Free Pascal development team
+
+ Basic Processor information for the Risc-V32
+
+ 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;
+
+Interface
+
+ uses
+ globtype;
+
+Type
+ bestreal = double;
+{$if FPC_FULLVERSION>20700}
+ bestrealrec = TDoubleRec;
+{$endif FPC_FULLVERSION>20700}
+ ts32real = single;
+ ts64real = double;
+ ts80real = extended;
+ ts128real = extended;
+ ts64comp = comp;
+
+ pbestreal=^bestreal;
+
+ { possible supported processors for this target }
+ tcputype =
+ (cpu_none,
+ cpu_rv32imafd,
+ cpu_rv32ima,
+ cpu_rv32im,
+ cpu_rv32i
+ );
+
+ tfputype =
+ (fpu_none,
+ fpu_libgcc,
+ fpu_soft,
+ 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_stdcall,
+ { the difference to stdcall is only the name mangling }
+ pocall_cdecl,
+ { the difference to stdcall is only the name mangling }
+ pocall_cppdecl,
+ { pass all const records by reference }
+ pocall_mwpascal
+ ];
+
+ cputypestr : array[tcputype] of string[10] = ('',
+ 'RV32IMAFD',
+ 'RV32IMA',
+ 'RV32IM',
+ 'RV32I'
+ );
+
+ fputypestr : array[tfputype] of string[8] = (
+ 'LIBGCC',
+ 'NONE',
+ 'SOFT',
+ '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]+
+ [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,
+ cs_opt_tailrecursion,cs_opt_reorder_fields,cs_opt_fastmath,
+ cs_opt_stackframe];
+
+ level1optimizerswitches = genericlevel1optimizerswitches;
+ level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches + [cs_opt_regvar,cs_opt_nodecse,cs_opt_tailrecursion];
+ level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
+ level4optimizerswitches = genericlevel4optimizerswitches + level3optimizerswitches + [cs_opt_stackframe];
+
+ type
+ tcpuflags =
+ (CPURV_HAS_MUL,
+ CPURV_HAS_ATOMIC,
+ CPURV_HAS_COMPACT
+ );
+
+ const
+ cpu_capabilities : array[tcputype] of set of tcpuflags =
+ ( { cpu_none } [],
+ { cpu_rv32imafd } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+ { cpu_rv32ima } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+ { cpu_rv32im } [CPURV_HAS_MUL],
+ { cpu_rv32i } []
+ );
+
+Implementation
+
+end.
diff --git a/compiler/riscv32/cpunode.pas b/compiler/riscv32/cpunode.pas
new file mode 100644
index 0000000000..463614ddf5
--- /dev/null
+++ b/compiler/riscv32/cpunode.pas
@@ -0,0 +1,50 @@
+{
+ Copyright (c) 2000-2002 by Florian Klaempfl
+
+ Includes the Risc-V32 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)
+ }
+ nrv32add,
+ nrv32cal,
+ nrvset,
+ nrvinl,
+ nrv32mat,
+ nrv32cnv
+// ,nrvcon
+ ;
+
+end.
diff --git a/compiler/riscv32/cpupara.pas b/compiler/riscv32/cpupara.pas
new file mode 100644
index 0000000000..7c90ebd074
--- /dev/null
+++ b/compiler/riscv32/cpupara.pas
@@ -0,0 +1,550 @@
+{
+ Copyright (c) 2002 by Florian Klaempfl
+
+ Risc-V32 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;
+
+ procedure getintparaloc(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; 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; varargsparas: boolean):longint;
+ end;
+
+ implementation
+
+ uses
+ cpuinfo,globals,
+ verbose,systems,
+ defutil,symtable,
+ procinfo,cpupi;
+
+
+ function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
+ begin
+ result:=[RS_X0..RS_X31]-[RS_X2,RS_X8..RS_X9,RS_X18..RS_X27];
+ end;
+
+
+ function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
+ begin
+ result:=[RS_F0..RS_F31]-[RS_F8..RS_F9,RS_F18..RS_F27];
+ end;
+
+
+ procedure tcpuparamanager.getintparaloc(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(200309271);
+ loc:=LOC_REGISTER;
+ register:=newreg(R_INTREGISTER,RS_X10+nr,R_SUBWHOLE);
+ end
+ else
+ begin
+ loc:=LOC_REFERENCE;
+ paraloc^.reference.index:=NR_STACK_POINTER_REG;
+ reference.offset:=sizeof(pint)*(nr);
+ end;
+ end;
+ end;
+
+
+
+ function getparaloc(p : tdef) : tcgloc;
+
+ 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:
+ if (cs_fp_emulation in current_settings.moduleswitches) or
+ (current_settings.fputype in [fpu_soft]) then
+ result := LOC_REGISTER
+ else
+ result := LOC_FPUREGISTER;
+ enumdef:
+ result:=LOC_REGISTER;
+ pointerdef:
+ result:=LOC_REGISTER;
+ formaldef:
+ result:=LOC_REGISTER;
+ classrefdef:
+ result:=LOC_REGISTER;
+ procvardef:
+ if (p.size = sizeof(pint)) then
+ result:=LOC_REGISTER
+ else
+ result:=LOC_REFERENCE;
+ recorddef:
+ if (p.size > 4) then
+ result:=LOC_REFERENCE
+ else
+ result:=LOC_REGISTER;
+ 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(2002071001);
+ 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;
+ { regular procvars must be passed by value, because you cannot pass
+ the address of a local stack location when calling e.g.
+ pthread_create with the address of a function (first of all it
+ expects the address of the function to execute and not the address
+ of a memory location containing that address, and secondly if you
+ first store the address on the stack and then pass the address of
+ this stack location, then this stack location may no longer be
+ valid when the newly started thread accesses it.
+
+ However, for "procedure of object" we must use the same calling
+ convention as for "8 byte record" due to the need for
+ interchangeability with the TMethod record type.
+ }
+ procvardef :
+ result:=
+ (def.size <> sizeof(pint));
+ recorddef :
+ result := (def.size > 8) or (varspez = vs_const);
+ 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];
+ end;
+ end;
+
+
+ procedure tcpuparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
+ begin
+ cur_stack_offset:=0;
+ curintreg:=RS_X10;
+ curfloatreg:=RS_F10;
+ curmmreg:=RS_NO;
+ end;
+
+
+ function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
+ var
+ paraloc : pcgparalocation;
+ retcgsize : tcgsize;
+ begin
+ if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
+ exit;
+
+ paraloc:=result.add_location;
+ { Return in FPU register? }
+ if result.def.typ=floatdef then
+ begin
+ paraloc^.loc:=LOC_FPUREGISTER;
+ paraloc^.register:=NR_FPU_RESULT_REG;
+ paraloc^.size:=retcgsize;
+ paraloc^.def:=result.def;
+ end
+ else
+ { Return in register }
+ begin
+ if retcgsize in [OS_64,OS_S64] then
+ begin
+ { low 32bits }
+ paraloc^.loc:=LOC_REGISTER;
+ if side=callerside then
+ paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
+ else
+ paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
+ paraloc^.size:=OS_32;
+ paraloc^.def:=u32inttype;
+ { high 32bits }
+ paraloc:=result.add_location;
+ paraloc^.loc:=LOC_REGISTER;
+ if side=callerside then
+ paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
+ else
+ paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
+ paraloc^.size:=OS_32;
+ paraloc^.def:=u32inttype;
+ end
+ else
+ begin
+ paraloc^.loc:=LOC_REGISTER;
+ if side=callerside then
+ paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
+ else
+ paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
+ paraloc^.size:=retcgsize;
+ paraloc^.def:=result.def;
+ end;
+ end;
+ 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; varargsparas: boolean):longint;
+ var
+ stack_offset: longint;
+ paralen: aint;
+ nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
+ locdef,
+ fdef,
+ paradef : tdef;
+ paraloc : pcgparalocation;
+ i : integer;
+ hp : tparavarsym;
+ loc : tcgloc;
+ paracgsize: tcgsize;
+ firstparaloc: boolean;
+
+ begin
+{$ifdef extdebug}
+ if po_explicitparaloc in p.procoptions then
+ internalerror(200411141);
+{$endif extdebug}
+
+ result:=0;
+ nextintreg := curintreg;
+ nextfloatreg := curfloatreg;
+ nextmmreg := curmmreg;
+ stack_offset := cur_stack_offset;
+ maxfpureg := RS_F17;
+
+ for i:=0 to paras.count-1 do
+ begin
+ hp:=tparavarsym(paras[i]);
+ paradef := hp.vardef;
+ { Syscall for Morphos can have already a paraloc set }
+ if (vo_has_explicit_paraloc in hp.varoptions) then
+ begin
+ if not(vo_is_syscall_lib in hp.varoptions) then
+ internalerror(200412153);
+ continue;
+ end;
+ hp.paraloc[side].reset;
+ { currently only support C-style array of const }
+ if (p.proccalloption in cstylearrayofconst) and
+ is_array_of_const(paradef) 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_X0;
+ paraloc^.size := OS_ADDR;
+ paraloc^.def:=voidpointertype;
+ break;
+ end;
+
+ if push_addr_param(hp.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)];
+ paracgsize:=def_cgsize(paradef);
+ { for things like formaldef }
+ if (paracgsize=OS_NO) then
+ begin
+ paracgsize:=OS_ADDR;
+ paralen := tcgsize2size[OS_ADDR];
+ end;
+ end;
+
+ loc := getparaloc(paradef);
+
+ hp.paraloc[side].alignment:=std_param_align;
+ hp.paraloc[side].size:=paracgsize;
+ hp.paraloc[side].intsize:=paralen;
+ hp.paraloc[side].def:=paradef;
+{$ifndef cpu64bitaddr}
+ if (is_64bit(paradef)) and
+ odd(nextintreg-RS_X10) then
+ inc(nextintreg);
+{$endif not cpu64bitaddr}
+ if (paralen = 0) then
+ if (paradef.typ = recorddef) then
+ begin
+ paraloc:=hp.paraloc[side].add_location;
+ paraloc^.loc := LOC_VOID;
+ end
+ else
+ internalerror(2005011310);
+ locdef:=paradef;
+ firstparaloc:=true;
+ { can become < 0 for e.g. 3-byte records }
+ while (paralen > 0) do
+ begin
+ paraloc:=hp.paraloc[side].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_X17) and
+ (not(vo_is_parentfp in hp.varoptions) or
+ not(po_delphi_nested_cc in p.procoptions)) then
+ begin
+ paraloc^.loc := loc;
+ { make sure we don't lose whether or not the type is signed }
+ if (paradef.typ<>orddef) then
+ begin
+ paracgsize:=int_cgsize(paralen);
+ locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
+ end;
+ if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
+ begin
+ paraloc^.size:=OS_INT;
+ paraloc^.def:=u32inttype;
+ end
+ else
+ begin
+ paraloc^.size:=paracgsize;
+ paraloc^.def:=locdef;
+ end;
+ { aix requires that record data stored in parameter
+ registers is left-aligned }
+ if (target_info.system in systems_aix) and
+ (paradef.typ = recorddef) and
+ (paralen < sizeof(aint)) then
+ begin
+ paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
+ paraloc^.size := OS_INT;
+ paraloc^.def := u32inttype;
+ end;
+ paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
+ inc(nextintreg);
+ dec(paralen,tcgsize2size[paraloc^.size]);
+ end
+ else if (loc = LOC_FPUREGISTER) and
+ (nextintreg <= RS_X17) then
+ begin
+ paraloc^.loc:=loc;
+ paraloc^.size := paracgsize;
+ paraloc^.def := paradef;
+ paraloc^.register:=newreg(R_FPUREGISTER,nextintreg,R_SUBWHOLE);
+ inc(nextintreg);
+ dec(paralen,tcgsize2size[paraloc^.size]);
+ end
+ else { LOC_REFERENCE }
+ begin
+ 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(2013060124);
+ end;
+ end;
+ LOC_REGISTER,
+ LOC_REFERENCE:
+ begin
+ paraloc^.size:=int_cgsize(paralen);
+ if paraloc^.size<>OS_NO then
+ paraloc^.def:=cgsize_orddef(paraloc^.size)
+ else
+ paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
+ end;
+ else
+ internalerror(2006011101);
+ end;
+ if (side = callerside) then
+ paraloc^.reference.index:=NR_STACK_POINTER_REG
+ else
+ begin
+ 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
+ trv32procinfo(current_procinfo).needs_frame_pointer := true;
+ end;
+
+ paraloc^.reference.offset:=stack_offset;
+
+ inc(stack_offset,align(paralen,4));
+ while (paralen > 0) and
+ (nextintreg < RS_X18) do
+ begin
+ inc(nextintreg);
+ dec(paralen,sizeof(pint));
+ end;
+ paralen := 0;
+ end;
+ firstparaloc:=false;
+ end;
+ end;
+ curintreg:=nextintreg;
+ curfloatreg:=nextfloatreg;
+ curmmreg:=nextmmreg;
+ cur_stack_offset:=stack_offset;
+ result:=stack_offset;
+ end;
+
+
+ function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; 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,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset, false);
+ if (p.proccalloption in cstylearrayofconst) then
+ { just continue loading the parameters in the registers }
+ begin
+ result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,true);
+ end
+ else
+ begin
+ parasize:=cur_stack_offset;
+ for i:=0 to varargspara.count-1 do
+ begin
+ hp:=tparavarsym(varargspara[i]);
+ hp.paraloc[callerside].alignment:=4;
+ paraloc:=hp.paraloc[callerside].add_location;
+ paraloc^.loc:=LOC_REFERENCE;
+ paraloc^.size:=def_cgsize(hp.vardef);
+ paraloc^.def:=hp.vardef;
+ paraloc^.reference.index:=NR_STACK_POINTER_REG;
+ l:=push_size(hp.varspez,hp.vardef,p.proccalloption);
+ paraloc^.reference.offset:=parasize;
+ parasize:=parasize+l;
+ end;
+ result:=parasize;
+ end;
+ if curfloatreg<>firstfloatreg then
+ include(varargspara.varargsinfo,va_uses_float_reg);
+ end;
+
+begin
+ paramanager:=tcpuparamanager.create;
+end.
diff --git a/compiler/riscv32/cpupi.pas b/compiler/riscv32/cpupi.pas
new file mode 100644
index 0000000000..138d9ab915
--- /dev/null
+++ b/compiler/riscv32/cpupi.pas
@@ -0,0 +1,123 @@
+{
+ 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,globtype,
+ cgbase,aasmdata,
+ procinfo,cpuinfo,psub;
+
+ type
+ trv32procinfo = class(tcgprocinfo)
+ { for arm thumb, we need to know the stackframe size before
+ starting procedure compilation, so this contains the stack frame size, the compiler
+ should assume
+ if this size is too little the procedure must be compiled again with a larger value }
+ stackframesize,
+ floatregstart : aint;
+ stackpaddingreg: TSuperRegister;
+
+ needs_frame_pointer: boolean;
+ // procedure handle_body_start;override;
+ // procedure after_pass1;override;
+ constructor create(aparent: tprocinfo); override;
+ procedure set_first_temp_offset;override;
+ function calc_stackframe_size:longint;override;
+ end;
+
+
+ implementation
+
+ uses
+ globals,systems,
+ cpubase,
+ tgobj,
+ symconst,symtype,symsym,symcpu,paramgr,
+ cgutils,
+ cgobj,
+ defutil,
+ aasmcpu;
+
+
+ constructor trv32procinfo.create(aparent: tprocinfo);
+ begin
+ inherited create(aparent);
+ maxpushedparasize := 0;
+ end;
+
+
+ procedure trv32procinfo.set_first_temp_offset;
+ begin
+ if (po_nostackframe in procdef.procoptions) then
+ begin
+ { maxpushedparasize sghould be zero,
+ if not we will get an error later. }
+ tg.setfirsttemp(maxpushedparasize);
+ exit;
+ end;
+
+ if tg.direction = -1 then
+ tg.setfirsttemp(-(1+12)*4)
+ else
+ tg.setfirsttemp(maxpushedparasize);
+ end;
+
+
+ function trv32procinfo.calc_stackframe_size:longint;
+ var
+ firstfloatreg,lastfloatreg,
+ r : byte;
+ floatsavesize : aword;
+ regs: tcpuregisterset;
+ begin
+ maxpushedparasize:=align(maxpushedparasize,max(current_settings.alignment.localalignmin,4));
+ 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;
+ end;
+ floatsavesize:=align(floatsavesize,max(current_settings.alignment.localalignmin,4));
+ result:=Align(tg.direction*tg.lasttemp,max(current_settings.alignment.localalignmin,4))+maxpushedparasize+aint(floatsavesize);
+
+ if tg.direction=1 then
+ floatregstart:=result-aint(floatsavesize)
+ else
+ floatregstart:=-result+maxpushedparasize;
+ end;
+
+
+begin
+ cprocinfo:=trv32procinfo;
+end.
+
diff --git a/compiler/riscv32/cputarg.pas b/compiler/riscv32/cputarg.pas
new file mode 100644
index 0000000000..0643083eee
--- /dev/null
+++ b/compiler/riscv32/cputarg.pas
@@ -0,0 +1,84 @@
+{
+ Copyright (c) 2001-2002 by Peter Vreman
+
+ Includes the Risc-V32 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}
+ {$ifndef NOTARGETEMBEDDED}
+ ,t_embed
+ {$endif}
+
+{**************************************
+ Assemblers
+**************************************}
+
+ {$ifndef NOAGRVGAS}
+ ,agrvgas
+ {$endif}
+
+{**************************************
+ Assembler Readers
+**************************************}
+
+ {$ifndef NoRaRVGas}
+ ,rarv32gas
+ {$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.
diff --git a/compiler/riscv32/hlcgcpu.pas b/compiler/riscv32/hlcgcpu.pas
new file mode 100644
index 0000000000..e18851b3ae
--- /dev/null
+++ b/compiler/riscv32/hlcgcpu.pas
@@ -0,0 +1,61 @@
+{
+ Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+ Member of the Free Pascal development team
+
+ This unit contains high-level code generator support for Risc-V32
+
+ 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
+ aasmdata,
+ symtype,
+ cgbase,cgutils,hlcgobj,hlcgrv;
+
+ type
+ thlcgcpu = class(thlcgriscv)
+ end;
+
+ procedure create_hlcodegen;
+
+implementation
+
+ uses
+ verbose,
+ cpubase,aasmcpu,
+ defutil,
+ cgobj,cgcpu;
+
+
+
+ procedure create_hlcodegen;
+ begin
+ hlcg:=thlcgcpu.create;
+ create_codegen;
+ end;
+
+
+begin
+ chlcgobj:=thlcgcpu;
+end.
+
diff --git a/compiler/riscv32/itcpugas.pas b/compiler/riscv32/itcpugas.pas
new file mode 100644
index 0000000000..7ef91d58dc
--- /dev/null
+++ b/compiler/riscv32/itcpugas.pas
@@ -0,0 +1,141 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ This unit contains the Risc-V32 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[14] = ('<none>',
+ 'nop',
+ 'lui','auipc','jal','jalr',
+ 'b','lb','lh','lw','lbu','lhu',
+ 'sb','sh','sw',
+ 'addi','slti','sltiu',
+ 'xori','ori','andi',
+ 'slli','srli','srai',
+ 'add','sub','sll','slt','sltu',
+ 'xor','srl','sra','or','and',
+ 'fence','fence.i',
+ 'ecall','ebreak',
+ 'csrrw','csrrs','csrrc','csrrwi','csrrsi','csrrci',
+
+ { m-extension }
+ 'mul','mulh','mulhsu','mulhu',
+ 'div','divu','rem','remu',
+
+ { a-extension }
+ 'lr.w','sc.w','amoswap.w','amoadd.w','amoxor.w','amoand.w',
+ 'amoor.w','amomin.w','amomax.w','amominu.w','amomaxu.w',
+
+ { f-extension }
+ 'flw','fsw',
+ 'fmadd.s','fmsub.s','fnmsub.s','fnmadd.s',
+ 'fadd.s','fsub.s','fmul.s','fdiv.s',
+ 'fsqrt.s','fsgnj.s','fsgnjn.s','fsgnjx.s',
+ 'fmin.s','fmax.s',
+ 'fmv.x.s','feq.s','flt.s','fle.s','fclass.s',
+ 'fcvt.w.s','fcvt.wu.s','fcvt.s.w','fcvt.s.wu',
+ 'fmv.s.x',
+ 'frcsr','frrm','frflags','fscsr','fsrm',
+ 'fsflags','fsrmi','fsflagsi',
+
+ { d-extension }
+ 'fld','fsd',
+ 'fmadd.d','fmsub.d','fnmsub.d','fnmadd.d',
+ 'fadd.d','fsub.d','fmul.d','fdiv.d',
+ 'fsqrt.d','fsgnj.d','fsgnjn.d','fsgnjx.d',
+ 'fmin.d','fmax.d',
+ 'feq.d','flt.d','fle.d','fclass.d',
+ 'fcvt.d.s','fcvt.s.d',
+ 'fcvt.w.d','fcvt.wu.d','fcvt.d.w','fcvt.d.wu',
+
+ { Machine mode }
+ 'mret','hret','sret','uret',
+ 'wfi',
+
+ { Supervisor mode }
+ 'sfence.vm'
+ );
+
+ 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 rrv32std.inc}
+ );
+
+ gas_regname_index : array[tregisterindex] of tregisterindex = (
+ {$i rrv32sri.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;
+
+
+ function gas_regname(r:Tregister):string;
+ var
+ p : tregisterindex;
+ begin
+ p:=findreg_by_number(r);
+ if p<>0 then
+ result:=gas_regname_table[p]
+ else
+ result:=generic_regname(r);
+ end;
+
+end.
diff --git a/compiler/riscv32/nrv32add.pas b/compiler/riscv32/nrv32add.pas
new file mode 100644
index 0000000000..836663390d
--- /dev/null
+++ b/compiler/riscv32/nrv32add.pas
@@ -0,0 +1,56 @@
+{
+ Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe
+
+ Code generation for add nodes on the Risc-V32
+
+ 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 nrv32add;
+
+{$i fpcdefs.inc}
+
+ interface
+
+ uses
+ node, ncgadd, aasmbase, nrvadd, cpubase;
+
+ type
+ trv32addnode = class(trvaddnode)
+ protected
+ function use_generic_mul32to64: boolean; override;
+ end;
+
+ implementation
+
+ uses
+ systems,
+ cutils,verbose,
+ paramgr,procinfo,
+ aasmtai,aasmdata,aasmcpu,defutil,
+ cgbase,cgcpu,cgutils,nadd,
+ cpupara,
+ ncon,nset,
+ hlcgobj, ncgutil,cgobj;
+
+ function trv32addnode.use_generic_mul32to64: boolean;
+ begin
+ result:=true;
+ end;
+
+begin
+ caddnode:=trv32addnode;
+end.
diff --git a/compiler/riscv32/nrv32cal.pas b/compiler/riscv32/nrv32cal.pas
new file mode 100644
index 0000000000..a043a3b6c0
--- /dev/null
+++ b/compiler/riscv32/nrv32cal.pas
@@ -0,0 +1,51 @@
+{
+ Copyright (c) 2002 by Florian Klaempfl
+
+ Implements the Risc-V32 specific part of call 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 nrv32cal;
+
+{$i fpcdefs.inc}
+
+interface
+
+ uses
+ symdef,node,ncal,ncgcal;
+
+ type
+ trv32callnode = class(tcgcallnode)
+ end;
+
+
+implementation
+
+ uses
+ globtype,systems,
+ cutils,verbose,globals,
+ symconst,symbase,symsym,symcpu,symtable,defutil,paramgr,parabase,
+ cgbase,pass_2,
+ cpuinfo,cpubase,aasmbase,aasmtai,aasmdata,aasmcpu,
+ nmem,nld,ncnv,
+ ncgutil,cgutils,cgobj,tgobj,rgobj,rgcpu,
+ cg64f32,cgcpu,cpupi,procinfo;
+
+
+begin
+ ccallnode:=trv32callnode;
+end.
diff --git a/compiler/riscv32/nrv32cnv.pas b/compiler/riscv32/nrv32cnv.pas
new file mode 100644
index 0000000000..dd56a22d49
--- /dev/null
+++ b/compiler/riscv32/nrv32cnv.pas
@@ -0,0 +1,151 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Generate Risc-V32 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 nrv32cnv;
+
+{$i fpcdefs.inc}
+
+interface
+
+ uses
+ node,ncnv,ncgcnv,nrvcnv;
+
+ type
+ trv32typeconvnode = class(trvtypeconvnode)
+ 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_set_to_set;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,
+ ncgutil,procinfo,
+ cpubase,aasmcpu,
+ rgobj,tgobj,cgobj,hlcgobj;
+
+
+{*****************************************************************************
+ FirstTypeConv
+*****************************************************************************}
+
+ function trv32typeconvnode.first_int_to_real: tnode;
+ var
+ fname: string[19];
+ begin
+ if (cs_fp_emulation in current_settings.moduleswitches) then
+ result:=inherited first_int_to_real
+ { converting a 64bit integer to a float requires a helper }
+ else
+ begin
+ 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;
+ if is_signed(left.resultdef) then
+ fname := 'fpc_int64_to_double'
+ else
+ fname := 'fpc_qword_to_double';
+ result := ccallnode.createintern(fname,ccallparanode.create(
+ left,nil));
+ left:=nil;
+ firstpass(result);
+ exit;
+ end
+ else
+ { other integers are supposed to be 32 bit }
+ begin
+ if is_signed(left.resultdef) then
+ inserttypeconv(left,s32inttype)
+ else
+ inserttypeconv(left,u32inttype);
+ firstpass(left);
+ end;
+ result := nil;
+ expectloc:=LOC_FPUREGISTER;
+ end;
+ end;
+
+
+{*****************************************************************************
+ SecondTypeConv
+*****************************************************************************}
+
+ procedure trv32typeconvnode.second_int_to_real;
+ const
+ ops: array[boolean,s32real..s64real] of TAsmOp =
+ ((A_FCVT_S_WU,A_FCVT_D_WU),
+ (A_FCVT_S_W,A_FCVT_D_W));
+ var
+ restype: tfloattype;
+ begin
+ location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
+
+ restype:=tfloatdef(resultdef).floattype;
+
+ location.Register := cg.getfpuregister(current_asmdata.CurrAsmList, tfloat2tcgsize[restype]);
+ if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
+ begin
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(ops[is_signed(left.resultdef),restype], location.register, left.location.register));
+ end
+ else
+ begin
+ { Load memory in fpu register }
+ hlcg.location_force_mem(current_asmdata.CurrAsmList, left.location, left.resultdef);
+ cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList, OS_F32, OS_F32, left.location.reference, location.Register);
+ tg.ungetiftemp(current_asmdata.CurrAsmList, left.location.reference);
+
+ case restype of
+ s64real: cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList, OS_F32, OS_F64, location.register, location.Register);
+ end;
+ end;
+ end;
+
+begin
+ ctypeconvnode:=trv32typeconvnode;
+end.
+
diff --git a/compiler/riscv32/nrv32mat.pas b/compiler/riscv32/nrv32mat.pas
new file mode 100644
index 0000000000..ee25d85273
--- /dev/null
+++ b/compiler/riscv32/nrv32mat.pas
@@ -0,0 +1,135 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Generate Risc-V32 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 nrv32mat;
+
+{$i fpcdefs.inc}
+
+interface
+
+ uses
+ node,nmat, ncgmat,
+ cgbase;
+
+ type
+ trv32moddivnode = class(tcgmoddivnode)
+ procedure emit_div_reg_reg(signed: boolean; denum, num: tregister); override;
+ procedure emit_mod_reg_reg(signed: boolean; denum, num: tregister); override;
+ function first_moddivint: tnode; override;
+ end;
+
+ trv32shlshrnode = class(tcgshlshrnode)
+ end;
+
+ trv32unaryminusnode = class(tcgunaryminusnode)
+ end;
+
+ trv32notnode = class(tcgnotnode)
+ procedure second_boolean; override;
+ end;
+
+implementation
+
+ uses
+ globtype,systems,constexp,
+ cutils,verbose,globals,
+ symconst,symdef,
+ aasmbase,aasmcpu,aasmtai,aasmdata,
+ defutil,
+ cgutils,cgobj,hlcgobj,pass_2,
+ ncon,procinfo,
+ cpubase,
+ ncgutil,cgcpu;
+
+ procedure trv32notnode.second_boolean;
+ var
+ tlabel, flabel: tasmlabel;
+ begin
+ if not handle_locjump then
+ begin
+ secondpass(left);
+ case left.location.loc of
+ LOC_FLAGS :
+ begin
+ Internalerror(2016060601);
+ //location_copy(location,left.location);
+ //inverse_flags(location.resflags);
+ 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);
+
+ current_asmdata.getjumplabel(tlabel);
+ current_asmdata.getjumplabel(flabel);
+
+ location_reset_jump(location,tlabel,flabel);
+
+ hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,left.resultdef,OC_EQ,0,left.location.register,tlabel);
+ hlcg.a_jmp_always(current_asmdata.CurrAsmList,flabel);
+ end;
+ else
+ internalerror(2003042401);
+ end;
+ end;
+ end;
+
+ procedure trv32moddivnode.emit_div_reg_reg(signed: boolean; denum, num: tregister);
+ var
+ op: TAsmOp;
+ begin
+ if signed then
+ op:=A_DIV
+ else
+ op:=A_DIVU;
+
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,denum,num,denum));
+ end;
+
+ procedure trv32moddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
+ var
+ op: TAsmOp;
+ begin
+ if signed then
+ op:=A_REM
+ else
+ op:=A_REMU;
+
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,denum,num,denum));
+ end;
+
+
+ function trv32moddivnode.first_moddivint: tnode;
+ begin
+ if (not is_64bitint(resultdef)) then
+ Result:=nil
+ else
+ result:=inherited;
+ end;
+
+begin
+ cmoddivnode:=trv32moddivnode;
+ cshlshrnode:=trv32shlshrnode;
+ cunaryminusnode:=trv32unaryminusnode;
+ cnotnode:=trv32notnode;
+end.
diff --git a/compiler/riscv32/rarv32.pas b/compiler/riscv32/rarv32.pas
new file mode 100644
index 0000000000..8d7d3effad
--- /dev/null
+++ b/compiler/riscv32/rarv32.pas
@@ -0,0 +1,41 @@
+{
+ Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman
+
+ Handles the common Risc-V32 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 rarv32;
+
+{$i fpcdefs.inc}
+
+ interface
+
+ uses
+ aasmbase,aasmtai,aasmdata,aasmcpu,
+ cpubase,rautils,cclasses;
+
+ type
+ TRVOperand=class(TOperand)
+ end;
+
+ TRVInstruction=class(TInstruction)
+ end;
+
+ implementation
+
+end.
diff --git a/compiler/riscv32/rarv32gas.pas b/compiler/riscv32/rarv32gas.pas
new file mode 100644
index 0000000000..c93feb374b
--- /dev/null
+++ b/compiler/riscv32/rarv32gas.pas
@@ -0,0 +1,771 @@
+{
+ Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
+
+ Does the parsing for the Risc-V32 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 rarv32gas;
+
+{$i fpcdefs.inc}
+
+ Interface
+
+ uses
+ raatt,rarv32;
+
+ type
+ trv32attreader = class(tattreader)
+ function is_register(const s: string): boolean; override;
+ function is_asmopcode(const s: string):boolean;override;
+ procedure handleopcode;override;
+ procedure BuildReference(oper : trvoperand);
+ procedure BuildOperand(oper : trvoperand);
+ procedure BuildOpCode(instr : trvinstruction);
+ procedure ReadAt(oper : trvoperand);
+ procedure ReadSym(oper : trvoperand);
+ end;
+
+
+ Implementation
+
+ uses
+ { helpers }
+ cutils,
+ { global }
+ globtype,globals,verbose,
+ systems,
+ { aasm }
+ cpubase,aasmbase,aasmtai,aasmdata,aasmcpu,
+ { symtable }
+ symconst,symdef,symsym,
+ { parser }
+ procinfo,
+ rabase,rautils,
+ cgbase,cgobj,cgrv
+ ;
+
+ procedure trv32attreader.ReadSym(oper : trvoperand);
+ var
+ tempstr, mangledname : string;
+ l,k,typesize : tcgint;
+ begin
+ tempstr:=actasmpattern;
+ Consume(AS_ID);
+ { typecasting? }
+ if (actasmtoken=AS_LPAREN) and
+ SearchType(tempstr,typesize) then
+ begin
+ oper.hastype:=true;
+ Consume(AS_LPAREN);
+ BuildOperand(oper);
+ Consume(AS_RPAREN);
+ if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
+ oper.SetSize(typesize,true);
+ end
+ else
+ if not oper.SetupVar(tempstr,false) then
+ Message1(sym_e_unknown_id,tempstr);
+ { record.field ? }
+ if actasmtoken=AS_DOT then
+ begin
+ BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
+ if (mangledname<>'') then
+ Message(asmr_e_invalid_reference_syntax);
+ inc(oper.opr.ref.offset,l);
+ end;
+ end;
+
+
+ procedure trv32attreader.ReadAt(oper : trvoperand);
+ begin
+ { check for ...@ }
+ if actasmtoken=AS_AT then
+ begin
+ if (oper.opr.ref.symbol=nil) and
+ (oper.opr.ref.offset = 0) then
+ Message(asmr_e_invalid_reference_syntax);
+ Consume(AS_AT);
+ if actasmtoken=AS_ID then
+ begin
+ {if upper(actasmpattern)='L' then
+ oper.opr.ref.refaddr:=addr_low
+ else if upper(actasmpattern)='HI' then
+ oper.opr.ref.refaddr:=addr_high
+ else if upper(actasmpattern)='HA' then
+ oper.opr.ref.refaddr:=addr_higha
+ else}
+ Message(asmr_e_invalid_reference_syntax);
+ Consume(AS_ID);
+ end
+ else
+ Message(asmr_e_invalid_reference_syntax);
+ end;
+ end;
+
+
+ Procedure trv32attreader.BuildReference(oper : trvoperand);
+
+ procedure Consume_RParen;
+ begin
+ if actasmtoken <> AS_RPAREN then
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(true);
+ end
+ else
+ begin
+ Consume(AS_RPAREN);
+ if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(true);
+ end;
+ end;
+ end;
+
+ var
+ l : tcgint;
+ relsym: string;
+ asmsymtyp: tasmsymtype;
+ isflags: tindsymflags;
+
+ begin
+ Consume(AS_LPAREN);
+ Case actasmtoken of
+ AS_INTNUM,
+ AS_MINUS,
+ AS_PLUS:
+ Begin
+ { offset(offset) is invalid }
+ If oper.opr.Ref.Offset <> 0 Then
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(true);
+ End
+ Else
+ Begin
+ oper.opr.Ref.Offset:=BuildConstExpression(false,true);
+ Consume(AS_RPAREN);
+ if actasmtoken=AS_AT then
+ ReadAt(oper);
+ end;
+ exit;
+ End;
+ AS_REGISTER: { (reg ... }
+ Begin
+ if ((oper.opr.typ=OPR_REFERENCE) and (oper.opr.ref.base<>NR_NO)) or
+ ((oper.opr.typ=OPR_LOCAL) and (oper.opr.localsym.localloc.loc<>LOC_REGISTER)) then
+ message(asmr_e_cannot_index_relative_var);
+ oper.opr.ref.base:=actasmregister;
+ Consume(AS_REGISTER);
+ Consume_RParen;
+ end; {end case }
+ AS_ID:
+ Begin
+ ReadSym(oper);
+ case actasmtoken of
+ AS_PLUS:
+ begin
+ { add a constant expression? }
+ l:=BuildConstExpression(true,true);
+ case oper.opr.typ of
+ OPR_CONSTANT :
+ inc(oper.opr.val,l);
+ OPR_LOCAL :
+ inc(oper.opr.localsymofs,l);
+ OPR_REFERENCE :
+ inc(oper.opr.ref.offset,l);
+ else
+ internalerror(200309202);
+ end;
+ end;
+ AS_MINUS:
+ begin
+ Consume(AS_MINUS);
+ BuildConstSymbolExpression(false,true,false,l,relsym,asmsymtyp);
+ if (relsym<>'') then
+ begin
+ if (oper.opr.typ = OPR_REFERENCE) then
+ oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym,AT_DATA)
+ else
+ begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end
+ end
+ else
+ begin
+ case oper.opr.typ of
+ OPR_CONSTANT :
+ dec(oper.opr.val,l);
+ OPR_LOCAL :
+ dec(oper.opr.localsymofs,l);
+ OPR_REFERENCE :
+ dec(oper.opr.ref.offset,l);
+ else
+ internalerror(2007092601);
+ end;
+ end;
+ end;
+ end;
+ Consume(AS_RPAREN);
+ if actasmtoken=AS_AT then
+ ReadAt(oper);
+ End;
+ AS_COMMA: { (, ... can either be scaling, or index }
+ Begin
+ Consume(AS_COMMA);
+ { Index }
+ if (actasmtoken=AS_REGISTER) then
+ Begin
+ oper.opr.ref.index:=actasmregister;
+ Consume(AS_REGISTER);
+ { check for scaling ... }
+ Consume_RParen;
+ end
+ else
+ begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end;
+ end;
+ else
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end;
+ end;
+ end;
+
+
+ Procedure trv32attreader.BuildOperand(oper : trvoperand);
+ var
+ expr : string;
+ typesize,l : tcgint;
+
+
+ procedure AddLabelOperand(hl:tasmlabel);
+ begin
+ if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
+ is_calljmp(actopcode) then
+ begin
+ oper.opr.typ:=OPR_SYMBOL;
+ oper.opr.symbol:=hl;
+ end
+ else
+ begin
+ oper.InitRef;
+ oper.opr.ref.symbol:=hl;
+ end;
+ end;
+
+
+ procedure MaybeRecordOffset;
+ var
+ mangledname: string;
+ hasdot : boolean;
+ l,
+ toffset,
+ tsize : tcgint;
+ begin
+ if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
+ exit;
+ l:=0;
+ hasdot:=(actasmtoken=AS_DOT);
+ if hasdot then
+ begin
+ if expr<>'' then
+ begin
+ BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
+ if (oper.opr.typ<>OPR_CONSTANT) and
+ (mangledname<>'') then
+ Message(asmr_e_wrong_sym_type);
+ inc(l,toffset);
+ oper.SetSize(tsize,true);
+ end;
+ end;
+ if actasmtoken in [AS_PLUS,AS_MINUS] then
+ inc(l,BuildConstExpression(true,false));
+ case oper.opr.typ of
+ OPR_LOCAL :
+ begin
+ { don't allow direct access to fields of parameters, because that
+ will generate buggy code. Allow it only for explicit typecasting }
+ if hasdot and
+ (not oper.hastype) and
+ (tabstractvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
+ (current_procinfo.procdef.proccalloption<>pocall_register) then
+ Message(asmr_e_cannot_access_field_directly_for_parameters);
+ inc(oper.opr.localsymofs,l)
+ end;
+ OPR_CONSTANT :
+ if (mangledname<>'') then
+ begin
+ if (oper.opr.val<>0) then
+ Message(asmr_e_wrong_sym_type);
+ oper.opr.typ:=OPR_SYMBOL;
+ oper.opr.symbol:=current_asmdata.DefineAsmSymbol(mangledname,AB_EXTERNAL,AT_FUNCTION,voidcodepointertype);
+ end
+ else
+ inc(oper.opr.val,l);
+ OPR_REFERENCE :
+ inc(oper.opr.ref.offset,l);
+ OPR_SYMBOL:
+ Message(asmr_e_invalid_symbol_ref);
+ else
+ internalerror(200309221);
+ end;
+ end;
+
+
+ function MaybeBuildReference:boolean;
+ { Try to create a reference, if not a reference is found then false
+ is returned }
+ begin
+ MaybeBuildReference:=true;
+ case actasmtoken of
+ AS_INTNUM,
+ AS_MINUS,
+ AS_PLUS:
+ Begin
+ oper.opr.ref.offset:=BuildConstExpression(True,False);
+ if actasmtoken<>AS_LPAREN then
+ Message(asmr_e_invalid_reference_syntax)
+ else
+ BuildReference(oper);
+ end;
+ AS_LPAREN:
+ BuildReference(oper);
+ AS_ID: { only a variable is allowed ... }
+ Begin
+ ReadSym(oper);
+ case actasmtoken of
+ AS_END,
+ AS_SEPARATOR,
+ AS_COMMA: ;
+ AS_LPAREN:
+ BuildReference(oper);
+ else
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ Consume(actasmtoken);
+ end;
+ end; {end case }
+ end;
+ else
+ MaybeBuildReference:=false;
+ end; { end case }
+ end;
+
+
+ var
+ tempreg : tregister;
+ hl : tasmlabel;
+ ofs : aint;
+ refaddr: trefaddr;
+ Begin
+ expr:='';
+
+ refaddr:=addr_full;
+ if actasmtoken=AS_MOD then
+ begin
+ consume(AS_MOD);
+
+ if actasmtoken<>AS_ID then
+ begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end
+ else
+ begin
+ if lower(actasmpattern)='pcrel_hi' then
+ refaddr:=addr_pcrel_hi20
+ else if lower(actasmpattern)='pcrel_lo' then
+ refaddr:=addr_pcrel_lo12
+ else if lower(actasmpattern)='hi' then
+ refaddr:=addr_hi20
+ else if lower(actasmpattern)='lo' then
+ refaddr:=addr_lo12
+ else
+ begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end;
+
+ consume(AS_ID);
+ consume(AS_LPAREN);
+ end;
+ end;
+
+ case actasmtoken of
+ AS_LPAREN: { Memory reference or constant expression }
+ Begin
+ oper.InitRef;
+ BuildReference(oper);
+ end;
+
+ AS_INTNUM,
+ AS_MINUS,
+ AS_PLUS:
+ Begin
+ { Constant memory offset }
+ { This must absolutely be followed by ( }
+ oper.InitRef;
+ oper.opr.ref.offset:=BuildConstExpression(True,False);
+ if actasmtoken<>AS_LPAREN then
+ begin
+ ofs:=oper.opr.ref.offset;
+ BuildConstantOperand(oper);
+ inc(oper.opr.val,ofs);
+ end
+ else
+ BuildReference(oper);
+ end;
+
+ AS_ID: { A constant expression, or a Variable ref. }
+ Begin
+ { Local Label ? }
+ if is_locallabel(actasmpattern) then
+ begin
+ CreateLocalLabel(actasmpattern,hl,false);
+ Consume(AS_ID);
+ AddLabelOperand(hl);
+ end
+ else
+ { Check for label }
+ if SearchLabel(actasmpattern,hl,false) then
+ begin
+ Consume(AS_ID);
+ AddLabelOperand(hl);
+ end
+ else
+ { probably a variable or normal expression }
+ { or a procedure (such as in CALL ID) }
+ Begin
+ { is it a constant ? }
+ if SearchIConstant(actasmpattern,l) then
+ Begin
+ if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
+ Message(asmr_e_invalid_operand_type);
+ BuildConstantOperand(oper);
+ end
+ else
+ begin
+ expr:=actasmpattern;
+ Consume(AS_ID);
+ { typecasting? }
+ if (actasmtoken=AS_LPAREN) and
+ SearchType(expr,typesize) then
+ begin
+ oper.hastype:=true;
+ Consume(AS_LPAREN);
+ BuildOperand(oper);
+ Consume(AS_RPAREN);
+ if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
+ oper.SetSize(typesize,true);
+ end
+ else
+ begin
+ if oper.SetupVar(expr,false) then
+ ReadAt(oper)
+ else
+ Begin
+ { look for special symbols ... }
+ if expr= '__HIGH' then
+ begin
+ consume(AS_LPAREN);
+ if not oper.setupvar('high'+actasmpattern,false) then
+ Message1(sym_e_unknown_id,'high'+actasmpattern);
+ consume(AS_ID);
+ consume(AS_RPAREN);
+ end
+ else
+ if expr = '__RESULT' then
+ oper.SetUpResult
+ else
+ if expr = '__SELF' then
+ oper.SetupSelf
+ else
+ if expr = '__OLDEBP' then
+ oper.SetupOldEBP
+ else
+ Message1(sym_e_unknown_id,expr);
+ end;
+ end;
+ end;
+ if actasmtoken=AS_DOT then
+ MaybeRecordOffset;
+ { add a constant expression? }
+ if (actasmtoken=AS_PLUS) then
+ begin
+ l:=BuildConstExpression(true,false);
+ case oper.opr.typ of
+ OPR_CONSTANT :
+ inc(oper.opr.val,l);
+ OPR_LOCAL :
+ inc(oper.opr.localsymofs,l);
+ OPR_REFERENCE :
+ inc(oper.opr.ref.offset,l);
+ else
+ internalerror(200309202);
+ end;
+ end
+ end;
+ { Do we have a indexing reference, then parse it also }
+ if actasmtoken=AS_LPAREN then
+ BuildReference(oper);
+ end;
+
+ AS_REGISTER: { Register, a variable reference or a constant reference }
+ Begin
+ { save the type of register used. }
+ tempreg:=actasmregister;
+ Consume(AS_REGISTER);
+ if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
+ begin
+ if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
+ Message(asmr_e_invalid_operand_type);
+ oper.opr.typ:=OPR_REGISTER;
+ oper.opr.reg:=tempreg;
+ end
+ else
+ Message(asmr_e_syn_operand);
+ end;
+ AS_END,
+ AS_SEPARATOR,
+ AS_COMMA: ;
+ else
+ Begin
+ Message(asmr_e_syn_operand);
+ Consume(actasmtoken);
+ end;
+ end; { end case }
+
+ if refaddr<>addr_full then
+ begin
+ if oper.opr.typ<>OPR_REFERENCE then
+ oper.InitRef;
+
+ oper.opr.ref.refaddr:=refaddr;
+ Consume(AS_RPAREN);
+ end;
+ end;
+
+
+{*****************************************************************************
+ trv32attreader
+*****************************************************************************}
+
+ procedure trv32attreader.BuildOpCode(instr : trvinstruction);
+ 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 trvoperand);
+ end; { end case }
+ until false;
+ if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
+ dec(operandnum);
+ instr.Ops:=operandnum;
+ end;
+
+
+ function trv32attreader.is_register(const s: string): boolean;
+ type
+ treg2str = record
+ name : string[3];
+ reg : tregister;
+ end;
+
+ const
+ extraregs : array[0..31] of treg2str = (
+ (name: 'A0'; reg : NR_X10),
+ (name: 'A1'; reg : NR_X11),
+ (name: 'A2'; reg : NR_X12),
+ (name: 'A3'; reg : NR_X13),
+ (name: 'A5'; reg : NR_X14),
+ (name: 'A6'; reg : NR_X15),
+ (name: 'A7'; reg : NR_X16),
+ (name: 'A8'; reg : NR_X17),
+ (name: 'RA'; reg : NR_X1),
+ (name: 'SP'; reg : NR_X2),
+ (name: 'GP'; reg : NR_X3),
+ (name: 'TP'; reg : NR_X4),
+ (name: 'T0'; reg : NR_X5),
+ (name: 'T1'; reg : NR_X6),
+ (name: 'T2'; reg : NR_X7),
+ (name: 'S0'; reg : NR_X8),
+ (name: 'FP'; reg : NR_X8),
+ (name: 'S1'; reg : NR_X9),
+ (name: 'S2'; reg : NR_X18),
+ (name: 'S3'; reg : NR_X19),
+ (name: 'S4'; reg : NR_X20),
+ (name: 'S5'; reg : NR_X21),
+ (name: 'S6'; reg : NR_X22),
+ (name: 'S7'; reg : NR_X23),
+ (name: 'S8'; reg : NR_X24),
+ (name: 'S9'; reg : NR_X25),
+ (name: 'S10';reg : NR_X26),
+ (name: 'S11';reg : NR_X27),
+ (name: 'T3'; reg : NR_X28),
+ (name: 'T4'; reg : NR_X29),
+ (name: 'T5'; reg : NR_X30),
+ (name: 'T6'; reg : NR_X31)
+ );
+
+ var
+ i : longint;
+
+ begin
+ result:=inherited is_register(s);
+ { reg found?
+ possible aliases are always 2 char
+ }
+ if result or (not (length(s) in [2,3])) then
+ exit;
+ for i:=low(extraregs) to high(extraregs) do
+ begin
+ if s=extraregs[i].name then
+ begin
+ actasmregister:=extraregs[i].reg;
+ result:=true;
+ actasmtoken:=AS_REGISTER;
+ exit;
+ end;
+ end;
+ end;
+
+
+ function trv32attreader.is_asmopcode(const s: string):boolean;
+ var
+ cond : tasmcond;
+ hs : string;
+
+ 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;
+ { not found, check branch instructions }
+ if hs[1]='B' then
+ begin
+ { we can search here without an extra table which is sorted by string length
+ because we take the whole remaining string without the leading B }
+ actopcode := A_Bxx;
+ for cond:=low(TAsmCond) to high(TAsmCond) do
+ if copy(hs,2,length(s)-1)=uppercond2str[cond] then
+ begin
+ actcondition:=cond;
+ actasmtoken:=AS_OPCODE;
+ is_asmopcode:=true;
+ exit;
+ end;
+ end;
+ end;
+
+
+ procedure trv32attreader.handleopcode;
+ var
+ instr : trvinstruction;
+ begin
+ instr:=trvinstruction.Create(trvoperand);
+ BuildOpcode(instr);
+ instr.condition := actcondition;
+ {
+ instr.AddReferenceSizes;
+ instr.SetInstructionOpsize;
+ instr.CheckOperandSizes;
+ }
+ instr.ConcatInstruction(curlist);
+ instr.Free;
+ end;
+
+
+{*****************************************************************************
+ Initialize
+*****************************************************************************}
+
+const
+ asmmode_rv32_standard_info : tasmmodeinfo =
+ (
+ id : asmmode_standard;
+ idtxt : 'STANDARD';
+ casmreader : trv32attreader;
+ );
+
+initialization
+ RegisterAsmMode(asmmode_rv32_standard_info);
+end.
diff --git a/compiler/riscv32/rrv32con.inc b/compiler/riscv32/rrv32con.inc
new file mode 100644
index 0000000000..94c5f42533
--- /dev/null
+++ b/compiler/riscv32/rrv32con.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+NR_NO = tregister($00000000);
+NR_X0 = tregister($01000000);
+NR_X1 = tregister($01000001);
+NR_X2 = tregister($01000002);
+NR_X3 = tregister($01000003);
+NR_X4 = tregister($01000004);
+NR_X5 = tregister($01000005);
+NR_X6 = tregister($01000006);
+NR_X7 = tregister($01000007);
+NR_X8 = tregister($01000008);
+NR_X9 = tregister($01000009);
+NR_X10 = tregister($0100000a);
+NR_X11 = tregister($0100000b);
+NR_X12 = tregister($0100000c);
+NR_X13 = tregister($0100000d);
+NR_X14 = tregister($0100000e);
+NR_X15 = tregister($0100000f);
+NR_X16 = tregister($01000010);
+NR_X17 = tregister($01000011);
+NR_X18 = tregister($01000012);
+NR_X19 = tregister($01000013);
+NR_X20 = tregister($01000014);
+NR_X21 = tregister($01000015);
+NR_X22 = tregister($01000016);
+NR_X23 = tregister($01000017);
+NR_X24 = tregister($01000018);
+NR_X25 = tregister($01000019);
+NR_X26 = tregister($0100001a);
+NR_X27 = tregister($0100001b);
+NR_X28 = tregister($0100001c);
+NR_X29 = tregister($0100001d);
+NR_X30 = tregister($0100001e);
+NR_X31 = tregister($0100001f);
+NR_F0 = tregister($02000000);
+NR_F1 = tregister($02000001);
+NR_F2 = tregister($02000002);
+NR_F3 = tregister($02000003);
+NR_F4 = tregister($02000004);
+NR_F5 = tregister($02000005);
+NR_F6 = tregister($02000006);
+NR_F7 = tregister($02000007);
+NR_F8 = tregister($02000008);
+NR_F9 = tregister($02000009);
+NR_F10 = tregister($0200000a);
+NR_F11 = tregister($0200000b);
+NR_F12 = tregister($0200000c);
+NR_F13 = tregister($0200000d);
+NR_F14 = tregister($0200000e);
+NR_F15 = tregister($0200000f);
+NR_F16 = tregister($02000010);
+NR_F17 = tregister($02000011);
+NR_F18 = tregister($02000012);
+NR_F19 = tregister($02000013);
+NR_F20 = tregister($02000014);
+NR_F21 = tregister($02000015);
+NR_F22 = tregister($02000016);
+NR_F23 = tregister($02000017);
+NR_F24 = tregister($02000018);
+NR_F25 = tregister($02000019);
+NR_F26 = tregister($0200001a);
+NR_F27 = tregister($0200001b);
+NR_F28 = tregister($0200001c);
+NR_F29 = tregister($0200001d);
+NR_F30 = tregister($0200001e);
+NR_F31 = tregister($0200001f);
+NR_FCSR = tregister($05000001);
diff --git a/compiler/riscv32/rrv32dwa.inc b/compiler/riscv32/rrv32dwa.inc
new file mode 100644
index 0000000000..6755ebb4c5
--- /dev/null
+++ b/compiler/riscv32/rrv32dwa.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+-1,
+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,
+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,
+0
diff --git a/compiler/riscv32/rrv32nor.inc b/compiler/riscv32/rrv32nor.inc
new file mode 100644
index 0000000000..a3c3b517a4
--- /dev/null
+++ b/compiler/riscv32/rrv32nor.inc
@@ -0,0 +1,2 @@
+{ don't edit, this file is generated from rv32reg.dat }
+66
diff --git a/compiler/riscv32/rrv32num.inc b/compiler/riscv32/rrv32num.inc
new file mode 100644
index 0000000000..f9553bf4fb
--- /dev/null
+++ b/compiler/riscv32/rrv32num.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+tregister($00000000),
+tregister($01000000),
+tregister($01000001),
+tregister($01000002),
+tregister($01000003),
+tregister($01000004),
+tregister($01000005),
+tregister($01000006),
+tregister($01000007),
+tregister($01000008),
+tregister($01000009),
+tregister($0100000a),
+tregister($0100000b),
+tregister($0100000c),
+tregister($0100000d),
+tregister($0100000e),
+tregister($0100000f),
+tregister($01000010),
+tregister($01000011),
+tregister($01000012),
+tregister($01000013),
+tregister($01000014),
+tregister($01000015),
+tregister($01000016),
+tregister($01000017),
+tregister($01000018),
+tregister($01000019),
+tregister($0100001a),
+tregister($0100001b),
+tregister($0100001c),
+tregister($0100001d),
+tregister($0100001e),
+tregister($0100001f),
+tregister($02000000),
+tregister($02000001),
+tregister($02000002),
+tregister($02000003),
+tregister($02000004),
+tregister($02000005),
+tregister($02000006),
+tregister($02000007),
+tregister($02000008),
+tregister($02000009),
+tregister($0200000a),
+tregister($0200000b),
+tregister($0200000c),
+tregister($0200000d),
+tregister($0200000e),
+tregister($0200000f),
+tregister($02000010),
+tregister($02000011),
+tregister($02000012),
+tregister($02000013),
+tregister($02000014),
+tregister($02000015),
+tregister($02000016),
+tregister($02000017),
+tregister($02000018),
+tregister($02000019),
+tregister($0200001a),
+tregister($0200001b),
+tregister($0200001c),
+tregister($0200001d),
+tregister($0200001e),
+tregister($0200001f),
+tregister($05000001)
diff --git a/compiler/riscv32/rrv32rni.inc b/compiler/riscv32/rrv32rni.inc
new file mode 100644
index 0000000000..de9f6b796b
--- /dev/null
+++ b/compiler/riscv32/rrv32rni.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.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
diff --git a/compiler/riscv32/rrv32sri.inc b/compiler/riscv32/rrv32sri.inc
new file mode 100644
index 0000000000..a39dc1faa3
--- /dev/null
+++ b/compiler/riscv32/rrv32sri.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+0,
+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,
+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
diff --git a/compiler/riscv32/rrv32sta.inc b/compiler/riscv32/rrv32sta.inc
new file mode 100644
index 0000000000..6755ebb4c5
--- /dev/null
+++ b/compiler/riscv32/rrv32sta.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+-1,
+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,
+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,
+0
diff --git a/compiler/riscv32/rrv32std.inc b/compiler/riscv32/rrv32std.inc
new file mode 100644
index 0000000000..468a711616
--- /dev/null
+++ b/compiler/riscv32/rrv32std.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+'INVALID',
+'x0',
+'x1',
+'x2',
+'x3',
+'x4',
+'x5',
+'x6',
+'x7',
+'x8',
+'x9',
+'x10',
+'x11',
+'x12',
+'x13',
+'x14',
+'x15',
+'x16',
+'x17',
+'x18',
+'x19',
+'x20',
+'x21',
+'x22',
+'x23',
+'x24',
+'x25',
+'x26',
+'x27',
+'x28',
+'x29',
+'x30',
+'x31',
+'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',
+'fcsr'
diff --git a/compiler/riscv32/rrv32sup.inc b/compiler/riscv32/rrv32sup.inc
new file mode 100644
index 0000000000..cb12862e9d
--- /dev/null
+++ b/compiler/riscv32/rrv32sup.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+RS_NO = $00;
+RS_X0 = $00;
+RS_X1 = $01;
+RS_X2 = $02;
+RS_X3 = $03;
+RS_X4 = $04;
+RS_X5 = $05;
+RS_X6 = $06;
+RS_X7 = $07;
+RS_X8 = $08;
+RS_X9 = $09;
+RS_X10 = $0a;
+RS_X11 = $0b;
+RS_X12 = $0c;
+RS_X13 = $0d;
+RS_X14 = $0e;
+RS_X15 = $0f;
+RS_X16 = $10;
+RS_X17 = $11;
+RS_X18 = $12;
+RS_X19 = $13;
+RS_X20 = $14;
+RS_X21 = $15;
+RS_X22 = $16;
+RS_X23 = $17;
+RS_X24 = $18;
+RS_X25 = $19;
+RS_X26 = $1a;
+RS_X27 = $1b;
+RS_X28 = $1c;
+RS_X29 = $1d;
+RS_X30 = $1e;
+RS_X31 = $1f;
+RS_F0 = $00;
+RS_F1 = $01;
+RS_F2 = $02;
+RS_F3 = $03;
+RS_F4 = $04;
+RS_F5 = $05;
+RS_F6 = $06;
+RS_F7 = $07;
+RS_F8 = $08;
+RS_F9 = $09;
+RS_F10 = $0a;
+RS_F11 = $0b;
+RS_F12 = $0c;
+RS_F13 = $0d;
+RS_F14 = $0e;
+RS_F15 = $0f;
+RS_F16 = $10;
+RS_F17 = $11;
+RS_F18 = $12;
+RS_F19 = $13;
+RS_F20 = $14;
+RS_F21 = $15;
+RS_F22 = $16;
+RS_F23 = $17;
+RS_F24 = $18;
+RS_F25 = $19;
+RS_F26 = $1a;
+RS_F27 = $1b;
+RS_F28 = $1c;
+RS_F29 = $1d;
+RS_F30 = $1e;
+RS_F31 = $1f;
+RS_FCSR = $01;
diff --git a/compiler/riscv32/rv32reg.dat b/compiler/riscv32/rv32reg.dat
new file mode 100644
index 0000000000..0be9f17f99
--- /dev/null
+++ b/compiler/riscv32/rv32reg.dat
@@ -0,0 +1,77 @@
+;
+; RiscV registers
+;
+; layout
+; <name>,<type>,<subtype>,<value>,<stdname>,<stab idx>,<dwarf idx>
+;
+NO,$00,$00,$00,INVALID,-1,-1
+; Integer registers
+X0,$01,$00,$00,x0,0,0
+X1,$01,$00,$01,x1,1,1
+X2,$01,$00,$02,x2,2,2
+X3,$01,$00,$03,x3,3,3
+X4,$01,$00,$04,x4,4,4
+X5,$01,$00,$05,x5,5,5
+X6,$01,$00,$06,x6,6,6
+X7,$01,$00,$07,x7,7,7
+X8,$01,$00,$08,x8,8,8
+X9,$01,$00,$09,x9,9,9
+X10,$01,$00,$0a,x10,10,10
+X11,$01,$00,$0b,x11,11,11
+X12,$01,$00,$0c,x12,12,12
+X13,$01,$00,$0d,x13,13,13
+X14,$01,$00,$0e,x14,14,14
+X15,$01,$00,$0f,x15,15,15
+X16,$01,$00,$10,x16,16,16
+X17,$01,$00,$11,x17,17,17
+X18,$01,$00,$12,x18,18,18
+X19,$01,$00,$13,x19,19,19
+X20,$01,$00,$14,x20,20,20
+X21,$01,$00,$15,x21,21,21
+X22,$01,$00,$16,x22,22,22
+X23,$01,$00,$17,x23,23,23
+X24,$01,$00,$18,x24,24,24
+X25,$01,$00,$19,x25,25,25
+X26,$01,$00,$1a,x26,26,26
+X27,$01,$00,$1b,x27,27,27
+X28,$01,$00,$1c,x28,28,28
+X29,$01,$00,$1d,x29,29,29
+X30,$01,$00,$1e,x30,30,30
+X31,$01,$00,$1f,x31,31,31
+
+; Float registers
+F0,$02,$00,$00,f0,0,0
+F1,$02,$00,$01,f1,1,1
+F2,$02,$00,$02,f2,2,2
+F3,$02,$00,$03,f3,3,3
+F4,$02,$00,$04,f4,4,4
+F5,$02,$00,$05,f5,5,5
+F6,$02,$00,$06,f6,6,6
+F7,$02,$00,$07,f7,7,7
+F8,$02,$00,$08,f8,8,8
+F9,$02,$00,$09,f9,9,9
+F10,$02,$00,$0a,f10,10,10
+F11,$02,$00,$0b,f11,11,11
+F12,$02,$00,$0c,f12,12,12
+F13,$02,$00,$0d,f13,13,13
+F14,$02,$00,$0e,f14,14,14
+F15,$02,$00,$0f,f15,15,15
+F16,$02,$00,$10,f16,16,16
+F17,$02,$00,$11,f17,17,17
+F18,$02,$00,$12,f18,18,18
+F19,$02,$00,$13,f19,19,19
+F20,$02,$00,$14,f20,20,20
+F21,$02,$00,$15,f21,21,21
+F22,$02,$00,$16,f22,22,22
+F23,$02,$00,$17,f23,23,23
+F24,$02,$00,$18,f24,24,24
+F25,$02,$00,$19,f25,25,25
+F26,$02,$00,$1a,f26,26,26
+F27,$02,$00,$1b,f27,27,27
+F28,$02,$00,$1c,f28,28,28
+F29,$02,$00,$1d,f29,29,29
+F30,$02,$00,$1e,f30,30,30
+F31,$02,$00,$1f,f31,31,31
+
+; Special registers
+FCSR,$05,$00,$01,fcsr,0,0
diff --git a/compiler/riscv32/symcpu.pas b/compiler/riscv32/symcpu.pas
new file mode 100644
index 0000000000..43005180e9
--- /dev/null
+++ b/compiler/riscv32/symcpu.pas
@@ -0,0 +1,216 @@
+{
+ Copyright (c) 2014 by Florian Klaempfl
+
+ Symbol table overrides for Risc-V32
+
+ 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
+ symconst,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
+
+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.
+
diff --git a/compiler/riscv64/aoptcpu.pas b/compiler/riscv64/aoptcpu.pas
new file mode 100644
index 0000000000..7e2ed6cf1a
--- /dev/null
+++ b/compiler/riscv64/aoptcpu.pas
@@ -0,0 +1,387 @@
+{
+ Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+ Development Team
+
+ This unit implements the RiscV64 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,
+ aoptobj, aoptcpub, aopt,
+ aasmtai, aasmcpu;
+
+type
+
+ TCpuAsmOptimizer = class(TAsmOptimizer)
+ function InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean; override;
+ function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean; override;
+ Function GetNextInstructionUsingReg(Current: tai; Out Next: tai; reg: TRegister): Boolean;
+ { outputs a debug message into the assembler file }
+ procedure DebugMsg(const s: string; p: tai);
+
+ function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
+ end;
+
+implementation
+
+ uses
+ cutils;
+
+ function MatchInstruction(const instr: tai; const op: TAsmOps; const AConditions: TAsmConds = []): boolean;
+ begin
+ result :=
+ (instr.typ = ait_instruction) and
+ (taicpu(instr).opcode in op) and
+ ((AConditions=[]) or (taicpu(instr).condition in AConditions));
+ 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;
+
+
+{$ifdef DEBUG_AOPTCPU}
+ procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
+ begin
+ asml.insertbefore(tai_comment.Create(strpnew(s)), p);
+ end;
+{$else DEBUG_AOPTCPU}
+ procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
+ begin
+ end;
+{$endif DEBUG_AOPTCPU}
+
+
+ function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
+ var
+ p: taicpu;
+ i: longint;
+ begin
+ result:=false;
+ if not (assigned(hp) and (hp.typ=ait_instruction)) then
+ exit;
+ p:=taicpu(hp);
+
+ i:=0;
+ while(i<p.ops) do
+ begin
+ case p.oper[I]^.typ of
+ top_reg:
+ result:=(p.oper[I]^.reg=reg) and (p.spilling_get_operation_type(i)<>operand_write);
+ top_ref:
+ result:=
+ (p.oper[I]^.ref^.base=reg);
+ end;
+ if result then exit; {Bailout if we found something}
+ Inc(I);
+ end;
+ end;
+
+
+ function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
+ begin
+ result:=
+ (hp.typ=ait_instruction) and
+ (taicpu(hp).ops>1) and
+ (taicpu(hp).oper[0]^.typ=top_reg) and
+ (taicpu(hp).oper[0]^.reg=reg) and
+ (taicpu(hp).spilling_get_operation_type(0)<>operand_read);
+ 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 TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
+
+ procedure RemoveInstr(var orig: tai; moveback: boolean = true);
+ var
+ n: tai;
+ begin
+ if moveback and (not GetLastInstruction(orig,n)) then
+ GetNextInstruction(orig,n);
+
+ AsmL.Remove(orig);
+ orig.Free;
+
+ orig:=n;
+ end;
+
+ var
+ hp1: tai;
+ begin
+ result:=false;
+ case p.typ of
+ ait_instruction:
+ begin
+ case taicpu(p).opcode of
+ A_ADDI:
+ begin
+ {
+ Changes
+ addi x, y, #
+ addi/addiw z, x, #
+ dealloc x
+ To
+ addi z, y, #+#
+ }
+ if (taicpu(p).ops=3) and
+ (taicpu(p).oper[2]^.typ=top_const) and
+ GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+ MatchInstruction(hp1,[A_ADDI,A_ADDIW]) and
+ (taicpu(hp1).ops=3) and
+ MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^) and
+ (taicpu(p).oper[2]^.typ=top_const) and
+ is_imm12(taicpu(p).oper[2]^.val+taicpu(hp1).oper[2]^.val) and
+ (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+ RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+ begin
+ taicpu(hp1).loadreg(1,taicpu(p).oper[1]^.reg);
+ taicpu(hp1).loadconst(2, taicpu(p).oper[2]^.val+taicpu(hp1).oper[2]^.val);
+
+ DebugMsg('Peephole AddiAddi2Addi performed', hp1);
+
+ RemoveInstr(p);
+
+ result:=true;
+ end
+ {
+ Changes
+ addi x, x, (ref)
+ ld/sd y, 0(x)
+ dealloc x
+ To
+ ld/sd y, 0(ref)(x)
+ }
+ else if (taicpu(p).ops=3) and
+ (taicpu(p).oper[2]^.typ=top_ref) and
+ MatchOperand(taicpu(p).oper[0]^,taicpu(p).oper[1]^) and
+ GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+ MatchInstruction(hp1, [A_LB,A_LBU,A_LH,A_LHU,A_LW,A_LWU,A_LD,
+ A_SB,A_SH,A_SW,A_SD]) and
+ (taicpu(hp1).ops=2) and
+ (taicpu(hp1).oper[1]^.typ=top_ref) and
+ (taicpu(hp1).oper[1]^.ref^.base=taicpu(p).oper[0]^.reg) and
+ (taicpu(hp1).oper[1]^.ref^.offset=0) and
+ (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+ RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+ begin
+ taicpu(hp1).loadref(1,taicpu(p).oper[2]^.ref^);
+ taicpu(hp1).oper[1]^.ref^.base:=taicpu(p).oper[1]^.reg;
+
+ DebugMsg('Peephole AddiMem2Mem performed', hp1);
+
+ RemoveInstr(p);
+
+ result:=true;
+ end;
+ end;
+ A_SUB:
+ begin
+ {
+ Turn
+ sub x,y,z
+ bgeu X0,x,...
+ dealloc x
+ Into
+ bne y,x,...
+ }
+ if (taicpu(p).ops=3) and
+ GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+ MatchInstruction(hp1,A_Bxx,[C_GEU,C_EQ]) and
+ (taicpu(hp1).ops=3) and
+ MatchOperand(taicpu(hp1).oper[0]^,NR_X0) and
+ MatchOperand(taicpu(hp1).oper[1]^,taicpu(p).oper[0]^) and
+ (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+ (not RegModifiedBetween(taicpu(p).oper[2]^.reg, p,hp1)) and
+ RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+ begin
+ taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
+ taicpu(hp1).loadreg(1,taicpu(p).oper[2]^.reg);
+ taicpu(hp1).condition:=C_EQ;
+
+ DebugMsg('Peephole SubBxx2Beq performed', hp1);
+
+ RemoveInstr(p);
+
+ result:=true;
+ end;
+ end;
+ A_SLTU:
+ begin
+ {
+ Turn
+ sltu x,X0,y
+ beq/bne x, X0, ...
+ dealloc x
+ Into
+ bltu/geu X0, y, ...
+ }
+ if (taicpu(p).ops=3) and
+ MatchOperand(taicpu(p).oper[1]^,NR_X0) and
+ GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+ MatchInstruction(hp1,A_Bxx,[C_NE,C_EQ]) and
+ (taicpu(hp1).ops=3) and
+ MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^) and
+ MatchOperand(taicpu(hp1).oper[1]^,NR_X0) and
+ (not RegModifiedBetween(taicpu(p).oper[2]^.reg, p,hp1)) and
+ RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+ begin
+ taicpu(hp1).loadreg(0,NR_X0);
+ taicpu(hp1).loadreg(1,taicpu(p).oper[2]^.reg);
+
+ if taicpu(hp1).condition=C_NE then
+ taicpu(hp1).condition:=C_LTU
+ else
+ taicpu(hp1).condition:=C_GEU;
+
+ DebugMsg('Peephole SltuB2B performed', hp1);
+
+ RemoveInstr(p);
+
+ result:=true;
+ end;
+ end;
+ A_SLTIU:
+ begin
+ {
+ Turn
+ sltiu x,y,1
+ beq/ne x,x0,...
+ dealloc x
+ Into
+ bne y,x0,...
+ }
+ if (taicpu(p).ops=3) and
+ (taicpu(p).oper[2]^.typ=top_const) and
+ (taicpu(p).oper[2]^.val=1) and
+ GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+ MatchInstruction(hp1,A_Bxx,[C_NE,C_EQ]) and
+ (taicpu(hp1).ops=3) and
+ MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^) and
+ MatchOperand(taicpu(hp1).oper[1]^,NR_X0) and
+ (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+ RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+ begin
+ taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
+ taicpu(hp1).condition:=inverse_cond(taicpu(hp1).condition);
+
+ DebugMsg('Peephole Sltiu0B2B performed', hp1);
+
+ RemoveInstr(p);
+
+ result:=true;
+ end;
+ end;
+ A_SLTI:
+ begin
+ {
+ Turn
+ slti x,y,0
+ beq/ne x,x0,...
+ dealloc x
+ Into
+ bge/lt y,x0,...
+ }
+ if (taicpu(p).ops=3) and
+ (taicpu(p).oper[2]^.typ=top_const) and
+ (taicpu(p).oper[2]^.val=0) and
+ GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+ (hp1.typ=ait_instruction) and
+ (taicpu(hp1).opcode=A_Bxx) and
+ (taicpu(hp1).ops=3) and
+ (taicpu(hp1).oper[0]^.typ=top_reg) and
+ (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
+ (taicpu(hp1).oper[1]^.typ=top_reg) and
+ (taicpu(hp1).oper[1]^.reg=NR_X0) and
+ (taicpu(hp1).condition in [C_NE,C_EQ]) and
+ (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+ RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+ begin
+ taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
+ taicpu(hp1).loadreg(1,NR_X0);
+
+ if taicpu(hp1).condition=C_NE then
+ taicpu(hp1).condition:=C_LT
+ else
+ taicpu(hp1).condition:=C_GE;
+
+ DebugMsg('Peephole Slti0B2B performed', hp1);
+
+ RemoveInstr(p);
+
+ result:=true;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+
+begin
+ casmoptimizer := TCpuAsmOptimizer;
+end.
diff --git a/compiler/riscv64/aoptcpub.pas b/compiler/riscv64/aoptcpub.pas
new file mode 100644
index 0000000000..da6587c061
--- /dev/null
+++ b/compiler/riscv64/aoptcpub.pas
@@ -0,0 +1,116 @@
+{
+ 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 RiscV64 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}
+
+{ enable the following define if memory references can have a scaled index }
+{ define RefsHaveScale}
+
+{ enable the following define if memory references can have a segment }
+{ override }
+{ define RefsHaveSegment}
+
+interface
+
+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;
+
+ { the maximum number of operands an instruction has }
+
+ MaxOps = 5;
+
+ {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_JAL;
+ aopt_condjmp = A_Bxx;
+
+implementation
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+
+constructor TCondRegs.init;
+begin
+end;
+
+destructor TCondRegs.Done;
+{$IFDEF inl}inline;
+{$ENDIF inl}
+begin
+end;
+
+end.
+
diff --git a/compiler/riscv64/aoptcpuc.pas b/compiler/riscv64/aoptcpuc.pas
new file mode 100644
index 0000000000..e002fedb21
--- /dev/null
+++ b/compiler/riscv64/aoptcpuc.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 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.
+
diff --git a/compiler/riscv64/aoptcpud.pas b/compiler/riscv64/aoptcpud.pas
new file mode 100644
index 0000000000..5e6e7fc308
--- /dev/null
+++ b/compiler/riscv64/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.
+
diff --git a/compiler/riscv64/cgcpu.pas b/compiler/riscv64/cgcpu.pas
new file mode 100644
index 0000000000..554107ab91
--- /dev/null
+++ b/compiler/riscv64/cgcpu.pas
@@ -0,0 +1,642 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ This unit implements the code generator for the RiscV64
+
+ 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,cgrv,
+ aasmbase, aasmcpu, aasmtai,aasmdata,
+ cpubase, cpuinfo, cgutils, rgcpu,
+ parabase;
+
+ type
+ tcgrv64 = class(tcgrv)
+ procedure init_register_allocators; override;
+ procedure done_register_allocators; override;
+
+ { move instructions }
+ procedure a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
+ procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister); 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;
+
+ procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
+
+ procedure g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean); override;
+ procedure g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean); override;
+
+ procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
+ procedure g_concatcopy(list: TAsmList; const source, dest: treference; len: aint); override;
+ end;
+
+ procedure create_codegen;
+
+implementation
+
+ uses
+ sysutils, cclasses,
+ globals, verbose, systems, cutils,
+ symconst, fmodule, symtable,
+ rgobj, tgobj, cpupi, procinfo, paramgr, cpupara;
+
+
+ procedure tcgrv64.init_register_allocators;
+ begin
+ inherited init_register_allocators;
+ rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
+ [RS_X10,RS_X11,RS_X12,RS_X13,RS_X14,RS_X15,RS_X16,RS_X17,
+ RS_X31,RS_X30,RS_X29,RS_X28,
+ RS_X5,RS_X6,RS_X7,
+ RS_X9,RS_X27,RS_X26,RS_X25,RS_X24,RS_X23,RS_X22,
+ RS_X21,RS_X20,RS_X19,RS_X18],first_int_imreg,[]);
+ rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
+ [RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,RS_F16,RS_F17,
+ RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
+ RS_F28,RS_F29,RS_F30,RS_F31,
+ RS_F8,RS_F9,
+ RS_F27,
+ RS_F26,RS_F25,RS_F24,RS_F23,RS_F22,RS_F21,RS_F20,RS_F19,RS_F18],first_fpu_imreg,[]);
+ end;
+
+
+ procedure tcgrv64.done_register_allocators;
+ begin
+ rg[R_INTREGISTER].free;
+ rg[R_FPUREGISTER].free;
+ inherited done_register_allocators;
+ end;
+
+
+ procedure tcgrv64.a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
+ var
+ ai: taicpu;
+ begin
+ list.concat(tai_comment.Create(strpnew('Move '+tcgsize2str(fromsize)+'->'+tcgsize2str(tosize))));
+
+ if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_S32) then
+ list.Concat(taicpu.op_reg_reg_const(A_ADDIW,reg2,reg1,0))
+ else if (tosize=OS_S32) and (tcgsize2unsigned[fromsize]=OS_64) then
+ list.Concat(taicpu.op_reg_reg_const(A_ADDIW,reg2,reg1,0))
+ else if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_8) then
+ list.Concat(taicpu.op_reg_reg_const(A_ANDI,reg2,reg1,$FF))
+ else if (tcgsize2size[fromsize] > tcgsize2size[tosize]) or
+ ((tcgsize2size[fromsize] = tcgsize2size[tosize]) and (fromsize <> tosize)) or
+ { do we need to mask out the sign when loading from smaller signed to larger unsigned type? }
+ ((tcgsize2unsigned[fromsize]<>fromsize) and ((tcgsize2unsigned[tosize]=tosize)) and
+ (tcgsize2size[fromsize] < tcgsize2size[tosize]) and (tcgsize2size[tosize] <> sizeof(pint)) ) then
+ begin
+ if tcgsize2size[fromsize]<tcgsize2size[tosize] then
+ begin
+ list.Concat(taicpu.op_reg_reg_const(A_SLLI,reg2,reg1,8*(8-tcgsize2size[fromsize])));
+
+ if tcgsize2unsigned[fromsize]<>fromsize then
+ list.Concat(taicpu.op_reg_reg_const(A_SRAI,reg2,reg2,8*(tcgsize2size[tosize]-tcgsize2size[fromsize])))
+ else
+ list.Concat(taicpu.op_reg_reg_const(A_SRLI,reg2,reg2,8*(tcgsize2size[tosize]-tcgsize2size[fromsize])));
+ end
+ else if tcgsize2unsigned[tosize]<>OS_64 then
+ list.Concat(taicpu.op_reg_reg_const(A_SLLI,reg2,reg1,8*(8-tcgsize2size[tosize])))
+ else
+ a_load_reg_reg(list,tosize,tosize,reg1,reg2);
+
+ if tcgsize2unsigned[tosize]=tosize then
+ list.Concat(taicpu.op_reg_reg_const(A_SRLI,reg2,reg2,8*(8-tcgsize2size[tosize])))
+ else
+ list.Concat(taicpu.op_reg_reg_const(A_SRAI,reg2,reg2,8*(8-tcgsize2size[tosize])));
+ end
+ else
+ begin
+ ai:=taicpu.op_reg_reg_const(A_ADDI,reg2,reg1,0);
+ list.concat(ai);
+ rg[R_INTREGISTER].add_move_instruction(ai);
+ end;
+ end;
+
+ procedure tcgrv64.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister);
+ var
+ l: TAsmLabel;
+ hr: treference;
+ begin
+ if a=0 then
+ a_load_reg_reg(list,size,size,NR_X0,register)
+ else
+ begin
+ if is_imm12(a) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,register,NR_X0,a))
+ else if is_lui_imm(a) then
+ list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF))
+ else if (int64(longint(a))=a) then
+ begin
+ if (a and $800)<>0 then
+ list.concat(taicpu.op_reg_const(A_LUI,register,((a shr 12)+1) and $FFFFF))
+ else
+ list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF));
+
+ list.concat(taicpu.op_reg_reg_const(A_ADDIW,register,register,SarSmallint(a shl 4,4)));
+ end
+ else
+ begin
+ reference_reset(hr,8,[]);
+
+ current_asmdata.getjumplabel(l);
+ current_procinfo.aktlocaldata.Concat(cai_align.Create(8));
+ cg.a_label(current_procinfo.aktlocaldata,l);
+ hr.symboldata:=current_procinfo.aktlocaldata.last;
+ current_procinfo.aktlocaldata.concat(tai_const.Create_64bit(a));
+
+ hr.symbol:=l;
+ hr.refaddr:=addr_pcrel_hi20;
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ list.concat(taicpu.op_reg_ref(A_AUIPC,register,hr));
+
+ reference_reset_symbol(hr,l,0,0,[]);
+ hr.refaddr:=addr_pcrel_lo12;
+ hr.base:=register;
+ list.concat(taicpu.op_reg_ref(A_LD,register,hr));
+ end;
+ end;
+ end;
+
+
+ procedure tcgrv64.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;
+ begin
+ if setflags 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
+ a_op_const_reg_reg(list,op,size,a,src,dst);
+ end;
+
+
+ procedure tcgrv64.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;
+ tmpreg, tmpreg0: tregister;
+ ai: taicpu;
+ begin
+ signed:=tcgsize2unsigned[size]<>size;
+
+ if setflags then
+ case op of
+ OP_ADD:
+ begin
+ current_asmdata.getjumplabel(l);
+
+ list.Concat(taicpu.op_reg_reg_reg(A_ADD,dst,src2,src1));
+
+ if signed then
+ begin
+ {
+ t0=src1<0
+ t1=result<src2
+ overflow if t0<>t1
+ }
+ tmpreg0:=getintregister(list,OS_INT);
+ tmpreg:=getintregister(list,OS_INT);
+ list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,src1,NR_X0));
+ list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg,dst,src2));
+
+ ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,tmpreg0,l,0);
+ ai.condition:=C_EQ;
+ list.concat(ai);
+ end
+ else
+ begin
+ {
+ jump if sum>=x
+ }
+ if size in [OS_S32,OS_32] then
+ begin
+ tmpreg:=getintregister(list,OS_INT);
+ a_load_reg_reg(list,size,OS_64,dst,tmpreg);
+ dst:=tmpreg;
+ end;
+
+ ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,dst,src2,l,0);
+ ai.condition:=C_GEU;
+ list.concat(ai);
+ end;
+
+ a_call_name(list,'FPC_OVERFLOW',false);
+ a_label(list,l);
+ end;
+ OP_SUB:
+ begin
+ current_asmdata.getjumplabel(l);
+
+ list.Concat(taicpu.op_reg_reg_reg(A_SUB,dst,src2,src1));
+
+ if signed then
+ begin
+ tmpreg0:=getintregister(list,OS_INT);
+ tmpreg:=getintregister(list,OS_INT);
+ list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,NR_X0,src1));
+ list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg,dst,src2));
+
+ ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,tmpreg0,l,0);
+ ai.condition:=C_EQ;
+ list.concat(ai);
+ end
+ else
+ begin
+ { no overflow if result<=src2 }
+ if size in [OS_S32,OS_32] then
+ begin
+ tmpreg:=getintregister(list,OS_INT);
+ a_load_reg_reg(list,size,OS_64,dst,tmpreg);
+ dst:=tmpreg;
+ end;
+
+ ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,src2,dst,l,0);
+ ai.condition:=C_GEU;
+ list.concat(ai);
+ end;
+
+ 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);
+
+ tmpreg:=getintregister(list,OS_INT);
+ tmpreg0:=getintregister(list,OS_INT);
+ list.Concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2));
+ list.Concat(taicpu.op_reg_reg_reg(A_MULH,tmpreg,src1,src2));
+
+ list.concat(taicpu.op_reg_reg_const(A_SRAI,tmpreg0,dst,63));
+
+ a_cmp_reg_reg_label(list,OS_INT,OC_EQ,tmpreg,tmpreg0,l);
+
+ 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);
+
+ tmpreg:=getintregister(list,OS_INT);
+ list.Concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2));
+ list.Concat(taicpu.op_reg_reg_reg(A_MULHU,tmpreg,src1,src2));
+
+ a_cmp_reg_reg_label(list,OS_INT,OC_EQ,tmpreg,NR_X0,l);
+
+ a_call_name(list,'FPC_OVERFLOW',false);
+ a_label(list,l);
+ end;
+ OP_IDIV:
+ begin
+ { Only overflow if dst is all 1's }
+ current_asmdata.getjumplabel(l);
+
+ tmpreg:=getintregister(list,OS_INT);
+ list.Concat(taicpu.op_reg_reg_reg(A_DIV,dst,src1,src2));
+ list.Concat(taicpu.op_reg_reg_const(A_ADDI,tmpreg,dst,1));
+
+ a_cmp_reg_reg_label(list,OS_INT,OC_NE,tmpreg,NR_X0,l);
+
+ a_call_name(list,'FPC_OVERFLOW',false);
+ a_label(list,l);
+ end;
+ end
+ else
+ a_op_reg_reg_reg(list,op,size,src1,src2,dst);
+ end;
+
+
+ procedure tcgrv64.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
+ begin
+ end;
+
+
+ procedure tcgrv64.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);
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ a_reg_alloc(list,NR_FRAME_POINTER_REG);
+
+ reference_reset_base(href,NR_STACK_POINTER_REG,-8,ctempposinvalid,0,[]);
+
+ { Int registers }
+ regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
+
+ if (pi_do_call in current_procinfo.flags) then
+ regs:=regs+[RS_RETURN_ADDRESS_REG];
+
+ stackcount:=0;
+ for r:=RS_X0 to RS_X31 do
+ if r in regs then
+ inc(stackcount,8);
+
+ { Float registers }
+ fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+ for r:=RS_F0 to RS_F31 do
+ if r in fregs then
+ inc(stackcount,8);
+
+ inc(localsize,stackcount);
+ if not is_imm12(-(localsize-stackcount)) then
+ begin
+ if not (RS_RETURN_ADDRESS_REG in regs) then
+ begin
+ include(regs,RS_RETURN_ADDRESS_REG);
+ inc(localsize,8);
+ inc(stackcount,8);
+ end;
+ end;
+
+ stackAdjust:=0;
+ if (CPURV_HAS_COMPACT in cpu_capabilities[current_settings.cputype]) and
+ (stackcount>0) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-stackcount));
+ inc(href.offset,stackcount);
+ stackAdjust:=stackcount;
+ dec(localsize,stackcount);
+ end;
+
+ for r:=RS_X0 to RS_X31 do
+ if r in regs then
+ begin
+ list.concat(taicpu.op_reg_ref(A_SD,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+ dec(href.offset,8);
+ end;
+
+ { Float registers }
+ for r:=RS_F0 to RS_F31 do
+ if r in fregs then
+ begin
+ list.concat(taicpu.op_reg_ref(A_FSD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+ dec(href.offset,8);
+ end;
+
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackAdjust));
+
+ if localsize>0 then
+ begin
+ localsize:=align(localsize,8);
+
+ if is_imm12(-localsize) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize))
+ else
+ begin
+ a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
+ list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+ end;
+ end;
+ end;
+ end;
+
+
+ procedure tcgrv64.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
+ var
+ r: tsuperregister;
+ regs, fregs: tcpuregisterset;
+ localsize: longint;
+ href: treference;
+ begin
+ if not(nostackframe) then
+ begin
+ regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
+
+ if (pi_do_call in current_procinfo.flags) then
+ regs:=regs+[RS_RETURN_ADDRESS_REG];
+
+ reference_reset_base(href,NR_STACK_POINTER_REG,-8,ctempposinvalid,0,[]);
+ for r:=RS_X31 downto RS_X0 do
+ if r in regs then
+ dec(href.offset,8);
+
+ { Float registers }
+ fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+ for r:=RS_F0 to RS_F31 do
+ if r in fregs then
+ dec(href.offset,8);
+
+ localsize:=current_procinfo.calc_stackframe_size+(-href.offset-8);
+ if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,0))
+ else if localsize>0 then
+ begin
+ localsize:=align(localsize,8);
+
+ if is_imm12(localsize) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
+ else
+ begin
+ if not (RS_RETURN_ADDRESS_REG in regs) then
+ begin
+ include(regs,RS_RETURN_ADDRESS_REG);
+ dec(href.offset,8);
+ inc(localsize,8);
+ end;
+
+ a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+ end;
+ end;
+
+ { Float registers }
+ for r:=RS_F31 downto RS_F0 do
+ if r in fregs then
+ begin
+ inc(href.offset,8);
+ list.concat(taicpu.op_reg_ref(A_FLD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+ end;
+
+ for r:=RS_X31 downto RS_X0 do
+ if r in regs then
+ begin
+ inc(href.offset,8);
+ list.concat(taicpu.op_reg_ref(A_LD,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+ end;
+ end;
+
+ list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_RETURN_ADDRESS_REG));
+ end;
+
+
+ procedure tcgrv64.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
+ var
+ paraloc1, paraloc2, paraloc3: TCGPara;
+ pd: tprocdef;
+ begin
+ pd:=search_system_proc('MOVE');
+ paraloc1.init;
+ paraloc2.init;
+ paraloc3.init;
+ paramanager.getintparaloc(list, pd, 1, paraloc1);
+ paramanager.getintparaloc(list, pd, 2, paraloc2);
+ paramanager.getintparaloc(list, pd, 3, paraloc3);
+ a_load_const_cgpara(list, OS_SINT, len, paraloc3);
+ a_loadaddr_ref_cgpara(list, dest, paraloc2);
+ a_loadaddr_ref_cgpara(list, Source, paraloc1);
+ paramanager.freecgpara(list, paraloc3);
+ paramanager.freecgpara(list, paraloc2);
+ paramanager.freecgpara(list, paraloc1);
+ alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
+ alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
+ a_call_name(list, 'FPC_MOVE', false);
+ dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
+ dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
+ paraloc3.done;
+ paraloc2.done;
+ paraloc1.done;
+ end;
+
+ procedure tcgrv64.g_concatcopy(list: TAsmList; const source, dest: treference; len: aint);
+ var
+ tmpreg1, hreg, countreg: TRegister;
+ src, dst, src2, dst2: TReference;
+ lab: tasmlabel;
+ Count, count2: aint;
+ begin
+ src2:=source;
+ fixref(list,src2);
+
+ dst2:=dest;
+ fixref(list,dst2);
+
+ if len > high(longint) then
+ internalerror(2002072704);
+ { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
+ allocated on stack. This can only be done before tmipsprocinfo.set_first_temp_offset,
+ i.e. before secondpass. Other internal procedures request correct stack frame
+ by setting pi_do_call during firstpass, but for this particular one it is impossible.
+ Therefore, if the current procedure is a leaf one, we have to leave it that way. }
+
+ { anybody wants to determine a good value here :)? }
+ if (len > 100) and
+ assigned(current_procinfo) and
+ (pi_do_call in current_procinfo.flags) then
+ g_concatcopy_move(list, src2, dst2, len)
+ else
+ begin
+ Count := len div 8;
+ reference_reset(src,sizeof(aint),[]);
+ { load the address of src2 into src.base }
+ src.base := GetAddressRegister(list);
+ a_loadaddr_ref_reg(list, src2, src.base);
+
+ reference_reset(dst,sizeof(aint),[]);
+ { load the address of dst2 into dst.base }
+ dst.base := GetAddressRegister(list);
+ a_loadaddr_ref_reg(list, dst2, dst.base);
+
+ { generate a loop }
+ if Count > 4 then
+ begin
+ countreg := GetIntRegister(list, OS_INT);
+ tmpreg1 := GetIntRegister(list, OS_INT);
+ a_load_const_reg(list, OS_INT, Count, countreg);
+ current_asmdata.getjumplabel(lab);
+ a_label(list, lab);
+ list.concat(taicpu.op_reg_ref(A_LD, tmpreg1, src));
+ list.concat(taicpu.op_reg_ref(A_SD, tmpreg1, dst));
+ list.concat(taicpu.op_reg_reg_const(A_ADDI, src.base, src.base, 8));
+ list.concat(taicpu.op_reg_reg_const(A_ADDI, dst.base, dst.base, 8));
+ list.concat(taicpu.op_reg_reg_const(A_ADDI, countreg, countreg, -1));
+ a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_X0,countreg,lab);
+ len := len mod 8;
+ end;
+ { unrolled loop }
+ Count := len div 8;
+ if Count > 0 then
+ begin
+ tmpreg1 := GetIntRegister(list, OS_INT);
+ count2 := 1;
+ while count2 <= Count do
+ begin
+ list.concat(taicpu.op_reg_ref(A_LD, tmpreg1, src));
+ list.concat(taicpu.op_reg_ref(A_SD, tmpreg1, dst));
+ Inc(src.offset, 8);
+ Inc(dst.offset, 8);
+ Inc(count2);
+ end;
+ len := len mod 8;
+ end;
+ if (len and 4) <> 0 then
+ begin
+ hreg := GetIntRegister(list, OS_INT);
+ a_load_ref_reg(list, OS_32, OS_32, src, hreg);
+ a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
+ Inc(src.offset, 4);
+ Inc(dst.offset, 4);
+ end;
+ { copy the leftovers }
+ if (len and 2) <> 0 then
+ begin
+ hreg := GetIntRegister(list, OS_INT);
+ a_load_ref_reg(list, OS_16, OS_16, src, hreg);
+ a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
+ Inc(src.offset, 2);
+ Inc(dst.offset, 2);
+ end;
+ if (len and 1) <> 0 then
+ begin
+ hreg := GetIntRegister(list, OS_INT);
+ a_load_ref_reg(list, OS_8, OS_8, src, hreg);
+ a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
+ end;
+ end;
+ end;
+
+procedure create_codegen;
+begin
+ cg := tcgrv64.create;
+ cg128:=tcg128.create;
+end;
+
+end.
diff --git a/compiler/riscv64/cpubase.pas b/compiler/riscv64/cpubase.pas
new file mode 100644
index 0000000000..89ce7d292a
--- /dev/null
+++ b/compiler/riscv64/cpubase.pas
@@ -0,0 +1,462 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Contains the base types for the RiscV64
+
+ 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 base types for the RiscV64
+}
+unit cpubase;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+ strings, globtype,
+ cutils, cclasses, aasmbase, cpuinfo, cgbase;
+
+{*****************************************************************************
+ Assembler Opcodes
+*****************************************************************************}
+
+type
+ TAsmOp=(A_None,
+ { Pseudo instructions }
+ A_NOP,
+ { normal opcodes }
+ A_LUI,A_AUIPC,A_JAL,A_JALR,
+ A_Bxx,A_LB,A_LH,A_LW,A_LBU,A_LHU,
+ A_SB,A_SH,A_SW,
+ A_ADDI,A_SLTI,A_SLTIU,
+ A_XORI,A_ORI,A_ANDI,
+ A_SLLI,A_SRLI,A_SRAI,
+ A_ADD,A_SUB,A_SLL,A_SLT,A_SLTU,
+ A_XOR,A_SRL,A_SRA,A_OR,A_AND,
+ A_FENCE,A_FENCE_I,
+ A_ECALL,A_EBREAK,
+ A_CSRRW,A_CSRRS,A_CSRRC,A_CSRRWI,A_CSRRSI,A_CSRRCI,
+ { 64-bit }
+ A_ADDIW,A_SLLIW,A_SRLIW,A_SRAIW,
+ A_ADDW,A_SLLW,A_SRLW,A_SUBW,A_SRAW,
+ A_LD,A_SD,A_LWU,
+
+ { M-extension }
+ A_MUL,A_MULH,A_MULHSU,A_MULHU,
+ A_DIV,A_DIVU,A_REM,A_REMU,
+ { 64-bit }
+ A_MULW,
+ A_DIVW,A_DIVUW,A_REMW,A_REMUW,
+
+ { A-extension }
+ A_LR_W,A_SC_W,A_AMOSWAP_W,A_AMOADD_W,A_AMOXOR_W,A_AMOAND_W,
+ A_AMOOR_W,A_AMOMIN_W,A_AMOMAX_W,A_AMOMINU_W,A_AMOMAXU_W,
+ { 64-bit }
+ A_LR_D,A_SC_D,A_AMOSWAP_D,A_AMOADD_D,A_AMOXOR_D,A_AMOAND_D,
+ A_AMOOR_D,A_AMOMIN_D,A_AMOMAX_D,A_AMOMINU_D,A_AMOMAXU_D,
+
+ { F-extension }
+ A_FLW,A_FSW,
+ A_FMADD_S,A_FMSUB_S,A_FNMSUB_S,A_FNMADD_S,
+ A_FADD_S,A_FSUB_S,A_FMUL_S,A_FDIV_S,
+ A_FSQRT_S,A_FSGNJ_S,A_FSGNJN_S,A_FSGNJX_S,
+ A_FMIN_S,A_FMAX_S,
+ A_FMV_X_S,A_FEQ_S,A_FLT_S,A_FLE_S,A_FCLASS_S,
+ A_FCVT_W_S,A_FCVT_WU_S,A_FCVT_S_W,A_FCVT_S_WU,
+ A_FMV_S_X,
+ A_FRCSR,A_FRRM,A_FRFLAGS,A_FSCSR,A_FSRM,
+ A_FSFLAGS,A_FSRMI,A_FSFLAGSI,
+ { 64-bit }
+ A_FCVT_L_S,A_FCVT_LU_S,
+ A_FCVT_S_L,A_FCVT_S_LU,
+
+ { D-extension }
+ A_FLD,A_FSD,
+ A_FMADD_D,A_FMSUB_D,A_FNMSUB_D,A_FNMADD_D,
+ A_FADD_D,A_FSUB_D,A_FMUL_D,A_FDIV_D,
+ A_FSQRT_D,A_FSGNJ_D,A_FSGNJN_D,A_FSGNJX_D,
+ A_FMIN_D,A_FMAX_D,
+ A_FEQ_D,A_FLT_D,A_FLE_D,A_FCLASS_D,
+ A_FCVT_D_S,A_FCVT_S_D,
+ A_FCVT_W_D,A_FCVT_WU_D,A_FCVT_D_W,A_FCVT_D_WU,
+ { 64-bit }
+ A_FCVT_L_D,A_FCVT_LU_D,A_FMV_X_D,
+ A_FCVT_D_L,A_FCVT_D_LU,A_FMV_D_X,
+
+ { Machine mode }
+ A_MRET,A_HRET,A_SRET,A_URET,
+ A_WFI,
+
+ { Supervisor }
+ A_SFENCE_VM
+ );
+
+ TAsmOps = set of TAsmOp;
+
+ {# This should define the array of instructions as string }
+ op2strtable = array[tasmop] of string[8];
+
+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 rrv32nor.inc}-1;
+ totherregisterset = set of tregisterindex;
+
+ 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 rrv32sup.inc}
+
+ { No Subregisters }
+ R_SUBWHOLE=R_SUBNONE;
+
+ { Available Registers }
+ {$i rrv32con.inc}
+
+ { Integer Super registers first and last }
+ first_int_imreg = $20;
+
+ { Float Super register first and last }
+ first_fpu_imreg = $20;
+
+ { MM Super register first and last }
+ first_mm_imreg = $20;
+
+{ TODO: Calculate bsstart}
+ regnumber_count_bsstart = 64;
+
+ regnumber_table : array[tregisterindex] of tregister = (
+ {$i rrv32num.inc}
+ );
+
+ regstabs_table : array[tregisterindex] of shortint = (
+ {$i rrv32sta.inc}
+ );
+
+ regdwarf_table : array[tregisterindex] of shortint = (
+ {$i rrv32dwa.inc}
+ );
+
+{*****************************************************************************
+ Operands
+*****************************************************************************}
+ type
+ TMemoryOrderingFlag = (moRl, moAq);
+ TMemoryOrdering = set of TMemoryOrderingFlag;
+
+ TFenceFlag = (ffI, ffO, ffR, ffW);
+ TFenceFlags = set of TFenceFlag;
+
+ TRoundingMode = (RM_Default,
+ RM_RNE,
+ RM_RTZ,
+ RM_RDN,
+ RM_RUP,
+ RM_RMM);
+
+ const
+ roundingmode2str : array[TRoundingMode] of string[3] = ('',
+ 'rne','rtz','rdn','rup','rmm');
+
+{*****************************************************************************
+ Conditions
+*****************************************************************************}
+
+ type
+ TAsmCond = (C_None { unconditional jumps },
+ C_LT,C_LTU,C_GE,C_GEU,C_NE,C_EQ);
+
+ TAsmConds = set of TAsmCond;
+
+ const
+ cond2str: Array[TAsmCond] of string[4] = ({cf_none}'',
+ { conditions when not using ctr decrement etc}
+ 'lt','ltu','ge','geu','ne','eq');
+
+ uppercond2str: Array[TAsmCond] of string[4] = ({cf_none}'',
+ { conditions when not using ctr decrement etc}
+ 'LT','LTU','GE','GEU','NE','EQ');
+
+ {*****************************************************************************
+ Flags
+ *****************************************************************************}
+
+type
+ TResFlagsEnum = (F_EQ,F_NE,F_LT,F_LTU,F_GE,F_GEU);
+
+{*****************************************************************************
+ Reference
+*****************************************************************************}
+
+ {*****************************************************************************
+ Operand Sizes
+ *****************************************************************************}
+
+ {*****************************************************************************
+ 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 rrv32sta.inc}
+ );
+
+ {*****************************************************************************
+ Generic Register names
+ *****************************************************************************}
+
+ {# Stack pointer register }
+ NR_STACK_POINTER_REG = NR_X2;
+ RS_STACK_POINTER_REG = RS_X2;
+ {# Frame pointer register }
+ NR_FRAME_POINTER_REG = NR_X8;
+ RS_FRAME_POINTER_REG = RS_X8;
+
+ NR_PIC_OFFSET_REG = NR_X3;
+ { Return address of a function }
+ NR_RETURN_ADDRESS_REG = NR_X1;
+ RS_RETURN_ADDRESS_REG = RS_X1;
+ { Results are returned in this register (32-bit values) }
+ NR_FUNCTION_RETURN_REG = NR_X10;
+ RS_FUNCTION_RETURN_REG = RS_X10;
+ { Low part of 64bit return value }
+ NR_FUNCTION_RETURN64_LOW_REG = NR_X10;
+ RS_FUNCTION_RETURN64_LOW_REG = RS_X10;
+ { High part of 64bit return value }
+ NR_FUNCTION_RETURN64_HIGH_REG = NR_X11;
+ RS_FUNCTION_RETURN64_HIGH_REG = RS_X11;
+ { 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_F10;
+ NR_MM_RESULT_REG = NR_NO;
+
+ NR_DEFAULTFLAGS = NR_NO;
+ RS_DEFAULTFLAGS = 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..12] of tsuperregister = (
+ RS_X2,
+ RS_X8,RS_X9,
+ RS_X18,RS_X19,
+ RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27
+ );
+
+ { 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; { for 32-bit version only }
+
+
+{*****************************************************************************
+ CPU Dependent Constants
+*****************************************************************************}
+
+ maxfpuregs = 8;
+
+ {*****************************************************************************
+ Helpers
+ *****************************************************************************}
+
+ function is_imm12(value: aint): boolean;
+ function is_lui_imm(value: aint): 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 conditions_equal(const c1,c2: TAsmCond): boolean;
+
+implementation
+
+ uses
+ rgbase,verbose;
+
+ const
+ std_regname_table : TRegNameTable = (
+ {$i rrv32std.inc}
+ );
+
+ regnumber_index : array[tregisterindex] of tregisterindex = (
+ {$i rrv32rni.inc}
+ );
+
+ std_regname_index : array[tregisterindex] of tregisterindex = (
+ {$i rrv32sri.inc}
+ );
+
+
+{*****************************************************************************
+ Helpers
+*****************************************************************************}
+
+ function is_imm12(value: aint): boolean;
+ begin
+ result:=(value >= -2048) and (value <= 2047);
+ end;
+
+
+ function is_lui_imm(value: aint): boolean;
+ begin
+ result:=SarInt64((value and $FFFFF000) shl 32, 32) = value;
+ end;
+
+
+ function is_calljmp(o:tasmop):boolean;
+ begin
+ is_calljmp:=false;
+ case o of
+ A_JAL,A_JALR,A_Bxx:
+ is_calljmp:=true;
+ end;
+ end;
+
+
+ function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+ const
+ inv_condflags:array[TAsmCond] of TAsmCond=(C_None,
+ C_GE,C_GEU,C_LT,C_LTU,C_EQ,C_NE);
+ begin
+ result := inv_condflags[c];
+ end;
+
+
+ function reg_cgsize(const reg: tregister): tcgsize;
+ begin
+ case getregtype(reg) of
+ R_INTREGISTER :
+ result:=OS_64;
+ R_MMREGISTER:
+ result:=OS_M128;
+ R_FPUREGISTER:
+ result:=OS_F64;
+ else
+ internalerror(200303181);
+ 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(200603251);
+ end;
+
+ function conditions_equal(const c1, c2: TAsmCond): boolean;
+ begin
+ result:=c1=c2;
+ end;
+
+end.
+
diff --git a/compiler/riscv64/cpuinfo.pas b/compiler/riscv64/cpuinfo.pas
new file mode 100644
index 0000000000..91879a0b48
--- /dev/null
+++ b/compiler/riscv64/cpuinfo.pas
@@ -0,0 +1,139 @@
+{
+ Copyright (c) 1998-2002 by the Free Pascal development team
+
+ Basic Processor information for the Risc-V64
+
+ 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;
+
+interface
+
+uses
+ globtype;
+
+type
+ bestreal = double;
+{$if FPC_FULLVERSION>20700}
+ bestrealrec = TDoubleRec;
+{$endif FPC_FULLVERSION>20700}
+ ts32real = single;
+ ts64real = double;
+ ts80real = extended;
+ ts128real = extended;
+ ts64comp = comp;
+
+ pbestreal = ^bestreal;
+
+ { possible supported processors for this target }
+ tcputype = (cpu_none,
+ cpu_rv64imafdc,
+ cpu_rv64imafd,
+ cpu_rv64ima,
+ cpu_rv64im,
+ cpu_rv64i
+ );
+
+ tfputype =
+ (fpu_none,
+ fpu_libgcc,
+ fpu_soft,
+ 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_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[10] = ('',
+ 'RV64IMAFDC',
+ 'RV64IMAFD',
+ 'RV64IMA',
+ 'RV64IM',
+ 'RV64I'
+ );
+
+ fputypestr: array[tfputype] of string[8] = ('',
+ 'LIBGCC',
+ 'SOFT',
+ '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]+
+ [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,
+ cs_opt_tailrecursion,cs_opt_reorder_fields,cs_opt_fastmath,
+ cs_opt_stackframe];
+
+ level1optimizerswitches = genericlevel1optimizerswitches;
+ level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
+ [cs_opt_regvar,cs_opt_stackframe,cs_opt_nodecse,cs_opt_tailrecursion];
+ level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
+ level4optimizerswitches = genericlevel4optimizerswitches + level3optimizerswitches + [cs_opt_stackframe];
+
+ type
+ tcpuflags =
+ (CPURV_HAS_MUL,
+ CPURV_HAS_ATOMIC,
+ CPURV_HAS_COMPACT
+ );
+
+ const
+ cpu_capabilities : array[tcputype] of set of tcpuflags =
+ ( { cpu_none } [],
+ { cpu_rv64imafdc } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC,CPURV_HAS_COMPACT],
+ { cpu_rv64imafd } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+ { cpu_rv64ima } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+ { cpu_rv64im } [CPURV_HAS_MUL],
+ { cpu_rv64i } []
+ );
+
+implementation
+
+end.
+
diff --git a/compiler/riscv64/cpunode.pas b/compiler/riscv64/cpunode.pas
new file mode 100644
index 0000000000..e619c41a42
--- /dev/null
+++ b/compiler/riscv64/cpunode.pas
@@ -0,0 +1,55 @@
+{
+ Copyright (c) 2000-2002 by Florian Klaempfl
+
+ Includes the RiscV64 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}
+ nrv64add,
+ nrv64cal,
+ nrvset,
+ nrvinl,
+ nrv64mat,
+ nrv64cnv,
+ nrv64ld
+{$else not llvm}
+ llvmnode
+{$endif not llvm}
+ ;
+
+end.
+
diff --git a/compiler/riscv64/cpupara.pas b/compiler/riscv64/cpupara.pas
new file mode 100644
index 0000000000..67602ed122
--- /dev/null
+++ b/compiler/riscv64/cpupara.pas
@@ -0,0 +1,545 @@
+{
+ Copyright (c) 2002 by Florian Klaempfl
+
+ RiscV64 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 getintparaloc(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; 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_X0..RS_X31]-[RS_X2,RS_X8..RS_X9,RS_X18..RS_X27];
+ end;
+
+ function tcpuparamanager.get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset;
+ begin
+ result:=[RS_F0..RS_F31]-[RS_F8..RS_F9,RS_F18..RS_F27];
+ end;
+
+ procedure tcpuparamanager.getintparaloc(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(200309271);
+ loc := LOC_REGISTER;
+ register := newreg(R_INTREGISTER, RS_X10 + 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;
+ 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:
+ if (cs_fp_emulation in current_settings.moduleswitches) or
+ (current_settings.fputype in [fpu_soft]) then
+ result := LOC_REGISTER
+ else
+ result := LOC_FPUREGISTER;
+ enumdef:
+ result := LOC_REGISTER;
+ pointerdef:
+ result := LOC_REGISTER;
+ formaldef:
+ result := LOC_REGISTER;
+ classrefdef:
+ result := LOC_REGISTER;
+ procvardef,
+ recorddef:
+ result := LOC_REGISTER;
+ 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(2002071001);
+ 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];
+ 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
+ { register parameter save area begins at 48(r2) }
+ cur_stack_offset := 0;
+ curintreg := RS_X10;
+ curfloatreg := RS_F10;
+ 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(2014113001);
+ 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(200411141);
+{$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(200412153);
+ 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_X0;
+ 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: tdef;
+ paralen: aint;
+ firstparaloc,
+ paraaligned: boolean;
+ begin
+ alllocdef:=nil;
+ locdef:=nil;
+ para.reset;
+ { 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)) then
+ begin
+ { general fallback rule: pass aggregate types in integer registers
+ without special adjustments (incl. Darwin h) }
+ loc:=LOC_REGISTER;
+ paracgsize:=int_cgsize(paralen);
+ 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(2005011310);
+ 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_X17) 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_X17) 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 (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_F17) then begin
+ paraloc^.loc := loc;
+ paraloc^.size := paracgsize;
+ paraloc^.def := locdef;
+ paraloc^.register := newreg(R_FPUREGISTER, nextfloatreg, R_SUBWHOLE);
+ { the RiscV ABI says that the GPR index is increased for every parameter, no matter
+ which type it is stored in
+
+ not really, https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#hardware-floating-point-calling-convention says
+ otherwise, gcc doesn't do it either }
+ inc(nextfloatreg);
+ dec(paralen, tcgsize2size[paraloc^.size]);
+ end else if (loc = LOC_MMREGISTER) then begin
+ { no mm registers }
+ internalerror(2018072601);
+ 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(2013060122);
+ end;
+ end;
+ LOC_REGISTER,
+ LOC_REFERENCE:
+ begin
+ paraloc^.size:=int_cgsize(paralen);
+ paraloc^.def:=get_paraloc_def(paradef, paralen, firstparaloc);
+ end;
+ else
+ internalerror(2006011101);
+ 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
+ trv64procinfo(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;
+ 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, callerside, 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 }
+ result := create_paraloc_info_intern(p, callerside, varargspara, curintreg,
+ curfloatreg, curmmreg, cur_stack_offset, true);
+ { varargs routines have to reserve at least 64 bytes for the RiscV ABI }
+ if (result < 64) then
+ result := 64;
+ end else begin
+ parasize := cur_stack_offset;
+ for i := 0 to varargspara.count - 1 do begin
+ hp := tparavarsym(varargspara[i]);
+ hp.paraloc[callerside].alignment := 8;
+ paraloc := hp.paraloc[callerside].add_location;
+ paraloc^.loc := LOC_REFERENCE;
+ paraloc^.size := def_cgsize(hp.vardef);
+ paraloc^.def := hp.vardef;
+ paraloc^.reference.index := NR_STACK_POINTER_REG;
+ l := push_size(hp.varspez, hp.vardef, p.proccalloption);
+ paraloc^.reference.offset := parasize;
+ parasize := parasize + l;
+ end;
+ result := parasize;
+ end;
+ if curfloatreg <> firstfloatreg then
+ include(varargspara.varargsinfo, va_uses_float_reg);
+end;
+
+function tcpuparamanager.parseparaloc(p: tparavarsym; const s: string): boolean;
+begin
+ internalerror(200404182);
+ result := true;
+end;
+
+
+begin
+ paramanager := tcpuparamanager.create;
+end.
+
diff --git a/compiler/riscv64/cpupi.pas b/compiler/riscv64/cpupi.pas
new file mode 100644
index 0000000000..a0b3c129fb
--- /dev/null
+++ b/compiler/riscv64/cpupi.pas
@@ -0,0 +1,116 @@
+{
+ 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
+ trv64procinfo = 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 trv64procinfo.create(aparent: tprocinfo);
+ begin
+ inherited create(aparent);
+ maxpushedparasize := 0;
+ end;
+
+
+ procedure trv64procinfo.set_first_temp_offset;
+ begin
+ if (po_nostackframe in procdef.procoptions) then
+ begin
+ { maxpushedparasize sghould be zero,
+ if not we will get an error later. }
+ tg.setfirsttemp(maxpushedparasize);
+ exit;
+ end;
+
+ if tg.direction = -1 then
+ tg.setfirsttemp(-(1+12)*8)
+ else
+ tg.setfirsttemp(maxpushedparasize);
+ end;
+
+
+ function trv64procinfo.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;
+ end;
+ floatsavesize:=system.align(floatsavesize,max(current_settings.alignment.localalignmin,8));
+ 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 := trv64procinfo;
+end.
+
diff --git a/compiler/riscv64/cputarg.pas b/compiler/riscv64/cputarg.pas
new file mode 100644
index 0000000000..6986b1f2b6
--- /dev/null
+++ b/compiler/riscv64/cputarg.pas
@@ -0,0 +1,85 @@
+{
+ Copyright (c) 2001-2002 by Peter Vreman
+
+ Includes the RiscV64 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}
+ {$ifndef NOTARGETEMBEDDED}
+ ,t_embed
+ {$endif}
+
+{**************************************
+ Assemblers
+**************************************}
+
+ {$ifndef NOAGRVGAS}
+ ,agrvgas
+ {$endif}
+
+{**************************************
+ Assembler Readers
+**************************************}
+
+ {$ifndef NoRaRVGas}
+ ,rarv64gas
+ {$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.
diff --git a/compiler/riscv64/hlcgcpu.pas b/compiler/riscv64/hlcgcpu.pas
new file mode 100644
index 0000000000..3c0f4968f7
--- /dev/null
+++ b/compiler/riscv64/hlcgcpu.pas
@@ -0,0 +1,78 @@
+{
+ Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+ Member of the Free Pascal development team
+
+ This unit contains high-level code generator support for riscv64
+
+ 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
+ globtype,
+ aasmdata,
+ symtype,
+ cgbase,cgutils,hlcgobj,hlcgrv;
+
+type
+ thlcgcpu = class(thlcgriscv)
+ procedure a_load_const_subsetreg(list: TAsmlist; tosubsetsize: tdef; a: tcgint; const sreg: tsubsetregister); override;
+ end;
+
+ procedure create_hlcodegen;
+
+implementation
+
+ uses
+ cpubase,aasmcpu,
+ defutil,
+ cgobj,cgcpu;
+
+ { thlcgcpu }
+
+
+ procedure thlcgcpu.a_load_const_subsetreg(list: TAsmlist; tosubsetsize: tdef; a: tcgint; const sreg: tsubsetregister);
+ var
+ tmpreg : TRegister;
+ begin
+{$ifdef extdebug}
+ list.concat(tai_comment.create(strpnew('a_load_const_subsetreg subsetregsize = ' + cgsize2string(sreg.subsetregsize) + ' subsetsize = ' + cgsize2string(def_cgsize(subsetsize)) + ' startbit = ' + intToStr(sreg.startbit) + ' a = ' + intToStr(a))));
+{$endif}
+ { loading the constant into the lowest bits of a temp register and then inserting is
+ better than loading some usually large constants and do some masking and shifting on riscv64 }
+ tmpreg:=getintregister(list,tosubsetsize);
+ a_load_const_reg(list,tosubsetsize,a,tmpreg);
+ a_load_reg_subsetreg(list,tosubsetsize,tosubsetsize,tmpreg,sreg);
+ end;
+
+
+ procedure create_hlcodegen;
+ begin
+ hlcg:=thlcgcpu.create;
+ create_codegen;
+ end;
+
+
+
+begin
+ chlcgobj:=thlcgcpu;
+end.
diff --git a/compiler/riscv64/itcpugas.pas b/compiler/riscv64/itcpugas.pas
new file mode 100644
index 0000000000..4fabace6e8
--- /dev/null
+++ b/compiler/riscv64/itcpugas.pas
@@ -0,0 +1,157 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ This unit contains the RiscV64 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[14] = ('<none>',
+ 'nop',
+ 'lui','auipc','jal','jalr',
+ 'b','lb','lh','lw','lbu','lhu',
+ 'sb','sh','sw',
+ 'addi','slti','sltiu',
+ 'xori','ori','andi',
+ 'slli','srli','srai',
+ 'add','sub','sll','slt','sltu',
+ 'xor','srl','sra','or','and',
+ 'fence','fence.i',
+ 'ecall','ebreak',
+ 'csrrw','csrrs','csrrc','csrrwi','csrrsi','csrrci',
+ { 64-bit }
+ 'addiw','slliw','srliw','sraiw',
+ 'addw','sllw','srlw','subw','sraw',
+ 'ld','sd','lwu',
+
+ { m-extension }
+ 'mul','mulh','mulhsu','mulhu',
+ 'div','divu','rem','remu',
+ { 64-bit }
+ 'mulw',
+ 'divw','divuw','remw','remuw',
+
+ { a-extension }
+ 'lr.w','sc.w','amoswap.w','amoadd.w','amoxor.w','amoand.w',
+ 'amoor.w','amomin.w','amomax.w','amominu.w','amomaxu.w',
+ { 64-bit }
+ 'lr.d','sc.d','amoswap.d','amoadd.d','amoxor.d','amoand.d',
+ 'amoor.d','amomin.d','amomax.d','amominu.d','amomaxu.d',
+
+ { f-extension }
+ 'flw','fsw',
+ 'fmadd.s','fmsub.s','fnmsub.s','fnmadd.s',
+ 'fadd.s','fsub.s','fmul.s','fdiv.s',
+ 'fsqrt.s','fsgnj.s','fsgnjn.s','fsgnjx.s',
+ 'fmin.s','fmax.s',
+ 'fmv.x.s','feq.s','flt.s','fle.s','fclass.s',
+ 'fcvt.w.s','fcvt.wu.s','fcvt.s.w','fcvt.s.wu',
+ 'fmv.s.x',
+ 'frcsr','frrm','frflags','fscsr','fsrm',
+ 'fsflags','fsrmi','fsflagsi',
+ { 64-bit }
+ 'fcvt.l.s','fcvt.lu.s',
+ 'fcvt.s.l','fcvt.s.lu',
+
+ { d-extension }
+ 'fld','fsd',
+ 'fmadd.d','fmsub.d','fnmsub.d','fnmadd.d',
+ 'fadd.d','fsub.d','fmul.d','fdiv.d',
+ 'fsqrt.d','fsgnj.d','fsgnjn.d','fsgnjx.d',
+ 'fmin.d','fmax.d',
+ 'feq.d','flt.d','fle.d','fclass.d',
+ 'fcvt.d.s','fcvt.s.d',
+ 'fcvt.w.d','fcvt.wu.d','fcvt.d.w','fcvt.d.wu',
+ { 64-bit }
+ 'fcvt.l.d','fcvt.lu.d','fmv.x.d',
+ 'fcvt.d.l','fcvt.d.lu','fmv.d.x',
+
+ { Machine mode }
+ 'mret','hret','sret','uret',
+ 'wfi',
+
+ { Supervisor mode }
+ 'sfence.vm'
+ );
+
+ 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 rrv32std.inc}
+ );
+
+ gas_regname_index : array[tregisterindex] of tregisterindex = (
+ {$i rrv32sri.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;
+
+
+ function gas_regname(r:Tregister):string;
+ var
+ p : tregisterindex;
+ begin
+ p:=findreg_by_number(r);
+ if p<>0 then
+ result:=gas_regname_table[p]
+ else
+ result:=generic_regname(r);
+ end;
+
+end.
+
diff --git a/compiler/riscv64/nrv64add.pas b/compiler/riscv64/nrv64add.pas
new file mode 100644
index 0000000000..37356772ff
--- /dev/null
+++ b/compiler/riscv64/nrv64add.pas
@@ -0,0 +1,98 @@
+{
+ Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe
+
+ Code generation for add nodes on the Risc-V64
+
+ 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 nrv64add;
+
+{$I fpcdefs.inc}
+
+ interface
+
+ uses
+ node, ncgadd, aasmbase, nrvadd, cpubase;
+
+ type
+ trv64addnode = class(trvaddnode)
+ protected
+ function pass_1: tnode; override;
+
+ procedure second_add64bit; override;
+
+ function use_generic_mul32to64: boolean; override;
+ end;
+
+ implementation
+
+ uses
+ systems,
+ cutils,verbose,
+ paramgr,procinfo,
+ aasmtai,aasmdata,aasmcpu,defutil,
+ cgbase,cgcpu,cgutils,
+ globals,
+ pass_1,
+ CPUInfo,cpupara,
+ ncon,nset,nadd,
+ symconst,
+ hlcgobj, ncgutil,cgobj;
+
+ function trv64addnode.pass_1: tnode;
+ begin
+ if (nodetype=muln) and
+ (left.resultdef.typ=orddef) and (left.resultdef.typ=orddef) and
+ (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype]) then
+ begin
+ result:=nil;
+
+ firstpass(left);
+ firstpass(right);
+
+ expectloc:=LOC_REGISTER;
+ end
+ else if (nodetype=muln) and
+ (not (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype])) and
+ (is_64bit(left.resultdef) or
+ is_64bit(right.resultdef)) then
+ begin
+ result:=first_add64bitint;
+ end
+ else
+ Result:=inherited pass_1;
+
+ if expectloc=LOC_FLAGS then
+ expectloc:=LOC_REGISTER;
+ end;
+
+
+ procedure trv64addnode.second_add64bit;
+ begin
+ second_addordinal;
+ end;
+
+
+ function trv64addnode.use_generic_mul32to64: boolean;
+ begin
+ result:=false;
+ end;
+
+begin
+ caddnode := trv64addnode;
+end.
+
diff --git a/compiler/riscv64/nrv64cal.pas b/compiler/riscv64/nrv64cal.pas
new file mode 100644
index 0000000000..7781434673
--- /dev/null
+++ b/compiler/riscv64/nrv64cal.pas
@@ -0,0 +1,56 @@
+{
+ Copyright (c) 2002 by Florian Klaempfl
+
+ Implements the RiscV64 specific part of call 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 nrv64cal;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+ aasmdata, cgbase,
+ symdef, node, ncal, ncgcal;
+
+type
+
+ trv64callparanode = class(tcgcallparanode)
+ end;
+
+ trv64ccallnode = class(tcgcallnode)
+ end;
+
+implementation
+
+uses
+ globtype, systems,
+ cutils, verbose, globals,
+ symconst, symbase, symsym, symtable, defutil, paramgr, parabase,
+ pass_2,
+ cpuinfo, cpubase, aasmbase, aasmtai, aasmcpu,
+ nmem, nld, ncnv,
+ ncgutil, cgutils, cgobj, tgobj, rgobj, rgcpu,
+ cgcpu, cpupi, procinfo;
+
+begin
+ ccallparanode:=trv64callparanode;
+ ccallnode := trv64ccallnode;
+end.
+
diff --git a/compiler/riscv64/nrv64cnv.pas b/compiler/riscv64/nrv64cnv.pas
new file mode 100644
index 0000000000..65c3714b36
--- /dev/null
+++ b/compiler/riscv64/nrv64cnv.pas
@@ -0,0 +1,124 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Generate RiscV64 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 nrv64cnv;
+
+{$I fpcdefs.inc}
+
+ interface
+
+ uses
+ node, ncnv, ncgcnv, nrvcnv;
+
+ type
+ trv64typeconvnode = class(trvtypeconvnode)
+ 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 trv64typeconvnode.first_int_to_real: tnode;
+ begin
+ if (cs_fp_emulation in current_settings.moduleswitches) then
+ result:=inherited first_int_to_real
+ { converting a 64bit integer to a float requires a helper }
+ else
+ begin
+ if (is_currency(left.resultdef)) then begin
+ // hack to avoid double division by 10000, as it's
+ // already done by typecheckpass.resultdef_int_to_real
+ left.resultdef := s64inttype;
+ end else begin
+ // everything that is less than 64 bits is converted to a 64 bit signed
+ // integer - because the int_to_real conversion is faster for 64 bit
+ // signed ints compared to 64 bit unsigned ints.
+ if (not (torddef(left.resultdef).ordtype in [s64bit, u64bit, scurrency])) then begin
+ inserttypeconv(left, s64inttype);
+ end;
+ end;
+ firstpass(left);
+ result := nil;
+ expectloc := LOC_FPUREGISTER;
+ end;
+ end;
+
+ {*****************************************************************************
+ SecondTypeConv
+ *****************************************************************************}
+
+ procedure trv64typeconvnode.second_int_to_real;
+ const
+ ops: array[boolean,boolean,s32real..s64real] of TAsmOp = (
+ ((A_FCVT_S_WU,A_FCVT_D_WU),
+ (A_FCVT_S_W,A_FCVT_D_W)),
+ ((A_FCVT_S_LU,A_FCVT_D_LU),
+ (A_FCVT_S_L,A_FCVT_D_L)));
+ var
+ restype: tfloattype;
+ 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);
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(ops[is_64bit(left.resultdef),is_signed(left.resultdef),restype], location.register, left.location.register));
+ end;
+
+begin
+ ctypeconvnode := trv64typeconvnode;
+end.
+
diff --git a/compiler/riscv64/nrv64ld.pas b/compiler/riscv64/nrv64ld.pas
new file mode 100644
index 0000000000..c2a6963a5b
--- /dev/null
+++ b/compiler/riscv64/nrv64ld.pas
@@ -0,0 +1,57 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Generate riscv64 assembler for nodes that handle loads and assignments
+
+ 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 nrv64ld;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+ node, ncgld;
+
+type
+ trv64loadnode = class(tcgloadnode)
+ procedure pass_generate_code override;
+ end;
+
+implementation
+
+uses
+ verbose,
+ systems,
+ cpubase,
+ cgutils, cgobj,
+ aasmbase, aasmtai,aasmdata,
+ symconst, symsym,
+ procinfo,
+ nld;
+
+procedure trv64loadnode.pass_generate_code;
+begin
+ inherited pass_generate_code;
+end;
+
+
+begin
+ cloadnode := trv64loadnode;
+end.
+
diff --git a/compiler/riscv64/nrv64mat.pas b/compiler/riscv64/nrv64mat.pas
new file mode 100644
index 0000000000..abcdfdb124
--- /dev/null
+++ b/compiler/riscv64/nrv64mat.pas
@@ -0,0 +1,163 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Generate RiscV64 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 nrv64mat;
+
+{$I fpcdefs.inc}
+
+ interface
+
+ uses
+ node,nmat, ncgmat,
+ cgbase;
+
+ type
+ trv64moddivnode = 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;
+
+ trv64shlshrnode = class(tcgshlshrnode)
+ end;
+
+ trv64unaryminusnode = class(tcgunaryminusnode)
+ end;
+
+ trv64notnode = 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 trv64notnode.second_boolean;
+ var
+ tlabel, flabel: tasmlabel;
+ begin
+ if not handle_locjump then
+ begin
+ secondpass(left);
+ case left.location.loc of
+ LOC_FLAGS :
+ begin
+ Internalerror(2016060601);
+ //location_copy(location,left.location);
+ //inverse_flags(location.resflags);
+ 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_SLTIU,location.register,left.location.register,1));
+ end;
+ else
+ internalerror(2003042401);
+ end;
+ end;
+ end;
+
+
+ function trv64moddivnode.use_moddiv64bitint_helper: boolean;
+ begin
+ Result:=true;
+ end;
+
+
+ procedure trv64moddivnode.emit_div_reg_reg(signed: boolean; denum, num: tregister);
+ var
+ op: TAsmOp;
+ begin
+ if signed then
+ op:=A_DIV
+ else
+ op:=A_DIVU;
+
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
+ end;
+
+
+ procedure trv64moddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
+ var
+ op: TAsmOp;
+ begin
+ if signed then
+ op:=A_REM
+ else
+ op:=A_REMU;
+
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
+ end;
+
+
+ function trv64moddivnode.first_moddiv64bitint: tnode;
+ var
+ power: longint;
+ 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) and
+ ((CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
+ (ispowerof2(tordconstnode(right).value,power) or
+ (tordconstnode(right).value=1) or
+ (tordconstnode(right).value=int64(-1))
+ )
+ ) then
+ result:=nil
+ else if (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
+ (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 := trv64moddivnode;
+ cshlshrnode := trv64shlshrnode;
+ cunaryminusnode := trv64unaryminusnode;
+ cnotnode := trv64notnode;
+end.
+
diff --git a/compiler/riscv64/rarv.pas b/compiler/riscv64/rarv.pas
new file mode 100644
index 0000000000..b02c55abab
--- /dev/null
+++ b/compiler/riscv64/rarv.pas
@@ -0,0 +1,50 @@
+{
+ Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman
+
+ Handles the common riscv 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 rarv;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+ aasmbase, aasmtai,aasmdata, aasmcpu,
+ cpubase, rautils, cclasses;
+
+type
+ TRVOperand = class(TOperand)
+ end;
+
+ TRVInstruction = class(TInstruction)
+ ordering: TMemoryOrdering;
+ function ConcatInstruction(p: TAsmList): tai; override;
+ end;
+
+implementation
+
+ function TRVInstruction.ConcatInstruction(p: TAsmList): tai;
+ begin
+ Result:=inherited ConcatInstruction(p);
+ (result as taicpu).memoryordering:=ordering;
+ end;
+
+end.
+
diff --git a/compiler/riscv64/rarv64gas.pas b/compiler/riscv64/rarv64gas.pas
new file mode 100644
index 0000000000..2c727846d8
--- /dev/null
+++ b/compiler/riscv64/rarv64gas.pas
@@ -0,0 +1,840 @@
+{
+ Copyright (c) 2016 by Jeppe Johansen
+
+ Does the parsing for the RiscV64 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 rarv64gas;
+
+{$I fpcdefs.inc}
+
+ interface
+
+ uses
+ raatt, rarv,
+ cpubase;
+
+ type
+ trv64attreader = class(tattreader)
+ actmemoryordering: TMemoryOrdering;
+ function is_register(const s: string): boolean; override;
+ function is_asmopcode(const s: string):boolean;override;
+ procedure handleopcode;override;
+ procedure BuildReference(oper : trvoperand);
+ procedure BuildOperand(oper : trvoperand);
+ procedure BuildOpCode(instr : trvinstruction);
+ procedure ReadAt(oper : trvoperand);
+ procedure ReadSym(oper : trvoperand);
+ end;
+
+ implementation
+
+ uses
+ { helpers }
+ cutils,
+ { global }
+ globtype,globals,verbose,
+ systems,
+ { aasm }
+ aasmbase,aasmtai,aasmdata,aasmcpu,
+ { symtable }
+ symconst,symsym,symdef,
+ { parser }
+ procinfo,
+ rabase,rautils,
+ cgbase,cgobj,cgrv
+ ;
+
+ procedure trv64attreader.ReadSym(oper : trvoperand);
+ var
+ tempstr, mangledname : string;
+ typesize,l,k : aint;
+ begin
+ tempstr:=actasmpattern;
+ Consume(AS_ID);
+ { typecasting? }
+ if (actasmtoken=AS_LPAREN) and
+ SearchType(tempstr,typesize) then
+ begin
+ oper.hastype:=true;
+ Consume(AS_LPAREN);
+ BuildOperand(oper);
+ Consume(AS_RPAREN);
+ if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
+ oper.SetSize(typesize,true);
+ end
+ else
+ if not oper.SetupVar(tempstr,false) then
+ Message1(sym_e_unknown_id,tempstr);
+ { record.field ? }
+ if actasmtoken=AS_DOT then
+ begin
+ BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
+ if (mangledname<>'') then
+ Message(asmr_e_invalid_reference_syntax);
+ inc(oper.opr.ref.offset,l);
+ end;
+ end;
+
+
+ procedure trv64attreader.ReadAt(oper : trvoperand);
+ begin
+ { check for ...@ }
+ if actasmtoken=AS_AT then
+ begin
+ if (oper.opr.ref.symbol=nil) and
+ (oper.opr.ref.offset = 0) then
+ Message(asmr_e_invalid_reference_syntax);
+ Consume(AS_AT);
+ if actasmtoken=AS_ID then
+ begin
+ {if upper(actasmpattern)='L' then
+ oper.opr.ref.refaddr:=addr_low
+ else if upper(actasmpattern)='HI' then
+ oper.opr.ref.refaddr:=addr_high
+ else if upper(actasmpattern)='HA' then
+ oper.opr.ref.refaddr:=addr_higha
+ else}
+ Message(asmr_e_invalid_reference_syntax);
+ Consume(AS_ID);
+ end
+ else
+ Message(asmr_e_invalid_reference_syntax);
+ end;
+ end;
+
+
+ procedure trv64attreader.BuildReference(oper: trvoperand);
+
+ procedure Consume_RParen;
+ begin
+ if actasmtoken <> AS_RPAREN then
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(true);
+ end
+ else
+ begin
+ Consume(AS_RPAREN);
+ if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(true);
+ end;
+ end;
+ end;
+
+ var
+ l : aint;
+ relsym: string;
+ asmsymtyp: tasmsymtype;
+ isflags: tindsymflags;
+
+ begin
+ Consume(AS_LPAREN);
+ Case actasmtoken of
+ AS_INTNUM,
+ AS_MINUS,
+ AS_PLUS:
+ Begin
+ { offset(offset) is invalid }
+ If oper.opr.Ref.Offset <> 0 Then
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(true);
+ End
+ Else
+ Begin
+ oper.opr.Ref.Offset:=BuildConstExpression(false,true);
+ Consume(AS_RPAREN);
+ if actasmtoken=AS_AT then
+ ReadAt(oper);
+ end;
+ exit;
+ End;
+ AS_REGISTER: { (reg ... }
+ Begin
+ if ((oper.opr.typ=OPR_REFERENCE) and (oper.opr.ref.base<>NR_NO)) or
+ ((oper.opr.typ=OPR_LOCAL) and (oper.opr.localsym.localloc.loc<>LOC_REGISTER)) then
+ message(asmr_e_cannot_index_relative_var);
+ oper.opr.ref.base:=actasmregister;
+ Consume(AS_REGISTER);
+ Consume_RParen;
+ end; {end case }
+ AS_ID:
+ Begin
+ ReadSym(oper);
+ case actasmtoken of
+ AS_PLUS:
+ begin
+ { add a constant expression? }
+ l:=BuildConstExpression(true,true);
+ case oper.opr.typ of
+ OPR_CONSTANT :
+ inc(oper.opr.val,l);
+ OPR_LOCAL :
+ inc(oper.opr.localsymofs,l);
+ OPR_REFERENCE :
+ inc(oper.opr.ref.offset,l);
+ else
+ internalerror(200309202);
+ end;
+ end;
+ AS_MINUS:
+ begin
+ Consume(AS_MINUS);
+ BuildConstSymbolExpression(false,true,false,l,relsym,asmsymtyp);
+ if (relsym<>'') then
+ begin
+ if (oper.opr.typ = OPR_REFERENCE) then
+ oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym,AT_DATA)
+ else
+ begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end
+ end
+ else
+ begin
+ case oper.opr.typ of
+ OPR_CONSTANT :
+ dec(oper.opr.val,l);
+ OPR_LOCAL :
+ dec(oper.opr.localsymofs,l);
+ OPR_REFERENCE :
+ dec(oper.opr.ref.offset,l);
+ else
+ internalerror(2007092601);
+ end;
+ end;
+ end;
+ end;
+ Consume(AS_RPAREN);
+ if actasmtoken=AS_AT then
+ ReadAt(oper);
+ End;
+ AS_COMMA: { (, ... can either be scaling, or index }
+ Begin
+ Consume(AS_COMMA);
+ { Index }
+ if (actasmtoken=AS_REGISTER) then
+ Begin
+ oper.opr.ref.index:=actasmregister;
+ Consume(AS_REGISTER);
+ { check for scaling ... }
+ Consume_RParen;
+ end
+ else
+ begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end;
+ end;
+ else
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end;
+ end;
+ end;
+
+
+ procedure trv64attreader.BuildOperand(oper: trvoperand);
+ var
+ expr : string;
+ typesize,l : aint;
+
+
+ procedure AddLabelOperand(hl:tasmlabel);
+ begin
+ if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
+ is_calljmp(actopcode) then
+ begin
+ oper.opr.typ:=OPR_SYMBOL;
+ oper.opr.symbol:=hl;
+ end
+ else
+ begin
+ oper.InitRef;
+ oper.opr.ref.symbol:=hl;
+ end;
+ end;
+
+
+ procedure MaybeRecordOffset;
+ var
+ mangledname: string;
+ hasdot : boolean;
+ l,
+ toffset,
+ tsize : aint;
+ begin
+ if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
+ exit;
+ l:=0;
+ hasdot:=(actasmtoken=AS_DOT);
+ if hasdot then
+ begin
+ if expr<>'' then
+ begin
+ BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
+ if (oper.opr.typ<>OPR_CONSTANT) and
+ (mangledname<>'') then
+ Message(asmr_e_wrong_sym_type);
+ inc(l,toffset);
+ oper.SetSize(tsize,true);
+ end;
+ end;
+ if actasmtoken in [AS_PLUS,AS_MINUS] then
+ inc(l,BuildConstExpression(true,false));
+ case oper.opr.typ of
+ OPR_LOCAL :
+ begin
+ { don't allow direct access to fields of parameters, because that
+ will generate buggy code. Allow it only for explicit typecasting }
+ if hasdot and
+ (not oper.hastype) and
+ (tabstractvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
+ (current_procinfo.procdef.proccalloption<>pocall_register) then
+ Message(asmr_e_cannot_access_field_directly_for_parameters);
+ inc(oper.opr.localsymofs,l)
+ end;
+ OPR_CONSTANT :
+ if (mangledname<>'') then
+ begin
+ if (oper.opr.val<>0) then
+ Message(asmr_e_wrong_sym_type);
+ oper.opr.typ:=OPR_SYMBOL;
+ oper.opr.symbol:=current_asmdata.DefineAsmSymbol(mangledname,AB_EXTERNAL,AT_FUNCTION,voidcodepointertype);
+ end
+ else
+ inc(oper.opr.val,l);
+ OPR_REFERENCE :
+ inc(oper.opr.ref.offset,l);
+ OPR_SYMBOL:
+ Message(asmr_e_invalid_symbol_ref);
+ else
+ internalerror(200309221);
+ end;
+ end;
+
+
+ function MaybeBuildReference:boolean;
+ { Try to create a reference, if not a reference is found then false
+ is returned }
+ begin
+ MaybeBuildReference:=true;
+ case actasmtoken of
+ AS_INTNUM,
+ AS_MINUS,
+ AS_PLUS:
+ Begin
+ oper.opr.ref.offset:=BuildConstExpression(True,False);
+ if actasmtoken<>AS_LPAREN then
+ Message(asmr_e_invalid_reference_syntax)
+ else
+ BuildReference(oper);
+ end;
+ AS_LPAREN:
+ BuildReference(oper);
+ AS_ID: { only a variable is allowed ... }
+ Begin
+ ReadSym(oper);
+ case actasmtoken of
+ AS_END,
+ AS_SEPARATOR,
+ AS_COMMA: ;
+ AS_LPAREN:
+ BuildReference(oper);
+ else
+ Begin
+ Message(asmr_e_invalid_reference_syntax);
+ Consume(actasmtoken);
+ end;
+ end; {end case }
+ end;
+ else
+ MaybeBuildReference:=false;
+ end; { end case }
+ end;
+
+
+ function is_fenceflag(hs : string): boolean;
+ var
+ i: longint;
+ flags: TFenceFlags;
+ begin
+ is_fenceflag := false;
+
+ flags:=[];
+ hs:=lower(hs);
+
+ if (actopcode in [A_FENCE]) and (length(hs) >= 1) then
+ begin
+ for i:=1 to length(hs) do
+ begin
+ case hs[i] of
+ 'i':
+ Include(flags,ffi);
+ 'o':
+ Include(flags,ffo);
+ 'r':
+ Include(flags,ffr);
+ 'w':
+ Include(flags,ffw);
+ else
+ exit;
+ end;
+ end;
+ oper.opr.typ := OPR_FENCEFLAGS;
+ oper.opr.fenceflags := flags;
+ exit(true);
+ end;
+ end;
+
+
+ var
+ tempreg : tregister;
+ hl : tasmlabel;
+ ofs : aint;
+ refaddr: trefaddr;
+ Begin
+ expr:='';
+
+ refaddr:=addr_full;
+ if actasmtoken=AS_MOD then
+ begin
+ consume(AS_MOD);
+
+ if actasmtoken<>AS_ID then
+ begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end
+ else
+ begin
+ if lower(actasmpattern)='pcrel_hi' then
+ refaddr:=addr_pcrel_hi20
+ else if lower(actasmpattern)='pcrel_lo' then
+ refaddr:=addr_pcrel_lo12
+ else if lower(actasmpattern)='hi' then
+ refaddr:=addr_hi20
+ else if lower(actasmpattern)='lo' then
+ refaddr:=addr_lo12
+ else
+ begin
+ Message(asmr_e_invalid_reference_syntax);
+ RecoverConsume(false);
+ end;
+
+ consume(AS_ID);
+ consume(AS_LPAREN);
+ end;
+ end;
+
+ case actasmtoken of
+ AS_LPAREN: { Memory reference or constant expression }
+ Begin
+ oper.InitRef;
+ BuildReference(oper);
+ end;
+
+ AS_INTNUM,
+ AS_MINUS,
+ AS_PLUS:
+ Begin
+ { Constant memory offset }
+ { This must absolutely be followed by ( }
+ oper.InitRef;
+ oper.opr.ref.offset:=BuildConstExpression(True,False);
+ if actasmtoken<>AS_LPAREN then
+ begin
+ ofs:=oper.opr.ref.offset;
+ BuildConstantOperand(oper);
+ inc(oper.opr.val,ofs);
+ end
+ else
+ BuildReference(oper);
+ end;
+
+ AS_ID: { A constant expression, or a Variable ref. }
+ Begin
+ if is_fenceflag(actasmpattern) then
+ begin
+ consume(AS_ID);
+ end
+ else
+ { Local Label ? }
+ if is_locallabel(actasmpattern) then
+ begin
+ CreateLocalLabel(actasmpattern,hl,false);
+ Consume(AS_ID);
+ AddLabelOperand(hl);
+ end
+ else
+ { Check for label }
+ if SearchLabel(actasmpattern,hl,false) then
+ begin
+ Consume(AS_ID);
+ AddLabelOperand(hl);
+ end
+ else
+ { probably a variable or normal expression }
+ { or a procedure (such as in CALL ID) }
+ Begin
+ { is it a constant ? }
+ if SearchIConstant(actasmpattern,l) then
+ Begin
+ if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
+ Message(asmr_e_invalid_operand_type);
+ BuildConstantOperand(oper);
+ end
+ else
+ begin
+ expr:=actasmpattern;
+ Consume(AS_ID);
+ { typecasting? }
+ if (actasmtoken=AS_LPAREN) and
+ SearchType(expr,typesize) then
+ begin
+ oper.hastype:=true;
+ Consume(AS_LPAREN);
+ BuildOperand(oper);
+ Consume(AS_RPAREN);
+ if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
+ oper.SetSize(typesize,true);
+ end
+ else
+ begin
+ if oper.SetupVar(expr,false) then
+ ReadAt(oper)
+ else
+ Begin
+ { look for special symbols ... }
+ if expr= '__HIGH' then
+ begin
+ consume(AS_LPAREN);
+ if not oper.setupvar('high'+actasmpattern,false) then
+ Message1(sym_e_unknown_id,'high'+actasmpattern);
+ consume(AS_ID);
+ consume(AS_RPAREN);
+ end
+ else
+ if expr = '__RESULT' then
+ oper.SetUpResult
+ else
+ if expr = '__SELF' then
+ oper.SetupSelf
+ else
+ if expr = '__OLDEBP' then
+ oper.SetupOldEBP
+ else
+ Message1(sym_e_unknown_id,expr);
+ end;
+ end;
+ end;
+ if actasmtoken=AS_DOT then
+ MaybeRecordOffset;
+ { add a constant expression? }
+ if (actasmtoken=AS_PLUS) then
+ begin
+ l:=BuildConstExpression(true,false);
+ case oper.opr.typ of
+ OPR_CONSTANT :
+ inc(oper.opr.val,l);
+ OPR_LOCAL :
+ inc(oper.opr.localsymofs,l);
+ OPR_REFERENCE :
+ inc(oper.opr.ref.offset,l);
+ else
+ internalerror(200309202);
+ end;
+ end
+ end;
+ { Do we have a indexing reference, then parse it also }
+ if actasmtoken=AS_LPAREN then
+ BuildReference(oper);
+ end;
+
+ AS_REGISTER: { Register, a variable reference or a constant reference }
+ Begin
+ { save the type of register used. }
+ tempreg:=actasmregister;
+ Consume(AS_REGISTER);
+ if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
+ begin
+ if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
+ Message(asmr_e_invalid_operand_type);
+ oper.opr.typ:=OPR_REGISTER;
+ oper.opr.reg:=tempreg;
+ end
+ else
+ Message(asmr_e_syn_operand);
+ end;
+ AS_END,
+ AS_SEPARATOR,
+ AS_COMMA: ;
+ else
+ Begin
+ Message(asmr_e_syn_operand);
+ Consume(actasmtoken);
+ end;
+ end; { end case }
+
+ if refaddr<>addr_full then
+ begin
+ if oper.opr.typ<>OPR_REFERENCE then
+ oper.InitRef;
+
+ oper.opr.ref.refaddr:=refaddr;
+ Consume(AS_RPAREN);
+ end;
+ end;
+
+
+{*****************************************************************************
+ trv64attreader
+*****************************************************************************}
+
+ procedure trv64attreader.BuildOpCode(instr : trvinstruction);
+ 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;
+ ordering:=actmemoryordering;
+ 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 trvoperand);
+ end; { end case }
+ until false;
+ if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
+ dec(operandnum);
+ instr.Ops:=operandnum;
+ end;
+
+ function trv64attreader.is_register(const s: string): boolean;
+ type
+ treg2str = record
+ name : string[3];
+ reg : tregister;
+ end;
+
+ const
+ extraregs : array[0..31] of treg2str = (
+ (name: 'A0'; reg : NR_X10),
+ (name: 'A1'; reg : NR_X11),
+ (name: 'A2'; reg : NR_X12),
+ (name: 'A3'; reg : NR_X13),
+ (name: 'A4'; reg : NR_X14),
+ (name: 'A5'; reg : NR_X15),
+ (name: 'A6'; reg : NR_X16),
+ (name: 'A7'; reg : NR_X17),
+ (name: 'RA'; reg : NR_X1),
+ (name: 'SP'; reg : NR_X2),
+ (name: 'GP'; reg : NR_X3),
+ (name: 'TP'; reg : NR_X4),
+ (name: 'T0'; reg : NR_X5),
+ (name: 'T1'; reg : NR_X6),
+ (name: 'T2'; reg : NR_X7),
+ (name: 'S0'; reg : NR_X8),
+ (name: 'FP'; reg : NR_X8),
+ (name: 'S1'; reg : NR_X9),
+ (name: 'S2'; reg : NR_X18),
+ (name: 'S3'; reg : NR_X19),
+ (name: 'S4'; reg : NR_X20),
+ (name: 'S5'; reg : NR_X21),
+ (name: 'S6'; reg : NR_X22),
+ (name: 'S7'; reg : NR_X23),
+ (name: 'S8'; reg : NR_X24),
+ (name: 'S9'; reg : NR_X25),
+ (name: 'S10';reg : NR_X26),
+ (name: 'S11';reg : NR_X27),
+ (name: 'T3'; reg : NR_X28),
+ (name: 'T4'; reg : NR_X29),
+ (name: 'T5'; reg : NR_X30),
+ (name: 'T6'; reg : NR_X31)
+ );
+
+ var
+ i : longint;
+
+ begin
+ result:=inherited is_register(s);
+ { reg found?
+ possible aliases are always 2 char
+ }
+ if result or (not (length(s) in [2,3])) then
+ exit;
+ for i:=low(extraregs) to high(extraregs) do
+ begin
+ if s=extraregs[i].name then
+ begin
+ actasmregister:=extraregs[i].reg;
+ result:=true;
+ actasmtoken:=AS_REGISTER;
+ exit;
+ end;
+ end;
+ end;
+
+
+ function trv64attreader.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;
+ { not found, check branch instructions }
+ if hs[1]='B' then
+ begin
+ { we can search here without an extra table which is sorted by string length
+ because we take the whole remaining string without the leading B }
+ actopcode := A_Bxx;
+ for cond:=low(TAsmCond) to high(TAsmCond) do
+ if copy(hs,2,length(s)-1)=uppercond2str[cond] then
+ begin
+ actcondition:=cond;
+ actasmtoken:=AS_OPCODE;
+ is_asmopcode:=true;
+ exit;
+ end;
+ end;
+
+ { check atomic instructions }
+ if (pos('AMO',hs)=1) or
+ (pos('LR', hs)=1) or
+ (pos('SC', hs)=1) then
+ begin
+ l := length(hs)-1;
+ while l>1 do
+ begin
+ actopcode := tasmop(ptruint(iasmops.find(copy(hs,1,l))));
+ if actopcode <> A_None then
+ begin
+ postfix := copy(hs,l+1,length(hs)-l);
+
+ if postfix='.AQRL' then actmemoryordering:=[moAq,moRl]
+ else if postfix='.RL' then actmemoryordering:=[moRl]
+ else if postfix='.AQ' then actmemoryordering:=[moAq]
+ else
+ exit;
+
+ actasmtoken:=AS_OPCODE;
+ is_asmopcode:=true;
+ exit;
+ end;
+ dec(l);
+ end;
+ end;
+ end;
+
+
+ procedure trv64attreader.handleopcode;
+ var
+ instr : trvinstruction;
+ begin
+ instr:=trvinstruction.Create(trvoperand);
+ BuildOpcode(instr);
+ instr.condition := actcondition;
+ {
+ instr.AddReferenceSizes;
+ instr.SetInstructionOpsize;
+ instr.CheckOperandSizes;
+ }
+ instr.ConcatInstruction(curlist);
+ instr.Free;
+ actmemoryordering:=[];
+ end;
+
+
+{*****************************************************************************
+ Initialize
+*****************************************************************************}
+
+ const
+ asmmode_rv64_standard_info : tasmmodeinfo =
+ (
+ id : asmmode_standard;
+ idtxt : 'STANDARD';
+ casmreader : trv64attreader;
+ );
+
+initialization
+ RegisterAsmMode(asmmode_rv64_standard_info);
+end.
+
diff --git a/compiler/riscv64/rrv32con.inc b/compiler/riscv64/rrv32con.inc
new file mode 100644
index 0000000000..94c5f42533
--- /dev/null
+++ b/compiler/riscv64/rrv32con.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+NR_NO = tregister($00000000);
+NR_X0 = tregister($01000000);
+NR_X1 = tregister($01000001);
+NR_X2 = tregister($01000002);
+NR_X3 = tregister($01000003);
+NR_X4 = tregister($01000004);
+NR_X5 = tregister($01000005);
+NR_X6 = tregister($01000006);
+NR_X7 = tregister($01000007);
+NR_X8 = tregister($01000008);
+NR_X9 = tregister($01000009);
+NR_X10 = tregister($0100000a);
+NR_X11 = tregister($0100000b);
+NR_X12 = tregister($0100000c);
+NR_X13 = tregister($0100000d);
+NR_X14 = tregister($0100000e);
+NR_X15 = tregister($0100000f);
+NR_X16 = tregister($01000010);
+NR_X17 = tregister($01000011);
+NR_X18 = tregister($01000012);
+NR_X19 = tregister($01000013);
+NR_X20 = tregister($01000014);
+NR_X21 = tregister($01000015);
+NR_X22 = tregister($01000016);
+NR_X23 = tregister($01000017);
+NR_X24 = tregister($01000018);
+NR_X25 = tregister($01000019);
+NR_X26 = tregister($0100001a);
+NR_X27 = tregister($0100001b);
+NR_X28 = tregister($0100001c);
+NR_X29 = tregister($0100001d);
+NR_X30 = tregister($0100001e);
+NR_X31 = tregister($0100001f);
+NR_F0 = tregister($02000000);
+NR_F1 = tregister($02000001);
+NR_F2 = tregister($02000002);
+NR_F3 = tregister($02000003);
+NR_F4 = tregister($02000004);
+NR_F5 = tregister($02000005);
+NR_F6 = tregister($02000006);
+NR_F7 = tregister($02000007);
+NR_F8 = tregister($02000008);
+NR_F9 = tregister($02000009);
+NR_F10 = tregister($0200000a);
+NR_F11 = tregister($0200000b);
+NR_F12 = tregister($0200000c);
+NR_F13 = tregister($0200000d);
+NR_F14 = tregister($0200000e);
+NR_F15 = tregister($0200000f);
+NR_F16 = tregister($02000010);
+NR_F17 = tregister($02000011);
+NR_F18 = tregister($02000012);
+NR_F19 = tregister($02000013);
+NR_F20 = tregister($02000014);
+NR_F21 = tregister($02000015);
+NR_F22 = tregister($02000016);
+NR_F23 = tregister($02000017);
+NR_F24 = tregister($02000018);
+NR_F25 = tregister($02000019);
+NR_F26 = tregister($0200001a);
+NR_F27 = tregister($0200001b);
+NR_F28 = tregister($0200001c);
+NR_F29 = tregister($0200001d);
+NR_F30 = tregister($0200001e);
+NR_F31 = tregister($0200001f);
+NR_FCSR = tregister($05000001);
diff --git a/compiler/riscv64/rrv32dwa.inc b/compiler/riscv64/rrv32dwa.inc
new file mode 100644
index 0000000000..6755ebb4c5
--- /dev/null
+++ b/compiler/riscv64/rrv32dwa.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+-1,
+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,
+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,
+0
diff --git a/compiler/riscv64/rrv32nor.inc b/compiler/riscv64/rrv32nor.inc
new file mode 100644
index 0000000000..a3c3b517a4
--- /dev/null
+++ b/compiler/riscv64/rrv32nor.inc
@@ -0,0 +1,2 @@
+{ don't edit, this file is generated from rv32reg.dat }
+66
diff --git a/compiler/riscv64/rrv32num.inc b/compiler/riscv64/rrv32num.inc
new file mode 100644
index 0000000000..f9553bf4fb
--- /dev/null
+++ b/compiler/riscv64/rrv32num.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+tregister($00000000),
+tregister($01000000),
+tregister($01000001),
+tregister($01000002),
+tregister($01000003),
+tregister($01000004),
+tregister($01000005),
+tregister($01000006),
+tregister($01000007),
+tregister($01000008),
+tregister($01000009),
+tregister($0100000a),
+tregister($0100000b),
+tregister($0100000c),
+tregister($0100000d),
+tregister($0100000e),
+tregister($0100000f),
+tregister($01000010),
+tregister($01000011),
+tregister($01000012),
+tregister($01000013),
+tregister($01000014),
+tregister($01000015),
+tregister($01000016),
+tregister($01000017),
+tregister($01000018),
+tregister($01000019),
+tregister($0100001a),
+tregister($0100001b),
+tregister($0100001c),
+tregister($0100001d),
+tregister($0100001e),
+tregister($0100001f),
+tregister($02000000),
+tregister($02000001),
+tregister($02000002),
+tregister($02000003),
+tregister($02000004),
+tregister($02000005),
+tregister($02000006),
+tregister($02000007),
+tregister($02000008),
+tregister($02000009),
+tregister($0200000a),
+tregister($0200000b),
+tregister($0200000c),
+tregister($0200000d),
+tregister($0200000e),
+tregister($0200000f),
+tregister($02000010),
+tregister($02000011),
+tregister($02000012),
+tregister($02000013),
+tregister($02000014),
+tregister($02000015),
+tregister($02000016),
+tregister($02000017),
+tregister($02000018),
+tregister($02000019),
+tregister($0200001a),
+tregister($0200001b),
+tregister($0200001c),
+tregister($0200001d),
+tregister($0200001e),
+tregister($0200001f),
+tregister($05000001)
diff --git a/compiler/riscv64/rrv32rni.inc b/compiler/riscv64/rrv32rni.inc
new file mode 100644
index 0000000000..de9f6b796b
--- /dev/null
+++ b/compiler/riscv64/rrv32rni.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.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
diff --git a/compiler/riscv64/rrv32sri.inc b/compiler/riscv64/rrv32sri.inc
new file mode 100644
index 0000000000..a39dc1faa3
--- /dev/null
+++ b/compiler/riscv64/rrv32sri.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+0,
+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,
+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
diff --git a/compiler/riscv64/rrv32sta.inc b/compiler/riscv64/rrv32sta.inc
new file mode 100644
index 0000000000..6755ebb4c5
--- /dev/null
+++ b/compiler/riscv64/rrv32sta.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+-1,
+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,
+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,
+0
diff --git a/compiler/riscv64/rrv32std.inc b/compiler/riscv64/rrv32std.inc
new file mode 100644
index 0000000000..468a711616
--- /dev/null
+++ b/compiler/riscv64/rrv32std.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+'INVALID',
+'x0',
+'x1',
+'x2',
+'x3',
+'x4',
+'x5',
+'x6',
+'x7',
+'x8',
+'x9',
+'x10',
+'x11',
+'x12',
+'x13',
+'x14',
+'x15',
+'x16',
+'x17',
+'x18',
+'x19',
+'x20',
+'x21',
+'x22',
+'x23',
+'x24',
+'x25',
+'x26',
+'x27',
+'x28',
+'x29',
+'x30',
+'x31',
+'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',
+'fcsr'
diff --git a/compiler/riscv64/rrv32sup.inc b/compiler/riscv64/rrv32sup.inc
new file mode 100644
index 0000000000..cb12862e9d
--- /dev/null
+++ b/compiler/riscv64/rrv32sup.inc
@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+RS_NO = $00;
+RS_X0 = $00;
+RS_X1 = $01;
+RS_X2 = $02;
+RS_X3 = $03;
+RS_X4 = $04;
+RS_X5 = $05;
+RS_X6 = $06;
+RS_X7 = $07;
+RS_X8 = $08;
+RS_X9 = $09;
+RS_X10 = $0a;
+RS_X11 = $0b;
+RS_X12 = $0c;
+RS_X13 = $0d;
+RS_X14 = $0e;
+RS_X15 = $0f;
+RS_X16 = $10;
+RS_X17 = $11;
+RS_X18 = $12;
+RS_X19 = $13;
+RS_X20 = $14;
+RS_X21 = $15;
+RS_X22 = $16;
+RS_X23 = $17;
+RS_X24 = $18;
+RS_X25 = $19;
+RS_X26 = $1a;
+RS_X27 = $1b;
+RS_X28 = $1c;
+RS_X29 = $1d;
+RS_X30 = $1e;
+RS_X31 = $1f;
+RS_F0 = $00;
+RS_F1 = $01;
+RS_F2 = $02;
+RS_F3 = $03;
+RS_F4 = $04;
+RS_F5 = $05;
+RS_F6 = $06;
+RS_F7 = $07;
+RS_F8 = $08;
+RS_F9 = $09;
+RS_F10 = $0a;
+RS_F11 = $0b;
+RS_F12 = $0c;
+RS_F13 = $0d;
+RS_F14 = $0e;
+RS_F15 = $0f;
+RS_F16 = $10;
+RS_F17 = $11;
+RS_F18 = $12;
+RS_F19 = $13;
+RS_F20 = $14;
+RS_F21 = $15;
+RS_F22 = $16;
+RS_F23 = $17;
+RS_F24 = $18;
+RS_F25 = $19;
+RS_F26 = $1a;
+RS_F27 = $1b;
+RS_F28 = $1c;
+RS_F29 = $1d;
+RS_F30 = $1e;
+RS_F31 = $1f;
+RS_FCSR = $01;
diff --git a/compiler/riscv64/rv32reg.dat b/compiler/riscv64/rv32reg.dat
new file mode 100644
index 0000000000..0be9f17f99
--- /dev/null
+++ b/compiler/riscv64/rv32reg.dat
@@ -0,0 +1,77 @@
+;
+; RiscV registers
+;
+; layout
+; <name>,<type>,<subtype>,<value>,<stdname>,<stab idx>,<dwarf idx>
+;
+NO,$00,$00,$00,INVALID,-1,-1
+; Integer registers
+X0,$01,$00,$00,x0,0,0
+X1,$01,$00,$01,x1,1,1
+X2,$01,$00,$02,x2,2,2
+X3,$01,$00,$03,x3,3,3
+X4,$01,$00,$04,x4,4,4
+X5,$01,$00,$05,x5,5,5
+X6,$01,$00,$06,x6,6,6
+X7,$01,$00,$07,x7,7,7
+X8,$01,$00,$08,x8,8,8
+X9,$01,$00,$09,x9,9,9
+X10,$01,$00,$0a,x10,10,10
+X11,$01,$00,$0b,x11,11,11
+X12,$01,$00,$0c,x12,12,12
+X13,$01,$00,$0d,x13,13,13
+X14,$01,$00,$0e,x14,14,14
+X15,$01,$00,$0f,x15,15,15
+X16,$01,$00,$10,x16,16,16
+X17,$01,$00,$11,x17,17,17
+X18,$01,$00,$12,x18,18,18
+X19,$01,$00,$13,x19,19,19
+X20,$01,$00,$14,x20,20,20
+X21,$01,$00,$15,x21,21,21
+X22,$01,$00,$16,x22,22,22
+X23,$01,$00,$17,x23,23,23
+X24,$01,$00,$18,x24,24,24
+X25,$01,$00,$19,x25,25,25
+X26,$01,$00,$1a,x26,26,26
+X27,$01,$00,$1b,x27,27,27
+X28,$01,$00,$1c,x28,28,28
+X29,$01,$00,$1d,x29,29,29
+X30,$01,$00,$1e,x30,30,30
+X31,$01,$00,$1f,x31,31,31
+
+; Float registers
+F0,$02,$00,$00,f0,0,0
+F1,$02,$00,$01,f1,1,1
+F2,$02,$00,$02,f2,2,2
+F3,$02,$00,$03,f3,3,3
+F4,$02,$00,$04,f4,4,4
+F5,$02,$00,$05,f5,5,5
+F6,$02,$00,$06,f6,6,6
+F7,$02,$00,$07,f7,7,7
+F8,$02,$00,$08,f8,8,8
+F9,$02,$00,$09,f9,9,9
+F10,$02,$00,$0a,f10,10,10
+F11,$02,$00,$0b,f11,11,11
+F12,$02,$00,$0c,f12,12,12
+F13,$02,$00,$0d,f13,13,13
+F14,$02,$00,$0e,f14,14,14
+F15,$02,$00,$0f,f15,15,15
+F16,$02,$00,$10,f16,16,16
+F17,$02,$00,$11,f17,17,17
+F18,$02,$00,$12,f18,18,18
+F19,$02,$00,$13,f19,19,19
+F20,$02,$00,$14,f20,20,20
+F21,$02,$00,$15,f21,21,21
+F22,$02,$00,$16,f22,22,22
+F23,$02,$00,$17,f23,23,23
+F24,$02,$00,$18,f24,24,24
+F25,$02,$00,$19,f25,25,25
+F26,$02,$00,$1a,f26,26,26
+F27,$02,$00,$1b,f27,27,27
+F28,$02,$00,$1c,f28,28,28
+F29,$02,$00,$1d,f29,29,29
+F30,$02,$00,$1e,f30,30,30
+F31,$02,$00,$1f,f31,31,31
+
+; Special registers
+FCSR,$05,$00,$01,fcsr,0,0
diff --git a/compiler/riscv64/symcpu.pas b/compiler/riscv64/symcpu.pas
new file mode 100644
index 0000000000..e1b5f3b08e
--- /dev/null
+++ b/compiler/riscv64/symcpu.pas
@@ -0,0 +1,220 @@
+{
+ Copyright (c) 2014 by Florian Klaempfl
+
+ Symbol table overrides for RiscV64
+
+ 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.
+
diff --git a/compiler/scandir.pas b/compiler/scandir.pas
index a30f7a13cd..f3fe0286d8 100644
--- a/compiler/scandir.pas
+++ b/compiler/scandir.pas
@@ -436,6 +436,12 @@ unit scandir;
end;
+ procedure dir_checkfpuexceptions;
+ begin
+ do_localswitch(cs_check_fpu_exceptions);
+ end;
+
+
procedure dir_objectchecks;
begin
do_localswitch(cs_check_object);
@@ -1902,6 +1908,7 @@ unit scandir;
AddDirective('BOOLEVAL',directive_all, @dir_booleval);
AddDirective('BITPACKING',directive_all, @dir_bitpacking);
AddDirective('CALLING',directive_all, @dir_calling);
+ AddDirective('CHECKFPUEXCEPTIONS',directive_all, @dir_checkfpuexceptions);
AddDirective('CHECKLOWADDRLOADS',directive_all, @dir_checklowaddrloads);
AddDirective('CHECKPOINTER',directive_all, @dir_checkpointer);
AddDirective('CODEALIGN',directive_all, @dir_codealign);
diff --git a/compiler/systems.inc b/compiler/systems.inc
index 9da234156e..3c60f4a7ce 100644
--- a/compiler/systems.inc
+++ b/compiler/systems.inc
@@ -52,7 +52,9 @@
cpu_i8086, { 15 }
cpu_aarch64, { 16 }
cpu_wasm, { 17 }
- cpu_sparc64 { 18 }
+ cpu_sparc64, { 18 }
+ cpu_riscv32, { 19 }
+ cpu_riscv64 { 20 }
);
tasmmode= (asmmode_none
@@ -179,7 +181,11 @@
system_wasm_wasm32, { 92 }
system_sparc64_linux, { 93 }
system_sparc64_solaris, { 94 }
- system_arm_netbsd { 95 }
+ system_arm_netbsd, { 95 }
+ system_riscv32_linux, { 96 }
+ system_riscv64_linux, { 97 }
+ system_riscv64_embedded, { 98 }
+ system_riscv32_embedded { 99 }
);
type
@@ -309,6 +315,7 @@
,abi_eabi,abi_armeb,abi_eabihf
,abi_old_win32_gnu
,abi_aarch64_darwin
+ ,abi_riscv_hf
);
const
diff --git a/compiler/systems.pas b/compiler/systems.pas
index b0201c7576..349d5b0314 100644
--- a/compiler/systems.pas
+++ b/compiler/systems.pas
@@ -232,7 +232,8 @@ interface
systems_android = [system_arm_android, system_i386_android, system_mipsel_android];
systems_linux = [system_i386_linux,system_x86_64_linux,system_powerpc_linux,system_powerpc64_linux,
system_arm_linux,system_sparc_linux,system_sparc64_linux,system_m68k_linux,
- system_x86_6432_linux,system_mipseb_linux,system_mipsel_linux,system_aarch64_linux];
+ system_x86_6432_linux,system_mipseb_linux,system_mipsel_linux,system_aarch64_linux,
+ system_riscv32_linux,system_riscv64_linux];
systems_dragonfly = [system_x86_64_dragonfly];
systems_freebsd = [system_i386_freebsd,
system_x86_64_freebsd];
@@ -274,7 +275,7 @@ interface
system_mips_embedded,system_arm_embedded,
system_powerpc64_embedded,system_avr_embedded,
system_jvm_java32,system_mipseb_embedded,system_mipsel_embedded,
- system_i8086_embedded];
+ system_i8086_embedded,system_riscv32_embedded,system_riscv64_embedded];
{ all systems that allow section directive }
systems_allow_section = systems_embedded;
@@ -397,7 +398,7 @@ interface
cpu2str : array[TSystemCpu] of string[10] =
('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64',
'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086',
- 'aarch64', 'wasm', 'sparc64');
+ 'aarch64', 'wasm', 'sparc64','riscv32','riscv64');
abiinfo : array[tabi] of tabiinfo = (
(name: 'DEFAULT'; supported: true),
@@ -409,7 +410,8 @@ interface
(name: 'ARMEB' ; supported:{$ifdef FPC_ARMEB}true{$else}false{$endif}),
(name: 'EABIHF' ; supported:{$ifdef FPC_ARMHF}true{$else}false{$endif}),
(name: 'OLDWIN32GNU'; supported:{$ifdef I386}true{$else}false{$endif}),
- (name: 'AARCH64IOS'; supported:{$ifdef aarch64}true{$else}false{$endif})
+ (name: 'AARCH64IOS'; supported:{$ifdef aarch64}true{$else}false{$endif}),
+ (name: 'RISCVHF'; supported:{$if defined(riscv32) or defined(riscv64)}true{$else}false{$endif})
);
var
@@ -1036,6 +1038,14 @@ begin
{$ifdef wasm}
default_target(system_wasm_wasm32);
{$endif}
+
+{$ifdef riscv32}
+ default_target(system_riscv32_linux);
+{$endif riscv32}
+
+{$ifdef riscv64}
+ default_target(system_riscv64_linux);
+{$endif riscv64}
end;
diff --git a/compiler/systems/i_linux.pas b/compiler/systems/i_linux.pas
index 701dca158f..c65535df91 100644
--- a/compiler/systems/i_linux.pas
+++ b/compiler/systems/i_linux.pas
@@ -1029,6 +1029,138 @@ unit i_linux;
llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64';
);
+ system_riscv32_linux_info : tsysteminfo =
+ (
+ system : system_riscv32_linux;
+ name : 'Linux for RISC-V 32';
+ shortname : 'Linux';
+ flags : [tf_needs_symbol_size,tf_smartlink_sections,
+ tf_needs_symbol_type,tf_files_case_sensitive,
+ tf_requires_proper_alignment,tf_has_winlike_resources];
+ cpu : cpu_riscv32;
+ unit_env : 'LINUXUNITS';
+ extradefines : 'UNIX;HASUNIX';
+ exeext : '';
+ defext : '.def';
+ scriptext : '.sh';
+ smartext : '.sl';
+ unitext : '.ppu';
+ unitlibext : '.ppl';
+ asmext : '.s';
+ objext : '.o';
+ resext : '.res';
+ resobjext : '.or';
+ sharedlibext : '.so';
+ staticlibext : '.a';
+ staticlibprefix : 'libp';
+ sharedlibprefix : 'lib';
+ sharedClibext : '.so';
+ staticClibext : '.a';
+ staticClibprefix : 'lib';
+ sharedClibprefix : 'lib';
+ importlibprefix : 'libimp';
+ importlibext : '.a';
+// p_ext_support : false;
+ Cprefix : '';
+ newline : #10;
+ dirsep : '/';
+ assem : as_gas;
+ assemextern : as_gas;
+ link : ld_none;
+ linkextern : ld_linux;
+ ar : ar_gnu_ar;
+ res : res_elf;
+ dbg : dbg_stabs;
+ script : script_unix;
+ endian : endian_little;
+ alignment :
+ (
+ procalign : 4;
+ loopalign : 4;
+ jumpalign : 0;
+ constalignmin : 0;
+ constalignmax : 8;
+ varalignmin : 0;
+ varalignmax : 8;
+ localalignmin : 4;
+ localalignmax : 8;
+ recordalignmin : 0;
+ recordalignmax : 8;
+ maxCrecordalign : 8
+ );
+ first_parm_offset : 0;
+ stacksize : 32*1024*1024;
+ stackalign : 8;
+ abi : abi_riscv_hf;
+ llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64';
+ );
+
+ system_riscv64_linux_info : tsysteminfo =
+ (
+ system : system_riscv64_linux;
+ name : 'Linux for RISC-V 64';
+ shortname : 'Linux';
+ flags : [tf_needs_symbol_size,tf_smartlink_sections,
+ tf_needs_symbol_type,tf_files_case_sensitive,
+ tf_requires_proper_alignment,tf_has_winlike_resources];
+ cpu : cpu_riscv64;
+ unit_env : 'LINUXUNITS';
+ extradefines : 'UNIX;HASUNIX';
+ exeext : '';
+ defext : '.def';
+ scriptext : '.sh';
+ smartext : '.sl';
+ unitext : '.ppu';
+ unitlibext : '.ppl';
+ asmext : '.s';
+ objext : '.o';
+ resext : '.res';
+ resobjext : '.or';
+ sharedlibext : '.so';
+ staticlibext : '.a';
+ staticlibprefix : 'libp';
+ sharedlibprefix : 'lib';
+ sharedClibext : '.so';
+ staticClibext : '.a';
+ staticClibprefix : 'lib';
+ sharedClibprefix : 'lib';
+ importlibprefix : 'libimp';
+ importlibext : '.a';
+// p_ext_support : false;
+ Cprefix : '';
+ newline : #10;
+ dirsep : '/';
+ assem : as_gas;
+ assemextern : as_gas;
+ link : ld_none;
+ linkextern : ld_linux;
+ ar : ar_gnu_ar;
+ res : res_elf;
+ dbg : dbg_dwarf2;
+ script : script_unix;
+ endian : endian_little;
+ alignment :
+ (
+ procalign : 8;
+ loopalign : 4;
+ jumpalign : 0;
+ constalignmin : 4;
+ constalignmax : 16;
+ varalignmin : 4;
+ varalignmax : 16;
+ localalignmin : 8;
+ localalignmax : 16;
+ recordalignmin : 0;
+ recordalignmax : 16;
+ maxCrecordalign : 16
+ );
+ first_parm_offset : 16;
+ stacksize : 10*1024*1024;
+ stackalign : 16;
+ abi : abi_riscv_hf;
+ llvmdatalayout : 'E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:64:64-v128:128:128-n32:64';
+ );
+
implementation
initialization
@@ -1095,4 +1227,14 @@ initialization
set_source_info(system_mipsel_linux_info);
{$endif linux}
{$endif CPUMIPSEL}
+{$ifdef CPURISCV32}
+ {$ifdef linux}
+ set_source_info(system_riscv32_linux_info);
+ {$endif linux}
+{$endif CPURISCV32}
+{$ifdef CPURISCV64}
+ {$ifdef linux}
+ set_source_info(system_riscv64_linux_info);
+ {$endif linux}
+{$endif CPURISCV64}
end.
diff --git a/compiler/systems/t_linux.pas b/compiler/systems/t_linux.pas
index 0a4af94074..908b19d267 100644
--- a/compiler/systems/t_linux.pas
+++ b/compiler/systems/t_linux.pas
@@ -181,6 +181,12 @@ begin
{$ifdef sparc64}
LibrarySearchPath.AddPath(sysrootpath,'/usr/lib/sparc64-linux-gnu',true);
{$endif sparc64}
+{$ifdef riscv32}
+ LibrarySearchPath.AddPath(sysrootpath,'/usr/lib/riscv32-linux-gnu',true);
+{$endif riscv32}
+{$ifdef riscv64}
+ LibrarySearchPath.AddPath(sysrootpath,'/usr/lib/riscv64-linux-gnu',true);
+{$endif riscv64}
end;
end;
@@ -234,6 +240,13 @@ const defdynlinker='/lib/ld-linux-aarch64.so.1';
const defdynlinker='/lib64/ld-linux.so.2';
{$endif sparc64}
+{$ifdef riscv32}
+ const defdynlinker='/lib32/ld.so.1';
+{$endif riscv32}
+{$ifdef riscv64}
+ const defdynlinker='/lib/ld-linux-riscv64-lp64d.so.1';
+{$endif riscv64}
+
procedure SetupDynlinker(out DynamicLinker:string;out libctype:TLibcType);
begin
@@ -338,6 +351,8 @@ const
platform_select='-EB';
{$endif}
{$endif}
+{$ifdef riscv32} platform_select='';{$endif} {unknown :( }
+{$ifdef riscv64} platform_select='';{$endif} {unknown :( }
var
platformopt: string;
@@ -1892,5 +1907,15 @@ initialization
RegisterTarget(system_mipseb_linux_info);
{$endif MIPSEL}
{$endif MIPS}
+{$ifdef riscv32}
+ RegisterImport(system_riscv32_linux,timportliblinux);
+ RegisterExport(system_riscv32_linux,texportliblinux);
+ RegisterTarget(system_riscv32_linux_info);
+{$endif riscv32}
+{$ifdef riscv64}
+ RegisterImport(system_riscv64_linux,timportliblinux);
+ RegisterExport(system_riscv64_linux,texportliblinux);
+ RegisterTarget(system_riscv64_linux_info);
+{$endif riscv64}
RegisterRes(res_elf_info,TWinLikeResourceFile);
end.
diff --git a/compiler/utils/Makefile b/compiler/utils/Makefile
index 9aa715fee9..07cbed1fa2 100644
--- a/compiler/utils/Makefile
+++ b/compiler/utils/Makefile
@@ -1,8 +1,8 @@
#
-# Don't edit, this file is generated by FPCMake Version 2.0.0
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2018/07/20]
#
default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm sparc64-linux
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded
BSDs = freebsd netbsd openbsd darwin dragonfly
UNIXs = linux $(BSDs) solaris qnx haiku aix
LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -586,6 +586,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
+endif
ifeq ($(FULL_TARGET),i386-linux)
override CLEAN_UNITS+=ppu crc
endif
@@ -841,6 +853,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override CLEAN_UNITS+=ppu crc
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override CLEAN_UNITS+=ppu crc
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override CLEAN_UNITS+=ppu crc
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override CLEAN_UNITS+=ppu crc
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override CLEAN_UNITS+=ppu crc
+endif
override INSTALL_FPCPACKAGE=y
ifeq ($(FULL_TARGET),i386-linux)
override COMPILER_UNITDIR+=..
@@ -1097,6 +1121,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override COMPILER_UNITDIR+=..
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_UNITDIR+=..
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_UNITDIR+=..
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_UNITDIR+=..
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_UNITDIR+=..
+endif
ifeq ($(FULL_TARGET),i386-linux)
override COMPILER_SOURCEDIR+=..
endif
@@ -1352,6 +1388,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
override COMPILER_SOURCEDIR+=..
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_SOURCEDIR+=..
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_SOURCEDIR+=..
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_SOURCEDIR+=..
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_SOURCEDIR+=..
+endif
override SHARED_BUILD=n
override SHARED_BUILD=n
ifdef REQUIRE_UNITSDIR
@@ -2274,6 +2322,18 @@ endif
ifeq ($(FULL_TARGET),sparc64-linux)
REQUIRE_PACKAGES_RTL=1
endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
ifdef REQUIRE_PACKAGES_RTL
PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
ifneq ($(PACKAGEDIR_RTL),)
diff --git a/compiler/utils/fpc.pp b/compiler/utils/fpc.pp
index e2152aaf69..b531da3f9a 100644
--- a/compiler/utils/fpc.pp
+++ b/compiler/utils/fpc.pp
@@ -168,6 +168,14 @@ program fpc;
processorname:='mips';
{$endif mips}
{$endif not mipsel}
+{$ifdef riscv32}
+ ppcbin:='ppcrv32';
+ processorname:='riscv32';
+{$endif riscv32}
+{$ifdef riscv64}
+ ppcbin:='ppcrv64';
+ processorname:='riscv64';
+{$endif riscv64}
versionstr:=''; { Default is just the name }
if ParamCount = 0 then
begin
diff --git a/compiler/utils/ppuutils/ppudump.pp b/compiler/utils/ppuutils/ppudump.pp
index 434c462706..6358d9b578 100644
--- a/compiler/utils/ppuutils/ppudump.pp
+++ b/compiler/utils/ppuutils/ppudump.pp
@@ -80,7 +80,9 @@ const
{ 15 } 'i8086',
{ 16 } 'aarch64',
{ 17 } 'wasm',
- { 18 } 'sparc64'
+ { 18 } 'sparc64',
+ { 19 } 'riscv32',
+ { 20 } 'riscv64'
);
{ List of all supported system-cpu couples }
@@ -181,7 +183,11 @@ const
{ 92 } 'WebAssembly-wasm',
{ 93 } 'Linux-sparc64',
{ 94 } 'Solaris-sparc64',
- { 95 } 'NetBSD-arm'
+ { 95 } 'NetBSD-arm',
+ { 96 } 'Linux-RiscV32',
+ { 97 } 'Linux-RiscV64',
+ { 98 } 'Embedded-RiscV32',
+ { 99 } 'Embedded-RiscV64'
);
const
diff --git a/compiler/version.pas b/compiler/version.pas
index 7ad3b20345..662a8b8373 100644
--- a/compiler/version.pas
+++ b/compiler/version.pas
@@ -74,6 +74,12 @@ interface
{$ifdef cpuaarch64}
source_cpu_string = 'aarch64';
{$endif cpuaarch64}
+{$ifdef cpuriscv64}
+ source_cpu_string = 'riscv64';
+{$endif cpuriscv64}
+{$ifdef cpuriscv32}
+ source_cpu_string = 'riscv32';
+{$endif cpuriscv32}
function version_string:string;
function full_version_string:string;