diff options
author | florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2018-09-26 19:49:08 +0000 |
---|---|---|
committer | florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2018-09-26 19:49:08 +0000 |
commit | 844935a6ffbca5d7ae4758de3aa4ef8496543f3a (patch) | |
tree | 4cc43a6480f3e1a1702fda012b2da986a015a0b3 /compiler | |
parent | acb2f648fb97fdc281287b6cdb3d0ca2a537ae7a (diff) | |
download | fpc-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')
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; |